@shriyanss/js-recon 1.3.1-beta.2 → 1.4.1-alpha.1

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/CLAUDE.md +50 -0
  3. package/README.md +1 -0
  4. package/build/cs_mast/index.js +122 -0
  5. package/build/cs_mast/index.js.map +1 -0
  6. package/build/globalConfig.js +2 -2
  7. package/build/globalConfig.js.map +1 -1
  8. package/build/index.js +32 -2
  9. package/build/index.js.map +1 -1
  10. package/build/lazyLoad/downloadLoadedJsUtil.js +6 -1
  11. package/build/lazyLoad/downloadLoadedJsUtil.js.map +1 -1
  12. package/build/lazyLoad/index.js +2 -1
  13. package/build/lazyLoad/index.js.map +1 -1
  14. package/build/lazyLoad/methodFilter.js +49 -0
  15. package/build/lazyLoad/methodFilter.js.map +1 -0
  16. package/build/lazyLoad/next_js/NextJsCrawler.js +12 -11
  17. package/build/lazyLoad/next_js/NextJsCrawler.js.map +1 -1
  18. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js +6 -1
  19. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js.map +1 -1
  20. package/build/lazyLoad/techDetect/checkNextJS.js +24 -15
  21. package/build/lazyLoad/techDetect/checkNextJS.js.map +1 -1
  22. package/build/lazyLoad/techDetect/checkSvelte.js +17 -0
  23. package/build/lazyLoad/techDetect/checkSvelte.js.map +1 -1
  24. package/build/lazyLoad/techDetect/index.js +11 -4
  25. package/build/lazyLoad/techDetect/index.js.map +1 -1
  26. package/build/map/vue_js/vue_resolveHttpClient.js +17 -2
  27. package/build/map/vue_js/vue_resolveHttpClient.js.map +1 -1
  28. package/build/map/vue_js/vue_resolveXhr.js +22 -2
  29. package/build/map/vue_js/vue_resolveXhr.js.map +1 -1
  30. package/build/refactor/index.js +126 -15
  31. package/build/refactor/index.js.map +1 -1
  32. package/build/refactor/next/helpers.js +214 -0
  33. package/build/refactor/next/helpers.js.map +1 -0
  34. package/build/refactor/next/index.js +40 -73
  35. package/build/refactor/next/index.js.map +1 -1
  36. package/build/refactor/next/transform.js +177 -0
  37. package/build/refactor/next/transform.js.map +1 -0
  38. package/build/refactor/next/validator.js +118 -0
  39. package/build/refactor/next/validator.js.map +1 -0
  40. package/build/refactor/react/helpers.js +93 -0
  41. package/build/refactor/react/helpers.js.map +1 -0
  42. package/build/refactor/react/index.js +186 -589
  43. package/build/refactor/react/index.js.map +1 -1
  44. package/build/refactor/react/library-classify.js +166 -0
  45. package/build/refactor/react/library-classify.js.map +1 -0
  46. package/build/refactor/react/transform.js +839 -0
  47. package/build/refactor/react/transform.js.map +1 -0
  48. package/build/refactor/react/validator.js +122 -0
  49. package/build/refactor/react/validator.js.map +1 -0
  50. package/build/run/index.js +13 -8
  51. package/build/run/index.js.map +1 -1
  52. package/build/utility/getChromiumPath.js +40 -0
  53. package/build/utility/getChromiumPath.js.map +1 -0
  54. package/build/utility/heap.js +42 -0
  55. package/build/utility/heap.js.map +1 -0
  56. package/build/utility/makeReq.js +11 -2
  57. package/build/utility/makeReq.js.map +1 -1
  58. package/package.json +3 -2
@@ -0,0 +1,839 @@
1
+ import _traverse from "@babel/traverse";
2
+ import _generator from "@babel/generator";
3
+ import * as t from "@babel/types";
4
+ import { tryExtractModuleExportsAssignment, tryExtractExportsAssignment, tryExtractRequireCall, buildModuleExportStatement, makeNamedExportStatement, } from "./helpers.js";
5
+ import { REACT_CANONICAL, JSX_RUNTIME_CANONICAL, REACT_DOM_CLIENT_CANONICAL, librarySource, } from "./library-classify.js";
6
+ const traverse = _traverse.default;
7
+ const generate = _generator.default;
8
+ /**
9
+ * Transforms a single webpack module function into an array of ES module statements.
10
+ *
11
+ * Four passes (all top-level only to avoid placing exports inside nested functions):
12
+ * 1. `<moduleParam>.exports = <rhs>` → `export * from` or `export default`
13
+ * 2. `<exportsParam>.<prop> = <rhs>` → named export (all modules with an exportsParam)
14
+ * 3. Hoist `var x = <requireParam>(N)` to static `import * as x from "./N.js"`
15
+ * 4. Replace remaining inline `<requireParam>(N)` calls with the hoisted name
16
+ */
17
+ export const transformModule = (mod) => {
18
+ const { fnPath, moduleParam, exportsParam, requireParam } = mod;
19
+ const body = fnPath.node.body;
20
+ if (!t.isBlockStatement(body))
21
+ return [];
22
+ // Pass 1 — handle `<moduleParam>.exports = <rhs>` at the top level only.
23
+ if (moduleParam) {
24
+ const next = [];
25
+ for (const stmt of body.body) {
26
+ if (!t.isExpressionStatement(stmt)) {
27
+ next.push(stmt);
28
+ continue;
29
+ }
30
+ const expr = stmt.expression;
31
+ const directRhs = tryExtractModuleExportsAssignment(expr, moduleParam);
32
+ if (directRhs) {
33
+ next.push(buildModuleExportStatement(directRhs, requireParam));
34
+ continue;
35
+ }
36
+ if (t.isSequenceExpression(expr)) {
37
+ let hadMatch = false;
38
+ const splitted = [];
39
+ for (const sub of expr.expressions) {
40
+ const rhs = tryExtractModuleExportsAssignment(sub, moduleParam);
41
+ if (rhs) {
42
+ hadMatch = true;
43
+ splitted.push(buildModuleExportStatement(rhs, requireParam));
44
+ }
45
+ else {
46
+ splitted.push(t.expressionStatement(sub));
47
+ }
48
+ }
49
+ if (hadMatch) {
50
+ next.push(...splitted);
51
+ continue;
52
+ }
53
+ }
54
+ next.push(stmt);
55
+ }
56
+ body.body = next;
57
+ }
58
+ // Pass 2 — handle `<exportsParam>.<propName> = <rhs>` at the top level only.
59
+ if (exportsParam) {
60
+ const next = [];
61
+ for (const stmt of body.body) {
62
+ if (!t.isExpressionStatement(stmt)) {
63
+ next.push(stmt);
64
+ continue;
65
+ }
66
+ const expr = stmt.expression;
67
+ const direct = tryExtractExportsAssignment(expr, exportsParam);
68
+ if (direct) {
69
+ next.push(makeNamedExportStatement(direct.propName, direct.rhs));
70
+ continue;
71
+ }
72
+ if (t.isSequenceExpression(expr)) {
73
+ const splitted = [];
74
+ for (const sub of expr.expressions) {
75
+ const match = tryExtractExportsAssignment(sub, exportsParam);
76
+ if (match) {
77
+ splitted.push(makeNamedExportStatement(match.propName, match.rhs));
78
+ }
79
+ else {
80
+ splitted.push(t.expressionStatement(sub));
81
+ }
82
+ }
83
+ next.push(...splitted);
84
+ continue;
85
+ }
86
+ next.push(stmt);
87
+ }
88
+ body.body = next;
89
+ }
90
+ // Pass 3 — hoist top-level `var <name> = <requireParam>(N)` to static imports.
91
+ // moduleSpec → importName
92
+ const hoistedImports = new Map();
93
+ // numId → canonical importName (used by Pass 4 for inline replacements)
94
+ const importNameByNumId = new Map();
95
+ if (requireParam) {
96
+ const next = [];
97
+ for (const stmt of body.body) {
98
+ if (!t.isVariableDeclaration(stmt)) {
99
+ next.push(stmt);
100
+ continue;
101
+ }
102
+ const kept = [];
103
+ for (const decl of stmt.declarations) {
104
+ if (!t.isIdentifier(decl.id) || !decl.init) {
105
+ kept.push(decl);
106
+ continue;
107
+ }
108
+ const numId = tryExtractRequireCall(decl.init, requireParam);
109
+ if (numId === null) {
110
+ kept.push(decl);
111
+ continue;
112
+ }
113
+ const spec = `./${numId}.js`;
114
+ if (!hoistedImports.has(spec)) {
115
+ hoistedImports.set(spec, decl.id.name);
116
+ importNameByNumId.set(numId, decl.id.name);
117
+ }
118
+ // declarator removed (it becomes the static import)
119
+ }
120
+ if (kept.length > 0) {
121
+ next.push(t.variableDeclaration(stmt.kind, kept));
122
+ }
123
+ }
124
+ body.body = next;
125
+ }
126
+ // Pass 4 — replace any remaining inline `<requireParam>(N)` calls with a synthesized
127
+ // namespace import reference.
128
+ if (requireParam) {
129
+ fnPath.traverse({
130
+ CallExpression(p) {
131
+ const numId = tryExtractRequireCall(p.node, requireParam);
132
+ if (numId === null)
133
+ return;
134
+ let name = importNameByNumId.get(numId);
135
+ if (!name) {
136
+ name = `_jsr_module_${numId}`;
137
+ hoistedImports.set(`./${numId}.js`, name);
138
+ importNameByNumId.set(numId, name);
139
+ }
140
+ p.replaceWith(t.identifier(name));
141
+ p.skip();
142
+ },
143
+ });
144
+ }
145
+ // Step 5 — strip outer function wrapper, prepend hoisted static imports.
146
+ const importStmts = [];
147
+ for (const [spec, name] of hoistedImports) {
148
+ importStmts.push(t.importDeclaration([t.importNamespaceSpecifier(t.identifier(name))], t.stringLiteral(spec)));
149
+ }
150
+ return [...importStmts, ...body.body];
151
+ };
152
+ // Returns true when fn matches the webpack runtime require helper:
153
+ // function X(id) { … return (moduleMap[id](mod, mod.exports, X), mod.exports); }
154
+ // The key signal is the final return statement: a SequenceExpression whose first element
155
+ // is a computed-member CallExpression and whose second is a `<var>.exports` MemberExpression.
156
+ const isWebpackRequireHelper = (fn) => {
157
+ if (fn.params.length !== 1)
158
+ return false;
159
+ for (const stmt of fn.body.body) {
160
+ if (!t.isReturnStatement(stmt) || !stmt.argument)
161
+ continue;
162
+ const arg = stmt.argument;
163
+ if (!t.isSequenceExpression(arg) || arg.expressions.length !== 2)
164
+ continue;
165
+ const [first, second] = arg.expressions;
166
+ if (!t.isCallExpression(first))
167
+ continue;
168
+ if (!t.isMemberExpression(first.callee) || !first.callee.computed)
169
+ continue;
170
+ if (!t.isMemberExpression(second))
171
+ continue;
172
+ if (!t.isIdentifier(second.property, { name: "exports" }))
173
+ continue;
174
+ return true;
175
+ }
176
+ return false;
177
+ };
178
+ // ---------------------------------------------------------------------------
179
+ // Pass D helpers — library-aware call-site rewriting
180
+ // ---------------------------------------------------------------------------
181
+ /** Resolves the canonical name for an accessed property on a library-bound local var.
182
+ * Returns null if the var is not a known library or the prop has no canonical mapping. */
183
+ function resolveLibraryProp(varName, prop, varToLib) {
184
+ const info = varToLib.get(varName);
185
+ if (!info || info.type === "unknown")
186
+ return null;
187
+ // Helper: is this name actually a canonical export for this library type?
188
+ const isCanonical = (name) => {
189
+ if (info.type === "react")
190
+ return REACT_CANONICAL.has(name);
191
+ // Fragment is also exported by react/jsx-runtime but excluded from JSX_RUNTIME_CANONICAL
192
+ // (which is used only for module classification). Accept it explicitly here for rewriting.
193
+ if (info.type === "react-jsx-runtime")
194
+ return JSX_RUNTIME_CANONICAL.has(name) || name === "Fragment";
195
+ if (info.type === "react-dom-client")
196
+ return REACT_DOM_CLIENT_CANONICAL.has(name);
197
+ return false;
198
+ };
199
+ // Check exportMap: only trust the value if it IS a canonical name.
200
+ // (Avoids mapping e.g. n.jsx = i → canonical 'i' when i is just a local fn.)
201
+ const viaMap = info.exportMap.get(prop);
202
+ if (viaMap && isCanonical(viaMap))
203
+ return { canonical: viaMap, libType: info.type };
204
+ // Fall back to checking the prop name itself (handles cases where the exported
205
+ // property name is already the canonical name, e.g. n.jsx = <iife>).
206
+ if (isCanonical(prop))
207
+ return { canonical: prop, libType: info.type };
208
+ return null;
209
+ }
210
+ /** Extracts `varName` and `prop` from a `(0, varName.prop)` or `varName.prop` callee. */
211
+ function tryExtractMemberCallee(callee) {
212
+ // (0, X.Y) form
213
+ if (t.isSequenceExpression(callee) && callee.expressions.length === 2) {
214
+ const [first, second] = callee.expressions;
215
+ if (t.isNumericLiteral(first) && first.value === 0 && t.isMemberExpression(second)) {
216
+ const obj = second.object;
217
+ const prop = second.property;
218
+ if (t.isIdentifier(obj) && t.isIdentifier(prop) && !second.computed) {
219
+ return { varName: obj.name, prop: prop.name };
220
+ }
221
+ }
222
+ }
223
+ // X.Y form
224
+ if (t.isMemberExpression(callee) && !callee.computed) {
225
+ const obj = callee.object;
226
+ const prop = callee.property;
227
+ if (t.isIdentifier(obj) && t.isIdentifier(prop)) {
228
+ return { varName: obj.name, prop: prop.name };
229
+ }
230
+ }
231
+ return null;
232
+ }
233
+ /**
234
+ * Pass D – rewrite library calls and collect which named exports are needed.
235
+ *
236
+ * Traverses all statements; for every `(0, X.Y)(args)` or `X.Y(args)` where X is a
237
+ * known library local var, replaces the callee with the canonical identifier and records
238
+ * the needed named import. Also rewrites bare member expressions `X.Y` that are NOT in a
239
+ * call position (e.g. passed as a value to another function).
240
+ *
241
+ * Returns the set of named exports needed per library type so the caller can build
242
+ * proper `import { ... } from "..."` declarations.
243
+ */
244
+ function rewriteLibraryCalls(statements, varToLib) {
245
+ // libType → set of canonical export names actually used
246
+ const usedExports = new Map();
247
+ const record = (libType, name) => {
248
+ const src = librarySource(libType);
249
+ if (!src)
250
+ return;
251
+ if (!usedExports.has(src))
252
+ usedExports.set(src, new Set());
253
+ usedExports.get(src).add(name);
254
+ };
255
+ const syntheticFile = t.file(t.program(statements, [], "module"));
256
+ traverse(syntheticFile, {
257
+ CallExpression(p) {
258
+ const info = tryExtractMemberCallee(p.node.callee);
259
+ if (!info)
260
+ return;
261
+ const resolved = resolveLibraryProp(info.varName, info.prop, varToLib);
262
+ if (!resolved)
263
+ return;
264
+ record(resolved.libType, resolved.canonical);
265
+ // Replace (0, X.Y)(...) or X.Y(...) with canonicalName(...)
266
+ p.node.callee = t.identifier(resolved.canonical);
267
+ // Do NOT skip — arguments may contain further (0, X.Y)(...) or X.Y member refs.
268
+ },
269
+ MemberExpression(p) {
270
+ // Rewrite X.Y in non-call positions (e.g. passed as callback value)
271
+ if (p.parent && t.isCallExpression(p.parent) && p.parent.callee === p.node)
272
+ return; // handled above
273
+ const obj = p.node.object;
274
+ const prop = p.node.property;
275
+ if (!t.isIdentifier(obj) || !t.isIdentifier(prop) || p.node.computed)
276
+ return;
277
+ const resolved = resolveLibraryProp(obj.name, prop.name, varToLib);
278
+ if (!resolved)
279
+ return;
280
+ record(resolved.libType, resolved.canonical);
281
+ p.replaceWith(t.identifier(resolved.canonical));
282
+ p.skip();
283
+ },
284
+ });
285
+ return usedExports;
286
+ }
287
+ // ---------------------------------------------------------------------------
288
+ // Pass E — Babel slicedToArray collapse
289
+ // ---------------------------------------------------------------------------
290
+ /** Returns true if the last arm of a `||` chain is an IIFE that throws TypeError. */
291
+ function isSlicedToArrayTail(node) {
292
+ if (!t.isCallExpression(node) || node.arguments.length !== 0)
293
+ return false;
294
+ const callee = node.callee;
295
+ if (!t.isFunctionExpression(callee) && !t.isArrowFunctionExpression(callee))
296
+ return false;
297
+ const body = callee.body;
298
+ if (!t.isBlockStatement(body))
299
+ return false;
300
+ return body.body.some((s) => t.isThrowStatement(s) &&
301
+ t.isNewExpression(s.argument) &&
302
+ t.isIdentifier(s.argument.callee, { name: "TypeError" }));
303
+ }
304
+ function hasSlicedToArrayTail(node) {
305
+ if (isSlicedToArrayTail(node))
306
+ return true;
307
+ if (t.isLogicalExpression(node) && node.operator === "||")
308
+ return hasSlicedToArrayTail(node.right);
309
+ return false;
310
+ }
311
+ /**
312
+ * Tries to detect a `var <temps>, resultVar = (<seqExpr>), target0 = resultVar[0], ...`
313
+ * pattern produced by Babel's slicedToArray expansion.
314
+ *
315
+ * Returns `{ actualExpr, resultVar, targets }` on match, or null.
316
+ */
317
+ function tryDetectSlicedToArray(decl) {
318
+ let resultVar = null;
319
+ let actualExpr = null;
320
+ for (const d of decl.declarations) {
321
+ if (!d.init || !t.isSequenceExpression(d.init))
322
+ continue;
323
+ const exprs = d.init.expressions;
324
+ if (exprs.length < 3)
325
+ continue;
326
+ // exprs[0]: tempVar = <actualCall>
327
+ if (!t.isAssignmentExpression(exprs[0]) || exprs[0].operator !== "=")
328
+ continue;
329
+ const firstAssign = exprs[0];
330
+ if (!t.isIdentifier(firstAssign.left))
331
+ continue;
332
+ // exprs[1]: countVar = <number>
333
+ if (!t.isAssignmentExpression(exprs[1]) || !t.isNumericLiteral(exprs[1].right))
334
+ continue;
335
+ // last expr: the TypeError IIFE (possibly nested in || chain)
336
+ if (!hasSlicedToArrayTail(exprs[exprs.length - 1]))
337
+ continue;
338
+ resultVar = t.isIdentifier(d.id) ? d.id.name : null;
339
+ if (!resultVar)
340
+ continue;
341
+ actualExpr = firstAssign.right;
342
+ break;
343
+ }
344
+ if (!resultVar || !actualExpr)
345
+ return null;
346
+ const targets = [];
347
+ for (const d of decl.declarations) {
348
+ if (!d.init || !t.isMemberExpression(d.init))
349
+ continue;
350
+ if (!t.isIdentifier(d.init.object, { name: resultVar }))
351
+ continue;
352
+ if (!d.init.computed || !t.isNumericLiteral(d.init.property))
353
+ continue;
354
+ if (!t.isIdentifier(d.id))
355
+ continue;
356
+ targets.push({ id: d.id, index: d.init.property.value });
357
+ }
358
+ return targets.length > 0 ? { actualExpr, resultVar, targets } : null;
359
+ }
360
+ /** Collapse Babel slicedToArray expansions in a statement list (including nested blocks). */
361
+ function collapseSlicedToArray(statements) {
362
+ const out = [];
363
+ for (const stmt of statements) {
364
+ // Recurse into block statements (e.g. if/else, function bodies handled via traversal)
365
+ if (t.isBlockStatement(stmt)) {
366
+ stmt.body = collapseSlicedToArray(stmt.body);
367
+ out.push(stmt);
368
+ continue;
369
+ }
370
+ if (!t.isVariableDeclaration(stmt)) {
371
+ out.push(stmt);
372
+ continue;
373
+ }
374
+ const match = tryDetectSlicedToArray(stmt);
375
+ if (!match) {
376
+ out.push(stmt);
377
+ continue;
378
+ }
379
+ const { actualExpr, resultVar, targets } = match;
380
+ // Sort targets by index so array pattern elements are in order
381
+ const sorted = [...targets].sort((a, b) => a.index - b.index);
382
+ const pattern = t.arrayPattern(sorted.map((tgt) => tgt.id));
383
+ out.push(t.variableDeclaration("const", [t.variableDeclarator(pattern, actualExpr)]));
384
+ }
385
+ return out;
386
+ }
387
+ /** Traverse all function bodies in a statement list and collapse slicedToArray inside them. */
388
+ function collapseSlicedToArrayDeep(statements) {
389
+ // First collapse top-level
390
+ const top = collapseSlicedToArray(statements);
391
+ // Then recurse into function bodies via a traverse
392
+ const syntheticFile = t.file(t.program(top, [], "module"));
393
+ traverse(syntheticFile, {
394
+ BlockStatement(p) {
395
+ const collapsed = collapseSlicedToArray(p.node.body);
396
+ if (collapsed !== p.node.body) {
397
+ p.node.body = collapsed;
398
+ }
399
+ },
400
+ });
401
+ return top;
402
+ }
403
+ // ---------------------------------------------------------------------------
404
+ // Pass F — JSX recovery
405
+ // ---------------------------------------------------------------------------
406
+ function exprToJsxName(expr) {
407
+ if (t.isStringLiteral(expr))
408
+ return t.jsxIdentifier(expr.value);
409
+ if (t.isIdentifier(expr))
410
+ return t.jsxIdentifier(expr.name);
411
+ if (t.isMemberExpression(expr) && !expr.computed && t.isIdentifier(expr.property)) {
412
+ const obj = exprToJsxName(expr.object);
413
+ if (obj)
414
+ return t.jsxMemberExpression(obj, t.jsxIdentifier(expr.property.name));
415
+ }
416
+ return null;
417
+ }
418
+ function exprToJsxAttrValue(expr) {
419
+ if (t.isStringLiteral(expr))
420
+ return expr;
421
+ return t.jsxExpressionContainer(expr);
422
+ }
423
+ function childToJsxChild(child) {
424
+ if (t.isStringLiteral(child))
425
+ return t.jsxText(child.value);
426
+ if (t.isJSXElement(child) || t.isJSXFragment(child))
427
+ return child;
428
+ // Recursively convert nested jsx(...) calls into JSX elements.
429
+ if (t.isCallExpression(child)) {
430
+ const converted = tryConvertToJSX(child);
431
+ if (converted)
432
+ return converted;
433
+ }
434
+ return t.jsxExpressionContainer(child);
435
+ }
436
+ function tryConvertToJSX(call) {
437
+ const callee = call.callee;
438
+ if (!t.isIdentifier(callee))
439
+ return null;
440
+ if (callee.name !== "jsx" && callee.name !== "jsxs" && callee.name !== "jsxDEV")
441
+ return null;
442
+ if (call.arguments.length < 2)
443
+ return null;
444
+ const tagArg = call.arguments[0];
445
+ const propsArg = call.arguments[1];
446
+ const jsxName = exprToJsxName(tagArg);
447
+ if (!jsxName)
448
+ return null;
449
+ const attrs = [];
450
+ const children = [];
451
+ if (t.isObjectExpression(propsArg)) {
452
+ for (const prop of propsArg.properties) {
453
+ if (!t.isObjectProperty(prop) || prop.computed)
454
+ continue;
455
+ const keyNode = prop.key;
456
+ const valNode = prop.value;
457
+ const keyName = t.isIdentifier(keyNode) ? keyNode.name : t.isStringLiteral(keyNode) ? keyNode.value : null;
458
+ if (!keyName)
459
+ continue;
460
+ if (keyName === "children") {
461
+ // children can be a single value or an array
462
+ if (t.isArrayExpression(valNode)) {
463
+ for (const el of valNode.elements) {
464
+ if (!el)
465
+ continue;
466
+ const ch = childToJsxChild(el);
467
+ if (ch)
468
+ children.push(ch);
469
+ }
470
+ }
471
+ else {
472
+ const ch = childToJsxChild(valNode);
473
+ if (ch)
474
+ children.push(ch);
475
+ }
476
+ continue;
477
+ }
478
+ // Normal prop
479
+ const attrName = t.jsxIdentifier(keyName);
480
+ if (t.isJSXExpressionContainer(valNode) || t.isStringLiteral(valNode)) {
481
+ attrs.push(t.jsxAttribute(attrName, exprToJsxAttrValue(valNode)));
482
+ }
483
+ else {
484
+ attrs.push(t.jsxAttribute(attrName, exprToJsxAttrValue(valNode)));
485
+ }
486
+ }
487
+ }
488
+ const selfClosing = children.length === 0;
489
+ const openingElement = t.jsxOpeningElement(jsxName, attrs, selfClosing);
490
+ const closingElement = selfClosing ? null : t.jsxClosingElement(jsxName);
491
+ return t.jsxElement(openingElement, closingElement, children, selfClosing);
492
+ }
493
+ /** Traverse statements and replace jsx()/jsxs() calls with JSXElement nodes. */
494
+ function recoverJSX(statements) {
495
+ const syntheticFile = t.file(t.program(statements, [], "module"));
496
+ traverse(syntheticFile, {
497
+ CallExpression(p) {
498
+ const jsxEl = tryConvertToJSX(p.node);
499
+ if (!jsxEl)
500
+ return;
501
+ p.replaceWith(jsxEl);
502
+ p.skip();
503
+ },
504
+ });
505
+ }
506
+ // ---------------------------------------------------------------------------
507
+ // Pass G — remove top-level Babel helpers and webpack internals
508
+ // ---------------------------------------------------------------------------
509
+ function isBabelArrayLikeToArrayHelper(stmt) {
510
+ if (!t.isFunctionDeclaration(stmt) || !stmt.id)
511
+ return false;
512
+ const body = stmt.body.body;
513
+ if (body.length < 2 || body.length > 4)
514
+ return false;
515
+ // Key signal: contains `for (var ... = Array(n); ...)` and a return of the array
516
+ const hasArrayOf = body.some((s) => {
517
+ if (!t.isForStatement(s))
518
+ return false;
519
+ const init = s.init;
520
+ if (!t.isVariableDeclaration(init))
521
+ return false;
522
+ return init.declarations.some((d) => d.init &&
523
+ t.isCallExpression(d.init) &&
524
+ t.isIdentifier(d.init.callee, { name: "Array" }));
525
+ });
526
+ return hasArrayOf;
527
+ }
528
+ // Detect `_typeof` — Babel's lazy-init typeof polyfill.
529
+ // Shape: 1-param function whose sole body statement is
530
+ // return ((fnName = <conditional>), fnName(arg))
531
+ function isBabelTypeofHelper(stmt) {
532
+ if (!t.isFunctionDeclaration(stmt) || !stmt.id || stmt.params.length !== 1)
533
+ return false;
534
+ const body = stmt.body.body;
535
+ if (body.length !== 1 || !t.isReturnStatement(body[0]))
536
+ return false;
537
+ const arg = body[0].argument;
538
+ if (!arg || !t.isSequenceExpression(arg))
539
+ return false;
540
+ const exprs = arg.expressions;
541
+ if (exprs.length !== 2)
542
+ return false;
543
+ const first = exprs[0];
544
+ return (t.isAssignmentExpression(first) &&
545
+ t.isIdentifier(first.left, { name: stmt.id.name }));
546
+ }
547
+ // Detect `_defineProperty` / `_toPropertyKey`+`_defineProperty` combos.
548
+ // Shape: 3-param function whose body contains an Object.defineProperty call with
549
+ // { value, enumerable, configurable, writable } descriptor.
550
+ function isBabelDefinePropertyHelper(stmt) {
551
+ if (!t.isFunctionDeclaration(stmt) || !stmt.id || stmt.params.length !== 3)
552
+ return false;
553
+ const bodyCode = stmt.body.body;
554
+ const hasDefProp = (node) => {
555
+ if (t.isCallExpression(node) &&
556
+ t.isMemberExpression(node.callee) &&
557
+ t.isIdentifier(node.callee.object, { name: "Object" }) &&
558
+ t.isIdentifier(node.callee.property, {
559
+ name: "defineProperty",
560
+ })) {
561
+ const args = node.arguments;
562
+ if (args.length >= 3 && t.isObjectExpression(args[2])) {
563
+ const props = args[2].properties;
564
+ const keys = props
565
+ .filter((p) => t.isObjectProperty(p) && t.isIdentifier(p.key))
566
+ .map((p) => p.key.name);
567
+ return keys.includes("enumerable") && keys.includes("configurable") && keys.includes("writable");
568
+ }
569
+ }
570
+ return false;
571
+ };
572
+ // Walk statements for the defineProperty call (may be nested in return/conditional)
573
+ const walk = (node) => {
574
+ if (hasDefProp(node))
575
+ return true;
576
+ for (const key of Object.keys(node)) {
577
+ const child = node[key];
578
+ if (!child || typeof child !== "object")
579
+ continue;
580
+ if (Array.isArray(child)) {
581
+ if (child.some((c) => c && typeof c === "object" && "type" in c && walk(c)))
582
+ return true;
583
+ }
584
+ else if ("type" in child) {
585
+ if (walk(child))
586
+ return true;
587
+ }
588
+ }
589
+ return false;
590
+ };
591
+ return bodyCode.some((s) => walk(s));
592
+ }
593
+ // Detect `_objectSpreadPropsHelper` / `_objectKeys`.
594
+ // Shape: 2-param function whose first statement declares a variable via Object.keys(param0)
595
+ // and whose body references getOwnPropertySymbols.
596
+ function isBabelObjectSpreadHelper(stmt) {
597
+ if (!t.isFunctionDeclaration(stmt) || !stmt.id || stmt.params.length !== 2)
598
+ return false;
599
+ const body = stmt.body.body;
600
+ if (body.length < 2)
601
+ return false;
602
+ // First statement: var t = Object.keys(e)
603
+ const first = body[0];
604
+ if (!t.isVariableDeclaration(first))
605
+ return false;
606
+ const firstIsObjectKeys = first.declarations.some((d) => {
607
+ if (!d.init || !t.isCallExpression(d.init))
608
+ return false;
609
+ const callee = d.init.callee;
610
+ return (t.isMemberExpression(callee) &&
611
+ t.isIdentifier(callee.object, { name: "Object" }) &&
612
+ t.isIdentifier(callee.property, { name: "keys" }));
613
+ });
614
+ if (!firstIsObjectKeys)
615
+ return false;
616
+ // Body references getOwnPropertySymbols
617
+ const bodyStr = JSON.stringify(body);
618
+ return bodyStr.includes('"getOwnPropertySymbols"');
619
+ }
620
+ /** Remove `var x = {}` declarations where every declarator has an empty-object init.
621
+ * These are webpack module-cache variables. */
622
+ function dropEmptyObjectVars(stmts) {
623
+ return stmts.filter((stmt) => {
624
+ if (!t.isVariableDeclaration(stmt))
625
+ return true;
626
+ return !stmt.declarations.every((d) => d.init && t.isObjectExpression(d.init) && d.init.properties.length === 0);
627
+ });
628
+ }
629
+ // ---------------------------------------------------------------------------
630
+ // Pass H — prune unused named imports (e.g. jsx/jsxs after JSX recovery)
631
+ // ---------------------------------------------------------------------------
632
+ /** Collect all free identifier references in the given statements. */
633
+ function collectReferencedNames(stmts) {
634
+ const names = new Set();
635
+ const syntheticFile = t.file(t.program(stmts, [], "module"));
636
+ traverse(syntheticFile, {
637
+ Identifier(p) {
638
+ var _a, _b, _c, _d, _e, _f, _g, _h;
639
+ // Skip identifier nodes that are property names or binding declarations
640
+ if ((_a = p.parentPath) === null || _a === void 0 ? void 0 : _a.isImportSpecifier())
641
+ return;
642
+ if ((_b = p.parentPath) === null || _b === void 0 ? void 0 : _b.isImportDefaultSpecifier())
643
+ return;
644
+ if ((_c = p.parentPath) === null || _c === void 0 ? void 0 : _c.isImportNamespaceSpecifier())
645
+ return;
646
+ if (((_d = p.parentPath) === null || _d === void 0 ? void 0 : _d.isMemberExpression()) &&
647
+ !p.parent.computed &&
648
+ p.parentPath.get("property") === p)
649
+ return;
650
+ if (((_e = p.parentPath) === null || _e === void 0 ? void 0 : _e.isObjectProperty()) &&
651
+ !p.parent.computed &&
652
+ p.parentPath.get("key") === p)
653
+ return;
654
+ if ((_f = p.parentPath) === null || _f === void 0 ? void 0 : _f.isJSXAttribute())
655
+ return;
656
+ if (((_g = p.parentPath) === null || _g === void 0 ? void 0 : _g.isJSXOpeningElement()) || ((_h = p.parentPath) === null || _h === void 0 ? void 0 : _h.isJSXClosingElement()))
657
+ return;
658
+ names.add(p.node.name);
659
+ },
660
+ JSXIdentifier(p) {
661
+ // JSX element names (e.g. <Fragment>) are JSXIdentifier nodes, not Identifier.
662
+ // Add them so their import specifiers survive Pass H pruning.
663
+ names.add(p.node.name);
664
+ },
665
+ });
666
+ return names;
667
+ }
668
+ /** Remove named import specifiers whose local name is not referenced in `bodyStmts`. */
669
+ function pruneUnusedNamedImports(importStmts, bodyStmts) {
670
+ const refs = collectReferencedNames(bodyStmts);
671
+ return importStmts
672
+ .map((stmt) => {
673
+ if (!t.isImportDeclaration(stmt))
674
+ return stmt;
675
+ const prunedSpecifiers = stmt.specifiers.filter((spec) => {
676
+ if (t.isImportNamespaceSpecifier(spec))
677
+ return true; // always keep namespace imports
678
+ if (t.isImportDefaultSpecifier(spec))
679
+ return true;
680
+ if (t.isImportSpecifier(spec)) {
681
+ const localName = t.isIdentifier(spec.local) ? spec.local.name : null;
682
+ return localName ? refs.has(localName) : true;
683
+ }
684
+ return true;
685
+ });
686
+ if (prunedSpecifiers.length === 0)
687
+ return null; // drop empty imports
688
+ if (prunedSpecifiers.length === stmt.specifiers.length)
689
+ return stmt; // unchanged
690
+ return t.importDeclaration(prunedSpecifiers, stmt.source);
691
+ })
692
+ .filter(Boolean);
693
+ }
694
+ // ---------------------------------------------------------------------------
695
+ // Main export
696
+ // ---------------------------------------------------------------------------
697
+ /**
698
+ * Transforms the non-module-map IIFE statements that become `index.js`.
699
+ *
700
+ * Passes:
701
+ * A – Remove webpack require helper function.
702
+ * B – Hoist top-level `var x = requireFn(N)` to static `import * as x from "./N.js"`.
703
+ * C – Replace remaining inline `requireFn(N)` calls.
704
+ * D – Rewrite library module calls using identity map (e.g. `l.H(...)` → `createRoot(...)`)
705
+ * and replace namespace imports with named imports from proper library paths.
706
+ * E – Collapse Babel slicedToArray expansions to `const [a, b] = expr`.
707
+ * F – Recover JSX from `jsx(tag, props)` / `jsxs(tag, props)` calls.
708
+ * G – Remove Babel array-helper functions (e.g. `arrayLikeToArray`).
709
+ */
710
+ export const transformIndexStatements = (statements, libModuleMap) => {
711
+ // Pass A — detect and remove webpack require helper(s).
712
+ const requireFnNames = new Set();
713
+ const afterA = [];
714
+ for (const stmt of statements) {
715
+ if (t.isFunctionDeclaration(stmt) && stmt.id && isWebpackRequireHelper(stmt)) {
716
+ requireFnNames.add(stmt.id.name);
717
+ continue; // drop
718
+ }
719
+ afterA.push(stmt);
720
+ }
721
+ if (requireFnNames.size === 0)
722
+ return statements; // nothing to do
723
+ const hoistedImports = new Map();
724
+ const importNameByNumId = new Map();
725
+ // Pass B — hoist top-level `var x = requireFn(N)` to static imports.
726
+ // Also build varName → moduleId so Pass D can look up library identity.
727
+ const varToModuleId = new Map(); // localVarName → numericModuleId
728
+ const afterB = [];
729
+ for (const stmt of afterA) {
730
+ if (!t.isVariableDeclaration(stmt)) {
731
+ afterB.push(stmt);
732
+ continue;
733
+ }
734
+ const kept = [];
735
+ for (const decl of stmt.declarations) {
736
+ if (!t.isIdentifier(decl.id) || !decl.init) {
737
+ kept.push(decl);
738
+ continue;
739
+ }
740
+ let matched = false;
741
+ for (const fnName of requireFnNames) {
742
+ const numId = tryExtractRequireCall(decl.init, fnName);
743
+ if (numId === null)
744
+ continue;
745
+ const spec = `./${numId}.js`;
746
+ const localName = decl.id.name;
747
+ if (!hoistedImports.has(spec)) {
748
+ hoistedImports.set(spec, localName);
749
+ importNameByNumId.set(numId, localName);
750
+ }
751
+ varToModuleId.set(localName, numId);
752
+ matched = true;
753
+ break;
754
+ }
755
+ if (!matched)
756
+ kept.push(decl);
757
+ }
758
+ if (kept.length > 0)
759
+ afterB.push(t.variableDeclaration(stmt.kind, kept));
760
+ }
761
+ // Pass C — replace remaining inline requireFn(N) calls recursively.
762
+ const syntheticFile = t.file(t.program(afterB, [], "module"));
763
+ traverse(syntheticFile, {
764
+ CallExpression(p) {
765
+ for (const fnName of requireFnNames) {
766
+ const numId = tryExtractRequireCall(p.node, fnName);
767
+ if (numId === null)
768
+ continue;
769
+ let name = importNameByNumId.get(numId);
770
+ if (!name) {
771
+ name = `_jsr_module_${numId}`;
772
+ hoistedImports.set(`./${numId}.js`, name);
773
+ importNameByNumId.set(numId, name);
774
+ }
775
+ p.replaceWith(t.identifier(name));
776
+ p.skip();
777
+ break;
778
+ }
779
+ },
780
+ });
781
+ // Pass D — library-aware import rewriting (only when libModuleMap is supplied).
782
+ // Build varName → LibraryModuleInfo, then rewrite calls and imports.
783
+ const finalImportStmts = [];
784
+ if (libModuleMap && libModuleMap.size > 0) {
785
+ // Map local var names to their library identity
786
+ const varToLib = new Map();
787
+ for (const [varName, numId] of varToModuleId) {
788
+ const info = libModuleMap.get(String(numId));
789
+ if (info)
790
+ varToLib.set(varName, info);
791
+ }
792
+ if (varToLib.size > 0) {
793
+ // Rewrite call-sites; collect which named exports are actually used
794
+ const usedExports = rewriteLibraryCalls(afterB, varToLib);
795
+ // Build import declarations for library modules (named imports).
796
+ // handledSpecs guards only the import-declaration emit (avoid duplicates when
797
+ // two local vars map to the same library source). The namespace-import deletion
798
+ // must happen for EVERY var that maps to a library, regardless of dedup.
799
+ const handledSpecs = new Set();
800
+ for (const [varName, info] of varToLib) {
801
+ const src = librarySource(info.type);
802
+ if (!src)
803
+ continue;
804
+ if (!handledSpecs.has(src)) {
805
+ handledSpecs.add(src);
806
+ const used = usedExports.get(src);
807
+ if (used && used.size > 0) {
808
+ const specifiers = [...used]
809
+ .sort()
810
+ .map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
811
+ finalImportStmts.push(t.importDeclaration(specifiers, t.stringLiteral(src)));
812
+ }
813
+ }
814
+ // Always remove the namespace import for this var, even if src was already handled.
815
+ const numId = varToModuleId.get(varName);
816
+ if (numId !== undefined)
817
+ hoistedImports.delete(`./${numId}.js`);
818
+ }
819
+ }
820
+ }
821
+ // Remaining (non-library) namespace imports
822
+ for (const [spec, name] of hoistedImports) {
823
+ finalImportStmts.push(t.importDeclaration([t.importNamespaceSpecifier(t.identifier(name))], t.stringLiteral(spec)));
824
+ }
825
+ // Pass E — collapse Babel slicedToArray expansions.
826
+ const afterE = collapseSlicedToArrayDeep(afterB);
827
+ // Pass F — JSX recovery.
828
+ recoverJSX(afterE);
829
+ // Pass G — remove top-level Babel helper functions and webpack module-cache vars.
830
+ const afterG = dropEmptyObjectVars(afterE.filter((stmt) => !isBabelArrayLikeToArrayHelper(stmt) &&
831
+ !isBabelTypeofHelper(stmt) &&
832
+ !isBabelDefinePropertyHelper(stmt) &&
833
+ !isBabelObjectSpreadHelper(stmt)));
834
+ // Pass H — prune named imports whose local name is no longer referenced
835
+ // (e.g. jsx/jsxs after JSX recovery, namespace imports that were cleared).
836
+ const prunedImports = pruneUnusedNamedImports(finalImportStmts, afterG);
837
+ return [...prunedImports, ...afterG];
838
+ };
839
+ //# sourceMappingURL=transform.js.map