tailwind-canonical 0.4.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -3
- package/dist/cli/cli.d.ts +9 -4
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +263 -77
- package/dist/cli/cli.js.map +1 -1
- package/dist/core/class-strings.d.ts +2 -0
- package/dist/core/class-strings.d.ts.map +1 -1
- package/dist/core/class-strings.js +1 -0
- package/dist/core/class-strings.js.map +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +2 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/merger.d.ts.map +1 -1
- package/dist/core/merger.js +73 -1
- package/dist/core/merger.js.map +1 -1
- package/dist/core/rules.d.ts +1 -0
- package/dist/core/rules.d.ts.map +1 -1
- package/dist/core/rules.js.map +1 -1
- package/dist/eslint/plugin.d.ts +7 -6
- package/dist/eslint/plugin.d.ts.map +1 -1
- package/dist/eslint/plugin.js +8 -8
- package/dist/eslint/plugin.js.map +1 -1
- package/dist/io/config.d.ts.map +1 -1
- package/dist/io/config.js +30 -5
- package/dist/io/config.js.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -12,9 +12,47 @@ npm install -D tailwind-canonical
|
|
|
12
12
|
yarn add -D tailwind-canonical
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
First scan to see what needs fixing:
|
|
18
|
+
```bash
|
|
19
|
+
npx tailwind-canonical ./src
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Create a config file to make the full pipeline re-runnable:
|
|
23
|
+
```ts
|
|
24
|
+
// tailwind-canonical.config.ts
|
|
25
|
+
export default {
|
|
26
|
+
defaultCommand: {
|
|
27
|
+
fix: true,
|
|
28
|
+
dedup: true,
|
|
29
|
+
sort: true,
|
|
30
|
+
typos: true,
|
|
31
|
+
targets: ['./src'],
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Now run the whole pipeline with a single command:
|
|
37
|
+
```bash
|
|
38
|
+
npx tailwind-canonical
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For ESLint integration, add to your flat config:
|
|
42
|
+
```js
|
|
43
|
+
import tailwindCanonical from 'tailwind-canonical/eslint'
|
|
44
|
+
|
|
45
|
+
export default [tailwindCanonical.configs.recommended]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
For pre-commit automation, see the [Pre-commit hook](#pre-commit-hook-husky--lefthook) section below.
|
|
49
|
+
|
|
15
50
|
## CLI
|
|
16
51
|
|
|
17
52
|
```bash
|
|
53
|
+
# Scaffold a tailwind-canonical.config.ts in the current directory
|
|
54
|
+
npx tailwind-canonical init
|
|
55
|
+
|
|
18
56
|
# Check for non-canonical arbitrary values
|
|
19
57
|
npx tailwind-canonical ./src
|
|
20
58
|
|
|
@@ -38,17 +76,26 @@ npx tailwind-canonical --merge ./src
|
|
|
38
76
|
# Combine: fix → dedup → merge → sort
|
|
39
77
|
npx tailwind-canonical --fix --dedup --merge --sort ./src
|
|
40
78
|
|
|
79
|
+
# Dry-run: report what the transforms would change, write nothing
|
|
80
|
+
npx tailwind-canonical --check --fix --dedup --sort ./src
|
|
81
|
+
|
|
41
82
|
# Cross-file consistency analysis
|
|
42
83
|
npx tailwind-canonical --analyze ./src
|
|
43
84
|
|
|
44
85
|
# Watch mode: re-run on every file save
|
|
45
86
|
npx tailwind-canonical --watch --fix --sort ./src
|
|
46
87
|
|
|
47
|
-
# Structured output for CI (check mode
|
|
88
|
+
# Structured output for CI (findings in check mode, summary in fix mode)
|
|
48
89
|
npx tailwind-canonical --reporter json ./src
|
|
49
90
|
npx tailwind-canonical --reporter sarif ./src
|
|
91
|
+
|
|
92
|
+
# Help and version
|
|
93
|
+
npx tailwind-canonical --help
|
|
94
|
+
npx tailwind-canonical --version
|
|
50
95
|
```
|
|
51
96
|
|
|
97
|
+
An unmatched target exits `1` with `No files matched: <targets>`.
|
|
98
|
+
|
|
52
99
|
## What each flag does
|
|
53
100
|
|
|
54
101
|
| Flag | What it fixes | Example |
|
|
@@ -57,10 +104,12 @@ npx tailwind-canonical --reporter sarif ./src
|
|
|
57
104
|
| `--dedup` | Redundant classes, conflicts, shorthand collapse | `flex block` → `block`, `px-4 py-4` → `p-4`, `border-t-2 border-b-2` → `border-y-2` |
|
|
58
105
|
| `--sort` | Canonical class order | `text-sm flex p-4` → `flex p-4 text-sm` |
|
|
59
106
|
| `--merge` | tailwind-merge conflict resolution | `bg-red-500 bg-blue-500` → `bg-blue-500` |
|
|
107
|
+
| `--check` | Dry-run: report what the combined transforms would change, write nothing (exit 1 on pending changes) | `would fix src/Button.tsx (1 replacement)` |
|
|
60
108
|
| `--analyze` | Cross-file consistency (color variants, scale drift, repeated patterns) | `Warning: 3 red color variants used for text: text-red-500, text-rose-500, text-red-600` |
|
|
61
109
|
| `--watch` | Re-run on every file save (debounced 50ms) | `[12:34:01] src/Button.tsx — 2 changes applied` |
|
|
110
|
+
| `--typos` | Likely misspelled color names (read-only; chains after transforms) | `text-gry-500` → `text-gray-500` [typo] |
|
|
62
111
|
| `--reporter json` | JSON output (check mode) or fix summary | machine-readable for CI pipelines |
|
|
63
|
-
| `--reporter sarif` | SARIF 2.1.0 output (check mode) | GitHub Code Scanning / VS Code |
|
|
112
|
+
| `--reporter sarif` | SARIF 2.1.0 output (findings in check/typos modes; transform mode emits an empty document unless `--typos` is chained) | GitHub Code Scanning / VS Code |
|
|
64
113
|
|
|
65
114
|
## Structured output (`--reporter`)
|
|
66
115
|
|
|
@@ -91,6 +140,15 @@ npx tailwind-canonical --fix --reporter json ./src
|
|
|
91
140
|
npx tailwind-canonical --reporter sarif ./src > results.sarif
|
|
92
141
|
```
|
|
93
142
|
|
|
143
|
+
**GitHub Actions integration:**
|
|
144
|
+
```yaml
|
|
145
|
+
- run: npx tailwind-canonical --reporter sarif ./src > results.sarif
|
|
146
|
+
continue-on-error: true
|
|
147
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
148
|
+
with:
|
|
149
|
+
sarif_file: results.sarif
|
|
150
|
+
```
|
|
151
|
+
|
|
94
152
|
## Typo detection (`--typos`)
|
|
95
153
|
|
|
96
154
|
Flags likely misspelled Tailwind color names (Levenshtein distance 1, low false-positive bias). Read-only.
|
|
@@ -103,6 +161,37 @@ npx tailwind-canonical --typos ./src
|
|
|
103
161
|
|
|
104
162
|
Only color-property classes (`text-`, `bg-`, `border-`, …) are checked. Valid colors, non-color utilities (`text-center`), custom colors (`bg-brand-500`), and arbitrary values are never flagged. Pairs with `--reporter json`; exits `1` on findings.
|
|
105
163
|
|
|
164
|
+
### Chaining with transforms
|
|
165
|
+
|
|
166
|
+
`--typos` combines with `--fix`/`--dedup`/`--merge`/`--sort`: the mutating pass runs first, then the typo scan — one command for lint-staged/CI:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
npx tailwind-canonical --fix --dedup --sort --typos ./src
|
|
170
|
+
# fixed src/Button.tsx (1 replacement)
|
|
171
|
+
# ✓ Fixed 1 replacement, 2 dedups, 3 sorted across 12 files
|
|
172
|
+
# src/Card.tsx:3:17 text-gry-500 → text-gray-500 [typo]
|
|
173
|
+
# ✖ Found 1 likely typo
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Exit code follows the typo scan (`1` on findings). With `--reporter json` the transform summary gains `typoTotal` and `typos` fields. `--analyze` remains exclusive: combining it with any other mode runs analyze only and warns. `--watch` is not supported with `--typos` (warned, single pass runs instead).
|
|
177
|
+
|
|
178
|
+
## Dry-run mode (`--check`)
|
|
179
|
+
|
|
180
|
+
Combine `--check` with any of `--fix`/`--dedup`/`--merge`/`--sort` to report what those transforms would change without writing anything to disk. Useful as a CI gate:
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
# CI
|
|
184
|
+
- run: npx tailwind-canonical --check --fix --dedup --sort ./src
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npx tailwind-canonical --check --fix --dedup --sort ./src
|
|
189
|
+
# would fix src/Button.tsx (1 replacement)
|
|
190
|
+
# ✖ 1 pending change across 1 file (run without --check to apply)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Exits `1` when any file would change (blocking the pipeline), `0` when the tree is already canonical. `--check` requires at least one transform flag; `--check` alone errors. `--analyze` takes priority over `--check` (warned, ignored). `--watch` is not supported with `--check` (warned, single pass runs instead). `--typos` still chains after the check pass since it's read-only. With `--reporter json` the transform report gains `"check": true`.
|
|
194
|
+
|
|
106
195
|
## Suppression comments
|
|
107
196
|
|
|
108
197
|
Skip specific lines or blocks from check and all transforms (`--fix`, `--dedup`, `--merge`, `--sort`):
|
|
@@ -290,6 +379,7 @@ export default {
|
|
|
290
379
|
dedup: true,
|
|
291
380
|
merge: true,
|
|
292
381
|
sort: true,
|
|
382
|
+
check: false, // dry-run mode: report changes without writing (useful for CI)
|
|
293
383
|
targets: ['./src'],
|
|
294
384
|
},
|
|
295
385
|
// Tune --analyze reporting
|
|
@@ -317,7 +407,7 @@ export default {
|
|
|
317
407
|
above, running `tailwind-canonical` is equivalent to
|
|
318
408
|
`tailwind-canonical --fix --dedup --merge --sort ./src`. Explicit CLI flags and
|
|
319
409
|
targets still override the config, so `tailwind-canonical --typos ./app` runs
|
|
320
|
-
only typo detection on `./app`.
|
|
410
|
+
only typo detection on `./app`. Supported keys: `fix`, `dedup`, `merge`, `sort`, `check`, `analyze`, `typos`, `watch`, `reporter`, `targets`.
|
|
321
411
|
|
|
322
412
|
`analyze` controls project-scale consistency reporting. `maxScaleGroups`,
|
|
323
413
|
`maxScaleValues`, `maxRareValues`, and `maxPatterns` keep terminal output
|
|
@@ -333,6 +423,16 @@ new configs should prefer `analyze`.
|
|
|
333
423
|
`tailwind-canonical.config.js` is still loaded as a fallback when no TypeScript
|
|
334
424
|
config exists.
|
|
335
425
|
|
|
426
|
+
The config is resolved upward from the current directory: if no config file is
|
|
427
|
+
found in `cwd`, tailwind-canonical checks each parent directory in turn, until
|
|
428
|
+
it finds one, reaches a `.git` directory, or reaches the filesystem root. This
|
|
429
|
+
makes the CLI monorepo-friendly — a single config at the repo root applies to
|
|
430
|
+
every package.
|
|
431
|
+
|
|
432
|
+
On Node 22.6–23.5, loading a `.ts` config requires `--experimental-strip-types`;
|
|
433
|
+
from Node 23.6 onward it works natively; the `.js` fallback works on every
|
|
434
|
+
supported Node version.
|
|
435
|
+
|
|
336
436
|
## ESLint plugin
|
|
337
437
|
|
|
338
438
|
```js
|
|
@@ -351,6 +451,15 @@ export default [
|
|
|
351
451
|
]
|
|
352
452
|
```
|
|
353
453
|
|
|
454
|
+
Or use the bundled flat-config shortcut:
|
|
455
|
+
|
|
456
|
+
```js
|
|
457
|
+
// eslint.config.js
|
|
458
|
+
import tailwindCanonical from 'tailwind-canonical/eslint'
|
|
459
|
+
|
|
460
|
+
export default [tailwindCanonical.configs.recommended]
|
|
461
|
+
```
|
|
462
|
+
|
|
354
463
|
### Rule options
|
|
355
464
|
|
|
356
465
|
`no-arbitrary-canonical` accepts the full tailwind-canonical `Config` object as
|
|
@@ -371,6 +480,12 @@ It **accepts but ignores**: `functionNames`, `attributeNames`, `sortOrder`.
|
|
|
371
480
|
These are CLI-only options, allowed in the schema purely so a single shared
|
|
372
481
|
config object can be passed without errors.
|
|
373
482
|
|
|
483
|
+
## Known limits
|
|
484
|
+
|
|
485
|
+
- **`--watch` does not pick up files created after start** — the watcher initializes a file list once and monitors only existing files for changes. New files in the target directories are not detected until the watcher is restarted.
|
|
486
|
+
- **`--typos` covers Tailwind color names only** — color-name detection uses Levenshtein distance 1 against the built-in Tailwind color palette. Custom colors from your config are supported via `extraColors` in the config, but typo detection does not extend to properties, function names, or arbitrary modifiers.
|
|
487
|
+
- **`--merge` requires `tailwind-merge` as a peer dependency** — the plugin is optional, so the CLI will error if you use `--merge` without installing `tailwind-merge`. Install with `pnpm add -D tailwind-merge`.
|
|
488
|
+
|
|
374
489
|
## Pre-commit hook (Husky / Lefthook)
|
|
375
490
|
|
|
376
491
|
```yaml
|
|
@@ -393,6 +508,17 @@ pre-commit:
|
|
|
393
508
|
npx tailwind-canonical --fix --dedup --sort ./src ./app
|
|
394
509
|
```
|
|
395
510
|
|
|
511
|
+
### lint-staged
|
|
512
|
+
|
|
513
|
+
```jsonc
|
|
514
|
+
// package.json
|
|
515
|
+
{
|
|
516
|
+
"lint-staged": {
|
|
517
|
+
"*.{jsx,tsx}": ["tailwind-canonical --fix --dedup --sort --typos"]
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
```
|
|
521
|
+
|
|
396
522
|
## Dead code detection (knip)
|
|
397
523
|
|
|
398
524
|
```bash
|
package/dist/cli/cli.d.ts
CHANGED
|
@@ -16,19 +16,24 @@ type Flags = {
|
|
|
16
16
|
watch: boolean;
|
|
17
17
|
analyze: boolean;
|
|
18
18
|
typos: boolean;
|
|
19
|
+
check: boolean;
|
|
20
|
+
help: boolean;
|
|
21
|
+
version: boolean;
|
|
19
22
|
reporter: Reporter;
|
|
20
23
|
targets: string[];
|
|
21
24
|
error?: string;
|
|
22
25
|
hasExplicitMode: boolean;
|
|
23
26
|
hasExplicitReporter: boolean;
|
|
24
27
|
hasExplicitWatch: boolean;
|
|
28
|
+
hasExplicitCheck: boolean;
|
|
25
29
|
};
|
|
26
30
|
export declare function parseArgs(argv: string[]): Flags;
|
|
27
31
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* order-stable so it can be
|
|
32
|
+
* `--analyze` is exclusive: it suppresses transforms, `--typos`, and
|
|
33
|
+
* `--watch`. `--typos` chains after transforms (fix → dedup → merge → sort →
|
|
34
|
+
* typo scan) but does not support `--watch`. This computes warnings for every
|
|
35
|
+
* flag the active mode will ignore. Pure and order-stable so it can be
|
|
36
|
+
* unit-tested via the injectable sink.
|
|
32
37
|
*/
|
|
33
38
|
export declare function flagWarnings(flags: Flags): string[];
|
|
34
39
|
export declare function run(argv: string[], cwd: string, sink?: Sink): Promise<RunResult>;
|
package/dist/cli/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":"AAgEA,MAAM,MAAM,IAAI,GAAG;IACjB,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5B,CAAC;AAQF,MAAM,MAAM,SAAS,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEjE,KAAK,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE1C,KAAK,KAAK,GAAG;IACX,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,OAAO,CAAC;IACzB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAyJF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAqE/C;AAgDD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,CAyBnD;AAgfD,wBAAsB,GAAG,CACvB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,IAAkB,GACvB,OAAO,CAAC,SAAS,CAAC,CA0RpB"}
|