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 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 only)
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
- * Modes are mutually exclusive with a fixed precedence: analyze > typos >
29
- * transform/check. `--watch` is only honored in transform/check mode. This
30
- * computes warnings for every flag that the active mode will ignore. Pure and
31
- * order-stable so it can be unit-tested via the injectable sink.
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>;
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":"AAwBA,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,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;CAC3B,CAAC;AAmJF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAwD/C;AA6CD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,CAwBnD;AAgbD,wBAAsB,GAAG,CACvB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,IAAkB,GACvB,OAAO,CAAC,SAAS,CAAC,CAwLpB"}
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"}