styled-components-to-stylex-codemod 0.0.56 → 0.0.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -384,7 +384,7 @@ await runTransform({
384
384
 
385
385
  ### Planning manual conversions
386
386
 
387
- `analyzeMigrationPlan` runs the codemod in analysis-only mode (it never writes files) and returns the bottom-up ordered list of files you must convert by hand — the genuine blockers the codemod can't convert — each with its consumer count, the exports to convert, how many files it unblocks, and the bail reasons. `formatMigrationPlan` renders it as a report (high-impact files first).
387
+ `analyzeMigrationPlan` runs the codemod in analysis-only mode (it never writes files) and returns the bottom-up ordered list of files you must convert by hand — the genuine blockers the codemod can't convert — each with its consumer count, the exports to convert, direct auto-migration payoff, secondary blocker-chain context, and the bail reasons. `formatMigrationPlan` renders it as a report with direct unlocks emphasized first so raw chain involvement is not mistaken for files unlocked by one blocker alone.
388
388
 
389
389
  ```ts
390
390
  import { analyzeMigrationPlan, formatMigrationPlan } from "styled-components-to-stylex-codemod";
@@ -1,7 +1,60 @@
1
1
  import { n as isTemplatePlaceholderInSelectorContext, r as PLACEHOLDER_RE } from "./selector-context-heuristic-Dptd93Xe.mjs";
2
- import path, { resolve } from "node:path";
2
+ import path, { relative, resolve } from "node:path";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { parse } from "@babel/parser";
5
+ //#region src/internal/utilities/ast-safety.ts
6
+ /**
7
+ * AST safety checks for null nodes and structural issues.
8
+ * Core concepts: recursive validation and error reporting.
9
+ */
10
+ /**
11
+ * `JSON.stringify` replacer that drops noisy AST positional metadata
12
+ * (`loc`/`tokens`/`comments`/`start`/`end`) and replaces circular references
13
+ * with `"[Circular]"`, so AST nodes can be serialized for logging or as a
14
+ * stable structural key. Create a fresh replacer per `stringify` call — it
15
+ * keeps per-serialization state.
16
+ */
17
+ function createAstSafeJsonReplacer() {
18
+ const seen = /* @__PURE__ */ new WeakSet();
19
+ return (key, value) => {
20
+ if (key === "loc" || key === "tokens" || key === "comments" || key === "start" || key === "end") return;
21
+ if (value && typeof value === "object") {
22
+ if (seen.has(value)) return "[Circular]";
23
+ seen.add(value);
24
+ }
25
+ return value;
26
+ };
27
+ }
28
+ /** AST node types whose `elements` array legitimately contains `null` (holes/elisions). */
29
+ const ARRAY_ELEMENT_HOLE_TYPES = new Set(["ArrayPattern", "ArrayExpression"]);
30
+ function assertNoNullNodesInArrays(node) {
31
+ const seen = /* @__PURE__ */ new WeakSet();
32
+ const visit = (cur, path, allowNulls) => {
33
+ if (cur === null || cur === void 0) return;
34
+ if (Array.isArray(cur)) {
35
+ for (let i = 0; i < cur.length; i++) {
36
+ if (cur[i] === null) {
37
+ if (!allowNulls) throw new Error(`Null AST node in array at ${path}[${i}]`);
38
+ continue;
39
+ }
40
+ visit(cur[i], `${path}[${i}]`, false);
41
+ }
42
+ return;
43
+ }
44
+ if (typeof cur !== "object") return;
45
+ const curObj = cur;
46
+ if (seen.has(curObj)) return;
47
+ seen.add(curObj);
48
+ const nodeType = cur.type;
49
+ const hasValidElementHoles = typeof nodeType === "string" && ARRAY_ELEMENT_HOLE_TYPES.has(nodeType);
50
+ for (const [k, v] of Object.entries(cur)) {
51
+ if (v === null) continue;
52
+ if (typeof v === "object") visit(v, `${path}.${k}`, hasValidElementHoles && k === "elements");
53
+ }
54
+ };
55
+ visit(node, "root", false);
56
+ }
57
+ //#endregion
5
58
  //#region src/internal/logger.ts
6
59
  /**
7
60
  * Logger and warning types for transform diagnostics.
@@ -132,20 +185,9 @@ var Logger = class Logger {
132
185
  }
133
186
  static formatContext(context) {
134
187
  if (typeof context === "undefined") return null;
135
- return JSON.stringify(context, createContextReplacer(), 2);
188
+ return JSON.stringify(context, createAstSafeJsonReplacer(), 2);
136
189
  }
137
190
  };
138
- function createContextReplacer() {
139
- const seen = /* @__PURE__ */ new WeakSet();
140
- return (key, value) => {
141
- if (key === "loc" || key === "tokens" || key === "comments" || key === "start" || key === "end") return;
142
- if (value && typeof value === "object") {
143
- if (seen.has(value)) return "[Circular]";
144
- seen.add(value);
145
- }
146
- return value;
147
- };
148
- }
149
191
  const MAX_DEPENDED_FILE_GROUPS = 15;
150
192
  var LoggerReport = class {
151
193
  warnings;
@@ -785,6 +827,31 @@ function isCssTag(tag, cssImportNames) {
785
827
  if (!tag || !cssImportNames || cssImportNames.size === 0) return false;
786
828
  return tag.type === "Identifier" && typeof tag.name === "string" && cssImportNames.has(tag.name);
787
829
  }
830
+ /**
831
+ * Build the shared `DEBUG_CODEMOD` report lines for cross-file prepass info.
832
+ * `header` distinguishes the standalone scan from the unified prepass; callers
833
+ * may append their own sections before writing.
834
+ */
835
+ function buildCrossFileDebugLines(header, scannedFiles, info) {
836
+ const cwd = process.cwd();
837
+ const rel = (p) => relative(cwd, p);
838
+ const lines = [header];
839
+ lines.push(` Scanned ${scannedFiles.length} file(s)`);
840
+ if (info.selectorUsages.size === 0) lines.push(" No cross-file selector usages found.");
841
+ else {
842
+ lines.push(` Found cross-file selector usages in ${info.selectorUsages.size} file(s):`);
843
+ for (const [consumer, usages] of info.selectorUsages) for (const u of usages) lines.push(` ${rel(consumer)} → ${u.importedName} (from ${rel(u.resolvedPath)}, transformed=${u.consumerIsTransformed})`);
844
+ }
845
+ if (info.componentsNeedingMarkerSidecar.size > 0) {
846
+ lines.push(" Components needing marker sidecar (both consumer and target transformed):");
847
+ for (const [file, names] of info.componentsNeedingMarkerSidecar) lines.push(` ${rel(file)}: ${[...names].join(", ")}`);
848
+ }
849
+ if (info.componentsNeedingGlobalSelectorBridge.size > 0) {
850
+ lines.push(" Components needing global selector bridge className (consumer not transformed):");
851
+ for (const [file, names] of info.componentsNeedingGlobalSelectorBridge) lines.push(` ${rel(file)}: ${[...names].join(", ")}`);
852
+ }
853
+ return lines;
854
+ }
788
855
  /** Safely extract the name string from an AST identifier-like node. */
789
856
  function getNodeName(node) {
790
857
  if (!node || typeof node !== "object") return;
@@ -811,22 +878,6 @@ function deduplicateAndResolve(filesToTransform, consumerPaths) {
811
878
  return result;
812
879
  }
813
880
  //#endregion
814
- //#region src/internal/utilities/default-export-name.ts
815
- /**
816
- * Regex helpers for inspecting a module's default export by source text.
817
- *
818
- * These operate on raw source strings (not the AST) so they can be shared by
819
- * both prepass and transform-step layers without import-graph coupling.
820
- */
821
- /**
822
- * Returns the local name of a PascalCase default export, supporting both
823
- * `export default Name` and `export { Name as default }` forms. Returns
824
- * `undefined` when no PascalCase default export is found.
825
- */
826
- function findDefaultExportedLocalName(source) {
827
- 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];
828
- }
829
- //#endregion
830
881
  //#region src/internal/utilities/ast-walk.ts
831
882
  const SKIPPED_KEYS = new Set([
832
883
  "loc",
@@ -852,4 +903,4 @@ function walkAst(root, visitor) {
852
903
  visit(root);
853
904
  }
854
905
  //#endregion
855
- export { PARTIAL_MIGRATION_INCOMPLETE_WARNING as C, Logger as S, getCascadeDependedFilePath as T, findImportSource as _, buildImportMapFromNodes as a, resolveBarrelReExportBinding as b, deduplicateAndResolve as c, findStyledImportNameFromNodes as d, walkForImportsAndTemplates as f, fileImportsFrom as g, fileExports as h, applyBridgeFields as i, findComponentSelectorLocalsFromNodes as l, createPrepassParser as m, findDefaultExportedLocalName as n, categorizeSelectorUsages as o, addToSetMap as p, BARE_TEMPLATE_IDENTIFIER_RE as r, collectStyledLocalBindingNames as s, walkAst as t, findCssImportNamesFromNodes as u, getReExportedSourceName as v, UNSUPPORTED_SHOULD_FORWARD_PROP_WARNING as w, CASCADE_CONFLICT_WARNING as x, resolveBarrelReExport as y };
906
+ export { PARTIAL_MIGRATION_INCOMPLETE_WARNING as C, createAstSafeJsonReplacer as D, assertNoNullNodesInArrays as E, Logger as S, getCascadeDependedFilePath as T, findImportSource as _, buildImportMapFromNodes as a, resolveBarrelReExportBinding as b, deduplicateAndResolve as c, findStyledImportNameFromNodes as d, walkForImportsAndTemplates as f, fileImportsFrom as g, fileExports as h, buildCrossFileDebugLines as i, findComponentSelectorLocalsFromNodes as l, createPrepassParser as m, BARE_TEMPLATE_IDENTIFIER_RE as n, categorizeSelectorUsages as o, addToSetMap as p, applyBridgeFields as r, collectStyledLocalBindingNames as s, walkAst as t, findCssImportNamesFromNodes as u, getReExportedSourceName as v, UNSUPPORTED_SHOULD_FORWARD_PROP_WARNING as w, CASCADE_CONFLICT_WARNING as x, resolveBarrelReExport as y };
@@ -1,6 +1,6 @@
1
1
  import { t as isSelectorContext } from "./selector-context-heuristic-Dptd93Xe.mjs";
2
- import { r as toRealPath } from "./path-utils-ByFNVtHo.mjs";
3
- import { r as escapeRegex } from "./string-utils-4eeXGa48.mjs";
2
+ import { r as toRealPath } from "./path-utils-BC4U8X_q.mjs";
3
+ import { r as escapeRegex } from "./string-utils-Bo3cWgss.mjs";
4
4
  import { readFileSync } from "node:fs";
5
5
  //#region src/internal/bridge-consumer-patcher.ts
6
6
  /**
@@ -1,5 +1,5 @@
1
- import { r as toRealPath } from "./path-utils-ByFNVtHo.mjs";
2
- import { r as escapeRegex } from "./string-utils-4eeXGa48.mjs";
1
+ import { r as toRealPath } from "./path-utils-BC4U8X_q.mjs";
2
+ import { r as escapeRegex } from "./string-utils-Bo3cWgss.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-BGGNjb8R.mjs";
1
+ import { a as ImportSource, i as AdapterInput, o as MarkerFileContext, s as defineAdapter, t as CollectedWarning } from "./logger-ByYsVkrB.mjs";
2
2
 
3
3
  //#region src/run.d.ts
4
4
  interface RunTransformOptions {
@@ -69,17 +69,6 @@ interface RunTransformOptions {
69
69
  * @default false
70
70
  */
71
71
  silent?: boolean;
72
- /**
73
- * Controls which styled declarations are eligible for conversion.
74
- *
75
- * - `"all"` converts every supported styled declaration.
76
- * - `"leavesOnly"` only converts declarations whose render base is intrinsic
77
- * after adapter resolution, or that wrap another leaf styled declaration in
78
- * the transform run (including cross-file imports).
79
- *
80
- * @default "all"
81
- */
82
- transformMode?: TransformMode;
83
72
  /**
84
73
  * When true, allow the codemod to leave individual styled declarations as-is when
85
74
  * they hit an unsupported pattern while transforming the rest of the file. This
package/dist/index.mjs CHANGED
@@ -1,14 +1,173 @@
1
1
  import { t as createModuleResolver } from "./resolve-imports-DgSAddIF.mjs";
2
- import { $ as describeValue, Q as assertValidAdapterInput, Y as defineAdapter, q as mergeMarkerDeclarations, t as transformedComponentAcceptsSx, x as identifierName } from "./sx-surface-_Hjc6ZDq.mjs";
3
- import { S as Logger, T as getCascadeDependedFilePath, a as buildImportMapFromNodes, b as resolveBarrelReExportBinding, f as walkForImportsAndTemplates, m as createPrepassParser, t as walkAst, y as resolveBarrelReExport } from "./ast-walk-CLvMH7Lm.mjs";
4
- import { n as extractStyledDefBases } from "./compute-leaf-set-D5GvkV-H.mjs";
5
- import { r as toRealPath } from "./path-utils-ByFNVtHo.mjs";
2
+ import { $ as assertValidAdapterInput, J as mergeMarkerDeclarations, X as defineAdapter, et as describeValue, t as transformedComponentAcceptsSx, x as identifierName } from "./sx-surface-Kv8zK8L4.mjs";
3
+ import { S as Logger, T as getCascadeDependedFilePath, a as buildImportMapFromNodes, b as resolveBarrelReExportBinding, f as walkForImportsAndTemplates, m as createPrepassParser, s as collectStyledLocalBindingNames, t as walkAst, y as resolveBarrelReExport } from "./ast-walk-DVmYZ2mK.mjs";
4
+ import { r as toRealPath } from "./path-utils-BC4U8X_q.mjs";
6
5
  import jscodeshift from "jscodeshift";
7
6
  import { fileURLToPath, pathToFileURL } from "node:url";
8
7
  import { dirname, join, relative, resolve } from "node:path";
9
8
  import { existsSync, readFileSync } from "node:fs";
10
9
  import { glob, readFile, writeFile } from "node:fs/promises";
11
10
  import { spawn } from "node:child_process";
11
+ //#region src/internal/prepass/styled-def-bases.ts
12
+ /**
13
+ * Extracts styled-component definition bases for prepass consumers that need
14
+ * component names and their root shape.
15
+ */
16
+ const RX_EXPORT_DECL = String.raw`(?:export\s+)?(?:const|let|var)\s+`;
17
+ /** `const Name = styled.tag` — intrinsic HTML/SVG tag member. */
18
+ const STYLED_INTRINSIC_MEMBER_RE = new RegExp(String.raw`\b${RX_EXPORT_DECL}([A-Z][A-Za-z0-9]*)\b[^=]*=\s*styled\.([a-z][a-zA-Z0-9]*)\b`, "g");
19
+ /** `const Name = styled("tag")` — intrinsic string tag. */
20
+ const STYLED_INTRINSIC_STRING_RE = new RegExp(String.raw`\b${RX_EXPORT_DECL}([A-Z][A-Za-z0-9]*)\b[^=]*=\s*styled\s*\(\s*["']([^"']+)["']`, "g");
21
+ /** `const Name = styled(Component)` — wraps another component identifier. */
22
+ const STYLED_COMPONENT_RE = new RegExp(String.raw`\b${RX_EXPORT_DECL}([A-Z][A-Za-z0-9]*)\b[^=]*=\s*styled\s*\(\s*([A-Z][A-Za-z0-9]*)\s*\)`, "g");
23
+ /**
24
+ * Regex-derived styled definition bases for files in the transform set.
25
+ * Later entries for the same component name overwrite earlier ones (rare).
26
+ */
27
+ function extractStyledDefBasesFromSource(filePath, source, into) {
28
+ let map = into.get(filePath);
29
+ if (!map) {
30
+ map = /* @__PURE__ */ new Map();
31
+ into.set(filePath, map);
32
+ }
33
+ STYLED_INTRINSIC_MEMBER_RE.lastIndex = 0;
34
+ for (const m of source.matchAll(STYLED_INTRINSIC_MEMBER_RE)) {
35
+ const name = m[1];
36
+ if (name) map.set(name, { kind: "intrinsic" });
37
+ }
38
+ STYLED_INTRINSIC_STRING_RE.lastIndex = 0;
39
+ for (const m of source.matchAll(STYLED_INTRINSIC_STRING_RE)) {
40
+ const name = m[1];
41
+ if (name) map.set(name, { kind: "intrinsic" });
42
+ }
43
+ STYLED_COMPONENT_RE.lastIndex = 0;
44
+ for (const m of source.matchAll(STYLED_COMPONENT_RE)) {
45
+ const name = m[1];
46
+ const ident = m[2];
47
+ if (name && ident) map.set(name, {
48
+ kind: "component",
49
+ ident
50
+ });
51
+ }
52
+ }
53
+ /**
54
+ * Regex baseline for styled defs, then an AST pass overrides/adds rows when the
55
+ * source parses. The AST pass understands aliased/named `styled` imports
56
+ * (`import { styled as sc }`) that the regexes (which assume the literal `styled`)
57
+ * miss, so callers that only ran the regex extractor under-report components.
58
+ */
59
+ function extractStyledDefBases(filePath, source, parser, into) {
60
+ extractStyledDefBasesFromSource(filePath, source, into);
61
+ try {
62
+ const ast = parser.parse(source);
63
+ const program = ast.program ?? ast;
64
+ const importNodes = [];
65
+ walkForImportsAndTemplates(program, importNodes, []);
66
+ extractStyledDefBasesFromAstProgram(filePath, program, collectStyledLocalBindingNames(importNodes), into);
67
+ } catch {}
68
+ }
69
+ /**
70
+ * AST-based extraction: understands `let`/`var`, export blocks, named `styled` imports,
71
+ * and `.attrs` / `.withConfig` chains before the tagged template.
72
+ * Results merge into `into`; bindings found here override regex entries for the same name.
73
+ */
74
+ function extractStyledDefBasesFromAstProgram(filePath, program, styledLocalNames, into) {
75
+ if (styledLocalNames.size === 0) return;
76
+ let map = into.get(filePath);
77
+ if (!map) {
78
+ map = /* @__PURE__ */ new Map();
79
+ into.set(filePath, map);
80
+ }
81
+ const body = program.body;
82
+ if (!body) return;
83
+ for (const stmt of body) walkStatement(stmt);
84
+ function walkStatement(stmt) {
85
+ if (stmt.type === "VariableDeclaration") {
86
+ for (const d of stmt.declarations ?? []) processDeclarator(d);
87
+ return;
88
+ }
89
+ if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) walkStatement(stmt.declaration);
90
+ }
91
+ function processDeclarator(decl) {
92
+ if (decl.type !== "VariableDeclarator") return;
93
+ const id = decl.id;
94
+ if (id.type !== "Identifier" || typeof id.name !== "string") return;
95
+ const tpl = findTaggedTemplate(unwrapInitializer(decl.init));
96
+ if (!tpl || tpl.type !== "TaggedTemplateExpression") return;
97
+ const base = classifyStyledTemplateTag(tpl.tag, styledLocalNames);
98
+ if (base) map.set(id.name, base);
99
+ }
100
+ }
101
+ function unwrapInitializer(node) {
102
+ let cur = node ?? void 0;
103
+ while (cur) {
104
+ if (cur.type === "TSAsExpression" || cur.type === "AsExpression") {
105
+ cur = cur.expression;
106
+ continue;
107
+ }
108
+ if (cur.type === "ParenthesizedExpression") {
109
+ cur = cur.expression;
110
+ continue;
111
+ }
112
+ return cur;
113
+ }
114
+ }
115
+ function findTaggedTemplate(node) {
116
+ const n = unwrapInitializer(node);
117
+ if (!n) return;
118
+ if (n.type === "TaggedTemplateExpression") return n;
119
+ }
120
+ /** Peel `.attrs` / `.withConfig` / nested calls down to `styled.div` or `styled(X)`. */
121
+ function peelStyledApplication(tag, styledNames) {
122
+ let cur = tag;
123
+ while (cur) {
124
+ if (cur.type === "CallExpression") {
125
+ const callee = cur.callee;
126
+ if (callee?.type === "MemberExpression") {
127
+ cur = callee;
128
+ continue;
129
+ }
130
+ if (callee?.type === "Identifier" && typeof callee.name === "string" && styledNames.has(callee.name)) return cur;
131
+ return null;
132
+ }
133
+ if (cur.type === "MemberExpression") {
134
+ const obj = cur.object;
135
+ if (obj?.type === "Identifier" && typeof obj.name === "string" && styledNames.has(obj.name)) return cur;
136
+ cur = obj;
137
+ continue;
138
+ }
139
+ break;
140
+ }
141
+ return null;
142
+ }
143
+ function classifyStyledTemplateTag(tag, styledNames) {
144
+ const root = peelStyledApplication(tag, styledNames);
145
+ if (!root) return null;
146
+ if (root.type === "MemberExpression") {
147
+ const obj = root.object;
148
+ const prop = root.property;
149
+ const objName = obj?.type === "Identifier" ? obj.name : void 0;
150
+ if (obj?.type !== "Identifier" || typeof objName !== "string" || !styledNames.has(objName)) return null;
151
+ const isComputed = Boolean(root.computed);
152
+ if (isComputed && prop?.type === "StringLiteral" && typeof prop.value === "string") return { kind: "intrinsic" };
153
+ if (!isComputed && prop?.type === "Identifier" && typeof prop.name === "string") return { kind: "intrinsic" };
154
+ return null;
155
+ }
156
+ if (root.type === "CallExpression") {
157
+ const callee = root.callee;
158
+ const arg0 = root.arguments?.[0];
159
+ const calleeName = callee?.type === "Identifier" ? callee.name : void 0;
160
+ if (callee?.type !== "Identifier" || typeof calleeName !== "string" || !styledNames.has(calleeName) || !arg0) return null;
161
+ if (arg0.type === "Identifier" && typeof arg0.name === "string") return {
162
+ kind: "component",
163
+ ident: arg0.name
164
+ };
165
+ if (arg0.type === "StringLiteral" && typeof arg0.value === "string") return { kind: "intrinsic" };
166
+ return null;
167
+ }
168
+ return null;
169
+ }
170
+ //#endregion
12
171
  //#region src/internal/prepass/resolve-static-members.ts
13
172
  /**
14
173
  * Resolves the underlying component name(s) a static member access like `Select.Option` refers to,
@@ -248,9 +407,6 @@ async function runTransform(options) {
248
407
  "Example: consumerPaths: \"src/**/*.tsx\" // scan for cross-file usage",
249
408
  "Example: consumerPaths: null // opt out"
250
409
  ].join("\n"));
251
- const transformModeRaw = options.transformMode;
252
- if (transformModeRaw !== void 0 && transformModeRaw !== "all" && transformModeRaw !== "leavesOnly") throw new Error(["runTransform(options): `transformMode` must be one of: \"all\", \"leavesOnly\".", `Received: transformMode=${describeValue(transformModeRaw)}`].join("\n"));
253
- const leavesOnly = options.transformMode === "leavesOnly";
254
410
  const { files, consumerPaths: consumerPathsOption, dryRun = false, print = false, parser = "tsx", formatterCommands, maxExamples } = options;
255
411
  if (maxExamples !== void 0) Logger.setMaxExamples(maxExamples);
256
412
  const adapterInput = options.adapter;
@@ -329,7 +485,7 @@ async function runTransform(options) {
329
485
  const { createModuleResolver } = await import("./resolve-imports-DgSAddIF.mjs").then((n) => n.n);
330
486
  const sharedResolver = createModuleResolver();
331
487
  filePaths = orderFilesByLocalImportDependencies(filePaths, sharedResolver, toRealPath);
332
- const { runPrepass } = await import("./run-prepass-BueJvYyf.mjs");
488
+ const { runPrepass } = await import("./run-prepass-CGL_ugPB.mjs");
333
489
  const absoluteFiles = filePaths.map((f) => resolve(f));
334
490
  const absoluteConsumers = consumerFilePaths.map((f) => resolve(f));
335
491
  let prepassResult;
@@ -342,9 +498,7 @@ async function runTransform(options) {
342
498
  resolver: sharedResolver,
343
499
  parserName: parser,
344
500
  createExternalInterface: adapterInput.externalInterface === "auto",
345
- enableAstCache: true,
346
- leavesOnly,
347
- resolveBaseComponent: adapterInput.resolveBaseComponent
501
+ enableAstCache: true
348
502
  });
349
503
  Logger.info(`Prepass: completed in ${formatElapsedSeconds(prepassStartedAt)}s\n`);
350
504
  } catch (err) {
@@ -356,8 +510,7 @@ async function runTransform(options) {
356
510
  componentsNeedingMarkerSidecar: /* @__PURE__ */ new Map(),
357
511
  componentsNeedingGlobalSelectorBridge: /* @__PURE__ */ new Map(),
358
512
  propUsageByFile: /* @__PURE__ */ new Map(),
359
- stylexComponentFiles: /* @__PURE__ */ new Map(),
360
- globalLeafKeys: leavesOnly ? /* @__PURE__ */ new Set() : void 0
513
+ stylexComponentFiles: /* @__PURE__ */ new Map()
361
514
  },
362
515
  consumerAnalysis: void 0,
363
516
  forwardedAsConsumers: /* @__PURE__ */ new Map(),
@@ -517,9 +670,7 @@ async function runTransform(options) {
517
670
  transformedComponents,
518
671
  transformedFileSources,
519
672
  transientPropRenames,
520
- allowPartialMigration: options.allowPartialMigration ?? (leavesOnly ? true : false),
521
- transformMode: leavesOnly ? "leavesOnly" : options.transformMode ?? "all",
522
- globalLeafKeys: crossFilePrepassResult.globalLeafKeys,
673
+ allowPartialMigration: options.allowPartialMigration ?? false,
523
674
  resolveModule: (fromFile, specifier) => sharedResolver.resolve(resolve(fromFile), specifier),
524
675
  runInBand: true,
525
676
  silent: options.silent ?? false
@@ -570,7 +721,7 @@ async function runTransform(options) {
570
721
  const result = await runTransformSequentially(transformModule, filePaths, runnerOptions);
571
722
  if (sidecarFiles.size > 0 && !dryRun) for (const [sidecarPath, content] of sidecarFiles) await writeFile(sidecarPath, mergeSidecarContent(sidecarPath, content), "utf-8");
572
723
  if (bridgeResults.size > 0 && !dryRun) {
573
- const { buildConsumerReplacements, patchConsumerFile } = await import("./bridge-consumer-patcher-B__X3jOg.mjs");
724
+ const { buildConsumerReplacements, patchConsumerFile } = await import("./bridge-consumer-patcher-jeeDUlId.mjs");
574
725
  const consumerReplacements = buildConsumerReplacements(crossFilePrepassResult.selectorUsages, bridgeResults, transformedFiles);
575
726
  const patchedFiles = [];
576
727
  for (const [consumerPath, replacements] of consumerReplacements) {
@@ -583,7 +734,7 @@ async function runTransform(options) {
583
734
  if (formatterCommands && patchedFiles.length > 0) await runFormatters(formatterCommands, patchedFiles);
584
735
  }
585
736
  if (prepassResult.forwardedAsConsumers.size > 0 && !dryRun) {
586
- const { buildForwardedAsReplacements, patchConsumerForwardedAs } = await import("./forwarded-as-consumer-patcher-Bs9ymhBa.mjs");
737
+ const { buildForwardedAsReplacements, patchConsumerForwardedAs } = await import("./forwarded-as-consumer-patcher-Do4PI4Qs.mjs");
587
738
  const forwardedAsReplacements = buildForwardedAsReplacements(prepassResult.forwardedAsConsumers, transformedFiles);
588
739
  const patchedFiles = [];
589
740
  for (const [consumerPath, entries] of forwardedAsReplacements) {
@@ -596,7 +747,7 @@ async function runTransform(options) {
596
747
  if (formatterCommands && patchedFiles.length > 0) await runFormatters(formatterCommands, patchedFiles);
597
748
  }
598
749
  if (transientPropRenames.size > 0 && !dryRun) {
599
- const { collectTransientPropPatches } = await import("./transient-prop-consumer-patcher-BDruM1OI.mjs");
750
+ const { collectTransientPropPatches } = await import("./transient-prop-consumer-patcher-D-iqO8-T.mjs");
600
751
  const patches = collectTransientPropPatches({
601
752
  transientPropRenames,
602
753
  consumerFilePaths: consumerFilePaths.map((p) => resolve(p)),
@@ -726,16 +877,10 @@ function createStandalonePrepassResult(prepass, filePath, transformedFiles, tran
726
877
  selectorUsages,
727
878
  componentsNeedingMarkerSidecar,
728
879
  componentsNeedingGlobalSelectorBridge,
729
- globalLeafKeys: getStandaloneGlobalLeafKeys(prepass.globalLeafKeys, standaloneFile),
730
880
  transformedFiles,
731
881
  transformedComponents
732
882
  };
733
883
  }
734
- function getStandaloneGlobalLeafKeys(globalLeafKeys, standaloneFile) {
735
- if (!globalLeafKeys) return;
736
- const filePrefix = `${standaloneFile}:`;
737
- return new Set([...globalLeafKeys].filter((key) => key.startsWith(filePrefix)));
738
- }
739
884
  function addSetMapEntry(map, key, value) {
740
885
  const values = map.get(key);
741
886
  if (values) {
@@ -950,7 +1095,10 @@ function formatMigrationPlan(plan) {
950
1095
  lines.push("Manual conversion plan");
951
1096
  lines.push("======================");
952
1097
  lines.push(`${manualConversionFiles.length} of ${totalFiles} file(s) need manual conversion.`);
953
- if (unlocksFileCount > 0) lines.push(`Focus on the ${priority.length} file(s) below — converting them unblocks ${unlocksFileCount} file(s) for automatic migration.`);
1098
+ if (unlocksFileCount > 0) {
1099
+ lines.push(`Focus on the ${priority.length} file(s) below. Direct payoff: converting all listed blockers lets ${unlocksFileCount} file(s) auto-migrate.`);
1100
+ lines.push(`Per-file "directly unlocks" counts are sole-blocker payoffs; chain context is secondary and may need other blockers or manual fixes too.`);
1101
+ }
954
1102
  lines.push("");
955
1103
  if (priority.length > 0) {
956
1104
  const positionByPath = new Map(priority.map((file, index) => [file.filePath, index + 1]));
@@ -1052,8 +1200,12 @@ function collectFocusPaths(files) {
1052
1200
  function appendFileEntry(lines, file, position, positionByPath) {
1053
1201
  lines.push(`${position}. ${file.filePath}`);
1054
1202
  const impact = [];
1055
- if (file.soleBlockerFileCount > 0) impact.push(`sole blocker for ${file.soleBlockerFileCount} file(s)`);
1056
- if (file.blockedFileCount > 0) impact.push(`in blocker chain for ${file.blockedFileCount} file(s)`);
1203
+ if (file.blockedFileCount > 0) impact.push(`directly unlocks ${file.soleBlockerFileCount} file(s)`);
1204
+ const chainOnlyFileCount = file.blockedFileCount - file.soleBlockerFileCount;
1205
+ if (chainOnlyFileCount > 0) {
1206
+ const prefix = file.soleBlockerFileCount > 0 ? "also " : "";
1207
+ impact.push(`chain context: ${chainOnlyFileCount} file(s) ${prefix}bail through this file but are not unlocked by it alone`);
1208
+ }
1057
1209
  if (file.consumerCount > 0) impact.push(`imported by ${file.consumerCount} file(s)`);
1058
1210
  if (impact.length > 0) lines.push(` → ${impact.join(" · ")}`);
1059
1211
  if (file.dependsOn.length > 0) {