styled-components-to-stylex-codemod 0.0.38 → 0.0.39
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/{bridge-consumer-patcher-BzAIO9pC.mjs → bridge-consumer-patcher-31jI1854.mjs} +146 -1
- package/dist/{forwarded-as-consumer-patcher-Cs0X-olz.mjs → forwarded-as-consumer-patcher-BYCrqzRm.mjs} +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +5 -4
- package/dist/prop-usage-D6ZiDfzz.mjs +136 -0
- package/dist/{run-prepass-Us5SBTib.mjs → run-prepass-qEr_Mc3y.mjs} +172 -20
- package/dist/{string-utils-KggM5TNH.mjs → string-utils-DD9wdRHW.mjs} +16 -1
- package/dist/{transform-types--9qCqNSJ.d.mts → transform-types-DJpFQ5xm.d.mts} +16 -1
- package/dist/transform.d.mts +1 -1
- package/dist/transform.mjs +879 -346
- package/dist/{transient-prop-consumer-patcher-DLsKxg1R.mjs → transient-prop-consumer-patcher-DdIYPSFk.mjs} +1 -1
- package/package.json +4 -4
- package/dist/styled-css-BVR82jN5.mjs +0 -72
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as toRealPath } from "./path-utils-BIpoL4Ue.mjs";
|
|
2
|
-
import { r as escapeRegex } from "./string-utils-
|
|
2
|
+
import { r as escapeRegex } from "./string-utils-DD9wdRHW.mjs";
|
|
3
3
|
import { t as isSelectorContext } from "./selector-context-heuristic-6_jSRGkZ.mjs";
|
|
4
4
|
import { readFileSync } from "node:fs";
|
|
5
5
|
//#region src/internal/bridge-consumer-patcher.ts
|
|
@@ -102,6 +102,7 @@ function patchConsumerFile(filePath, replacements) {
|
|
|
102
102
|
return match;
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
|
+
modified = removeNowUnusedComponentImports(modified, replacements);
|
|
105
106
|
return modified !== source ? modified : null;
|
|
106
107
|
}
|
|
107
108
|
/** Find the end position of an import statement starting at startIdx (handles multi-line imports). */
|
|
@@ -119,5 +120,149 @@ function isInStyledTemplateSelectorContext(source, offset, length) {
|
|
|
119
120
|
function hasExactImportName(importSpecifiers, name) {
|
|
120
121
|
return new RegExp(`(?:^|[^A-Za-z0-9_$])${escapeRegex(name)}(?:$|[^A-Za-z0-9_$])`).test(importSpecifiers);
|
|
121
122
|
}
|
|
123
|
+
function removeNowUnusedComponentImports(source, replacements) {
|
|
124
|
+
let modified = source;
|
|
125
|
+
for (const replacement of replacements) {
|
|
126
|
+
if (hasIdentifierUsageOutsideImports(modified, replacement.localName)) continue;
|
|
127
|
+
modified = removeNamedImportSpecifier(modified, replacement.importSource, replacement.localName);
|
|
128
|
+
}
|
|
129
|
+
return modified;
|
|
130
|
+
}
|
|
131
|
+
function hasIdentifierUsageOutsideImports(source, name) {
|
|
132
|
+
const withoutImports = stripImportDeclarations(stripComments(source));
|
|
133
|
+
return new RegExp(`(^|[^A-Za-z0-9_$])${escapeRegex(name)}($|[^A-Za-z0-9_$])`).test(withoutImports);
|
|
134
|
+
}
|
|
135
|
+
function stripImportDeclarations(source) {
|
|
136
|
+
const lines = source.split(/(?<=\n)/);
|
|
137
|
+
let result = "";
|
|
138
|
+
let inImport = false;
|
|
139
|
+
let nestingDepth = 0;
|
|
140
|
+
for (const line of lines) {
|
|
141
|
+
if (!inImport && !isImportDeclarationStart(line)) {
|
|
142
|
+
result += line;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
inImport = true;
|
|
146
|
+
nestingDepth += getImportNestingDelta(line);
|
|
147
|
+
if (nestingDepth <= 0 && isImportDeclarationEnd(line)) {
|
|
148
|
+
inImport = false;
|
|
149
|
+
nestingDepth = 0;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
function isImportDeclarationStart(line) {
|
|
155
|
+
const match = line.match(/^[ \t]*import\b/);
|
|
156
|
+
if (!match) return false;
|
|
157
|
+
const next = line.slice(match[0].length).trimStart()[0];
|
|
158
|
+
return next !== "(" && next !== ".";
|
|
159
|
+
}
|
|
160
|
+
function isImportDeclarationEnd(line) {
|
|
161
|
+
const trimmed = line.trim();
|
|
162
|
+
return trimmed.endsWith(";") || /^import\s+["'][^"']+["']$/.test(trimmed) || /\bfrom\s+["'][^"']+["'](?:\s+with\s+\{[^}]*\})?$/.test(trimmed);
|
|
163
|
+
}
|
|
164
|
+
function getImportNestingDelta(line) {
|
|
165
|
+
let depth = 0;
|
|
166
|
+
let quote = null;
|
|
167
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
168
|
+
const char = line[index];
|
|
169
|
+
if (quote) {
|
|
170
|
+
if (char === "\\") index += 1;
|
|
171
|
+
else if (char === quote) quote = null;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (char === "'" || char === "\"") quote = char;
|
|
175
|
+
else if (char === "{" || char === "(" || char === "[") depth += 1;
|
|
176
|
+
else if (char === "}" || char === ")" || char === "]") depth -= 1;
|
|
177
|
+
}
|
|
178
|
+
return depth;
|
|
179
|
+
}
|
|
180
|
+
function stripComments(source) {
|
|
181
|
+
let result = "";
|
|
182
|
+
let state = "normal";
|
|
183
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
184
|
+
const char = source[index] ?? "";
|
|
185
|
+
const next = source[index + 1] ?? "";
|
|
186
|
+
if (state === "lineComment") {
|
|
187
|
+
if (char === "\n") {
|
|
188
|
+
result += char;
|
|
189
|
+
state = "normal";
|
|
190
|
+
} else result += " ";
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (state === "blockComment") {
|
|
194
|
+
if (char === "*" && next === "/") {
|
|
195
|
+
result += " ";
|
|
196
|
+
index += 1;
|
|
197
|
+
state = "normal";
|
|
198
|
+
} else result += char === "\n" ? "\n" : " ";
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (state === "template") {
|
|
202
|
+
if (char === "/" && next === "/") {
|
|
203
|
+
result += " ";
|
|
204
|
+
index += 1;
|
|
205
|
+
state = "lineComment";
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (char === "/" && next === "*") {
|
|
209
|
+
result += " ";
|
|
210
|
+
index += 1;
|
|
211
|
+
state = "blockComment";
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
result += char;
|
|
215
|
+
if (char === "\\") {
|
|
216
|
+
result += next;
|
|
217
|
+
index += 1;
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (char === "`") state = "normal";
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (state === "singleQuote" || state === "doubleQuote") {
|
|
224
|
+
result += char;
|
|
225
|
+
if (char === "\\") {
|
|
226
|
+
result += next;
|
|
227
|
+
index += 1;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (state === "singleQuote" && char === "'" || state === "doubleQuote" && char === "\"") state = "normal";
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (char === "/" && next === "/") {
|
|
234
|
+
result += " ";
|
|
235
|
+
index += 1;
|
|
236
|
+
state = "lineComment";
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (char === "/" && next === "*") {
|
|
240
|
+
result += " ";
|
|
241
|
+
index += 1;
|
|
242
|
+
state = "blockComment";
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (char === "'") state = "singleQuote";
|
|
246
|
+
else if (char === "\"") state = "doubleQuote";
|
|
247
|
+
else if (char === "`") state = "template";
|
|
248
|
+
result += char;
|
|
249
|
+
}
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
function removeNamedImportSpecifier(source, importSource, localName) {
|
|
253
|
+
const namedImportRegex = new RegExp(`import\\s+([\\w$]+\\s*,\\s*)?\\{([^}]*)\\}\\s+from\\s+(['"]${escapeRegex(importSource)}['"]\\s*;?)`, "g");
|
|
254
|
+
return source.replace(namedImportRegex, (_match, defaultPart, specifierList, fromClause) => {
|
|
255
|
+
const remainingSpecifiers = String(specifierList).split(",").map((specifier) => specifier.trim()).filter(Boolean).filter((specifier) => getImportedSpecifierLocalName(specifier) !== localName);
|
|
256
|
+
if (remainingSpecifiers.length > 0) return `import ${defaultPart ?? ""}{ ${remainingSpecifiers.join(", ")} } from ${fromClause}`;
|
|
257
|
+
const defaultName = String(defaultPart ?? "").replace(/,\s*$/, "").trim();
|
|
258
|
+
if (defaultName) return `import ${defaultName} from ${fromClause}`;
|
|
259
|
+
return "";
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
function getImportedSpecifierLocalName(specifier) {
|
|
263
|
+
const aliasMatch = specifier.match(/\bas\s+([A-Za-z_$][\w$]*)$/);
|
|
264
|
+
if (aliasMatch?.[1]) return aliasMatch[1];
|
|
265
|
+
return specifier.trim();
|
|
266
|
+
}
|
|
122
267
|
//#endregion
|
|
123
268
|
export { buildConsumerReplacements, patchConsumerFile };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as toRealPath } from "./path-utils-BIpoL4Ue.mjs";
|
|
2
|
-
import { r as escapeRegex } from "./string-utils-
|
|
2
|
+
import { r as escapeRegex } from "./string-utils-DD9wdRHW.mjs";
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
//#region src/internal/forwarded-as-consumer-patcher.ts
|
|
5
5
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CollectedWarning, c as MarkerFileContext, l as defineAdapter, n as TransformMode, o as AdapterInput, s as ImportSource } from "./transform-types
|
|
1
|
+
import { a as CollectedWarning, c as MarkerFileContext, l as defineAdapter, n as TransformMode, o as AdapterInput, s as ImportSource } from "./transform-types-DJpFQ5xm.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/run.d.ts
|
|
4
4
|
interface RunTransformOptions {
|
package/dist/index.mjs
CHANGED
|
@@ -149,7 +149,7 @@ async function runTransform(options) {
|
|
|
149
149
|
const { createModuleResolver } = await import("./resolve-imports-BlxKezSJ.mjs").then((n) => n.n);
|
|
150
150
|
const sharedResolver = createModuleResolver();
|
|
151
151
|
filePaths = orderFilesByLocalImportDependencies(filePaths, sharedResolver, toRealPath);
|
|
152
|
-
const { runPrepass } = await import("./run-prepass-
|
|
152
|
+
const { runPrepass } = await import("./run-prepass-qEr_Mc3y.mjs");
|
|
153
153
|
const absoluteFiles = filePaths.map((f) => resolve(f));
|
|
154
154
|
const absoluteConsumers = consumerFilePaths.map((f) => resolve(f));
|
|
155
155
|
let prepassResult;
|
|
@@ -172,6 +172,7 @@ async function runTransform(options) {
|
|
|
172
172
|
selectorUsages: /* @__PURE__ */ new Map(),
|
|
173
173
|
componentsNeedingMarkerSidecar: /* @__PURE__ */ new Map(),
|
|
174
174
|
componentsNeedingGlobalSelectorBridge: /* @__PURE__ */ new Map(),
|
|
175
|
+
propUsageByFile: /* @__PURE__ */ new Map(),
|
|
175
176
|
globalLeafKeys: leavesOnly ? /* @__PURE__ */ new Set() : void 0
|
|
176
177
|
},
|
|
177
178
|
consumerAnalysis: void 0,
|
|
@@ -308,7 +309,7 @@ async function runTransform(options) {
|
|
|
308
309
|
const result = await runTransformSequentially(transformModule, filePaths, runnerOptions);
|
|
309
310
|
if (sidecarFiles.size > 0 && !dryRun) for (const [sidecarPath, content] of sidecarFiles) await writeFile(sidecarPath, mergeSidecarContent(sidecarPath, content), "utf-8");
|
|
310
311
|
if (bridgeResults.size > 0 && !dryRun) {
|
|
311
|
-
const { buildConsumerReplacements, patchConsumerFile } = await import("./bridge-consumer-patcher-
|
|
312
|
+
const { buildConsumerReplacements, patchConsumerFile } = await import("./bridge-consumer-patcher-31jI1854.mjs");
|
|
312
313
|
const consumerReplacements = buildConsumerReplacements(crossFilePrepassResult.selectorUsages, bridgeResults, transformedFiles);
|
|
313
314
|
const patchedFiles = [];
|
|
314
315
|
for (const [consumerPath, replacements] of consumerReplacements) {
|
|
@@ -321,7 +322,7 @@ async function runTransform(options) {
|
|
|
321
322
|
if (formatterCommands && patchedFiles.length > 0) await runFormatters(formatterCommands, patchedFiles);
|
|
322
323
|
}
|
|
323
324
|
if (prepassResult.forwardedAsConsumers.size > 0 && !dryRun) {
|
|
324
|
-
const { buildForwardedAsReplacements, patchConsumerForwardedAs } = await import("./forwarded-as-consumer-patcher-
|
|
325
|
+
const { buildForwardedAsReplacements, patchConsumerForwardedAs } = await import("./forwarded-as-consumer-patcher-BYCrqzRm.mjs");
|
|
325
326
|
const forwardedAsReplacements = buildForwardedAsReplacements(prepassResult.forwardedAsConsumers, transformedFiles);
|
|
326
327
|
const patchedFiles = [];
|
|
327
328
|
for (const [consumerPath, entries] of forwardedAsReplacements) {
|
|
@@ -334,7 +335,7 @@ async function runTransform(options) {
|
|
|
334
335
|
if (formatterCommands && patchedFiles.length > 0) await runFormatters(formatterCommands, patchedFiles);
|
|
335
336
|
}
|
|
336
337
|
if (transientPropRenames.size > 0 && !dryRun) {
|
|
337
|
-
const { collectTransientPropPatches } = await import("./transient-prop-consumer-patcher-
|
|
338
|
+
const { collectTransientPropPatches } = await import("./transient-prop-consumer-patcher-DdIYPSFk.mjs");
|
|
338
339
|
const patches = collectTransientPropPatches({
|
|
339
340
|
transientPropRenames,
|
|
340
341
|
consumerFilePaths: consumerFilePaths.map((p) => resolve(p)),
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { compile } from "stylis";
|
|
2
|
+
//#region src/internal/styled-css.ts
|
|
3
|
+
/** Matches `__SC_EXPR_N__` and captures the slot index in group 1. */
|
|
4
|
+
const PLACEHOLDER_RE = /__SC_EXPR_(\d+)__/;
|
|
5
|
+
function parseStyledTemplateLiteral(template) {
|
|
6
|
+
const parts = [];
|
|
7
|
+
const slots = [];
|
|
8
|
+
for (let i = 0; i < template.quasis.length; i++) {
|
|
9
|
+
const quasi = template.quasis[i];
|
|
10
|
+
parts.push(quasi.value.raw);
|
|
11
|
+
const expr = template.expressions[i];
|
|
12
|
+
if (!expr) continue;
|
|
13
|
+
const placeholder = makeInterpolationPlaceholder(i);
|
|
14
|
+
const startOffset = parts.join("").length;
|
|
15
|
+
parts.push(placeholder);
|
|
16
|
+
const endOffset = parts.join("").length;
|
|
17
|
+
slots.push({
|
|
18
|
+
index: i,
|
|
19
|
+
placeholder,
|
|
20
|
+
expression: expr,
|
|
21
|
+
startOffset,
|
|
22
|
+
endOffset
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
const rawCss = parts.join("");
|
|
26
|
+
return {
|
|
27
|
+
rawCss,
|
|
28
|
+
slots,
|
|
29
|
+
stylisAst: compile(terminateStandaloneInterpolationStatements(rawCss))
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function terminateStandaloneInterpolationStatements(css) {
|
|
33
|
+
let parenDepth = 0;
|
|
34
|
+
const lines = css.split(/(?<=\n)/);
|
|
35
|
+
const depthsBeforeLine = [];
|
|
36
|
+
for (const line of lines) {
|
|
37
|
+
depthsBeforeLine.push(parenDepth);
|
|
38
|
+
parenDepth = updateParenDepth(parenDepth, line);
|
|
39
|
+
}
|
|
40
|
+
return lines.map((line, index) => {
|
|
41
|
+
return depthsBeforeLine[index] === 0 && /^\s*__SC_EXPR_\d+__\s*$/.test(line) && isBeforeAtRule(lines, index) ? line.replace(/(\s*)$/, ";$1") : line;
|
|
42
|
+
}).join("");
|
|
43
|
+
}
|
|
44
|
+
function makeInterpolationPlaceholder(index) {
|
|
45
|
+
return `__SC_EXPR_${index}__`;
|
|
46
|
+
}
|
|
47
|
+
function isBeforeAtRule(lines, startIndex) {
|
|
48
|
+
for (let i = startIndex + 1; i < lines.length; i++) {
|
|
49
|
+
const trimmed = lines[i].trim();
|
|
50
|
+
if (!trimmed || /^__SC_EXPR_\d+__\s*;?$/.test(trimmed)) continue;
|
|
51
|
+
return trimmed.startsWith("@");
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
function updateParenDepth(startDepth, line) {
|
|
56
|
+
let depth = startDepth;
|
|
57
|
+
let inString = false;
|
|
58
|
+
for (let i = 0; i < line.length; i++) {
|
|
59
|
+
const ch = line[i];
|
|
60
|
+
if ((ch === "\"" || ch === "'") && line[i - 1] !== "\\") {
|
|
61
|
+
if (!inString) inString = ch;
|
|
62
|
+
else if (inString === ch) inString = false;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (inString) continue;
|
|
66
|
+
if (ch === "(") depth++;
|
|
67
|
+
else if (ch === ")") depth = Math.max(0, depth - 1);
|
|
68
|
+
}
|
|
69
|
+
return depth;
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/internal/utilities/jsx-static-literal.ts
|
|
73
|
+
function readStaticJsxLiteral(attr) {
|
|
74
|
+
if (!isObjectRecord(attr) || attr.type !== "JSXAttribute") return;
|
|
75
|
+
if (!("value" in attr) || attr.value == null) return true;
|
|
76
|
+
const directLiteral = readLiteralNodeValue(attr.value);
|
|
77
|
+
if (directLiteral !== void 0) return directLiteral;
|
|
78
|
+
if (!isObjectRecord(attr.value) || attr.value.type !== "JSXExpressionContainer") return;
|
|
79
|
+
return readLiteralNodeValue(attr.value.expression);
|
|
80
|
+
}
|
|
81
|
+
function readLiteralNodeValue(node) {
|
|
82
|
+
if (!isObjectRecord(node)) return;
|
|
83
|
+
if (node.type === "StringLiteral" || node.type === "NumericLiteral" || node.type === "BooleanLiteral") return isStaticLiteral(node.value) ? node.value : void 0;
|
|
84
|
+
if (node.type === "Literal") return isStaticLiteral(node.value) ? node.value : void 0;
|
|
85
|
+
if (node.type === "UnaryExpression" && node.operator === "-") {
|
|
86
|
+
const value = readLiteralNodeValue(node.argument);
|
|
87
|
+
return typeof value === "number" ? -value : void 0;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function isObjectRecord(value) {
|
|
91
|
+
return typeof value === "object" && value !== null;
|
|
92
|
+
}
|
|
93
|
+
function isStaticLiteral(value) {
|
|
94
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/internal/utilities/prop-usage.ts
|
|
98
|
+
const KNOWN_NON_ELEMENT_PROPS = new Set([
|
|
99
|
+
"className",
|
|
100
|
+
"style",
|
|
101
|
+
"as",
|
|
102
|
+
"ref",
|
|
103
|
+
"forwardedAs",
|
|
104
|
+
"key",
|
|
105
|
+
"children"
|
|
106
|
+
]);
|
|
107
|
+
function createComponentPropUsageInfo(name) {
|
|
108
|
+
return {
|
|
109
|
+
componentName: name,
|
|
110
|
+
usageCount: 0,
|
|
111
|
+
hasUnknownUsage: false,
|
|
112
|
+
props: {}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function mergeComponentPropUsage(info, usage) {
|
|
116
|
+
info.usageCount += 1;
|
|
117
|
+
if (usage.hasSpread) info.hasUnknownUsage = true;
|
|
118
|
+
const presentProps = new Set(Object.keys(usage.props));
|
|
119
|
+
for (const [propName, propInfo] of Object.entries(info.props)) if (!presentProps.has(propName)) propInfo.omittedCount += 1;
|
|
120
|
+
for (const [propName, value] of Object.entries(usage.props)) {
|
|
121
|
+
const propInfo = info.props[propName] ?? (info.props[propName] = {
|
|
122
|
+
values: [],
|
|
123
|
+
hasUnknown: false,
|
|
124
|
+
usageCount: 0,
|
|
125
|
+
omittedCount: info.usageCount - 1
|
|
126
|
+
});
|
|
127
|
+
propInfo.usageCount += 1;
|
|
128
|
+
if (value.kind === "unknown") {
|
|
129
|
+
propInfo.hasUnknown = true;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (!propInfo.values.some((existing) => existing === value.value)) propInfo.values.push(value.value);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { PLACEHOLDER_RE as a, readStaticJsxLiteral as i, createComponentPropUsageInfo as n, parseStyledTemplateLiteral as o, mergeComponentPropUsage as r, terminateStandaloneInterpolationStatements as s, KNOWN_NON_ELEMENT_PROPS as t };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as Logger, i as resolveBarrelReExport, n as fileImportsFrom, r as findImportSource, t as fileExports } from "./extract-external-interface-CdHbvfxu.mjs";
|
|
2
2
|
import { n as extractStyledDefBasesFromAstProgram, r as extractStyledDefBasesFromSource, t as computeGlobalLeafKeys } from "./compute-leaf-set-Drcu2eju.mjs";
|
|
3
|
-
import { r as escapeRegex } from "./string-utils-
|
|
4
|
-
import {
|
|
3
|
+
import { r as escapeRegex } from "./string-utils-DD9wdRHW.mjs";
|
|
4
|
+
import { a as PLACEHOLDER_RE, i as readStaticJsxLiteral, n as createComponentPropUsageInfo, r as mergeComponentPropUsage, t as KNOWN_NON_ELEMENT_PROPS } from "./prop-usage-D6ZiDfzz.mjs";
|
|
5
5
|
import { t as isSelectorContext } from "./selector-context-heuristic-6_jSRGkZ.mjs";
|
|
6
6
|
import { relative, resolve } from "node:path";
|
|
7
7
|
import { readFileSync, realpathSync } from "node:fs";
|
|
@@ -457,6 +457,7 @@ async function runPrepass(options) {
|
|
|
457
457
|
const styleUsages = /* @__PURE__ */ new Map();
|
|
458
458
|
const elementPropUsages = /* @__PURE__ */ new Map();
|
|
459
459
|
const spreadPropUsages = /* @__PURE__ */ new Map();
|
|
460
|
+
const propUsageCandidates = /* @__PURE__ */ new Map();
|
|
460
461
|
const styledWrapperUsages = [];
|
|
461
462
|
const fileContents = /* @__PURE__ */ new Map();
|
|
462
463
|
const cachedRead = (filePath) => {
|
|
@@ -491,14 +492,16 @@ async function runPrepass(options) {
|
|
|
491
492
|
categorizeSelectorUsages(usages, componentsNeedingMarkerSidecar, componentsNeedingGlobalSelectorBridge);
|
|
492
493
|
}
|
|
493
494
|
}
|
|
495
|
+
if (hasStyled) {
|
|
496
|
+
STYLED_DEF_RE.lastIndex = 0;
|
|
497
|
+
for (const m of source.matchAll(STYLED_DEF_RE)) if (m[1]) addToSetMap(styledDefFiles, filePath, m[1]);
|
|
498
|
+
}
|
|
494
499
|
if (createExternalInterface && hasStyled) {
|
|
495
500
|
STYLED_CALL_RE.lastIndex = 0;
|
|
496
501
|
for (const m of source.matchAll(STYLED_CALL_RE)) if (m[1]) styledCallUsages.push({
|
|
497
502
|
file: filePath,
|
|
498
503
|
name: m[1]
|
|
499
504
|
});
|
|
500
|
-
STYLED_DEF_RE.lastIndex = 0;
|
|
501
|
-
for (const m of source.matchAll(STYLED_DEF_RE)) if (m[1]) addToSetMap(styledDefFiles, filePath, m[1]);
|
|
502
505
|
STYLED_COMPONENT_WRAPPER_RE.lastIndex = 0;
|
|
503
506
|
for (const m of source.matchAll(STYLED_COMPONENT_WRAPPER_RE)) if (m[1] && m[2]) styledWrapperUsages.push({
|
|
504
507
|
file: filePath,
|
|
@@ -523,22 +526,37 @@ async function runPrepass(options) {
|
|
|
523
526
|
}
|
|
524
527
|
}
|
|
525
528
|
const styledFileCount = fileContents.size;
|
|
526
|
-
if (
|
|
529
|
+
if (styledDefFiles.size > 0) {
|
|
527
530
|
const allStyledNames = /* @__PURE__ */ new Set();
|
|
528
531
|
for (const names of styledDefFiles.values()) for (const name of names) allStyledNames.add(name);
|
|
529
532
|
if (allStyledNames.size > 0) {
|
|
530
|
-
const rgHits = rgClassNameStyleFilter(uniqueAllFiles);
|
|
533
|
+
const rgHits = createExternalInterface ? rgClassNameStyleFilter(uniqueAllFiles) : void 0;
|
|
534
|
+
const jsxHits = rgJsxComponentFilter(uniqueAllFiles);
|
|
531
535
|
const scanAndRecord = (filePath, source) => {
|
|
532
|
-
for (const result of scanConsumerProps(source, allStyledNames)) {
|
|
536
|
+
if (createExternalInterface) for (const result of scanConsumerProps(source, allStyledNames)) {
|
|
533
537
|
addToSetMap(classNameStyleUsages, result.name, filePath);
|
|
534
538
|
if (result.className) addToSetMap(classNameUsages, result.name, filePath);
|
|
535
539
|
if (result.style) addToSetMap(styleUsages, result.name, filePath);
|
|
536
540
|
if (result.elementProps) addToSetMap(elementPropUsages, result.name, filePath);
|
|
537
541
|
if (result.spreadProps) addToSetMap(spreadPropUsages, result.name, filePath);
|
|
538
542
|
}
|
|
543
|
+
for (const usage of scanConsumerStaticPropUsages(filePath, source, allStyledNames, parser)) {
|
|
544
|
+
const entries = propUsageCandidates.get(usage.name) ?? [];
|
|
545
|
+
entries.push(usage);
|
|
546
|
+
propUsageCandidates.set(usage.name, entries);
|
|
547
|
+
}
|
|
539
548
|
};
|
|
540
|
-
for (const [filePath, source] of fileContents)
|
|
541
|
-
|
|
549
|
+
for (const [filePath, source] of fileContents) {
|
|
550
|
+
if (jsxHits && !jsxHits.has(filePath) && (!createExternalInterface || !rgHits?.has(filePath))) continue;
|
|
551
|
+
scanAndRecord(filePath, source);
|
|
552
|
+
}
|
|
553
|
+
const filesToScan = (() => {
|
|
554
|
+
const hits = /* @__PURE__ */ new Set();
|
|
555
|
+
const hasAnyFilter = createExternalInterface && rgHits !== void 0 || jsxHits !== void 0;
|
|
556
|
+
if (createExternalInterface && rgHits) for (const f of rgHits) hits.add(f);
|
|
557
|
+
if (jsxHits) for (const f of jsxHits) hits.add(f);
|
|
558
|
+
return hasAnyFilter ? [...hits].filter((f) => allFilesSet.has(f) && !fileContents.has(f)) : uniqueAllFiles.filter((f) => !fileContents.has(f));
|
|
559
|
+
})();
|
|
542
560
|
for (const filePath of filesToScan) {
|
|
543
561
|
const source = cachedRead(filePath);
|
|
544
562
|
if (!source) continue;
|
|
@@ -640,6 +658,13 @@ async function runPrepass(options) {
|
|
|
640
658
|
targetPath: defFile
|
|
641
659
|
});
|
|
642
660
|
}
|
|
661
|
+
const propUsageByFile = buildPropUsageByFile({
|
|
662
|
+
styledDefFiles,
|
|
663
|
+
propUsageCandidates,
|
|
664
|
+
cachedRead,
|
|
665
|
+
resolve: resolve$1,
|
|
666
|
+
toRealPath
|
|
667
|
+
});
|
|
643
668
|
let globalLeafKeys;
|
|
644
669
|
if (leavesOnly) {
|
|
645
670
|
const styledDefBases = /* @__PURE__ */ new Map();
|
|
@@ -657,6 +682,7 @@ async function runPrepass(options) {
|
|
|
657
682
|
selectorUsages,
|
|
658
683
|
componentsNeedingMarkerSidecar,
|
|
659
684
|
componentsNeedingGlobalSelectorBridge,
|
|
685
|
+
propUsageByFile,
|
|
660
686
|
styledDefFiles: createExternalInterface ? styledDefFiles : void 0,
|
|
661
687
|
globalLeafKeys
|
|
662
688
|
};
|
|
@@ -665,7 +691,10 @@ async function runPrepass(options) {
|
|
|
665
691
|
const reStyled = consumerAnalysis ? [...consumerAnalysis.values()].filter((v) => v.styles).length : 0;
|
|
666
692
|
const asProp = consumerAnalysis ? [...consumerAnalysis.values()].filter((v) => v.as).length : 0;
|
|
667
693
|
const refProp = consumerAnalysis ? [...consumerAnalysis.values()].filter((v) => v.ref).length : 0;
|
|
668
|
-
|
|
694
|
+
const propUsageCount = [...propUsageByFile.values()].reduce((sum, byComponent) => {
|
|
695
|
+
return sum + byComponent.size;
|
|
696
|
+
}, 0);
|
|
697
|
+
Logger.info(`Prepass: scanned ${uniqueAllFiles.length} files in ${elapsed}s — ${styledFileCount} with styled-components, ${selectorUsages.size} cross-file selectors, ${reStyled} re-styled, ${asProp} as-prop, ${refProp} ref-prop, ${classNameStyleUsages.size} className/style, ${propUsageCount} prop-usage, ${forwardedAsConsumers.size} forwardedAs\n`);
|
|
669
698
|
}
|
|
670
699
|
if (process.env.DEBUG_CODEMOD) logPrepassDebug(uniqueAllFiles, crossFileInfo, consumerAnalysis);
|
|
671
700
|
return {
|
|
@@ -751,16 +780,6 @@ function buildLocalToImportedMap(source) {
|
|
|
751
780
|
}
|
|
752
781
|
return map;
|
|
753
782
|
}
|
|
754
|
-
/** Props that don't indicate element-specific usage (non-element props). */
|
|
755
|
-
const KNOWN_NON_ELEMENT_PROPS = new Set([
|
|
756
|
-
"className",
|
|
757
|
-
"style",
|
|
758
|
-
"as",
|
|
759
|
-
"ref",
|
|
760
|
-
"forwardedAs",
|
|
761
|
-
"key",
|
|
762
|
-
"children"
|
|
763
|
-
]);
|
|
764
783
|
/**
|
|
765
784
|
* Scan source for JSX usage of specific components with className, style,
|
|
766
785
|
* element-specific props, or JSX spread.
|
|
@@ -811,6 +830,114 @@ function scanConsumerProps(source, componentNames) {
|
|
|
811
830
|
}
|
|
812
831
|
return [...resultMap.values()];
|
|
813
832
|
}
|
|
833
|
+
function scanConsumerStaticPropUsages(filePath, source, componentNames, parser) {
|
|
834
|
+
if (!/<[A-Z]/.test(source)) return [];
|
|
835
|
+
let ast;
|
|
836
|
+
try {
|
|
837
|
+
ast = parser.parse(source);
|
|
838
|
+
} catch {
|
|
839
|
+
return [];
|
|
840
|
+
}
|
|
841
|
+
const importNodes = [];
|
|
842
|
+
const jsxOpenings = [];
|
|
843
|
+
walkForImportsAndJsxOpenings(ast.program ?? ast, importNodes, jsxOpenings);
|
|
844
|
+
const importMap = buildImportMapFromNodes(importNodes);
|
|
845
|
+
const usages = [];
|
|
846
|
+
for (const opening of jsxOpenings) {
|
|
847
|
+
const tagName = getJsxOpeningIdentifierName(opening.name);
|
|
848
|
+
if (!tagName) continue;
|
|
849
|
+
const importEntry = importMap.get(tagName);
|
|
850
|
+
const resolvedName = componentNames.has(tagName) ? tagName : importEntry && componentNames.has(importEntry.importedName) ? importEntry.importedName : void 0;
|
|
851
|
+
if (!resolvedName) continue;
|
|
852
|
+
const props = {};
|
|
853
|
+
let hasSpread = false;
|
|
854
|
+
for (const attr of opening.attributes ?? []) {
|
|
855
|
+
if (!attr) continue;
|
|
856
|
+
if (attr.type === "JSXSpreadAttribute") {
|
|
857
|
+
hasSpread = true;
|
|
858
|
+
continue;
|
|
859
|
+
}
|
|
860
|
+
if (attr.type !== "JSXAttribute") continue;
|
|
861
|
+
const propName = getJsxAttributeName(attr.name);
|
|
862
|
+
if (!propName || KNOWN_NON_ELEMENT_PROPS.has(propName)) continue;
|
|
863
|
+
const value = readStaticJsxLiteral(attr);
|
|
864
|
+
props[propName] = value === void 0 ? { kind: "unknown" } : {
|
|
865
|
+
kind: "static",
|
|
866
|
+
value
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
usages.push({
|
|
870
|
+
name: resolvedName,
|
|
871
|
+
filePath,
|
|
872
|
+
usage: {
|
|
873
|
+
props,
|
|
874
|
+
hasSpread
|
|
875
|
+
}
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
return usages;
|
|
879
|
+
}
|
|
880
|
+
function buildPropUsageByFile(args) {
|
|
881
|
+
const { styledDefFiles, propUsageCandidates, cachedRead, resolve, toRealPath } = args;
|
|
882
|
+
const propUsageByFile = /* @__PURE__ */ new Map();
|
|
883
|
+
for (const [defFile, names] of styledDefFiles) {
|
|
884
|
+
const defSrc = cachedRead(defFile);
|
|
885
|
+
for (const name of names) {
|
|
886
|
+
const candidates = propUsageCandidates.get(name);
|
|
887
|
+
if (!candidates || !fileExports(defSrc, name)) continue;
|
|
888
|
+
for (const candidate of candidates) {
|
|
889
|
+
const usageFile = candidate.filePath;
|
|
890
|
+
if (usageFile !== defFile && !fileImportsFrom(cachedRead(usageFile), usageFile, name, defFile, resolve)) continue;
|
|
891
|
+
mergeComponentPropUsage(getOrCreateComponentPropUsage(getOrCreatePropUsageFileMap(propUsageByFile, toRealPath(defFile)), name), candidate.usage);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
return propUsageByFile;
|
|
896
|
+
}
|
|
897
|
+
function getOrCreatePropUsageFileMap(propUsageByFile, filePath) {
|
|
898
|
+
let byComponent = propUsageByFile.get(filePath);
|
|
899
|
+
if (!byComponent) {
|
|
900
|
+
byComponent = /* @__PURE__ */ new Map();
|
|
901
|
+
propUsageByFile.set(filePath, byComponent);
|
|
902
|
+
}
|
|
903
|
+
return byComponent;
|
|
904
|
+
}
|
|
905
|
+
function getOrCreateComponentPropUsage(byComponent, name) {
|
|
906
|
+
let info = byComponent.get(name);
|
|
907
|
+
if (!info) {
|
|
908
|
+
info = createComponentPropUsageInfo(name);
|
|
909
|
+
byComponent.set(name, info);
|
|
910
|
+
}
|
|
911
|
+
return info;
|
|
912
|
+
}
|
|
913
|
+
function walkForImportsAndJsxOpenings(node, imports, jsxOpenings) {
|
|
914
|
+
if (!node || typeof node !== "object") return;
|
|
915
|
+
const n = node;
|
|
916
|
+
if (n.type === "ImportDeclaration") {
|
|
917
|
+
imports.push(n);
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
if (n.type === "JSXOpeningElement") {
|
|
921
|
+
jsxOpenings.push(n);
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
for (const key of Object.keys(n)) {
|
|
925
|
+
if (key === "type" || key === "start" || key === "end" || key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
|
|
926
|
+
const val = n[key];
|
|
927
|
+
if (Array.isArray(val)) for (const child of val) walkForImportsAndJsxOpenings(child, imports, jsxOpenings);
|
|
928
|
+
else if (val && typeof val === "object" && val.type) walkForImportsAndJsxOpenings(val, imports, jsxOpenings);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
function getJsxOpeningIdentifierName(name) {
|
|
932
|
+
if (!name) return null;
|
|
933
|
+
if (name.type === "JSXIdentifier" && typeof name.name === "string") return name.name;
|
|
934
|
+
return null;
|
|
935
|
+
}
|
|
936
|
+
function getJsxAttributeName(name) {
|
|
937
|
+
if (!name) return null;
|
|
938
|
+
if (name.type === "JSXIdentifier" && typeof name.name === "string") return name.name;
|
|
939
|
+
return null;
|
|
940
|
+
}
|
|
814
941
|
/**
|
|
815
942
|
* Use ripgrep to find files containing `className` or `style` props.
|
|
816
943
|
* Searches for the prop keywords (not component names) to keep the pattern
|
|
@@ -840,6 +967,31 @@ function rgClassNameStyleFilter(files) {
|
|
|
840
967
|
return;
|
|
841
968
|
}
|
|
842
969
|
}
|
|
970
|
+
/** Use ripgrep to find files with PascalCase JSX tags. */
|
|
971
|
+
function rgJsxComponentFilter(files) {
|
|
972
|
+
const dirs = deduplicateParentDirs(files);
|
|
973
|
+
if (dirs.length === 0) return;
|
|
974
|
+
try {
|
|
975
|
+
const globArgs = [
|
|
976
|
+
"*.tsx",
|
|
977
|
+
"*.jsx",
|
|
978
|
+
"*.ts",
|
|
979
|
+
"*.js",
|
|
980
|
+
"*.mts",
|
|
981
|
+
"*.cts",
|
|
982
|
+
"*.mjs",
|
|
983
|
+
"*.cjs"
|
|
984
|
+
].map((glob) => `--glob ${shellQuote(glob)}`).join(" ");
|
|
985
|
+
const output = execSync(`rg -l ${shellQuote(String.raw`<[A-Z]`)} ${globArgs} ${dirs.map(shellQuote).join(" ")}`, {
|
|
986
|
+
encoding: "utf-8",
|
|
987
|
+
maxBuffer: 10 * 1024 * 1024
|
|
988
|
+
});
|
|
989
|
+
return new Set(output.trim().split("\n").filter(Boolean).map((f) => resolve(f)));
|
|
990
|
+
} catch (err) {
|
|
991
|
+
if (err instanceof Error && "status" in err && err.status === 1) return /* @__PURE__ */ new Set();
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
843
995
|
/** Scan a single file for cross-file selector usages using AST parsing. */
|
|
844
996
|
function scanFileForSelectorsAst(filePath, source, transformSet, resolver, parser, toRealPath, readFile, cache, failOnParseError) {
|
|
845
997
|
const hash = cache ? createHash("md5").update(source).digest("hex") : void 0;
|
|
@@ -104,6 +104,21 @@ function isPrettierIgnoreComment(body) {
|
|
|
104
104
|
return /^\s*prettier-ignore\s*$/.test(body);
|
|
105
105
|
}
|
|
106
106
|
/**
|
|
107
|
+
* Returns true if a comment body is only a visual marker for a styles section.
|
|
108
|
+
* These markers describe the old styled-components grouping, not emitted StyleX code.
|
|
109
|
+
*/
|
|
110
|
+
function isStyleSectionMarkerComment(body) {
|
|
111
|
+
const marker = body.trim().replace(/^[-\s]+/, "").replace(/[-\s]+$/, "").trim().toLowerCase();
|
|
112
|
+
return /^(?:styled\s*-?\s*components?|styles?)$/.test(marker);
|
|
113
|
+
}
|
|
114
|
+
function getCommentBody(comment) {
|
|
115
|
+
const c = comment && typeof comment === "object" ? comment : {};
|
|
116
|
+
return typeof c.value === "string" ? c.value : "";
|
|
117
|
+
}
|
|
118
|
+
function isJSDocBlockComment(comment) {
|
|
119
|
+
return (comment && typeof comment === "object" ? comment : {}).type === "CommentBlock" && getCommentBody(comment).trimStart().startsWith("*");
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
107
122
|
* Normalizes whitespace in a CSS value string.
|
|
108
123
|
* Collapses all sequences of whitespace (including newlines) to single spaces
|
|
109
124
|
* and trims leading/trailing whitespace.
|
|
@@ -125,4 +140,4 @@ function hasTopLevelMatch(value, pattern) {
|
|
|
125
140
|
return false;
|
|
126
141
|
}
|
|
127
142
|
//#endregion
|
|
128
|
-
export {
|
|
143
|
+
export { isBackgroundImageValue as a, isSingleBackgroundComponent as c, kebabToCamelCase as d, looksLikeLength as f, sanitizeIdentifier as h, getCommentBody as i, isStyleSectionMarkerComment as l, normalizeWhitespace as m, capitalize as n, isJSDocBlockComment as o, lowerFirst as p, escapeRegex as r, isPrettierIgnoreComment as s, camelToKebabCase as t, isValidIdentifierName as u };
|