tailwind-canonical 0.2.2 → 0.4.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.
Files changed (104) hide show
  1. package/README.md +58 -4
  2. package/dist/cli/cli.d.ts +33 -0
  3. package/dist/cli/cli.d.ts.map +1 -0
  4. package/dist/cli/cli.js +416 -0
  5. package/dist/cli/cli.js.map +1 -0
  6. package/dist/cli/index.js +4 -315
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/core/analyzer.d.ts +2 -1
  9. package/dist/core/analyzer.d.ts.map +1 -1
  10. package/dist/core/analyzer.js +8 -14
  11. package/dist/core/analyzer.js.map +1 -1
  12. package/dist/core/class-strings.d.ts +6 -1
  13. package/dist/core/class-strings.d.ts.map +1 -1
  14. package/dist/core/class-strings.js +19 -8
  15. package/dist/core/class-strings.js.map +1 -1
  16. package/dist/core/config.d.ts +2 -1
  17. package/dist/core/config.d.ts.map +1 -1
  18. package/dist/core/config.js +20 -11
  19. package/dist/core/config.js.map +1 -1
  20. package/dist/core/consistency.d.ts +6 -1
  21. package/dist/core/consistency.d.ts.map +1 -1
  22. package/dist/core/consistency.js +38 -101
  23. package/dist/core/consistency.js.map +1 -1
  24. package/dist/core/deduplicator.d.ts +5 -1
  25. package/dist/core/deduplicator.d.ts.map +1 -1
  26. package/dist/core/deduplicator.js +26 -17
  27. package/dist/core/deduplicator.js.map +1 -1
  28. package/dist/core/fixer.d.ts +5 -1
  29. package/dist/core/fixer.d.ts.map +1 -1
  30. package/dist/core/fixer.js +8 -10
  31. package/dist/core/fixer.js.map +1 -1
  32. package/dist/core/lexicon.d.ts +16 -0
  33. package/dist/core/lexicon.d.ts.map +1 -0
  34. package/dist/core/lexicon.js +133 -0
  35. package/dist/core/lexicon.js.map +1 -0
  36. package/dist/core/merger.d.ts +5 -1
  37. package/dist/core/merger.d.ts.map +1 -1
  38. package/dist/core/merger.js +7 -8
  39. package/dist/core/merger.js.map +1 -1
  40. package/dist/core/rules.d.ts +3 -0
  41. package/dist/core/rules.d.ts.map +1 -1
  42. package/dist/core/rules.js +15 -1
  43. package/dist/core/rules.js.map +1 -1
  44. package/dist/core/scanner.d.ts +5 -2
  45. package/dist/core/scanner.d.ts.map +1 -1
  46. package/dist/core/scanner.js +12 -80
  47. package/dist/core/scanner.js.map +1 -1
  48. package/dist/core/sorter.d.ts +5 -1
  49. package/dist/core/sorter.d.ts.map +1 -1
  50. package/dist/core/sorter.js +7 -7
  51. package/dist/core/sorter.js.map +1 -1
  52. package/dist/core/suppressions.d.ts +8 -0
  53. package/dist/core/suppressions.d.ts.map +1 -0
  54. package/dist/core/suppressions.js +44 -0
  55. package/dist/core/suppressions.js.map +1 -0
  56. package/dist/core/typos.d.ts +14 -0
  57. package/dist/core/typos.d.ts.map +1 -0
  58. package/dist/core/typos.js +71 -0
  59. package/dist/core/typos.js.map +1 -0
  60. package/dist/eslint/plugin.d.ts +3 -74
  61. package/dist/eslint/plugin.d.ts.map +1 -1
  62. package/dist/eslint/plugin.js +30 -16
  63. package/dist/eslint/plugin.js.map +1 -1
  64. package/dist/index.d.ts +5 -4
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +11 -3
  67. package/dist/index.js.map +1 -1
  68. package/dist/io/analyzer.d.ts +4 -0
  69. package/dist/io/analyzer.d.ts.map +1 -0
  70. package/dist/io/analyzer.js +7 -0
  71. package/dist/io/analyzer.js.map +1 -0
  72. package/dist/io/config.d.ts +3 -0
  73. package/dist/io/config.d.ts.map +1 -0
  74. package/dist/io/config.js +12 -0
  75. package/dist/io/config.js.map +1 -0
  76. package/dist/io/consistency.d.ts +4 -0
  77. package/dist/io/consistency.d.ts.map +1 -0
  78. package/dist/io/consistency.js +21 -0
  79. package/dist/io/consistency.js.map +1 -0
  80. package/dist/io/deduplicator.d.ts +3 -0
  81. package/dist/io/deduplicator.d.ts.map +1 -0
  82. package/dist/io/deduplicator.js +10 -0
  83. package/dist/io/deduplicator.js.map +1 -0
  84. package/dist/io/fixer.d.ts +3 -0
  85. package/dist/io/fixer.d.ts.map +1 -0
  86. package/dist/io/fixer.js +10 -0
  87. package/dist/io/fixer.js.map +1 -0
  88. package/dist/io/merger.d.ts +3 -0
  89. package/dist/io/merger.d.ts.map +1 -0
  90. package/dist/io/merger.js +11 -0
  91. package/dist/io/merger.js.map +1 -0
  92. package/dist/io/scanner.d.ts +4 -0
  93. package/dist/io/scanner.d.ts.map +1 -0
  94. package/dist/io/scanner.js +78 -0
  95. package/dist/io/scanner.js.map +1 -0
  96. package/dist/io/sorter.d.ts +4 -0
  97. package/dist/io/sorter.d.ts.map +1 -0
  98. package/dist/io/sorter.js +10 -0
  99. package/dist/io/sorter.js.map +1 -0
  100. package/dist/io/typos.d.ts +4 -0
  101. package/dist/io/typos.d.ts.map +1 -0
  102. package/dist/io/typos.js +7 -0
  103. package/dist/io/typos.js.map +1 -0
  104. package/package.json +9 -3
package/README.md CHANGED
@@ -2,6 +2,8 @@
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.
6
+
5
7
  ## Install
6
8
 
7
9
  ```bash
@@ -89,6 +91,34 @@ npx tailwind-canonical --fix --reporter json ./src
89
91
  npx tailwind-canonical --reporter sarif ./src > results.sarif
90
92
  ```
91
93
 
94
+ ## Typo detection (`--typos`)
95
+
96
+ Flags likely misspelled Tailwind color names (Levenshtein distance 1, low false-positive bias). Read-only.
97
+
98
+ ```bash
99
+ npx tailwind-canonical --typos ./src
100
+ # src/Card.tsx:3:17 text-gry-500 → text-gray-500 [typo]
101
+ # src/Nav.tsx:8:12 bg-slte-100 → bg-slate-100 [typo]
102
+ ```
103
+
104
+ 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
+
106
+ ## Suppression comments
107
+
108
+ Skip specific lines or blocks from check and all transforms (`--fix`, `--dedup`, `--merge`, `--sort`):
109
+
110
+ ```jsx
111
+ {/* tailwind-canonical-disable-next-line */}
112
+ <div className="text-[13px]" /> {/* left untouched */}
113
+
114
+ {/* tailwind-canonical-disable */}
115
+ <div className="text-[13px] p-[7px]" /> {/* whole block untouched */}
116
+ <div className="m-[9px]" />
117
+ {/* tailwind-canonical-enable */}
118
+ ```
119
+
120
+ The pragmas are matched as substrings, so any comment style works (`//`, `/* */`, `{/* */}`).
121
+
92
122
  ## Cross-file consistency (`--analyze`)
93
123
 
94
124
  Detects semantic inconsistencies visible only at project scale — it never modifies files.
@@ -215,7 +245,10 @@ left-2 right-2 → inset-x-2
215
245
  | `h-[64px]` | `h-16` | Spacing scale ÷4 |
216
246
  | `w-[50%]` | `w-1/2` | Percentage fractions |
217
247
  | `opacity-[0.5]` | `opacity-50` | Opacity scale |
218
- | `text-[11px]` | `text-2xs` | Custom token |
248
+ | `text-[11px]` | `text-2xs` | Built-in extra token |
249
+ | `text-[8px]`–`text-[10px]` | `text-3xs` | Built-in extra token |
250
+
251
+ `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`.
219
252
 
220
253
  Non-divisible values (`h-[22px]`, `px-[7px]`) are left untouched.
221
254
 
@@ -228,7 +261,6 @@ export default {
228
261
  customTextTokens: {
229
262
  10: '3xs',
230
263
  11: '2xs',
231
- 13: 'xxs',
232
264
  },
233
265
  customSpacingTokens: {
234
266
  14: '3.5',
@@ -237,10 +269,12 @@ export default {
237
269
  attributeNames: ['className', 'class', ':class', 'tw'],
238
270
  // Support utility function wrappers
239
271
  functionNames: ['cn', 'clsx', 'cva'],
272
+ // Never suggest replacements for classes matching these patterns
273
+ ignorePatterns: [/^font-/, /-\[var\(/],
240
274
  }
241
275
  ```
242
276
 
243
- `customTextTokens` merges with the built-in text size map. `customSpacingTokens` supplements the default ÷4 spacing logic.
277
+ `customTextTokens` merges with the built-in text size map. `customSpacingTokens` supplements the default ÷4 spacing logic. `ignorePatterns` makes `suggestCanonical` skip matching classes everywhere — CLI, analyzer, and the ESLint plugin.
244
278
 
245
279
  `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
280
 
@@ -264,6 +298,26 @@ export default [
264
298
  ]
265
299
  ```
266
300
 
301
+ ### Rule options
302
+
303
+ `no-arbitrary-canonical` accepts the full tailwind-canonical `Config` object as
304
+ its rule options, so the same shared config can be reused for both the CLI and
305
+ ESLint without schema errors:
306
+
307
+ ```js
308
+ 'tailwind-canonical/no-arbitrary-canonical': [
309
+ 'warn',
310
+ { customTextTokens: { 11: '2xs' }, ignorePatterns: [/^font-/] },
311
+ ],
312
+ ```
313
+
314
+ The rule **honors**: `customTextTokens`, `customSpacingTokens`, `ignorePatterns`
315
+ (all applied via `suggestCanonical`).
316
+
317
+ It **accepts but ignores**: `functionNames`, `attributeNames`, `sortOrder`.
318
+ These are CLI-only options, allowed in the schema purely so a single shared
319
+ config object can be passed without errors.
320
+
267
321
  ## Pre-commit hook (Husky / Lefthook)
268
322
 
269
323
  ```yaml
@@ -292,7 +346,7 @@ npx tailwind-canonical --fix --dedup --sort ./src ./app
292
346
  pnpm knip
293
347
  ```
294
348
 
295
- Detects unused exports, files, and dependencies. Config in `knip.json`.
349
+ Detects unused exports, files, and dependencies. Config in `knip.json`. Enforced in CI and in the `pre-push` git hook.
296
350
 
297
351
  ## Programmatic API
298
352
 
@@ -0,0 +1,33 @@
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';
11
+ type Flags = {
12
+ fix: boolean;
13
+ merge: boolean;
14
+ dedup: boolean;
15
+ sort: boolean;
16
+ watch: boolean;
17
+ analyze: boolean;
18
+ typos: boolean;
19
+ reporter: Reporter;
20
+ targets: string[];
21
+ error?: string;
22
+ };
23
+ export declare function parseArgs(argv: string[]): Flags;
24
+ /**
25
+ * Modes are mutually exclusive with a fixed precedence: analyze > typos >
26
+ * transform/check. `--watch` is only honored in transform/check mode. This
27
+ * computes warnings for every flag that the active mode will ignore. Pure and
28
+ * order-stable so it can be unit-tested via the injectable sink.
29
+ */
30
+ export declare function flagWarnings(flags: Flags): string[];
31
+ export declare function run(argv: string[], cwd: string, sink?: Sink): Promise<RunResult>;
32
+ export {};
33
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":"AAuBA,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;CAChB,CAAC;AAsFF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CA0C/C;AASD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,CAwBnD;AAyLD,wBAAsB,GAAG,CACvB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,IAAkB,GACvB,OAAO,CAAC,SAAS,CAAC,CAiMpB"}
@@ -0,0 +1,416 @@
1
+ import { watch as fsWatch } from 'node:fs';
2
+ import { dirname, resolve } from 'node:path';
3
+ import { analyzeFile } from '../core/analyzer.js';
4
+ import { toClassStringOpts } from '../core/class-strings.js';
5
+ import { loadConfig } from '../core/config.js';
6
+ import { analyzeConsistencyFiles, toConsistencyOptions, } from '../core/consistency.js';
7
+ import { dedupeFile } from '../core/deduplicator.js';
8
+ import { fixFile } from '../core/fixer.js';
9
+ import { mergeFile } from '../core/merger.js';
10
+ import { resolveTargets } from '../core/scanner.js';
11
+ import { sortFile } from '../core/sorter.js';
12
+ import { analyzeTyposFile } from '../core/typos.js';
13
+ const SARIF_SCHEMA = 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json';
14
+ const USAGE = 'Usage: tailwind-canonical [--fix] [--merge] [--dedup] [--sort] [--analyze] [--typos] [--watch] [--reporter json|sarif] <dir|file> [dir|file...]';
15
+ const defaultSink = {
16
+ log: (s) => console.log(s),
17
+ error: (s) => console.error(s),
18
+ write: (s) => process.stdout.write(s),
19
+ };
20
+ function errMsg(e) {
21
+ return e instanceof Error ? e.message : String(e);
22
+ }
23
+ function pluralize(n, word) {
24
+ return `${n} ${word}${n !== 1 ? 's' : ''}`;
25
+ }
26
+ function timestamp() {
27
+ const d = new Date();
28
+ const pad = (n) => n.toString().padStart(2, '0');
29
+ return `[${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}]`;
30
+ }
31
+ const REPORTERS = ['text', 'json', 'sarif'];
32
+ function isReporter(value) {
33
+ return REPORTERS.includes(value);
34
+ }
35
+ export function parseArgs(argv) {
36
+ let reporter = 'text';
37
+ let reporterRaw;
38
+ const consumed = new Set();
39
+ for (let i = 0; i < argv.length; i += 1) {
40
+ const arg = argv[i];
41
+ if (arg === '--reporter') {
42
+ consumed.add(i);
43
+ reporterRaw = argv[i + 1];
44
+ if (i + 1 < argv.length)
45
+ consumed.add(i + 1);
46
+ }
47
+ else if (arg.startsWith('--reporter=')) {
48
+ consumed.add(i);
49
+ reporterRaw = arg.slice('--reporter='.length);
50
+ }
51
+ }
52
+ let error;
53
+ if (reporterRaw !== undefined) {
54
+ if (isReporter(reporterRaw)) {
55
+ reporter = reporterRaw;
56
+ }
57
+ else {
58
+ error = `Unknown reporter: ${reporterRaw} (expected ${REPORTERS.join('|')})`;
59
+ }
60
+ }
61
+ const targets = argv.filter((a, i) => !(a.startsWith('--') || consumed.has(i)));
62
+ return {
63
+ fix: argv.includes('--fix'),
64
+ merge: argv.includes('--merge'),
65
+ dedup: argv.includes('--dedup'),
66
+ sort: argv.includes('--sort'),
67
+ watch: argv.includes('--watch'),
68
+ analyze: argv.includes('--analyze'),
69
+ typos: argv.includes('--typos'),
70
+ reporter,
71
+ targets,
72
+ error,
73
+ };
74
+ }
75
+ const TRANSFORM_FLAGS = [
76
+ { key: 'fix', flag: '--fix' },
77
+ { key: 'dedup', flag: '--dedup' },
78
+ { key: 'merge', flag: '--merge' },
79
+ { key: 'sort', flag: '--sort' },
80
+ ];
81
+ /**
82
+ * Modes are mutually exclusive with a fixed precedence: analyze > typos >
83
+ * transform/check. `--watch` is only honored in transform/check mode. This
84
+ * computes warnings for every flag that the active mode will ignore. Pure and
85
+ * order-stable so it can be unit-tested via the injectable sink.
86
+ */
87
+ export function flagWarnings(flags) {
88
+ const warnings = [];
89
+ if (flags.analyze) {
90
+ for (const { key, flag } of TRANSFORM_FLAGS) {
91
+ if (flags[key])
92
+ warnings.push(`${flag} ignored: --analyze takes priority`);
93
+ }
94
+ if (flags.typos)
95
+ warnings.push('--typos ignored: --analyze takes priority');
96
+ if (flags.watch)
97
+ warnings.push('--watch ignored: not supported with --analyze');
98
+ return warnings;
99
+ }
100
+ if (flags.typos) {
101
+ for (const { key, flag } of TRANSFORM_FLAGS) {
102
+ if (flags[key])
103
+ warnings.push(`${flag} ignored: --typos takes priority`);
104
+ }
105
+ if (flags.watch)
106
+ warnings.push('--watch ignored: not supported with --typos');
107
+ return warnings;
108
+ }
109
+ return warnings;
110
+ }
111
+ function runTypos(files, config, reporter, sink) {
112
+ let hadError = false;
113
+ const findings = [];
114
+ for (const file of files) {
115
+ try {
116
+ findings.push(...analyzeTyposFile(file, config));
117
+ }
118
+ catch (err) {
119
+ hadError = true;
120
+ sink.error(`${file}: ${errMsg(err)}`);
121
+ }
122
+ }
123
+ if (reporter === 'json') {
124
+ const report = {
125
+ total: findings.length,
126
+ typos: findings,
127
+ };
128
+ sink.write(`${JSON.stringify(report, null, 2)}\n`);
129
+ return { exitCode: findings.length > 0 || hadError ? 1 : 0 };
130
+ }
131
+ for (const f of findings) {
132
+ sink.log(` ${f.file}:${f.line}:${f.col} ${f.original} → ${f.suggestion} [typo]`);
133
+ }
134
+ if (findings.length === 0) {
135
+ sink.log('✓ No likely typos found');
136
+ }
137
+ else {
138
+ sink.log(`\n✖ Found ${pluralize(findings.length, 'likely typo')}`);
139
+ }
140
+ return { exitCode: findings.length > 0 || hadError ? 1 : 0 };
141
+ }
142
+ async function processFile(file, flags, config) {
143
+ const opts = toClassStringOpts(config);
144
+ const counts = { fixed: 0, deduped: 0, merged: 0, sorted: 0 };
145
+ if (flags.fix)
146
+ counts.fixed = fixFile(file, config);
147
+ if (flags.dedup)
148
+ counts.deduped = dedupeFile(file, opts);
149
+ if (flags.merge)
150
+ counts.merged = await mergeFile(file, opts);
151
+ if (flags.sort)
152
+ counts.sorted = sortFile(file, opts, config.sortOrder);
153
+ return counts;
154
+ }
155
+ function totalOf(c) {
156
+ return c.fixed + c.deduped + c.merged + c.sorted;
157
+ }
158
+ function runAnalyze(files, config, reporter, sink) {
159
+ let hadError = false;
160
+ const options = toConsistencyOptions(config);
161
+ const report = analyzeConsistencyFiles(files, config, options, (file, err) => {
162
+ hadError = true;
163
+ sink.error(`${file}: ${errMsg(err)}`);
164
+ });
165
+ const issueCount = report.colorVariants.length +
166
+ report.scaleInconsistencies.length +
167
+ report.combinations.length;
168
+ if (reporter === 'json') {
169
+ sink.write(`${JSON.stringify(report, null, 2)}\n`);
170
+ return { exitCode: issueCount > 0 || hadError ? 1 : 0 };
171
+ }
172
+ for (const group of report.colorVariants) {
173
+ const tokens = group.variants
174
+ .map((v) => `${group.property}-${v.token} (${v.count})`)
175
+ .join(', ');
176
+ sink.log(` Warning: ${group.variants.length} ${group.family} color variants used for ${group.property}: ${tokens}`);
177
+ }
178
+ for (const scale of report.scaleInconsistencies) {
179
+ const values = scale.values
180
+ .map((v) => `${scale.property}-${v.value} (${pluralize(v.files.length, 'file')})`)
181
+ .join(' vs ');
182
+ sink.log(` Warning: ${scale.property} inconsistency: ${values}`);
183
+ }
184
+ for (const combo of report.combinations) {
185
+ sink.log(` Pattern: "${combo.classes.join(' ')}" repeated in ${pluralize(combo.files.length, 'file')}`);
186
+ }
187
+ if (issueCount === 0) {
188
+ sink.log('✓ No cross-file inconsistencies found');
189
+ }
190
+ else {
191
+ sink.log(`\n✖ Found ${pluralize(issueCount, 'consistency issue')} across ${pluralize(report.filesAnalyzed, 'file')}`);
192
+ }
193
+ return { exitCode: issueCount > 0 || hadError ? 1 : 0 };
194
+ }
195
+ function startWatch(files, flags, config, sink) {
196
+ const transforming = flags.fix || flags.dedup || flags.merge || flags.sort;
197
+ const fileSet = new Set(files);
198
+ const inFlight = new Set();
199
+ const timers = new Map();
200
+ const dirs = new Set(files.map((f) => dirname(f)));
201
+ sink.log(`Watching ${pluralize(files.length, 'file')}... (Ctrl+C to stop)`);
202
+ for (const dir of dirs) {
203
+ fsWatch(dir, { recursive: true }, (_, filename) => {
204
+ if (!filename)
205
+ return;
206
+ const full = resolve(dir, filename);
207
+ if (!fileSet.has(full) || inFlight.has(full))
208
+ return;
209
+ clearTimeout(timers.get(full));
210
+ timers.set(full, setTimeout(() => {
211
+ if (transforming) {
212
+ inFlight.add(full);
213
+ processFile(full, flags, config)
214
+ .then((counts) => {
215
+ const total = totalOf(counts);
216
+ if (total > 0) {
217
+ sink.log(`${timestamp()} ${full} — ${pluralize(total, 'change')} applied`);
218
+ }
219
+ })
220
+ .catch((err) => {
221
+ sink.error(`${timestamp()} ${full} — error: ${err instanceof Error ? err.message : String(err)}`);
222
+ })
223
+ .finally(() => inFlight.delete(full));
224
+ }
225
+ else {
226
+ const findings = analyzeFile(full, config);
227
+ if (findings.length > 0) {
228
+ sink.log(`${timestamp()} ${full} — ${pluralize(findings.length, 'finding')}`);
229
+ for (const f of findings) {
230
+ const tag = f.suggestion.isCustomToken ? ' [custom token]' : '';
231
+ sink.log(` ${f.line}:${f.col} ${f.suggestion.original} → ${f.suggestion.canonical}${tag}`);
232
+ }
233
+ }
234
+ }
235
+ }, 50));
236
+ });
237
+ }
238
+ process.on('SIGINT', () => {
239
+ sink.log('\nWatcher stopped.');
240
+ process.exit(0);
241
+ });
242
+ return { exitCode: 0, watching: true };
243
+ }
244
+ export async function run(argv, cwd, sink = defaultSink) {
245
+ const flags = parseArgs(argv);
246
+ if (flags.error) {
247
+ sink.error(flags.error);
248
+ return { exitCode: 1 };
249
+ }
250
+ if (flags.targets.length === 0) {
251
+ sink.error(USAGE);
252
+ return { exitCode: 1 };
253
+ }
254
+ if (flags.merge) {
255
+ try {
256
+ await import('tailwind-merge');
257
+ }
258
+ catch {
259
+ sink.error('--merge requires tailwind-merge: pnpm add -D tailwind-merge');
260
+ return { exitCode: 1 };
261
+ }
262
+ }
263
+ let config;
264
+ try {
265
+ config = await loadConfig(cwd);
266
+ }
267
+ catch (err) {
268
+ sink.error(`tailwind-canonical: ${err instanceof Error ? err.message : String(err)}`);
269
+ return { exitCode: 1 };
270
+ }
271
+ for (const warning of flagWarnings(flags)) {
272
+ sink.error(`Warning: ${warning}`);
273
+ }
274
+ const files = await resolveTargets(flags.targets);
275
+ if (flags.analyze)
276
+ return runAnalyze(files, config, flags.reporter, sink);
277
+ if (flags.typos)
278
+ return runTypos(files, config, flags.reporter, sink);
279
+ const transforming = flags.fix || flags.dedup || flags.merge || flags.sort;
280
+ const totals = { fixed: 0, deduped: 0, merged: 0, sorted: 0 };
281
+ const allFindings = [];
282
+ const changedFiles = [];
283
+ let hadError = false;
284
+ if (!flags.watch) {
285
+ for (const file of files) {
286
+ try {
287
+ if (transforming) {
288
+ const counts = await processFile(file, flags, config);
289
+ totals.fixed += counts.fixed;
290
+ totals.deduped += counts.deduped;
291
+ totals.merged += counts.merged;
292
+ totals.sorted += counts.sorted;
293
+ if (totalOf(counts) > 0)
294
+ changedFiles.push(file);
295
+ if (flags.reporter === 'text') {
296
+ if (counts.fixed > 0)
297
+ sink.log(` fixed ${file} (${pluralize(counts.fixed, 'replacement')})`);
298
+ if (counts.deduped > 0)
299
+ sink.log(` deduped ${file} (${pluralize(counts.deduped, 'class string')})`);
300
+ if (counts.merged > 0)
301
+ sink.log(` merged ${file} (${pluralize(counts.merged, 'conflict')})`);
302
+ if (counts.sorted > 0)
303
+ sink.log(` sorted ${file} (${pluralize(counts.sorted, 'class string')})`);
304
+ }
305
+ }
306
+ else {
307
+ const findings = analyzeFile(file, config);
308
+ allFindings.push(...findings);
309
+ if (flags.reporter === 'text') {
310
+ for (const f of findings) {
311
+ const tag = f.suggestion.isCustomToken ? ' [custom token]' : '';
312
+ sink.log(` ${f.file}:${f.line}:${f.col} ${f.suggestion.original} → ${f.suggestion.canonical}${tag}`);
313
+ }
314
+ }
315
+ }
316
+ }
317
+ catch (err) {
318
+ hadError = true;
319
+ sink.error(`${file}: ${errMsg(err)}`);
320
+ }
321
+ }
322
+ }
323
+ if (flags.watch)
324
+ return startWatch(files, flags, config, sink);
325
+ if (transforming) {
326
+ if (flags.reporter === 'json') {
327
+ const report = {
328
+ files: files.length,
329
+ changedFiles,
330
+ fixed: totals.fixed,
331
+ deduped: totals.deduped,
332
+ merged: totals.merged,
333
+ sorted: totals.sorted,
334
+ };
335
+ sink.write(`${JSON.stringify(report, null, 2)}\n`);
336
+ return { exitCode: hadError ? 1 : 0 };
337
+ }
338
+ const parts = [];
339
+ if (flags.fix)
340
+ parts.push(pluralize(totals.fixed, 'replacement'));
341
+ if (flags.dedup)
342
+ parts.push(pluralize(totals.deduped, 'dedup'));
343
+ if (flags.merge)
344
+ parts.push(`${pluralize(totals.merged, 'conflict')} merged`);
345
+ if (flags.sort)
346
+ parts.push(`${totals.sorted} sorted`);
347
+ sink.log(`\n✓ Fixed ${parts.join(', ')} across ${pluralize(files.length, 'file')}`);
348
+ return { exitCode: hadError ? 1 : 0 };
349
+ }
350
+ const totalFindings = allFindings.length;
351
+ if (flags.reporter === 'json') {
352
+ const report = {
353
+ files: files.length,
354
+ total: totalFindings,
355
+ findings: allFindings.map((f) => ({
356
+ file: f.file,
357
+ line: f.line,
358
+ col: f.col,
359
+ original: f.suggestion.original,
360
+ canonical: f.suggestion.canonical,
361
+ isCustomToken: f.suggestion.isCustomToken,
362
+ })),
363
+ };
364
+ sink.write(`${JSON.stringify(report, null, 2)}\n`);
365
+ return { exitCode: totalFindings > 0 || hadError ? 1 : 0 };
366
+ }
367
+ if (flags.reporter === 'sarif') {
368
+ const sarifOutput = {
369
+ $schema: SARIF_SCHEMA,
370
+ version: '2.1.0',
371
+ runs: [
372
+ {
373
+ tool: {
374
+ driver: {
375
+ name: 'tailwind-canonical',
376
+ informationUri: 'https://github.com/peak-lab/tailwind-canonical',
377
+ rules: [
378
+ {
379
+ id: 'no-arbitrary-canonical',
380
+ name: 'NoArbitraryCanonical',
381
+ shortDescription: {
382
+ text: 'Arbitrary value has a canonical Tailwind equivalent',
383
+ },
384
+ },
385
+ ],
386
+ },
387
+ },
388
+ results: allFindings.map((f) => ({
389
+ ruleId: 'no-arbitrary-canonical',
390
+ message: {
391
+ text: `${f.suggestion.original} → ${f.suggestion.canonical}`,
392
+ },
393
+ locations: [
394
+ {
395
+ physicalLocation: {
396
+ artifactLocation: { uri: f.file },
397
+ region: { startLine: f.line, startColumn: f.col },
398
+ },
399
+ },
400
+ ],
401
+ })),
402
+ },
403
+ ],
404
+ };
405
+ sink.write(`${JSON.stringify(sarifOutput, null, 2)}\n`);
406
+ return { exitCode: totalFindings > 0 || hadError ? 1 : 0 };
407
+ }
408
+ if (totalFindings > 0) {
409
+ sink.log(`\n✖ Found ${totalFindings} non-canonical class${totalFindings !== 1 ? 'es' : ''}`);
410
+ sink.log(' Run with --fix to auto-replace\n');
411
+ return { exitCode: 1 };
412
+ }
413
+ sink.log('✓ No non-canonical classes found');
414
+ return { exitCode: hadError ? 1 : 0 };
415
+ }
416
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAgB,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAoB,MAAM,kBAAkB,CAAC;AAEtE,MAAM,YAAY,GAChB,gGAAgG,CAAC;AAEnG,MAAM,KAAK,GACT,iJAAiJ,CAAC;AAQpJ,MAAM,WAAW,GAAS;IACxB,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;CACtC,CAAC;AAmFF,SAAS,MAAM,CAAC,CAAU;IACxB,OAAO,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,SAAS,CAAC,CAAS,EAAE,IAAY;IACxC,OAAO,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAC7C,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;IACrB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACzD,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC;AAChF,CAAC;AAED,MAAM,SAAS,GAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjE,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAQ,SAA+B,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,IAAI,QAAQ,GAAa,MAAM,CAAC;IAChC,IAAI,WAA+B,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IAEnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YACzB,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAChB,WAAW,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;gBAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/C,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YACzC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAChB,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,IAAI,KAAyB,CAAC;IAC9B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,QAAQ,GAAG,WAAW,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,qBAAqB,WAAW,cAAc,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QAC/E,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CACzB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CACnD,CAAC;IAEF,OAAO;QACL,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC3B,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/B,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/B,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC7B,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/B,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;QACnC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/B,QAAQ;QACR,OAAO;QACP,KAAK;KACN,CAAC;AACJ,CAAC;AAED,MAAM,eAAe,GAAsD;IACzE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE;IAC7B,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;IACjC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;IACjC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;CAChC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAY;IACvC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,eAAe,EAAE,CAAC;YAC5C,IAAI,KAAK,CAAC,GAAG,CAAC;gBACZ,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,oCAAoC,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,KAAK,CAAC,KAAK;YAAE,QAAQ,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC5E,IAAI,KAAK,CAAC,KAAK;YACb,QAAQ,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;QACjE,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,eAAe,EAAE,CAAC;YAC5C,IAAI,KAAK,CAAC,GAAG,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,kCAAkC,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,KAAK,CAAC,KAAK;YACb,QAAQ,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QAC/D,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,QAAQ,CACf,KAAe,EACf,MAAc,EACd,QAAkB,EAClB,IAAU;IAEV,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,MAAM,MAAM,GAAoB;YAC9B,KAAK,EAAE,QAAQ,CAAC,MAAM;YACtB,KAAK,EAAE,QAAQ;SAChB,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACnD,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/D,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,GAAG,CACN,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,UAAU,SAAS,CACzE,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,GAAG,CAAC,aAAa,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,IAAY,EACZ,KAAY,EACZ,MAAc;IAEd,MAAM,IAAI,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,MAAM,GAAe,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC1E,IAAI,KAAK,CAAC,GAAG;QAAE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpD,IAAI,KAAK,CAAC,KAAK;QAAE,MAAM,CAAC,OAAO,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACzD,IAAI,KAAK,CAAC,KAAK;QAAE,MAAM,CAAC,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7D,IAAI,KAAK,CAAC,IAAI;QAAE,MAAM,CAAC,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACvE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,OAAO,CAAC,CAAa;IAC5B,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;AACnD,CAAC;AAED,SAAS,UAAU,CACjB,KAAe,EACf,MAAc,EACd,QAAkB,EAClB,IAAU;IAEV,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,uBAAuB,CACpC,KAAK,EACL,MAAM,EACN,OAAO,EACP,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACZ,QAAQ,GAAG,IAAI,CAAC;QAChB,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC,CACF,CAAC;IACF,MAAM,UAAU,GACd,MAAM,CAAC,aAAa,CAAC,MAAM;QAC3B,MAAM,CAAC,oBAAoB,CAAC,MAAM;QAClC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC;IAE7B,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACnD,OAAO,EAAE,QAAQ,EAAE,UAAU,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ;aAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC;aACvD,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,IAAI,CAAC,GAAG,CACN,cAAc,KAAK,CAAC,QAAQ,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,4BAA4B,KAAK,CAAC,QAAQ,KAAK,MAAM,EAAE,CAC3G,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,oBAAoB,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;aACxB,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CACJ,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CACxE;aACA,IAAI,CAAC,MAAM,CAAC,CAAC;QAChB,IAAI,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,QAAQ,mBAAmB,MAAM,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxC,IAAI,CAAC,GAAG,CACN,eAAe,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAC/F,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,GAAG,CACN,aAAa,SAAS,CAAC,UAAU,EAAE,mBAAmB,CAAC,WAAW,SAAS,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,EAAE,CAC5G,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,UAAU,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1D,CAAC;AAED,SAAS,UAAU,CACjB,KAAe,EACf,KAAY,EACZ,MAAc,EACd,IAAU;IAEV,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC;IAC3E,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAyC,CAAC;IAChE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAS,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3D,IAAI,CAAC,GAAG,CAAC,YAAY,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,sBAAsB,CAAC,CAAC;IAE5E,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE;YAChD,IAAI,CAAC,QAAQ;gBAAE,OAAO;YACtB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,OAAO;YACrD,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,GAAG,CACR,IAAI,EACJ,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,YAAY,EAAE,CAAC;oBACjB,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACnB,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC;yBAC7B,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;wBACf,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;wBAC9B,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;4BACd,IAAI,CAAC,GAAG,CACN,GAAG,SAAS,EAAE,IAAI,IAAI,MAAM,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CACjE,CAAC;wBACJ,CAAC;oBACH,CAAC,CAAC;yBACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;wBACtB,IAAI,CAAC,KAAK,CACR,GAAG,SAAS,EAAE,IAAI,IAAI,aAAa,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACtF,CAAC;oBACJ,CAAC,CAAC;yBACD,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC1C,CAAC;qBAAM,CAAC;oBACN,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;oBAC3C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACxB,IAAI,CAAC,GAAG,CACN,GAAG,SAAS,EAAE,IAAI,IAAI,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CACpE,CAAC;wBACF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;4BACzB,MAAM,GAAG,GAAG,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;4BAChE,IAAI,CAAC,GAAG,CACN,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,QAAQ,MAAM,CAAC,CAAC,UAAU,CAAC,SAAS,GAAG,GAAG,EAAE,CACnF,CAAC;wBACJ,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC,EAAE,EAAE,CAAC,CACP,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,IAAc,EACd,GAAW,EACX,OAAa,WAAW;IAExB,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE9B,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAClB,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;YAC1E,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,KAAK,CACR,uBAAuB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC1E,CAAC;QACF,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,KAAK,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAElD,IAAI,KAAK,CAAC,OAAO;QAAE,OAAO,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAE1E,IAAI,KAAK,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAEtE,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC;IAC3E,MAAM,MAAM,GAAe,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC1E,MAAM,WAAW,GAAc,EAAE,CAAC;IAClC,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACjB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,IAAI,YAAY,EAAE,CAAC;oBACjB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;oBACtD,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC;oBAC7B,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC;oBACjC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC;oBAC/B,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC;oBAC/B,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;wBAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACjD,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;wBAC9B,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC;4BAClB,IAAI,CAAC,GAAG,CACN,YAAY,IAAI,KAAK,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAC/D,CAAC;wBACJ,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC;4BACpB,IAAI,CAAC,GAAG,CACN,aAAa,IAAI,KAAK,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC,GAAG,CACnE,CAAC;wBACJ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;4BACnB,IAAI,CAAC,GAAG,CACN,YAAY,IAAI,KAAK,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,CAC7D,CAAC;wBACJ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;4BACnB,IAAI,CAAC,GAAG,CACN,YAAY,IAAI,KAAK,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,CACjE,CAAC;oBACN,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;oBAC3C,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;oBAC9B,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;wBAC9B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;4BACzB,MAAM,GAAG,GAAG,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;4BAChE,IAAI,CAAC,GAAG,CACN,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,QAAQ,MAAM,CAAC,CAAC,UAAU,CAAC,SAAS,GAAG,GAAG,EAAE,CAC7F,CAAC;wBACJ,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,QAAQ,GAAG,IAAI,CAAC;gBAChB,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,KAAK;QAAE,OAAO,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAE/D,IAAI,YAAY,EAAE,CAAC;QACjB,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAwB;gBAClC,KAAK,EAAE,KAAK,CAAC,MAAM;gBACnB,YAAY;gBACZ,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC;YACF,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACnD,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxC,CAAC;QACD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,GAAG;YAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC;QAClE,IAAI,KAAK,CAAC,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAChE,IAAI,KAAK,CAAC,KAAK;YACb,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;QAC/D,IAAI,KAAK,CAAC,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC;QACtD,IAAI,CAAC,GAAG,CACN,aAAa,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAC1E,CAAC;QACF,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACxC,CAAC;IAED,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC;IAEzC,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAuB;YACjC,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,KAAK,EAAE,aAAa;YACpB,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAChC,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ;gBAC/B,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC,SAAS;gBACjC,aAAa,EAAE,CAAC,CAAC,UAAU,CAAC,aAAa;aAC1C,CAAC,CAAC;SACJ,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACnD,OAAO,EAAE,QAAQ,EAAE,aAAa,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAgB;YAC/B,OAAO,EAAE,YAAY;YACrB,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE;gBACJ;oBACE,IAAI,EAAE;wBACJ,MAAM,EAAE;4BACN,IAAI,EAAE,oBAAoB;4BAC1B,cAAc,EAAE,gDAAgD;4BAChE,KAAK,EAAE;gCACL;oCACE,EAAE,EAAE,wBAAwB;oCAC5B,IAAI,EAAE,sBAAsB;oCAC5B,gBAAgB,EAAE;wCAChB,IAAI,EAAE,qDAAqD;qCAC5D;iCACF;6BACF;yBACF;qBACF;oBACD,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBAC/B,MAAM,EAAE,wBAAwB;wBAChC,OAAO,EAAE;4BACP,IAAI,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,QAAQ,MAAM,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE;yBAC7D;wBACD,SAAS,EAAE;4BACT;gCACE,gBAAgB,EAAE;oCAChB,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE;oCACjC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,GAAG,EAAE;iCAClD;6BACF;yBACF;qBACF,CAAC,CAAC;iBACJ;aACF;SACF,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACxD,OAAO,EAAE,QAAQ,EAAE,aAAa,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,CAAC;IAED,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC,GAAG,CACN,aAAa,aAAa,uBAAuB,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACnF,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;QAC/C,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAC7C,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxC,CAAC"}