tailwind-unwind 0.3.0 → 0.5.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 +130 -239
- package/dist/{chunk-4GXMK3NB.js → chunk-RMTZCCPS.js} +664 -129
- package/dist/chunk-RMTZCCPS.js.map +1 -0
- package/dist/cli/index.js +133 -43
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +148 -39
- package/dist/index.js +21 -1
- package/package.json +3 -2
- package/dist/chunk-4GXMK3NB.js.map +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,30 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
ANALYZE_DEFAULTS,
|
|
4
|
+
DEFAULT_TARGET_PATH,
|
|
5
|
+
GENERATE_DEFAULTS,
|
|
3
6
|
analyzeCommand,
|
|
4
7
|
applyCommand,
|
|
8
|
+
checkCommand,
|
|
5
9
|
generateCommand,
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
initCommand,
|
|
11
|
+
loadCommandOptions,
|
|
12
|
+
resolveOutputPath,
|
|
13
|
+
resolveTargetPath
|
|
14
|
+
} from "../chunk-RMTZCCPS.js";
|
|
8
15
|
|
|
9
16
|
// src/cli/index.ts
|
|
10
17
|
import { Command } from "commander";
|
|
11
18
|
import chalk from "chalk";
|
|
12
19
|
|
|
13
|
-
// src/cli/defaults.ts
|
|
14
|
-
var ANALYZE_DEFAULTS = {
|
|
15
|
-
minOccurrences: 5,
|
|
16
|
-
minSize: 2,
|
|
17
|
-
maxSize: 5,
|
|
18
|
-
top: 10
|
|
19
|
-
};
|
|
20
|
-
var GENERATE_DEFAULTS = {
|
|
21
|
-
minOccurrences: 3,
|
|
22
|
-
minSize: 2,
|
|
23
|
-
maxSize: 5,
|
|
24
|
-
top: 10,
|
|
25
|
-
prefix: "twu-"
|
|
26
|
-
};
|
|
27
|
-
|
|
28
20
|
// src/cli/parseOptions.ts
|
|
29
21
|
function splitPatterns(value) {
|
|
30
22
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
@@ -60,7 +52,9 @@ async function resolveCommandOptions(command, opts, targetPath) {
|
|
|
60
52
|
dryRun: opts.dryRun,
|
|
61
53
|
prettier: opts.prettier,
|
|
62
54
|
fromReport: opts.fromReport,
|
|
63
|
-
extractableOnly: opts.extractableOnly
|
|
55
|
+
extractableOnly: opts.extractableOnly,
|
|
56
|
+
changed: parseChanged(opts.changed),
|
|
57
|
+
force: opts.force
|
|
64
58
|
},
|
|
65
59
|
{ targetPath }
|
|
66
60
|
);
|
|
@@ -80,9 +74,23 @@ async function resolveCommandOptions(command, opts, targetPath) {
|
|
|
80
74
|
dryRun: opts.dryRun ?? resolved.dryRun,
|
|
81
75
|
prettier: opts.prettier ?? resolved.prettier,
|
|
82
76
|
fromReport: opts.fromReport ?? resolved.fromReport,
|
|
83
|
-
extractableOnly: opts.extractableOnly ?? resolved.extractableOnly
|
|
77
|
+
extractableOnly: opts.extractableOnly ?? resolved.extractableOnly,
|
|
78
|
+
changed: parseChanged(opts.changed) ?? resolved.changed,
|
|
79
|
+
force: opts.force ?? resolved.force
|
|
84
80
|
};
|
|
85
81
|
}
|
|
82
|
+
function parseChanged(value) {
|
|
83
|
+
if (value === void 0 || value === null || value === "") {
|
|
84
|
+
return void 0;
|
|
85
|
+
}
|
|
86
|
+
if (value === true || value === "true") {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
if (typeof value === "string") {
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
return void 0;
|
|
93
|
+
}
|
|
86
94
|
function withNumericDefaults(resolved, opts, defaults) {
|
|
87
95
|
return {
|
|
88
96
|
...resolved,
|
|
@@ -116,20 +124,69 @@ function addSharedOptions(command) {
|
|
|
116
124
|
).option(
|
|
117
125
|
"--exclude <patterns>",
|
|
118
126
|
'Comma-separated glob exclude patterns (e.g. "**/*.test.tsx")'
|
|
127
|
+
).option(
|
|
128
|
+
"--changed [ref]",
|
|
129
|
+
"Only scan git-changed files (optional ref, default: working tree vs HEAD)"
|
|
119
130
|
);
|
|
120
131
|
}
|
|
132
|
+
function optionalCliNumber(value) {
|
|
133
|
+
if (value === void 0 || value === null || value === "") {
|
|
134
|
+
return void 0;
|
|
135
|
+
}
|
|
136
|
+
const parsed = Number(value);
|
|
137
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
138
|
+
}
|
|
139
|
+
function resolveChangedFlag(opts) {
|
|
140
|
+
if (!process.argv.includes("--changed")) {
|
|
141
|
+
return void 0;
|
|
142
|
+
}
|
|
143
|
+
if (typeof opts.changed === "string" && opts.changed.length > 0) {
|
|
144
|
+
return opts.changed;
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
121
148
|
program.name("tailwind-unwind").description("Analyze Tailwind CSS class usage in React/Next.js projects").version(CLI_VERSION);
|
|
149
|
+
program.command("init").description("Create a starter tailwind-unwind.config.json from project scan").argument("[path]", "Project directory", DEFAULT_TARGET_PATH).option("--output <file>", "Config output path").option("--force", "Overwrite existing config file").option("--min-occurrences <n>", "Minimum occurrences threshold").option("--top <n>", "Number of patterns to include in names").option("--prefix <name>", "Namespace prefix for generated classes").action(async (targetPath, opts) => {
|
|
150
|
+
try {
|
|
151
|
+
const scanPath = resolveTargetPath(targetPath);
|
|
152
|
+
const resolved = withNumericDefaults(
|
|
153
|
+
await resolveCommandOptions("init", opts, scanPath),
|
|
154
|
+
opts,
|
|
155
|
+
ANALYZE_DEFAULTS
|
|
156
|
+
);
|
|
157
|
+
await initCommand(scanPath, {
|
|
158
|
+
output: opts.output ?? resolved.output,
|
|
159
|
+
force: Boolean(opts.force || resolved.force),
|
|
160
|
+
minOccurrences: resolved.minOccurrences,
|
|
161
|
+
top: resolved.top,
|
|
162
|
+
prefix: resolved.prefix ?? GENERATE_DEFAULTS.prefix,
|
|
163
|
+
include: resolved.include,
|
|
164
|
+
exclude: resolved.exclude
|
|
165
|
+
});
|
|
166
|
+
} catch (error) {
|
|
167
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
168
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
122
172
|
addSharedOptions(
|
|
123
|
-
program.command("analyze").description("Scan a directory and report frequent Tailwind class combinations").argument("
|
|
173
|
+
program.command("analyze").description("Scan a directory and report frequent Tailwind class combinations").argument("[path]", "Directory to analyze", DEFAULT_TARGET_PATH).option("--min-occurrences <n>", "Minimum occurrences threshold").option("--min-size <n>", "Minimum classes per combination").option("--max-size <n>", "Maximum classes per combination").option("--top <n>", "Number of top combinations to show").option("--format <type>", "Output format: console or json", "console").option("--no-dedupe-subsets", "Include subset combinations in results")
|
|
124
174
|
).action(async (targetPath, opts) => {
|
|
125
175
|
try {
|
|
176
|
+
const scanPath = resolveTargetPath(targetPath);
|
|
126
177
|
const resolved = withNumericDefaults(
|
|
127
|
-
await resolveCommandOptions("analyze", opts,
|
|
178
|
+
await resolveCommandOptions("analyze", { ...opts, changed: resolveChangedFlag(opts) }, scanPath),
|
|
128
179
|
opts,
|
|
129
180
|
ANALYZE_DEFAULTS
|
|
130
181
|
);
|
|
131
|
-
|
|
182
|
+
const generateResolved = withNumericDefaults(
|
|
183
|
+
await resolveCommandOptions("generate", { ...opts, changed: resolveChangedFlag(opts) }, scanPath),
|
|
184
|
+
opts,
|
|
185
|
+
GENERATE_DEFAULTS
|
|
186
|
+
);
|
|
187
|
+
await analyzeCommand(scanPath, {
|
|
132
188
|
minOccurrences: resolved.minOccurrences,
|
|
189
|
+
extractableMinOccurrences: generateResolved.minOccurrences,
|
|
133
190
|
minSize: resolved.minSize,
|
|
134
191
|
maxSize: resolved.maxSize,
|
|
135
192
|
top: resolved.top,
|
|
@@ -137,6 +194,7 @@ addSharedOptions(
|
|
|
137
194
|
dedupeSubsets: process.argv.includes("--no-dedupe-subsets") ? false : resolved.dedupeSubsets ?? true,
|
|
138
195
|
include: resolved.include,
|
|
139
196
|
exclude: resolved.exclude,
|
|
197
|
+
changed: resolved.changed,
|
|
140
198
|
configPath: resolved.configPath
|
|
141
199
|
});
|
|
142
200
|
} catch (error) {
|
|
@@ -146,24 +204,16 @@ addSharedOptions(
|
|
|
146
204
|
}
|
|
147
205
|
});
|
|
148
206
|
addSharedOptions(
|
|
149
|
-
program.command("generate").description("Generate @layer components CSS from repeated className sets").argument("[path]", "Directory to
|
|
207
|
+
program.command("generate").description("Generate @layer components CSS from repeated className sets").argument("[path]", "Directory to scan", DEFAULT_TARGET_PATH).option("--output <file>", "Output CSS file path").option("--from-report <file>", "Generate from analyze JSON report").option("--extractable-only", "Only generate extractable patterns from analyze").option("--format <type>", "Output format: console or json", "console").option("--min-occurrences <n>", "Minimum occurrences threshold").option("--min-size <n>", "Minimum classes per combination").option("--max-size <n>", "Maximum classes per combination").option("--top <n>", "Number of combinations to generate").option("--prefix <name>", "Namespace prefix for generated classes")
|
|
150
208
|
).action(async (targetPath, opts) => {
|
|
151
209
|
try {
|
|
210
|
+
const scanPath = resolveTargetPath(targetPath);
|
|
152
211
|
const resolved = withNumericDefaults(
|
|
153
|
-
await resolveCommandOptions("generate", opts,
|
|
212
|
+
await resolveCommandOptions("generate", { ...opts, changed: resolveChangedFlag(opts) }, scanPath),
|
|
154
213
|
opts,
|
|
155
214
|
GENERATE_DEFAULTS
|
|
156
215
|
);
|
|
157
|
-
const output = opts.output
|
|
158
|
-
const scanPath = targetPath ?? ".";
|
|
159
|
-
if (!output) {
|
|
160
|
-
console.error(chalk.red("Error: --output is required"));
|
|
161
|
-
process.exit(1);
|
|
162
|
-
}
|
|
163
|
-
if (!opts.fromReport && !resolved.fromReport && !targetPath) {
|
|
164
|
-
console.error(chalk.red("Error: <path> is required without --from-report"));
|
|
165
|
-
process.exit(1);
|
|
166
|
-
}
|
|
216
|
+
const output = resolveOutputPath(opts.output, resolved.output);
|
|
167
217
|
await generateCommand(scanPath, {
|
|
168
218
|
output,
|
|
169
219
|
minOccurrences: resolved.minOccurrences,
|
|
@@ -173,6 +223,7 @@ addSharedOptions(
|
|
|
173
223
|
prefix: resolved.prefix,
|
|
174
224
|
include: resolved.include,
|
|
175
225
|
exclude: resolved.exclude,
|
|
226
|
+
changed: resolved.changed,
|
|
176
227
|
configPath: resolved.configPath,
|
|
177
228
|
names: resolved.names,
|
|
178
229
|
format: resolved.format,
|
|
@@ -186,20 +237,17 @@ addSharedOptions(
|
|
|
186
237
|
}
|
|
187
238
|
});
|
|
188
239
|
addSharedOptions(
|
|
189
|
-
program.command("apply").description("Replace repeated className strings with generated component classes").argument("
|
|
240
|
+
program.command("apply").description("Replace repeated className strings with generated component classes").argument("[path]", "Directory to modify", DEFAULT_TARGET_PATH).option("--output <file>", "Output CSS file path").option("--from-report <file>", "Use component list from analyze JSON report").option("--extractable-only", "Only apply extractable patterns from analyze").option("--format <type>", "Output format: console or json", "console").option("--prettier", "Format modified files with Prettier when available").option("--min-occurrences <n>", "Minimum occurrences threshold").option("--min-size <n>", "Minimum classes per combination").option("--max-size <n>", "Maximum classes per combination").option("--top <n>", "Number of component classes to use").option("--dry-run", "Preview replacements without writing files").option("--verbose-skipped", "List every skipped replacement location").option("--prefix <name>", "Namespace prefix for generated classes")
|
|
190
241
|
).action(async (targetPath, opts) => {
|
|
191
242
|
try {
|
|
243
|
+
const scanPath = resolveTargetPath(targetPath);
|
|
192
244
|
const resolved = withNumericDefaults(
|
|
193
|
-
await resolveCommandOptions("apply", opts,
|
|
245
|
+
await resolveCommandOptions("apply", { ...opts, changed: resolveChangedFlag(opts) }, scanPath),
|
|
194
246
|
opts,
|
|
195
247
|
GENERATE_DEFAULTS
|
|
196
248
|
);
|
|
197
|
-
const output = opts.output
|
|
198
|
-
|
|
199
|
-
console.error(chalk.red("Error: --output is required"));
|
|
200
|
-
process.exit(1);
|
|
201
|
-
}
|
|
202
|
-
await applyCommand(targetPath, {
|
|
249
|
+
const output = resolveOutputPath(opts.output, resolved.output);
|
|
250
|
+
await applyCommand(scanPath, {
|
|
203
251
|
output,
|
|
204
252
|
minOccurrences: resolved.minOccurrences,
|
|
205
253
|
minSize: resolved.minSize,
|
|
@@ -208,13 +256,55 @@ addSharedOptions(
|
|
|
208
256
|
prefix: resolved.prefix,
|
|
209
257
|
include: resolved.include,
|
|
210
258
|
exclude: resolved.exclude,
|
|
259
|
+
changed: resolved.changed,
|
|
211
260
|
configPath: resolved.configPath,
|
|
212
261
|
names: resolved.names,
|
|
213
262
|
format: resolved.format,
|
|
214
263
|
fromReport: opts.fromReport ?? resolved.fromReport,
|
|
215
264
|
extractableOnly: Boolean(opts.extractableOnly || resolved.extractableOnly),
|
|
216
265
|
dryRun: process.argv.includes("--dry-run") ? true : Boolean(resolved.dryRun),
|
|
217
|
-
prettier: Boolean(opts.prettier || resolved.prettier)
|
|
266
|
+
prettier: Boolean(opts.prettier || resolved.prettier),
|
|
267
|
+
verboseSkipped: Boolean(opts.verboseSkipped)
|
|
268
|
+
});
|
|
269
|
+
} catch (error) {
|
|
270
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
271
|
+
console.error("Unexpected error:", message);
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
addSharedOptions(
|
|
276
|
+
program.command("check").description("Scan for extractable duplicates and preview apply (dry-run)").argument("[path]", "Directory to scan", DEFAULT_TARGET_PATH).option("--output <file>", "CSS output path used in the apply preview").option("--format <type>", "Output format: console or json", "console").option("--min-occurrences <n>", "Minimum occurrences for the analyze list").option("--top <n>", "Number of extractable patterns to show").option("--fail-on-extractable <n>", "Exit 1 when extractable patterns exceed n").option("--verbose-skipped", "List every skipped replacement location").option("--prefix <name>", "Namespace prefix for generated classes")
|
|
277
|
+
).action(async (targetPath, opts) => {
|
|
278
|
+
try {
|
|
279
|
+
const scanPath = resolveTargetPath(targetPath);
|
|
280
|
+
const analyzeResolved = withNumericDefaults(
|
|
281
|
+
await resolveCommandOptions("analyze", { ...opts, changed: resolveChangedFlag(opts) }, scanPath),
|
|
282
|
+
opts,
|
|
283
|
+
ANALYZE_DEFAULTS
|
|
284
|
+
);
|
|
285
|
+
const generateResolved = withNumericDefaults(
|
|
286
|
+
await resolveCommandOptions("generate", { ...opts, changed: resolveChangedFlag(opts) }, scanPath),
|
|
287
|
+
opts,
|
|
288
|
+
GENERATE_DEFAULTS
|
|
289
|
+
);
|
|
290
|
+
const output = resolveOutputPath(opts.output, generateResolved.output);
|
|
291
|
+
const failOnExtractable = process.argv.includes("--fail-on-extractable") ? optionalCliNumber(opts.failOnExtractable) ?? 0 : void 0;
|
|
292
|
+
await checkCommand(scanPath, {
|
|
293
|
+
minOccurrences: analyzeResolved.minOccurrences,
|
|
294
|
+
extractableMinOccurrences: generateResolved.minOccurrences,
|
|
295
|
+
minSize: analyzeResolved.minSize,
|
|
296
|
+
maxSize: analyzeResolved.maxSize,
|
|
297
|
+
top: analyzeResolved.top,
|
|
298
|
+
prefix: generateResolved.prefix,
|
|
299
|
+
include: analyzeResolved.include,
|
|
300
|
+
exclude: analyzeResolved.exclude,
|
|
301
|
+
changed: analyzeResolved.changed,
|
|
302
|
+
configPath: analyzeResolved.configPath ?? generateResolved.configPath,
|
|
303
|
+
names: generateResolved.names,
|
|
304
|
+
output,
|
|
305
|
+
format: opts.format === "json" ? "json" : "console",
|
|
306
|
+
failOnExtractable,
|
|
307
|
+
verboseSkipped: Boolean(opts.verboseSkipped)
|
|
218
308
|
});
|
|
219
309
|
} catch (error) {
|
|
220
310
|
const message = error instanceof Error ? error.message : String(error);
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/index.ts","../../src/cli/defaults.ts","../../src/cli/parseOptions.ts","../../src/cli/version.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { analyzeCommand } from '../commands/analyze.js';\nimport { applyCommand } from '../commands/apply.js';\nimport { generateCommand } from '../commands/generate.js';\nimport { ANALYZE_DEFAULTS, GENERATE_DEFAULTS } from './defaults.js';\nimport { resolveCommandOptions, withNumericDefaults } from './parseOptions.js';\nimport { CLI_VERSION } from './version.js';\n\nconst program = new Command();\n\nfunction addSharedOptions(command: Command): Command {\n return command\n .option('--config <file>', 'Path to tailwind-unwind config file')\n .option(\n '--include <patterns>',\n 'Comma-separated glob include patterns (e.g. \"src/**/*.tsx\")',\n )\n .option(\n '--exclude <patterns>',\n 'Comma-separated glob exclude patterns (e.g. \"**/*.test.tsx\")',\n );\n}\n\nprogram\n .name('tailwind-unwind')\n .description('Analyze Tailwind CSS class usage in React/Next.js projects')\n .version(CLI_VERSION);\n\naddSharedOptions(\n program\n .command('analyze')\n .description('Scan a directory and report frequent Tailwind class combinations')\n .argument('<path>', 'Directory to analyze')\n .option('--min-occurrences <n>', 'Minimum occurrences threshold')\n .option('--min-size <n>', 'Minimum classes per combination')\n .option('--max-size <n>', 'Maximum classes per combination')\n .option('--top <n>', 'Number of top combinations to show')\n .option('--format <type>', 'Output format: console or json', 'console')\n .option('--no-dedupe-subsets', 'Include subset combinations in results'),\n).action(async (targetPath: string, opts) => {\n try {\n const resolved = withNumericDefaults(\n await resolveCommandOptions('analyze', opts, targetPath),\n opts,\n ANALYZE_DEFAULTS,\n );\n\n await analyzeCommand(targetPath, {\n minOccurrences: resolved.minOccurrences,\n minSize: resolved.minSize,\n maxSize: resolved.maxSize,\n top: resolved.top,\n format: resolved.format,\n dedupeSubsets: process.argv.includes('--no-dedupe-subsets')\n ? false\n : (resolved.dedupeSubsets ?? true),\n include: resolved.include,\n exclude: resolved.exclude,\n configPath: resolved.configPath,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error('Unexpected error:', message);\n process.exit(1);\n }\n});\n\naddSharedOptions(\n program\n .command('generate')\n .description('Generate @layer components CSS from repeated className sets')\n .argument('[path]', 'Directory to analyze')\n .option('--output <file>', 'Output CSS file path')\n .option('--from-report <file>', 'Generate from analyze JSON report')\n .option('--extractable-only', 'Only generate extractable patterns from analyze')\n .option('--format <type>', 'Output format: console or json', 'console')\n .option('--min-occurrences <n>', 'Minimum occurrences threshold')\n .option('--min-size <n>', 'Minimum classes per combination')\n .option('--max-size <n>', 'Maximum classes per combination')\n .option('--top <n>', 'Number of combinations to generate')\n .option('--prefix <name>', 'Namespace prefix for generated classes'),\n).action(async (targetPath: string | undefined, opts) => {\n try {\n const resolved = withNumericDefaults(\n await resolveCommandOptions('generate', opts, targetPath),\n opts,\n GENERATE_DEFAULTS,\n );\n const output = opts.output ?? resolved.output;\n const scanPath = targetPath ?? '.';\n\n if (!output) {\n console.error(chalk.red('Error: --output is required'));\n process.exit(1);\n }\n\n if (!opts.fromReport && !resolved.fromReport && !targetPath) {\n console.error(chalk.red('Error: <path> is required without --from-report'));\n process.exit(1);\n }\n\n await generateCommand(scanPath, {\n output,\n minOccurrences: resolved.minOccurrences,\n minSize: resolved.minSize,\n maxSize: resolved.maxSize,\n top: resolved.top,\n prefix: resolved.prefix,\n include: resolved.include,\n exclude: resolved.exclude,\n configPath: resolved.configPath,\n names: resolved.names,\n format: resolved.format,\n fromReport: opts.fromReport ?? resolved.fromReport,\n extractableOnly: Boolean(opts.extractableOnly || resolved.extractableOnly),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error('Unexpected error:', message);\n process.exit(1);\n }\n});\n\naddSharedOptions(\n program\n .command('apply')\n .description('Replace repeated className strings with generated component classes')\n .argument('<path>', 'Directory to modify')\n .option('--output <file>', 'Output CSS file path')\n .option('--from-report <file>', 'Use component list from analyze JSON report')\n .option('--extractable-only', 'Only apply extractable patterns from analyze')\n .option('--format <type>', 'Output format: console or json', 'console')\n .option('--prettier', 'Format modified files with Prettier when available')\n .option('--min-occurrences <n>', 'Minimum occurrences threshold')\n .option('--min-size <n>', 'Minimum classes per combination')\n .option('--max-size <n>', 'Maximum classes per combination')\n .option('--top <n>', 'Number of component classes to use')\n .option('--dry-run', 'Preview replacements without writing files')\n .option('--prefix <name>', 'Namespace prefix for generated classes'),\n).action(async (targetPath: string, opts) => {\n try {\n const resolved = withNumericDefaults(\n await resolveCommandOptions('apply', opts, targetPath),\n opts,\n GENERATE_DEFAULTS,\n );\n const output = opts.output ?? resolved.output;\n\n if (!output) {\n console.error(chalk.red('Error: --output is required'));\n process.exit(1);\n }\n\n await applyCommand(targetPath, {\n output,\n minOccurrences: resolved.minOccurrences,\n minSize: resolved.minSize,\n maxSize: resolved.maxSize,\n top: resolved.top,\n prefix: resolved.prefix,\n include: resolved.include,\n exclude: resolved.exclude,\n configPath: resolved.configPath,\n names: resolved.names,\n format: resolved.format,\n fromReport: opts.fromReport ?? resolved.fromReport,\n extractableOnly: Boolean(opts.extractableOnly || resolved.extractableOnly),\n dryRun: process.argv.includes('--dry-run')\n ? true\n : Boolean(resolved.dryRun),\n prettier: Boolean(opts.prettier || resolved.prettier),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error('Unexpected error:', message);\n process.exit(1);\n }\n});\n\nprogram.parse();\n","export const ANALYZE_DEFAULTS = {\n minOccurrences: 5,\n minSize: 2,\n maxSize: 5,\n top: 10,\n} as const;\n\nexport const GENERATE_DEFAULTS = {\n minOccurrences: 3,\n minSize: 2,\n maxSize: 5,\n top: 10,\n prefix: 'twu-',\n} as const;\n","import { loadCommandOptions } from '../config/loadConfig.js';\nimport type { CliCommand } from '../config/types.js';\nimport type { AnalyzeOptions } from '../parser/types.js';\n\nfunction splitPatterns(value: unknown): string[] | undefined {\n if (typeof value !== 'string' || value.trim().length === 0) {\n return undefined;\n }\n\n return value\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part.length > 0);\n}\n\nfunction optionalNumber(value: unknown): number | undefined {\n if (value === undefined || value === null || value === '') {\n return undefined;\n }\n\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nexport interface RawCliOptions {\n config?: string;\n minOccurrences?: string | number;\n minSize?: string | number;\n maxSize?: string | number;\n top?: string | number;\n prefix?: string;\n dedupeSubsets?: boolean;\n include?: string;\n exclude?: string;\n output?: string;\n format?: string;\n dryRun?: boolean;\n prettier?: boolean;\n fromReport?: string;\n extractableOnly?: boolean;\n}\n\nfunction cliNumber(\n value: string | number | undefined,\n fallback: number,\n): number {\n const parsed = optionalNumber(value);\n return parsed ?? fallback;\n}\n\n/**\n * Merge config file values with CLI flags (CLI wins).\n */\nexport async function resolveCommandOptions(\n command: CliCommand,\n opts: RawCliOptions,\n targetPath?: string,\n): Promise<\n AnalyzeOptions & { output?: string; dryRun?: boolean; names?: Record<string, string> }\n> {\n const resolved = await loadCommandOptions(\n command,\n {\n configPath: opts.config,\n minOccurrences: optionalNumber(opts.minOccurrences),\n minSize: optionalNumber(opts.minSize),\n maxSize: optionalNumber(opts.maxSize),\n top: optionalNumber(opts.top),\n prefix: opts.prefix,\n dedupeSubsets: opts.dedupeSubsets,\n include: splitPatterns(opts.include),\n exclude: splitPatterns(opts.exclude),\n output: opts.output,\n dryRun: opts.dryRun,\n prettier: opts.prettier,\n fromReport: opts.fromReport,\n extractableOnly: opts.extractableOnly,\n },\n { targetPath },\n );\n\n return {\n minOccurrences: resolved.minOccurrences,\n minSize: resolved.minSize,\n maxSize: resolved.maxSize,\n top: resolved.top,\n prefix: resolved.prefix,\n dedupeSubsets: resolved.dedupeSubsets,\n include: resolved.include,\n exclude: resolved.exclude,\n configPath: resolved.configPath,\n output: resolved.output,\n names: resolved.names,\n format: opts.format === 'json' ? 'json' : 'console',\n dryRun: opts.dryRun ?? resolved.dryRun,\n prettier: opts.prettier ?? resolved.prettier,\n fromReport: opts.fromReport ?? resolved.fromReport,\n extractableOnly: opts.extractableOnly ?? resolved.extractableOnly,\n };\n}\n\nexport function withNumericDefaults(\n resolved: Awaited<ReturnType<typeof resolveCommandOptions>>,\n opts: RawCliOptions,\n defaults: {\n minOccurrences: number;\n minSize: number;\n maxSize: number;\n top: number;\n prefix?: string;\n },\n) {\n return {\n ...resolved,\n minOccurrences:\n resolved.minOccurrences ??\n cliNumber(opts.minOccurrences, defaults.minOccurrences),\n minSize: resolved.minSize ?? cliNumber(opts.minSize, defaults.minSize),\n maxSize: resolved.maxSize ?? cliNumber(opts.maxSize, defaults.maxSize),\n top: resolved.top ?? cliNumber(opts.top, defaults.top),\n prefix: resolved.prefix ?? opts.prefix ?? defaults.prefix,\n };\n}\n\n/** @deprecated Use resolveCommandOptions */\nexport const resolveAnalyzeOptions = (\n opts: RawCliOptions,\n targetPath?: string,\n) => resolveCommandOptions('analyze', opts, targetPath);\n","import { readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nfunction readPackageVersion(): string {\n const currentDir = path.dirname(fileURLToPath(import.meta.url));\n const packageJsonPath = path.join(currentDir, '../../package.json');\n const raw = readFileSync(packageJsonPath, 'utf-8');\n const pkg = JSON.parse(raw) as { version?: string };\n return pkg.version ?? '0.0.0';\n}\n\nexport const CLI_VERSION = readPackageVersion();\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/index.ts","../../src/cli/parseOptions.ts","../../src/cli/version.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { analyzeCommand } from '../commands/analyze.js';\nimport { applyCommand } from '../commands/apply.js';\nimport { checkCommand } from '../commands/check.js';\nimport { generateCommand } from '../commands/generate.js';\nimport { initCommand } from '../commands/init.js';\nimport {\n ANALYZE_DEFAULTS,\n DEFAULT_TARGET_PATH,\n GENERATE_DEFAULTS,\n resolveOutputPath,\n resolveTargetPath,\n} from './defaults.js';\nimport { resolveCommandOptions, withNumericDefaults } from './parseOptions.js';\nimport { CLI_VERSION } from './version.js';\n\nconst program = new Command();\n\nfunction addSharedOptions(command: Command): Command {\n return command\n .option('--config <file>', 'Path to tailwind-unwind config file')\n .option(\n '--include <patterns>',\n 'Comma-separated glob include patterns (e.g. \"src/**/*.tsx\")',\n )\n .option(\n '--exclude <patterns>',\n 'Comma-separated glob exclude patterns (e.g. \"**/*.test.tsx\")',\n )\n .option(\n '--changed [ref]',\n 'Only scan git-changed files (optional ref, default: working tree vs HEAD)',\n );\n}\n\nfunction optionalCliNumber(value: unknown): number | undefined {\n if (value === undefined || value === null || value === '') {\n return undefined;\n }\n\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction resolveChangedFlag(opts: { changed?: string | boolean }): boolean | string | undefined {\n if (!process.argv.includes('--changed')) {\n return undefined;\n }\n\n if (typeof opts.changed === 'string' && opts.changed.length > 0) {\n return opts.changed;\n }\n\n return true;\n}\n\nprogram\n .name('tailwind-unwind')\n .description('Analyze Tailwind CSS class usage in React/Next.js projects')\n .version(CLI_VERSION);\n\nprogram\n .command('init')\n .description('Create a starter tailwind-unwind.config.json from project scan')\n .argument('[path]', 'Project directory', DEFAULT_TARGET_PATH)\n .option('--output <file>', 'Config output path')\n .option('--force', 'Overwrite existing config file')\n .option('--min-occurrences <n>', 'Minimum occurrences threshold')\n .option('--top <n>', 'Number of patterns to include in names')\n .option('--prefix <name>', 'Namespace prefix for generated classes')\n .action(async (targetPath: string, opts) => {\n try {\n const scanPath = resolveTargetPath(targetPath);\n const resolved = withNumericDefaults(\n await resolveCommandOptions('init', opts, scanPath),\n opts,\n ANALYZE_DEFAULTS,\n );\n\n await initCommand(scanPath, {\n output: opts.output ?? resolved.output,\n force: Boolean(opts.force || resolved.force),\n minOccurrences: resolved.minOccurrences,\n top: resolved.top,\n prefix: resolved.prefix ?? GENERATE_DEFAULTS.prefix,\n include: resolved.include,\n exclude: resolved.exclude,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(chalk.red(`Error: ${message}`));\n process.exit(1);\n }\n });\n\naddSharedOptions(\n program\n .command('analyze')\n .description('Scan a directory and report frequent Tailwind class combinations')\n .argument('[path]', 'Directory to analyze', DEFAULT_TARGET_PATH)\n .option('--min-occurrences <n>', 'Minimum occurrences threshold')\n .option('--min-size <n>', 'Minimum classes per combination')\n .option('--max-size <n>', 'Maximum classes per combination')\n .option('--top <n>', 'Number of top combinations to show')\n .option('--format <type>', 'Output format: console or json', 'console')\n .option('--no-dedupe-subsets', 'Include subset combinations in results'),\n).action(async (targetPath: string, opts) => {\n try {\n const scanPath = resolveTargetPath(targetPath);\n const resolved = withNumericDefaults(\n await resolveCommandOptions('analyze', { ...opts, changed: resolveChangedFlag(opts) }, scanPath),\n opts,\n ANALYZE_DEFAULTS,\n );\n const generateResolved = withNumericDefaults(\n await resolveCommandOptions('generate', { ...opts, changed: resolveChangedFlag(opts) }, scanPath),\n opts,\n GENERATE_DEFAULTS,\n );\n\n await analyzeCommand(scanPath, {\n minOccurrences: resolved.minOccurrences,\n extractableMinOccurrences: generateResolved.minOccurrences,\n minSize: resolved.minSize,\n maxSize: resolved.maxSize,\n top: resolved.top,\n format: resolved.format,\n dedupeSubsets: process.argv.includes('--no-dedupe-subsets')\n ? false\n : (resolved.dedupeSubsets ?? true),\n include: resolved.include,\n exclude: resolved.exclude,\n changed: resolved.changed,\n configPath: resolved.configPath,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error('Unexpected error:', message);\n process.exit(1);\n }\n});\n\naddSharedOptions(\n program\n .command('generate')\n .description('Generate @layer components CSS from repeated className sets')\n .argument('[path]', 'Directory to scan', DEFAULT_TARGET_PATH)\n .option('--output <file>', 'Output CSS file path')\n .option('--from-report <file>', 'Generate from analyze JSON report')\n .option('--extractable-only', 'Only generate extractable patterns from analyze')\n .option('--format <type>', 'Output format: console or json', 'console')\n .option('--min-occurrences <n>', 'Minimum occurrences threshold')\n .option('--min-size <n>', 'Minimum classes per combination')\n .option('--max-size <n>', 'Maximum classes per combination')\n .option('--top <n>', 'Number of combinations to generate')\n .option('--prefix <name>', 'Namespace prefix for generated classes'),\n).action(async (targetPath: string | undefined, opts) => {\n try {\n const scanPath = resolveTargetPath(targetPath);\n const resolved = withNumericDefaults(\n await resolveCommandOptions('generate', { ...opts, changed: resolveChangedFlag(opts) }, scanPath),\n opts,\n GENERATE_DEFAULTS,\n );\n const output = resolveOutputPath(opts.output, resolved.output);\n\n await generateCommand(scanPath, {\n output,\n minOccurrences: resolved.minOccurrences,\n minSize: resolved.minSize,\n maxSize: resolved.maxSize,\n top: resolved.top,\n prefix: resolved.prefix,\n include: resolved.include,\n exclude: resolved.exclude,\n changed: resolved.changed,\n configPath: resolved.configPath,\n names: resolved.names,\n format: resolved.format,\n fromReport: opts.fromReport ?? resolved.fromReport,\n extractableOnly: Boolean(opts.extractableOnly || resolved.extractableOnly),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error('Unexpected error:', message);\n process.exit(1);\n }\n});\n\naddSharedOptions(\n program\n .command('apply')\n .description('Replace repeated className strings with generated component classes')\n .argument('[path]', 'Directory to modify', DEFAULT_TARGET_PATH)\n .option('--output <file>', 'Output CSS file path')\n .option('--from-report <file>', 'Use component list from analyze JSON report')\n .option('--extractable-only', 'Only apply extractable patterns from analyze')\n .option('--format <type>', 'Output format: console or json', 'console')\n .option('--prettier', 'Format modified files with Prettier when available')\n .option('--min-occurrences <n>', 'Minimum occurrences threshold')\n .option('--min-size <n>', 'Minimum classes per combination')\n .option('--max-size <n>', 'Maximum classes per combination')\n .option('--top <n>', 'Number of component classes to use')\n .option('--dry-run', 'Preview replacements without writing files')\n .option('--verbose-skipped', 'List every skipped replacement location')\n .option('--prefix <name>', 'Namespace prefix for generated classes'),\n).action(async (targetPath: string, opts) => {\n try {\n const scanPath = resolveTargetPath(targetPath);\n const resolved = withNumericDefaults(\n await resolveCommandOptions('apply', { ...opts, changed: resolveChangedFlag(opts) }, scanPath),\n opts,\n GENERATE_DEFAULTS,\n );\n const output = resolveOutputPath(opts.output, resolved.output);\n\n await applyCommand(scanPath, {\n output,\n minOccurrences: resolved.minOccurrences,\n minSize: resolved.minSize,\n maxSize: resolved.maxSize,\n top: resolved.top,\n prefix: resolved.prefix,\n include: resolved.include,\n exclude: resolved.exclude,\n changed: resolved.changed,\n configPath: resolved.configPath,\n names: resolved.names,\n format: resolved.format,\n fromReport: opts.fromReport ?? resolved.fromReport,\n extractableOnly: Boolean(opts.extractableOnly || resolved.extractableOnly),\n dryRun: process.argv.includes('--dry-run')\n ? true\n : Boolean(resolved.dryRun),\n prettier: Boolean(opts.prettier || resolved.prettier),\n verboseSkipped: Boolean(opts.verboseSkipped),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error('Unexpected error:', message);\n process.exit(1);\n }\n});\n\naddSharedOptions(\n program\n .command('check')\n .description('Scan for extractable duplicates and preview apply (dry-run)')\n .argument('[path]', 'Directory to scan', DEFAULT_TARGET_PATH)\n .option('--output <file>', 'CSS output path used in the apply preview')\n .option('--format <type>', 'Output format: console or json', 'console')\n .option('--min-occurrences <n>', 'Minimum occurrences for the analyze list')\n .option('--top <n>', 'Number of extractable patterns to show')\n .option('--fail-on-extractable <n>', 'Exit 1 when extractable patterns exceed n')\n .option('--verbose-skipped', 'List every skipped replacement location')\n .option('--prefix <name>', 'Namespace prefix for generated classes'),\n).action(async (targetPath: string, opts) => {\n try {\n const scanPath = resolveTargetPath(targetPath);\n const analyzeResolved = withNumericDefaults(\n await resolveCommandOptions('analyze', { ...opts, changed: resolveChangedFlag(opts) }, scanPath),\n opts,\n ANALYZE_DEFAULTS,\n );\n const generateResolved = withNumericDefaults(\n await resolveCommandOptions('generate', { ...opts, changed: resolveChangedFlag(opts) }, scanPath),\n opts,\n GENERATE_DEFAULTS,\n );\n const output = resolveOutputPath(opts.output, generateResolved.output);\n const failOnExtractable = process.argv.includes('--fail-on-extractable')\n ? optionalCliNumber(opts.failOnExtractable) ?? 0\n : undefined;\n\n await checkCommand(scanPath, {\n minOccurrences: analyzeResolved.minOccurrences,\n extractableMinOccurrences: generateResolved.minOccurrences,\n minSize: analyzeResolved.minSize,\n maxSize: analyzeResolved.maxSize,\n top: analyzeResolved.top,\n prefix: generateResolved.prefix,\n include: analyzeResolved.include,\n exclude: analyzeResolved.exclude,\n changed: analyzeResolved.changed,\n configPath: analyzeResolved.configPath ?? generateResolved.configPath,\n names: generateResolved.names,\n output,\n format: opts.format === 'json' ? 'json' : 'console',\n failOnExtractable,\n verboseSkipped: Boolean(opts.verboseSkipped),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error('Unexpected error:', message);\n process.exit(1);\n }\n});\n\nprogram.parse();\n","import { loadCommandOptions } from '../config/loadConfig.js';\nimport type { CliCommand } from '../config/types.js';\nimport type { AnalyzeOptions } from '../parser/types.js';\n\nfunction splitPatterns(value: unknown): string[] | undefined {\n if (typeof value !== 'string' || value.trim().length === 0) {\n return undefined;\n }\n\n return value\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part.length > 0);\n}\n\nfunction optionalNumber(value: unknown): number | undefined {\n if (value === undefined || value === null || value === '') {\n return undefined;\n }\n\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nexport interface RawCliOptions {\n config?: string;\n minOccurrences?: string | number;\n minSize?: string | number;\n maxSize?: string | number;\n top?: string | number;\n prefix?: string;\n dedupeSubsets?: boolean;\n include?: string;\n exclude?: string;\n output?: string;\n format?: string;\n dryRun?: boolean;\n prettier?: boolean;\n fromReport?: string;\n extractableOnly?: boolean;\n changed?: string | boolean;\n force?: boolean;\n}\n\nfunction cliNumber(\n value: string | number | undefined,\n fallback: number,\n): number {\n const parsed = optionalNumber(value);\n return parsed ?? fallback;\n}\n\n/**\n * Merge config file values with CLI flags (CLI wins).\n */\nexport async function resolveCommandOptions(\n command: CliCommand,\n opts: RawCliOptions,\n targetPath?: string,\n): Promise<\n AnalyzeOptions & { output?: string; dryRun?: boolean; names?: Record<string, string> }\n> {\n const resolved = await loadCommandOptions(\n command,\n {\n configPath: opts.config,\n minOccurrences: optionalNumber(opts.minOccurrences),\n minSize: optionalNumber(opts.minSize),\n maxSize: optionalNumber(opts.maxSize),\n top: optionalNumber(opts.top),\n prefix: opts.prefix,\n dedupeSubsets: opts.dedupeSubsets,\n include: splitPatterns(opts.include),\n exclude: splitPatterns(opts.exclude),\n output: opts.output,\n dryRun: opts.dryRun,\n prettier: opts.prettier,\n fromReport: opts.fromReport,\n extractableOnly: opts.extractableOnly,\n changed: parseChanged(opts.changed),\n force: opts.force,\n },\n { targetPath },\n );\n\n return {\n minOccurrences: resolved.minOccurrences,\n minSize: resolved.minSize,\n maxSize: resolved.maxSize,\n top: resolved.top,\n prefix: resolved.prefix,\n dedupeSubsets: resolved.dedupeSubsets,\n include: resolved.include,\n exclude: resolved.exclude,\n configPath: resolved.configPath,\n output: resolved.output,\n names: resolved.names,\n format: opts.format === 'json' ? 'json' : 'console',\n dryRun: opts.dryRun ?? resolved.dryRun,\n prettier: opts.prettier ?? resolved.prettier,\n fromReport: opts.fromReport ?? resolved.fromReport,\n extractableOnly: opts.extractableOnly ?? resolved.extractableOnly,\n changed: parseChanged(opts.changed) ?? resolved.changed,\n force: opts.force ?? resolved.force,\n };\n}\n\nfunction parseChanged(value: unknown): boolean | string | undefined {\n if (value === undefined || value === null || value === '') {\n return undefined;\n }\n\n if (value === true || value === 'true') {\n return true;\n }\n\n if (typeof value === 'string') {\n return value;\n }\n\n return undefined;\n}\n\nexport function withNumericDefaults(\n resolved: Awaited<ReturnType<typeof resolveCommandOptions>>,\n opts: RawCliOptions,\n defaults: {\n minOccurrences: number;\n minSize: number;\n maxSize: number;\n top: number;\n prefix?: string;\n },\n) {\n return {\n ...resolved,\n minOccurrences:\n resolved.minOccurrences ??\n cliNumber(opts.minOccurrences, defaults.minOccurrences),\n minSize: resolved.minSize ?? cliNumber(opts.minSize, defaults.minSize),\n maxSize: resolved.maxSize ?? cliNumber(opts.maxSize, defaults.maxSize),\n top: resolved.top ?? cliNumber(opts.top, defaults.top),\n prefix: resolved.prefix ?? opts.prefix ?? defaults.prefix,\n };\n}\n\n/** @deprecated Use resolveCommandOptions */\nexport const resolveAnalyzeOptions = (\n opts: RawCliOptions,\n targetPath?: string,\n) => resolveCommandOptions('analyze', opts, targetPath);\n","import { readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nfunction readPackageVersion(): string {\n const currentDir = path.dirname(fileURLToPath(import.meta.url));\n const packageJsonPath = path.join(currentDir, '../../package.json');\n const raw = readFileSync(packageJsonPath, 'utf-8');\n const pkg = JSON.parse(raw) as { version?: string };\n return pkg.version ?? '0.0.0';\n}\n\nexport const CLI_VERSION = readPackageVersion();\n"],"mappings":"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","names":[]}
|