tailwind-unwind 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -4
- package/dist/{chunk-FASYIEVZ.js → chunk-4GXMK3NB.js} +542 -107
- package/dist/chunk-4GXMK3NB.js.map +1 -0
- package/dist/cli/index.js +26 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +144 -73
- package/dist/index.js +21 -1
- package/package.json +10 -1
- package/tailwind-unwind.config.example.json +5 -2
- package/dist/chunk-FASYIEVZ.js.map +0 -1
|
@@ -12,6 +12,9 @@ var KNOWN_ROOT_KEYS = /* @__PURE__ */ new Set([
|
|
|
12
12
|
"top",
|
|
13
13
|
"dedupeSubsets",
|
|
14
14
|
"dryRun",
|
|
15
|
+
"prettier",
|
|
16
|
+
"fromReport",
|
|
17
|
+
"extractableOnly",
|
|
15
18
|
"analyze",
|
|
16
19
|
"generate",
|
|
17
20
|
"apply"
|
|
@@ -24,33 +27,36 @@ var KNOWN_COMMAND_KEYS = /* @__PURE__ */ new Set([
|
|
|
24
27
|
"prefix",
|
|
25
28
|
"output",
|
|
26
29
|
"dedupeSubsets",
|
|
27
|
-
"dryRun"
|
|
30
|
+
"dryRun",
|
|
31
|
+
"prettier",
|
|
32
|
+
"fromReport",
|
|
33
|
+
"extractableOnly"
|
|
28
34
|
]);
|
|
29
35
|
function isRecord(value) {
|
|
30
36
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31
37
|
}
|
|
32
|
-
function assertPositiveNumber(value,
|
|
38
|
+
function assertPositiveNumber(value, path7, errors) {
|
|
33
39
|
if (value === void 0) {
|
|
34
40
|
return;
|
|
35
41
|
}
|
|
36
42
|
if (typeof value !== "number" || !Number.isFinite(value) || value < 1) {
|
|
37
|
-
errors.push(`${
|
|
43
|
+
errors.push(`${path7} must be a positive number`);
|
|
38
44
|
}
|
|
39
45
|
}
|
|
40
|
-
function assertBoolean(value,
|
|
46
|
+
function assertBoolean(value, path7, errors) {
|
|
41
47
|
if (value === void 0) {
|
|
42
48
|
return;
|
|
43
49
|
}
|
|
44
50
|
if (typeof value !== "boolean") {
|
|
45
|
-
errors.push(`${
|
|
51
|
+
errors.push(`${path7} must be a boolean`);
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
|
-
function assertStringArray(value,
|
|
54
|
+
function assertStringArray(value, path7, errors) {
|
|
49
55
|
if (value === void 0) {
|
|
50
56
|
return;
|
|
51
57
|
}
|
|
52
58
|
if (!Array.isArray(value) || !value.every((item) => typeof item === "string" && item.length > 0)) {
|
|
53
|
-
errors.push(`${
|
|
59
|
+
errors.push(`${path7} must be an array of non-empty strings`);
|
|
54
60
|
}
|
|
55
61
|
}
|
|
56
62
|
function validateCommandSection(value, section, errors) {
|
|
@@ -72,6 +78,11 @@ function validateCommandSection(value, section, errors) {
|
|
|
72
78
|
assertPositiveNumber(value.top, `${section}.top`, errors);
|
|
73
79
|
assertBoolean(value.dedupeSubsets, `${section}.dedupeSubsets`, errors);
|
|
74
80
|
assertBoolean(value.dryRun, `${section}.dryRun`, errors);
|
|
81
|
+
assertBoolean(value.prettier, `${section}.prettier`, errors);
|
|
82
|
+
assertBoolean(value.extractableOnly, `${section}.extractableOnly`, errors);
|
|
83
|
+
if (value.fromReport !== void 0 && (typeof value.fromReport !== "string" || value.fromReport.length === 0)) {
|
|
84
|
+
errors.push(`${section}.fromReport must be a non-empty string`);
|
|
85
|
+
}
|
|
75
86
|
if (value.prefix !== void 0 && (typeof value.prefix !== "string" || value.prefix.length === 0)) {
|
|
76
87
|
errors.push(`${section}.prefix must be a non-empty string`);
|
|
77
88
|
}
|
|
@@ -118,6 +129,11 @@ function validateConfigFile(raw, configPath) {
|
|
|
118
129
|
assertPositiveNumber(source.top, "top", errors);
|
|
119
130
|
assertBoolean(source.dedupeSubsets, "dedupeSubsets", errors);
|
|
120
131
|
assertBoolean(source.dryRun, "dryRun", errors);
|
|
132
|
+
assertBoolean(source.prettier, "prettier", errors);
|
|
133
|
+
assertBoolean(source.extractableOnly, "extractableOnly", errors);
|
|
134
|
+
if (source.fromReport !== void 0 && (typeof source.fromReport !== "string" || source.fromReport.length === 0)) {
|
|
135
|
+
errors.push("fromReport must be a non-empty string");
|
|
136
|
+
}
|
|
121
137
|
validateNames(source.names, errors);
|
|
122
138
|
validateCommandSection(source.analyze, "analyze", errors);
|
|
123
139
|
validateCommandSection(source.generate, "generate", errors);
|
|
@@ -189,6 +205,15 @@ function pickCommandConfig(source) {
|
|
|
189
205
|
if (typeof source.dryRun === "boolean") {
|
|
190
206
|
config.dryRun = source.dryRun;
|
|
191
207
|
}
|
|
208
|
+
if (typeof source.prettier === "boolean") {
|
|
209
|
+
config.prettier = source.prettier;
|
|
210
|
+
}
|
|
211
|
+
if (typeof source.fromReport === "string" && source.fromReport.length > 0) {
|
|
212
|
+
config.fromReport = source.fromReport;
|
|
213
|
+
}
|
|
214
|
+
if (typeof source.extractableOnly === "boolean") {
|
|
215
|
+
config.extractableOnly = source.extractableOnly;
|
|
216
|
+
}
|
|
192
217
|
return config;
|
|
193
218
|
}
|
|
194
219
|
function pickNames(source) {
|
|
@@ -936,6 +961,113 @@ function calculatePotentialReduction(occurrences, topCombinations) {
|
|
|
936
961
|
return Math.min(100, Math.round(savable / totalClassUsages * 100));
|
|
937
962
|
}
|
|
938
963
|
|
|
964
|
+
// src/parser/variantHelpers.ts
|
|
965
|
+
import babelTraverse from "@babel/traverse";
|
|
966
|
+
var VARIANT_CALLEES = /* @__PURE__ */ new Set(["tv", "cva"]);
|
|
967
|
+
function isVariantCallee(expression) {
|
|
968
|
+
if (expression.type === "Identifier") {
|
|
969
|
+
return VARIANT_CALLEES.has(expression.name);
|
|
970
|
+
}
|
|
971
|
+
if (expression.type === "MemberExpression" && expression.property.type === "Identifier") {
|
|
972
|
+
return VARIANT_CALLEES.has(expression.property.name);
|
|
973
|
+
}
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
function collectStringsFromObject(node) {
|
|
977
|
+
const classes = [];
|
|
978
|
+
for (const prop of node.properties) {
|
|
979
|
+
if (prop.type === "SpreadElement") {
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
if (prop.type !== "ObjectProperty") {
|
|
983
|
+
continue;
|
|
984
|
+
}
|
|
985
|
+
collectStringsFromPropertyValue(prop, classes);
|
|
986
|
+
}
|
|
987
|
+
return classes;
|
|
988
|
+
}
|
|
989
|
+
function collectStringsFromPropertyValue(prop, classes) {
|
|
990
|
+
const keyName = prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "StringLiteral" ? prop.key.value : null;
|
|
991
|
+
const { value } = prop;
|
|
992
|
+
if (value.type === "StringLiteral") {
|
|
993
|
+
classes.push(...splitClassString(value.value));
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
if (value.type === "ObjectExpression") {
|
|
997
|
+
if (keyName === "variants" || keyName === "compoundVariants") {
|
|
998
|
+
for (const nested of value.properties) {
|
|
999
|
+
if (nested.type === "ObjectProperty") {
|
|
1000
|
+
collectStringsFromPropertyValue(nested, classes);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
classes.push(...collectStringsFromObject(value));
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
if (value.type === "ArrayExpression") {
|
|
1009
|
+
for (const element of value.elements) {
|
|
1010
|
+
if (element === null || element.type === "SpreadElement") {
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
1013
|
+
if (element.type === "StringLiteral") {
|
|
1014
|
+
classes.push(...splitClassString(element.value));
|
|
1015
|
+
} else if (element.type === "ObjectExpression") {
|
|
1016
|
+
classes.push(...collectStringsFromObject(element));
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
function extractClassesFromVariantCall(call) {
|
|
1022
|
+
const classes = [];
|
|
1023
|
+
for (const arg of call.arguments) {
|
|
1024
|
+
if (arg.type === "SpreadElement" || arg.type === "ArgumentPlaceholder") {
|
|
1025
|
+
continue;
|
|
1026
|
+
}
|
|
1027
|
+
if (arg.type === "StringLiteral") {
|
|
1028
|
+
classes.push(...splitClassString(arg.value));
|
|
1029
|
+
continue;
|
|
1030
|
+
}
|
|
1031
|
+
if (arg.type === "ObjectExpression") {
|
|
1032
|
+
classes.push(...collectStringsFromObject(arg));
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
return [...new Set(classes)];
|
|
1036
|
+
}
|
|
1037
|
+
function resolveTraverse(module) {
|
|
1038
|
+
if (typeof module === "function") {
|
|
1039
|
+
return module;
|
|
1040
|
+
}
|
|
1041
|
+
const withDefault = module;
|
|
1042
|
+
if (typeof withDefault.default === "function") {
|
|
1043
|
+
return withDefault.default;
|
|
1044
|
+
}
|
|
1045
|
+
throw new Error("Failed to load @babel/traverse");
|
|
1046
|
+
}
|
|
1047
|
+
var traverse = resolveTraverse(babelTraverse);
|
|
1048
|
+
function collectVariantRegistry(ast) {
|
|
1049
|
+
const registry = /* @__PURE__ */ new Map();
|
|
1050
|
+
traverse(ast, {
|
|
1051
|
+
VariableDeclarator(path7) {
|
|
1052
|
+
registerVariantDeclarator(path7.node, registry);
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
return registry;
|
|
1056
|
+
}
|
|
1057
|
+
function registerVariantDeclarator(declarator, registry) {
|
|
1058
|
+
if (declarator.id.type !== "Identifier" || declarator.init?.type !== "CallExpression") {
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
const { init } = declarator;
|
|
1062
|
+
if (init.callee.type === "V8IntrinsicIdentifier" || !isVariantCallee(init.callee)) {
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
const classes = extractClassesFromVariantCall(init);
|
|
1066
|
+
if (classes.length > 0) {
|
|
1067
|
+
registry.set(declarator.id.name, classes);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
939
1071
|
// src/parser/classHelpers.ts
|
|
940
1072
|
var CLASS_MERGE_CALLEES = /* @__PURE__ */ new Set([
|
|
941
1073
|
"cn",
|
|
@@ -978,18 +1110,34 @@ function isClassMergeCallee(expression) {
|
|
|
978
1110
|
}
|
|
979
1111
|
return false;
|
|
980
1112
|
}
|
|
981
|
-
function extractFromCallArguments(args) {
|
|
1113
|
+
function extractFromCallArguments(args, registry) {
|
|
982
1114
|
const parts = [];
|
|
983
1115
|
for (const arg of args) {
|
|
984
1116
|
if (arg.type === "SpreadElement" || arg.type === "ArgumentPlaceholder") {
|
|
985
1117
|
parts.push({ classes: [], isDynamic: true });
|
|
986
1118
|
continue;
|
|
987
1119
|
}
|
|
988
|
-
parts.push(extractClassesFromExpression(arg));
|
|
1120
|
+
parts.push(extractClassesFromExpression(arg, registry));
|
|
989
1121
|
}
|
|
990
1122
|
return mergeExtractions(parts);
|
|
991
1123
|
}
|
|
992
|
-
function
|
|
1124
|
+
function extractFromVariantCall(call, registry) {
|
|
1125
|
+
const { callee } = call;
|
|
1126
|
+
if (callee.type !== "V8IntrinsicIdentifier" && isVariantCallee(callee)) {
|
|
1127
|
+
const classes = extractClassesFromVariantCall(call);
|
|
1128
|
+
const hasDynamicArgs = call.arguments.some(
|
|
1129
|
+
(arg) => arg.type === "SpreadElement" || arg.type === "ArgumentPlaceholder"
|
|
1130
|
+
);
|
|
1131
|
+
return { classes, isDynamic: hasDynamicArgs };
|
|
1132
|
+
}
|
|
1133
|
+
if (callee.type === "Identifier" && registry?.has(callee.name)) {
|
|
1134
|
+
const classes = registry.get(callee.name) ?? [];
|
|
1135
|
+
const hasArgs = call.arguments.length > 0;
|
|
1136
|
+
return { classes, isDynamic: hasArgs };
|
|
1137
|
+
}
|
|
1138
|
+
return { classes: [], isDynamic: true };
|
|
1139
|
+
}
|
|
1140
|
+
function extractClassesFromExpression(expression, registry) {
|
|
993
1141
|
switch (expression.type) {
|
|
994
1142
|
case "StringLiteral":
|
|
995
1143
|
return extractFromStringLiteral(expression.value);
|
|
@@ -998,40 +1146,44 @@ function extractClassesFromExpression(expression) {
|
|
|
998
1146
|
case "CallExpression": {
|
|
999
1147
|
const { callee } = expression;
|
|
1000
1148
|
if (callee.type !== "V8IntrinsicIdentifier" && isClassMergeCallee(callee)) {
|
|
1001
|
-
return extractFromCallArguments(expression.arguments);
|
|
1149
|
+
return extractFromCallArguments(expression.arguments, registry);
|
|
1150
|
+
}
|
|
1151
|
+
const variantExtraction = extractFromVariantCall(expression, registry);
|
|
1152
|
+
if (variantExtraction.classes.length > 0 || !variantExtraction.isDynamic) {
|
|
1153
|
+
return variantExtraction;
|
|
1002
1154
|
}
|
|
1003
1155
|
return { classes: [], isDynamic: true };
|
|
1004
1156
|
}
|
|
1005
1157
|
case "ConditionalExpression": {
|
|
1006
1158
|
const merged = mergeExtractions([
|
|
1007
|
-
extractClassesFromExpression(expression.consequent),
|
|
1008
|
-
extractClassesFromExpression(expression.alternate)
|
|
1159
|
+
extractClassesFromExpression(expression.consequent, registry),
|
|
1160
|
+
extractClassesFromExpression(expression.alternate, registry)
|
|
1009
1161
|
]);
|
|
1010
1162
|
return { ...merged, isDynamic: true };
|
|
1011
1163
|
}
|
|
1012
1164
|
case "LogicalExpression": {
|
|
1013
1165
|
const merged = mergeExtractions([
|
|
1014
|
-
extractClassesFromExpression(expression.left),
|
|
1015
|
-
extractClassesFromExpression(expression.right)
|
|
1166
|
+
extractClassesFromExpression(expression.left, registry),
|
|
1167
|
+
extractClassesFromExpression(expression.right, registry)
|
|
1016
1168
|
]);
|
|
1017
1169
|
return { ...merged, isDynamic: true };
|
|
1018
1170
|
}
|
|
1019
1171
|
case "ArrayExpression":
|
|
1020
|
-
return extractFromArrayExpression(expression);
|
|
1172
|
+
return extractFromArrayExpression(expression, registry);
|
|
1021
1173
|
case "ObjectExpression":
|
|
1022
1174
|
return extractFromObjectExpression(expression);
|
|
1023
1175
|
default:
|
|
1024
1176
|
return { classes: [], isDynamic: true };
|
|
1025
1177
|
}
|
|
1026
1178
|
}
|
|
1027
|
-
function extractFromArrayExpression(node) {
|
|
1179
|
+
function extractFromArrayExpression(node, registry) {
|
|
1028
1180
|
const parts = [];
|
|
1029
1181
|
for (const element of node.elements) {
|
|
1030
1182
|
if (element === null || element.type === "SpreadElement") {
|
|
1031
1183
|
parts.push({ classes: [], isDynamic: true });
|
|
1032
1184
|
continue;
|
|
1033
1185
|
}
|
|
1034
|
-
parts.push(extractClassesFromExpression(element));
|
|
1186
|
+
parts.push(extractClassesFromExpression(element, registry));
|
|
1035
1187
|
}
|
|
1036
1188
|
return mergeExtractions(parts);
|
|
1037
1189
|
}
|
|
@@ -1086,7 +1238,7 @@ function isClassAttribute(attr) {
|
|
|
1086
1238
|
const name = getAttributeName(attr);
|
|
1087
1239
|
return name !== null && CLASS_ATTRIBUTES.has(name);
|
|
1088
1240
|
}
|
|
1089
|
-
function extractFromJSXAttribute(attr) {
|
|
1241
|
+
function extractFromJSXAttribute(attr, registry) {
|
|
1090
1242
|
if (!isClassAttribute(attr)) {
|
|
1091
1243
|
return null;
|
|
1092
1244
|
}
|
|
@@ -1096,7 +1248,7 @@ function extractFromJSXAttribute(attr) {
|
|
|
1096
1248
|
return { classes: [], isDynamic: true, line };
|
|
1097
1249
|
}
|
|
1098
1250
|
if (value.type === "StringLiteral") {
|
|
1099
|
-
const result = extractClassesFromExpression(value);
|
|
1251
|
+
const result = extractClassesFromExpression(value, registry);
|
|
1100
1252
|
return { classes: result.classes, isDynamic: result.isDynamic, line };
|
|
1101
1253
|
}
|
|
1102
1254
|
if (value.type === "JSXExpressionContainer") {
|
|
@@ -1104,7 +1256,7 @@ function extractFromJSXAttribute(attr) {
|
|
|
1104
1256
|
if (expr.type === "JSXEmptyExpression") {
|
|
1105
1257
|
return { classes: [], isDynamic: true, line };
|
|
1106
1258
|
}
|
|
1107
|
-
const result = extractClassesFromExpression(expr);
|
|
1259
|
+
const result = extractClassesFromExpression(expr, registry);
|
|
1108
1260
|
return { classes: result.classes, isDynamic: result.isDynamic, line };
|
|
1109
1261
|
}
|
|
1110
1262
|
return { classes: [], isDynamic: true, line };
|
|
@@ -1121,9 +1273,9 @@ function parseSourceToAst(source) {
|
|
|
1121
1273
|
}
|
|
1122
1274
|
|
|
1123
1275
|
// src/parser/jsxParser.ts
|
|
1124
|
-
import
|
|
1276
|
+
import babelTraverse2 from "@babel/traverse";
|
|
1125
1277
|
import fs2 from "fs/promises";
|
|
1126
|
-
function
|
|
1278
|
+
function resolveTraverse2(module) {
|
|
1127
1279
|
if (typeof module === "function") {
|
|
1128
1280
|
return module;
|
|
1129
1281
|
}
|
|
@@ -1133,9 +1285,9 @@ function resolveTraverse(module) {
|
|
|
1133
1285
|
}
|
|
1134
1286
|
throw new Error("Failed to load @babel/traverse");
|
|
1135
1287
|
}
|
|
1136
|
-
var
|
|
1137
|
-
function isJSXElementWithClassAttribute(
|
|
1138
|
-
const opening =
|
|
1288
|
+
var traverse2 = resolveTraverse2(babelTraverse2);
|
|
1289
|
+
function isJSXElementWithClassAttribute(path7) {
|
|
1290
|
+
const opening = path7.node.openingElement;
|
|
1139
1291
|
return opening.attributes.some(
|
|
1140
1292
|
(attr) => attr.type === "JSXAttribute" && isClassAttribute(attr)
|
|
1141
1293
|
);
|
|
@@ -1143,15 +1295,16 @@ function isJSXElementWithClassAttribute(path6) {
|
|
|
1143
1295
|
function collectExtractionsFromAst(ast, filePath) {
|
|
1144
1296
|
const extractions = [];
|
|
1145
1297
|
const warnings = [];
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1298
|
+
const variantRegistry = collectVariantRegistry(ast);
|
|
1299
|
+
traverse2(ast, {
|
|
1300
|
+
JSXElement(path7) {
|
|
1301
|
+
if (!isJSXElementWithClassAttribute(path7)) {
|
|
1149
1302
|
return;
|
|
1150
1303
|
}
|
|
1151
|
-
const opening =
|
|
1304
|
+
const opening = path7.node.openingElement;
|
|
1152
1305
|
for (const attr of opening.attributes) {
|
|
1153
1306
|
if (attr.type !== "JSXAttribute") continue;
|
|
1154
|
-
const extraction = extractFromJSXAttribute(attr);
|
|
1307
|
+
const extraction = extractFromJSXAttribute(attr, variantRegistry);
|
|
1155
1308
|
if (!extraction) continue;
|
|
1156
1309
|
if (extraction.isDynamic && extraction.classes.length === 0) {
|
|
1157
1310
|
const lineInfo = extraction.line ? `:${extraction.line}` : "";
|
|
@@ -1467,11 +1620,66 @@ async function analyzeCommand(targetPath, options = {}) {
|
|
|
1467
1620
|
return report;
|
|
1468
1621
|
}
|
|
1469
1622
|
|
|
1623
|
+
// src/codemod/formatSource.ts
|
|
1624
|
+
import { createRequire } from "module";
|
|
1625
|
+
import path4 from "path";
|
|
1626
|
+
var require2 = createRequire(import.meta.url);
|
|
1627
|
+
async function loadPrettier() {
|
|
1628
|
+
try {
|
|
1629
|
+
const prettier = await import("prettier");
|
|
1630
|
+
return prettier;
|
|
1631
|
+
} catch {
|
|
1632
|
+
try {
|
|
1633
|
+
return require2("prettier");
|
|
1634
|
+
} catch {
|
|
1635
|
+
return null;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
async function formatSource(source, options) {
|
|
1640
|
+
const prettier = await loadPrettier();
|
|
1641
|
+
if (!prettier) {
|
|
1642
|
+
return { source, formatted: false };
|
|
1643
|
+
}
|
|
1644
|
+
try {
|
|
1645
|
+
const config = await prettier.resolveConfig(options.filePath);
|
|
1646
|
+
const formatted = await prettier.format(source, {
|
|
1647
|
+
...config,
|
|
1648
|
+
filepath: options.filePath
|
|
1649
|
+
});
|
|
1650
|
+
return { source: formatted, formatted: true };
|
|
1651
|
+
} catch {
|
|
1652
|
+
return { source, formatted: false };
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
async function formatModifiedFiles(files, sources, cwd = process.cwd()) {
|
|
1656
|
+
const formatted = [];
|
|
1657
|
+
const skipped = [];
|
|
1658
|
+
for (const file of files) {
|
|
1659
|
+
const source = sources.get(file);
|
|
1660
|
+
if (!source) {
|
|
1661
|
+
skipped.push(file);
|
|
1662
|
+
continue;
|
|
1663
|
+
}
|
|
1664
|
+
const result = await formatSource(source, {
|
|
1665
|
+
filePath: path4.resolve(cwd, file),
|
|
1666
|
+
cwd
|
|
1667
|
+
});
|
|
1668
|
+
if (result.formatted) {
|
|
1669
|
+
sources.set(file, result.source);
|
|
1670
|
+
formatted.push(file);
|
|
1671
|
+
} else {
|
|
1672
|
+
skipped.push(file);
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
return { formatted, skipped };
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1470
1678
|
// src/codemod/replaceClassNames.ts
|
|
1471
1679
|
import babelGenerate from "@babel/generator";
|
|
1472
|
-
import
|
|
1680
|
+
import babelTraverse3 from "@babel/traverse";
|
|
1473
1681
|
import * as t from "@babel/types";
|
|
1474
|
-
function
|
|
1682
|
+
function resolveTraverse3(module) {
|
|
1475
1683
|
if (typeof module === "function") {
|
|
1476
1684
|
return module;
|
|
1477
1685
|
}
|
|
@@ -1491,7 +1699,7 @@ function resolveGenerator(module) {
|
|
|
1491
1699
|
}
|
|
1492
1700
|
throw new Error("Failed to load @babel/generator");
|
|
1493
1701
|
}
|
|
1494
|
-
var
|
|
1702
|
+
var traverse3 = resolveTraverse3(babelTraverse3);
|
|
1495
1703
|
var generate = resolveGenerator(babelGenerate);
|
|
1496
1704
|
function isClassMergeCallee2(expression) {
|
|
1497
1705
|
if (expression.type === "Identifier") {
|
|
@@ -1586,16 +1794,54 @@ function tryReplaceMergeCall(call, replacementMap) {
|
|
|
1586
1794
|
partial: true
|
|
1587
1795
|
};
|
|
1588
1796
|
}
|
|
1589
|
-
function
|
|
1797
|
+
function tryReplaceTemplateLiteral(attr, replacementMap, registry) {
|
|
1798
|
+
const value = attr.value;
|
|
1799
|
+
if (value?.type !== "JSXExpressionContainer") {
|
|
1800
|
+
return null;
|
|
1801
|
+
}
|
|
1802
|
+
const expression = value.expression;
|
|
1803
|
+
if (expression.type !== "TemplateLiteral" || expression.expressions.length === 0) {
|
|
1804
|
+
return null;
|
|
1805
|
+
}
|
|
1806
|
+
const extracted = extractClassesFromExpression(expression, registry);
|
|
1807
|
+
if (extracted.classes.length === 0) {
|
|
1808
|
+
return null;
|
|
1809
|
+
}
|
|
1810
|
+
const key = normalizeClasses(extracted.classes);
|
|
1811
|
+
const replacement = replacementMap.get(key);
|
|
1812
|
+
if (!replacement) {
|
|
1813
|
+
return null;
|
|
1814
|
+
}
|
|
1815
|
+
const newQuasis = expression.quasis.map((quasi, index) => {
|
|
1816
|
+
if (index !== 0) {
|
|
1817
|
+
return quasi;
|
|
1818
|
+
}
|
|
1819
|
+
const prefix = expression.expressions.length > 0 ? `${replacement} ` : replacement;
|
|
1820
|
+
return t.templateElement(
|
|
1821
|
+
{ raw: prefix, cooked: prefix },
|
|
1822
|
+
quasi.tail
|
|
1823
|
+
);
|
|
1824
|
+
});
|
|
1825
|
+
return {
|
|
1826
|
+
expression: t.templateLiteral(newQuasis, [...expression.expressions]),
|
|
1827
|
+
from: key,
|
|
1828
|
+
to: replacement,
|
|
1829
|
+
partial: true
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1832
|
+
function tryReplaceClassAttribute(attr, replacementMap, registry) {
|
|
1590
1833
|
const value = attr.value;
|
|
1591
1834
|
if (value?.type !== "JSXExpressionContainer") {
|
|
1592
1835
|
return null;
|
|
1593
1836
|
}
|
|
1594
1837
|
const expression = value.expression;
|
|
1595
|
-
if (expression.type === "JSXEmptyExpression"
|
|
1838
|
+
if (expression.type === "JSXEmptyExpression") {
|
|
1596
1839
|
return null;
|
|
1597
1840
|
}
|
|
1598
|
-
|
|
1841
|
+
if (isClassMergeCall(expression)) {
|
|
1842
|
+
return tryReplaceMergeCall(expression, replacementMap);
|
|
1843
|
+
}
|
|
1844
|
+
return tryReplaceTemplateLiteral(attr, replacementMap, registry);
|
|
1599
1845
|
}
|
|
1600
1846
|
function replaceClassNamesInSource(source, replacementMap, filePath) {
|
|
1601
1847
|
const replacements = [];
|
|
@@ -1610,16 +1856,21 @@ function replaceClassNamesInSource(source, replacementMap, filePath) {
|
|
|
1610
1856
|
const message = error instanceof Error ? error.message : String(error);
|
|
1611
1857
|
throw new Error(`Failed to parse ${filePath}: ${message}`);
|
|
1612
1858
|
}
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1859
|
+
const variantRegistry = collectVariantRegistry(ast);
|
|
1860
|
+
traverse3(ast, {
|
|
1861
|
+
JSXElement(path7) {
|
|
1862
|
+
const opening = path7.node.openingElement;
|
|
1616
1863
|
for (const attr of opening.attributes) {
|
|
1617
1864
|
if (attr.type !== "JSXAttribute" || !isClassAttribute(attr)) {
|
|
1618
1865
|
continue;
|
|
1619
1866
|
}
|
|
1620
|
-
const extraction = extractFromJSXAttribute(attr);
|
|
1867
|
+
const extraction = extractFromJSXAttribute(attr, variantRegistry);
|
|
1621
1868
|
if (!extraction) continue;
|
|
1622
|
-
const mergeReplacement = tryReplaceClassAttribute(
|
|
1869
|
+
const mergeReplacement = tryReplaceClassAttribute(
|
|
1870
|
+
attr,
|
|
1871
|
+
replacementMap,
|
|
1872
|
+
variantRegistry
|
|
1873
|
+
);
|
|
1623
1874
|
if (mergeReplacement) {
|
|
1624
1875
|
if (mergeReplacement.expression.type === "StringLiteral") {
|
|
1625
1876
|
setStringClassAttribute(attr, mergeReplacement.expression.value);
|
|
@@ -1775,10 +2026,61 @@ function buildComponents(occurrences, options) {
|
|
|
1775
2026
|
}
|
|
1776
2027
|
return { components, css, replacementMap };
|
|
1777
2028
|
}
|
|
2029
|
+
function buildComponentsFromCombinations(combinations, options) {
|
|
2030
|
+
const { css, components } = generateComponentCss({
|
|
2031
|
+
sourcePath: options.sourcePath,
|
|
2032
|
+
combinations,
|
|
2033
|
+
prefix: options.prefix,
|
|
2034
|
+
names: options.names
|
|
2035
|
+
});
|
|
2036
|
+
const replacementMap = /* @__PURE__ */ new Map();
|
|
2037
|
+
for (const component of components) {
|
|
2038
|
+
const key = [...component.classes].sort().join(" ");
|
|
2039
|
+
replacementMap.set(key, component.className);
|
|
2040
|
+
}
|
|
2041
|
+
return { components, css, replacementMap };
|
|
2042
|
+
}
|
|
1778
2043
|
|
|
1779
|
-
// src/
|
|
2044
|
+
// src/core/loadAnalyzeReport.ts
|
|
1780
2045
|
import fs4 from "fs/promises";
|
|
1781
|
-
|
|
2046
|
+
function isAnalysisReport(value) {
|
|
2047
|
+
if (typeof value !== "object" || value === null) {
|
|
2048
|
+
return false;
|
|
2049
|
+
}
|
|
2050
|
+
const report = value;
|
|
2051
|
+
return typeof report.targetPath === "string" && typeof report.stats === "object" && Array.isArray(report.stats.topCombinations);
|
|
2052
|
+
}
|
|
2053
|
+
async function loadExtractableCombinations(reportPath, options = {}) {
|
|
2054
|
+
const raw = await fs4.readFile(reportPath, "utf-8");
|
|
2055
|
+
const parsed = JSON.parse(raw);
|
|
2056
|
+
if (!isAnalysisReport(parsed)) {
|
|
2057
|
+
throw new Error(`Invalid analyze report: ${reportPath}`);
|
|
2058
|
+
}
|
|
2059
|
+
const combinations = parsed.stats.topCombinations.filter(
|
|
2060
|
+
(combo) => options.extractableOnly === false ? true : combo.extractable === true
|
|
2061
|
+
);
|
|
2062
|
+
if (combinations.length === 0) {
|
|
2063
|
+
throw new Error(
|
|
2064
|
+
"No extractable combinations found in report. Re-run analyze or use --extractable-only=false."
|
|
2065
|
+
);
|
|
2066
|
+
}
|
|
2067
|
+
return {
|
|
2068
|
+
targetPath: parsed.targetPath,
|
|
2069
|
+
combinations
|
|
2070
|
+
};
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
// src/reporters/operationJsonReporter.ts
|
|
2074
|
+
function printGenerateJsonReport(report) {
|
|
2075
|
+
console.log(JSON.stringify(report, null, 2));
|
|
2076
|
+
}
|
|
2077
|
+
function printApplyJsonReport(report) {
|
|
2078
|
+
console.log(JSON.stringify(report, null, 2));
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
// src/commands/apply.ts
|
|
2082
|
+
import fs5 from "fs/promises";
|
|
2083
|
+
import path5 from "path";
|
|
1782
2084
|
import chalk3 from "chalk";
|
|
1783
2085
|
async function applyCommand(targetPath, options) {
|
|
1784
2086
|
let scanResult;
|
|
@@ -1786,7 +2088,8 @@ async function applyCommand(targetPath, options) {
|
|
|
1786
2088
|
scanResult = await scanProject({
|
|
1787
2089
|
targetPath,
|
|
1788
2090
|
include: options.include,
|
|
1789
|
-
exclude: options.exclude
|
|
2091
|
+
exclude: options.exclude,
|
|
2092
|
+
extractableMinOccurrences: options.minOccurrences ?? 3
|
|
1790
2093
|
});
|
|
1791
2094
|
} catch (error) {
|
|
1792
2095
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1794,20 +2097,57 @@ async function applyCommand(targetPath, options) {
|
|
|
1794
2097
|
process.exit(1);
|
|
1795
2098
|
}
|
|
1796
2099
|
for (const warning of scanResult.warnings) {
|
|
1797
|
-
|
|
2100
|
+
if (options.format !== "json") {
|
|
2101
|
+
console.warn(chalk3.yellow(`\u26A0 ${warning}`));
|
|
2102
|
+
}
|
|
1798
2103
|
}
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
2104
|
+
let components;
|
|
2105
|
+
let css;
|
|
2106
|
+
let replacementMap;
|
|
2107
|
+
try {
|
|
2108
|
+
if (options.fromReport) {
|
|
2109
|
+
const loadedReport = await loadExtractableCombinations(options.fromReport, {
|
|
2110
|
+
extractableOnly: options.extractableOnly ?? true
|
|
2111
|
+
});
|
|
2112
|
+
const built = buildComponentsFromCombinations(loadedReport.combinations, {
|
|
2113
|
+
sourcePath: scanResult.resolvedPath,
|
|
2114
|
+
prefix: options.prefix,
|
|
2115
|
+
names: options.names
|
|
2116
|
+
});
|
|
2117
|
+
components = built.components;
|
|
2118
|
+
css = built.css;
|
|
2119
|
+
replacementMap = built.replacementMap;
|
|
2120
|
+
} else if (options.extractableOnly) {
|
|
2121
|
+
const combinations = scanResult.report.stats.topCombinations.filter(
|
|
2122
|
+
(combo) => combo.extractable
|
|
2123
|
+
);
|
|
2124
|
+
const built = buildComponentsFromCombinations(combinations, {
|
|
2125
|
+
sourcePath: scanResult.resolvedPath,
|
|
2126
|
+
prefix: options.prefix,
|
|
2127
|
+
names: options.names
|
|
2128
|
+
});
|
|
2129
|
+
components = built.components;
|
|
2130
|
+
css = built.css;
|
|
2131
|
+
replacementMap = built.replacementMap;
|
|
2132
|
+
} else {
|
|
2133
|
+
const built = buildComponents(scanResult.occurrences, {
|
|
2134
|
+
sourcePath: scanResult.resolvedPath,
|
|
2135
|
+
minOccurrences: options.minOccurrences ?? 3,
|
|
2136
|
+
minSize: options.minSize,
|
|
2137
|
+
maxSize: options.maxSize,
|
|
2138
|
+
topLimit: options.top,
|
|
2139
|
+
prefix: options.prefix,
|
|
2140
|
+
names: options.names
|
|
2141
|
+
});
|
|
2142
|
+
components = built.components;
|
|
2143
|
+
css = built.css;
|
|
2144
|
+
replacementMap = built.replacementMap;
|
|
1809
2145
|
}
|
|
1810
|
-
)
|
|
2146
|
+
} catch (error) {
|
|
2147
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2148
|
+
console.error(chalk3.red(`Error: ${message}`));
|
|
2149
|
+
process.exit(1);
|
|
2150
|
+
}
|
|
1811
2151
|
if (components.length === 0) {
|
|
1812
2152
|
console.error(
|
|
1813
2153
|
chalk3.yellow(
|
|
@@ -1816,31 +2156,71 @@ async function applyCommand(targetPath, options) {
|
|
|
1816
2156
|
);
|
|
1817
2157
|
process.exit(1);
|
|
1818
2158
|
}
|
|
1819
|
-
const outputPath =
|
|
2159
|
+
const outputPath = path5.resolve(options.output);
|
|
1820
2160
|
let filesModified = 0;
|
|
1821
2161
|
let replacementsTotal = 0;
|
|
1822
2162
|
const allReplacements = [];
|
|
1823
2163
|
const allSkipped = [];
|
|
2164
|
+
const modifiedSources = /* @__PURE__ */ new Map();
|
|
2165
|
+
const modifiedFiles = [];
|
|
1824
2166
|
for (const file of scanResult.files) {
|
|
1825
|
-
const original = await
|
|
1826
|
-
const
|
|
2167
|
+
const original = await fs5.readFile(file, "utf-8");
|
|
2168
|
+
const result2 = replaceClassNamesInSource(
|
|
1827
2169
|
original,
|
|
1828
2170
|
replacementMap,
|
|
1829
2171
|
file
|
|
1830
2172
|
);
|
|
1831
|
-
replacementsTotal +=
|
|
1832
|
-
allReplacements.push(...
|
|
1833
|
-
allSkipped.push(...
|
|
1834
|
-
if (
|
|
2173
|
+
replacementsTotal += result2.replacements.length;
|
|
2174
|
+
allReplacements.push(...result2.replacements);
|
|
2175
|
+
allSkipped.push(...result2.skipped);
|
|
2176
|
+
if (result2.changed) {
|
|
1835
2177
|
filesModified += 1;
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
}
|
|
2178
|
+
modifiedSources.set(file, result2.source);
|
|
2179
|
+
modifiedFiles.push(file);
|
|
1839
2180
|
}
|
|
1840
2181
|
}
|
|
2182
|
+
let prettierFormatted = [];
|
|
2183
|
+
if (!options.dryRun && options.prettier && modifiedFiles.length > 0) {
|
|
2184
|
+
const formatResult = await formatModifiedFiles(
|
|
2185
|
+
modifiedFiles,
|
|
2186
|
+
modifiedSources,
|
|
2187
|
+
process.cwd()
|
|
2188
|
+
);
|
|
2189
|
+
prettierFormatted = formatResult.formatted;
|
|
2190
|
+
}
|
|
1841
2191
|
if (!options.dryRun) {
|
|
1842
|
-
|
|
1843
|
-
|
|
2192
|
+
for (const file of modifiedFiles) {
|
|
2193
|
+
const source = modifiedSources.get(file);
|
|
2194
|
+
if (source) {
|
|
2195
|
+
await fs5.writeFile(file, source, "utf-8");
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
await fs5.mkdir(path5.dirname(outputPath), { recursive: true });
|
|
2199
|
+
await fs5.writeFile(outputPath, css, "utf-8");
|
|
2200
|
+
}
|
|
2201
|
+
const result = {
|
|
2202
|
+
filesModified,
|
|
2203
|
+
replacementsTotal,
|
|
2204
|
+
outputPath,
|
|
2205
|
+
componentsGenerated: components.length,
|
|
2206
|
+
components,
|
|
2207
|
+
replacements: allReplacements,
|
|
2208
|
+
skipped: allSkipped,
|
|
2209
|
+
prettierFormatted
|
|
2210
|
+
};
|
|
2211
|
+
if (options.format === "json") {
|
|
2212
|
+
printApplyJsonReport({
|
|
2213
|
+
command: "apply",
|
|
2214
|
+
dryRun: Boolean(options.dryRun),
|
|
2215
|
+
outputPath,
|
|
2216
|
+
filesModified,
|
|
2217
|
+
replacementsTotal,
|
|
2218
|
+
componentsGenerated: components.length,
|
|
2219
|
+
components,
|
|
2220
|
+
replacements: allReplacements,
|
|
2221
|
+
skipped: allSkipped
|
|
2222
|
+
});
|
|
2223
|
+
return result;
|
|
1844
2224
|
}
|
|
1845
2225
|
console.log("");
|
|
1846
2226
|
if (options.dryRun) {
|
|
@@ -1858,6 +2238,11 @@ async function applyCommand(targetPath, options) {
|
|
|
1858
2238
|
console.log(
|
|
1859
2239
|
chalk3.gray(` Replacements: `) + chalk3.white(String(replacementsTotal))
|
|
1860
2240
|
);
|
|
2241
|
+
if (prettierFormatted.length > 0) {
|
|
2242
|
+
console.log(
|
|
2243
|
+
chalk3.gray(` Prettier formatted: `) + chalk3.white(String(prettierFormatted.length))
|
|
2244
|
+
);
|
|
2245
|
+
}
|
|
1861
2246
|
if (allReplacements.length > 0) {
|
|
1862
2247
|
console.log("");
|
|
1863
2248
|
console.log(chalk3.bold("Replacements:"));
|
|
@@ -1871,9 +2256,7 @@ async function applyCommand(targetPath, options) {
|
|
|
1871
2256
|
}
|
|
1872
2257
|
if (allSkipped.length > 0) {
|
|
1873
2258
|
console.log("");
|
|
1874
|
-
console.log(
|
|
1875
|
-
chalk3.bold.yellow(`Skipped (${allSkipped.length}):`)
|
|
1876
|
-
);
|
|
2259
|
+
console.log(chalk3.bold.yellow(`Skipped (${allSkipped.length}):`));
|
|
1877
2260
|
for (const item of allSkipped) {
|
|
1878
2261
|
const line = item.line ? `:${item.line}` : "";
|
|
1879
2262
|
const classes = item.classes.join(" ");
|
|
@@ -1886,51 +2269,97 @@ async function applyCommand(targetPath, options) {
|
|
|
1886
2269
|
if (!options.dryRun) {
|
|
1887
2270
|
console.log(
|
|
1888
2271
|
chalk3.cyan(
|
|
1889
|
-
`Import ${
|
|
2272
|
+
`Import ${path5.basename(outputPath)} in your global CSS if you haven't already.`
|
|
1890
2273
|
)
|
|
1891
2274
|
);
|
|
1892
2275
|
console.log("");
|
|
1893
2276
|
}
|
|
1894
|
-
return
|
|
1895
|
-
filesModified,
|
|
1896
|
-
replacementsTotal,
|
|
1897
|
-
outputPath,
|
|
1898
|
-
componentsGenerated: components.length
|
|
1899
|
-
};
|
|
2277
|
+
return result;
|
|
1900
2278
|
}
|
|
1901
2279
|
|
|
1902
2280
|
// src/commands/generate.ts
|
|
1903
|
-
import
|
|
1904
|
-
import
|
|
2281
|
+
import fs6 from "fs/promises";
|
|
2282
|
+
import path6 from "path";
|
|
1905
2283
|
import chalk4 from "chalk";
|
|
1906
2284
|
async function generateCommand(targetPath, options) {
|
|
1907
|
-
let scanResult;
|
|
2285
|
+
let scanResult = null;
|
|
2286
|
+
let components;
|
|
2287
|
+
let css;
|
|
1908
2288
|
try {
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
2289
|
+
if (options.fromReport) {
|
|
2290
|
+
const loadedReport = await loadExtractableCombinations(options.fromReport, {
|
|
2291
|
+
extractableOnly: options.extractableOnly ?? true
|
|
2292
|
+
});
|
|
2293
|
+
const built = buildComponentsFromCombinations(loadedReport.combinations, {
|
|
2294
|
+
sourcePath: loadedReport.targetPath || targetPath,
|
|
2295
|
+
prefix: options.prefix,
|
|
2296
|
+
names: options.names
|
|
2297
|
+
});
|
|
2298
|
+
components = built.components;
|
|
2299
|
+
css = built.css;
|
|
2300
|
+
} else {
|
|
2301
|
+
scanResult = await scanProject({
|
|
2302
|
+
targetPath,
|
|
2303
|
+
include: options.include,
|
|
2304
|
+
exclude: options.exclude,
|
|
2305
|
+
extractableMinOccurrences: options.minOccurrences ?? 3
|
|
2306
|
+
});
|
|
2307
|
+
if (options.extractableOnly) {
|
|
2308
|
+
const combinations = scanResult.report.stats.topCombinations.filter(
|
|
2309
|
+
(combo) => combo.extractable
|
|
2310
|
+
);
|
|
2311
|
+
const built = buildComponentsFromCombinations(combinations, {
|
|
2312
|
+
sourcePath: scanResult.resolvedPath,
|
|
2313
|
+
prefix: options.prefix,
|
|
2314
|
+
names: options.names
|
|
2315
|
+
});
|
|
2316
|
+
components = built.components;
|
|
2317
|
+
css = built.css;
|
|
2318
|
+
} else {
|
|
2319
|
+
const built = buildComponents(scanResult.occurrences, {
|
|
2320
|
+
sourcePath: scanResult.resolvedPath,
|
|
2321
|
+
minOccurrences: options.minOccurrences ?? 3,
|
|
2322
|
+
minSize: options.minSize,
|
|
2323
|
+
maxSize: options.maxSize,
|
|
2324
|
+
topLimit: options.top,
|
|
2325
|
+
prefix: options.prefix,
|
|
2326
|
+
names: options.names
|
|
2327
|
+
});
|
|
2328
|
+
components = built.components;
|
|
2329
|
+
css = built.css;
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
1914
2332
|
} catch (error) {
|
|
1915
2333
|
const message = error instanceof Error ? error.message : String(error);
|
|
1916
2334
|
console.error(chalk4.red(`Error: ${message}`));
|
|
1917
2335
|
process.exit(1);
|
|
1918
2336
|
}
|
|
1919
|
-
|
|
1920
|
-
|
|
2337
|
+
if (scanResult) {
|
|
2338
|
+
for (const warning of scanResult.warnings) {
|
|
2339
|
+
if (options.format !== "json") {
|
|
2340
|
+
console.warn(chalk4.yellow(`\u26A0 ${warning}`));
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
const outputPath = path6.resolve(options.output);
|
|
2345
|
+
await fs6.mkdir(path6.dirname(outputPath), { recursive: true });
|
|
2346
|
+
await fs6.writeFile(outputPath, css, "utf-8");
|
|
2347
|
+
const result = {
|
|
2348
|
+
outputPath,
|
|
2349
|
+
componentsGenerated: components.length,
|
|
2350
|
+
components,
|
|
2351
|
+
report: scanResult?.report ?? null
|
|
2352
|
+
};
|
|
2353
|
+
if (options.format === "json") {
|
|
2354
|
+
printGenerateJsonReport({
|
|
2355
|
+
command: "generate",
|
|
2356
|
+
outputPath,
|
|
2357
|
+
componentsGenerated: components.length,
|
|
2358
|
+
components,
|
|
2359
|
+
cssWritten: true
|
|
2360
|
+
});
|
|
2361
|
+
return result;
|
|
1921
2362
|
}
|
|
1922
|
-
const { css, components } = buildComponents(scanResult.occurrences, {
|
|
1923
|
-
sourcePath: scanResult.resolvedPath,
|
|
1924
|
-
minOccurrences: options.minOccurrences ?? 3,
|
|
1925
|
-
minSize: options.minSize,
|
|
1926
|
-
maxSize: options.maxSize,
|
|
1927
|
-
topLimit: options.top,
|
|
1928
|
-
prefix: options.prefix,
|
|
1929
|
-
names: options.names
|
|
1930
|
-
});
|
|
1931
|
-
const outputPath = path5.resolve(options.output);
|
|
1932
|
-
await fs5.mkdir(path5.dirname(outputPath), { recursive: true });
|
|
1933
|
-
await fs5.writeFile(outputPath, css, "utf-8");
|
|
1934
2363
|
console.log("");
|
|
1935
2364
|
console.log(chalk4.bold.green("\u2705 CSS generated successfully"));
|
|
1936
2365
|
console.log(chalk4.gray(` Output: `) + chalk4.white(outputPath));
|
|
@@ -1959,11 +2388,7 @@ async function generateCommand(targetPath, options) {
|
|
|
1959
2388
|
);
|
|
1960
2389
|
}
|
|
1961
2390
|
console.log("");
|
|
1962
|
-
return
|
|
1963
|
-
outputPath,
|
|
1964
|
-
componentsGenerated: components.length,
|
|
1965
|
-
report: scanResult.report
|
|
1966
|
-
};
|
|
2391
|
+
return result;
|
|
1967
2392
|
}
|
|
1968
2393
|
|
|
1969
2394
|
export {
|
|
@@ -1979,6 +2404,10 @@ export {
|
|
|
1979
2404
|
findFrequentPatterns,
|
|
1980
2405
|
findRepeatedClassSets,
|
|
1981
2406
|
calculatePotentialReduction,
|
|
2407
|
+
VARIANT_CALLEES,
|
|
2408
|
+
isVariantCallee,
|
|
2409
|
+
extractClassesFromVariantCall,
|
|
2410
|
+
collectVariantRegistry,
|
|
1982
2411
|
CLASS_MERGE_CALLEES,
|
|
1983
2412
|
extractClassesFromExpression,
|
|
1984
2413
|
isClassAttribute,
|
|
@@ -1993,6 +2422,8 @@ export {
|
|
|
1993
2422
|
printConsoleReport,
|
|
1994
2423
|
printJsonReport,
|
|
1995
2424
|
analyzeCommand,
|
|
2425
|
+
formatSource,
|
|
2426
|
+
formatModifiedFiles,
|
|
1996
2427
|
replaceClassNamesInSource,
|
|
1997
2428
|
DEFAULT_CLASS_PREFIX,
|
|
1998
2429
|
normalizeClassPrefix,
|
|
@@ -2000,7 +2431,11 @@ export {
|
|
|
2000
2431
|
assignComponentClassNames,
|
|
2001
2432
|
generateComponentCss,
|
|
2002
2433
|
buildComponents,
|
|
2434
|
+
buildComponentsFromCombinations,
|
|
2435
|
+
loadExtractableCombinations,
|
|
2436
|
+
printGenerateJsonReport,
|
|
2437
|
+
printApplyJsonReport,
|
|
2003
2438
|
applyCommand,
|
|
2004
2439
|
generateCommand
|
|
2005
2440
|
};
|
|
2006
|
-
//# sourceMappingURL=chunk-
|
|
2441
|
+
//# sourceMappingURL=chunk-4GXMK3NB.js.map
|