styled-components-to-stylex-codemod 0.0.48 → 0.0.50
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/{extract-external-interface-CvkkJZb1.mjs → ast-walk-DgShpexa.mjs} +69 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +241 -21
- package/dist/{compute-leaf-set-90UrZ9WP.mjs → prepass-parser-BRDlW3DI.mjs} +100 -2
- package/dist/{prop-usage-Bz3z0V2F.mjs → prop-usage-QtOSsKTr.mjs} +15 -1
- package/dist/{run-prepass-1yZOVT3P.mjs → run-prepass-Da3N174M.mjs} +117 -106
- package/dist/{transform-types-Bshr_dBf.d.mts → transform-types-CHRHLCj_.d.mts} +10 -1
- package/dist/transform.d.mts +1 -1
- package/dist/transform.mjs +2174 -376
- package/dist/{typescript-analysis-C_25uBrt.mjs → typescript-analysis-CmIDxfLv.mjs} +117 -0
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@ import { readFileSync } from "node:fs";
|
|
|
5
5
|
* Logger and warning types for transform diagnostics.
|
|
6
6
|
* Core concepts: severity classification and source context reporting.
|
|
7
7
|
*/
|
|
8
|
+
const CASCADE_CONFLICT_WARNING = "styled(ImportedComponent) wraps a component whose file uses styled-components — convert the base component's file first to avoid CSS cascade conflicts";
|
|
8
9
|
const UNSUPPORTED_SHOULD_FORWARD_PROP_WARNING = "Unsupported shouldForwardProp pattern (only !prop.startsWith(), ![].includes(prop), and prop !== are supported)";
|
|
9
10
|
/**
|
|
10
11
|
* When fileCount <= this threshold, warnings are printed per-file inline and
|
|
@@ -134,6 +135,7 @@ function createContextReplacer() {
|
|
|
134
135
|
return value;
|
|
135
136
|
};
|
|
136
137
|
}
|
|
138
|
+
const MAX_DEPENDED_FILE_GROUPS = 15;
|
|
137
139
|
var LoggerReport = class {
|
|
138
140
|
warnings;
|
|
139
141
|
fileCount;
|
|
@@ -163,6 +165,20 @@ var LoggerReport = class {
|
|
|
163
165
|
lines.push("");
|
|
164
166
|
lines.push(`▸ ${group.message} (${group.warnings.length})`);
|
|
165
167
|
lines.push("");
|
|
168
|
+
const dependedFileGroups = this.groupDependedFiles(group);
|
|
169
|
+
if (dependedFileGroups.length > 0) {
|
|
170
|
+
lines.push(" Top depended files:");
|
|
171
|
+
lines.push("");
|
|
172
|
+
for (const [index, dependedFileGroup] of dependedFileGroups.entries()) {
|
|
173
|
+
const usageCount = dependedFileGroup.usageFiles.length;
|
|
174
|
+
const usageLabel = usageCount === 1 ? "usage file" : "usage files";
|
|
175
|
+
lines.push(` ${index + 1}. ${dependedFileGroup.dependedFilePath} (${usageCount} ${usageLabel})`);
|
|
176
|
+
for (const usageFile of dependedFileGroup.usageFiles.slice(0, MAX_EXAMPLES)) lines.push(` ${usageFile}`);
|
|
177
|
+
const remainingUsageFiles = usageCount - MAX_EXAMPLES;
|
|
178
|
+
if (remainingUsageFiles > 0) lines.push(` ... and ${remainingUsageFiles} more usage file(s)`);
|
|
179
|
+
lines.push("");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
166
182
|
const seenFiles = /* @__PURE__ */ new Set();
|
|
167
183
|
const uniqueLocations = [];
|
|
168
184
|
for (const loc of group.warnings) if (!seenFiles.has(loc.filePath)) {
|
|
@@ -212,6 +228,21 @@ var LoggerReport = class {
|
|
|
212
228
|
}
|
|
213
229
|
return Array.from(groupMap.values()).sort((a, b) => b.warnings.length - a.warnings.length);
|
|
214
230
|
}
|
|
231
|
+
groupDependedFiles(group) {
|
|
232
|
+
if (group.message !== "styled(ImportedComponent) wraps a component whose file uses styled-components — convert the base component's file first to avoid CSS cascade conflicts") return [];
|
|
233
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
234
|
+
for (const warning of group.warnings) {
|
|
235
|
+
const dependedFilePath = getCascadeDependedFilePath(warning);
|
|
236
|
+
if (!dependedFilePath) continue;
|
|
237
|
+
const dependedFileWarnings = groupMap.get(dependedFilePath) ?? [];
|
|
238
|
+
dependedFileWarnings.push(warning);
|
|
239
|
+
groupMap.set(dependedFilePath, dependedFileWarnings);
|
|
240
|
+
}
|
|
241
|
+
return Array.from(groupMap.entries()).map(([dependedFilePath, warnings]) => ({
|
|
242
|
+
dependedFilePath,
|
|
243
|
+
usageFiles: uniqueSorted(warnings.map((warning) => warning.filePath))
|
|
244
|
+
})).sort((a, b) => b.usageFiles.length - a.usageFiles.length).slice(0, MAX_DEPENDED_FILE_GROUPS);
|
|
245
|
+
}
|
|
215
246
|
getSnippet(filePath, loc) {
|
|
216
247
|
if (!loc) return;
|
|
217
248
|
const lines = this.getFileLines(filePath);
|
|
@@ -240,6 +271,18 @@ var LoggerReport = class {
|
|
|
240
271
|
}
|
|
241
272
|
}
|
|
242
273
|
};
|
|
274
|
+
function getCascadeDependedFilePath(warning) {
|
|
275
|
+
const context = warning.context;
|
|
276
|
+
if (!context || typeof context !== "object") return;
|
|
277
|
+
const record = context;
|
|
278
|
+
const definitionPath = record.definitionPath;
|
|
279
|
+
if (typeof definitionPath === "string") return definitionPath;
|
|
280
|
+
const importedPath = record.importedPath;
|
|
281
|
+
return typeof importedPath === "string" ? importedPath : void 0;
|
|
282
|
+
}
|
|
283
|
+
function uniqueSorted(values) {
|
|
284
|
+
return Array.from(new Set(values)).sort((a, b) => a.localeCompare(b));
|
|
285
|
+
}
|
|
243
286
|
const WARN_BG_COLOR = "\x1B[43m";
|
|
244
287
|
const WARN_TEXT_COLOR = "\x1B[30m";
|
|
245
288
|
const ERROR_BG_COLOR = "\x1B[41m";
|
|
@@ -380,4 +423,29 @@ function getFileImportsFromRes(name) {
|
|
|
380
423
|
return cached;
|
|
381
424
|
}
|
|
382
425
|
//#endregion
|
|
383
|
-
|
|
426
|
+
//#region src/internal/utilities/ast-walk.ts
|
|
427
|
+
const SKIPPED_KEYS = new Set([
|
|
428
|
+
"loc",
|
|
429
|
+
"comments",
|
|
430
|
+
"leadingComments",
|
|
431
|
+
"trailingComments"
|
|
432
|
+
]);
|
|
433
|
+
function walkAst(root, visitor) {
|
|
434
|
+
const visit = (node) => {
|
|
435
|
+
if (!node || typeof node !== "object") return;
|
|
436
|
+
if (Array.isArray(node)) {
|
|
437
|
+
for (const child of node) visit(child);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
const n = node;
|
|
441
|
+
visitor(n);
|
|
442
|
+
for (const key of Object.keys(n)) {
|
|
443
|
+
if (SKIPPED_KEYS.has(key)) continue;
|
|
444
|
+
const child = n[key];
|
|
445
|
+
if (child && typeof child === "object") visit(child);
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
visit(root);
|
|
449
|
+
}
|
|
450
|
+
//#endregion
|
|
451
|
+
export { getReExportedSourceName as a, CASCADE_CONFLICT_WARNING as c, findImportSource as i, Logger as l, fileExports as n, resolveBarrelReExport as o, fileImportsFrom as r, resolveBarrelReExportBinding as s, walkAst as t, UNSUPPORTED_SHOULD_FORWARD_PROP_WARNING as u };
|
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-CHRHLCj_.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/run.d.ts
|
|
4
4
|
interface RunTransformOptions {
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { c as describeValue, i as defineAdapter, n as mergeMarkerDeclarations, s as assertValidAdapterInput, t as transformedComponentAcceptsSx } from "./sx-surface-BzqO3hcC.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { l as Logger, o as resolveBarrelReExport, t as walkAst } from "./ast-walk-DgShpexa.mjs";
|
|
3
|
+
import { i as extractStyledDefBasesFromSource, t as createPrepassParser } from "./prepass-parser-BRDlW3DI.mjs";
|
|
4
4
|
import { r as toRealPath } from "./path-utils-BC4U8X_q.mjs";
|
|
5
5
|
import jscodeshift from "jscodeshift";
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -8,6 +8,162 @@ import { dirname, join, resolve } from "node:path";
|
|
|
8
8
|
import { existsSync, readFileSync } from "node:fs";
|
|
9
9
|
import { glob, readFile, writeFile } from "node:fs/promises";
|
|
10
10
|
import { spawn } from "node:child_process";
|
|
11
|
+
//#region src/internal/prepass/resolve-static-members.ts
|
|
12
|
+
/**
|
|
13
|
+
* Resolves the underlying component name(s) a static member access like `Select.Option` refers to,
|
|
14
|
+
* by structurally walking the defining module's AST.
|
|
15
|
+
*
|
|
16
|
+
* This replaces an earlier regex-over-source approach: regexes could not reliably skip type
|
|
17
|
+
* annotations, stop at the right `;`, or distinguish identifiers from type names. We parse once
|
|
18
|
+
* (cached per source) with the shared prepass parser and answer member lookups against real nodes.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Given the module `source`, the candidate root component names a local binding resolves to, and a
|
|
22
|
+
* static member path (`["Option"]` for `Select.Option`), returns every component name the member
|
|
23
|
+
* path can statically resolve to, plus the final member name as a fallback (matching the prior
|
|
24
|
+
* behavior so downstream metadata lookups still have something to try).
|
|
25
|
+
*/
|
|
26
|
+
function resolveStaticMemberComponentNames(source, rootNames, memberPath, parserName = "tsx") {
|
|
27
|
+
const program = parseProgram(source, parserName);
|
|
28
|
+
const fallbackMember = memberPath[memberPath.length - 1];
|
|
29
|
+
const fallback = fallbackMember ? [fallbackMember] : [];
|
|
30
|
+
if (!program) return [...new Set([...rootNames, ...fallback])];
|
|
31
|
+
const index = buildModuleIndex(program);
|
|
32
|
+
let owners = expandStaticComponentOwners(index, rootNames);
|
|
33
|
+
for (const memberName of memberPath) {
|
|
34
|
+
const nextOwners = /* @__PURE__ */ new Set();
|
|
35
|
+
for (const ownerName of owners) for (const target of findStaticMemberTargets(index, ownerName, memberName)) nextOwners.add(target);
|
|
36
|
+
owners = nextOwners;
|
|
37
|
+
if (owners.size === 0) break;
|
|
38
|
+
}
|
|
39
|
+
return [...new Set([...owners, ...fallback])];
|
|
40
|
+
}
|
|
41
|
+
const programCache = /* @__PURE__ */ new Map();
|
|
42
|
+
function parseProgram(source, parserName) {
|
|
43
|
+
const cached = programCache.get(source);
|
|
44
|
+
if (cached !== void 0) return cached;
|
|
45
|
+
const parsed = tryParse(source, parserName);
|
|
46
|
+
programCache.set(source, parsed);
|
|
47
|
+
return parsed;
|
|
48
|
+
}
|
|
49
|
+
function tryParse(source, parserName) {
|
|
50
|
+
for (const name of parserName === "tsx" ? ["tsx", "ts"] : [parserName]) try {
|
|
51
|
+
const ast = createPrepassParser(name).parse(source);
|
|
52
|
+
return ast.program ?? ast;
|
|
53
|
+
} catch {}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function buildModuleIndex(program) {
|
|
57
|
+
const initializers = /* @__PURE__ */ new Map();
|
|
58
|
+
const memberAssignments = /* @__PURE__ */ new Map();
|
|
59
|
+
walkAst(program, (node) => {
|
|
60
|
+
if (node.type === "VariableDeclarator") {
|
|
61
|
+
const name = identifierName(node.id);
|
|
62
|
+
const init = node.init;
|
|
63
|
+
if (name && init) initializers.set(name, init);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (node.type === "AssignmentExpression" && node.operator === "=") {
|
|
67
|
+
const target = capitalizedIdentifierName(node.right);
|
|
68
|
+
const member = staticMemberAccess(node.left);
|
|
69
|
+
if (target && member) addMemberTarget(memberAssignments, member.object, member.property, target);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
initializers,
|
|
74
|
+
memberAssignments
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Expands the root binding names to every capitalized identifier transitively referenced from their
|
|
79
|
+
* initializers (e.g. `const X = cond ? A : B` pulls in `A` and `B`). Mirrors the breadth the member
|
|
80
|
+
* lookup needs without assuming a particular declaration shape.
|
|
81
|
+
*/
|
|
82
|
+
function expandStaticComponentOwners(index, rootNames) {
|
|
83
|
+
const owners = new Set(rootNames);
|
|
84
|
+
const visit = (name) => {
|
|
85
|
+
const init = index.initializers.get(name);
|
|
86
|
+
if (!init) return;
|
|
87
|
+
for (const referenced of collectCapitalizedIdentifiers(init)) if (!owners.has(referenced)) {
|
|
88
|
+
owners.add(referenced);
|
|
89
|
+
visit(referenced);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
for (const name of rootNames) visit(name);
|
|
93
|
+
return owners;
|
|
94
|
+
}
|
|
95
|
+
function findStaticMemberTargets(index, ownerName, memberName) {
|
|
96
|
+
const targets = new Set(index.memberAssignments.get(ownerName)?.get(memberName) ?? []);
|
|
97
|
+
const init = index.initializers.get(ownerName);
|
|
98
|
+
for (const objectLiteral of objectLiteralsFromInitializer(index, init)) collectMemberTargetsFromObjectLiteral(objectLiteral, memberName, targets);
|
|
99
|
+
return targets;
|
|
100
|
+
}
|
|
101
|
+
/** Object expressions an owner's value is built from: a direct literal or `Object.assign(...)` args. */
|
|
102
|
+
function objectLiteralsFromInitializer(index, init) {
|
|
103
|
+
if (!init) return [];
|
|
104
|
+
if (init.type === "ObjectExpression") return [init];
|
|
105
|
+
if (isObjectAssignCall(init)) {
|
|
106
|
+
const literals = [];
|
|
107
|
+
for (const arg of init.arguments ?? []) if (arg.type === "ObjectExpression") literals.push(arg);
|
|
108
|
+
else {
|
|
109
|
+
const referenced = identifierName(arg);
|
|
110
|
+
const referencedInit = referenced ? index.initializers.get(referenced) : void 0;
|
|
111
|
+
if (referencedInit?.type === "ObjectExpression") literals.push(referencedInit);
|
|
112
|
+
}
|
|
113
|
+
return literals;
|
|
114
|
+
}
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
function collectMemberTargetsFromObjectLiteral(objectLiteral, memberName, targets) {
|
|
118
|
+
for (const property of objectLiteral.properties ?? []) {
|
|
119
|
+
if (property.type !== "ObjectProperty" && property.type !== "Property") continue;
|
|
120
|
+
if (identifierName(property.key) !== memberName) continue;
|
|
121
|
+
const target = capitalizedIdentifierName(property.value);
|
|
122
|
+
if (target) targets.add(target);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function isObjectAssignCall(node) {
|
|
126
|
+
if (node.type !== "CallExpression") return false;
|
|
127
|
+
const member = staticMemberAccess(node.callee);
|
|
128
|
+
return member?.object === "Object" && member.property === "assign";
|
|
129
|
+
}
|
|
130
|
+
function collectCapitalizedIdentifiers(node) {
|
|
131
|
+
const names = /* @__PURE__ */ new Set();
|
|
132
|
+
walkAst(node, (child) => {
|
|
133
|
+
if (child.type === "Identifier" && /^[A-Z]/.test(String(child.name))) names.add(String(child.name));
|
|
134
|
+
});
|
|
135
|
+
return names;
|
|
136
|
+
}
|
|
137
|
+
function staticMemberAccess(node) {
|
|
138
|
+
if (!node || node.type !== "MemberExpression" && node.type !== "OptionalMemberExpression" || node.computed === true) return null;
|
|
139
|
+
const object = identifierName(node.object);
|
|
140
|
+
const property = identifierName(node.property);
|
|
141
|
+
return object && property ? {
|
|
142
|
+
object,
|
|
143
|
+
property
|
|
144
|
+
} : null;
|
|
145
|
+
}
|
|
146
|
+
function addMemberTarget(memberAssignments, object, property, target) {
|
|
147
|
+
let byMember = memberAssignments.get(object);
|
|
148
|
+
if (!byMember) {
|
|
149
|
+
byMember = /* @__PURE__ */ new Map();
|
|
150
|
+
memberAssignments.set(object, byMember);
|
|
151
|
+
}
|
|
152
|
+
let targets = byMember.get(property);
|
|
153
|
+
if (!targets) {
|
|
154
|
+
targets = /* @__PURE__ */ new Set();
|
|
155
|
+
byMember.set(property, targets);
|
|
156
|
+
}
|
|
157
|
+
targets.add(target);
|
|
158
|
+
}
|
|
159
|
+
function identifierName(node) {
|
|
160
|
+
return node?.type === "Identifier" && typeof node.name === "string" ? node.name : null;
|
|
161
|
+
}
|
|
162
|
+
function capitalizedIdentifierName(node) {
|
|
163
|
+
const name = identifierName(node);
|
|
164
|
+
return name && /^[A-Z]/.test(name) ? name : null;
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
11
167
|
//#region src/run.ts
|
|
12
168
|
/**
|
|
13
169
|
* Runs the codemod over input files with an adapter.
|
|
@@ -149,7 +305,7 @@ async function runTransform(options) {
|
|
|
149
305
|
const { createModuleResolver } = await import("./resolve-imports-DgSAddIF.mjs").then((n) => n.n);
|
|
150
306
|
const sharedResolver = createModuleResolver();
|
|
151
307
|
filePaths = orderFilesByLocalImportDependencies(filePaths, sharedResolver, toRealPath);
|
|
152
|
-
const { runPrepass } = await import("./run-prepass-
|
|
308
|
+
const { runPrepass } = await import("./run-prepass-Da3N174M.mjs");
|
|
153
309
|
const absoluteFiles = filePaths.map((f) => resolve(f));
|
|
154
310
|
const absoluteConsumers = consumerFilePaths.map((f) => resolve(f));
|
|
155
311
|
let prepassResult;
|
|
@@ -249,12 +405,15 @@ async function runTransform(options) {
|
|
|
249
405
|
if (!resolvedImport) return;
|
|
250
406
|
const resolvedPath = toRealPath(resolvedImport);
|
|
251
407
|
const definitionSourcePath = resolveExistingSourcePath(resolveBarrelReExport(resolvedPath, ctx.importedName, prepassResolve, cachedRead) ?? resolvedPath);
|
|
252
|
-
const
|
|
408
|
+
const memberPath = ctx.memberPath ?? [];
|
|
409
|
+
const autoInterfaceNames = memberPath.length > 0 ? [ctx.localName, memberPath[memberPath.length - 1]] : ctx.importedName === "default" ? [ctx.localName, ctx.importedName] : [ctx.importedName];
|
|
253
410
|
const styledDefinitionNames = getStyledDefinitionNames(definitionSourcePath);
|
|
254
|
-
const
|
|
411
|
+
const rootSourceComponentNames = ctx.importedName === "default" ? [ctx.localName, getDefaultExportedName(definitionSourcePath)].filter((name) => typeof name === "string") : [ctx.importedName];
|
|
412
|
+
const sourceComponentNames = memberPath.length > 0 ? resolveStaticMemberComponentNames(cachedRead(definitionSourcePath), rootSourceComponentNames, memberPath) : rootSourceComponentNames;
|
|
255
413
|
const typedComponent = findTypedComponentMetadata(prepassResult.typeScriptMetadata, definitionSourcePath, sourceComponentNames);
|
|
256
414
|
if (typedComponent?.supportsSxProp === true) return {
|
|
257
415
|
acceptsSx: true,
|
|
416
|
+
...typedComponent.sxTarget ? { sxTarget: typedComponent.sxTarget } : {},
|
|
258
417
|
sxExcludedProperties: typedComponent.sxExcludedProperties,
|
|
259
418
|
sxAllowedProperties: typedComponent.sxAllowedProperties
|
|
260
419
|
};
|
|
@@ -339,7 +498,23 @@ async function runTransform(options) {
|
|
|
339
498
|
transformedFiles: /* @__PURE__ */ new Set()
|
|
340
499
|
},
|
|
341
500
|
silent: true,
|
|
342
|
-
isolateFiles: true
|
|
501
|
+
isolateFiles: true,
|
|
502
|
+
createIsolatedOptions(filePath) {
|
|
503
|
+
const isolatedTransformedFiles = /* @__PURE__ */ new Set();
|
|
504
|
+
return {
|
|
505
|
+
...runnerOptions,
|
|
506
|
+
dry: true,
|
|
507
|
+
print: false,
|
|
508
|
+
sidecarFiles: /* @__PURE__ */ new Map(),
|
|
509
|
+
bridgeResults: /* @__PURE__ */ new Map(),
|
|
510
|
+
transformedFiles: isolatedTransformedFiles,
|
|
511
|
+
transformedFileSources: /* @__PURE__ */ new Map(),
|
|
512
|
+
transientPropRenames: /* @__PURE__ */ new Map(),
|
|
513
|
+
crossFilePrepassResult: createStandalonePrepassResult(crossFilePrepassResult, filePath, isolatedTransformedFiles),
|
|
514
|
+
silent: true,
|
|
515
|
+
isolateFiles: true
|
|
516
|
+
};
|
|
517
|
+
}
|
|
343
518
|
});
|
|
344
519
|
standaloneWarnings = Logger.createReport().getWarnings();
|
|
345
520
|
Logger._clearCollected();
|
|
@@ -480,6 +655,46 @@ function readFileForOrdering(filePath) {
|
|
|
480
655
|
return "";
|
|
481
656
|
}
|
|
482
657
|
}
|
|
658
|
+
function createStandalonePrepassResult(prepass, filePath, transformedFiles) {
|
|
659
|
+
const standaloneFile = toRealPath(resolve(filePath));
|
|
660
|
+
const selectorUsages = /* @__PURE__ */ new Map();
|
|
661
|
+
const componentsNeedingMarkerSidecar = /* @__PURE__ */ new Map();
|
|
662
|
+
const componentsNeedingGlobalSelectorBridge = /* @__PURE__ */ new Map();
|
|
663
|
+
for (const [consumerPath, usages] of prepass.selectorUsages) {
|
|
664
|
+
const consumerIsTransformed = toRealPath(consumerPath) === standaloneFile;
|
|
665
|
+
const isolatedUsages = usages.map((usage) => ({
|
|
666
|
+
...usage,
|
|
667
|
+
consumerIsTransformed
|
|
668
|
+
}));
|
|
669
|
+
selectorUsages.set(consumerPath, isolatedUsages);
|
|
670
|
+
for (const usage of isolatedUsages) {
|
|
671
|
+
if (usage.bridgeComponentName) continue;
|
|
672
|
+
if (consumerIsTransformed) addSetMapEntry(componentsNeedingMarkerSidecar, usage.resolvedPath, usage.importedName);
|
|
673
|
+
addSetMapEntry(componentsNeedingGlobalSelectorBridge, usage.resolvedPath, usage.importedName);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return {
|
|
677
|
+
...prepass,
|
|
678
|
+
selectorUsages,
|
|
679
|
+
componentsNeedingMarkerSidecar,
|
|
680
|
+
componentsNeedingGlobalSelectorBridge,
|
|
681
|
+
globalLeafKeys: getStandaloneGlobalLeafKeys(prepass.globalLeafKeys, standaloneFile),
|
|
682
|
+
transformedFiles
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
function getStandaloneGlobalLeafKeys(globalLeafKeys, standaloneFile) {
|
|
686
|
+
if (!globalLeafKeys) return;
|
|
687
|
+
const filePrefix = `${standaloneFile}:`;
|
|
688
|
+
return new Set([...globalLeafKeys].filter((key) => key.startsWith(filePrefix)));
|
|
689
|
+
}
|
|
690
|
+
function addSetMapEntry(map, key, value) {
|
|
691
|
+
const values = map.get(key);
|
|
692
|
+
if (values) {
|
|
693
|
+
values.add(value);
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
map.set(key, new Set([value]));
|
|
697
|
+
}
|
|
483
698
|
async function runTransformSequentially(transformModule, filePaths, options) {
|
|
484
699
|
const transform = await loadTransformFunction(transformModule);
|
|
485
700
|
const aggregate = {
|
|
@@ -491,20 +706,25 @@ async function runTransformSequentially(transformModule, filePaths, options) {
|
|
|
491
706
|
files: []
|
|
492
707
|
};
|
|
493
708
|
const startedAt = performance.now();
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
709
|
+
const createApi = () => {
|
|
710
|
+
const j = jscodeshift.withParser(options.parser);
|
|
711
|
+
return {
|
|
712
|
+
j,
|
|
713
|
+
jscodeshift: j,
|
|
714
|
+
stats: () => {},
|
|
715
|
+
report: (msg) => {
|
|
716
|
+
if (!options.silent) process.stdout.write(`${msg}\n`);
|
|
717
|
+
}
|
|
718
|
+
};
|
|
502
719
|
};
|
|
720
|
+
const sharedApi = createApi();
|
|
503
721
|
for (const filePath of filePaths) {
|
|
722
|
+
const fileOptions = options.createIsolatedOptions?.(filePath) ?? options;
|
|
723
|
+
const api = fileOptions.isolateFiles === true ? createApi() : sharedApi;
|
|
504
724
|
if (options.isolateFiles === true) {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
725
|
+
fileOptions.transformedFiles.clear();
|
|
726
|
+
fileOptions.transformedFileSources.clear();
|
|
727
|
+
fileOptions.crossFilePrepassResult?.transformedFiles?.clear();
|
|
508
728
|
}
|
|
509
729
|
let source;
|
|
510
730
|
try {
|
|
@@ -522,8 +742,8 @@ async function runTransformSequentially(transformModule, filePaths, options) {
|
|
|
522
742
|
const output = await transform({
|
|
523
743
|
path: filePath,
|
|
524
744
|
source
|
|
525
|
-
}, api,
|
|
526
|
-
if (output !== null)
|
|
745
|
+
}, api, fileOptions);
|
|
746
|
+
if (output !== null) fileOptions.transformedFileSources.set(toRealPath(filePath), output);
|
|
527
747
|
if (output === null) {
|
|
528
748
|
aggregate.skip += 1;
|
|
529
749
|
aggregate.files.push({
|
|
@@ -540,8 +760,8 @@ async function runTransformSequentially(transformModule, filePaths, options) {
|
|
|
540
760
|
});
|
|
541
761
|
continue;
|
|
542
762
|
}
|
|
543
|
-
if (
|
|
544
|
-
if (!
|
|
763
|
+
if (fileOptions.print) process.stdout.write(`${output}\n`);
|
|
764
|
+
if (!fileOptions.dry) await writeFile(filePath, output, "utf-8");
|
|
545
765
|
aggregate.ok += 1;
|
|
546
766
|
aggregate.files.push({
|
|
547
767
|
filePath,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as findImportSource, s as resolveBarrelReExportBinding } from "./ast-walk-DgShpexa.mjs";
|
|
2
|
+
import { parse } from "@babel/parser";
|
|
2
3
|
//#region src/internal/prepass/compute-leaf-set.ts
|
|
3
4
|
/**
|
|
4
5
|
* Computes which styled-component bindings are "leaves" for leaves-only mode:
|
|
@@ -239,4 +240,101 @@ function findDefaultExportedLocalName(source) {
|
|
|
239
240
|
return source.match(/\bexport\s+default\s+([A-Z][A-Za-z0-9]*)\b/)?.[1] ?? source.match(/\bexport\s*\{[^}]*\b([A-Z][A-Za-z0-9]*)\s+as\s+default\b[^}]*\}/)?.[1];
|
|
240
241
|
}
|
|
241
242
|
//#endregion
|
|
242
|
-
|
|
243
|
+
//#region src/internal/prepass/prepass-parser.ts
|
|
244
|
+
/**
|
|
245
|
+
* Shared babel parser for prepass modules.
|
|
246
|
+
*
|
|
247
|
+
* Uses @babel/parser directly with `tokens: false` for ~35% faster parsing
|
|
248
|
+
* compared to jscodeshift's getParser (which enables token generation).
|
|
249
|
+
*
|
|
250
|
+
* Both scan-cross-file-selectors and extract-external-interface can share this parser
|
|
251
|
+
* to avoid duplicate parser initialization.
|
|
252
|
+
*/
|
|
253
|
+
/**
|
|
254
|
+
* Create a babel parser with tokens disabled, matching jscodeshift's plugin set
|
|
255
|
+
* for the given parser name.
|
|
256
|
+
*
|
|
257
|
+
* - `tsx` / `ts`: TypeScript plugins (tsx also includes JSX)
|
|
258
|
+
* - `babel` / `babylon` / `flow`: Flow plugins + JSX
|
|
259
|
+
*
|
|
260
|
+
* Note: jscodeshift's `flow` parser uses the `flow-parser` package (not babel).
|
|
261
|
+
* We always use `@babel/parser` with the `flow` plugin instead, since it produces
|
|
262
|
+
* the same AST node types (ImportDeclaration, TaggedTemplateExpression) that the
|
|
263
|
+
* prepass walks, and avoids an extra parser dependency.
|
|
264
|
+
*/
|
|
265
|
+
function createPrepassParser(parserName = "tsx") {
|
|
266
|
+
const options = parserName === "ts" || parserName === "tsx" ? buildOptions(TS_PLUGINS, parserName === "tsx") : buildOptions(FLOW_PLUGINS, true);
|
|
267
|
+
return { parse(source) {
|
|
268
|
+
return parse(source, options);
|
|
269
|
+
} };
|
|
270
|
+
}
|
|
271
|
+
function buildOptions(plugins, includeJsx) {
|
|
272
|
+
return {
|
|
273
|
+
sourceType: "module",
|
|
274
|
+
allowImportExportEverywhere: true,
|
|
275
|
+
allowReturnOutsideFunction: true,
|
|
276
|
+
startLine: 1,
|
|
277
|
+
tokens: false,
|
|
278
|
+
plugins: includeJsx ? ["jsx", ...plugins] : plugins
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Plugins for TypeScript parsers (ts, tsx).
|
|
283
|
+
* Same as jscodeshift's tsOptions.plugins minus "jsx" (added conditionally).
|
|
284
|
+
*/
|
|
285
|
+
const TS_PLUGINS = [
|
|
286
|
+
"asyncGenerators",
|
|
287
|
+
"decoratorAutoAccessors",
|
|
288
|
+
"bigInt",
|
|
289
|
+
"classPrivateMethods",
|
|
290
|
+
"classPrivateProperties",
|
|
291
|
+
"classProperties",
|
|
292
|
+
"decorators-legacy",
|
|
293
|
+
"doExpressions",
|
|
294
|
+
"dynamicImport",
|
|
295
|
+
"exportDefaultFrom",
|
|
296
|
+
"exportNamespaceFrom",
|
|
297
|
+
"functionBind",
|
|
298
|
+
"functionSent",
|
|
299
|
+
"importAttributes",
|
|
300
|
+
"importMeta",
|
|
301
|
+
"nullishCoalescingOperator",
|
|
302
|
+
"numericSeparator",
|
|
303
|
+
"objectRestSpread",
|
|
304
|
+
"optionalCatchBinding",
|
|
305
|
+
"optionalChaining",
|
|
306
|
+
["pipelineOperator", { proposal: "minimal" }],
|
|
307
|
+
"throwExpressions",
|
|
308
|
+
"typescript"
|
|
309
|
+
];
|
|
310
|
+
/**
|
|
311
|
+
* Plugins for Flow/Babylon parsers (babel, babylon, flow).
|
|
312
|
+
* Same as jscodeshift's babylon parser plugins minus "jsx" (added conditionally).
|
|
313
|
+
*/
|
|
314
|
+
const FLOW_PLUGINS = [
|
|
315
|
+
["flow", { all: true }],
|
|
316
|
+
"flowComments",
|
|
317
|
+
"asyncGenerators",
|
|
318
|
+
"bigInt",
|
|
319
|
+
"classProperties",
|
|
320
|
+
"classPrivateProperties",
|
|
321
|
+
"classPrivateMethods",
|
|
322
|
+
["decorators", { decoratorsBeforeExport: false }],
|
|
323
|
+
"doExpressions",
|
|
324
|
+
"dynamicImport",
|
|
325
|
+
"exportDefaultFrom",
|
|
326
|
+
"exportNamespaceFrom",
|
|
327
|
+
"functionBind",
|
|
328
|
+
"functionSent",
|
|
329
|
+
"importMeta",
|
|
330
|
+
"logicalAssignment",
|
|
331
|
+
"nullishCoalescingOperator",
|
|
332
|
+
"numericSeparator",
|
|
333
|
+
"objectRestSpread",
|
|
334
|
+
"optionalCatchBinding",
|
|
335
|
+
"optionalChaining",
|
|
336
|
+
["pipelineOperator", { proposal: "minimal" }],
|
|
337
|
+
"throwExpressions"
|
|
338
|
+
];
|
|
339
|
+
//#endregion
|
|
340
|
+
export { extractStyledDefBasesFromSource as i, computeGlobalLeafKeys as n, extractStyledDefBasesFromAstProgram as r, createPrepassParser as t };
|
|
@@ -61,5 +61,19 @@ function mergeComponentPropUsage(info, usage) {
|
|
|
61
61
|
if (!propInfo.values.some((existing) => existing === value.value)) propInfo.values.push(value.value);
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Formats a `prop === value` JS condition for an observed static variant bucket,
|
|
66
|
+
* quoting strings and emitting numbers bare. Shared by every observed-variant emitter.
|
|
67
|
+
*/
|
|
68
|
+
function formatObservedVariantCondition(propName, value) {
|
|
69
|
+
return `${propName} === ${typeof value === "number" ? String(value) : JSON.stringify(value)}`;
|
|
70
|
+
}
|
|
71
|
+
function getExhaustiveObservedStaticValues(info, propName) {
|
|
72
|
+
const propUsage = info?.props[propName];
|
|
73
|
+
if (!info || info.hasUnknownUsage || !propUsage || propUsage.hasUnknown) return null;
|
|
74
|
+
if (propUsage.values.length < 1) return null;
|
|
75
|
+
const values = propUsage.values.filter((value) => typeof value === "string" || typeof value === "number");
|
|
76
|
+
return values.length === propUsage.values.length ? values : null;
|
|
77
|
+
}
|
|
64
78
|
//#endregion
|
|
65
|
-
export {
|
|
79
|
+
export { mergeComponentPropUsage as a, getExhaustiveObservedStaticValues as i, createComponentPropUsageInfo as n, readStaticJsxLiteral as o, formatObservedVariantCondition as r, KNOWN_NON_ELEMENT_PROPS as t };
|