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,315 @@
1
+ import * as t from '@babel/types';
2
+ import { isInsideWith } from '../utils/ast.js';
3
+ import { traverseForChanges } from '../utils/change-tracking.js';
4
+ import { isConditionalGate, reorderableToStatement } from '../utils/evaluation-order.js';
5
+ import { isStandaloneDeclaration } from '../utils/paths.js';
6
+ /**
7
+ * Lowers conditional expressions to `if` statements. Expression values use a
8
+ * temporary. Parameter defaults and repeating loop tests stay unchanged because
9
+ * hoisting would change when they run.
10
+ *
11
+ * @example
12
+ * // ◀️ before
13
+ * var y = a ? b : c;
14
+ * log(d ? e : f);
15
+ *
16
+ * // ▶️ after
17
+ * var y;
18
+ * if (a) { y = b; } else { y = c; }
19
+ * var _ternaryResult;
20
+ * if (d) { _ternaryResult = e; } else { _ternaryResult = f; }
21
+ * log(_ternaryResult);
22
+ */
23
+ export function ternaryToIf(ast) {
24
+ // Flatten sequences and logical gates before lifting ternaries. Replacements
25
+ // detach queued child paths, so every handler checks liveness.
26
+ const preparationChanged = traverseForChanges(ast, preparationVisitor);
27
+ const loweringChanged = traverseForChanges(ast, visitor);
28
+ return preparationChanged || loweringChanged;
29
+ }
30
+ const preparationVisitor = {
31
+ ConditionalExpression(path, state) {
32
+ if (!isPathLive(path) || isInsideWith(path)) {
33
+ return;
34
+ }
35
+ const stmtPath = path.getStatementParent();
36
+ if (!stmtPath) {
37
+ return;
38
+ }
39
+ if (hoistEnclosingSequence(path, stmtPath) || lowerEnclosingLogical(path, stmtPath)) {
40
+ state.changed = true;
41
+ }
42
+ },
43
+ };
44
+ const visitor = {
45
+ ConditionalExpression(path, state) {
46
+ // Statement replacement detaches queued siblings. `with` can also shadow the
47
+ // synthesized result temporary.
48
+ if (!isPathLive(path) || isInsideWith(path)) {
49
+ return;
50
+ }
51
+ if (lowerConditional(path)) {
52
+ state.changed = true;
53
+ }
54
+ },
55
+ };
56
+ function lowerConditional(path) {
57
+ const parent = path.parentPath;
58
+ if (!parent) {
59
+ return false;
60
+ }
61
+ const { test, consequent, alternate } = path.node;
62
+ if (parent.isExpressionStatement() && parent.node.expression === path.node) {
63
+ parent.replaceWith(t.ifStatement(test, t.blockStatement(seqToExpressionStatements(consequent)), t.blockStatement(seqToExpressionStatements(alternate))));
64
+ // Skip the orphaned path after replacing its parent.
65
+ path.skip();
66
+ return true;
67
+ }
68
+ if (parent.isReturnStatement() && parent.node.argument === path.node) {
69
+ parent.replaceWith(t.ifStatement(test, t.blockStatement(seqWithFinal(consequent, t.returnStatement)), t.blockStatement(seqWithFinal(alternate, t.returnStatement))));
70
+ path.skip();
71
+ return true;
72
+ }
73
+ if (parent.isThrowStatement() && parent.node.argument === path.node) {
74
+ parent.replaceWith(t.ifStatement(test, t.blockStatement(seqWithFinal(consequent, t.throwStatement)), t.blockStatement(seqWithFinal(alternate, t.throwStatement))));
75
+ path.skip();
76
+ return true;
77
+ }
78
+ if (parent.isAssignmentExpression() &&
79
+ parent.node.operator === '=' &&
80
+ t.isIdentifier(parent.node.left) &&
81
+ parent.node.right === path.node &&
82
+ parent.parentPath?.isExpressionStatement() &&
83
+ parent.parentPath.node.expression === parent.node) {
84
+ const target = parent.node.left;
85
+ parent.parentPath.replaceWith(t.ifStatement(test, t.blockStatement(seqWithAssignment(consequent, target)), t.blockStatement(seqWithAssignment(alternate, target))));
86
+ path.skip();
87
+ return true;
88
+ }
89
+ if (parent.isVariableDeclarator() &&
90
+ t.isIdentifier(parent.node.id) &&
91
+ parent.node.init === path.node &&
92
+ parent.parentPath?.isVariableDeclaration() &&
93
+ // Splitting lexical declarations would end TDZ early, and bare `const` is
94
+ // invalid. Keep their initializer behind a result temp.
95
+ parent.parentPath.node.kind === 'var' &&
96
+ parent.parentPath.node.declarations.length === 1 &&
97
+ isStandaloneDeclaration(parent.parentPath)) {
98
+ const declPath = parent.parentPath;
99
+ const target = parent.node.id;
100
+ declPath.replaceWithMultiple([
101
+ t.variableDeclaration(declPath.node.kind, [t.variableDeclarator(t.cloneNode(target))]),
102
+ t.ifStatement(test, t.blockStatement(seqWithAssignment(consequent, target)), t.blockStatement(seqWithAssignment(alternate, target))),
103
+ ]);
104
+ path.skip();
105
+ return true;
106
+ }
107
+ const stmtPath = path.getStatementParent();
108
+ if (!stmtPath) {
109
+ return false;
110
+ }
111
+ if (isInsideAssignmentPattern(path, stmtPath)) {
112
+ return false;
113
+ }
114
+ if (isInsideLoopHeader(path, stmtPath)) {
115
+ return false;
116
+ }
117
+ // Lifting requires no short-circuit gate or earlier effect in the statement.
118
+ if (!reorderableToStatement(path, stmtPath)) {
119
+ return false;
120
+ }
121
+ const { scope } = path;
122
+ const tmpId = scope.generateUidIdentifier('ternaryResult');
123
+ scope.push({ id: t.cloneNode(tmpId) });
124
+ const ifStmt = t.ifStatement(test, t.blockStatement([
125
+ t.expressionStatement(t.assignmentExpression('=', t.cloneNode(tmpId), consequent)),
126
+ ]), t.blockStatement([
127
+ t.expressionStatement(t.assignmentExpression('=', t.cloneNode(tmpId), alternate)),
128
+ ]));
129
+ // Detach the ternary before reusing its children in the new `if`.
130
+ path.replaceWith(t.cloneNode(tmpId));
131
+ stmtPath.insertBefore(ifStmt);
132
+ return true;
133
+ }
134
+ function isInsideAssignmentPattern(path, stmtPath) {
135
+ let ancestor = path.parentPath;
136
+ while (ancestor && ancestor !== stmtPath) {
137
+ if (ancestor.isAssignmentPattern()) {
138
+ return true;
139
+ }
140
+ ancestor = ancestor.parentPath;
141
+ }
142
+ return false;
143
+ }
144
+ // Split the innermost sequence so its ternary reaches a safe statement position.
145
+ function hoistEnclosingSequence(path, stmtPath) {
146
+ const seqPath = findEnclosingSequence(path, stmtPath);
147
+ if (!seqPath) {
148
+ return false;
149
+ }
150
+ const elements = seqPath.node.expressions;
151
+ if (elements.length < 2) {
152
+ return false;
153
+ }
154
+ const seqStmt = seqPath.getStatementParent();
155
+ if (!seqStmt) {
156
+ return false;
157
+ }
158
+ // The sequence must run once at statement position without crossing a gate,
159
+ // case test, parameter default, loop header, or earlier effect.
160
+ if (isInsideLoopHeader(seqPath, seqStmt) ||
161
+ isInsideAssignmentPattern(seqPath, seqStmt) ||
162
+ isInsideSwitchCaseTest(seqPath, seqStmt) ||
163
+ !reorderableToStatement(seqPath, seqStmt)) {
164
+ return false;
165
+ }
166
+ const preceding = elements.slice(0, -1).map((e) => t.expressionStatement(t.cloneNode(e)));
167
+ const last = t.cloneNode(elements.at(-1));
168
+ seqPath.replaceWith(last);
169
+ seqStmt.insertBefore(preceding);
170
+ path.skip();
171
+ return true;
172
+ }
173
+ // Hoisting from a case test would run its work before the switch reaches that case.
174
+ function isInsideSwitchCaseTest(path, stmtPath) {
175
+ let ancestor = path.parentPath;
176
+ while (ancestor && ancestor !== stmtPath) {
177
+ if (ancestor.isSwitchCase()) {
178
+ return true;
179
+ }
180
+ ancestor = ancestor.parentPath;
181
+ }
182
+ return false;
183
+ }
184
+ // A live path must still occupy every recorded parent key up to the Program.
185
+ function isPathLive(path) {
186
+ let cur = path;
187
+ while (cur) {
188
+ if (!cur.node) {
189
+ return false;
190
+ }
191
+ const parent = cur.parentPath;
192
+ if (!parent) {
193
+ return cur.isProgram() || cur.isFile();
194
+ }
195
+ if (!parent.node) {
196
+ return false;
197
+ }
198
+ const parentNode = parent.node;
199
+ let held = parentNode[cur.key];
200
+ if (cur.listKey != null) {
201
+ const arr = parentNode[cur.listKey];
202
+ held = Array.isArray(arr) ? arr[cur.key] : arr;
203
+ }
204
+ if (held !== cur.node) {
205
+ return false;
206
+ }
207
+ cur = parent;
208
+ }
209
+ return false;
210
+ }
211
+ function findEnclosingSequence(path, stmtPath) {
212
+ let cur = path;
213
+ let parent = cur.parentPath;
214
+ let found = null;
215
+ while (parent && parent !== stmtPath) {
216
+ if (isConditionalGate(parent, cur)) {
217
+ return null;
218
+ }
219
+ if (!found && parent.isSequenceExpression()) {
220
+ found = parent;
221
+ }
222
+ cur = parent;
223
+ parent = cur.parentPath;
224
+ }
225
+ return found;
226
+ }
227
+ // Convert an enclosing logical gate to a conditional so this pass remains
228
+ // self-contained and can lower it on the next visit.
229
+ function lowerEnclosingLogical(path, stmtPath) {
230
+ const logical = findEnclosingShortCircuitLogical(path, stmtPath);
231
+ if (!logical || logical.removed || !logical.container) {
232
+ return false;
233
+ }
234
+ const { node } = logical;
235
+ const { left, right } = node;
236
+ let test;
237
+ let valueRef;
238
+ if (t.isIdentifier(left) && logical.scope.hasBinding(left.name)) {
239
+ test = left;
240
+ valueRef = t.cloneNode(left);
241
+ }
242
+ else {
243
+ const tmp = logical.scope.generateUidIdentifierBasedOnNode(left);
244
+ logical.scope.push({ id: t.cloneNode(tmp) });
245
+ test = t.assignmentExpression('=', t.cloneNode(tmp), left);
246
+ valueRef = t.cloneNode(tmp);
247
+ }
248
+ const testExpr = node.operator === '??' ? t.binaryExpression('!=', test, t.nullLiteral()) : test;
249
+ logical.replaceWith(node.operator === '&&'
250
+ ? t.conditionalExpression(testExpr, right, valueRef)
251
+ : t.conditionalExpression(testExpr, valueRef, right));
252
+ path.skip();
253
+ return true;
254
+ }
255
+ function findEnclosingShortCircuitLogical(path, stmtPath) {
256
+ let cur = path;
257
+ let parent = cur.parentPath;
258
+ let found = null;
259
+ while (parent && parent !== stmtPath) {
260
+ if (!found) {
261
+ if (parent.isConditionalExpression() &&
262
+ (parent.node.consequent === cur.node || parent.node.alternate === cur.node)) {
263
+ return null;
264
+ }
265
+ if (parent.isLogicalExpression() && parent.node.right === cur.node) {
266
+ found = parent;
267
+ }
268
+ }
269
+ else if (isConditionalGate(parent, cur)) {
270
+ return null;
271
+ }
272
+ cur = parent;
273
+ parent = cur.parentPath;
274
+ }
275
+ return found;
276
+ }
277
+ // Loop tests and updates repeat, while a `for` initializer runs once.
278
+ function isInsideLoopHeader(path, stmtPath) {
279
+ let ancestor = path;
280
+ while (ancestor && ancestor.parentPath !== stmtPath) {
281
+ ancestor = ancestor.parentPath;
282
+ }
283
+ if (!ancestor) {
284
+ return false;
285
+ }
286
+ if (stmtPath.isWhileStatement() || stmtPath.isDoWhileStatement()) {
287
+ return ancestor.parentKey === 'test';
288
+ }
289
+ if (stmtPath.isForStatement()) {
290
+ return ancestor.parentKey === 'test' || ancestor.parentKey === 'update';
291
+ }
292
+ return false;
293
+ }
294
+ // Split sequences so later lifts target the right statement.
295
+ function seqToExpressionStatements(expr) {
296
+ if (t.isSequenceExpression(expr)) {
297
+ return expr.expressions.map((e) => t.expressionStatement(e));
298
+ }
299
+ return [t.expressionStatement(expr)];
300
+ }
301
+ // In return and throw, only the final sequence element supplies the value.
302
+ function seqWithFinal(expr, build) {
303
+ if (t.isSequenceExpression(expr)) {
304
+ const last = expr.expressions.at(-1);
305
+ const init = expr.expressions.slice(0, -1).map((e) => t.expressionStatement(e));
306
+ return [...init, build(last)];
307
+ }
308
+ return [build(expr)];
309
+ }
310
+ // In a bare assignment, only the final sequence element supplies the value.
311
+ function seqWithAssignment(expr, target) {
312
+ const build = (value) => t.expressionStatement(t.assignmentExpression('=', t.cloneNode(target), value));
313
+ return seqWithFinal(expr, build);
314
+ }
315
+ //# sourceMappingURL=ternary-to-if.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ternary-to-if.js","sourceRoot":"","sources":["../../src/transforms/ternary-to-if.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { File } from '@babel/types';
2
+ /**
3
+ * Rewrites numeric updates as compound assignments for later expansion. Prefix
4
+ * results already match. Postfix forms require a position that discards the old
5
+ * value.
6
+ *
7
+ * BigInt differs because adding the number `1` throws. Only bindings proven to
8
+ * stay numeric are rewritten. Members and parameters stay unchanged.
9
+ *
10
+ * @example
11
+ * // ◀️ before
12
+ * let i = 0;
13
+ * i++;
14
+ * arr[++i] = 1;
15
+ * let n = 5n;
16
+ * n++;
17
+ *
18
+ * // ▶️ after
19
+ * let i = 0;
20
+ * i += 1;
21
+ * arr[i += 1] = 1;
22
+ * let n = 5n;
23
+ * n++;
24
+ */
25
+ export declare function updateToAssignment(ast: File): boolean;
26
+ //# sourceMappingURL=update-to-assignment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-to-assignment.d.ts","sourceRoot":"","sources":["../../src/transforms/update-to-assignment.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAMxC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,CAErD"}
@@ -0,0 +1,120 @@
1
+ import * as t from '@babel/types';
2
+ import { isDirectEvalCall, isInsideWith } from '../utils/ast.js';
3
+ import { traverseForChanges } from '../utils/change-tracking.js';
4
+ /**
5
+ * Rewrites numeric updates as compound assignments for later expansion. Prefix
6
+ * results already match. Postfix forms require a position that discards the old
7
+ * value.
8
+ *
9
+ * BigInt differs because adding the number `1` throws. Only bindings proven to
10
+ * stay numeric are rewritten. Members and parameters stay unchanged.
11
+ *
12
+ * @example
13
+ * // ◀️ before
14
+ * let i = 0;
15
+ * i++;
16
+ * arr[++i] = 1;
17
+ * let n = 5n;
18
+ * n++;
19
+ *
20
+ * // ▶️ after
21
+ * let i = 0;
22
+ * i += 1;
23
+ * arr[i += 1] = 1;
24
+ * let n = 5n;
25
+ * n++;
26
+ */
27
+ export function updateToAssignment(ast) {
28
+ return traverseForChanges(ast, visitor);
29
+ }
30
+ const visitor = {
31
+ UpdateExpression(path, state) {
32
+ const { argument, prefix, operator } = path.node;
33
+ if (!t.isIdentifier(argument)) {
34
+ return;
35
+ }
36
+ if (!prefix && !valueIsDiscarded(path)) {
37
+ return;
38
+ }
39
+ // `with` can retarget the name and defeat the numeric proof.
40
+ if (isInsideWith(path)) {
41
+ return;
42
+ }
43
+ const binding = path.scope.getBinding(argument.name);
44
+ if (!isNumericBinding(binding)) {
45
+ return;
46
+ }
47
+ // Direct eval anywhere in the binding's scope can change its type.
48
+ if (bindingScopeReachesDirectEval(binding)) {
49
+ return;
50
+ }
51
+ const compound = operator === '++' ? '+=' : '-=';
52
+ path.replaceWith(t.assignmentExpression(compound, argument, t.numericLiteral(1)));
53
+ state.changed = true;
54
+ },
55
+ };
56
+ function valueIsDiscarded(path) {
57
+ const { parentPath } = path;
58
+ if (!parentPath) {
59
+ return false;
60
+ }
61
+ if (parentPath.isExpressionStatement()) {
62
+ return true;
63
+ }
64
+ if (parentPath.isForStatement() && parentPath.node.update === path.node) {
65
+ return true;
66
+ }
67
+ if (parentPath.isSequenceExpression()) {
68
+ return parentPath.node.expressions.at(-1) !== path.node;
69
+ }
70
+ return false;
71
+ }
72
+ // The initializer and every mutation must keep the binding numeric.
73
+ function isNumericBinding(binding) {
74
+ if (!binding || (binding.kind !== 'var' && binding.kind !== 'let')) {
75
+ return false;
76
+ }
77
+ const declarator = binding.path.node;
78
+ if (!t.isVariableDeclarator(declarator) || !t.isNumericLiteral(declarator.init)) {
79
+ return false;
80
+ }
81
+ // Babel misses the string writes from an Annex B `for-in` initializer.
82
+ if (isForInOfLoopVariable(binding)) {
83
+ return false;
84
+ }
85
+ return binding.constantViolations.every((violation) => keepsNumeric(violation.node));
86
+ }
87
+ // A sibling or nested direct eval can still close over and reassign the binding.
88
+ function bindingScopeReachesDirectEval(binding) {
89
+ let found = false;
90
+ t.traverseFast(binding.scope.block, (node) => {
91
+ if (isDirectEvalCall(node)) {
92
+ found = true;
93
+ }
94
+ return found ? t.traverseFast.stop : undefined;
95
+ });
96
+ return found;
97
+ }
98
+ function isForInOfLoopVariable(binding) {
99
+ const declaration = binding.path.parentPath;
100
+ if (!declaration || !declaration.isVariableDeclaration()) {
101
+ return false;
102
+ }
103
+ const loop = declaration.parentPath;
104
+ return (loop != null &&
105
+ (loop.isForInStatement() || loop.isForOfStatement()) &&
106
+ loop.node.left === declaration.node);
107
+ }
108
+ function keepsNumeric(node) {
109
+ if (t.isUpdateExpression(node)) {
110
+ return true;
111
+ }
112
+ if (t.isVariableDeclarator(node)) {
113
+ return t.isNumericLiteral(node.init);
114
+ }
115
+ if (t.isAssignmentExpression(node)) {
116
+ return t.isNumericLiteral(node.right);
117
+ }
118
+ return false;
119
+ }
120
+ //# sourceMappingURL=update-to-assignment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-to-assignment.js","sourceRoot":"","sources":["../../src/transforms/update-to-assignment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { File } from '@babel/types';
2
+ /**
3
+ * Moves a safe literal-shaped right operand to the left of a comparison.
4
+ * Relational operators are flipped after swapping.
5
+ *
6
+ * Unary operations over literals also count when their coercion cannot act.
7
+ *
8
+ * @example
9
+ * // ◀️ before
10
+ * if (x === 1) {}
11
+ * if (name !== "foo") {}
12
+ * if (count > 5) {}
13
+ * if (idx <= 10) {}
14
+ *
15
+ * // ▶️ after
16
+ * if (1 === x) {}
17
+ * if ("foo" !== name) {}
18
+ * if (5 < count) {}
19
+ * if (10 >= idx) {}
20
+ */
21
+ export declare function yodifyConditions(ast: File): boolean;
22
+ //# sourceMappingURL=yodify-conditions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yodify-conditions.d.ts","sourceRoot":"","sources":["../../src/transforms/yodify-conditions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAMxC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,CAEnD"}
@@ -0,0 +1,91 @@
1
+ import * as t from '@babel/types';
2
+ import { traverseForChanges } from '../utils/change-tracking.js';
3
+ import { isLiteralShaped } from '../utils/literal.js';
4
+ /**
5
+ * Moves a safe literal-shaped right operand to the left of a comparison.
6
+ * Relational operators are flipped after swapping.
7
+ *
8
+ * Unary operations over literals also count when their coercion cannot act.
9
+ *
10
+ * @example
11
+ * // ◀️ before
12
+ * if (x === 1) {}
13
+ * if (name !== "foo") {}
14
+ * if (count > 5) {}
15
+ * if (idx <= 10) {}
16
+ *
17
+ * // ▶️ after
18
+ * if (1 === x) {}
19
+ * if ("foo" !== name) {}
20
+ * if (5 < count) {}
21
+ * if (10 >= idx) {}
22
+ */
23
+ export function yodifyConditions(ast) {
24
+ return traverseForChanges(ast, visitor);
25
+ }
26
+ const visitor = {
27
+ BinaryExpression(path, state) {
28
+ const { node } = path;
29
+ const op = node.operator;
30
+ if (!isComparisonOp(op)) {
31
+ return;
32
+ }
33
+ if (!t.isExpression(node.left)) {
34
+ return;
35
+ }
36
+ if (isLiteralShaped(node.left)) {
37
+ return;
38
+ }
39
+ // The moved right side must run no user code, including object coercion.
40
+ if (!swappingRightIsEffectFree(node.right)) {
41
+ return;
42
+ }
43
+ // Relational comparison coerces left first, so a regexp operand cannot swap.
44
+ if (RELATIONAL_FLIP[op] !== undefined && containsRegExpLiteral(node.right)) {
45
+ return;
46
+ }
47
+ const { left } = node;
48
+ const { right } = node;
49
+ node.left = right;
50
+ node.right = left;
51
+ const flipped = RELATIONAL_FLIP[op];
52
+ if (flipped !== undefined) {
53
+ node.operator = flipped;
54
+ }
55
+ state.changed = true;
56
+ },
57
+ };
58
+ const COMPARISON_OPS = new Set(['==', '!=', '===', '!==', '<', '<=', '>', '>=']);
59
+ function isComparisonOp(op) {
60
+ return COMPARISON_OPS.has(op);
61
+ }
62
+ const RELATIONAL_FLIP = {
63
+ '<': '>',
64
+ '>': '<',
65
+ '<=': '>=',
66
+ '>=': '<=',
67
+ };
68
+ // Numeric unary over regexp invokes ToPrimitive and cannot move earlier.
69
+ function swappingRightIsEffectFree(node) {
70
+ return isLiteralShaped(node) && !numericUnaryCoercesRegExp(node);
71
+ }
72
+ // `!` only propagates risk because ToBoolean never invokes object coercion.
73
+ function numericUnaryCoercesRegExp(node) {
74
+ if (!t.isUnaryExpression(node) || !t.isExpression(node.argument)) {
75
+ return false;
76
+ }
77
+ if (node.operator === '!') {
78
+ return numericUnaryCoercesRegExp(node.argument);
79
+ }
80
+ return t.isRegExpLiteral(node.argument) || numericUnaryCoercesRegExp(node.argument);
81
+ }
82
+ function containsRegExpLiteral(node) {
83
+ if (t.isRegExpLiteral(node)) {
84
+ return true;
85
+ }
86
+ if (t.isUnaryExpression(node) && t.isExpression(node.argument)) {
87
+ return containsRegExpLiteral(node.argument);
88
+ }
89
+ return false;
90
+ }
91
+ //# sourceMappingURL=yodify-conditions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yodify-conditions.js","sourceRoot":"","sources":["../../src/transforms/yodify-conditions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { NodePath } from '@babel/traverse';
2
+ import * as t from '@babel/types';
3
+ export declare function isInDirectivePrologue(path: NodePath): boolean;
4
+ export declare function walkOwnFunctionScope(root: t.Node, callback: (node: t.Node) => void): void;
5
+ export declare function hasDuplicateParamNames(params: t.Function['params']): boolean;
6
+ export declare function isProtoKey(key: t.Node): boolean;
7
+ export declare function isInsideWith(path: NodePath): boolean;
8
+ export declare function enclosingScopeHasDirectEval(path: NodePath): boolean;
9
+ export declare function isDirectEvalCall(node: t.Node): boolean;
10
+ //# sourceMappingURL=ast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/utils/ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAGjC,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAsB7D;AAGD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,KAAK,IAAI,GAAG,IAAI,CAQzF;AAID,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,OAAO,CAW5E;AAID,wBAAgB,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,GAAG,OAAO,CAK/C;AAGD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAKpD;AAID,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAYnE;AAyCD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAG,OAAO,CAEtD"}