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/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
- loadCommandOptions
7
- } from "../chunk-4GXMK3NB.js";
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("<path>", "Directory to analyze").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")
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, targetPath),
178
+ await resolveCommandOptions("analyze", { ...opts, changed: resolveChangedFlag(opts) }, scanPath),
128
179
  opts,
129
180
  ANALYZE_DEFAULTS
130
181
  );
131
- await analyzeCommand(targetPath, {
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 analyze").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")
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, targetPath),
212
+ await resolveCommandOptions("generate", { ...opts, changed: resolveChangedFlag(opts) }, scanPath),
154
213
  opts,
155
214
  GENERATE_DEFAULTS
156
215
  );
157
- const output = opts.output ?? resolved.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("<path>", "Directory to modify").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("--prefix <name>", "Namespace prefix for generated classes")
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, targetPath),
245
+ await resolveCommandOptions("apply", { ...opts, changed: resolveChangedFlag(opts) }, scanPath),
194
246
  opts,
195
247
  GENERATE_DEFAULTS
196
248
  );
197
- const output = opts.output ?? resolved.output;
198
- if (!output) {
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);
@@ -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":";;;;;;;;;AAEA,SAAS,eAAe;AACxB,OAAO,WAAW;;;ACHX,IAAM,mBAAmB;AAAA,EAC9B,gBAAgB;AAAA,EAChB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,KAAK;AACP;AAEO,IAAM,oBAAoB;AAAA,EAC/B,gBAAgB;AAAA,EAChB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,KAAK;AAAA,EACL,QAAQ;AACV;;;ACTA,SAAS,cAAc,OAAsC;AAC3D,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,WAAW,GAAG;AAC1D,WAAO;AAAA,EACT;AAEA,SAAO,MACJ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;AACrC;AAEA,SAAS,eAAe,OAAoC;AAC1D,MAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,IAAI;AACzD,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,OAAO,KAAK;AAC3B,SAAO,OAAO,SAAS,MAAM,IAAI,SAAS;AAC5C;AAoBA,SAAS,UACP,OACA,UACQ;AACR,QAAM,SAAS,eAAe,KAAK;AACnC,SAAO,UAAU;AACnB;AAKA,eAAsB,sBACpB,SACA,MACA,YAGA;AACA,QAAM,WAAW,MAAM;AAAA,IACrB;AAAA,IACA;AAAA,MACE,YAAY,KAAK;AAAA,MACjB,gBAAgB,eAAe,KAAK,cAAc;AAAA,MAClD,SAAS,eAAe,KAAK,OAAO;AAAA,MACpC,SAAS,eAAe,KAAK,OAAO;AAAA,MACpC,KAAK,eAAe,KAAK,GAAG;AAAA,MAC5B,QAAQ,KAAK;AAAA,MACb,eAAe,KAAK;AAAA,MACpB,SAAS,cAAc,KAAK,OAAO;AAAA,MACnC,SAAS,cAAc,KAAK,OAAO;AAAA,MACnC,QAAQ,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,MACf,YAAY,KAAK;AAAA,MACjB,iBAAiB,KAAK;AAAA,IACxB;AAAA,IACE,EAAE,WAAW;AAAA,EACf;AAEA,SAAO;AAAA,IACL,gBAAgB,SAAS;AAAA,IACzB,SAAS,SAAS;AAAA,IAClB,SAAS,SAAS;AAAA,IAClB,KAAK,SAAS;AAAA,IACd,QAAQ,SAAS;AAAA,IACjB,eAAe,SAAS;AAAA,IACxB,SAAS,SAAS;AAAA,IAClB,SAAS,SAAS;AAAA,IAClB,YAAY,SAAS;AAAA,IACrB,QAAQ,SAAS;AAAA,IACjB,OAAO,SAAS;AAAA,IAChB,QAAQ,KAAK,WAAW,SAAS,SAAS;AAAA,IAC1C,QAAQ,KAAK,UAAU,SAAS;AAAA,IAChC,UAAU,KAAK,YAAY,SAAS;AAAA,IACpC,YAAY,KAAK,cAAc,SAAS;AAAA,IACxC,iBAAiB,KAAK,mBAAmB,SAAS;AAAA,EACpD;AACF;AAEO,SAAS,oBACd,UACA,MACA,UAOA;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,gBACE,SAAS,kBACT,UAAU,KAAK,gBAAgB,SAAS,cAAc;AAAA,IACxD,SAAS,SAAS,WAAW,UAAU,KAAK,SAAS,SAAS,OAAO;AAAA,IACrE,SAAS,SAAS,WAAW,UAAU,KAAK,SAAS,SAAS,OAAO;AAAA,IACrE,KAAK,SAAS,OAAO,UAAU,KAAK,KAAK,SAAS,GAAG;AAAA,IACrD,QAAQ,SAAS,UAAU,KAAK,UAAU,SAAS;AAAA,EACrD;AACF;;;AC1HA,SAAS,oBAAoB;AAC7B,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAE9B,SAAS,qBAA6B;AACpC,QAAM,aAAa,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAC9D,QAAM,kBAAkB,KAAK,KAAK,YAAY,oBAAoB;AAClE,QAAM,MAAM,aAAa,iBAAiB,OAAO;AACjD,QAAM,MAAM,KAAK,MAAM,GAAG;AAC1B,SAAO,IAAI,WAAW;AACxB;AAEO,IAAM,cAAc,mBAAmB;;;AHD9C,IAAM,UAAU,IAAI,QAAQ;AAE5B,SAAS,iBAAiB,SAA2B;AACnD,SAAO,QACJ,OAAO,mBAAmB,qCAAqC,EAC/D;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF;AACJ;AAEA,QACG,KAAK,iBAAiB,EACtB,YAAY,4DAA4D,EACxE,QAAQ,WAAW;AAEtB;AAAA,EACE,QACG,QAAQ,SAAS,EACjB,YAAY,kEAAkE,EAC9E,SAAS,UAAU,sBAAsB,EACzC,OAAO,yBAAyB,+BAA+B,EAC/D,OAAO,kBAAkB,iCAAiC,EAC1D,OAAO,kBAAkB,iCAAiC,EAC1D,OAAO,aAAa,oCAAoC,EACxD,OAAO,mBAAmB,kCAAkC,SAAS,EACrE,OAAO,uBAAuB,wCAAwC;AAC3E,EAAE,OAAO,OAAO,YAAoB,SAAS;AAC3C,MAAI;AACF,UAAM,WAAW;AAAA,MACf,MAAM,sBAAsB,WAAW,MAAM,UAAU;AAAA,MACvD;AAAA,MACA;AAAA,IACF;AAEA,UAAM,eAAe,YAAY;AAAA,MAC/B,gBAAgB,SAAS;AAAA,MACzB,SAAS,SAAS;AAAA,MAClB,SAAS,SAAS;AAAA,MAClB,KAAK,SAAS;AAAA,MACd,QAAQ,SAAS;AAAA,MACjB,eAAe,QAAQ,KAAK,SAAS,qBAAqB,IACtD,QACC,SAAS,iBAAiB;AAAA,MAC/B,SAAS,SAAS;AAAA,MAClB,SAAS,SAAS;AAAA,MAClB,YAAY,SAAS;AAAA,IACvB,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAQ,MAAM,qBAAqB,OAAO;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAED;AAAA,EACE,QACG,QAAQ,UAAU,EAClB,YAAY,6DAA6D,EACzE,SAAS,UAAU,sBAAsB,EACzC,OAAO,mBAAmB,sBAAsB,EAChD,OAAO,wBAAwB,mCAAmC,EAClE,OAAO,sBAAsB,iDAAiD,EAC9E,OAAO,mBAAmB,kCAAkC,SAAS,EACrE,OAAO,yBAAyB,+BAA+B,EAC/D,OAAO,kBAAkB,iCAAiC,EAC1D,OAAO,kBAAkB,iCAAiC,EAC1D,OAAO,aAAa,oCAAoC,EACxD,OAAO,mBAAmB,wCAAwC;AACvE,EAAE,OAAO,OAAO,YAAgC,SAAS;AACvD,MAAI;AACF,UAAM,WAAW;AAAA,MACf,MAAM,sBAAsB,YAAY,MAAM,UAAU;AAAA,MACxD;AAAA,MACA;AAAA,IACF;AACA,UAAM,SAAS,KAAK,UAAU,SAAS;AACvC,UAAM,WAAW,cAAc;AAE/B,QAAI,CAAC,QAAQ;AACX,cAAQ,MAAM,MAAM,IAAI,6BAA6B,CAAC;AACtD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI,CAAC,KAAK,cAAc,CAAC,SAAS,cAAc,CAAC,YAAY;AAC3D,cAAQ,MAAM,MAAM,IAAI,iDAAiD,CAAC;AAC1E,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,gBAAgB,UAAU;AAAA,MAC9B;AAAA,MACA,gBAAgB,SAAS;AAAA,MACzB,SAAS,SAAS;AAAA,MAClB,SAAS,SAAS;AAAA,MAClB,KAAK,SAAS;AAAA,MACd,QAAQ,SAAS;AAAA,MACjB,SAAS,SAAS;AAAA,MAClB,SAAS,SAAS;AAAA,MAClB,YAAY,SAAS;AAAA,MACrB,OAAO,SAAS;AAAA,MAChB,QAAQ,SAAS;AAAA,MACjB,YAAY,KAAK,cAAc,SAAS;AAAA,MACxC,iBAAiB,QAAQ,KAAK,mBAAmB,SAAS,eAAe;AAAA,IAC3E,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAQ,MAAM,qBAAqB,OAAO;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAED;AAAA,EACE,QACG,QAAQ,OAAO,EACf,YAAY,qEAAqE,EACjF,SAAS,UAAU,qBAAqB,EACxC,OAAO,mBAAmB,sBAAsB,EAChD,OAAO,wBAAwB,6CAA6C,EAC5E,OAAO,sBAAsB,8CAA8C,EAC3E,OAAO,mBAAmB,kCAAkC,SAAS,EACrE,OAAO,cAAc,oDAAoD,EACzE,OAAO,yBAAyB,+BAA+B,EAC/D,OAAO,kBAAkB,iCAAiC,EAC1D,OAAO,kBAAkB,iCAAiC,EAC1D,OAAO,aAAa,oCAAoC,EACxD,OAAO,aAAa,4CAA4C,EAChE,OAAO,mBAAmB,wCAAwC;AACvE,EAAE,OAAO,OAAO,YAAoB,SAAS;AAC3C,MAAI;AACF,UAAM,WAAW;AAAA,MACf,MAAM,sBAAsB,SAAS,MAAM,UAAU;AAAA,MACrD;AAAA,MACA;AAAA,IACF;AACA,UAAM,SAAS,KAAK,UAAU,SAAS;AAEvC,QAAI,CAAC,QAAQ;AACX,cAAQ,MAAM,MAAM,IAAI,6BAA6B,CAAC;AACtD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,aAAa,YAAY;AAAA,MAC7B;AAAA,MACA,gBAAgB,SAAS;AAAA,MACzB,SAAS,SAAS;AAAA,MAClB,SAAS,SAAS;AAAA,MAClB,KAAK,SAAS;AAAA,MACd,QAAQ,SAAS;AAAA,MACjB,SAAS,SAAS;AAAA,MAClB,SAAS,SAAS;AAAA,MAClB,YAAY,SAAS;AAAA,MACrB,OAAO,SAAS;AAAA,MAChB,QAAQ,SAAS;AAAA,MACjB,YAAY,KAAK,cAAc,SAAS;AAAA,MACxC,iBAAiB,QAAQ,KAAK,mBAAmB,SAAS,eAAe;AAAA,MACzE,QAAQ,QAAQ,KAAK,SAAS,WAAW,IACrC,OACA,QAAQ,SAAS,MAAM;AAAA,MAC3B,UAAU,QAAQ,KAAK,YAAY,SAAS,QAAQ;AAAA,IACtD,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAQ,MAAM,qBAAqB,OAAO;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAED,QAAQ,MAAM;","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":[]}