webfuscator 1.3.1 → 1.3.3

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 (174) hide show
  1. package/README.md +4 -1
  2. package/dist/obfuscator.d.ts.map +1 -1
  3. package/dist/obfuscator.js +25 -13
  4. package/dist/obfuscator.js.map +1 -1
  5. package/dist/options.d.ts +10 -9
  6. package/dist/options.d.ts.map +1 -1
  7. package/dist/transforms/arguments-to-parameters.d.ts +2 -5
  8. package/dist/transforms/arguments-to-parameters.d.ts.map +1 -1
  9. package/dist/transforms/arguments-to-parameters.js +2 -5
  10. package/dist/transforms/arguments-to-parameters.js.map +1 -1
  11. package/dist/transforms/arrow-to-function.d.ts +3 -4
  12. package/dist/transforms/arrow-to-function.d.ts.map +1 -1
  13. package/dist/transforms/arrow-to-function.js +3 -4
  14. package/dist/transforms/arrow-to-function.js.map +1 -1
  15. package/dist/transforms/collapse-single-use-temps.d.ts +2 -3
  16. package/dist/transforms/collapse-single-use-temps.d.ts.map +1 -1
  17. package/dist/transforms/collapse-single-use-temps.js +2 -3
  18. package/dist/transforms/collapse-single-use-temps.js.map +1 -1
  19. package/dist/transforms/conceal-strings.d.ts +2 -19
  20. package/dist/transforms/conceal-strings.d.ts.map +1 -1
  21. package/dist/transforms/conceal-strings.js +2 -19
  22. package/dist/transforms/conceal-strings.js.map +1 -1
  23. package/dist/transforms/const-let-to-var.d.ts +3 -4
  24. package/dist/transforms/const-let-to-var.d.ts.map +1 -1
  25. package/dist/transforms/const-let-to-var.js +3 -4
  26. package/dist/transforms/const-let-to-var.js.map +1 -1
  27. package/dist/transforms/do-while-to-while.d.ts +2 -3
  28. package/dist/transforms/do-while-to-while.d.ts.map +1 -1
  29. package/dist/transforms/do-while-to-while.js +2 -3
  30. package/dist/transforms/do-while-to-while.js.map +1 -1
  31. package/dist/transforms/drop-console.d.ts +1 -4
  32. package/dist/transforms/drop-console.d.ts.map +1 -1
  33. package/dist/transforms/drop-console.js +1 -4
  34. package/dist/transforms/drop-console.js.map +1 -1
  35. package/dist/transforms/expand-binary-assignment.d.ts +2 -8
  36. package/dist/transforms/expand-binary-assignment.d.ts.map +1 -1
  37. package/dist/transforms/expand-binary-assignment.js +2 -8
  38. package/dist/transforms/expand-binary-assignment.js.map +1 -1
  39. package/dist/transforms/expand-logical-assignment.d.ts +3 -2
  40. package/dist/transforms/expand-logical-assignment.d.ts.map +1 -1
  41. package/dist/transforms/expand-logical-assignment.js +3 -2
  42. package/dist/transforms/expand-logical-assignment.js.map +1 -1
  43. package/dist/transforms/extract-object-properties.d.ts +2 -3
  44. package/dist/transforms/extract-object-properties.d.ts.map +1 -1
  45. package/dist/transforms/extract-object-properties.js +2 -3
  46. package/dist/transforms/extract-object-properties.js.map +1 -1
  47. package/dist/transforms/fold-builtin-methods.d.ts +2 -3
  48. package/dist/transforms/fold-builtin-methods.d.ts.map +1 -1
  49. package/dist/transforms/fold-builtin-methods.js +2 -3
  50. package/dist/transforms/fold-builtin-methods.js.map +1 -1
  51. package/dist/transforms/fold-constants.d.ts +2 -2
  52. package/dist/transforms/fold-constants.js +2 -2
  53. package/dist/transforms/for-to-while.d.ts +2 -3
  54. package/dist/transforms/for-to-while.d.ts.map +1 -1
  55. package/dist/transforms/for-to-while.js +2 -3
  56. package/dist/transforms/for-to-while.js.map +1 -1
  57. package/dist/transforms/function-declaration-to-expression.d.ts +3 -7
  58. package/dist/transforms/function-declaration-to-expression.d.ts.map +1 -1
  59. package/dist/transforms/function-declaration-to-expression.js +3 -7
  60. package/dist/transforms/function-declaration-to-expression.js.map +1 -1
  61. package/dist/transforms/hoist-variables.d.ts +2 -4
  62. package/dist/transforms/hoist-variables.d.ts.map +1 -1
  63. package/dist/transforms/hoist-variables.js +2 -4
  64. package/dist/transforms/hoist-variables.js.map +1 -1
  65. package/dist/transforms/inline-functions.d.ts +2 -2
  66. package/dist/transforms/inline-functions.js +2 -2
  67. package/dist/transforms/logical-to-ternary.d.ts +2 -2
  68. package/dist/transforms/logical-to-ternary.js +2 -2
  69. package/dist/transforms/mangle-properties.d.ts +2 -3
  70. package/dist/transforms/mangle-properties.d.ts.map +1 -1
  71. package/dist/transforms/mangle-properties.js +2 -3
  72. package/dist/transforms/mangle-properties.js.map +1 -1
  73. package/dist/transforms/merge-variable-declarations.d.ts +1 -3
  74. package/dist/transforms/merge-variable-declarations.d.ts.map +1 -1
  75. package/dist/transforms/merge-variable-declarations.js +1 -3
  76. package/dist/transforms/merge-variable-declarations.js.map +1 -1
  77. package/dist/transforms/nullish-coalescing-to-ternary.d.ts +2 -2
  78. package/dist/transforms/nullish-coalescing-to-ternary.js +2 -2
  79. package/dist/transforms/numbers-to-strings.d.ts +1 -5
  80. package/dist/transforms/numbers-to-strings.d.ts.map +1 -1
  81. package/dist/transforms/numbers-to-strings.js +1 -5
  82. package/dist/transforms/numbers-to-strings.js.map +1 -1
  83. package/dist/transforms/object-method-to-property.d.ts +2 -10
  84. package/dist/transforms/object-method-to-property.d.ts.map +1 -1
  85. package/dist/transforms/object-method-to-property.js +2 -10
  86. package/dist/transforms/object-method-to-property.js.map +1 -1
  87. package/dist/transforms/optional-chaining-to-ternary.d.ts +2 -3
  88. package/dist/transforms/optional-chaining-to-ternary.d.ts.map +1 -1
  89. package/dist/transforms/optional-chaining-to-ternary.js +2 -3
  90. package/dist/transforms/optional-chaining-to-ternary.js.map +1 -1
  91. package/dist/transforms/pack-declarations-into-parameters.d.ts +2 -5
  92. package/dist/transforms/pack-declarations-into-parameters.d.ts.map +1 -1
  93. package/dist/transforms/pack-declarations-into-parameters.js +2 -5
  94. package/dist/transforms/pack-declarations-into-parameters.js.map +1 -1
  95. package/dist/transforms/pack-expressions.d.ts +20 -0
  96. package/dist/transforms/pack-expressions.d.ts.map +1 -0
  97. package/dist/transforms/pack-expressions.js +132 -0
  98. package/dist/transforms/pack-expressions.js.map +1 -0
  99. package/dist/transforms/pack.d.ts +2 -4
  100. package/dist/transforms/pack.d.ts.map +1 -1
  101. package/dist/transforms/pack.js +2 -4
  102. package/dist/transforms/pack.js.map +1 -1
  103. package/dist/transforms/remove-unreachable-code.d.ts +2 -4
  104. package/dist/transforms/remove-unreachable-code.d.ts.map +1 -1
  105. package/dist/transforms/remove-unreachable-code.js +2 -4
  106. package/dist/transforms/remove-unreachable-code.js.map +1 -1
  107. package/dist/transforms/remove-unused-code.d.ts +2 -2
  108. package/dist/transforms/remove-unused-code.js +2 -2
  109. package/dist/transforms/rename-identifiers.d.ts +2 -3
  110. package/dist/transforms/rename-identifiers.d.ts.map +1 -1
  111. package/dist/transforms/rename-identifiers.js +2 -3
  112. package/dist/transforms/rename-identifiers.js.map +1 -1
  113. package/dist/transforms/reorder-function-declarations.d.ts +2 -6
  114. package/dist/transforms/reorder-function-declarations.d.ts.map +1 -1
  115. package/dist/transforms/reorder-function-declarations.js +2 -6
  116. package/dist/transforms/reorder-function-declarations.js.map +1 -1
  117. package/dist/transforms/specials-to-strings.d.ts +2 -13
  118. package/dist/transforms/specials-to-strings.d.ts.map +1 -1
  119. package/dist/transforms/specials-to-strings.js +2 -13
  120. package/dist/transforms/specials-to-strings.js.map +1 -1
  121. package/dist/transforms/switch-to-if.d.ts +3 -4
  122. package/dist/transforms/switch-to-if.d.ts.map +1 -1
  123. package/dist/transforms/switch-to-if.js +3 -4
  124. package/dist/transforms/switch-to-if.js.map +1 -1
  125. package/dist/transforms/ternary-to-if.d.ts +2 -3
  126. package/dist/transforms/ternary-to-if.d.ts.map +1 -1
  127. package/dist/transforms/ternary-to-if.js +2 -3
  128. package/dist/transforms/ternary-to-if.js.map +1 -1
  129. package/dist/transforms/update-to-assignment.d.ts +2 -6
  130. package/dist/transforms/update-to-assignment.d.ts.map +1 -1
  131. package/dist/transforms/update-to-assignment.js +2 -6
  132. package/dist/transforms/update-to-assignment.js.map +1 -1
  133. package/dist/transforms/yodify-conditions.d.ts +2 -3
  134. package/dist/transforms/yodify-conditions.d.ts.map +1 -1
  135. package/dist/transforms/yodify-conditions.js +2 -3
  136. package/dist/transforms/yodify-conditions.js.map +1 -1
  137. package/package.json +2 -18
  138. package/src/obfuscator.ts +27 -13
  139. package/src/options.ts +12 -10
  140. package/src/transforms/arguments-to-parameters.ts +2 -5
  141. package/src/transforms/arrow-to-function.ts +3 -4
  142. package/src/transforms/collapse-single-use-temps.ts +2 -3
  143. package/src/transforms/conceal-strings.ts +2 -19
  144. package/src/transforms/const-let-to-var.ts +3 -4
  145. package/src/transforms/do-while-to-while.ts +2 -3
  146. package/src/transforms/drop-console.ts +1 -4
  147. package/src/transforms/expand-binary-assignment.ts +2 -8
  148. package/src/transforms/expand-logical-assignment.ts +3 -2
  149. package/src/transforms/extract-object-properties.ts +2 -3
  150. package/src/transforms/fold-builtin-methods.ts +2 -3
  151. package/src/transforms/fold-constants.ts +2 -2
  152. package/src/transforms/for-to-while.ts +2 -3
  153. package/src/transforms/function-declaration-to-expression.ts +3 -7
  154. package/src/transforms/hoist-variables.ts +2 -4
  155. package/src/transforms/inline-functions.ts +2 -2
  156. package/src/transforms/logical-to-ternary.ts +2 -2
  157. package/src/transforms/mangle-properties.ts +2 -3
  158. package/src/transforms/merge-variable-declarations.ts +1 -3
  159. package/src/transforms/nullish-coalescing-to-ternary.ts +2 -2
  160. package/src/transforms/numbers-to-strings.ts +1 -5
  161. package/src/transforms/object-method-to-property.ts +2 -10
  162. package/src/transforms/optional-chaining-to-ternary.ts +2 -3
  163. package/src/transforms/pack-declarations-into-parameters.ts +2 -5
  164. package/src/transforms/pack-expressions.ts +159 -0
  165. package/src/transforms/pack.ts +2 -4
  166. package/src/transforms/remove-unreachable-code.ts +2 -4
  167. package/src/transforms/remove-unused-code.ts +2 -2
  168. package/src/transforms/rename-identifiers.ts +2 -3
  169. package/src/transforms/reorder-function-declarations.ts +2 -6
  170. package/src/transforms/specials-to-strings.ts +2 -13
  171. package/src/transforms/switch-to-if.ts +3 -4
  172. package/src/transforms/ternary-to-if.ts +2 -3
  173. package/src/transforms/update-to-assignment.ts +2 -6
  174. package/src/transforms/yodify-conditions.ts +2 -3
@@ -9,9 +9,8 @@ import type { ChangeState } from '../utils/change-tracking'
9
9
  import { isCalleeOrTagOf } from '../utils/paths'
10
10
 
11
11
  /**
12
- * Replaces a constant object or array wrapper with one binding per entry when
13
- * every reference is a static-key read. The inliner can then see function
14
- * values directly.
12
+ * Replaces eligible object and array wrapper bindings with separate bindings
13
+ * for their statically accessed entries.
15
14
  *
16
15
  * @example
17
16
  * // ◀️ before
@@ -10,9 +10,8 @@ import type { ChangeState } from '../utils/change-tracking'
10
10
  import { valueToLiteral } from '../utils/literal'
11
11
 
12
12
  /**
13
- * Replaces built-in calls and reads with smaller syntax or host-computed
14
- * constants. Host evaluation requires known arguments and receivers. Shadowed
15
- * names, optional forms, and regexp methods stay unchanged.
13
+ * Replaces eligible built-in calls and property reads with smaller equivalent
14
+ * expressions or constants.
16
15
  *
17
16
  * @example
18
17
  * // ◀️ before
@@ -10,8 +10,8 @@ import { valueToLiteral } from '../utils/literal'
10
10
  import { isCalleeOrTagOf } from '../utils/paths'
11
11
 
12
12
  /**
13
- * Folds pure constant expressions to literals via `evaluateConstant`.
14
- * Logical and conditional nodes can fold directly to a chosen nonliteral branch.
13
+ * Replaces pure compile-time constant expressions with equivalent literals or
14
+ * selected branches.
15
15
  *
16
16
  * @example
17
17
  * // ◀️ before
@@ -7,9 +7,8 @@ import type { ChangeState } from '../utils/change-tracking'
7
7
  import { collectLoopLabels, generateLoopLabel, redirectContinues } from '../utils/loop-lowering'
8
8
 
9
9
  /**
10
- * Rewrites classic `for` loops as an initializer followed by `while`. Continues
11
- * become breaks from an inner block so the update still runs. Iterator loops
12
- * stay unchanged.
10
+ * Rewrites classic `for` loops as equivalent `while` loops. `for...in` and
11
+ * `for...of` loops stay unchanged.
13
12
  *
14
13
  * @example
15
14
  * // ◀️ before
@@ -6,13 +6,9 @@ import { traverseForChanges } from '../utils/change-tracking'
6
6
  import type { ChangeState } from '../utils/change-tracking'
7
7
 
8
8
  /**
9
- * Rewrites function declarations at script top level or directly inside a
10
- * function body as `var` initializers. It leaves a declaration unchanged when
11
- * an earlier statement could execute user code before the assignment.
12
- *
13
- * Name inference and recursive references still use the `var` binding.
14
- *
15
- * Block-level and module top-level declarations stay unchanged.
9
+ * Rewrites eligible function declarations in scripts and function bodies as
10
+ * `var`-initialized function expressions. Declarations stay unchanged when
11
+ * moving initialization to their statement position could alter execution.
16
12
  *
17
13
  * @example
18
14
  * // ◀️ before
@@ -6,10 +6,8 @@ import type { File } from '@babel/types'
6
6
  import type { ChangeState } from '../utils/change-tracking'
7
7
 
8
8
  /**
9
- * Moves `var` declarations to the start of their var scope without moving
10
- * initializer evaluation.
11
- *
12
- * Direct exports stay in place. Static blocks keep separate declarations.
9
+ * Moves `var` declarations to the beginning of their containing function or
10
+ * program without moving initializer evaluation.
13
11
  *
14
12
  * @example
15
13
  * // ◀️ before
@@ -12,8 +12,8 @@ import { generateLoopLabel } from '../utils/loop-lowering'
12
12
  import { isInStrictContext } from '../utils/paths'
13
13
 
14
14
  /**
15
- * Replaces eligible calls with function bodies, working from inner calls out.
16
- * Declarations are removed after their last reference disappears.
15
+ * Replaces eligible function calls with the called function's body and removes
16
+ * declarations that become unused.
17
17
  *
18
18
  * @example
19
19
  * // ◀️ before
@@ -9,8 +9,8 @@ import { lowerLogicalWriteStatement } from '../utils/logical-lowering'
9
9
  import { buildNonNullishCheck, buildNullishCheck } from '../utils/nullish'
10
10
 
11
11
  /**
12
- * Rewrites logical expressions as guarded assignments or ternaries. A
13
- * side-effectful left side is cached in the ternary test for later hoisting.
12
+ * Rewrites logical expressions as equivalent conditional expressions or
13
+ * guarded assignments while preserving short-circuit evaluation.
14
14
  *
15
15
  * @example
16
16
  * // ◀️ before
@@ -12,9 +12,8 @@ import { mulberry32 } from '../utils/random'
12
12
  import { StringGenerator } from '../utils/string-generator'
13
13
 
14
14
  /**
15
- * Renames statically known public properties through one program-wide mapping.
16
- * Options select or reserve names, and collision checks keep every unchanged
17
- * property distinct from the generated names.
15
+ * Renames statically known public properties using one consistent program-wide
16
+ * mapping.
18
17
  *
19
18
  * @example
20
19
  * // ◀️ before
@@ -4,9 +4,7 @@ import type { File } from '@babel/types'
4
4
  import { rewriteStatementLists } from '../utils/statement-lists'
5
5
 
6
6
  /**
7
- * Merges adjacent variable declarations when their kinds and export wrappers
8
- * match. It runs in programs, blocks, switch cases, and static blocks, and
9
- * removes unlabeled empty statements between compatible declarations.
7
+ * Merges adjacent compatible variable declarations into a single declaration.
10
8
  *
11
9
  * @example
12
10
  * // ◀️ before
@@ -8,8 +8,8 @@ import { lowerLogicalWriteStatement } from '../utils/logical-lowering'
8
8
  import { buildNonNullishCheck, buildNullishCheck } from '../utils/nullish'
9
9
 
10
10
  /**
11
- * Rewrites `a ?? b` as a guarded assignment or strict null and undefined
12
- * checks. A side-effectful left side is cached.
11
+ * Rewrites nullish-coalescing expressions as equivalent conditional expressions
12
+ * while evaluating the left operand once.
13
13
  *
14
14
  * @example
15
15
  * // ◀️ before
@@ -7,11 +7,7 @@ import { traverseForChanges } from '../utils/change-tracking'
7
7
  import type { ChangeState } from '../utils/change-tracking'
8
8
 
9
9
  /**
10
- * Rewrites numeric literals as strings coerced with unary plus. Under `+`, `-`,
11
- * or `~`, the existing operator supplies that coercion. Other unary operators
12
- * keep the wrapper because their string behavior differs.
13
- *
14
- * Preparation has already converted numeric object keys to strings.
10
+ * Rewrites numeric literals as equivalent string-coercion expressions.
15
11
  *
16
12
  * @example
17
13
  * // ◀️ before
@@ -7,16 +7,8 @@ import { traverseForChanges } from '../utils/change-tracking'
7
7
  import type { ChangeState } from '../utils/change-tracking'
8
8
 
9
9
  /**
10
- * Rewrites generator and async object methods as function-valued properties so
11
- * later passes can lift and inline them.
12
- *
13
- * Plain methods stay concise because a function property would gain construction
14
- * and `prototype`. Generator and async functions remain non-constructors. Any
15
- * method using `super` also stays intact because a function has no HomeObject.
16
- *
17
- * Non-computed `__proto__` methods stay intact because the property form invokes
18
- * ECMA-262 B.3.1 prototype-setting behavior. Computed keys create own properties
19
- * and can be rewritten.
10
+ * Rewrites eligible async and generator object methods as function-valued
11
+ * properties.
20
12
  *
21
13
  * @example
22
14
  * // ◀️ before
@@ -7,9 +7,8 @@ import type { ChangeState } from '../utils/change-tracking'
7
7
  import { buildNullishCheck } from '../utils/nullish'
8
8
 
9
9
  /**
10
- * Rewrites optional chains as nested ternaries. Side-effectful receivers are
11
- * cached, and member calls retain their `this`. Optional deletion short-circuits
12
- * to `true` as required by ECMA-262 13.5.1.
10
+ * Rewrites optional chains as equivalent conditional expressions while
11
+ * preserving short-circuiting and method receivers.
13
12
  *
14
13
  * @example
15
14
  * // ◀️ before
@@ -8,11 +8,8 @@ import type { ChangeState } from '../utils/change-tracking'
8
8
  import { isLiteralShaped } from '../utils/literal'
9
9
 
10
10
  /**
11
- * Moves leading literal-valued `var` declarations into trailing default
12
- * parameters. Arrows, rest parameters, name collisions, and functions with
13
- * callers that could fill a new slot stay unchanged.
14
- *
15
- * Packing also requires unchanged `arguments`, directive, and hoisting behavior.
11
+ * Moves eligible leading `var` declarations with literal initializers into
12
+ * trailing default parameters.
16
13
  *
17
14
  * @example
18
15
  * // ◀️ before
@@ -0,0 +1,159 @@
1
+ import * as t from '@babel/types'
2
+ import type { File } from '@babel/types'
3
+
4
+ import { rewriteStatementLists } from '../utils/statement-lists'
5
+
6
+ /**
7
+ * Combines adjacent expression statements with the comma operator and moves
8
+ * them into a following compatible statement when execution order is preserved.
9
+ *
10
+ * @example
11
+ * // ◀️ before
12
+ * function run() {
13
+ * prepare();
14
+ * update();
15
+ * return finish();
16
+ * }
17
+ *
18
+ * // ▶️ after
19
+ * function run() {
20
+ * return prepare(), update(), finish();
21
+ * }
22
+ */
23
+ export function packExpressions(ast: File): boolean {
24
+ return rewriteStatementLists(ast, (statements) =>
25
+ packStatementList(statements.map((path) => path.node)),
26
+ )
27
+ }
28
+
29
+ type StatementLike = t.Program['body'][number]
30
+
31
+ function packStatementList(list: readonly StatementLike[]): StatementLike[] | null {
32
+ const out: StatementLike[] = []
33
+ let pending: t.ExpressionStatement[] = []
34
+ let changed = false
35
+
36
+ const flush = (): void => {
37
+ if (pending.length === 1) {
38
+ out.push(pending[0]!)
39
+ } else if (pending.length > 1) {
40
+ out.push(
41
+ t.expressionStatement(
42
+ expressionFrom(
43
+ flattenExpressions(pending.map((pendingStatement) => pendingStatement.expression)),
44
+ ),
45
+ ),
46
+ )
47
+ changed = true
48
+ }
49
+ pending = []
50
+ }
51
+
52
+ for (const statement of list) {
53
+ if (t.isExpressionStatement(statement)) {
54
+ pending.push(statement)
55
+ continue
56
+ }
57
+
58
+ if (pending.length > 0) {
59
+ const expressions = flattenExpressions(
60
+ pending.map((pendingStatement) => pendingStatement.expression),
61
+ )
62
+ if (prependToConsumer(statement, expressions)) {
63
+ out.push(statement)
64
+ pending = []
65
+ changed = true
66
+ continue
67
+ }
68
+ }
69
+
70
+ flush()
71
+ out.push(statement)
72
+ }
73
+
74
+ flush()
75
+ return changed ? out : null
76
+ }
77
+
78
+ function prependToConsumer(statement: StatementLike, expressions: t.Expression[]): boolean {
79
+ if (t.isReturnStatement(statement)) {
80
+ const argument = statement.argument ?? t.unaryExpression('void', t.numericLiteral(0))
81
+ statement.argument = prependExpressions(expressions, argument)
82
+ return true
83
+ }
84
+ if (t.isThrowStatement(statement)) {
85
+ statement.argument = prependExpressions(expressions, statement.argument)
86
+ return true
87
+ }
88
+ if (t.isIfStatement(statement)) {
89
+ statement.test = prependExpressions(expressions, statement.test)
90
+ return true
91
+ }
92
+ if (t.isSwitchStatement(statement)) {
93
+ statement.discriminant = prependExpressions(expressions, statement.discriminant)
94
+ return true
95
+ }
96
+ if (t.isWithStatement(statement)) {
97
+ statement.object = prependExpressions(expressions, statement.object)
98
+ return true
99
+ }
100
+ if (t.isForStatement(statement)) {
101
+ if (t.isVariableDeclaration(statement.init)) {
102
+ return false
103
+ }
104
+ statement.init = statement.init
105
+ ? prependExpressions(expressions, statement.init)
106
+ : expressionFrom(expressions)
107
+ return true
108
+ }
109
+ if (t.isForInStatement(statement) || t.isForOfStatement(statement)) {
110
+ if (!canPrependToForXRight(statement.left)) {
111
+ return false
112
+ }
113
+ statement.right = prependExpressions(expressions, statement.right)
114
+ return true
115
+ }
116
+ return false
117
+ }
118
+
119
+ function canPrependToForXRight(left: t.ForInStatement['left']): boolean {
120
+ if (!t.isVariableDeclaration(left)) {
121
+ return true
122
+ }
123
+ // A lexical loop head is active while the right side runs; a preceding
124
+ // statement is outside it. A legacy var initializer also runs before the
125
+ // right side.
126
+ return left.kind === 'var' && left.declarations.every((declaration) => !declaration.init)
127
+ }
128
+
129
+ function flattenExpressions(input: readonly t.Expression[]): t.Expression[] {
130
+ const remaining: t.Expression[] = []
131
+ for (let index = input.length - 1; index >= 0; index--) {
132
+ remaining.push(input[index]!)
133
+ }
134
+
135
+ const expressions: t.Expression[] = []
136
+ while (remaining.length > 0) {
137
+ const expression = remaining.pop()!
138
+ if (t.isSequenceExpression(expression)) {
139
+ for (let index = expression.expressions.length - 1; index >= 0; index--) {
140
+ remaining.push(expression.expressions[index]!)
141
+ }
142
+ } else {
143
+ expressions.push(expression)
144
+ }
145
+ }
146
+ return expressions
147
+ }
148
+
149
+ function prependExpressions(
150
+ expressions: readonly t.Expression[],
151
+ consumer: t.Expression,
152
+ ): t.Expression {
153
+ const flattenedConsumer = flattenExpressions([consumer])
154
+ return expressionFrom([...expressions, ...flattenedConsumer])
155
+ }
156
+
157
+ function expressionFrom(expressions: t.Expression[]): t.Expression {
158
+ return expressions.length === 1 ? expressions[0]! : t.sequenceExpression(expressions)
159
+ }
@@ -107,10 +107,8 @@ const STANDARD_GLOBALS: readonly string[] = [
107
107
  ]
108
108
 
109
109
  /**
110
- * Serializes the whole program and runs it through the `Function` constructor.
111
- * Imports stay outside the generated function. Reads and writes to other free
112
- * names go through accessors created in the original top-level scope. Export
113
- * statements are rejected because they cannot appear in a `Function` body.
110
+ * Serializes the program and executes it through a generated `Function`
111
+ * constructor.
114
112
  *
115
113
  * @example
116
114
  * // ◀️ before
@@ -6,10 +6,8 @@ import { traverseForChanges } from '../utils/change-tracking'
6
6
  import type { ChangeState } from '../utils/change-tracking'
7
7
 
8
8
  /**
9
- * Removes statements after unconditional control flow in the same statement list.
10
- *
11
- * Hoisted function and `var` declarations stay because reachable code may still
12
- * observe their bindings.
9
+ * Removes unreachable statements that follow unconditional control flow while
10
+ * retaining declarations whose hoisting can still be observed.
13
11
  *
14
12
  * @example
15
13
  * // ◀️ before
@@ -7,8 +7,8 @@ import { isSideEffectFree } from '../analysis/purity'
7
7
  import type { ChangeState } from '../utils/change-tracking'
8
8
 
9
9
  /**
10
- * Removes unused declarations and expression statements that have no effects.
11
- * Sweeps continue because each removal can strand another binding.
10
+ * Removes unused declarations and side-effect-free expression statements until
11
+ * no further code becomes unused.
12
12
  *
13
13
  * @example
14
14
  * // ◀️ before
@@ -9,9 +9,8 @@ import { mulberry32 } from '../utils/random'
9
9
  import { StringGenerator } from '../utils/string-generator'
10
10
 
11
11
  /**
12
- * Renames bindings and labels with the configured string generator. Generated
13
- * names do not capture unresolved names or bindings still used from an outer
14
- * scope. Separate sibling scopes may reuse the same names.
12
+ * Renames bindings and labels with the configured string generator while
13
+ * avoiding name capture.
15
14
  *
16
15
  * @example
17
16
  * // ◀️ before
@@ -6,12 +6,8 @@ import { rewriteStatementLists } from '../utils/statement-lists'
6
6
  import type { StatementListContainer } from '../utils/statement-lists'
7
7
 
8
8
  /**
9
- * Moves hoisted function declarations to the end of each program, block, switch
10
- * case, or static block. It keeps declaration order, including duplicate names.
11
- *
12
- * If moving every declaration would turn a string expression into a directive,
13
- * one declaration stays before the string. Direct exports stay in place.
14
- * Indirect exports move with their local declaration.
9
+ * Moves hoisted function declarations to the end of their statement lists
10
+ * without changing their relative order.
15
11
  *
16
12
  * @example
17
13
  * // ◀️ before
@@ -9,19 +9,8 @@ import { mulberry32 } from '../utils/random'
9
9
  import { StringGenerator } from '../utils/string-generator'
10
10
 
11
11
  /**
12
- * Rewrites five constant-like values through strings for later string mangling:
13
- *
14
- * - `true` -> `!!"<random>"`
15
- * - `false` -> `!"<random>"`
16
- * - `NaN` -> `+"<random>"`
17
- * - `undefined`-> `void "<random>"`
18
- * - `Infinity` -> `1/!"<random>"`
19
- *
20
- * Generated strings are nonempty and nonnumeric, fixing their truthiness and
21
- * numeric coercion.
22
- *
23
- * `NaN`, `Infinity`, and `undefined` require genuine global reads. Delete and
24
- * write positions stay unchanged because the replacement is not a reference.
12
+ * Rewrites `true`, `false`, `NaN`, `undefined`, and `Infinity` as equivalent
13
+ * expressions built from strings.
25
14
  *
26
15
  * @example
27
16
  * // ◀️ before
@@ -9,10 +9,9 @@ import { isPrimitiveLiteral } from '../utils/literal'
9
9
  import { generateLoopLabel } from '../utils/loop-lowering'
10
10
 
11
11
  /**
12
- * Lowers `switch` to an `if` chain or, when cases fall through, a labeled block
13
- * with a fallthrough flag. Case tests keep source order and evaluation count.
14
- * Cases with lexical or function declarations stay unchanged because separate
15
- * `if` blocks cannot preserve the shared switch scope.
12
+ * Rewrites eligible `switch` statements as equivalent `if` statements, using a
13
+ * labeled block when fallthrough must be preserved. Switches whose shared case
14
+ * scope cannot be preserved stay unchanged.
16
15
  *
17
16
  * @example
18
17
  * // ◀️ before
@@ -8,9 +8,8 @@ import { isConditionalGate, reorderableToStatement } from '../utils/evaluation-o
8
8
  import { isStandaloneDeclaration } from '../utils/paths'
9
9
 
10
10
  /**
11
- * Lowers conditional expressions to `if` statements. Expression values use a
12
- * temporary. Parameter defaults and repeating loop tests stay unchanged because
13
- * hoisting would change when they run.
11
+ * Rewrites eligible conditional expressions as `if` statements, using a
12
+ * temporary when their value is needed.
14
13
  *
15
14
  * @example
16
15
  * // ◀️ before
@@ -6,12 +6,8 @@ import { traverseForChanges } from '../utils/change-tracking'
6
6
  import type { ChangeState } from '../utils/change-tracking'
7
7
 
8
8
  /**
9
- * Rewrites numeric updates as compound assignments for later expansion. Prefix
10
- * results already match. Postfix forms require a position that discards the old
11
- * value.
12
- *
13
- * BigInt differs because adding the number `1` throws. Only bindings proven to
14
- * stay numeric are rewritten. Members and parameters stay unchanged.
9
+ * Rewrites eligible numeric update expressions as compound assignments. Postfix
10
+ * updates stay unchanged when their original value is used.
15
11
  *
16
12
  * @example
17
13
  * // ◀️ before
@@ -7,9 +7,8 @@ import type { ChangeState } from '../utils/change-tracking'
7
7
  import { isLiteralShaped } from '../utils/literal'
8
8
 
9
9
  /**
10
- * Moves a right operand made from literals and unary operators to the left of a
11
- * comparison when swapping does not change coercion order. Relational operators
12
- * are flipped after swapping.
10
+ * Moves eligible literal-like right operands to the left side of comparisons,
11
+ * reversing relational operators as needed.
13
12
  *
14
13
  * @example
15
14
  * // ◀️ before