tailwind-canonical 0.6.0 → 0.7.1

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.
Files changed (114) hide show
  1. package/README.md +103 -21
  2. package/dist/cli/cli.d.ts +2 -12
  3. package/dist/cli/cli.js +241 -512
  4. package/dist/cli/format.d.ts +3 -0
  5. package/dist/cli/format.js +11 -0
  6. package/dist/cli/index.d.ts +0 -1
  7. package/dist/cli/index.js +0 -1
  8. package/dist/cli/reporters.d.ts +69 -0
  9. package/dist/cli/reporters.js +333 -0
  10. package/dist/cli/types.d.ts +16 -0
  11. package/dist/cli/types.js +1 -0
  12. package/dist/cli/watch.d.ts +11 -0
  13. package/dist/cli/watch.js +33 -0
  14. package/dist/core/analyzer.d.ts +0 -1
  15. package/dist/core/analyzer.js +3 -3
  16. package/dist/core/class-strings.d.ts +0 -1
  17. package/dist/core/class-strings.js +13 -8
  18. package/dist/core/config.d.ts +2 -3
  19. package/dist/core/config.js +34 -44
  20. package/dist/core/consistency.d.ts +1 -2
  21. package/dist/core/consistency.js +1 -6
  22. package/dist/core/deduplicator.d.ts +0 -1
  23. package/dist/core/deduplicator.js +119 -175
  24. package/dist/core/fixer.d.ts +0 -1
  25. package/dist/core/fixer.js +0 -1
  26. package/dist/core/lexicon.d.ts +1 -1
  27. package/dist/core/lexicon.js +1 -2
  28. package/dist/core/merger.d.ts +0 -1
  29. package/dist/core/merger.js +41 -29
  30. package/dist/core/rules.d.ts +2 -1
  31. package/dist/core/rules.js +90 -57
  32. package/dist/core/scanner.d.ts +0 -1
  33. package/dist/core/scanner.js +23 -21
  34. package/dist/core/sorter.d.ts +0 -1
  35. package/dist/core/sorter.js +85 -10
  36. package/dist/core/suppressions.d.ts +1 -3
  37. package/dist/core/suppressions.js +17 -14
  38. package/dist/core/typos.d.ts +0 -1
  39. package/dist/core/typos.js +3 -3
  40. package/dist/eslint/plugin.d.ts +0 -1
  41. package/dist/eslint/plugin.js +64 -30
  42. package/dist/index.d.ts +1 -2
  43. package/dist/index.js +1 -2
  44. package/dist/io/analyzer.d.ts +0 -1
  45. package/dist/io/analyzer.js +0 -1
  46. package/dist/io/config.d.ts +9 -1
  47. package/dist/io/config.js +66 -5
  48. package/dist/io/consistency.d.ts +0 -1
  49. package/dist/io/consistency.js +0 -1
  50. package/dist/io/deduplicator.d.ts +0 -1
  51. package/dist/io/deduplicator.js +0 -1
  52. package/dist/io/fixer.d.ts +0 -1
  53. package/dist/io/fixer.js +0 -1
  54. package/dist/io/merger.d.ts +0 -1
  55. package/dist/io/merger.js +0 -1
  56. package/dist/io/scanner.d.ts +0 -1
  57. package/dist/io/scanner.js +0 -1
  58. package/dist/io/sorter.d.ts +0 -1
  59. package/dist/io/sorter.js +0 -1
  60. package/dist/io/typos.d.ts +0 -1
  61. package/dist/io/typos.js +0 -1
  62. package/package.json +10 -9
  63. package/dist/cli/cli.d.ts.map +0 -1
  64. package/dist/cli/cli.js.map +0 -1
  65. package/dist/cli/index.d.ts.map +0 -1
  66. package/dist/cli/index.js.map +0 -1
  67. package/dist/core/analyzer.d.ts.map +0 -1
  68. package/dist/core/analyzer.js.map +0 -1
  69. package/dist/core/class-strings.d.ts.map +0 -1
  70. package/dist/core/class-strings.js.map +0 -1
  71. package/dist/core/config.d.ts.map +0 -1
  72. package/dist/core/config.js.map +0 -1
  73. package/dist/core/consistency.d.ts.map +0 -1
  74. package/dist/core/consistency.js.map +0 -1
  75. package/dist/core/deduplicator.d.ts.map +0 -1
  76. package/dist/core/deduplicator.js.map +0 -1
  77. package/dist/core/fixer.d.ts.map +0 -1
  78. package/dist/core/fixer.js.map +0 -1
  79. package/dist/core/lexicon.d.ts.map +0 -1
  80. package/dist/core/lexicon.js.map +0 -1
  81. package/dist/core/merger.d.ts.map +0 -1
  82. package/dist/core/merger.js.map +0 -1
  83. package/dist/core/rules.d.ts.map +0 -1
  84. package/dist/core/rules.js.map +0 -1
  85. package/dist/core/scanner.d.ts.map +0 -1
  86. package/dist/core/scanner.js.map +0 -1
  87. package/dist/core/sorter.d.ts.map +0 -1
  88. package/dist/core/sorter.js.map +0 -1
  89. package/dist/core/suppressions.d.ts.map +0 -1
  90. package/dist/core/suppressions.js.map +0 -1
  91. package/dist/core/typos.d.ts.map +0 -1
  92. package/dist/core/typos.js.map +0 -1
  93. package/dist/eslint/plugin.d.ts.map +0 -1
  94. package/dist/eslint/plugin.js.map +0 -1
  95. package/dist/index.d.ts.map +0 -1
  96. package/dist/index.js.map +0 -1
  97. package/dist/io/analyzer.d.ts.map +0 -1
  98. package/dist/io/analyzer.js.map +0 -1
  99. package/dist/io/config.d.ts.map +0 -1
  100. package/dist/io/config.js.map +0 -1
  101. package/dist/io/consistency.d.ts.map +0 -1
  102. package/dist/io/consistency.js.map +0 -1
  103. package/dist/io/deduplicator.d.ts.map +0 -1
  104. package/dist/io/deduplicator.js.map +0 -1
  105. package/dist/io/fixer.d.ts.map +0 -1
  106. package/dist/io/fixer.js.map +0 -1
  107. package/dist/io/merger.d.ts.map +0 -1
  108. package/dist/io/merger.js.map +0 -1
  109. package/dist/io/scanner.d.ts.map +0 -1
  110. package/dist/io/scanner.js.map +0 -1
  111. package/dist/io/sorter.d.ts.map +0 -1
  112. package/dist/io/sorter.js.map +0 -1
  113. package/dist/io/typos.d.ts.map +0 -1
  114. package/dist/io/typos.js.map +0 -1
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Lint and auto-fix Tailwind CSS classes: arbitrary values → canonical, deduplication, shorthand collapsing, and class sorting.
4
4
 
5
- > Compatible with Tailwind CSS v3.3+ and v4 — zero `tailwindcss` dependency (conventions are built in). Custom theme tokens are supported via config.
5
+ > Compatible with Tailwind CSS v4 out of the box, and with v3.3+ via [`tailwindVersion: 3`](#tailwind-v3-vs-v4-tailwindversion) — the ÷4 spacing rule assumes v4's dynamic scale, so v3 projects must set it. Zero `tailwindcss` dependency (conventions are built in). Custom theme tokens are supported via config.
6
6
 
7
7
  ## Install
8
8
 
@@ -50,7 +50,7 @@ For pre-commit automation, see the [Pre-commit hook](#pre-commit-hook-husky--lef
50
50
  ## CLI
51
51
 
52
52
  ```bash
53
- # Scaffold a tailwind-canonical.config.ts in the current directory
53
+ # Scaffold a config in the current directory (.ts, or .js/.mjs on older Node)
54
54
  npx tailwind-canonical init
55
55
 
56
56
  # Check for non-canonical arbitrary values
@@ -140,6 +140,11 @@ npx tailwind-canonical --fix --reporter json ./src
140
140
  npx tailwind-canonical --reporter sarif ./src > results.sarif
141
141
  ```
142
142
 
143
+ Each result's `artifactLocation.uri` is relative to the git root (falling back to the working
144
+ directory), with `uriBaseId: "%SRCROOT%"`, so Code Scanning maps it from any subdirectory.
145
+ Results also carry `level`, a full `region` (start/end column) and line-independent
146
+ `partialFingerprints`; `tool.driver.version` records the emitting version.
147
+
143
148
  **GitHub Actions integration:**
144
149
  ```yaml
145
150
  - run: npx tailwind-canonical --reporter sarif ./src > results.sarif
@@ -349,13 +354,63 @@ left-2 right-2 → inset-x-2
349
354
  | `h-[64px]` | `h-16` | Spacing scale ÷4 |
350
355
  | `w-[50%]` | `w-1/2` | Percentage fractions |
351
356
  | `opacity-[0.5]` | `opacity-50` | Opacity scale |
352
- | `text-[11px]` | `text-2xs` | Built-in extra token |
353
- | `text-[8px]`–`text-[10px]` | `text-3xs` | Built-in extra token |
357
+ | `text-[11px]` | `text-2xs` | Requires `customTextTokens` |
358
+ | `text-[8px]`–`text-[10px]` | `text-3xs` | Requires `customTextTokens` |
354
359
 
355
- `text-2xs` (11px) and `text-3xs` (8–10px) are part of the built-in text size map — they convert with no config. Override or extend the map via `customTextTokens`.
360
+ `text-2xs` and `text-3xs` are not stock Tailwind tokens, so they are not in the built-in text size map — without config, `text-[11px]` and `text-[8px]`–`text-[10px]` are left untouched. Enable them with `customTextTokens`:
361
+
362
+ ```ts
363
+ export default { customTextTokens: { 8: '3xs', 9: '3xs', 10: '3xs', 11: '2xs' } }
364
+ ```
356
365
 
357
366
  Non-divisible values (`h-[22px]`, `px-[7px]`) are left untouched.
358
367
 
368
+ ### Tailwind v3 vs v4 (`tailwindVersion`)
369
+
370
+ The ÷4 spacing rule assumes the **v4** scale, where every step is derived from
371
+ `calc(var(--spacing) * n)` and any integer works. v3 ships a discrete scale, so
372
+ `p-[52px]` → `p-13` compiles to nothing at all on v3 and the padding silently
373
+ disappears. Set `tailwindVersion: 3` on a v3 project:
374
+
375
+ ```ts
376
+ export default {
377
+ tailwindVersion: 3, // default: 4
378
+ }
379
+ ```
380
+
381
+ In v3 mode, suggestions are restricted to what v3.3 actually generates — the
382
+ scale differs per utility, not just per family:
383
+
384
+ | Class | `tailwindVersion: 4` | `tailwindVersion: 3` |
385
+ |---|---|---|
386
+ | `p-[16px]` | `p-4` | `p-4` |
387
+ | `p-[52px]` | `p-13` | untouched — not on the v3 scale |
388
+ | `max-w-[16px]` | `max-w-4` | untouched — scale arrived after v3.3 |
389
+ | `max-w-[0px]` | `max-w-0` | `max-w-0` — the zero step does exist |
390
+ | `size-[16px]` | `size-4` | untouched — no scale at all in v3.3 |
391
+ | `max-h-[16px]` | `max-h-4` | `max-h-4` |
392
+ | `max-w-[50%]` | `max-w-1/2` | untouched — no fractions in v3.3 |
393
+ | `top-[20%]` | `top-1/5` | untouched — v3.3 stops at quarters here |
394
+ | `top-[25%]` | `top-1/4` | `top-1/4` |
395
+ | `w-[8.333333%]` | `w-1/12` | `w-1/12` — `w` carries the full set |
396
+
397
+ Spacing steps: `size-*` has no numeric scale in v3.3, and `min-w-*`, `max-w-*`
398
+ and `min-h-*` only ship the zero step — they gained the scale afterwards.
399
+ Fractions: `w` carries all thirteen, `h` stops at sixths, `inset`/`top`/`left`/
400
+ `right`/`bottom`/`translate-x`/`translate-y` only have halves, thirds and
401
+ quarters, and `min-w`/`max-w`/`min-h`/`max-h` have none.
402
+
403
+ `text-*`, `rounded-*` and `opacity-*` are identical in both majors and are
404
+ never gated. `customSpacingTokens` stays your decision and is applied in both
405
+ modes. All of the above was measured against `tailwindcss@3.3.7`, the
406
+ advertised floor.
407
+
408
+ **On v3.4**, keep `tailwindVersion: 3`. v3.4 added the numeric scale to
409
+ `size-*`, `min-w-*`, `max-w-*` and `min-h-*`, but its spacing scale is still
410
+ discrete — `p-13` does not exist there either. So v3 mode is the safe setting
411
+ and merely leaves a few v3.4-valid suggestions on the table; `tailwindVersion:
412
+ 4` would emit steps v3.4 cannot generate.
413
+
359
414
  ## Config
360
415
 
361
416
  Create `tailwind-canonical.config.ts` at the root:
@@ -369,6 +424,8 @@ export default {
369
424
  customSpacingTokens: {
370
425
  14: '3.5',
371
426
  },
427
+ // Target Tailwind major: 3 restricts suggestions to the v3 scale (default: 4)
428
+ tailwindVersion: 4,
372
429
  // Support non-React attribute patterns (default: ['className'])
373
430
  attributeNames: ['className', 'class', ':class', 'tw'],
374
431
  // Support utility function wrappers
@@ -420,8 +477,15 @@ files and at most 3 times.
420
477
  The older top-level rare-value keys are still accepted for compatibility, but
421
478
  new configs should prefer `analyze`.
422
479
 
423
- `tailwind-canonical.config.js` is still loaded as a fallback when no TypeScript
424
- config exists.
480
+ Accepted filenames, in resolution order: `tailwind-canonical.config.ts`,
481
+ `.mts`, `.js`, `.mjs`.
482
+
483
+ A `.ts` or `.mts` config needs Node's type stripping, which is on by default
484
+ from Node 22.18 and 23.6, and available behind `--experimental-strip-types`
485
+ from 22.6. Short of that use `.mjs`, or `.js` when your nearest `package.json`
486
+ declares `"type": "module"`; both load on every supported Node. `tailwind-
487
+ canonical init` scaffolds a filename that loads on a bare `node` — it will not
488
+ write `.ts` just because the process it runs in happens to carry the flag.
425
489
 
426
490
  The config is resolved upward from the current directory: if no config file is
427
491
  found in `cwd`, tailwind-canonical checks each parent directory in turn, until
@@ -429,10 +493,6 @@ it finds one, reaches a `.git` directory, or reaches the filesystem root. This
429
493
  makes the CLI monorepo-friendly — a single config at the repo root applies to
430
494
  every package.
431
495
 
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
-
436
496
  ## ESLint plugin
437
497
 
438
498
  ```js
@@ -531,15 +591,37 @@ Detects unused exports, files, and dependencies. Config in `knip.json`. Enforced
531
591
 
532
592
  ```ts
533
593
  import {
534
- suggestCanonical, // pure: class string → suggestion or null
535
- analyzeFile, // find non-canonical classes in a file
536
- fixFile, // apply --fix in-place
537
- deduplicateClasses, // pure: deduplicate a class string
538
- dedupeFile, // apply --dedup in-place
539
- sortClasses, // pure: sort a class string
540
- sortFile, // apply --sort in-place
541
- mergeFile, // apply --merge in-place (requires tailwind-merge)
542
- scanFiles, // recursive file scanner (sync, dir/file targets)
543
- resolveTargets, // async glob resolver with negation + brace expansion
594
+ suggestCanonical, // pure: class string → suggestion or null
595
+ analyzeFile, // find non-canonical classes in a file
596
+ fixFile, // apply --fix in-place
597
+ deduplicateClasses, // pure: deduplicate a class string
598
+ dedupeFile, // apply --dedup in-place
599
+ sortClasses, // pure: sort a class string
600
+ sortFile, // apply --sort in-place
601
+ DEFAULT_SORT_ORDER, // default sort category order (override via config sortOrder)
602
+ mergeFile, // apply --merge in-place (requires tailwind-merge)
603
+ scanFiles, // recursive file scanner (sync, dir/file targets)
604
+ resolveTargets, // async glob resolver with negation + brace expansion
605
+ loadConfig, // load + validate tailwind-canonical.config.{ts,mts,js,mjs} for a cwd
606
+ analyzeConsistency, // pure: cross-file consistency analysis (--analyze)
607
+ analyzeTyposFile, // find likely color-name typos in a file
608
+ detectTypo, // pure: check one class for a likely color-name typo
609
+ } from 'tailwind-canonical'
610
+
611
+ import type {
612
+ Config, // shared config object accepted across the API
613
+ Suggestion, // suggestCanonical's non-null return shape
614
+ Finding, // one entry returned by analyzeFile
615
+ ScanOptions, // extensions/ignore options for scanFiles/resolveTargets
616
+ SortCategory, // one entry of DEFAULT_SORT_ORDER / config.sortOrder
617
+ TypoFinding, // one entry returned by analyzeTyposFile
618
+ ConsistencyOptions, // options accepted by analyzeConsistency
619
+ ConsistencyReport, // analyzeConsistency's return shape
620
+ FileClasses, // per-file input shape for analyzeConsistency
621
+ ColorVariant, // one variant inside a ConsistencyReport color group
622
+ ColorVariantGroup, // one color-family group in ConsistencyReport.colorVariants
623
+ ScaleInconsistency, // one entry in ConsistencyReport.scaleInconsistencies
624
+ ScaleValue, // one value inside a ScaleInconsistency
625
+ ClassCombination, // one repeated-pattern entry in ConsistencyReport.combinations
544
626
  } from 'tailwind-canonical'
545
627
  ```
package/dist/cli/cli.d.ts CHANGED
@@ -1,13 +1,5 @@
1
- export type Sink = {
2
- log: (s: string) => void;
3
- error: (s: string) => void;
4
- write: (s: string) => void;
5
- };
6
- export type RunResult = {
7
- exitCode: number;
8
- watching?: boolean;
9
- };
10
- type Reporter = 'text' | 'json' | 'sarif';
1
+ import type { Reporter, RunResult, Sink } from './types.js';
2
+ export type { RunResult, Sink } from './types.js';
11
3
  type Flags = {
12
4
  fix: boolean;
13
5
  merge: boolean;
@@ -37,5 +29,3 @@ export declare function parseArgs(argv: string[]): Flags;
37
29
  */
38
30
  export declare function flagWarnings(flags: Flags): string[];
39
31
  export declare function run(argv: string[], cwd: string, sink?: Sink): Promise<RunResult>;
40
- export {};
41
- //# sourceMappingURL=cli.d.ts.map