tailwind-unwind 0.4.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 +73 -27
- package/dist/{chunk-UXXIEFP4.js → chunk-RMTZCCPS.js} +385 -100
- package/dist/chunk-RMTZCCPS.js.map +1 -0
- package/dist/cli/index.js +80 -44
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +143 -78
- package/dist/index.js +11 -1
- package/package.json +1 -1
- package/dist/chunk-UXXIEFP4.js.map +0 -1
|
@@ -1530,8 +1530,10 @@ async function scanProject(options) {
|
|
|
1530
1530
|
topLimit: options.topLimit,
|
|
1531
1531
|
dedupeSubsets: options.dedupeSubsets
|
|
1532
1532
|
});
|
|
1533
|
+
const analyzeMinOccurrences = options.minOccurrences ?? 5;
|
|
1534
|
+
const extractableMinOccurrences = options.extractableMinOccurrences ?? 3;
|
|
1533
1535
|
const extractableSets = findRepeatedClassSets(occurrences, {
|
|
1534
|
-
minOccurrences:
|
|
1536
|
+
minOccurrences: extractableMinOccurrences,
|
|
1535
1537
|
minSize: options.minSize,
|
|
1536
1538
|
maxSize: options.maxSize,
|
|
1537
1539
|
topLimit: Number.POSITIVE_INFINITY
|
|
@@ -1558,7 +1560,10 @@ async function scanProject(options) {
|
|
|
1558
1560
|
0
|
|
1559
1561
|
),
|
|
1560
1562
|
topCombinations,
|
|
1561
|
-
potentialReductionPercent
|
|
1563
|
+
potentialReductionPercent,
|
|
1564
|
+
extractablePatternCount: extractableSets.length,
|
|
1565
|
+
analyzeMinOccurrences,
|
|
1566
|
+
extractableMinOccurrences
|
|
1562
1567
|
},
|
|
1563
1568
|
parseWarnings: warnings
|
|
1564
1569
|
};
|
|
@@ -1567,7 +1572,8 @@ async function scanProject(options) {
|
|
|
1567
1572
|
files,
|
|
1568
1573
|
occurrences,
|
|
1569
1574
|
warnings,
|
|
1570
|
-
report
|
|
1575
|
+
report,
|
|
1576
|
+
extractableCombinations: extractableSets
|
|
1571
1577
|
};
|
|
1572
1578
|
}
|
|
1573
1579
|
|
|
@@ -1659,16 +1665,8 @@ async function initCommand(targetPath, options = {}) {
|
|
|
1659
1665
|
);
|
|
1660
1666
|
console.log("");
|
|
1661
1667
|
console.log(chalk.cyan("Next steps:"));
|
|
1662
|
-
console.log(
|
|
1663
|
-
|
|
1664
|
-
` npx tailwind-unwind analyze ${targetPath} --config ${path5.basename(outputPath)}`
|
|
1665
|
-
)
|
|
1666
|
-
);
|
|
1667
|
-
console.log(
|
|
1668
|
-
chalk.white(
|
|
1669
|
-
` npx tailwind-unwind generate ${targetPath} --config ${path5.basename(outputPath)}`
|
|
1670
|
-
)
|
|
1671
|
-
);
|
|
1668
|
+
console.log(chalk.white(" npx tailwind-unwind check"));
|
|
1669
|
+
console.log(chalk.white(" npx tailwind-unwind generate"));
|
|
1672
1670
|
console.log("");
|
|
1673
1671
|
return {
|
|
1674
1672
|
configPath: outputPath,
|
|
@@ -1753,26 +1751,35 @@ function printConsoleReport(report, options = {}) {
|
|
|
1753
1751
|
`\u{1F4A1} Potential code reduction: ${stats.potentialReductionPercent}%`
|
|
1754
1752
|
)
|
|
1755
1753
|
);
|
|
1756
|
-
const
|
|
1754
|
+
const extractableInTop = stats.topCombinations.filter(
|
|
1757
1755
|
(combo) => combo.extractable
|
|
1758
1756
|
).length;
|
|
1759
|
-
if (
|
|
1757
|
+
if (stats.analyzeMinOccurrences !== stats.extractableMinOccurrences) {
|
|
1758
|
+
console.log("");
|
|
1759
|
+
console.log(
|
|
1760
|
+
chalk2.yellow(
|
|
1761
|
+
`Note: this list uses min-occurrences ${stats.analyzeMinOccurrences}; generate/apply extract exact duplicates with \u2265${stats.extractableMinOccurrences}.`
|
|
1762
|
+
)
|
|
1763
|
+
);
|
|
1764
|
+
if (stats.extractablePatternCount > extractableInTop) {
|
|
1765
|
+
console.log(
|
|
1766
|
+
chalk2.yellow(
|
|
1767
|
+
` ${stats.extractablePatternCount} extractable pattern(s) total in project.`
|
|
1768
|
+
)
|
|
1769
|
+
);
|
|
1770
|
+
}
|
|
1771
|
+
} else if (stats.extractablePatternCount > 0) {
|
|
1760
1772
|
console.log(
|
|
1761
1773
|
chalk2.magenta(
|
|
1762
|
-
`\u{1F4A1} ${
|
|
1774
|
+
`\u{1F4A1} ${stats.extractablePatternCount} extractable pattern(s) ready for generate/apply`
|
|
1763
1775
|
)
|
|
1764
1776
|
);
|
|
1765
1777
|
}
|
|
1766
1778
|
console.log(
|
|
1767
|
-
chalk2.magenta(
|
|
1768
|
-
"\u{1F4A1} Generate CSS: npx tailwind-unwind generate <path> --output styles.css"
|
|
1769
|
-
)
|
|
1770
|
-
);
|
|
1771
|
-
console.log(
|
|
1772
|
-
chalk2.magenta(
|
|
1773
|
-
"\u{1F4A1} Apply classes: npx tailwind-unwind apply <path> --output styles.css"
|
|
1774
|
-
)
|
|
1779
|
+
chalk2.magenta("\u{1F4A1} Quick check: npx tailwind-unwind check")
|
|
1775
1780
|
);
|
|
1781
|
+
console.log(chalk2.magenta("\u{1F4A1} Generate CSS: npx tailwind-unwind generate"));
|
|
1782
|
+
console.log(chalk2.magenta("\u{1F4A1} Apply classes: npx tailwind-unwind apply"));
|
|
1776
1783
|
console.log("");
|
|
1777
1784
|
}
|
|
1778
1785
|
|
|
@@ -1796,7 +1803,7 @@ async function analyzeCommand(targetPath, options = {}) {
|
|
|
1796
1803
|
include: options.include,
|
|
1797
1804
|
exclude: options.exclude,
|
|
1798
1805
|
changed: options.changed,
|
|
1799
|
-
extractableMinOccurrences:
|
|
1806
|
+
extractableMinOccurrences: options.extractableMinOccurrences
|
|
1800
1807
|
});
|
|
1801
1808
|
} catch (error) {
|
|
1802
1809
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1817,31 +1824,31 @@ async function analyzeCommand(targetPath, options = {}) {
|
|
|
1817
1824
|
return report;
|
|
1818
1825
|
}
|
|
1819
1826
|
|
|
1820
|
-
// src/
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1827
|
+
// src/cli/defaults.ts
|
|
1828
|
+
var DEFAULT_TARGET_PATH = ".";
|
|
1829
|
+
var DEFAULT_OUTPUT_PATH = "styles.css";
|
|
1830
|
+
var ANALYZE_DEFAULTS = {
|
|
1831
|
+
minOccurrences: 5,
|
|
1832
|
+
minSize: 2,
|
|
1833
|
+
maxSize: 5,
|
|
1834
|
+
top: 10
|
|
1835
|
+
};
|
|
1836
|
+
var GENERATE_DEFAULTS = {
|
|
1837
|
+
minOccurrences: 3,
|
|
1838
|
+
minSize: 2,
|
|
1839
|
+
maxSize: 5,
|
|
1840
|
+
top: 10,
|
|
1841
|
+
prefix: "twu-",
|
|
1842
|
+
output: DEFAULT_OUTPUT_PATH
|
|
1843
|
+
};
|
|
1844
|
+
function resolveTargetPath(targetPath) {
|
|
1845
|
+
if (typeof targetPath === "string" && targetPath.trim().length > 0) {
|
|
1846
|
+
return targetPath;
|
|
1834
1847
|
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
return
|
|
1839
|
-
replacementCount: replacements.length,
|
|
1840
|
-
utilityTokensBefore,
|
|
1841
|
-
utilityTokensAfter,
|
|
1842
|
-
tokensSaved,
|
|
1843
|
-
percentReduction
|
|
1844
|
-
};
|
|
1848
|
+
return DEFAULT_TARGET_PATH;
|
|
1849
|
+
}
|
|
1850
|
+
function resolveOutputPath(cliOutput, configOutput) {
|
|
1851
|
+
return cliOutput ?? configOutput ?? DEFAULT_OUTPUT_PATH;
|
|
1845
1852
|
}
|
|
1846
1853
|
|
|
1847
1854
|
// src/codemod/formatSource.ts
|
|
@@ -2294,6 +2301,33 @@ async function loadExtractableCombinations(reportPath, options = {}) {
|
|
|
2294
2301
|
};
|
|
2295
2302
|
}
|
|
2296
2303
|
|
|
2304
|
+
// src/analyzer/savings.ts
|
|
2305
|
+
function calculateSavings(replacements) {
|
|
2306
|
+
if (replacements.length === 0) {
|
|
2307
|
+
return {
|
|
2308
|
+
replacementCount: 0,
|
|
2309
|
+
utilityTokensBefore: 0,
|
|
2310
|
+
utilityTokensAfter: 0,
|
|
2311
|
+
tokensSaved: 0,
|
|
2312
|
+
percentReduction: 0
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
let utilityTokensBefore = 0;
|
|
2316
|
+
for (const replacement of replacements) {
|
|
2317
|
+
utilityTokensBefore += replacement.from.split(/\s+/).filter(Boolean).length;
|
|
2318
|
+
}
|
|
2319
|
+
const utilityTokensAfter = replacements.length;
|
|
2320
|
+
const tokensSaved = Math.max(0, utilityTokensBefore - utilityTokensAfter);
|
|
2321
|
+
const percentReduction = utilityTokensBefore === 0 ? 0 : Math.round(tokensSaved / utilityTokensBefore * 100);
|
|
2322
|
+
return {
|
|
2323
|
+
replacementCount: replacements.length,
|
|
2324
|
+
utilityTokensBefore,
|
|
2325
|
+
utilityTokensAfter,
|
|
2326
|
+
tokensSaved,
|
|
2327
|
+
percentReduction
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2297
2331
|
// src/reporters/operationJsonReporter.ts
|
|
2298
2332
|
function printGenerateJsonReport(report) {
|
|
2299
2333
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -2302,10 +2336,61 @@ function printApplyJsonReport(report) {
|
|
|
2302
2336
|
console.log(JSON.stringify(report, null, 2));
|
|
2303
2337
|
}
|
|
2304
2338
|
|
|
2339
|
+
// src/reporters/skippedReporter.ts
|
|
2340
|
+
import chalk4 from "chalk";
|
|
2341
|
+
function groupSkippedByReason(skipped) {
|
|
2342
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2343
|
+
for (const item of skipped) {
|
|
2344
|
+
const bucket = groups.get(item.reason) ?? [];
|
|
2345
|
+
bucket.push(item);
|
|
2346
|
+
groups.set(item.reason, bucket);
|
|
2347
|
+
}
|
|
2348
|
+
return [...groups.entries()].map(([reason, items]) => ({
|
|
2349
|
+
reason,
|
|
2350
|
+
count: items.length,
|
|
2351
|
+
items
|
|
2352
|
+
})).sort((left, right) => right.count - left.count);
|
|
2353
|
+
}
|
|
2354
|
+
function printSkippedReport(skipped, options = {}) {
|
|
2355
|
+
if (skipped.length === 0) {
|
|
2356
|
+
return;
|
|
2357
|
+
}
|
|
2358
|
+
const groups = groupSkippedByReason(skipped);
|
|
2359
|
+
console.log("");
|
|
2360
|
+
console.log(chalk4.bold.yellow(`Skipped (${skipped.length}):`));
|
|
2361
|
+
if (options.verbose) {
|
|
2362
|
+
for (const item of skipped) {
|
|
2363
|
+
const line = item.line ? `:${item.line}` : "";
|
|
2364
|
+
console.log(
|
|
2365
|
+
chalk4.gray(` ${item.filePath}${line}`) + chalk4.yellow(` [${item.reason}]`) + chalk4.dim(` "${item.classes.join(" ")}"`)
|
|
2366
|
+
);
|
|
2367
|
+
}
|
|
2368
|
+
return;
|
|
2369
|
+
}
|
|
2370
|
+
for (const group of groups) {
|
|
2371
|
+
console.log(
|
|
2372
|
+
chalk4.yellow(` ${group.reason}: `) + chalk4.white(String(group.count))
|
|
2373
|
+
);
|
|
2374
|
+
const preview = group.items.slice(0, 2);
|
|
2375
|
+
for (const item of preview) {
|
|
2376
|
+
const line = item.line ? `:${item.line}` : "";
|
|
2377
|
+
console.log(
|
|
2378
|
+
chalk4.gray(` ${item.filePath}${line}`) + chalk4.dim(` "${item.classes.join(" ")}"`)
|
|
2379
|
+
);
|
|
2380
|
+
}
|
|
2381
|
+
if (group.items.length > 2) {
|
|
2382
|
+
console.log(
|
|
2383
|
+
chalk4.dim(` (+${group.items.length - 2} more with same reason)`)
|
|
2384
|
+
);
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
console.log(chalk4.dim(" Use --verbose-skipped to list every skipped location."));
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2305
2390
|
// src/commands/apply.ts
|
|
2306
2391
|
import fs6 from "fs/promises";
|
|
2307
2392
|
import path7 from "path";
|
|
2308
|
-
import
|
|
2393
|
+
import chalk5 from "chalk";
|
|
2309
2394
|
async function applyCommand(targetPath, options) {
|
|
2310
2395
|
let scanResult;
|
|
2311
2396
|
try {
|
|
@@ -2318,12 +2403,12 @@ async function applyCommand(targetPath, options) {
|
|
|
2318
2403
|
});
|
|
2319
2404
|
} catch (error) {
|
|
2320
2405
|
const message = error instanceof Error ? error.message : String(error);
|
|
2321
|
-
console.error(
|
|
2406
|
+
console.error(chalk5.red(`Error: ${message}`));
|
|
2322
2407
|
process.exit(1);
|
|
2323
2408
|
}
|
|
2324
2409
|
for (const warning of scanResult.warnings) {
|
|
2325
|
-
if (options.format !== "json") {
|
|
2326
|
-
console.warn(
|
|
2410
|
+
if (!options.quiet && options.format !== "json") {
|
|
2411
|
+
console.warn(chalk5.yellow(`\u26A0 ${warning}`));
|
|
2327
2412
|
}
|
|
2328
2413
|
}
|
|
2329
2414
|
let components;
|
|
@@ -2370,16 +2455,29 @@ async function applyCommand(targetPath, options) {
|
|
|
2370
2455
|
}
|
|
2371
2456
|
} catch (error) {
|
|
2372
2457
|
const message = error instanceof Error ? error.message : String(error);
|
|
2373
|
-
console.error(
|
|
2458
|
+
console.error(chalk5.red(`Error: ${message}`));
|
|
2374
2459
|
process.exit(1);
|
|
2375
2460
|
}
|
|
2376
2461
|
if (components.length === 0) {
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2462
|
+
if (!options.quiet) {
|
|
2463
|
+
console.error(
|
|
2464
|
+
chalk5.yellow(
|
|
2465
|
+
"No repeated className sets found. Try lowering --min-occurrences."
|
|
2466
|
+
)
|
|
2467
|
+
);
|
|
2468
|
+
process.exit(1);
|
|
2469
|
+
}
|
|
2470
|
+
return {
|
|
2471
|
+
filesModified: 0,
|
|
2472
|
+
replacementsTotal: 0,
|
|
2473
|
+
outputPath: path7.resolve(options.output),
|
|
2474
|
+
componentsGenerated: 0,
|
|
2475
|
+
components: [],
|
|
2476
|
+
replacements: [],
|
|
2477
|
+
skipped: [],
|
|
2478
|
+
prettierFormatted: [],
|
|
2479
|
+
savings: calculateSavings([])
|
|
2480
|
+
};
|
|
2383
2481
|
}
|
|
2384
2482
|
const outputPath = path7.resolve(options.output);
|
|
2385
2483
|
let filesModified = 0;
|
|
@@ -2435,7 +2533,7 @@ async function applyCommand(targetPath, options) {
|
|
|
2435
2533
|
prettierFormatted,
|
|
2436
2534
|
savings
|
|
2437
2535
|
};
|
|
2438
|
-
if (options.format === "json") {
|
|
2536
|
+
if (options.format === "json" && !options.quiet) {
|
|
2439
2537
|
printApplyJsonReport({
|
|
2440
2538
|
command: "apply",
|
|
2441
2539
|
dryRun: Boolean(options.dryRun),
|
|
@@ -2450,73 +2548,250 @@ async function applyCommand(targetPath, options) {
|
|
|
2450
2548
|
});
|
|
2451
2549
|
return result;
|
|
2452
2550
|
}
|
|
2551
|
+
if (options.quiet) {
|
|
2552
|
+
return result;
|
|
2553
|
+
}
|
|
2453
2554
|
console.log("");
|
|
2454
2555
|
if (options.dryRun) {
|
|
2455
|
-
console.log(
|
|
2556
|
+
console.log(chalk5.bold.yellow("\u{1F50D} Dry run \u2014 no files were modified"));
|
|
2456
2557
|
} else {
|
|
2457
|
-
console.log(
|
|
2558
|
+
console.log(chalk5.bold.green("\u2705 Classes applied successfully"));
|
|
2458
2559
|
}
|
|
2459
|
-
console.log(
|
|
2560
|
+
console.log(chalk5.gray(` CSS output: `) + chalk5.white(outputPath));
|
|
2460
2561
|
console.log(
|
|
2461
|
-
|
|
2562
|
+
chalk5.gray(` Component classes: `) + chalk5.white(String(components.length))
|
|
2462
2563
|
);
|
|
2463
2564
|
console.log(
|
|
2464
|
-
|
|
2565
|
+
chalk5.gray(` Files modified: `) + chalk5.white(String(filesModified))
|
|
2465
2566
|
);
|
|
2466
2567
|
console.log(
|
|
2467
|
-
|
|
2568
|
+
chalk5.gray(` Replacements: `) + chalk5.white(String(replacementsTotal))
|
|
2468
2569
|
);
|
|
2469
2570
|
if (prettierFormatted.length > 0) {
|
|
2470
2571
|
console.log(
|
|
2471
|
-
|
|
2572
|
+
chalk5.gray(` Prettier formatted: `) + chalk5.white(String(prettierFormatted.length))
|
|
2472
2573
|
);
|
|
2473
2574
|
}
|
|
2474
2575
|
if (savings.replacementCount > 0) {
|
|
2475
2576
|
console.log("");
|
|
2476
|
-
console.log(
|
|
2577
|
+
console.log(chalk5.bold("Savings:"));
|
|
2477
2578
|
console.log(
|
|
2478
|
-
|
|
2579
|
+
chalk5.gray(" Utility tokens before: ") + chalk5.white(String(savings.utilityTokensBefore))
|
|
2479
2580
|
);
|
|
2480
2581
|
console.log(
|
|
2481
|
-
|
|
2582
|
+
chalk5.gray(" Utility tokens after: ") + chalk5.white(String(savings.utilityTokensAfter))
|
|
2482
2583
|
);
|
|
2483
2584
|
console.log(
|
|
2484
|
-
|
|
2585
|
+
chalk5.gray(" Tokens saved: ") + chalk5.green(String(savings.tokensSaved))
|
|
2485
2586
|
);
|
|
2486
2587
|
console.log(
|
|
2487
|
-
|
|
2588
|
+
chalk5.gray(" Reduction: ") + chalk5.green(`${savings.percentReduction}%`)
|
|
2488
2589
|
);
|
|
2489
2590
|
}
|
|
2490
2591
|
if (allReplacements.length > 0) {
|
|
2491
2592
|
console.log("");
|
|
2492
|
-
console.log(
|
|
2593
|
+
console.log(chalk5.bold("Replacements:"));
|
|
2493
2594
|
for (const item of allReplacements) {
|
|
2494
2595
|
const line = item.line ? `:${item.line}` : "";
|
|
2495
|
-
const partialTag = item.partial ?
|
|
2596
|
+
const partialTag = item.partial ? chalk5.dim(" (partial)") : "";
|
|
2496
2597
|
console.log(
|
|
2497
|
-
|
|
2598
|
+
chalk5.gray(` ${item.filePath}${line}`) + chalk5.white(` "${item.from}" `) + chalk5.cyan("\u2192") + chalk5.green(` "${item.to}"`) + partialTag
|
|
2498
2599
|
);
|
|
2499
2600
|
}
|
|
2500
2601
|
}
|
|
2501
|
-
|
|
2602
|
+
printSkippedReport(allSkipped, { verbose: options.verboseSkipped });
|
|
2603
|
+
console.log("");
|
|
2604
|
+
if (!options.dryRun) {
|
|
2605
|
+
console.log(
|
|
2606
|
+
chalk5.cyan(
|
|
2607
|
+
`Import ${path7.basename(outputPath)} in your global CSS if you haven't already.`
|
|
2608
|
+
)
|
|
2609
|
+
);
|
|
2502
2610
|
console.log("");
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2611
|
+
}
|
|
2612
|
+
return result;
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
// src/reporters/checkReporter.ts
|
|
2616
|
+
import chalk6 from "chalk";
|
|
2617
|
+
function printCheckJsonReport(report) {
|
|
2618
|
+
console.log(JSON.stringify(report, null, 2));
|
|
2619
|
+
}
|
|
2620
|
+
function printCheckConsoleReport(analysisReport, options) {
|
|
2621
|
+
const { stats } = analysisReport;
|
|
2622
|
+
const topLimit = options.topLimit ?? 5;
|
|
2623
|
+
const extractableInTop = stats.topCombinations.filter(
|
|
2624
|
+
(combo) => combo.extractable
|
|
2625
|
+
).length;
|
|
2626
|
+
console.log("");
|
|
2627
|
+
console.log(chalk6.bold.cyan("\u2713 Tailwind check"));
|
|
2628
|
+
console.log(chalk6.cyan("\u2501".repeat(41)));
|
|
2629
|
+
console.log(`Files scanned: ${chalk6.white(String(stats.filesScanned))}`);
|
|
2630
|
+
console.log(
|
|
2631
|
+
`Extractable patterns: ${chalk6.white(String(stats.extractablePatternCount))}` + chalk6.gray(" (exact duplicates ready for generate/apply)")
|
|
2632
|
+
);
|
|
2633
|
+
if (stats.analyzeMinOccurrences !== stats.extractableMinOccurrences) {
|
|
2634
|
+
console.log("");
|
|
2635
|
+
console.log(
|
|
2636
|
+
chalk6.yellow(
|
|
2637
|
+
`Note: analyze lists patterns with \u2265${stats.analyzeMinOccurrences} occurrences; generate/apply extract exact duplicates with \u2265${stats.extractableMinOccurrences}.`
|
|
2638
|
+
)
|
|
2639
|
+
);
|
|
2640
|
+
if (stats.extractablePatternCount > extractableInTop) {
|
|
2507
2641
|
console.log(
|
|
2508
|
-
|
|
2642
|
+
chalk6.yellow(
|
|
2643
|
+
` ${stats.extractablePatternCount - extractableInTop} more extractable pattern(s) exist below the analyze threshold.`
|
|
2644
|
+
)
|
|
2509
2645
|
);
|
|
2510
2646
|
}
|
|
2511
2647
|
}
|
|
2512
|
-
|
|
2513
|
-
|
|
2648
|
+
if (stats.extractablePatternCount === 0) {
|
|
2649
|
+
console.log("");
|
|
2514
2650
|
console.log(
|
|
2515
|
-
|
|
2516
|
-
`Import ${path7.basename(outputPath)} in your global CSS if you haven't already.`
|
|
2517
|
-
)
|
|
2651
|
+
chalk6.green("No extractable duplicates found. Nothing to refactor right now.")
|
|
2518
2652
|
);
|
|
2519
2653
|
console.log("");
|
|
2654
|
+
console.log(options.passed ? chalk6.green("Check passed.") : chalk6.red("Check failed."));
|
|
2655
|
+
console.log("");
|
|
2656
|
+
return;
|
|
2657
|
+
}
|
|
2658
|
+
const previewCount = Math.min(topLimit, stats.topCombinations.length);
|
|
2659
|
+
if (previewCount > 0) {
|
|
2660
|
+
console.log("");
|
|
2661
|
+
console.log(chalk6.bold("Top extractable patterns:"));
|
|
2662
|
+
for (const combo of stats.topCombinations.filter((item) => item.extractable).slice(0, topLimit)) {
|
|
2663
|
+
console.log(
|
|
2664
|
+
chalk6.white(` \u2022 "${normalizeClasses(combo.classes)}"`) + chalk6.gray(` \u2014 ${combo.occurrences}\xD7 \u2192 `) + chalk6.green(combo.suggestion)
|
|
2665
|
+
);
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
if (options.preview) {
|
|
2669
|
+
const preview = options.preview;
|
|
2670
|
+
console.log("");
|
|
2671
|
+
console.log(chalk6.bold("Apply preview (dry-run):"));
|
|
2672
|
+
console.log(
|
|
2673
|
+
chalk6.gray(" CSS output: ") + chalk6.white(options.outputPath)
|
|
2674
|
+
);
|
|
2675
|
+
console.log(
|
|
2676
|
+
chalk6.gray(" Component classes: ") + chalk6.white(String(preview.componentsGenerated))
|
|
2677
|
+
);
|
|
2678
|
+
console.log(
|
|
2679
|
+
chalk6.gray(" Files to modify: ") + chalk6.white(String(preview.filesModified))
|
|
2680
|
+
);
|
|
2681
|
+
console.log(
|
|
2682
|
+
chalk6.gray(" Replacements: ") + chalk6.white(String(preview.replacementsTotal))
|
|
2683
|
+
);
|
|
2684
|
+
if (preview.savings.replacementCount > 0) {
|
|
2685
|
+
console.log(
|
|
2686
|
+
chalk6.gray(" Token reduction: ") + chalk6.green(`${preview.savings.percentReduction}%`)
|
|
2687
|
+
);
|
|
2688
|
+
}
|
|
2689
|
+
printSkippedReport(preview.skipped, {
|
|
2690
|
+
verbose: options.verboseSkipped
|
|
2691
|
+
});
|
|
2692
|
+
}
|
|
2693
|
+
console.log("");
|
|
2694
|
+
if (options.passed) {
|
|
2695
|
+
console.log(chalk6.green("Check passed."));
|
|
2696
|
+
} else {
|
|
2697
|
+
console.log(chalk6.red("Check failed."));
|
|
2698
|
+
}
|
|
2699
|
+
console.log(chalk6.cyan("Next steps:"));
|
|
2700
|
+
console.log(chalk6.white(" npx tailwind-unwind generate"));
|
|
2701
|
+
console.log(chalk6.white(" npx tailwind-unwind apply --dry-run"));
|
|
2702
|
+
console.log("");
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2705
|
+
// src/commands/check.ts
|
|
2706
|
+
import chalk7 from "chalk";
|
|
2707
|
+
async function checkCommand(targetPath, options) {
|
|
2708
|
+
let scanResult;
|
|
2709
|
+
try {
|
|
2710
|
+
scanResult = await scanProject({
|
|
2711
|
+
targetPath,
|
|
2712
|
+
minOccurrences: options.minOccurrences,
|
|
2713
|
+
minSize: options.minSize,
|
|
2714
|
+
maxSize: options.maxSize,
|
|
2715
|
+
topLimit: options.top,
|
|
2716
|
+
dedupeSubsets: options.dedupeSubsets,
|
|
2717
|
+
include: options.include,
|
|
2718
|
+
exclude: options.exclude,
|
|
2719
|
+
changed: options.changed,
|
|
2720
|
+
extractableMinOccurrences: options.extractableMinOccurrences
|
|
2721
|
+
});
|
|
2722
|
+
} catch (error) {
|
|
2723
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2724
|
+
console.error(chalk7.red(`Error: ${message}`));
|
|
2725
|
+
process.exit(1);
|
|
2726
|
+
}
|
|
2727
|
+
if (options.format !== "json") {
|
|
2728
|
+
for (const warning of scanResult.warnings) {
|
|
2729
|
+
console.warn(chalk7.yellow(`\u26A0 ${warning}`));
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
const extractablePatternCount = scanResult.report.stats.extractablePatternCount;
|
|
2733
|
+
const failThreshold = options.failOnExtractable;
|
|
2734
|
+
const passed = failThreshold === void 0 ? true : extractablePatternCount <= failThreshold;
|
|
2735
|
+
let preview = null;
|
|
2736
|
+
if (extractablePatternCount > 0) {
|
|
2737
|
+
preview = await applyCommand(targetPath, {
|
|
2738
|
+
output: options.output,
|
|
2739
|
+
minOccurrences: options.extractableMinOccurrences ?? GENERATE_DEFAULTS.minOccurrences,
|
|
2740
|
+
minSize: options.minSize,
|
|
2741
|
+
maxSize: options.maxSize,
|
|
2742
|
+
top: options.top,
|
|
2743
|
+
prefix: options.prefix,
|
|
2744
|
+
include: options.include,
|
|
2745
|
+
exclude: options.exclude,
|
|
2746
|
+
changed: options.changed,
|
|
2747
|
+
configPath: options.configPath,
|
|
2748
|
+
names: options.names,
|
|
2749
|
+
extractableOnly: true,
|
|
2750
|
+
dryRun: true,
|
|
2751
|
+
quiet: true,
|
|
2752
|
+
verboseSkipped: options.verboseSkipped
|
|
2753
|
+
});
|
|
2754
|
+
}
|
|
2755
|
+
const result = {
|
|
2756
|
+
passed,
|
|
2757
|
+
extractablePatternCount,
|
|
2758
|
+
report: scanResult.report,
|
|
2759
|
+
preview
|
|
2760
|
+
};
|
|
2761
|
+
if (options.format === "json") {
|
|
2762
|
+
const jsonReport = {
|
|
2763
|
+
command: "check",
|
|
2764
|
+
passed,
|
|
2765
|
+
outputPath: options.output,
|
|
2766
|
+
extractablePatternCount,
|
|
2767
|
+
analyzeMinOccurrences: scanResult.report.stats.analyzeMinOccurrences,
|
|
2768
|
+
extractableMinOccurrences: scanResult.report.stats.extractableMinOccurrences,
|
|
2769
|
+
report: scanResult.report,
|
|
2770
|
+
preview: preview ? {
|
|
2771
|
+
componentsGenerated: preview.componentsGenerated,
|
|
2772
|
+
filesModified: preview.filesModified,
|
|
2773
|
+
replacementsTotal: preview.replacementsTotal,
|
|
2774
|
+
skippedTotal: preview.skipped.length,
|
|
2775
|
+
savings: preview.savings
|
|
2776
|
+
} : null
|
|
2777
|
+
};
|
|
2778
|
+
printCheckJsonReport(jsonReport);
|
|
2779
|
+
} else {
|
|
2780
|
+
printCheckConsoleReport(scanResult.report, {
|
|
2781
|
+
outputPath: options.output,
|
|
2782
|
+
topLimit: options.top,
|
|
2783
|
+
preview,
|
|
2784
|
+
verboseSkipped: options.verboseSkipped,
|
|
2785
|
+
passed
|
|
2786
|
+
});
|
|
2787
|
+
}
|
|
2788
|
+
if (!passed) {
|
|
2789
|
+
console.error(
|
|
2790
|
+
chalk7.red(
|
|
2791
|
+
`Found ${extractablePatternCount} extractable pattern(s); limit is ${failThreshold}.`
|
|
2792
|
+
)
|
|
2793
|
+
);
|
|
2794
|
+
process.exit(1);
|
|
2520
2795
|
}
|
|
2521
2796
|
return result;
|
|
2522
2797
|
}
|
|
@@ -2524,7 +2799,7 @@ async function applyCommand(targetPath, options) {
|
|
|
2524
2799
|
// src/commands/generate.ts
|
|
2525
2800
|
import fs7 from "fs/promises";
|
|
2526
2801
|
import path8 from "path";
|
|
2527
|
-
import
|
|
2802
|
+
import chalk8 from "chalk";
|
|
2528
2803
|
async function generateCommand(targetPath, options) {
|
|
2529
2804
|
let scanResult = null;
|
|
2530
2805
|
let components;
|
|
@@ -2576,13 +2851,13 @@ async function generateCommand(targetPath, options) {
|
|
|
2576
2851
|
}
|
|
2577
2852
|
} catch (error) {
|
|
2578
2853
|
const message = error instanceof Error ? error.message : String(error);
|
|
2579
|
-
console.error(
|
|
2854
|
+
console.error(chalk8.red(`Error: ${message}`));
|
|
2580
2855
|
process.exit(1);
|
|
2581
2856
|
}
|
|
2582
2857
|
if (scanResult) {
|
|
2583
2858
|
for (const warning of scanResult.warnings) {
|
|
2584
2859
|
if (options.format !== "json") {
|
|
2585
|
-
console.warn(
|
|
2860
|
+
console.warn(chalk8.yellow(`\u26A0 ${warning}`));
|
|
2586
2861
|
}
|
|
2587
2862
|
}
|
|
2588
2863
|
}
|
|
@@ -2606,28 +2881,28 @@ async function generateCommand(targetPath, options) {
|
|
|
2606
2881
|
return result;
|
|
2607
2882
|
}
|
|
2608
2883
|
console.log("");
|
|
2609
|
-
console.log(
|
|
2610
|
-
console.log(
|
|
2884
|
+
console.log(chalk8.bold.green("\u2705 CSS generated successfully"));
|
|
2885
|
+
console.log(chalk8.gray(` Output: `) + chalk8.white(outputPath));
|
|
2611
2886
|
console.log(
|
|
2612
|
-
|
|
2887
|
+
chalk8.gray(` Components: `) + chalk8.white(String(components.length))
|
|
2613
2888
|
);
|
|
2614
2889
|
if (components.length > 0) {
|
|
2615
2890
|
console.log("");
|
|
2616
|
-
console.log(
|
|
2891
|
+
console.log(chalk8.bold("Generated classes:"));
|
|
2617
2892
|
for (const component of components) {
|
|
2618
2893
|
console.log(
|
|
2619
|
-
|
|
2894
|
+
chalk8.green(` .${component.className}`) + chalk8.gray(` \u2014 ${component.occurrences} occurrences, `) + chalk8.dim(component.classes.join(" "))
|
|
2620
2895
|
);
|
|
2621
2896
|
}
|
|
2622
2897
|
console.log("");
|
|
2623
2898
|
console.log(
|
|
2624
|
-
|
|
2625
|
-
"Run apply to replace className strings: npx tailwind-unwind apply
|
|
2899
|
+
chalk8.cyan(
|
|
2900
|
+
"Run apply to replace className strings: npx tailwind-unwind apply"
|
|
2626
2901
|
)
|
|
2627
2902
|
);
|
|
2628
2903
|
} else {
|
|
2629
2904
|
console.log(
|
|
2630
|
-
|
|
2905
|
+
chalk8.yellow(
|
|
2631
2906
|
"\nNo repeated className sets matched the filters. Try lowering --min-occurrences."
|
|
2632
2907
|
)
|
|
2633
2908
|
);
|
|
@@ -2671,7 +2946,11 @@ export {
|
|
|
2671
2946
|
printConsoleReport,
|
|
2672
2947
|
printJsonReport,
|
|
2673
2948
|
analyzeCommand,
|
|
2674
|
-
|
|
2949
|
+
DEFAULT_TARGET_PATH,
|
|
2950
|
+
ANALYZE_DEFAULTS,
|
|
2951
|
+
GENERATE_DEFAULTS,
|
|
2952
|
+
resolveTargetPath,
|
|
2953
|
+
resolveOutputPath,
|
|
2675
2954
|
formatSource,
|
|
2676
2955
|
formatModifiedFiles,
|
|
2677
2956
|
replaceClassNamesInSource,
|
|
@@ -2683,9 +2962,15 @@ export {
|
|
|
2683
2962
|
buildComponents,
|
|
2684
2963
|
buildComponentsFromCombinations,
|
|
2685
2964
|
loadExtractableCombinations,
|
|
2965
|
+
calculateSavings,
|
|
2686
2966
|
printGenerateJsonReport,
|
|
2687
2967
|
printApplyJsonReport,
|
|
2968
|
+
groupSkippedByReason,
|
|
2969
|
+
printSkippedReport,
|
|
2688
2970
|
applyCommand,
|
|
2971
|
+
printCheckJsonReport,
|
|
2972
|
+
printCheckConsoleReport,
|
|
2973
|
+
checkCommand,
|
|
2689
2974
|
generateCommand
|
|
2690
2975
|
};
|
|
2691
|
-
//# sourceMappingURL=chunk-
|
|
2976
|
+
//# sourceMappingURL=chunk-RMTZCCPS.js.map
|