styled-components-to-stylex-codemod 0.0.48 → 0.0.49

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.
@@ -380,4 +380,29 @@ function getFileImportsFromRes(name) {
380
380
  return cached;
381
381
  }
382
382
  //#endregion
383
- export { resolveBarrelReExport as a, UNSUPPORTED_SHOULD_FORWARD_PROP_WARNING as c, getReExportedSourceName as i, fileImportsFrom as n, resolveBarrelReExportBinding as o, findImportSource as r, Logger as s, fileExports as t };
383
+ //#region src/internal/utilities/ast-walk.ts
384
+ const SKIPPED_KEYS = new Set([
385
+ "loc",
386
+ "comments",
387
+ "leadingComments",
388
+ "trailingComments"
389
+ ]);
390
+ function walkAst(root, visitor) {
391
+ const visit = (node) => {
392
+ if (!node || typeof node !== "object") return;
393
+ if (Array.isArray(node)) {
394
+ for (const child of node) visit(child);
395
+ return;
396
+ }
397
+ const n = node;
398
+ visitor(n);
399
+ for (const key of Object.keys(n)) {
400
+ if (SKIPPED_KEYS.has(key)) continue;
401
+ const child = n[key];
402
+ if (child && typeof child === "object") visit(child);
403
+ }
404
+ };
405
+ visit(root);
406
+ }
407
+ //#endregion
408
+ export { getReExportedSourceName as a, Logger as c, findImportSource as i, UNSUPPORTED_SHOULD_FORWARD_PROP_WARNING as l, fileExports as n, resolveBarrelReExport as o, fileImportsFrom as r, resolveBarrelReExportBinding as s, walkAst as t };
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-Bshr_dBf.mjs";
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 { a as resolveBarrelReExport, s as Logger } from "./extract-external-interface-CvkkJZb1.mjs";
3
- import { r as extractStyledDefBasesFromSource } from "./compute-leaf-set-90UrZ9WP.mjs";
2
+ import { c as Logger, o as resolveBarrelReExport, t as walkAst } from "./ast-walk-DigTJqU7.mjs";
3
+ import { i as extractStyledDefBasesFromSource, t as createPrepassParser } from "./prepass-parser-CwdDzSgx.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-1yZOVT3P.mjs");
308
+ const { runPrepass } = await import("./run-prepass-BWQCThfh.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 autoInterfaceNames = ctx.importedName === "default" ? [ctx.localName, ctx.importedName] : [ctx.importedName];
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 sourceComponentNames = ctx.importedName === "default" ? [ctx.localName, getDefaultExportedName(definitionSourcePath)].filter((name) => typeof name === "string") : [ctx.importedName];
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
  };
@@ -1,4 +1,5 @@
1
- import { o as resolveBarrelReExportBinding, r as findImportSource } from "./extract-external-interface-CvkkJZb1.mjs";
1
+ import { i as findImportSource, s as resolveBarrelReExportBinding } from "./ast-walk-DigTJqU7.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
- export { extractStyledDefBasesFromAstProgram as n, extractStyledDefBasesFromSource as r, computeGlobalLeafKeys as t };
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 { readStaticJsxLiteral as i, createComponentPropUsageInfo as n, mergeComponentPropUsage as r, KNOWN_NON_ELEMENT_PROPS as t };
79
+ export { mergeComponentPropUsage as a, getExhaustiveObservedStaticValues as i, createComponentPropUsageInfo as n, readStaticJsxLiteral as o, formatObservedVariantCondition as r, KNOWN_NON_ELEMENT_PROPS as t };
@@ -1,13 +1,12 @@
1
- import { a as resolveBarrelReExport, n as fileImportsFrom, o as resolveBarrelReExportBinding, r as findImportSource, s as Logger, t as fileExports } from "./extract-external-interface-CvkkJZb1.mjs";
2
- import { n as extractStyledDefBasesFromAstProgram, r as extractStyledDefBasesFromSource, t as computeGlobalLeafKeys } from "./compute-leaf-set-90UrZ9WP.mjs";
1
+ import { c as Logger, i as findImportSource, n as fileExports, o as resolveBarrelReExport, r as fileImportsFrom, s as resolveBarrelReExportBinding, t as walkAst } from "./ast-walk-DigTJqU7.mjs";
2
+ import { i as extractStyledDefBasesFromSource, n as computeGlobalLeafKeys, r as extractStyledDefBasesFromAstProgram, t as createPrepassParser } from "./prepass-parser-CwdDzSgx.mjs";
3
3
  import { r as escapeRegex } from "./string-utils-DD9wdRHW.mjs";
4
4
  import { n as isTemplatePlaceholderInSelectorContext, r as PLACEHOLDER_RE, t as isSelectorContext } from "./selector-context-heuristic-LVizWWOR.mjs";
5
- import { i as readStaticJsxLiteral, n as createComponentPropUsageInfo, r as mergeComponentPropUsage, t as KNOWN_NON_ELEMENT_PROPS } from "./prop-usage-Bz3z0V2F.mjs";
5
+ import { a as mergeComponentPropUsage, n as createComponentPropUsageInfo, o as readStaticJsxLiteral, t as KNOWN_NON_ELEMENT_PROPS } from "./prop-usage-QtOSsKTr.mjs";
6
6
  import { relative, resolve } from "node:path";
7
7
  import { readFileSync, realpathSync } from "node:fs";
8
8
  import { execSync } from "node:child_process";
9
9
  import { createHash } from "node:crypto";
10
- import { parse } from "@babel/parser";
11
10
  //#region src/internal/utilities/collection-utils.ts
12
11
  /** Add a value to a Set stored in a Map, creating the Set if it doesn't exist. */
13
12
  function addToSetMap(map, key, value) {
@@ -19,103 +18,6 @@ function addToSetMap(map, key, value) {
19
18
  set.add(value);
20
19
  }
21
20
  //#endregion
22
- //#region src/internal/prepass/prepass-parser.ts
23
- /**
24
- * Shared babel parser for prepass modules.
25
- *
26
- * Uses @babel/parser directly with `tokens: false` for ~35% faster parsing
27
- * compared to jscodeshift's getParser (which enables token generation).
28
- *
29
- * Both scan-cross-file-selectors and extract-external-interface can share this parser
30
- * to avoid duplicate parser initialization.
31
- */
32
- /**
33
- * Create a babel parser with tokens disabled, matching jscodeshift's plugin set
34
- * for the given parser name.
35
- *
36
- * - `tsx` / `ts`: TypeScript plugins (tsx also includes JSX)
37
- * - `babel` / `babylon` / `flow`: Flow plugins + JSX
38
- *
39
- * Note: jscodeshift's `flow` parser uses the `flow-parser` package (not babel).
40
- * We always use `@babel/parser` with the `flow` plugin instead, since it produces
41
- * the same AST node types (ImportDeclaration, TaggedTemplateExpression) that the
42
- * prepass walks, and avoids an extra parser dependency.
43
- */
44
- function createPrepassParser(parserName = "tsx") {
45
- const options = parserName === "ts" || parserName === "tsx" ? buildOptions(TS_PLUGINS, parserName === "tsx") : buildOptions(FLOW_PLUGINS, true);
46
- return { parse(source) {
47
- return parse(source, options);
48
- } };
49
- }
50
- function buildOptions(plugins, includeJsx) {
51
- return {
52
- sourceType: "module",
53
- allowImportExportEverywhere: true,
54
- allowReturnOutsideFunction: true,
55
- startLine: 1,
56
- tokens: false,
57
- plugins: includeJsx ? ["jsx", ...plugins] : plugins
58
- };
59
- }
60
- /**
61
- * Plugins for TypeScript parsers (ts, tsx).
62
- * Same as jscodeshift's tsOptions.plugins minus "jsx" (added conditionally).
63
- */
64
- const TS_PLUGINS = [
65
- "asyncGenerators",
66
- "decoratorAutoAccessors",
67
- "bigInt",
68
- "classPrivateMethods",
69
- "classPrivateProperties",
70
- "classProperties",
71
- "decorators-legacy",
72
- "doExpressions",
73
- "dynamicImport",
74
- "exportDefaultFrom",
75
- "exportNamespaceFrom",
76
- "functionBind",
77
- "functionSent",
78
- "importAttributes",
79
- "importMeta",
80
- "nullishCoalescingOperator",
81
- "numericSeparator",
82
- "objectRestSpread",
83
- "optionalCatchBinding",
84
- "optionalChaining",
85
- ["pipelineOperator", { proposal: "minimal" }],
86
- "throwExpressions",
87
- "typescript"
88
- ];
89
- /**
90
- * Plugins for Flow/Babylon parsers (babel, babylon, flow).
91
- * Same as jscodeshift's babylon parser plugins minus "jsx" (added conditionally).
92
- */
93
- const FLOW_PLUGINS = [
94
- ["flow", { all: true }],
95
- "flowComments",
96
- "asyncGenerators",
97
- "bigInt",
98
- "classProperties",
99
- "classPrivateProperties",
100
- "classPrivateMethods",
101
- ["decorators", { decoratorsBeforeExport: false }],
102
- "doExpressions",
103
- "dynamicImport",
104
- "exportDefaultFrom",
105
- "exportNamespaceFrom",
106
- "functionBind",
107
- "functionSent",
108
- "importMeta",
109
- "logicalAssignment",
110
- "nullishCoalescingOperator",
111
- "numericSeparator",
112
- "objectRestSpread",
113
- "optionalCatchBinding",
114
- "optionalChaining",
115
- ["pipelineOperator", { proposal: "minimal" }],
116
- "throwExpressions"
117
- ];
118
- //#endregion
119
21
  //#region src/internal/prepass/scan-cross-file-selectors.ts
120
22
  /**
121
23
  * Pre-filter: matches any bare `${Identifier}` template expression.
@@ -750,7 +652,7 @@ function isTypeScriptParser(parserName) {
750
652
  }
751
653
  async function loadTypeScriptAnalysis() {
752
654
  try {
753
- return await import("./typescript-analysis-C_25uBrt.mjs");
655
+ return await import("./typescript-analysis-CmIDxfLv.mjs");
754
656
  } catch (err) {
755
657
  const message = err instanceof Error ? err.message : String(err);
756
658
  if (message.includes("typescript") && (message.includes("Cannot find") || message.includes("ERR_MODULE_NOT_FOUND"))) throw new Error(["TypeScript parser runs require the optional `typescript` package for compiler metadata.", "Install TypeScript in the project (supported range: >=5.0.0 <6), or use a non-TypeScript parser."].join("\n"));
@@ -883,14 +785,16 @@ function scanConsumerJsxUsages(filePath, source, componentNames, parser) {
883
785
  }
884
786
  const importNodes = [];
885
787
  const jsxOpenings = [];
886
- walkForImportsAndJsxOpenings(ast.program ?? ast, importNodes, jsxOpenings);
788
+ const program = ast.program ?? ast;
789
+ walkForImportsAndJsxOpenings(program, importNodes, jsxOpenings);
887
790
  const importMap = buildImportMapFromNodes(importNodes);
791
+ const staticIdentifierValues = collectStaticIdentifierValues(program);
888
792
  const resultMap = /* @__PURE__ */ new Map();
889
793
  const staticPropUsages = [];
890
794
  for (const opening of jsxOpenings) {
891
795
  const resolvedComponent = resolveJsxOpeningComponent(opening.name, importMap, componentNames);
892
796
  if (!resolvedComponent) continue;
893
- const openingUsage = readConsumerOpeningUsage(opening);
797
+ const openingUsage = readConsumerOpeningUsage(opening, staticIdentifierValues);
894
798
  const { externalProps } = openingUsage;
895
799
  if (externalProps.className || externalProps.style || externalProps.spreadProps || externalProps.elementProps) {
896
800
  const key = `${resolvedComponent.name}\0${resolvedComponent.importSource ?? ""}`;
@@ -941,7 +845,7 @@ function resolveJsxOpeningComponent(name, importMap, componentNames) {
941
845
  importSource: importEntry.source
942
846
  } : void 0;
943
847
  }
944
- function readConsumerOpeningUsage(opening) {
848
+ function readConsumerOpeningUsage(opening, staticIdentifierValues) {
945
849
  const externalProps = {
946
850
  className: false,
947
851
  style: false,
@@ -964,7 +868,7 @@ function readConsumerOpeningUsage(opening) {
964
868
  else if (propName === "style") externalProps.style = true;
965
869
  else if (isElementConsumerProp(propName)) externalProps.elementProps = true;
966
870
  if (!KNOWN_NON_ELEMENT_PROPS.has(propName)) {
967
- const value = readStaticJsxLiteral(attr);
871
+ const value = readStaticJsxLiteral(attr) ?? readStaticIdentifierJsxValue(attr, staticIdentifierValues);
968
872
  props[propName] = value === void 0 ? { kind: "unknown" } : {
969
873
  kind: "static",
970
874
  value
@@ -979,6 +883,113 @@ function readConsumerOpeningUsage(opening) {
979
883
  }
980
884
  };
981
885
  }
886
+ function collectStaticIdentifierValues(program) {
887
+ const values = /* @__PURE__ */ new Map();
888
+ for (const declaration of moduleLevelVariableDeclarations(program)) {
889
+ if (declaration.kind !== "const") continue;
890
+ const declarators = declaration.declarations ?? [];
891
+ for (const decl of declarators) {
892
+ const name = decl.id?.type === "Identifier" ? decl.id.name : null;
893
+ const value = staticValueFromNode(decl.init);
894
+ if (name && value !== void 0) values.set(name, value);
895
+ }
896
+ }
897
+ if (values.size === 0) return values;
898
+ const bindingCounts = countBoundNames(program);
899
+ const shadowedNames = [];
900
+ for (const [name] of values) if ((bindingCounts.get(name) ?? 0) > 1) shadowedNames.push(name);
901
+ for (const name of shadowedNames) values.delete(name);
902
+ return values;
903
+ }
904
+ /** Top-level `const`/`let`/`var` declarations, unwrapping `export` declarations. */
905
+ function moduleLevelVariableDeclarations(program) {
906
+ const body = program.body ?? [];
907
+ const declarations = [];
908
+ for (const node of body) if (node.type === "VariableDeclaration") declarations.push(node);
909
+ else if (node.type === "ExportNamedDeclaration") {
910
+ const inner = node.declaration;
911
+ if (inner?.type === "VariableDeclaration") declarations.push(inner);
912
+ }
913
+ return declarations;
914
+ }
915
+ /** Counts how many times each name is introduced as a binding anywhere in the module. */
916
+ function countBoundNames(program) {
917
+ const counts = /* @__PURE__ */ new Map();
918
+ const bump = (name) => {
919
+ if (name) counts.set(name, (counts.get(name) ?? 0) + 1);
920
+ };
921
+ const bumpId = (node) => {
922
+ if (node?.type === "Identifier") bump(node.name ?? "");
923
+ };
924
+ walkAst(program, (node) => {
925
+ switch (node.type) {
926
+ case "VariableDeclarator":
927
+ collectPatternNames(node.id, bump);
928
+ break;
929
+ case "FunctionDeclaration":
930
+ case "FunctionExpression":
931
+ case "ArrowFunctionExpression":
932
+ bumpId(node.id);
933
+ for (const param of node.params ?? []) collectPatternNames(param, bump);
934
+ break;
935
+ case "ClassDeclaration":
936
+ case "ClassExpression":
937
+ bumpId(node.id);
938
+ break;
939
+ case "CatchClause":
940
+ collectPatternNames(node.param, bump);
941
+ break;
942
+ case "ImportSpecifier":
943
+ case "ImportDefaultSpecifier":
944
+ case "ImportNamespaceSpecifier":
945
+ bumpId(node.local);
946
+ break;
947
+ }
948
+ });
949
+ return counts;
950
+ }
951
+ /** Collects every identifier name bound by a (possibly destructured) binding pattern. */
952
+ function collectPatternNames(node, add) {
953
+ if (!node) return;
954
+ switch (node.type) {
955
+ case "Identifier":
956
+ add(node.name ?? "");
957
+ break;
958
+ case "ObjectPattern":
959
+ for (const property of node.properties ?? []) if (property.type === "RestElement") collectPatternNames(property.argument, add);
960
+ else collectPatternNames(property.value, add);
961
+ break;
962
+ case "ArrayPattern":
963
+ for (const element of node.elements ?? []) collectPatternNames(element ?? void 0, add);
964
+ break;
965
+ case "AssignmentPattern":
966
+ collectPatternNames(node.left, add);
967
+ break;
968
+ case "RestElement":
969
+ collectPatternNames(node.argument, add);
970
+ break;
971
+ case "TSParameterProperty":
972
+ collectPatternNames(node.parameter, add);
973
+ break;
974
+ }
975
+ }
976
+ function readStaticIdentifierJsxValue(attr, staticIdentifierValues) {
977
+ const value = attr.value;
978
+ const expr = value?.type === "JSXExpressionContainer" ? value.expression : null;
979
+ const name = expr?.type === "Identifier" ? expr.name : null;
980
+ return name ? staticIdentifierValues.get(name) : void 0;
981
+ }
982
+ const STATIC_LITERAL_NODE_TYPES = new Set([
983
+ "Literal",
984
+ "StringLiteral",
985
+ "NumericLiteral",
986
+ "BooleanLiteral"
987
+ ]);
988
+ function staticValueFromNode(node) {
989
+ if (!node || !STATIC_LITERAL_NODE_TYPES.has(node.type)) return;
990
+ const value = node.value;
991
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? value : void 0;
992
+ }
982
993
  function isElementConsumerProp(propName) {
983
994
  return !KNOWN_NON_ELEMENT_PROPS.has(propName) && !propName.startsWith("$");
984
995
  }