tailwind-canonical 0.1.3 → 0.2.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 +252 -23
- package/dist/cli/index.js +253 -23
- package/dist/cli/index.js.map +1 -1
- package/dist/core/analyzer.d.ts.map +1 -1
- package/dist/core/analyzer.js +17 -11
- package/dist/core/analyzer.js.map +1 -1
- package/dist/core/class-strings.d.ts +14 -0
- package/dist/core/class-strings.d.ts.map +1 -0
- package/dist/core/class-strings.js +127 -0
- package/dist/core/class-strings.js.map +1 -0
- package/dist/core/consistency.d.ts +46 -0
- package/dist/core/consistency.d.ts.map +1 -0
- package/dist/core/consistency.js +252 -0
- package/dist/core/consistency.js.map +1 -0
- package/dist/core/deduplicator.d.ts +2 -1
- package/dist/core/deduplicator.d.ts.map +1 -1
- package/dist/core/deduplicator.js +341 -75
- package/dist/core/deduplicator.js.map +1 -1
- package/dist/core/fixer.d.ts.map +1 -1
- package/dist/core/fixer.js +14 -18
- package/dist/core/fixer.js.map +1 -1
- package/dist/core/merger.d.ts +2 -1
- package/dist/core/merger.d.ts.map +1 -1
- package/dist/core/merger.js +5 -14
- package/dist/core/merger.js.map +1 -1
- package/dist/core/rules.d.ts +4 -0
- package/dist/core/rules.d.ts.map +1 -1
- package/dist/core/rules.js +43 -55
- package/dist/core/rules.js.map +1 -1
- package/dist/core/scanner.d.ts +2 -1
- package/dist/core/scanner.d.ts.map +1 -1
- package/dist/core/scanner.js +105 -6
- package/dist/core/scanner.js.map +1 -1
- package/dist/core/sorter.d.ts +6 -0
- package/dist/core/sorter.d.ts.map +1 -0
- package/dist/core/sorter.js +166 -0
- package/dist/core/sorter.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# tailwind-canonical
|
|
2
2
|
|
|
3
|
-
Lint and auto-fix Tailwind CSS arbitrary values
|
|
3
|
+
Lint and auto-fix Tailwind CSS classes: arbitrary values → canonical, deduplication, shorthand collapsing, and class sorting.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -13,24 +13,212 @@ yarn add -D tailwind-canonical
|
|
|
13
13
|
## CLI
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
# Check
|
|
16
|
+
# Check for non-canonical arbitrary values
|
|
17
17
|
npx tailwind-canonical ./src
|
|
18
18
|
|
|
19
|
-
#
|
|
19
|
+
# Glob patterns (quote to prevent shell expansion)
|
|
20
|
+
npx tailwind-canonical 'src/**/*.tsx'
|
|
21
|
+
npx tailwind-canonical 'src/**/*.{tsx,ts}'
|
|
22
|
+
npx tailwind-canonical 'src/**/*.tsx' '!src/generated/**'
|
|
23
|
+
|
|
24
|
+
# Auto-fix: arbitrary → canonical
|
|
20
25
|
npx tailwind-canonical --fix ./src
|
|
26
|
+
|
|
27
|
+
# Deduplicate and collapse shorthands
|
|
28
|
+
npx tailwind-canonical --dedup ./src
|
|
29
|
+
|
|
30
|
+
# Sort classes into canonical order
|
|
31
|
+
npx tailwind-canonical --sort ./src
|
|
32
|
+
|
|
33
|
+
# Resolve conflicts with tailwind-merge (requires: pnpm add -D tailwind-merge)
|
|
34
|
+
npx tailwind-canonical --merge ./src
|
|
35
|
+
|
|
36
|
+
# Combine: fix → dedup → merge → sort
|
|
37
|
+
npx tailwind-canonical --fix --dedup --merge --sort ./src
|
|
38
|
+
|
|
39
|
+
# Cross-file consistency analysis
|
|
40
|
+
npx tailwind-canonical --analyze ./src
|
|
41
|
+
|
|
42
|
+
# Watch mode: re-run on every file save
|
|
43
|
+
npx tailwind-canonical --watch --fix --sort ./src
|
|
44
|
+
|
|
45
|
+
# Structured output for CI (check mode only)
|
|
46
|
+
npx tailwind-canonical --reporter json ./src
|
|
47
|
+
npx tailwind-canonical --reporter sarif ./src
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## What each flag does
|
|
51
|
+
|
|
52
|
+
| Flag | What it fixes | Example |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `--fix` | Arbitrary values → canonical tokens | `text-[12px]` → `text-xs` |
|
|
55
|
+
| `--dedup` | Redundant classes, conflicts, shorthand collapse | `flex block` → `block`, `px-4 py-4` → `p-4`, `border-t-2 border-b-2` → `border-y-2` |
|
|
56
|
+
| `--sort` | Canonical class order | `text-sm flex p-4` → `flex p-4 text-sm` |
|
|
57
|
+
| `--merge` | tailwind-merge conflict resolution | `bg-red-500 bg-blue-500` → `bg-blue-500` |
|
|
58
|
+
| `--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` |
|
|
59
|
+
| `--watch` | Re-run on every file save (debounced 50ms) | `[12:34:01] src/Button.tsx — 2 changes applied` |
|
|
60
|
+
| `--reporter json` | JSON output (check mode) or fix summary | machine-readable for CI pipelines |
|
|
61
|
+
| `--reporter sarif` | SARIF 2.1.0 output (check mode) | GitHub Code Scanning / VS Code |
|
|
62
|
+
|
|
63
|
+
## Structured output (`--reporter`)
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# JSON — check mode: outputs findings, exits 1 if any found
|
|
67
|
+
npx tailwind-canonical --reporter json ./src
|
|
68
|
+
```
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"files": 3,
|
|
72
|
+
"total": 2,
|
|
73
|
+
"findings": [
|
|
74
|
+
{ "file": "src/Button.tsx", "line": 12, "col": 17, "original": "text-[14px]", "canonical": "text-sm", "isCustomToken": false }
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# JSON — fix mode: outputs summary of changes
|
|
81
|
+
npx tailwind-canonical --fix --reporter json ./src
|
|
82
|
+
```
|
|
83
|
+
```json
|
|
84
|
+
{ "files": 3, "changedFiles": ["src/Button.tsx"], "fixed": 1, "deduped": 0, "merged": 0, "sorted": 0 }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# SARIF — compatible with GitHub Code Scanning and VS Code Problem Matcher
|
|
89
|
+
npx tailwind-canonical --reporter sarif ./src > results.sarif
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Cross-file consistency (`--analyze`)
|
|
93
|
+
|
|
94
|
+
Detects semantic inconsistencies visible only at project scale — it never modifies files.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npx tailwind-canonical --analyze ./src
|
|
98
|
+
# Warning: 3 red color variants used for text: text-red-500 (4), text-rose-500 (1), text-red-600 (2)
|
|
99
|
+
# Warning: px inconsistency: px-4 (8 files) vs px-3 (2 files)
|
|
100
|
+
# Warning: z inconsistency: z-[100] (3 files) vs z-[200] (1 file) vs z-[50] (2 files)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Three detectors:
|
|
104
|
+
|
|
105
|
+
| Detector | What it flags |
|
|
106
|
+
|---|---|
|
|
107
|
+
| Color variants | Multiple shades/colors of the same hue family used for one property (`text`, `bg`, `border`, …) |
|
|
108
|
+
| Scale inconsistency | Competing values for the same spacing / `gap` / `z` property across files |
|
|
109
|
+
| Repeated patterns | Identical class combinations recurring across 3+ files |
|
|
110
|
+
|
|
111
|
+
Pairs with `--reporter json` for machine-readable output. Exits `1` when any inconsistency is found.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npx tailwind-canonical --analyze --reporter json ./src
|
|
115
|
+
```
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"filesAnalyzed": 42,
|
|
119
|
+
"colorVariants": [
|
|
120
|
+
{ "property": "text", "family": "red",
|
|
121
|
+
"variants": [
|
|
122
|
+
{ "token": "red-500", "count": 4, "files": ["src/Alert.tsx"] },
|
|
123
|
+
{ "token": "rose-500", "count": 1, "files": ["src/Toast.tsx"] }
|
|
124
|
+
] }
|
|
125
|
+
],
|
|
126
|
+
"scaleInconsistencies": [
|
|
127
|
+
{ "property": "px",
|
|
128
|
+
"values": [
|
|
129
|
+
{ "value": "4", "count": 8, "files": ["src/Button.tsx"] },
|
|
130
|
+
{ "value": "3", "count": 2, "files": ["src/IconButton.tsx"] }
|
|
131
|
+
] }
|
|
132
|
+
],
|
|
133
|
+
"combinations": []
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Canonical class order (`--sort`)
|
|
138
|
+
|
|
139
|
+
`layout → position → display → flex/grid → sizing → border → spacing → typography → colors → effects → transitions → transforms → interactivity → a11y → variants`
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
// before
|
|
143
|
+
className="text-sm bg-red-500 flex h-10 w-full p-4 rounded"
|
|
144
|
+
|
|
145
|
+
// after
|
|
146
|
+
className="flex h-10 w-full rounded p-4 text-sm bg-red-500"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Variants (`hover:`, `sm:`, `focus:`) are sorted after base classes, with responsive breakpoints before state variants.
|
|
150
|
+
|
|
151
|
+
### Custom order (`sortOrder`)
|
|
152
|
+
|
|
153
|
+
Override the category order via config. Categories you omit (and unknown classes) sort to the end, preserving their original relative order. Variants are always sorted after base classes regardless of order.
|
|
154
|
+
|
|
155
|
+
```js
|
|
156
|
+
// tailwind-canonical.config.js
|
|
157
|
+
export default {
|
|
158
|
+
sortOrder: [
|
|
159
|
+
'display',
|
|
160
|
+
'position',
|
|
161
|
+
'sizing',
|
|
162
|
+
'spacing',
|
|
163
|
+
'border',
|
|
164
|
+
'typography',
|
|
165
|
+
'colors',
|
|
166
|
+
'effects',
|
|
167
|
+
],
|
|
168
|
+
}
|
|
21
169
|
```
|
|
22
170
|
|
|
23
|
-
|
|
171
|
+
Valid category names: `layout`, `position`, `inset`, `display`, `flex-grid`, `sizing`, `border`, `spacing`, `typography`, `colors`, `effects`, `transitions`, `transforms`, `interactivity`, `accessibility`. Omit `sortOrder` to use the default order above.
|
|
24
172
|
|
|
173
|
+
## Deduplication (`--dedup`)
|
|
174
|
+
|
|
175
|
+
### Exact duplicates and conflicts
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
flex flex flex → flex
|
|
179
|
+
flex block → block (last wins)
|
|
180
|
+
relative absolute → absolute
|
|
25
181
|
```
|
|
26
|
-
src/components/badge.tsx:12:18 text-[11px] → text-2xs [custom token]
|
|
27
|
-
src/components/card.tsx:34:5 h-[64px] → h-16
|
|
28
|
-
src/components/card.tsx:41:5 text-[12px] → text-xs
|
|
29
182
|
|
|
30
|
-
|
|
31
|
-
|
|
183
|
+
### Padding / margin shorthand collapse
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
px-4 py-4 → p-4
|
|
187
|
+
p-4 px-2 → py-4 px-2
|
|
188
|
+
pt-2 pb-2 → py-2
|
|
189
|
+
pl-4 pr-4 → px-4
|
|
190
|
+
mx-4 my-4 → m-4
|
|
32
191
|
```
|
|
33
192
|
|
|
193
|
+
### Border shorthand collapse
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
border-t-2 border-b-2 border-l-2 border-r-2 → border-2
|
|
197
|
+
border-t-2 border-b-2 → border-y-2
|
|
198
|
+
border-l-4 border-r-4 → border-x-4
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Inset shorthand collapse
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
top-4 right-4 bottom-4 left-4 → inset-4
|
|
205
|
+
top-4 bottom-4 → inset-y-4
|
|
206
|
+
left-2 right-2 → inset-x-2
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Arbitrary value detection (`--fix`)
|
|
210
|
+
|
|
211
|
+
| Arbitrary | Canonical | Notes |
|
|
212
|
+
|---|---|---|
|
|
213
|
+
| `text-[12px]` | `text-xs` | Built-in |
|
|
214
|
+
| `text-[0.75rem]` | `text-xs` | rem values |
|
|
215
|
+
| `h-[64px]` | `h-16` | Spacing scale ÷4 |
|
|
216
|
+
| `w-[50%]` | `w-1/2` | Percentage fractions |
|
|
217
|
+
| `opacity-[0.5]` | `opacity-50` | Opacity scale |
|
|
218
|
+
| `text-[11px]` | `text-2xs` | Custom token |
|
|
219
|
+
|
|
220
|
+
Non-divisible values (`h-[22px]`, `px-[7px]`) are left untouched.
|
|
221
|
+
|
|
34
222
|
## Config
|
|
35
223
|
|
|
36
224
|
Create `tailwind-canonical.config.js` at the root:
|
|
@@ -42,9 +230,22 @@ export default {
|
|
|
42
230
|
11: '2xs',
|
|
43
231
|
13: 'xxs',
|
|
44
232
|
},
|
|
233
|
+
customSpacingTokens: {
|
|
234
|
+
14: '3.5',
|
|
235
|
+
},
|
|
236
|
+
// Support non-React attribute patterns (default: ['className'])
|
|
237
|
+
attributeNames: ['className', 'class', ':class', 'tw'],
|
|
238
|
+
// Support utility function wrappers
|
|
239
|
+
functionNames: ['cn', 'clsx', 'cva'],
|
|
45
240
|
}
|
|
46
241
|
```
|
|
47
242
|
|
|
243
|
+
`customTextTokens` merges with the built-in text size map. `customSpacingTokens` supplements the default ÷4 spacing logic.
|
|
244
|
+
|
|
245
|
+
`attributeNames` controls which HTML/JSX attributes are scanned (default: `['className']`). Use `['class']` for plain HTML/PHP/Jinja templates, `[':class']` for Vue, `['tw']` for styled-components.
|
|
246
|
+
|
|
247
|
+
`functionNames` enables scanning inside utility function calls like `cn(...)` and `clsx(...)`.
|
|
248
|
+
|
|
48
249
|
## ESLint plugin
|
|
49
250
|
|
|
50
251
|
```js
|
|
@@ -56,28 +257,56 @@ export default [
|
|
|
56
257
|
plugins: { 'tailwind-canonical': tailwindCanonical },
|
|
57
258
|
rules: {
|
|
58
259
|
'tailwind-canonical/no-arbitrary-canonical': 'warn',
|
|
260
|
+
// Optional: flag tailwind-merge conflicts (requires tailwind-merge peer dep)
|
|
261
|
+
'tailwind-canonical/no-conflicting-classes': 'warn',
|
|
59
262
|
},
|
|
60
263
|
},
|
|
61
264
|
]
|
|
62
265
|
```
|
|
63
266
|
|
|
64
|
-
## Pre-commit hook (Husky)
|
|
267
|
+
## Pre-commit hook (Husky / Lefthook)
|
|
268
|
+
|
|
269
|
+
```yaml
|
|
270
|
+
# Lefthook: lefthook.yml
|
|
271
|
+
pre-commit:
|
|
272
|
+
parallel: true
|
|
273
|
+
commands:
|
|
274
|
+
tailwind:
|
|
275
|
+
glob: "src/**/*.{tsx,jsx}"
|
|
276
|
+
run: npx tailwind-canonical --fix --dedup --sort {staged_files}
|
|
277
|
+
stage_fixed: true
|
|
278
|
+
lint:
|
|
279
|
+
glob: "src/**/*.{ts,tsx,js,jsx,json}"
|
|
280
|
+
run: npx biome check --write --no-errors-on-unmatched {staged_files}
|
|
281
|
+
stage_fixed: true
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
# Husky: .husky/pre-commit
|
|
286
|
+
npx tailwind-canonical --fix --dedup --sort ./src ./app
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Dead code detection (knip)
|
|
65
290
|
|
|
66
291
|
```bash
|
|
67
|
-
|
|
68
|
-
npx tailwind-canonical ./src ./app
|
|
292
|
+
pnpm knip
|
|
69
293
|
```
|
|
70
294
|
|
|
71
|
-
|
|
295
|
+
Detects unused exports, files, and dependencies. Config in `knip.json`.
|
|
72
296
|
|
|
73
|
-
|
|
74
|
-
|---|---|---|
|
|
75
|
-
| `text-[12px]` | `text-xs` | Built-in |
|
|
76
|
-
| `text-[14px]` | `text-sm` | Built-in |
|
|
77
|
-
| `text-[11px]` | `text-2xs` | Custom token |
|
|
78
|
-
| `h-[64px]` | `h-16` | Spacing scale ÷4 |
|
|
79
|
-
| `w-[32px]` | `w-8` | Spacing scale ÷4 |
|
|
80
|
-
| `min-h-[56px]` | `min-h-14` | Spacing scale ÷4 |
|
|
81
|
-
| `max-w-[280px]` | `max-w-70` | Spacing scale ÷4 |
|
|
297
|
+
## Programmatic API
|
|
82
298
|
|
|
83
|
-
|
|
299
|
+
```ts
|
|
300
|
+
import {
|
|
301
|
+
suggestCanonical, // pure: class string → suggestion or null
|
|
302
|
+
analyzeFile, // find non-canonical classes in a file
|
|
303
|
+
fixFile, // apply --fix in-place
|
|
304
|
+
deduplicateClasses, // pure: deduplicate a class string
|
|
305
|
+
dedupeFile, // apply --dedup in-place
|
|
306
|
+
sortClasses, // pure: sort a class string
|
|
307
|
+
sortFile, // apply --sort in-place
|
|
308
|
+
mergeFile, // apply --merge in-place (requires tailwind-merge)
|
|
309
|
+
scanFiles, // recursive file scanner (sync, dir/file targets)
|
|
310
|
+
resolveTargets, // async glob resolver with negation + brace expansion
|
|
311
|
+
} from 'tailwind-canonical'
|
|
312
|
+
```
|
package/dist/cli/index.js
CHANGED
|
@@ -1,16 +1,39 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { watch as fsWatch } from 'node:fs';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
2
4
|
import { analyzeFile } from '../core/analyzer.js';
|
|
5
|
+
import { analyzeConsistencyFiles } from '../core/consistency.js';
|
|
3
6
|
import { dedupeFile } from '../core/deduplicator.js';
|
|
4
7
|
import { fixFile } from '../core/fixer.js';
|
|
5
8
|
import { mergeFile } from '../core/merger.js';
|
|
6
|
-
import {
|
|
9
|
+
import { resolveTargets } from '../core/scanner.js';
|
|
10
|
+
import { sortFile } from '../core/sorter.js';
|
|
11
|
+
function pluralize(n, word) {
|
|
12
|
+
return `${n} ${word}${n !== 1 ? 's' : ''}`;
|
|
13
|
+
}
|
|
14
|
+
function timestamp() {
|
|
15
|
+
const d = new Date();
|
|
16
|
+
return `[${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}:${d.getSeconds().toString().padStart(2, '0')}]`;
|
|
17
|
+
}
|
|
18
|
+
const SARIF_SCHEMA = 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json';
|
|
7
19
|
const args = process.argv.slice(2);
|
|
8
20
|
const fix = args.includes('--fix');
|
|
9
21
|
const merge = args.includes('--merge');
|
|
10
22
|
const dedup = args.includes('--dedup');
|
|
11
|
-
const
|
|
23
|
+
const sort = args.includes('--sort');
|
|
24
|
+
const watch = args.includes('--watch');
|
|
25
|
+
const analyze = args.includes('--analyze');
|
|
26
|
+
const reporterIdx = args.indexOf('--reporter');
|
|
27
|
+
const reporter = reporterIdx !== -1 &&
|
|
28
|
+
(args[reporterIdx + 1] === 'json' || args[reporterIdx + 1] === 'sarif')
|
|
29
|
+
? args[reporterIdx + 1]
|
|
30
|
+
: 'text';
|
|
31
|
+
const targets = args.filter((a, i) => !a.startsWith('--') &&
|
|
32
|
+
args[i - 1] !== '--reporter' &&
|
|
33
|
+
a !== 'json' &&
|
|
34
|
+
a !== 'sarif');
|
|
12
35
|
if (targets.length === 0) {
|
|
13
|
-
console.error('Usage: tailwind-canonical [--fix] [--merge] [--dedup] <dir|file> [dir|file...]');
|
|
36
|
+
console.error('Usage: tailwind-canonical [--fix] [--merge] [--dedup] [--sort] [--analyze] [--watch] [--reporter json|sarif] <dir|file> [dir|file...]');
|
|
14
37
|
process.exit(1);
|
|
15
38
|
}
|
|
16
39
|
if (merge) {
|
|
@@ -26,53 +49,260 @@ let config = {};
|
|
|
26
49
|
try {
|
|
27
50
|
const { default: userConfig } = await import(new URL(`file://${process.cwd()}/tailwind-canonical.config.js`).href);
|
|
28
51
|
config = userConfig;
|
|
52
|
+
// biome-ignore lint/suspicious/noEmptyBlockStatements: config file is optional
|
|
29
53
|
}
|
|
30
54
|
catch { }
|
|
31
|
-
|
|
55
|
+
async function processFile(file) {
|
|
56
|
+
let count = 0;
|
|
57
|
+
if (fix)
|
|
58
|
+
count += fixFile(file, config);
|
|
59
|
+
if (dedup)
|
|
60
|
+
count += dedupeFile(file, {
|
|
61
|
+
functionNames: config.functionNames,
|
|
62
|
+
attributeNames: config.attributeNames,
|
|
63
|
+
});
|
|
64
|
+
if (merge)
|
|
65
|
+
count += await mergeFile(file, {
|
|
66
|
+
functionNames: config.functionNames,
|
|
67
|
+
attributeNames: config.attributeNames,
|
|
68
|
+
});
|
|
69
|
+
if (sort)
|
|
70
|
+
count += sortFile(file, {
|
|
71
|
+
functionNames: config.functionNames,
|
|
72
|
+
attributeNames: config.attributeNames,
|
|
73
|
+
}, config.sortOrder);
|
|
74
|
+
return count;
|
|
75
|
+
}
|
|
76
|
+
const files = await resolveTargets(targets);
|
|
77
|
+
if (analyze) {
|
|
78
|
+
const report = analyzeConsistencyFiles(files, config);
|
|
79
|
+
const issueCount = report.colorVariants.length +
|
|
80
|
+
report.scaleInconsistencies.length +
|
|
81
|
+
report.combinations.length;
|
|
82
|
+
if (reporter === 'json') {
|
|
83
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
for (const group of report.colorVariants) {
|
|
87
|
+
const tokens = group.variants
|
|
88
|
+
.map((v) => `${group.property}-${v.token} (${v.count})`)
|
|
89
|
+
.join(', ');
|
|
90
|
+
console.log(` Warning: ${group.variants.length} ${group.family} color variants used for ${group.property}: ${tokens}`);
|
|
91
|
+
}
|
|
92
|
+
for (const scale of report.scaleInconsistencies) {
|
|
93
|
+
const values = scale.values
|
|
94
|
+
.map((v) => `${scale.property}-${v.value} (${pluralize(v.files.length, 'file')})`)
|
|
95
|
+
.join(' vs ');
|
|
96
|
+
console.log(` Warning: ${scale.property} inconsistency: ${values}`);
|
|
97
|
+
}
|
|
98
|
+
for (const combo of report.combinations) {
|
|
99
|
+
console.log(` Pattern: "${combo.classes.join(' ')}" repeated in ${pluralize(combo.files.length, 'file')}`);
|
|
100
|
+
}
|
|
101
|
+
if (issueCount === 0) {
|
|
102
|
+
console.log('✓ No cross-file inconsistencies found');
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.log(`\n✖ Found ${pluralize(issueCount, 'consistency issue')} across ${pluralize(report.filesAnalyzed, 'file')}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (issueCount > 0)
|
|
109
|
+
process.exit(1);
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
32
112
|
let totalFindings = 0;
|
|
33
113
|
let totalFixed = 0;
|
|
34
114
|
let totalMerged = 0;
|
|
35
115
|
let totalDeduped = 0;
|
|
116
|
+
let totalSorted = 0;
|
|
117
|
+
const allFindings = [];
|
|
118
|
+
const changedFiles = [];
|
|
36
119
|
for (const file of files) {
|
|
37
120
|
if (fix) {
|
|
38
121
|
const count = fixFile(file, config);
|
|
39
122
|
if (count > 0) {
|
|
40
|
-
console.log(` fixed ${file} (${count} replacement${count > 1 ? 's' : ''})`);
|
|
41
123
|
totalFixed += count;
|
|
124
|
+
changedFiles.push(file);
|
|
125
|
+
if (reporter === 'text') {
|
|
126
|
+
console.log(` fixed ${file} (${pluralize(count, 'replacement')})`);
|
|
127
|
+
}
|
|
42
128
|
}
|
|
43
129
|
}
|
|
44
130
|
if (dedup) {
|
|
45
|
-
const count = dedupeFile(file
|
|
131
|
+
const count = dedupeFile(file, {
|
|
132
|
+
functionNames: config.functionNames,
|
|
133
|
+
attributeNames: config.attributeNames,
|
|
134
|
+
});
|
|
46
135
|
if (count > 0) {
|
|
47
|
-
console.log(` deduped ${file} (${count} class string${count > 1 ? 's' : ''})`);
|
|
48
136
|
totalDeduped += count;
|
|
137
|
+
if (!changedFiles.includes(file))
|
|
138
|
+
changedFiles.push(file);
|
|
139
|
+
if (reporter === 'text') {
|
|
140
|
+
console.log(` deduped ${file} (${pluralize(count, 'class string')})`);
|
|
141
|
+
}
|
|
49
142
|
}
|
|
50
143
|
}
|
|
51
144
|
if (merge) {
|
|
52
|
-
const count = await mergeFile(file
|
|
145
|
+
const count = await mergeFile(file, {
|
|
146
|
+
functionNames: config.functionNames,
|
|
147
|
+
attributeNames: config.attributeNames,
|
|
148
|
+
});
|
|
53
149
|
if (count > 0) {
|
|
54
|
-
console.log(` merged ${file} (${count} conflict${count > 1 ? 's' : ''})`);
|
|
55
150
|
totalMerged += count;
|
|
151
|
+
if (!changedFiles.includes(file))
|
|
152
|
+
changedFiles.push(file);
|
|
153
|
+
if (reporter === 'text') {
|
|
154
|
+
console.log(` merged ${file} (${pluralize(count, 'conflict')})`);
|
|
155
|
+
}
|
|
56
156
|
}
|
|
57
157
|
}
|
|
58
|
-
if (
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
158
|
+
if (sort) {
|
|
159
|
+
const count = sortFile(file, {
|
|
160
|
+
functionNames: config.functionNames,
|
|
161
|
+
attributeNames: config.attributeNames,
|
|
162
|
+
}, config.sortOrder);
|
|
163
|
+
if (count > 0) {
|
|
164
|
+
totalSorted += count;
|
|
165
|
+
if (!changedFiles.includes(file))
|
|
166
|
+
changedFiles.push(file);
|
|
167
|
+
if (reporter === 'text') {
|
|
168
|
+
console.log(` sorted ${file} (${pluralize(count, 'class string')})`);
|
|
169
|
+
}
|
|
63
170
|
}
|
|
171
|
+
}
|
|
172
|
+
if (!(fix || dedup || merge || sort)) {
|
|
173
|
+
const findings = analyzeFile(file, config);
|
|
174
|
+
allFindings.push(...findings);
|
|
64
175
|
totalFindings += findings.length;
|
|
176
|
+
if (reporter === 'text' && !watch) {
|
|
177
|
+
for (const f of findings) {
|
|
178
|
+
const tag = f.suggestion.isCustomToken ? ' [custom token]' : '';
|
|
179
|
+
console.log(` ${f.file}:${f.line}:${f.col} ${f.suggestion.original} → ${f.suggestion.canonical}${tag}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
65
182
|
}
|
|
66
183
|
}
|
|
67
|
-
if (
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
184
|
+
if (watch) {
|
|
185
|
+
const fileSet = new Set(files);
|
|
186
|
+
const timers = new Map();
|
|
187
|
+
const dirs = new Set(files.map((f) => dirname(f)));
|
|
188
|
+
console.log(`Watching ${pluralize(files.length, 'file')}... (Ctrl+C to stop)`);
|
|
189
|
+
for (const dir of dirs) {
|
|
190
|
+
fsWatch(dir, { recursive: true }, (_, filename) => {
|
|
191
|
+
if (!filename)
|
|
192
|
+
return;
|
|
193
|
+
const full = resolve(dir, filename);
|
|
194
|
+
if (!fileSet.has(full))
|
|
195
|
+
return;
|
|
196
|
+
clearTimeout(timers.get(full));
|
|
197
|
+
timers.set(full, setTimeout(() => {
|
|
198
|
+
if (fix || dedup || merge || sort) {
|
|
199
|
+
processFile(full)
|
|
200
|
+
.then((count) => {
|
|
201
|
+
if (count > 0)
|
|
202
|
+
console.log(`${timestamp()} ${full} — ${pluralize(count, 'change')} applied`);
|
|
203
|
+
})
|
|
204
|
+
// biome-ignore lint/suspicious/noEmptyBlockStatements: watcher errors are silent by design
|
|
205
|
+
.catch(() => { });
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
const findings = analyzeFile(full, config);
|
|
209
|
+
if (findings.length > 0) {
|
|
210
|
+
console.log(`${timestamp()} ${full} — ${pluralize(findings.length, 'finding')}`);
|
|
211
|
+
for (const f of findings) {
|
|
212
|
+
const tag = f.suggestion.isCustomToken ? ' [custom token]' : '';
|
|
213
|
+
console.log(` ${f.line}:${f.col} ${f.suggestion.original} → ${f.suggestion.canonical}${tag}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}, 50));
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
process.on('SIGINT', () => {
|
|
221
|
+
console.log('\nWatcher stopped.');
|
|
222
|
+
process.exit(0);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
else if (fix || dedup || merge || sort) {
|
|
226
|
+
if (reporter === 'json') {
|
|
227
|
+
process.stdout.write(`${JSON.stringify({
|
|
228
|
+
files: files.length,
|
|
229
|
+
changedFiles,
|
|
230
|
+
fixed: totalFixed,
|
|
231
|
+
deduped: totalDeduped,
|
|
232
|
+
merged: totalMerged,
|
|
233
|
+
sorted: totalSorted,
|
|
234
|
+
}, null, 2)}\n`);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
const parts = [];
|
|
238
|
+
if (fix)
|
|
239
|
+
parts.push(pluralize(totalFixed, 'replacement'));
|
|
240
|
+
if (dedup)
|
|
241
|
+
parts.push(pluralize(totalDeduped, 'dedup'));
|
|
242
|
+
if (merge)
|
|
243
|
+
parts.push(`${pluralize(totalMerged, 'conflict')} merged`);
|
|
244
|
+
if (sort)
|
|
245
|
+
parts.push(`${totalSorted} sorted`);
|
|
246
|
+
console.log(`\n✓ Fixed ${parts.join(', ')} across ${files.length} file${files.length !== 1 ? 's' : ''}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else if (reporter === 'json') {
|
|
250
|
+
process.stdout.write(`${JSON.stringify({
|
|
251
|
+
files: files.length,
|
|
252
|
+
total: totalFindings,
|
|
253
|
+
findings: allFindings.map((f) => ({
|
|
254
|
+
file: f.file,
|
|
255
|
+
line: f.line,
|
|
256
|
+
col: f.col,
|
|
257
|
+
original: f.suggestion.original,
|
|
258
|
+
canonical: f.suggestion.canonical,
|
|
259
|
+
isCustomToken: f.suggestion.isCustomToken,
|
|
260
|
+
})),
|
|
261
|
+
}, null, 2)}\n`);
|
|
262
|
+
if (totalFindings > 0)
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
else if (reporter === 'sarif') {
|
|
266
|
+
const sarifOutput = {
|
|
267
|
+
$schema: SARIF_SCHEMA,
|
|
268
|
+
version: '2.1.0',
|
|
269
|
+
runs: [
|
|
270
|
+
{
|
|
271
|
+
tool: {
|
|
272
|
+
driver: {
|
|
273
|
+
name: 'tailwind-canonical',
|
|
274
|
+
informationUri: 'https://github.com/peak-lab/tailwind-canonical',
|
|
275
|
+
rules: [
|
|
276
|
+
{
|
|
277
|
+
id: 'no-arbitrary-canonical',
|
|
278
|
+
name: 'NoArbitraryCanonical',
|
|
279
|
+
shortDescription: {
|
|
280
|
+
text: 'Arbitrary value has a canonical Tailwind equivalent',
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
results: allFindings.map((f) => ({
|
|
287
|
+
ruleId: 'no-arbitrary-canonical',
|
|
288
|
+
message: {
|
|
289
|
+
text: `${f.suggestion.original} → ${f.suggestion.canonical}`,
|
|
290
|
+
},
|
|
291
|
+
locations: [
|
|
292
|
+
{
|
|
293
|
+
physicalLocation: {
|
|
294
|
+
artifactLocation: { uri: f.file },
|
|
295
|
+
region: { startLine: f.line, startColumn: f.col },
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
})),
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
};
|
|
303
|
+
process.stdout.write(`${JSON.stringify(sarifOutput, null, 2)}\n`);
|
|
304
|
+
if (totalFindings > 0)
|
|
305
|
+
process.exit(1);
|
|
76
306
|
}
|
|
77
307
|
else if (totalFindings > 0) {
|
|
78
308
|
console.log(`\n✖ Found ${totalFindings} non-canonical class${totalFindings !== 1 ? 'es' : ''}`);
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|