tailwind-unwind 0.2.0 → 0.3.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/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Expression, JSXAttribute, Node } from '@babel/types';
1
+ import { Node, CallExpression, Expression, JSXAttribute } from '@babel/types';
2
2
 
3
3
  type CliCommand = 'analyze' | 'generate' | 'apply';
4
4
  interface CommandConfig {
@@ -10,6 +10,9 @@ interface CommandConfig {
10
10
  output?: string;
11
11
  dedupeSubsets?: boolean;
12
12
  dryRun?: boolean;
13
+ prettier?: boolean;
14
+ fromReport?: string;
15
+ extractableOnly?: boolean;
13
16
  }
14
17
  /** Keys are space-separated utility strings; values are base class names (without prefix). */
15
18
  type CustomNamesConfig = Record<string, string>;
@@ -99,6 +102,9 @@ interface AnalyzeOptions {
99
102
  configPath?: string;
100
103
  /** Custom base class names keyed by space-separated utility strings */
101
104
  names?: Record<string, string>;
105
+ prettier?: boolean;
106
+ fromReport?: string;
107
+ extractableOnly?: boolean;
102
108
  }
103
109
 
104
110
  /**
@@ -106,20 +112,32 @@ interface AnalyzeOptions {
106
112
  */
107
113
  declare function analyzeCommand(targetPath: string, options?: AnalyzeOptions): Promise<AnalysisReport>;
108
114
 
109
- interface ApplyOptions extends AnalyzeOptions {
110
- output: string;
111
- dryRun?: boolean;
115
+ interface GeneratedComponent {
116
+ className: string;
117
+ classes: string[];
118
+ occurrences: number;
112
119
  }
113
- interface ApplyResult {
114
- filesModified: number;
115
- replacementsTotal: number;
116
- outputPath: string;
117
- componentsGenerated: number;
120
+ interface CssGeneratorOptions {
121
+ sourcePath: string;
122
+ combinations: ClassCombination[];
123
+ prefix?: string;
124
+ names?: CustomNamesConfig;
125
+ }
126
+ interface CssGeneratorResult {
127
+ css: string;
128
+ components: GeneratedComponent[];
118
129
  }
130
+ interface AssignClassNamesOptions {
131
+ prefix?: string;
132
+ names?: CustomNamesConfig;
133
+ }
134
+ /** Assign unique, prefixed component class names. */
135
+ declare function assignComponentClassNames(combinations: ClassCombination[], options?: AssignClassNamesOptions): GeneratedComponent[];
119
136
  /**
120
- * Generate component CSS and replace matching className strings in source files.
137
+ * Build a Tailwind CSS file with @layer components and @apply rules
138
+ * for the most frequent class combinations.
121
139
  */
122
- declare function applyCommand(targetPath: string, options: ApplyOptions): Promise<ApplyResult>;
140
+ declare function generateComponentCss(options: CssGeneratorOptions): CssGeneratorResult;
123
141
 
124
142
  interface PatternFinderOptions {
125
143
  minOccurrences?: number;
@@ -144,6 +162,86 @@ declare function findRepeatedClassSets(occurrences: ClassNameOccurrence[], optio
144
162
  */
145
163
  declare function calculatePotentialReduction(occurrences: ClassNameOccurrence[], topCombinations: ClassCombination[]): number;
146
164
 
165
+ interface BuildComponentsOptions extends PatternFinderOptions {
166
+ sourcePath: string;
167
+ prefix?: string;
168
+ names?: Record<string, string>;
169
+ }
170
+ interface BuildComponentsResult {
171
+ components: GeneratedComponent[];
172
+ css: string;
173
+ replacementMap: Map<string, string>;
174
+ }
175
+ /** Build component classes, CSS, and a normalized-class → name lookup map. */
176
+ declare function buildComponents(occurrences: ClassNameOccurrence[], options: BuildComponentsOptions): BuildComponentsResult;
177
+ /** Build components from pre-selected combinations (e.g. analyze report). */
178
+ declare function buildComponentsFromCombinations(combinations: ClassCombination[], options: BuildComponentsOptions): BuildComponentsResult;
179
+
180
+ interface ClassReplacement {
181
+ filePath: string;
182
+ line?: number;
183
+ from: string;
184
+ to: string;
185
+ partial?: boolean;
186
+ }
187
+ interface SkippedReplacement {
188
+ filePath: string;
189
+ line?: number;
190
+ reason: string;
191
+ classes: string[];
192
+ }
193
+ interface ReplaceClassNamesResult {
194
+ source: string;
195
+ replacements: ClassReplacement[];
196
+ skipped: SkippedReplacement[];
197
+ changed: boolean;
198
+ }
199
+ /**
200
+ * Replace exact matching className/class values with generated component classes.
201
+ * Supports partial replacement inside cn()/clsx() when dynamic args are present.
202
+ */
203
+ declare function replaceClassNamesInSource(source: string, replacementMap: Map<string, string>, filePath: string): ReplaceClassNamesResult;
204
+
205
+ interface GenerateJsonReport {
206
+ command: 'generate';
207
+ outputPath: string;
208
+ componentsGenerated: number;
209
+ components: GeneratedComponent[];
210
+ cssWritten: boolean;
211
+ }
212
+ interface ApplyJsonReport {
213
+ command: 'apply';
214
+ dryRun: boolean;
215
+ outputPath: string;
216
+ filesModified: number;
217
+ replacementsTotal: number;
218
+ componentsGenerated: number;
219
+ components: GeneratedComponent[];
220
+ replacements: ClassReplacement[];
221
+ skipped: SkippedReplacement[];
222
+ }
223
+ declare function printGenerateJsonReport(report: GenerateJsonReport): void;
224
+ declare function printApplyJsonReport(report: ApplyJsonReport): void;
225
+
226
+ interface ApplyOptions extends AnalyzeOptions {
227
+ output: string;
228
+ dryRun?: boolean;
229
+ }
230
+ interface ApplyResult {
231
+ filesModified: number;
232
+ replacementsTotal: number;
233
+ outputPath: string;
234
+ componentsGenerated: number;
235
+ components: Awaited<ReturnType<typeof buildComponents>>['components'];
236
+ replacements: ApplyJsonReport['replacements'];
237
+ skipped: ApplyJsonReport['skipped'];
238
+ prettierFormatted: string[];
239
+ }
240
+ /**
241
+ * Generate component CSS and replace matching className strings in source files.
242
+ */
243
+ declare function applyCommand(targetPath: string, options: ApplyOptions): Promise<ApplyResult>;
244
+
147
245
  interface ScanProjectOptions extends PatternFinderOptions {
148
246
  targetPath: string;
149
247
  include?: string[];
@@ -169,77 +267,54 @@ interface GenerateOptions extends AnalyzeOptions {
169
267
  interface GenerateResult {
170
268
  outputPath: string;
171
269
  componentsGenerated: number;
172
- report: Awaited<ReturnType<typeof scanProject>>['report'];
270
+ components: Awaited<ReturnType<typeof buildComponents>>['components'];
271
+ report: Awaited<ReturnType<typeof scanProject>>['report'] | null;
173
272
  }
174
273
  /**
175
274
  * Analyze a project and write @layer components CSS to the output file.
176
275
  */
177
276
  declare function generateCommand(targetPath: string, options: GenerateOptions): Promise<GenerateResult>;
178
277
 
179
- interface GeneratedComponent {
180
- className: string;
181
- classes: string[];
182
- occurrences: number;
183
- }
184
- interface CssGeneratorOptions {
185
- sourcePath: string;
278
+ interface LoadedAnalyzeReport {
279
+ targetPath: string;
186
280
  combinations: ClassCombination[];
187
- prefix?: string;
188
- names?: CustomNamesConfig;
189
- }
190
- interface CssGeneratorResult {
191
- css: string;
192
- components: GeneratedComponent[];
193
- }
194
- interface AssignClassNamesOptions {
195
- prefix?: string;
196
- names?: CustomNamesConfig;
197
281
  }
198
- /** Assign unique, prefixed component class names. */
199
- declare function assignComponentClassNames(combinations: ClassCombination[], options?: AssignClassNamesOptions): GeneratedComponent[];
200
282
  /**
201
- * Build a Tailwind CSS file with @layer components and @apply rules
202
- * for the most frequent class combinations.
283
+ * Load an analyze JSON report and return extractable combinations for generate.
203
284
  */
204
- declare function generateComponentCss(options: CssGeneratorOptions): CssGeneratorResult;
285
+ declare function loadExtractableCombinations(reportPath: string, options?: {
286
+ extractableOnly?: boolean;
287
+ }): Promise<LoadedAnalyzeReport>;
205
288
 
206
- interface BuildComponentsOptions extends PatternFinderOptions {
207
- sourcePath: string;
208
- prefix?: string;
209
- names?: Record<string, string>;
210
- }
211
- interface BuildComponentsResult {
212
- components: GeneratedComponent[];
213
- css: string;
214
- replacementMap: Map<string, string>;
215
- }
216
- /** Build component classes, CSS, and a normalized-class → name lookup map. */
217
- declare function buildComponents(occurrences: ClassNameOccurrence[], options: BuildComponentsOptions): BuildComponentsResult;
218
-
219
- interface ClassReplacement {
220
- filePath: string;
221
- line?: number;
222
- from: string;
223
- to: string;
224
- partial?: boolean;
225
- }
226
- interface SkippedReplacement {
289
+ interface FormatSourceOptions {
227
290
  filePath: string;
228
- line?: number;
229
- reason: string;
230
- classes: string[];
291
+ cwd?: string;
231
292
  }
232
- interface ReplaceClassNamesResult {
293
+ /**
294
+ * Format source with Prettier when available in the project.
295
+ * Returns original source unchanged if Prettier is not installed.
296
+ */
297
+ declare function formatSource(source: string, options: FormatSourceOptions): Promise<{
233
298
  source: string;
234
- replacements: ClassReplacement[];
235
- skipped: SkippedReplacement[];
236
- changed: boolean;
237
- }
299
+ formatted: boolean;
300
+ }>;
301
+ declare function formatModifiedFiles(files: string[], sources: Map<string, string>, cwd?: string): Promise<{
302
+ formatted: string[];
303
+ skipped: string[];
304
+ }>;
305
+
306
+ /** Variant APIs that define reusable Tailwind class sets. */
307
+ declare const VARIANT_CALLEES: Set<string>;
308
+ declare function isVariantCallee(expression: Expression): boolean;
238
309
  /**
239
- * Replace exact matching className/class values with generated component classes.
240
- * Supports partial replacement inside cn()/clsx() when dynamic args are present.
310
+ * Extract Tailwind tokens from a cva()/tv() definition call.
241
311
  */
242
- declare function replaceClassNamesInSource(source: string, replacementMap: Map<string, string>, filePath: string): ReplaceClassNamesResult;
312
+ declare function extractClassesFromVariantCall(call: CallExpression): string[];
313
+ type VariantRegistry = Map<string, string[]>;
314
+ /**
315
+ * Collect `const x = cva(...)` / `const x = tv(...)` definitions in a file.
316
+ */
317
+ declare function collectVariantRegistry(ast: Node): VariantRegistry;
243
318
 
244
319
  /**
245
320
  * Suggest a short, human-readable component class name from a utility list.
@@ -281,15 +356,11 @@ interface ExtractedClasses {
281
356
  classes: string[];
282
357
  isDynamic: boolean;
283
358
  }
284
- /**
285
- * Recursively pull static Tailwind tokens from JSX className expressions.
286
- * Unknown/dynamic fragments set `isDynamic: true` but may still yield partial classes.
287
- */
288
- declare function extractClassesFromExpression(expression: Expression): ExtractedClasses;
359
+ declare function extractClassesFromExpression(expression: Expression, registry?: VariantRegistry): ExtractedClasses;
289
360
 
290
361
  declare function isClassAttribute(attr: JSXAttribute): boolean;
291
362
  /** Extract Tailwind classes from a className/class JSX attribute. */
292
- declare function extractFromJSXAttribute(attr: JSXAttribute): ClassNameExtraction | null;
363
+ declare function extractFromJSXAttribute(attr: JSXAttribute, registry?: VariantRegistry): ClassNameExtraction | null;
293
364
  declare function parseSourceToAst(source: string): Node;
294
365
 
295
366
  /**
@@ -326,4 +397,4 @@ declare const IGNORED_DIRECTORIES: readonly ["node_modules", ".next", "dist", "b
326
397
  /** fast-glob ignore patterns — match directories at any depth. */
327
398
  declare const IGNORE_PATTERNS: string[];
328
399
 
329
- export { type AnalysisReport, type AnalysisStats, type AnalyzeOptions, type ApplyOptions, type ApplyResult, CLASS_MERGE_CALLEES, type ClassCombination, type ClassNameExtraction, type ClassNameOccurrence, type ClassReplacement, type CliCommand, type CombinationLocation, type CommandConfig, type CssGeneratorOptions, type CssGeneratorResult, type CustomNamesConfig, DEFAULT_CLASS_PREFIX, type GenerateOptions, type GenerateResult, type GeneratedComponent, IGNORED_DIRECTORIES, IGNORE_PATTERNS, type ParseResult, type ReplaceClassNamesResult, type SkippedReplacement, type TailwindUnwindConfig, type TailwindUnwindConfigFile, analyzeCommand, applyCommand, assignComponentClassNames, buildComponents, calculatePotentialReduction, dedupeSubsetCombinations, extractClassesFromExpression, extractFromJSXAttribute, findFrequentPatterns, findRepeatedClassSets, generateCombinations, generateCommand, generateComponentCss, isClassAttribute, isStrictSubset, loadCommandOptions, normalizeClassPrefix, normalizeClasses, normalizeNamesConfig, parseFile, parseSource, parseSourceToAst, printConsoleReport, printJsonReport, replaceClassNamesInSource, scanProject, splitClassString, suggestClassName, validateConfigFile, walkSourceFiles, withClassPrefix };
400
+ export { type AnalysisReport, type AnalysisStats, type AnalyzeOptions, type ApplyOptions, type ApplyResult, CLASS_MERGE_CALLEES, type ClassCombination, type ClassNameExtraction, type ClassNameOccurrence, type ClassReplacement, type CliCommand, type CombinationLocation, type CommandConfig, type CssGeneratorOptions, type CssGeneratorResult, type CustomNamesConfig, DEFAULT_CLASS_PREFIX, type GenerateOptions, type GenerateResult, type GeneratedComponent, IGNORED_DIRECTORIES, IGNORE_PATTERNS, type ParseResult, type ReplaceClassNamesResult, type SkippedReplacement, type TailwindUnwindConfig, type TailwindUnwindConfigFile, VARIANT_CALLEES, analyzeCommand, applyCommand, assignComponentClassNames, buildComponents, buildComponentsFromCombinations, calculatePotentialReduction, collectVariantRegistry, dedupeSubsetCombinations, extractClassesFromExpression, extractClassesFromVariantCall, extractFromJSXAttribute, findFrequentPatterns, findRepeatedClassSets, formatModifiedFiles, formatSource, generateCombinations, generateCommand, generateComponentCss, isClassAttribute, isStrictSubset, isVariantCallee, loadCommandOptions, loadExtractableCombinations, normalizeClassPrefix, normalizeClasses, normalizeNamesConfig, parseFile, parseSource, parseSourceToAst, printApplyJsonReport, printConsoleReport, printGenerateJsonReport, printJsonReport, replaceClassNamesInSource, scanProject, splitClassString, suggestClassName, validateConfigFile, walkSourceFiles, withClassPrefix };
package/dist/index.js CHANGED
@@ -3,29 +3,39 @@ import {
3
3
  DEFAULT_CLASS_PREFIX,
4
4
  IGNORED_DIRECTORIES,
5
5
  IGNORE_PATTERNS,
6
+ VARIANT_CALLEES,
6
7
  analyzeCommand,
7
8
  applyCommand,
8
9
  assignComponentClassNames,
9
10
  buildComponents,
11
+ buildComponentsFromCombinations,
10
12
  calculatePotentialReduction,
13
+ collectVariantRegistry,
11
14
  dedupeSubsetCombinations,
12
15
  extractClassesFromExpression,
16
+ extractClassesFromVariantCall,
13
17
  extractFromJSXAttribute,
14
18
  findFrequentPatterns,
15
19
  findRepeatedClassSets,
20
+ formatModifiedFiles,
21
+ formatSource,
16
22
  generateCombinations,
17
23
  generateCommand,
18
24
  generateComponentCss,
19
25
  isClassAttribute,
20
26
  isStrictSubset,
27
+ isVariantCallee,
21
28
  loadCommandOptions,
29
+ loadExtractableCombinations,
22
30
  normalizeClassPrefix,
23
31
  normalizeClasses,
24
32
  normalizeNamesConfig,
25
33
  parseFile,
26
34
  parseSource,
27
35
  parseSourceToAst,
36
+ printApplyJsonReport,
28
37
  printConsoleReport,
38
+ printGenerateJsonReport,
29
39
  printJsonReport,
30
40
  replaceClassNamesInSource,
31
41
  scanProject,
@@ -34,35 +44,45 @@ import {
34
44
  validateConfigFile,
35
45
  walkSourceFiles,
36
46
  withClassPrefix
37
- } from "./chunk-FASYIEVZ.js";
47
+ } from "./chunk-4GXMK3NB.js";
38
48
  export {
39
49
  CLASS_MERGE_CALLEES,
40
50
  DEFAULT_CLASS_PREFIX,
41
51
  IGNORED_DIRECTORIES,
42
52
  IGNORE_PATTERNS,
53
+ VARIANT_CALLEES,
43
54
  analyzeCommand,
44
55
  applyCommand,
45
56
  assignComponentClassNames,
46
57
  buildComponents,
58
+ buildComponentsFromCombinations,
47
59
  calculatePotentialReduction,
60
+ collectVariantRegistry,
48
61
  dedupeSubsetCombinations,
49
62
  extractClassesFromExpression,
63
+ extractClassesFromVariantCall,
50
64
  extractFromJSXAttribute,
51
65
  findFrequentPatterns,
52
66
  findRepeatedClassSets,
67
+ formatModifiedFiles,
68
+ formatSource,
53
69
  generateCombinations,
54
70
  generateCommand,
55
71
  generateComponentCss,
56
72
  isClassAttribute,
57
73
  isStrictSubset,
74
+ isVariantCallee,
58
75
  loadCommandOptions,
76
+ loadExtractableCombinations,
59
77
  normalizeClassPrefix,
60
78
  normalizeClasses,
61
79
  normalizeNamesConfig,
62
80
  parseFile,
63
81
  parseSource,
64
82
  parseSourceToAst,
83
+ printApplyJsonReport,
65
84
  printConsoleReport,
85
+ printGenerateJsonReport,
66
86
  printJsonReport,
67
87
  replaceClassNamesInSource,
68
88
  scanProject,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailwind-unwind",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Analyze Tailwind CSS class usage patterns in React/Next.js projects",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -44,6 +44,14 @@
44
44
  "engines": {
45
45
  "node": ">=18"
46
46
  },
47
+ "peerDependencies": {
48
+ "prettier": ">=3.0.0"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "prettier": {
52
+ "optional": true
53
+ }
54
+ },
47
55
  "dependencies": {
48
56
  "@babel/generator": "^7.27.0",
49
57
  "@babel/parser": "^7.27.0",
@@ -60,6 +68,7 @@
60
68
  "@types/node": "^22.15.3",
61
69
  "tsup": "^8.4.0",
62
70
  "typescript": "^5.8.3",
71
+ "prettier": "^3.5.3",
63
72
  "vitest": "^3.1.2"
64
73
  }
65
74
  }
@@ -14,11 +14,14 @@
14
14
  "minOccurrences": 3,
15
15
  "prefix": "twu-",
16
16
  "output": "src/styles/components.css",
17
- "top": 20
17
+ "top": 20,
18
+ "fromReport": "report.json",
19
+ "extractableOnly": true
18
20
  },
19
21
  "apply": {
20
22
  "minOccurrences": 3,
21
23
  "prefix": "twu-",
22
- "output": "src/styles/components.css"
24
+ "output": "src/styles/components.css",
25
+ "prettier": true
23
26
  }
24
27
  }