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.
- package/README.md +103 -21
- package/dist/cli/cli.d.ts +2 -12
- package/dist/cli/cli.js +241 -512
- package/dist/cli/format.d.ts +3 -0
- package/dist/cli/format.js +11 -0
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +0 -1
- package/dist/cli/reporters.d.ts +69 -0
- package/dist/cli/reporters.js +333 -0
- package/dist/cli/types.d.ts +16 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/watch.d.ts +11 -0
- package/dist/cli/watch.js +33 -0
- package/dist/core/analyzer.d.ts +0 -1
- package/dist/core/analyzer.js +3 -3
- package/dist/core/class-strings.d.ts +0 -1
- package/dist/core/class-strings.js +13 -8
- package/dist/core/config.d.ts +2 -3
- package/dist/core/config.js +34 -44
- package/dist/core/consistency.d.ts +1 -2
- package/dist/core/consistency.js +1 -6
- package/dist/core/deduplicator.d.ts +0 -1
- package/dist/core/deduplicator.js +119 -175
- package/dist/core/fixer.d.ts +0 -1
- package/dist/core/fixer.js +0 -1
- package/dist/core/lexicon.d.ts +1 -1
- package/dist/core/lexicon.js +1 -2
- package/dist/core/merger.d.ts +0 -1
- package/dist/core/merger.js +41 -29
- package/dist/core/rules.d.ts +2 -1
- package/dist/core/rules.js +90 -57
- package/dist/core/scanner.d.ts +0 -1
- package/dist/core/scanner.js +23 -21
- package/dist/core/sorter.d.ts +0 -1
- package/dist/core/sorter.js +85 -10
- package/dist/core/suppressions.d.ts +1 -3
- package/dist/core/suppressions.js +17 -14
- package/dist/core/typos.d.ts +0 -1
- package/dist/core/typos.js +3 -3
- package/dist/eslint/plugin.d.ts +0 -1
- package/dist/eslint/plugin.js +64 -30
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/io/analyzer.d.ts +0 -1
- package/dist/io/analyzer.js +0 -1
- package/dist/io/config.d.ts +9 -1
- package/dist/io/config.js +66 -5
- package/dist/io/consistency.d.ts +0 -1
- package/dist/io/consistency.js +0 -1
- package/dist/io/deduplicator.d.ts +0 -1
- package/dist/io/deduplicator.js +0 -1
- package/dist/io/fixer.d.ts +0 -1
- package/dist/io/fixer.js +0 -1
- package/dist/io/merger.d.ts +0 -1
- package/dist/io/merger.js +0 -1
- package/dist/io/scanner.d.ts +0 -1
- package/dist/io/scanner.js +0 -1
- package/dist/io/sorter.d.ts +0 -1
- package/dist/io/sorter.js +0 -1
- package/dist/io/typos.d.ts +0 -1
- package/dist/io/typos.js +0 -1
- package/package.json +10 -9
- package/dist/cli/cli.d.ts.map +0 -1
- package/dist/cli/cli.js.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/core/analyzer.d.ts.map +0 -1
- package/dist/core/analyzer.js.map +0 -1
- package/dist/core/class-strings.d.ts.map +0 -1
- package/dist/core/class-strings.js.map +0 -1
- package/dist/core/config.d.ts.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/consistency.d.ts.map +0 -1
- package/dist/core/consistency.js.map +0 -1
- package/dist/core/deduplicator.d.ts.map +0 -1
- package/dist/core/deduplicator.js.map +0 -1
- package/dist/core/fixer.d.ts.map +0 -1
- package/dist/core/fixer.js.map +0 -1
- package/dist/core/lexicon.d.ts.map +0 -1
- package/dist/core/lexicon.js.map +0 -1
- package/dist/core/merger.d.ts.map +0 -1
- package/dist/core/merger.js.map +0 -1
- package/dist/core/rules.d.ts.map +0 -1
- package/dist/core/rules.js.map +0 -1
- package/dist/core/scanner.d.ts.map +0 -1
- package/dist/core/scanner.js.map +0 -1
- package/dist/core/sorter.d.ts.map +0 -1
- package/dist/core/sorter.js.map +0 -1
- package/dist/core/suppressions.d.ts.map +0 -1
- package/dist/core/suppressions.js.map +0 -1
- package/dist/core/typos.d.ts.map +0 -1
- package/dist/core/typos.js.map +0 -1
- package/dist/eslint/plugin.d.ts.map +0 -1
- package/dist/eslint/plugin.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/io/analyzer.d.ts.map +0 -1
- package/dist/io/analyzer.js.map +0 -1
- package/dist/io/config.d.ts.map +0 -1
- package/dist/io/config.js.map +0 -1
- package/dist/io/consistency.d.ts.map +0 -1
- package/dist/io/consistency.js.map +0 -1
- package/dist/io/deduplicator.d.ts.map +0 -1
- package/dist/io/deduplicator.js.map +0 -1
- package/dist/io/fixer.d.ts.map +0 -1
- package/dist/io/fixer.js.map +0 -1
- package/dist/io/merger.d.ts.map +0 -1
- package/dist/io/merger.js.map +0 -1
- package/dist/io/scanner.d.ts.map +0 -1
- package/dist/io/scanner.js.map +0 -1
- package/dist/io/sorter.d.ts.map +0 -1
- package/dist/io/sorter.js.map +0 -1
- package/dist/io/typos.d.ts.map +0 -1
- 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+
|
|
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
|
|
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` |
|
|
353
|
-
| `text-[8px]`–`text-[10px]` | `text-3xs` |
|
|
357
|
+
| `text-[11px]` | `text-2xs` | Requires `customTextTokens` |
|
|
358
|
+
| `text-[8px]`–`text-[10px]` | `text-3xs` | Requires `customTextTokens` |
|
|
354
359
|
|
|
355
|
-
`text-2xs`
|
|
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.
|
|
424
|
-
|
|
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,
|
|
535
|
-
analyzeFile,
|
|
536
|
-
fixFile,
|
|
537
|
-
deduplicateClasses,
|
|
538
|
-
dedupeFile,
|
|
539
|
-
sortClasses,
|
|
540
|
-
sortFile,
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
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
|
-
|
|
2
|
-
|
|
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
|