webfuscator 0.9.4

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 (289) hide show
  1. package/DISCLOSURE +9 -0
  2. package/LICENSE +21 -0
  3. package/README.md +83 -0
  4. package/dist/analysis/constant.d.ts +11 -0
  5. package/dist/analysis/constant.d.ts.map +1 -0
  6. package/dist/analysis/constant.js +261 -0
  7. package/dist/analysis/constant.js.map +1 -0
  8. package/dist/analysis/document-order.d.ts +5 -0
  9. package/dist/analysis/document-order.d.ts.map +1 -0
  10. package/dist/analysis/document-order.js +124 -0
  11. package/dist/analysis/document-order.js.map +1 -0
  12. package/dist/analysis/inlineability.d.ts +13 -0
  13. package/dist/analysis/inlineability.d.ts.map +1 -0
  14. package/dist/analysis/inlineability.js +270 -0
  15. package/dist/analysis/inlineability.js.map +1 -0
  16. package/dist/analysis/purity.d.ts +5 -0
  17. package/dist/analysis/purity.d.ts.map +1 -0
  18. package/dist/analysis/purity.js +281 -0
  19. package/dist/analysis/purity.js.map +1 -0
  20. package/dist/index.d.ts +3 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +2 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/obfuscator.d.ts +4 -0
  25. package/dist/obfuscator.d.ts.map +1 -0
  26. package/dist/obfuscator.js +222 -0
  27. package/dist/obfuscator.js.map +1 -0
  28. package/dist/options.d.ts +73 -0
  29. package/dist/options.d.ts.map +1 -0
  30. package/dist/options.js +2 -0
  31. package/dist/options.js.map +1 -0
  32. package/dist/preparation/dot-to-bracket.d.ts +16 -0
  33. package/dist/preparation/dot-to-bracket.d.ts.map +1 -0
  34. package/dist/preparation/dot-to-bracket.js +36 -0
  35. package/dist/preparation/dot-to-bracket.js.map +1 -0
  36. package/dist/preparation/expand-destructuring.d.ts +26 -0
  37. package/dist/preparation/expand-destructuring.d.ts.map +1 -0
  38. package/dist/preparation/expand-destructuring.js +154 -0
  39. package/dist/preparation/expand-destructuring.js.map +1 -0
  40. package/dist/preparation/expand-template-literals.d.ts +23 -0
  41. package/dist/preparation/expand-template-literals.d.ts.map +1 -0
  42. package/dist/preparation/expand-template-literals.js +78 -0
  43. package/dist/preparation/expand-template-literals.js.map +1 -0
  44. package/dist/preparation/rewrite-class-fields.d.ts +43 -0
  45. package/dist/preparation/rewrite-class-fields.d.ts.map +1 -0
  46. package/dist/preparation/rewrite-class-fields.js +270 -0
  47. package/dist/preparation/rewrite-class-fields.js.map +1 -0
  48. package/dist/preparation/split-sequence-expressions.d.ts +15 -0
  49. package/dist/preparation/split-sequence-expressions.d.ts.map +1 -0
  50. package/dist/preparation/split-sequence-expressions.js +36 -0
  51. package/dist/preparation/split-sequence-expressions.js.map +1 -0
  52. package/dist/preparation/split-variable-declarations.d.ts +20 -0
  53. package/dist/preparation/split-variable-declarations.d.ts.map +1 -0
  54. package/dist/preparation/split-variable-declarations.js +36 -0
  55. package/dist/preparation/split-variable-declarations.js.map +1 -0
  56. package/dist/preparation/stringify-object-keys.d.ts +21 -0
  57. package/dist/preparation/stringify-object-keys.d.ts.map +1 -0
  58. package/dist/preparation/stringify-object-keys.js +96 -0
  59. package/dist/preparation/stringify-object-keys.js.map +1 -0
  60. package/dist/preparation/wrap-single-statements.d.ts +24 -0
  61. package/dist/preparation/wrap-single-statements.d.ts.map +1 -0
  62. package/dist/preparation/wrap-single-statements.js +53 -0
  63. package/dist/preparation/wrap-single-statements.js.map +1 -0
  64. package/dist/transforms/arguments-to-parameters.d.ts +20 -0
  65. package/dist/transforms/arguments-to-parameters.d.ts.map +1 -0
  66. package/dist/transforms/arguments-to-parameters.js +162 -0
  67. package/dist/transforms/arguments-to-parameters.js.map +1 -0
  68. package/dist/transforms/arrow-to-function.d.ts +46 -0
  69. package/dist/transforms/arrow-to-function.d.ts.map +1 -0
  70. package/dist/transforms/arrow-to-function.js +203 -0
  71. package/dist/transforms/arrow-to-function.js.map +1 -0
  72. package/dist/transforms/collapse-single-use-temps.d.ts +16 -0
  73. package/dist/transforms/collapse-single-use-temps.d.ts.map +1 -0
  74. package/dist/transforms/collapse-single-use-temps.js +805 -0
  75. package/dist/transforms/collapse-single-use-temps.js.map +1 -0
  76. package/dist/transforms/const-let-to-var.d.ts +21 -0
  77. package/dist/transforms/const-let-to-var.d.ts.map +1 -0
  78. package/dist/transforms/const-let-to-var.js +217 -0
  79. package/dist/transforms/const-let-to-var.js.map +1 -0
  80. package/dist/transforms/const-to-let.d.ts +17 -0
  81. package/dist/transforms/const-to-let.d.ts.map +1 -0
  82. package/dist/transforms/const-to-let.js +33 -0
  83. package/dist/transforms/const-to-let.js.map +1 -0
  84. package/dist/transforms/do-while-to-while.d.ts +26 -0
  85. package/dist/transforms/do-while-to-while.d.ts.map +1 -0
  86. package/dist/transforms/do-while-to-while.js +54 -0
  87. package/dist/transforms/do-while-to-while.js.map +1 -0
  88. package/dist/transforms/drop-console.d.ts +27 -0
  89. package/dist/transforms/drop-console.d.ts.map +1 -0
  90. package/dist/transforms/drop-console.js +107 -0
  91. package/dist/transforms/drop-console.js.map +1 -0
  92. package/dist/transforms/drop-debugger.d.ts +18 -0
  93. package/dist/transforms/drop-debugger.d.ts.map +1 -0
  94. package/dist/transforms/drop-debugger.js +34 -0
  95. package/dist/transforms/drop-debugger.js.map +1 -0
  96. package/dist/transforms/expand-binary-assignment.d.ts +26 -0
  97. package/dist/transforms/expand-binary-assignment.d.ts.map +1 -0
  98. package/dist/transforms/expand-binary-assignment.js +78 -0
  99. package/dist/transforms/expand-binary-assignment.js.map +1 -0
  100. package/dist/transforms/expand-logical-assignment.d.ts +22 -0
  101. package/dist/transforms/expand-logical-assignment.d.ts.map +1 -0
  102. package/dist/transforms/expand-logical-assignment.js +73 -0
  103. package/dist/transforms/expand-logical-assignment.js.map +1 -0
  104. package/dist/transforms/extract-object-properties.d.ts +21 -0
  105. package/dist/transforms/extract-object-properties.d.ts.map +1 -0
  106. package/dist/transforms/extract-object-properties.js +340 -0
  107. package/dist/transforms/extract-object-properties.js.map +1 -0
  108. package/dist/transforms/fold-builtin-methods.d.ts +23 -0
  109. package/dist/transforms/fold-builtin-methods.d.ts.map +1 -0
  110. package/dist/transforms/fold-builtin-methods.js +839 -0
  111. package/dist/transforms/fold-builtin-methods.js.map +1 -0
  112. package/dist/transforms/fold-constants.d.ts +16 -0
  113. package/dist/transforms/fold-constants.d.ts.map +1 -0
  114. package/dist/transforms/fold-constants.js +421 -0
  115. package/dist/transforms/fold-constants.js.map +1 -0
  116. package/dist/transforms/for-to-while.d.ts +29 -0
  117. package/dist/transforms/for-to-while.d.ts.map +1 -0
  118. package/dist/transforms/for-to-while.js +91 -0
  119. package/dist/transforms/for-to-while.js.map +1 -0
  120. package/dist/transforms/function-declaration-to-expression.d.ts +28 -0
  121. package/dist/transforms/function-declaration-to-expression.d.ts.map +1 -0
  122. package/dist/transforms/function-declaration-to-expression.js +95 -0
  123. package/dist/transforms/function-declaration-to-expression.js.map +1 -0
  124. package/dist/transforms/inline-functions.d.ts +16 -0
  125. package/dist/transforms/inline-functions.d.ts.map +1 -0
  126. package/dist/transforms/inline-functions.js +896 -0
  127. package/dist/transforms/inline-functions.js.map +1 -0
  128. package/dist/transforms/logical-to-ternary.d.ts +20 -0
  129. package/dist/transforms/logical-to-ternary.d.ts.map +1 -0
  130. package/dist/transforms/logical-to-ternary.js +78 -0
  131. package/dist/transforms/logical-to-ternary.js.map +1 -0
  132. package/dist/transforms/mangle-properties.d.ts +27 -0
  133. package/dist/transforms/mangle-properties.d.ts.map +1 -0
  134. package/dist/transforms/mangle-properties.js +703 -0
  135. package/dist/transforms/mangle-properties.js.map +1 -0
  136. package/dist/transforms/nullish-coalescing-to-ternary.d.ts +18 -0
  137. package/dist/transforms/nullish-coalescing-to-ternary.d.ts.map +1 -0
  138. package/dist/transforms/nullish-coalescing-to-ternary.js +61 -0
  139. package/dist/transforms/nullish-coalescing-to-ternary.js.map +1 -0
  140. package/dist/transforms/numbers-to-strings.d.ts +19 -0
  141. package/dist/transforms/numbers-to-strings.d.ts.map +1 -0
  142. package/dist/transforms/numbers-to-strings.js +51 -0
  143. package/dist/transforms/numbers-to-strings.js.map +1 -0
  144. package/dist/transforms/object-method-to-property.d.ts +34 -0
  145. package/dist/transforms/object-method-to-property.d.ts.map +1 -0
  146. package/dist/transforms/object-method-to-property.js +78 -0
  147. package/dist/transforms/object-method-to-property.js.map +1 -0
  148. package/dist/transforms/optional-chaining-to-ternary.d.ts +19 -0
  149. package/dist/transforms/optional-chaining-to-ternary.d.ts.map +1 -0
  150. package/dist/transforms/optional-chaining-to-ternary.js +206 -0
  151. package/dist/transforms/optional-chaining-to-ternary.js.map +1 -0
  152. package/dist/transforms/pack-declarations-into-parameters.d.ts +22 -0
  153. package/dist/transforms/pack-declarations-into-parameters.d.ts.map +1 -0
  154. package/dist/transforms/pack-declarations-into-parameters.js +208 -0
  155. package/dist/transforms/pack-declarations-into-parameters.js.map +1 -0
  156. package/dist/transforms/remove-anonymous-function-names.d.ts +17 -0
  157. package/dist/transforms/remove-anonymous-function-names.d.ts.map +1 -0
  158. package/dist/transforms/remove-anonymous-function-names.js +72 -0
  159. package/dist/transforms/remove-anonymous-function-names.js.map +1 -0
  160. package/dist/transforms/remove-unreachable-code.d.ts +21 -0
  161. package/dist/transforms/remove-unreachable-code.d.ts.map +1 -0
  162. package/dist/transforms/remove-unreachable-code.js +103 -0
  163. package/dist/transforms/remove-unreachable-code.js.map +1 -0
  164. package/dist/transforms/remove-unused-code.d.ts +18 -0
  165. package/dist/transforms/remove-unused-code.d.ts.map +1 -0
  166. package/dist/transforms/remove-unused-code.js +249 -0
  167. package/dist/transforms/remove-unused-code.js.map +1 -0
  168. package/dist/transforms/rename-identifiers.d.ts +24 -0
  169. package/dist/transforms/rename-identifiers.d.ts.map +1 -0
  170. package/dist/transforms/rename-identifiers.js +264 -0
  171. package/dist/transforms/rename-identifiers.js.map +1 -0
  172. package/dist/transforms/specials-to-strings.d.ts +30 -0
  173. package/dist/transforms/specials-to-strings.d.ts.map +1 -0
  174. package/dist/transforms/specials-to-strings.js +101 -0
  175. package/dist/transforms/specials-to-strings.js.map +1 -0
  176. package/dist/transforms/switch-to-if.d.ts +28 -0
  177. package/dist/transforms/switch-to-if.d.ts.map +1 -0
  178. package/dist/transforms/switch-to-if.js +279 -0
  179. package/dist/transforms/switch-to-if.js.map +1 -0
  180. package/dist/transforms/ternary-to-if.d.ts +20 -0
  181. package/dist/transforms/ternary-to-if.d.ts.map +1 -0
  182. package/dist/transforms/ternary-to-if.js +315 -0
  183. package/dist/transforms/ternary-to-if.js.map +1 -0
  184. package/dist/transforms/update-to-assignment.d.ts +26 -0
  185. package/dist/transforms/update-to-assignment.d.ts.map +1 -0
  186. package/dist/transforms/update-to-assignment.js +120 -0
  187. package/dist/transforms/update-to-assignment.js.map +1 -0
  188. package/dist/transforms/yodify-conditions.d.ts +22 -0
  189. package/dist/transforms/yodify-conditions.d.ts.map +1 -0
  190. package/dist/transforms/yodify-conditions.js +91 -0
  191. package/dist/transforms/yodify-conditions.js.map +1 -0
  192. package/dist/utils/ast.d.ts +10 -0
  193. package/dist/utils/ast.d.ts.map +1 -0
  194. package/dist/utils/ast.js +112 -0
  195. package/dist/utils/ast.js.map +1 -0
  196. package/dist/utils/change-tracking.d.ts +8 -0
  197. package/dist/utils/change-tracking.d.ts.map +1 -0
  198. package/dist/utils/change-tracking.js +8 -0
  199. package/dist/utils/change-tracking.js.map +1 -0
  200. package/dist/utils/dom-properties.d.ts +2 -0
  201. package/dist/utils/dom-properties.d.ts.map +1 -0
  202. package/dist/utils/dom-properties.js +9252 -0
  203. package/dist/utils/dom-properties.js.map +1 -0
  204. package/dist/utils/evaluation-order.d.ts +4 -0
  205. package/dist/utils/evaluation-order.d.ts.map +1 -0
  206. package/dist/utils/evaluation-order.js +152 -0
  207. package/dist/utils/evaluation-order.js.map +1 -0
  208. package/dist/utils/literal.d.ts +5 -0
  209. package/dist/utils/literal.d.ts.map +1 -0
  210. package/dist/utils/literal.js +90 -0
  211. package/dist/utils/literal.js.map +1 -0
  212. package/dist/utils/logical-lowering.d.ts +4 -0
  213. package/dist/utils/logical-lowering.d.ts.map +1 -0
  214. package/dist/utils/logical-lowering.js +104 -0
  215. package/dist/utils/logical-lowering.js.map +1 -0
  216. package/dist/utils/loop-lowering.d.ts +23 -0
  217. package/dist/utils/loop-lowering.d.ts.map +1 -0
  218. package/dist/utils/loop-lowering.js +88 -0
  219. package/dist/utils/loop-lowering.js.map +1 -0
  220. package/dist/utils/paths.d.ts +9 -0
  221. package/dist/utils/paths.d.ts.map +1 -0
  222. package/dist/utils/paths.js +90 -0
  223. package/dist/utils/paths.js.map +1 -0
  224. package/dist/utils/random.d.ts +3 -0
  225. package/dist/utils/random.d.ts.map +1 -0
  226. package/dist/utils/random.js +22 -0
  227. package/dist/utils/random.js.map +1 -0
  228. package/dist/utils/string-generator.d.ts +37 -0
  229. package/dist/utils/string-generator.d.ts.map +1 -0
  230. package/dist/utils/string-generator.js +175 -0
  231. package/dist/utils/string-generator.js.map +1 -0
  232. package/package.json +76 -0
  233. package/src/analysis/constant.ts +310 -0
  234. package/src/analysis/document-order.ts +141 -0
  235. package/src/analysis/inlineability.ts +336 -0
  236. package/src/analysis/purity.ts +315 -0
  237. package/src/index.ts +2 -0
  238. package/src/obfuscator.ts +271 -0
  239. package/src/options.ts +114 -0
  240. package/src/preparation/dot-to-bracket.ts +41 -0
  241. package/src/preparation/expand-destructuring.ts +211 -0
  242. package/src/preparation/expand-template-literals.ts +92 -0
  243. package/src/preparation/rewrite-class-fields.ts +320 -0
  244. package/src/preparation/split-sequence-expressions.ts +40 -0
  245. package/src/preparation/split-variable-declarations.ts +39 -0
  246. package/src/preparation/stringify-object-keys.ts +107 -0
  247. package/src/preparation/wrap-single-statements.ts +63 -0
  248. package/src/transforms/arguments-to-parameters.ts +187 -0
  249. package/src/transforms/arrow-to-function.ts +225 -0
  250. package/src/transforms/collapse-single-use-temps.ts +957 -0
  251. package/src/transforms/const-let-to-var.ts +246 -0
  252. package/src/transforms/const-to-let.ts +38 -0
  253. package/src/transforms/do-while-to-while.ts +69 -0
  254. package/src/transforms/drop-console.ts +119 -0
  255. package/src/transforms/drop-debugger.ts +38 -0
  256. package/src/transforms/expand-binary-assignment.ts +94 -0
  257. package/src/transforms/expand-logical-assignment.ts +84 -0
  258. package/src/transforms/extract-object-properties.ts +404 -0
  259. package/src/transforms/fold-builtin-methods.ts +949 -0
  260. package/src/transforms/fold-constants.ts +462 -0
  261. package/src/transforms/for-to-while.ts +109 -0
  262. package/src/transforms/function-declaration-to-expression.ts +108 -0
  263. package/src/transforms/inline-functions.ts +1074 -0
  264. package/src/transforms/logical-to-ternary.ts +92 -0
  265. package/src/transforms/mangle-properties.ts +819 -0
  266. package/src/transforms/nullish-coalescing-to-ternary.ts +77 -0
  267. package/src/transforms/numbers-to-strings.ts +61 -0
  268. package/src/transforms/object-method-to-property.ts +86 -0
  269. package/src/transforms/optional-chaining-to-ternary.ts +225 -0
  270. package/src/transforms/pack-declarations-into-parameters.ts +233 -0
  271. package/src/transforms/remove-anonymous-function-names.ts +84 -0
  272. package/src/transforms/remove-unreachable-code.ts +115 -0
  273. package/src/transforms/remove-unused-code.ts +296 -0
  274. package/src/transforms/rename-identifiers.ts +289 -0
  275. package/src/transforms/specials-to-strings.ts +116 -0
  276. package/src/transforms/switch-to-if.ts +339 -0
  277. package/src/transforms/ternary-to-if.ts +387 -0
  278. package/src/transforms/update-to-assignment.ts +132 -0
  279. package/src/transforms/yodify-conditions.ts +103 -0
  280. package/src/utils/ast.ts +129 -0
  281. package/src/utils/change-tracking.ts +15 -0
  282. package/src/utils/dom-properties.ts +9252 -0
  283. package/src/utils/evaluation-order.ts +178 -0
  284. package/src/utils/literal.ts +96 -0
  285. package/src/utils/logical-lowering.ts +132 -0
  286. package/src/utils/loop-lowering.ts +109 -0
  287. package/src/utils/paths.ts +103 -0
  288. package/src/utils/random.ts +22 -0
  289. package/src/utils/string-generator.ts +206 -0
@@ -0,0 +1,896 @@
1
+ import traverse from '@babel/traverse';
2
+ import * as t from '@babel/types';
3
+ import { analyzeInlineability } from '../analysis/inlineability.js';
4
+ import { isPure } from '../analysis/purity.js';
5
+ import { enclosingScopeHasDirectEval, isInsideWith, walkOwnFunctionScope } from '../utils/ast.js';
6
+ import { reorderableToStatement } from '../utils/evaluation-order.js';
7
+ import { generateLoopLabel } from '../utils/loop-lowering.js';
8
+ import { hasAnnexBFunctionAlias, isInStrictContext } from '../utils/paths.js';
9
+ /**
10
+ * Replaces eligible calls with function bodies, working from inner calls out.
11
+ * Declarations are removed after their last reference disappears.
12
+ *
13
+ * @example
14
+ * // ◀️ before
15
+ * function id(x) { return x; }
16
+ * var y = id(compute());
17
+ *
18
+ * // ▶️ after
19
+ * var _x = compute();
20
+ * var y = _x;
21
+ */
22
+ export function inlineFunctions(ast) {
23
+ const candidates = analyzeInlineability(ast);
24
+ if (candidates.size === 0) {
25
+ return false;
26
+ }
27
+ let anyInlined = false;
28
+ traverse(ast, {
29
+ CallExpression: {
30
+ exit(path) {
31
+ // Direct statement-array edits bypass Babel's binding updates. Crawl the
32
+ // owner so later sibling calls see new initialized temps in this pass.
33
+ const tempOwner = path.getFunctionParent() ?? path.scope.getProgramParent().path;
34
+ if (tryInlineAtCallExpr(path, candidates)) {
35
+ anyInlined = true;
36
+ tempOwner.scope.crawl();
37
+ rebindCandidates(candidates);
38
+ }
39
+ },
40
+ },
41
+ });
42
+ if (!anyInlined) {
43
+ return false;
44
+ }
45
+ dropZeroRefCandidates(candidates);
46
+ return true;
47
+ }
48
+ function tryInlineAtCallExpr(path, candidates) {
49
+ const { callee } = path.node;
50
+ if (!t.isIdentifier(callee)) {
51
+ return false;
52
+ }
53
+ const candidate = candidates.get(callee.name);
54
+ if (!candidate) {
55
+ return false;
56
+ }
57
+ const binding = path.scope.getBinding(callee.name);
58
+ if (!binding || binding !== candidate.binding) {
59
+ return false;
60
+ }
61
+ // Earlier inlining can add free references to this candidate's live body.
62
+ const freeVars = computeLiveFreeVars(candidate);
63
+ if (!isSafeAtCallSite(candidate, freeVars, path, candidates)) {
64
+ return false;
65
+ }
66
+ return inlineCallSite(path, candidate, freeVars);
67
+ }
68
+ // A crawl replaces Binding objects. Re-resolve candidates from their declarations.
69
+ function rebindCandidates(candidates) {
70
+ for (const [name, candidate] of candidates) {
71
+ const declId = declarationIdentifier(candidate.declarationPath);
72
+ const binding = candidate.declarationPath.removed
73
+ ? null
74
+ : candidate.declarationPath.scope.getBinding(name);
75
+ if (!binding || !declId || binding.identifier !== declId) {
76
+ candidates.delete(name);
77
+ continue;
78
+ }
79
+ candidate.binding = binding;
80
+ }
81
+ }
82
+ function dropZeroRefCandidates(candidates) {
83
+ const first = candidates.values().next().value;
84
+ if (!first) {
85
+ return;
86
+ }
87
+ first.declarationPath.scope.getProgramParent().crawl();
88
+ for (const candidate of candidates.values()) {
89
+ const declPath = candidate.declarationPath;
90
+ if (declPath.removed) {
91
+ continue;
92
+ }
93
+ const declId = declarationIdentifier(declPath);
94
+ if (!declId) {
95
+ continue;
96
+ }
97
+ // An outer same-named binding must not decide whether this declaration drops.
98
+ const binding = declPath.scope.getBinding(candidate.name);
99
+ if (!binding || binding.identifier !== declId || binding.references > 0) {
100
+ continue;
101
+ }
102
+ declPath.remove();
103
+ }
104
+ }
105
+ function declarationIdentifier(declPath) {
106
+ if (declPath.isFunctionDeclaration()) {
107
+ return declPath.node.id ?? null;
108
+ }
109
+ if (declPath.isVariableDeclaration() && declPath.node.declarations.length === 1) {
110
+ const { id } = declPath.node.declarations[0];
111
+ return t.isIdentifier(id) ? id : null;
112
+ }
113
+ return null;
114
+ }
115
+ function isSafeAtCallSite(candidate, freeVars, callPath, candidates) {
116
+ // `with`, direct eval, and Annex B aliases can redirect free names outside
117
+ // Babel's scope table.
118
+ if (isInsideWith(callPath) || enclosingScopeHasDirectEval(callPath)) {
119
+ return false;
120
+ }
121
+ if (annexBHoistShadowsFreeVar(callPath, freeVars)) {
122
+ return false;
123
+ }
124
+ // Spliced code inherits call-site strictness, so it must match the callee.
125
+ if (isInStrictContext(candidate.fnPath) !== isInStrictContext(callPath)) {
126
+ return false;
127
+ }
128
+ // In a loop, spliced uninitialized `var` bindings would retain prior values.
129
+ if (callIsInsideLoop(callPath) &&
130
+ bodyHasUninitializedVar(candidate.fnNode.body)) {
131
+ return false;
132
+ }
133
+ for (const freeVar of freeVars) {
134
+ const declSiteBinding = candidate.fnPath.scope.parent?.getBinding(freeVar);
135
+ const callSiteBinding = callPath.scope.getBinding(freeVar);
136
+ if (declSiteBinding !== callSiteBinding) {
137
+ return false;
138
+ }
139
+ }
140
+ if (isInUnsafeExpressionPosition(callPath)) {
141
+ return false;
142
+ }
143
+ const stmtParent = callPath.getStatementParent();
144
+ if (!stmtParent) {
145
+ return false;
146
+ }
147
+ // The call must run exactly once at statement position. Repeating loop slots,
148
+ // short-circuiting chains, case tests, and earlier effects are refused.
149
+ if (stmtParent.isLoop() && callInReevaluatedLoopPosition(callPath, stmtParent)) {
150
+ return false;
151
+ }
152
+ if (withinOptionalChain(callPath, stmtParent)) {
153
+ return false;
154
+ }
155
+ if (!reorderableToStatement(callPath, stmtParent)) {
156
+ return false;
157
+ }
158
+ if (argsContainContextExpression(callPath)) {
159
+ return false;
160
+ }
161
+ if (argsContainCandidateCalls(callPath, candidates)) {
162
+ return false;
163
+ }
164
+ return true;
165
+ }
166
+ // ECMA-262 B.3.2.1 creates a sloppy block-function alias that Babel misses in
167
+ // the enclosing scope.
168
+ function annexBHoistShadowsFreeVar(callPath, freeVars) {
169
+ if (freeVars.size === 0 || isInStrictContext(callPath)) {
170
+ return false;
171
+ }
172
+ const owner = callPath.getFunctionParent() ?? callPath.scope.getProgramParent().path;
173
+ let found = false;
174
+ owner.traverse({
175
+ Function(path) {
176
+ path.skip();
177
+ },
178
+ FunctionDeclaration(path) {
179
+ const { id } = path.node;
180
+ if (id && freeVars.has(id.name) && hasAnnexBFunctionAlias(path)) {
181
+ found = true;
182
+ path.stop();
183
+ }
184
+ },
185
+ });
186
+ return found;
187
+ }
188
+ // Only loops in the same function repeat the spliced body.
189
+ function callIsInsideLoop(callPath) {
190
+ for (let current = callPath.parentPath; current; current = current.parentPath) {
191
+ if (current.isLoop()) {
192
+ return true;
193
+ }
194
+ if (current.isFunction() || current.isProgram()) {
195
+ return false;
196
+ }
197
+ }
198
+ return false;
199
+ }
200
+ function bodyHasUninitializedVar(body) {
201
+ let found = false;
202
+ walkOwnFunctionScope(body, (node) => {
203
+ if (t.isVariableDeclarator(node) && t.isIdentifier(node.id) && node.init == null) {
204
+ found = true;
205
+ }
206
+ });
207
+ return found;
208
+ }
209
+ function bodyHasTryFinally(body) {
210
+ let found = false;
211
+ walkOwnFunctionScope(body, (node) => {
212
+ if (t.isTryStatement(node) && node.finalizer != null) {
213
+ found = true;
214
+ }
215
+ });
216
+ return found;
217
+ }
218
+ // Loop tests and updates repeat. Initializers and iterator sources run once.
219
+ function callInReevaluatedLoopPosition(callPath, loopPath) {
220
+ let cur = callPath;
221
+ while (cur.parentPath && cur.parentPath !== loopPath) {
222
+ cur = cur.parentPath;
223
+ }
224
+ if (loopPath.isForStatement()) {
225
+ return cur.key !== 'init';
226
+ }
227
+ if (loopPath.isForInStatement() || loopPath.isForOfStatement()) {
228
+ return cur.key !== 'right';
229
+ }
230
+ return true;
231
+ }
232
+ // Any optional ancestor may short-circuit the call.
233
+ function withinOptionalChain(callPath, stmtParent) {
234
+ let cur = callPath;
235
+ for (;;) {
236
+ const parent = cur.parentPath;
237
+ if (!parent || parent === stmtParent) {
238
+ return false;
239
+ }
240
+ if (parent.isOptionalMemberExpression() || parent.isOptionalCallExpression()) {
241
+ return true;
242
+ }
243
+ cur = parent;
244
+ }
245
+ }
246
+ function argsContainContextExpression(callPath) {
247
+ const stmtParent = callPath.getStatementParent();
248
+ if (!stmtParent) {
249
+ return false;
250
+ }
251
+ if (callPath.parentPath === stmtParent ||
252
+ (callPath.parentPath?.isExpressionStatement() && callPath.parentPath === stmtParent)) {
253
+ return false;
254
+ }
255
+ for (const arg of callPath.node.arguments) {
256
+ if (containsThisOrArguments(arg)) {
257
+ return true;
258
+ }
259
+ }
260
+ return false;
261
+ }
262
+ function containsThisOrArguments(node) {
263
+ let found = false;
264
+ t.traverseFast(node, (visited) => {
265
+ // Non-arrow functions bind their own `this` and `arguments`.
266
+ if (t.isFunction(visited) && !t.isArrowFunctionExpression(visited)) {
267
+ return t.traverseFast.skip;
268
+ }
269
+ const isContextRef = t.isThisExpression(visited) || (t.isIdentifier(visited) && visited.name === 'arguments');
270
+ if (isContextRef) {
271
+ found = true;
272
+ }
273
+ return isContextRef ? t.traverseFast.stop : undefined;
274
+ });
275
+ return found;
276
+ }
277
+ function argsContainCandidateCalls(callPath, candidates) {
278
+ for (const arg of callPath.node.arguments) {
279
+ if (containsCandidateCall(arg, candidates)) {
280
+ return true;
281
+ }
282
+ }
283
+ return false;
284
+ }
285
+ function containsCandidateCall(node, candidates) {
286
+ let found = false;
287
+ t.traverseFast(node, (visited) => {
288
+ const isCandidateCall = t.isCallExpression(visited) &&
289
+ t.isIdentifier(visited.callee) &&
290
+ candidates.has(visited.callee.name);
291
+ if (isCandidateCall) {
292
+ found = true;
293
+ }
294
+ return isCandidateCall ? t.traverseFast.stop : undefined;
295
+ });
296
+ return found;
297
+ }
298
+ function isInUnsafeExpressionPosition(path) {
299
+ let current = path;
300
+ while (current.parentPath) {
301
+ const parent = current.parentPath;
302
+ if (parent.isStatement()) {
303
+ return false;
304
+ }
305
+ if (parent.isConditionalExpression() &&
306
+ (current.key === 'consequent' || current.key === 'alternate')) {
307
+ return true;
308
+ }
309
+ if (parent.isLogicalExpression() && current.key === 'right') {
310
+ return true;
311
+ }
312
+ if (parent.isSequenceExpression() &&
313
+ parent.node.expressions.indexOf(current.node) > 0) {
314
+ return true;
315
+ }
316
+ // Default values run per call in the function's parameter scope.
317
+ if (parent.isAssignmentPattern() && current.key === 'right') {
318
+ return true;
319
+ }
320
+ // Logical-assignment right sides are conditional.
321
+ if (parent.isAssignmentExpression() &&
322
+ current.key === 'right' &&
323
+ (parent.node.operator === '||=' ||
324
+ parent.node.operator === '&&=' ||
325
+ parent.node.operator === '??=')) {
326
+ return true;
327
+ }
328
+ current = parent;
329
+ }
330
+ return false;
331
+ }
332
+ function getReturnPattern(stmts) {
333
+ if (stmts.length === 0) {
334
+ return 'none';
335
+ }
336
+ for (let i = 0; i < stmts.length - 1; i++) {
337
+ if (containsReturn(stmts[i])) {
338
+ return 'complex';
339
+ }
340
+ }
341
+ const last = stmts.at(-1);
342
+ if (t.isReturnStatement(last)) {
343
+ return 'trailing';
344
+ }
345
+ if (containsReturn(last)) {
346
+ return 'complex';
347
+ }
348
+ return 'none';
349
+ }
350
+ function containsReturn(node) {
351
+ let found = false;
352
+ t.traverseFast(node, (visited) => {
353
+ if (t.isFunction(visited) && visited !== node) {
354
+ return t.traverseFast.skip;
355
+ }
356
+ const isReturn = t.isReturnStatement(visited);
357
+ if (isReturn) {
358
+ found = true;
359
+ }
360
+ return isReturn ? t.traverseFast.stop : undefined;
361
+ });
362
+ return found;
363
+ }
364
+ function inlineCallSite(callPath, candidate, freeVars) {
365
+ if (callPath.removed) {
366
+ return false;
367
+ }
368
+ const args = callPath.node.arguments;
369
+ const argPaths = callPath.get('arguments');
370
+ const body = candidate.fnNode.body;
371
+ const returnPattern = getReturnPattern(body.body);
372
+ const stmtParent = callPath.getStatementParent();
373
+ if (!stmtParent) {
374
+ return false;
375
+ }
376
+ const containerPath = stmtParent.parentPath;
377
+ if (!containerPath) {
378
+ return false;
379
+ }
380
+ let containerArray = null;
381
+ if (containerPath.isBlock()) {
382
+ containerArray = containerPath.node.body;
383
+ }
384
+ else if (containerPath.isSwitchCase()) {
385
+ containerArray = containerPath.node.consequent;
386
+ }
387
+ if (!containerArray) {
388
+ return false;
389
+ }
390
+ const stmtIndex = containerArray.indexOf(stmtParent.node);
391
+ if (stmtIndex === -1) {
392
+ return false;
393
+ }
394
+ const { scope } = stmtParent;
395
+ const labelName = generateLoopLabel(stmtParent, 'inlined');
396
+ // Returns can write directly into a bare assignment or `var` initializer.
397
+ // Hoisted `var` already defaults to `undefined`. A plain assignment is safe
398
+ // only with one trailing return and no fall-through path.
399
+ const trailingReturn = returnPattern === 'trailing' ? body.body.at(-1) : null;
400
+ const trailingReturnHasArgument = trailingReturn != null && trailingReturn.argument != null;
401
+ const rawTarget = returnPattern === 'none' ? null : identifyDirectAssignmentTarget(callPath, freeVars, args);
402
+ // A finalizer runs before the call publishes its return value. Direct writes
403
+ // inside its `try` would expose the value too early.
404
+ const returnObservableByFinally = returnPattern === 'complex' && bodyHasTryFinally(body);
405
+ const directTarget = rawTarget == null ||
406
+ returnObservableByFinally ||
407
+ (rawTarget.kind === 'assign' && !trailingReturnHasArgument)
408
+ ? null
409
+ : rawTarget;
410
+ const retVarName = directTarget ? directTarget.name : scope.generateUid('returnValue');
411
+ const nameMap = new Map();
412
+ const elidedParams = new Set();
413
+ for (let i = 0; i < candidate.params.length; i++) {
414
+ const param = candidate.params[i];
415
+ const argPath = i < args.length ? argPaths[i] : null;
416
+ if (argPath &&
417
+ argEligibleForElision(argPath, callPath.scope) &&
418
+ !freeVars.has(argPath.node.name) &&
419
+ isParamReadOnly(candidate, param) &&
420
+ // An elided parameter must not alias the target that receives return writes.
421
+ argPath.node.name !== retVarName) {
422
+ nameMap.set(param, argPath.node.name);
423
+ elidedParams.add(param);
424
+ }
425
+ else {
426
+ nameMap.set(param, scope.generateUid(param));
427
+ }
428
+ }
429
+ for (const name of collectFunctionScopedNames(body)) {
430
+ if (!nameMap.has(name)) {
431
+ nameMap.set(name, scope.generateUid(name));
432
+ }
433
+ }
434
+ const labelMap = new Map();
435
+ collectLabels(body, labelMap, scope);
436
+ // Each call site needs an independently renamed deep clone.
437
+ const clonedBody = t.cloneNode(body, true).body;
438
+ for (const stmt of clonedBody) {
439
+ renameInBody(stmt, nameMap);
440
+ }
441
+ for (const stmt of clonedBody) {
442
+ renameLabelsInNode(stmt, labelMap);
443
+ }
444
+ let emittedAnyBreak = false;
445
+ if (returnPattern === 'complex') {
446
+ walkStatementsMut(clonedBody, {
447
+ onReturn(node, ctx) {
448
+ // A bare return must overwrite any earlier return value with `undefined`.
449
+ const argument = node.argument ?? t.unaryExpression('void', t.numericLiteral(0));
450
+ const stmts = [
451
+ t.expressionStatement(t.assignmentExpression('=', t.identifier(retVarName), argument)),
452
+ ];
453
+ if (!ctx.tailPosition) {
454
+ stmts.push(t.breakStatement(t.identifier(labelName)));
455
+ emittedAnyBreak = true;
456
+ }
457
+ return stmts;
458
+ },
459
+ }, { insideNestedLoop: false, insideNestedSwitch: false, tailPosition: true });
460
+ }
461
+ else if (returnPattern === 'trailing') {
462
+ const lastIdx = clonedBody.length - 1;
463
+ const last = clonedBody[lastIdx];
464
+ if (t.isReturnStatement(last)) {
465
+ if (last.argument) {
466
+ clonedBody[lastIdx] = t.expressionStatement(t.assignmentExpression('=', t.identifier(retVarName), last.argument));
467
+ }
468
+ else {
469
+ clonedBody.splice(lastIdx, 1);
470
+ }
471
+ }
472
+ }
473
+ const paramAssignments = [];
474
+ for (let i = 0; i < candidate.params.length; i++) {
475
+ if (elidedParams.has(candidate.params[i])) {
476
+ continue;
477
+ }
478
+ const newName = nameMap.get(candidate.params[i]);
479
+ const argNode = i < args.length ? t.cloneNode(args[i]) : t.unaryExpression('void', t.numericLiteral(0));
480
+ paramAssignments.push(t.variableDeclaration('var', [t.variableDeclarator(t.identifier(newName), argNode)]));
481
+ }
482
+ for (let i = candidate.params.length; i < args.length; i++) {
483
+ paramAssignments.push(t.expressionStatement(t.cloneNode(args[i])));
484
+ }
485
+ // Only rewritten early returns need the labeled wrapper.
486
+ const needsLabel = returnPattern === 'complex' && emittedAnyBreak;
487
+ if (directTarget) {
488
+ const replacement = [];
489
+ if (directTarget.kind === 'declarator') {
490
+ replacement.push(t.variableDeclaration('var', [t.variableDeclarator(t.identifier(directTarget.name))]));
491
+ }
492
+ if (needsLabel) {
493
+ replacement.push(t.labeledStatement(t.identifier(labelName), t.blockStatement([...paramAssignments, ...clonedBody])));
494
+ }
495
+ else {
496
+ replacement.push(...paramAssignments, ...clonedBody);
497
+ }
498
+ stmtParent.replaceWithMultiple(replacement);
499
+ return true;
500
+ }
501
+ if (needsLabel) {
502
+ const retVarDecl = t.variableDeclaration('var', [
503
+ t.variableDeclarator(t.identifier(retVarName)),
504
+ ]);
505
+ const labeledBlock = t.labeledStatement(t.identifier(labelName), t.blockStatement([...paramAssignments, ...clonedBody]));
506
+ containerArray.splice(stmtIndex, 0, retVarDecl, labeledBlock);
507
+ callPath.replaceWith(t.identifier(retVarName));
508
+ }
509
+ else if (returnPattern === 'none') {
510
+ containerArray.splice(stmtIndex, 0, ...paramAssignments, ...clonedBody);
511
+ callPath.replaceWith(t.unaryExpression('void', t.numericLiteral(0)));
512
+ }
513
+ else {
514
+ const retVarDecl = t.variableDeclaration('var', [
515
+ t.variableDeclarator(t.identifier(retVarName)),
516
+ ]);
517
+ containerArray.splice(stmtIndex, 0, retVarDecl, ...paramAssignments, ...clonedBody);
518
+ callPath.replaceWith(t.identifier(retVarName));
519
+ }
520
+ return true;
521
+ }
522
+ function identifyDirectAssignmentTarget(callPath, freeVars, args) {
523
+ const parent = callPath.parentPath;
524
+ if (!parent) {
525
+ return null;
526
+ }
527
+ if (parent.isVariableDeclarator() &&
528
+ t.isIdentifier(parent.node.id) &&
529
+ parent.node.init === callPath.node) {
530
+ const declPath = parent.parentPath;
531
+ if (!declPath || !declPath.isVariableDeclaration() || declPath.node.declarations.length !== 1) {
532
+ return null;
533
+ }
534
+ // Only `var` can become an uninitialized direct target without changing TDZ
535
+ // or block scope.
536
+ if (declPath.node.kind !== 'var') {
537
+ return null;
538
+ }
539
+ const owner = declPath.parentPath;
540
+ if (!owner) {
541
+ return null;
542
+ }
543
+ if (owner.isForStatement() && owner.node.init === declPath.node) {
544
+ return null;
545
+ }
546
+ if (owner.isForInStatement() && owner.node.left === declPath.node) {
547
+ return null;
548
+ }
549
+ if (owner.isForOfStatement() && owner.node.left === declPath.node) {
550
+ return null;
551
+ }
552
+ const { name } = parent.node.id;
553
+ if (freeVars.has(name)) {
554
+ return null;
555
+ }
556
+ if (argsContainIdentName(args, name)) {
557
+ return null;
558
+ }
559
+ return { kind: 'declarator', name };
560
+ }
561
+ if (parent.isAssignmentExpression() &&
562
+ parent.node.operator === '=' &&
563
+ t.isIdentifier(parent.node.left) &&
564
+ parent.node.right === callPath.node) {
565
+ const stmt = parent.parentPath;
566
+ if (!stmt || !stmt.isExpressionStatement() || stmt.node.expression !== parent.node) {
567
+ return null;
568
+ }
569
+ const { name } = parent.node.left;
570
+ if (freeVars.has(name)) {
571
+ return null;
572
+ }
573
+ if (argsContainIdentName(args, name)) {
574
+ return null;
575
+ }
576
+ return { kind: 'assign', name };
577
+ }
578
+ return null;
579
+ }
580
+ function argsContainIdentName(args, name) {
581
+ for (const arg of args) {
582
+ if (t.isIdentifier(arg) && arg.name === name) {
583
+ return true;
584
+ }
585
+ }
586
+ return false;
587
+ }
588
+ function isParamReadOnly(candidate, paramName) {
589
+ const binding = candidate.fnPath.scope.bindings[paramName];
590
+ return !binding || binding.constantViolations.length === 0;
591
+ }
592
+ // Eliding a parameter repeats the argument read at each use. The read must be
593
+ // pure and resolve to an invariant binding.
594
+ function argEligibleForElision(argPath, scope) {
595
+ if (!argPath.isIdentifier()) {
596
+ return false;
597
+ }
598
+ const binding = scope.getBinding(argPath.node.name);
599
+ if (!binding || binding.constantViolations.length > 0) {
600
+ return false;
601
+ }
602
+ return isPure(argPath.node, scope, argPath);
603
+ }
604
+ // Catch parameters stay scoped to their copied handlers. Counting them here
605
+ // would rename same-named free references outside the handler.
606
+ function collectFunctionScopedNames(body) {
607
+ const names = new Set();
608
+ walkOwnFunctionScope(body, (node) => {
609
+ if (t.isVariableDeclarator(node) && t.isIdentifier(node.id)) {
610
+ names.add(node.id.name);
611
+ }
612
+ });
613
+ return names;
614
+ }
615
+ // Optional catch bindings contribute no names.
616
+ function catchParamNames(clause) {
617
+ if (!clause.param) {
618
+ return new Set();
619
+ }
620
+ return new Set(Object.keys(t.getBindingIdentifiers(clause.param)));
621
+ }
622
+ // Nested functions do not contribute names to the current function scope.
623
+ function collectOwnScopeBindings(fn) {
624
+ const declared = new Set();
625
+ for (const param of fn.params) {
626
+ for (const name of Object.keys(t.getBindingIdentifiers(param))) {
627
+ declared.add(name);
628
+ }
629
+ }
630
+ if (t.isBlockStatement(fn.body)) {
631
+ for (const name of collectFunctionScopedNames(fn.body)) {
632
+ declared.add(name);
633
+ }
634
+ }
635
+ return declared;
636
+ }
637
+ // Recompute free names from the live body after earlier inlining. Conservative
638
+ // extras only add call-site identity checks.
639
+ function computeLiveFreeVars(candidate) {
640
+ const body = candidate.fnNode.body;
641
+ const ownBound = collectOwnScopeBindings(candidate.fnNode);
642
+ const free = new Set();
643
+ const shadows = new ShadowStack();
644
+ t.traverse(body, {
645
+ enter(node, ancestors) {
646
+ if (t.isFunction(node)) {
647
+ shadows.push(node, collectOwnScopeBindings(node));
648
+ return;
649
+ }
650
+ if (t.isCatchClause(node)) {
651
+ shadows.push(node, catchParamNames(node));
652
+ return;
653
+ }
654
+ if (!t.isIdentifier(node)) {
655
+ return;
656
+ }
657
+ const slot = ancestors.at(-1);
658
+ if (slot && isNonReferenceSlot(slot.node, slot.key)) {
659
+ return;
660
+ }
661
+ const { name } = node;
662
+ if (ownBound.has(name) || shadows.covers(name)) {
663
+ return;
664
+ }
665
+ free.add(name);
666
+ },
667
+ exit(node) {
668
+ if (t.isFunction(node) || t.isCatchClause(node)) {
669
+ shadows.pop(node);
670
+ }
671
+ },
672
+ });
673
+ return free;
674
+ }
675
+ // Live shadow frames prevent renaming references owned by an inner binding.
676
+ class ShadowStack {
677
+ counts = new Map();
678
+ framesByNode = new WeakMap();
679
+ push(node, names) {
680
+ if (names.size === 0) {
681
+ return;
682
+ }
683
+ this.framesByNode.set(node, names);
684
+ for (const name of names) {
685
+ this.counts.set(name, (this.counts.get(name) ?? 0) + 1);
686
+ }
687
+ }
688
+ pop(node) {
689
+ const names = this.framesByNode.get(node);
690
+ if (!names) {
691
+ return;
692
+ }
693
+ this.framesByNode.delete(node);
694
+ for (const name of names) {
695
+ const count = this.counts.get(name);
696
+ if (count <= 1) {
697
+ this.counts.delete(name);
698
+ }
699
+ else {
700
+ this.counts.set(name, count - 1);
701
+ }
702
+ }
703
+ }
704
+ covers(name) {
705
+ return (this.counts.get(name) ?? 0) > 0;
706
+ }
707
+ }
708
+ function collectLabels(body, labelMap, scope) {
709
+ walkOwnFunctionScope(body, (node) => {
710
+ if (t.isLabeledStatement(node) && !labelMap.has(node.label.name)) {
711
+ labelMap.set(node.label.name, scope.generateUid(node.label.name));
712
+ }
713
+ });
714
+ }
715
+ function renameLabelsInNode(node, labelMap) {
716
+ if (t.isFunction(node)) {
717
+ return;
718
+ }
719
+ walkOwnFunctionScope(node, (visited) => {
720
+ if (t.isLabeledStatement(visited) && labelMap.has(visited.label.name)) {
721
+ visited.label = t.identifier(labelMap.get(visited.label.name));
722
+ }
723
+ if (t.isBreakStatement(visited) && visited.label && labelMap.has(visited.label.name)) {
724
+ visited.label = t.identifier(labelMap.get(visited.label.name));
725
+ }
726
+ if (t.isContinueStatement(visited) && visited.label && labelMap.has(visited.label.name)) {
727
+ visited.label = t.identifier(labelMap.get(visited.label.name));
728
+ }
729
+ });
730
+ }
731
+ // Rename the detached clone before splicing. Babel's scope renamer needs a live
732
+ // path, while splicing first would publish unrenamed hoisted variables.
733
+ function renameInBody(node, nameMap) {
734
+ const shadows = new ShadowStack();
735
+ t.traverse(node, {
736
+ enter(visited, ancestors) {
737
+ if (t.isFunction(visited)) {
738
+ shadows.push(visited, mappedShadow(collectOwnScopeBindings(visited), nameMap));
739
+ return;
740
+ }
741
+ if (t.isCatchClause(visited)) {
742
+ shadows.push(visited, mappedShadow(catchParamNames(visited), nameMap));
743
+ return;
744
+ }
745
+ if (!t.isIdentifier(visited)) {
746
+ return;
747
+ }
748
+ const mapped = nameMap.get(visited.name);
749
+ if (mapped === undefined) {
750
+ return;
751
+ }
752
+ if (shadows.covers(visited.name)) {
753
+ return;
754
+ }
755
+ const slot = ancestors.at(-1);
756
+ if (slot && isNonReferenceSlot(slot.node, slot.key)) {
757
+ return;
758
+ }
759
+ visited.name = mapped;
760
+ },
761
+ exit(visited) {
762
+ if (t.isFunction(visited) || t.isCatchClause(visited)) {
763
+ shadows.pop(visited);
764
+ }
765
+ },
766
+ });
767
+ }
768
+ // Only remapped names need shadow tracking.
769
+ function mappedShadow(names, nameMap) {
770
+ const introduced = new Set();
771
+ for (const name of names) {
772
+ if (nameMap.has(name)) {
773
+ introduced.add(name);
774
+ }
775
+ }
776
+ return introduced;
777
+ }
778
+ function isNonReferenceSlot(parent, key) {
779
+ if (key === 'property' && t.isMemberExpression(parent) && !parent.computed) {
780
+ return true;
781
+ }
782
+ if (key === 'key' &&
783
+ (t.isObjectProperty(parent) || t.isObjectMethod(parent) || t.isClassMethod(parent)) &&
784
+ !parent.computed) {
785
+ return true;
786
+ }
787
+ if (key === 'label' &&
788
+ (t.isLabeledStatement(parent) || t.isBreakStatement(parent) || t.isContinueStatement(parent))) {
789
+ return true;
790
+ }
791
+ return false;
792
+ }
793
+ // Nested-function control flow belongs to that function.
794
+ function walkStatementsMut(stmts, hooks, ctx) {
795
+ const context = ctx ?? {
796
+ insideNestedLoop: false,
797
+ insideNestedSwitch: false,
798
+ tailPosition: false,
799
+ };
800
+ for (let index = 0; index < stmts.length; index++) {
801
+ const stmt = stmts[index];
802
+ const isLast = index === stmts.length - 1;
803
+ const stmtCtx = {
804
+ ...context,
805
+ tailPosition: context.tailPosition && isLast,
806
+ };
807
+ if (t.isContinueStatement(stmt) && hooks.onContinue) {
808
+ const replacement = hooks.onContinue(stmt, stmtCtx);
809
+ if (replacement) {
810
+ stmts[index] = replacement;
811
+ }
812
+ continue;
813
+ }
814
+ if (t.isBreakStatement(stmt) && hooks.onBreak) {
815
+ hooks.onBreak(stmt, stmtCtx);
816
+ continue;
817
+ }
818
+ if (t.isReturnStatement(stmt) && hooks.onReturn) {
819
+ const replacement = hooks.onReturn(stmt, stmtCtx);
820
+ if (replacement) {
821
+ stmts.splice(index, 1, ...replacement);
822
+ index += replacement.length - 1;
823
+ }
824
+ continue;
825
+ }
826
+ walkIntoCompound(stmt, hooks, stmtCtx);
827
+ }
828
+ }
829
+ function walkIntoCompound(node, hooks, ctx) {
830
+ if (t.isBlockStatement(node)) {
831
+ walkStatementsMut(node.body, hooks, ctx);
832
+ return;
833
+ }
834
+ if (t.isIfStatement(node)) {
835
+ node.consequent = walkSingleChild(node.consequent, hooks, ctx);
836
+ if (node.alternate) {
837
+ node.alternate = walkSingleChild(node.alternate, hooks, ctx);
838
+ }
839
+ return;
840
+ }
841
+ if (t.isLabeledStatement(node)) {
842
+ node.body = walkSingleChild(node.body, hooks, ctx);
843
+ return;
844
+ }
845
+ if (t.isTryStatement(node)) {
846
+ const inner = { ...ctx, tailPosition: false };
847
+ walkStatementsMut(node.block.body, hooks, inner);
848
+ if (node.handler) {
849
+ walkStatementsMut(node.handler.body.body, hooks, inner);
850
+ }
851
+ if (node.finalizer) {
852
+ walkStatementsMut(node.finalizer.body, hooks, inner);
853
+ }
854
+ return;
855
+ }
856
+ if (t.isSwitchStatement(node)) {
857
+ const inner = {
858
+ ...ctx,
859
+ insideNestedSwitch: true,
860
+ tailPosition: false,
861
+ };
862
+ for (const switchCase of node.cases) {
863
+ walkStatementsMut(switchCase.consequent, hooks, inner);
864
+ }
865
+ return;
866
+ }
867
+ if (t.isWhileStatement(node) ||
868
+ t.isDoWhileStatement(node) ||
869
+ t.isForStatement(node) ||
870
+ t.isForInStatement(node) ||
871
+ t.isForOfStatement(node)) {
872
+ const inner = {
873
+ ...ctx,
874
+ insideNestedLoop: true,
875
+ tailPosition: false,
876
+ };
877
+ node.body = walkSingleChild(node.body, hooks, inner);
878
+ return;
879
+ }
880
+ if (t.isWithStatement(node)) {
881
+ node.body = walkSingleChild(node.body, hooks, { ...ctx, tailPosition: false });
882
+ }
883
+ }
884
+ function walkSingleChild(child, hooks, ctx) {
885
+ if (t.isBlockStatement(child)) {
886
+ walkStatementsMut(child.body, hooks, ctx);
887
+ return child;
888
+ }
889
+ const wrapped = [child];
890
+ walkStatementsMut(wrapped, hooks, ctx);
891
+ if (wrapped.length === 1) {
892
+ return wrapped[0];
893
+ }
894
+ return t.blockStatement(wrapped);
895
+ }
896
+ //# sourceMappingURL=inline-functions.js.map