webfuscator 1.1.0 → 1.2.0

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 (152) hide show
  1. package/dist/analysis/constant.js +3 -3
  2. package/dist/analysis/constant.js.map +1 -1
  3. package/dist/analysis/inlineability.js +2 -2
  4. package/dist/analysis/inlineability.js.map +1 -1
  5. package/dist/analysis/purity.js +1 -1
  6. package/dist/analysis/purity.js.map +1 -1
  7. package/dist/index.d.ts +2 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/obfuscator.d.ts.map +1 -1
  11. package/dist/obfuscator.js.map +1 -1
  12. package/dist/options.d.ts.map +1 -1
  13. package/dist/preparation/expand-destructuring.js +4 -3
  14. package/dist/preparation/expand-destructuring.js.map +1 -1
  15. package/dist/preparation/expand-template-literals.js +3 -2
  16. package/dist/preparation/expand-template-literals.js.map +1 -1
  17. package/dist/preparation/split-sequence-expressions.js +1 -1
  18. package/dist/preparation/split-sequence-expressions.js.map +1 -1
  19. package/dist/preparation/split-variable-declarations.js +1 -1
  20. package/dist/preparation/split-variable-declarations.js.map +1 -1
  21. package/dist/preparation/stringify-object-keys.js +1 -1
  22. package/dist/preparation/stringify-object-keys.js.map +1 -1
  23. package/dist/preparation/wrap-single-statements.js +2 -2
  24. package/dist/preparation/wrap-single-statements.js.map +1 -1
  25. package/dist/transforms/arguments-to-parameters.js +1 -1
  26. package/dist/transforms/arguments-to-parameters.js.map +1 -1
  27. package/dist/transforms/arrow-to-function.js.map +1 -1
  28. package/dist/transforms/collapse-single-use-temps.js +7 -7
  29. package/dist/transforms/collapse-single-use-temps.js.map +1 -1
  30. package/dist/transforms/const-let-to-var.js +3 -3
  31. package/dist/transforms/const-let-to-var.js.map +1 -1
  32. package/dist/transforms/const-to-let.js.map +1 -1
  33. package/dist/transforms/do-while-to-while.js +3 -3
  34. package/dist/transforms/do-while-to-while.js.map +1 -1
  35. package/dist/transforms/drop-console.js +4 -3
  36. package/dist/transforms/drop-console.js.map +1 -1
  37. package/dist/transforms/drop-debugger.js.map +1 -1
  38. package/dist/transforms/expand-binary-assignment.js +5 -3
  39. package/dist/transforms/expand-binary-assignment.js.map +1 -1
  40. package/dist/transforms/expand-logical-assignment.js +5 -3
  41. package/dist/transforms/expand-logical-assignment.js.map +1 -1
  42. package/dist/transforms/extract-object-properties.js +7 -7
  43. package/dist/transforms/extract-object-properties.js.map +1 -1
  44. package/dist/transforms/fold-builtin-methods.js +16 -15
  45. package/dist/transforms/fold-builtin-methods.js.map +1 -1
  46. package/dist/transforms/fold-constants.js +2 -2
  47. package/dist/transforms/fold-constants.js.map +1 -1
  48. package/dist/transforms/for-to-while.js +5 -5
  49. package/dist/transforms/for-to-while.js.map +1 -1
  50. package/dist/transforms/function-declaration-to-expression.js +3 -3
  51. package/dist/transforms/function-declaration-to-expression.js.map +1 -1
  52. package/dist/transforms/inline-functions.js +7 -7
  53. package/dist/transforms/inline-functions.js.map +1 -1
  54. package/dist/transforms/logical-to-ternary.js +2 -2
  55. package/dist/transforms/logical-to-ternary.js.map +1 -1
  56. package/dist/transforms/mangle-properties.d.ts.map +1 -1
  57. package/dist/transforms/mangle-properties.js +35 -86
  58. package/dist/transforms/mangle-properties.js.map +1 -1
  59. package/dist/transforms/nullish-coalescing-to-ternary.js +2 -2
  60. package/dist/transforms/nullish-coalescing-to-ternary.js.map +1 -1
  61. package/dist/transforms/numbers-to-strings.js +2 -2
  62. package/dist/transforms/numbers-to-strings.js.map +1 -1
  63. package/dist/transforms/object-method-to-property.js +1 -1
  64. package/dist/transforms/object-method-to-property.js.map +1 -1
  65. package/dist/transforms/optional-chaining-to-ternary.js +2 -2
  66. package/dist/transforms/optional-chaining-to-ternary.js.map +1 -1
  67. package/dist/transforms/pack-declarations-into-parameters.js +2 -2
  68. package/dist/transforms/pack-declarations-into-parameters.js.map +1 -1
  69. package/dist/transforms/pack.d.ts.map +1 -1
  70. package/dist/transforms/pack.js +10 -11
  71. package/dist/transforms/pack.js.map +1 -1
  72. package/dist/transforms/remove-anonymous-function-names.js +3 -3
  73. package/dist/transforms/remove-anonymous-function-names.js.map +1 -1
  74. package/dist/transforms/remove-unreachable-code.js +1 -1
  75. package/dist/transforms/remove-unreachable-code.js.map +1 -1
  76. package/dist/transforms/remove-unused-code.js +4 -4
  77. package/dist/transforms/remove-unused-code.js.map +1 -1
  78. package/dist/transforms/rename-identifiers.d.ts.map +1 -1
  79. package/dist/transforms/rename-identifiers.js +4 -3
  80. package/dist/transforms/rename-identifiers.js.map +1 -1
  81. package/dist/transforms/specials-to-strings.d.ts.map +1 -1
  82. package/dist/transforms/specials-to-strings.js +2 -2
  83. package/dist/transforms/specials-to-strings.js.map +1 -1
  84. package/dist/transforms/switch-to-if.js +7 -7
  85. package/dist/transforms/switch-to-if.js.map +1 -1
  86. package/dist/transforms/ternary-to-if.js +7 -4
  87. package/dist/transforms/ternary-to-if.js.map +1 -1
  88. package/dist/transforms/update-to-assignment.js +4 -2
  89. package/dist/transforms/update-to-assignment.js.map +1 -1
  90. package/dist/transforms/yodify-conditions.js +3 -3
  91. package/dist/transforms/yodify-conditions.js.map +1 -1
  92. package/dist/utils/ast.d.ts.map +1 -1
  93. package/dist/utils/ast.js +2 -1
  94. package/dist/utils/ast.js.map +1 -1
  95. package/dist/utils/evaluation-order.js.map +1 -1
  96. package/dist/utils/logical-lowering.js +2 -2
  97. package/dist/utils/logical-lowering.js.map +1 -1
  98. package/dist/utils/loop-lowering.js +1 -1
  99. package/dist/utils/loop-lowering.js.map +1 -1
  100. package/dist/utils/string-generator.js +1 -1
  101. package/dist/utils/string-generator.js.map +1 -1
  102. package/package.json +11 -10
  103. package/src/analysis/constant.ts +4 -4
  104. package/src/analysis/inlineability.ts +4 -4
  105. package/src/analysis/purity.ts +3 -3
  106. package/src/index.ts +4 -2
  107. package/src/obfuscator.ts +42 -42
  108. package/src/options.ts +1 -1
  109. package/src/preparation/expand-destructuring.ts +5 -4
  110. package/src/preparation/expand-template-literals.ts +4 -3
  111. package/src/preparation/split-sequence-expressions.ts +2 -2
  112. package/src/preparation/split-variable-declarations.ts +1 -1
  113. package/src/preparation/stringify-object-keys.ts +2 -2
  114. package/src/preparation/wrap-single-statements.ts +2 -2
  115. package/src/transforms/arguments-to-parameters.ts +5 -5
  116. package/src/transforms/arrow-to-function.ts +3 -3
  117. package/src/transforms/collapse-single-use-temps.ts +14 -14
  118. package/src/transforms/const-let-to-var.ts +6 -6
  119. package/src/transforms/const-to-let.ts +4 -4
  120. package/src/transforms/do-while-to-while.ts +6 -6
  121. package/src/transforms/drop-console.ts +8 -7
  122. package/src/transforms/drop-debugger.ts +2 -2
  123. package/src/transforms/expand-binary-assignment.ts +8 -6
  124. package/src/transforms/expand-logical-assignment.ts +8 -6
  125. package/src/transforms/extract-object-properties.ts +12 -12
  126. package/src/transforms/fold-builtin-methods.ts +20 -19
  127. package/src/transforms/fold-constants.ts +8 -8
  128. package/src/transforms/for-to-while.ts +8 -8
  129. package/src/transforms/function-declaration-to-expression.ts +5 -5
  130. package/src/transforms/inline-functions.ts +14 -14
  131. package/src/transforms/logical-to-ternary.ts +7 -7
  132. package/src/transforms/mangle-properties.ts +43 -97
  133. package/src/transforms/nullish-coalescing-to-ternary.ts +6 -6
  134. package/src/transforms/numbers-to-strings.ts +4 -4
  135. package/src/transforms/object-method-to-property.ts +4 -4
  136. package/src/transforms/optional-chaining-to-ternary.ts +5 -5
  137. package/src/transforms/pack-declarations-into-parameters.ts +7 -7
  138. package/src/transforms/pack.ts +20 -16
  139. package/src/transforms/remove-anonymous-function-names.ts +5 -5
  140. package/src/transforms/remove-unreachable-code.ts +3 -3
  141. package/src/transforms/remove-unused-code.ts +8 -8
  142. package/src/transforms/rename-identifiers.ts +9 -8
  143. package/src/transforms/specials-to-strings.ts +7 -7
  144. package/src/transforms/switch-to-if.ts +12 -12
  145. package/src/transforms/ternary-to-if.ts +12 -9
  146. package/src/transforms/update-to-assignment.ts +7 -5
  147. package/src/transforms/yodify-conditions.ts +6 -6
  148. package/src/utils/ast.ts +2 -1
  149. package/src/utils/evaluation-order.ts +1 -1
  150. package/src/utils/logical-lowering.ts +3 -3
  151. package/src/utils/loop-lowering.ts +1 -1
  152. package/src/utils/string-generator.ts +1 -1
@@ -2,11 +2,11 @@ import type { NodePath, Visitor } from '@babel/traverse'
2
2
  import * as t from '@babel/types'
3
3
  import type { File } from '@babel/types'
4
4
 
5
- import { isPure } from 'src/analysis/purity'
6
- import { isInsideWith } from 'src/utils/ast'
7
- import { traverseForChanges } from 'src/utils/change-tracking'
8
- import type { ChangeState } from 'src/utils/change-tracking'
9
- import { lowerLogicalWriteStatement } from 'src/utils/logical-lowering'
5
+ import { isPure } from '../analysis/purity'
6
+ import { isInsideWith } from '../utils/ast'
7
+ import { traverseForChanges } from '../utils/change-tracking'
8
+ import type { ChangeState } from '../utils/change-tracking'
9
+ import { lowerLogicalWriteStatement } from '../utils/logical-lowering'
10
10
 
11
11
  /**
12
12
  * Rewrites logical expressions as guarded assignments or ternaries. A
@@ -40,7 +40,7 @@ const visitor: Visitor<ChangeState> = {
40
40
  }
41
41
 
42
42
  function lowerLogical(path: NodePath<t.LogicalExpression>): boolean {
43
- const { node } = path
43
+ const node = path.node
44
44
  const op = node.operator
45
45
  if (op !== '&&' && op !== '||' && op !== '??') {
46
46
  return false
@@ -54,7 +54,7 @@ function lowerLogical(path: NodePath<t.LogicalExpression>): boolean {
54
54
  return true
55
55
  }
56
56
 
57
- const { scope } = path
57
+ const scope = path.scope
58
58
  const leftPath = path.get('left')
59
59
  let testSrc: t.Expression
60
60
  let valueSrc: t.Expression
@@ -3,13 +3,13 @@ import type { NodePath, Scope, Visitor } from '@babel/traverse'
3
3
  import * as t from '@babel/types'
4
4
  import type { File } from '@babel/types'
5
5
 
6
- import { evaluateConstant, isOpaque } from 'src/analysis/constant'
7
- import type { ManglePropertiesOptions, PropertyNameGenerator, TransformContext } from 'src/options'
8
- import { isProtoKey } from 'src/utils/ast'
9
- import type { ChangeState } from 'src/utils/change-tracking'
10
- import { DOM_PROPERTIES } from 'src/utils/dom-properties'
11
- import { mulberry32 } from 'src/utils/random'
12
- import { StringGenerator } from 'src/utils/string-generator'
6
+ import { evaluateConstant, isOpaque } from '../analysis/constant'
7
+ import type { ManglePropertiesOptions, PropertyNameGenerator, TransformContext } from '../options'
8
+ import { isProtoKey } from '../utils/ast'
9
+ import type { ChangeState } from '../utils/change-tracking'
10
+ import { DOM_PROPERTIES } from '../utils/dom-properties'
11
+ import { mulberry32 } from '../utils/random'
12
+ import { StringGenerator } from '../utils/string-generator'
13
13
 
14
14
  /**
15
15
  * Renames statically known public properties through one program-wide mapping.
@@ -49,6 +49,27 @@ const NUMERIC_PROPERTY_RE = /^-?[0-9]+(?:\.[0-9]+)?(?:e[+-][0-9]+)?$/u
49
49
  const SYNTAX_SENSITIVE_GENERATED_NAMES = new Set(['__proto__', 'constructor', 'prototype'])
50
50
  const MAX_GENERATOR_ATTEMPTS = 100_000
51
51
 
52
+ /**
53
+ * Names a platform object may own wherever the output runs. That could be a
54
+ * browser, a Node process, or an embedded engine, and nothing here can tell
55
+ * which, so the table unions every host name Terser collected. Renaming a name
56
+ * the target owns breaks the program. Reserving one it does not own costs a
57
+ * single missed rename.
58
+ *
59
+ * `builtins: true` is the caller promising that none of these names reach a
60
+ * platform object in their target.
61
+ */
62
+ const RESERVED_PROPERTIES: ReadonlySet<string> = new Set([
63
+ ...DOM_PROPERTIES,
64
+ // V8 reads `Error.prepareStackTrace` back off the constructor, and it postdates the table.
65
+ 'prepareStackTrace',
66
+ // Not host names. ES3 rejects a keyword after `.`, which some downstream
67
+ // tooling still enforces, so they stay out of the generated keys too.
68
+ 'false',
69
+ 'null',
70
+ 'true',
71
+ ])
72
+
52
73
  type KeyedProperty =
53
74
  | t.ClassAccessorProperty
54
75
  | t.ClassMethod
@@ -92,7 +113,7 @@ class PropertyManglerState implements ChangeState {
92
113
  this.regex = compileRegex(options.regex)
93
114
 
94
115
  if (!options.builtins) {
95
- for (const name of builtinProperties()) {
116
+ for (const name of RESERVED_PROPERTIES) {
96
117
  this.reserved.add(name)
97
118
  }
98
119
  }
@@ -292,7 +313,7 @@ const collectVisitor: Visitor<PropertyManglerState> = {
292
313
  (t.isCallExpression(path.node) || t.isOptionalCallExpression(path.node)) &&
293
314
  isObjectDefinePropertyCall(path as NodePath<Call>)
294
315
  ) {
295
- const [, key] = path.node.arguments
316
+ const key = path.node.arguments[1]
296
317
  if (key && t.isExpression(key)) {
297
318
  collectTerminalNames(key, path.scope, path, state)
298
319
  }
@@ -324,7 +345,7 @@ const rewriteVisitor: Visitor<PropertyManglerState> = {
324
345
  (t.isCallExpression(path.node) || t.isOptionalCallExpression(path.node)) &&
325
346
  isObjectDefinePropertyCall(path as NodePath<Call>)
326
347
  ) {
327
- const [, key] = path.node.arguments
348
+ const key = path.node.arguments[1]
328
349
  if (key && t.isExpression(key)) {
329
350
  path.node.arguments[1] = rewriteTerminalNames(key, path.scope, path, state)
330
351
  }
@@ -341,7 +362,7 @@ const rewriteVisitor: Visitor<PropertyManglerState> = {
341
362
  }
342
363
 
343
364
  function prepareKeyedProperty(path: NodePath<KeyedProperty>, state: PropertyManglerState): void {
344
- const { node } = path
365
+ const node = path.node
345
366
  if (isSemanticKey(node)) {
346
367
  const name = plainKeyName(node.key)
347
368
  if (name !== null) {
@@ -360,7 +381,7 @@ function prepareKeyedProperty(path: NodePath<KeyedProperty>, state: PropertyMang
360
381
  }
361
382
 
362
383
  function prepareMember(path: NodePath<Member>, state: PropertyManglerState): void {
363
- const { node } = path
384
+ const node = path.node
364
385
  if (state.keepQuoted && node.computed && t.isExpression(node.property)) {
365
386
  protectTerminalNames(node.property, path.scope, path, state)
366
387
  }
@@ -370,7 +391,7 @@ function prepareMember(path: NodePath<Member>, state: PropertyManglerState): voi
370
391
  }
371
392
 
372
393
  function protectQuotedKey(path: NodePath<KeyedProperty>, state: PropertyManglerState): void {
373
- const { node } = path
394
+ const node = path.node
374
395
  if (node.computed) {
375
396
  if (t.isExpression(node.key)) {
376
397
  protectTerminalNames(node.key, path.scope, path, state)
@@ -398,7 +419,7 @@ function protectName(name: string, state: PropertyManglerState): void {
398
419
  }
399
420
 
400
421
  function addAnnotatedKey(path: NodePath<KeyedProperty>, state: PropertyManglerState): void {
401
- const { node } = path
422
+ const node = path.node
402
423
  if (node.computed) {
403
424
  if (t.isExpression(node.key)) {
404
425
  forEachTerminalName(node.key, path.scope, path, (name) => state.annotated.add(name))
@@ -412,7 +433,7 @@ function addAnnotatedKey(path: NodePath<KeyedProperty>, state: PropertyManglerSt
412
433
  }
413
434
 
414
435
  function addAnnotatedMember(path: NodePath<Member>, state: PropertyManglerState): void {
415
- const { node } = path
436
+ const node = path.node
416
437
  if (node.computed) {
417
438
  if (t.isExpression(node.property)) {
418
439
  forEachTerminalName(node.property, path.scope, path, (name) => state.annotated.add(name))
@@ -423,7 +444,7 @@ function addAnnotatedMember(path: NodePath<Member>, state: PropertyManglerState)
423
444
  }
424
445
 
425
446
  function collectKeyedProperty(path: NodePath<KeyedProperty>, state: PropertyManglerState): void {
426
- const { node } = path
447
+ const node = path.node
427
448
  if (node.computed) {
428
449
  if (!state.keepQuoted && t.isExpression(node.key)) {
429
450
  collectTerminalNames(node.key, path.scope, path, state)
@@ -440,7 +461,7 @@ function collectKeyedProperty(path: NodePath<KeyedProperty>, state: PropertyMang
440
461
  }
441
462
 
442
463
  function collectMember(path: NodePath<Member>, state: PropertyManglerState): void {
443
- const { node } = path
464
+ const node = path.node
444
465
  if (node.computed) {
445
466
  if (!state.keepQuoted && t.isExpression(node.property)) {
446
467
  collectTerminalNames(node.property, path.scope, path, state)
@@ -468,7 +489,7 @@ function collectTerminalNames(
468
489
  }
469
490
 
470
491
  function rewriteKeyedProperty(path: NodePath<KeyedProperty>, state: PropertyManglerState): void {
471
- const { node } = path
492
+ const node = path.node
472
493
  if (node.computed) {
473
494
  if (!state.keepQuoted && t.isExpression(node.key)) {
474
495
  node.key = rewriteTerminalNames(node.key, path.scope, path, state)
@@ -495,7 +516,7 @@ function rewriteKeyedProperty(path: NodePath<KeyedProperty>, state: PropertyMang
495
516
  }
496
517
 
497
518
  function rewriteMember(path: NodePath<Member>, state: PropertyManglerState): void {
498
- const { node } = path
519
+ const node = path.node
499
520
  if (node.computed) {
500
521
  if (!state.keepQuoted && t.isExpression(node.property)) {
501
522
  node.property = rewriteTerminalNames(node.property, path.scope, path, state)
@@ -650,7 +671,7 @@ function memberHasMangleAnnotation(path: NodePath<Member>): boolean {
650
671
  }
651
672
 
652
673
  function isTransparentAnnotationParent(path: NodePath, child: t.Node): boolean {
653
- const { node } = path
674
+ const node = path.node
654
675
  return (
655
676
  (t.isAssignmentExpression(node) && node.left === child) ||
656
677
  (t.isCallExpression(node) && node.callee === child) ||
@@ -671,8 +692,8 @@ function hasAnnotation(node: t.Node, annotation: string): boolean {
671
692
  }
672
693
 
673
694
  function isObjectDefinePropertyCall(path: NodePath<Call>): boolean {
674
- const { node } = path
675
- const { callee } = node
695
+ const node = path.node
696
+ const callee = node.callee
676
697
  if (
677
698
  (!t.isMemberExpression(callee) && !t.isOptionalMemberExpression(callee)) ||
678
699
  !t.isIdentifier(callee.object, { name: 'Object' })
@@ -742,78 +763,3 @@ function compileRegex(regex: ManglePropertiesOptions['regex']): RegExp | null {
742
763
  }
743
764
  return new RegExp(regex.source, regex.flags)
744
765
  }
745
-
746
- const BUILTIN_OBJECTS: readonly object[] = [
747
- Object,
748
- Array,
749
- Function,
750
- Number,
751
- String,
752
- Boolean,
753
- BigInt,
754
- Symbol,
755
- Error,
756
- AggregateError,
757
- EvalError,
758
- RangeError,
759
- ReferenceError,
760
- SyntaxError,
761
- TypeError,
762
- URIError,
763
- Math,
764
- Date,
765
- RegExp,
766
- JSON,
767
- ArrayBuffer,
768
- SharedArrayBuffer,
769
- DataView,
770
- Atomics,
771
- Float32Array,
772
- Float64Array,
773
- Int8Array,
774
- Int16Array,
775
- Int32Array,
776
- BigInt64Array,
777
- Uint8Array,
778
- Uint8ClampedArray,
779
- Uint16Array,
780
- Uint32Array,
781
- BigUint64Array,
782
- Map,
783
- Set,
784
- WeakMap,
785
- WeakSet,
786
- WeakRef,
787
- FinalizationRegistry,
788
- Promise,
789
- Proxy,
790
- Reflect,
791
- Intl,
792
- WebAssembly,
793
- ]
794
-
795
- let cachedBuiltinProperties: ReadonlySet<string> | undefined
796
-
797
- function builtinProperties(): ReadonlySet<string> {
798
- cachedBuiltinProperties ??= collectBuiltinProperties()
799
- return cachedBuiltinProperties
800
- }
801
-
802
- function collectBuiltinProperties(): ReadonlySet<string> {
803
- const names = new Set(DOM_PROPERTIES)
804
- for (const name of ['null', 'true', 'false', 'NaN', 'Infinity', '-Infinity', 'undefined']) {
805
- names.add(name)
806
- }
807
- for (const object of BUILTIN_OBJECTS) {
808
- for (const name of Object.getOwnPropertyNames(object)) {
809
- names.add(name)
810
- }
811
- const prototype = 'prototype' in object ? object.prototype : null
812
- if (prototype && (typeof prototype === 'object' || typeof prototype === 'function')) {
813
- for (const name of Object.getOwnPropertyNames(prototype)) {
814
- names.add(name)
815
- }
816
- }
817
- }
818
- return names
819
- }
@@ -2,10 +2,10 @@ import type { NodePath, Visitor } from '@babel/traverse'
2
2
  import * as t from '@babel/types'
3
3
  import type { File } from '@babel/types'
4
4
 
5
- import { isInsideWith } from 'src/utils/ast'
6
- import { traverseForChanges } from 'src/utils/change-tracking'
7
- import type { ChangeState } from 'src/utils/change-tracking'
8
- import { lowerLogicalWriteStatement } from 'src/utils/logical-lowering'
5
+ import { isInsideWith } from '../utils/ast'
6
+ import { traverseForChanges } from '../utils/change-tracking'
7
+ import type { ChangeState } from '../utils/change-tracking'
8
+ import { lowerLogicalWriteStatement } from '../utils/logical-lowering'
9
9
 
10
10
  /**
11
11
  * Rewrites `a ?? b` as a guarded assignment or `a != null ? a : b`. A
@@ -35,7 +35,7 @@ const visitor: Visitor<ChangeState> = {
35
35
  }
36
36
 
37
37
  function lowerNullishCoalescing(path: NodePath<t.LogicalExpression>): boolean {
38
- const { node } = path
38
+ const node = path.node
39
39
  if (node.operator !== '??') {
40
40
  return false
41
41
  }
@@ -48,7 +48,7 @@ function lowerNullishCoalescing(path: NodePath<t.LogicalExpression>): boolean {
48
48
  return true
49
49
  }
50
50
 
51
- const { scope } = path
51
+ const scope = path.scope
52
52
  let test: t.Expression
53
53
  let consequent: t.Expression
54
54
 
@@ -2,8 +2,8 @@ import type { NodePath, Visitor } from '@babel/traverse'
2
2
  import * as t from '@babel/types'
3
3
  import type { File } from '@babel/types'
4
4
 
5
- import { traverseForChanges } from 'src/utils/change-tracking'
6
- import type { ChangeState } from 'src/utils/change-tracking'
5
+ import { traverseForChanges } from '../utils/change-tracking'
6
+ import type { ChangeState } from '../utils/change-tracking'
7
7
 
8
8
  /**
9
9
  * Rewrites numeric literals as strings coerced with unary plus. Under `+`, `-`,
@@ -34,7 +34,7 @@ const visitor: Visitor<ChangeState> = {
34
34
  return
35
35
  }
36
36
  const str = t.stringLiteral(String(path.node.value))
37
- const { parent } = path
37
+ const parent = path.parent
38
38
  if (
39
39
  t.isUnaryExpression(parent) &&
40
40
  parent.argument === path.node &&
@@ -50,7 +50,7 @@ const visitor: Visitor<ChangeState> = {
50
50
  }
51
51
 
52
52
  function isNonComputedKey(path: NodePath<t.NumericLiteral>): boolean {
53
- const { parentPath } = path
53
+ const parentPath = path.parentPath
54
54
  if (!parentPath) {
55
55
  return false
56
56
  }
@@ -2,9 +2,9 @@ import type { NodePath, Visitor } from '@babel/traverse'
2
2
  import * as t from '@babel/types'
3
3
  import type { File } from '@babel/types'
4
4
 
5
- import { isProtoKey } from 'src/utils/ast'
6
- import { traverseForChanges } from 'src/utils/change-tracking'
7
- import type { ChangeState } from 'src/utils/change-tracking'
5
+ import { isProtoKey } from '../utils/ast'
6
+ import { traverseForChanges } from '../utils/change-tracking'
7
+ import type { ChangeState } from '../utils/change-tracking'
8
8
 
9
9
  /**
10
10
  * Rewrites generator and async object methods as function-valued properties so
@@ -43,7 +43,7 @@ export function objectMethodToProperty(ast: File): boolean {
43
43
 
44
44
  const visitor: Visitor<ChangeState> = {
45
45
  ObjectMethod(path, state) {
46
- const { node } = path
46
+ const node = path.node
47
47
  if (node.kind !== 'method' || (!node.generator && !node.async)) {
48
48
  return
49
49
  }
@@ -2,9 +2,9 @@ import type { NodePath, Visitor } from '@babel/traverse'
2
2
  import * as t from '@babel/types'
3
3
  import type { File } from '@babel/types'
4
4
 
5
- import { isInsideWith } from 'src/utils/ast'
6
- import { traverseForChanges } from 'src/utils/change-tracking'
7
- import type { ChangeState } from 'src/utils/change-tracking'
5
+ import { isInsideWith } from '../utils/ast'
6
+ import { traverseForChanges } from '../utils/change-tracking'
7
+ import type { ChangeState } from '../utils/change-tracking'
8
8
 
9
9
  /**
10
10
  * Rewrites optional chains as nested ternaries. Side-effectful receivers are
@@ -129,7 +129,7 @@ function transformChain(path: OptionalPath): boolean {
129
129
 
130
130
  let cur: NodePath = path
131
131
  while (cur.isOptionalMemberExpression() || cur.isOptionalCallExpression()) {
132
- const { node } = cur
132
+ const node = cur.node
133
133
  if (node.optional) {
134
134
  optionals.push(node as unknown as t.MemberExpression | t.CallExpression)
135
135
  }
@@ -193,7 +193,7 @@ function transformChain(path: OptionalPath): boolean {
193
193
  // A cached member call needs its original receiver as `this`.
194
194
  if (isCall && t.isMemberExpression(chain)) {
195
195
  const callNode = node as t.CallExpression
196
- const { object } = chain
196
+ const object = chain.object
197
197
  if (!t.isSuper(object)) {
198
198
  let context: t.Expression
199
199
  const memoized = path.scope.maybeGenerateMemoised(object)
@@ -2,11 +2,11 @@ import type { Binding, NodePath, Visitor } from '@babel/traverse'
2
2
  import * as t from '@babel/types'
3
3
  import type { File } from '@babel/types'
4
4
 
5
- import { enclosingScopeHasDirectEval, hasDuplicateParamNames } from 'src/utils/ast'
6
- import { traverseForChanges } from 'src/utils/change-tracking'
7
- import type { ChangeState } from 'src/utils/change-tracking'
8
- import { isLiteralShaped } from 'src/utils/literal'
9
- import { hasAnnexBFunctionAlias } from 'src/utils/paths'
5
+ import { enclosingScopeHasDirectEval, hasDuplicateParamNames } from '../utils/ast'
6
+ import { traverseForChanges } from '../utils/change-tracking'
7
+ import type { ChangeState } from '../utils/change-tracking'
8
+ import { isLiteralShaped } from '../utils/literal'
9
+ import { hasAnnexBFunctionAlias } from '../utils/paths'
10
10
 
11
11
  /**
12
12
  * Moves leading literal-valued `var` declarations into trailing default
@@ -54,7 +54,7 @@ function packLeadingIntoParams(path: NodePath<t.Function>): boolean {
54
54
  if (hasAnnexBFunctionAlias(path)) {
55
55
  return false
56
56
  }
57
- const { params } = path.node
57
+ const params = path.node.params
58
58
  if (params.some((param) => t.isRestElement(param))) {
59
59
  return false
60
60
  }
@@ -63,7 +63,7 @@ function packLeadingIntoParams(path: NodePath<t.Function>): boolean {
63
63
  return false
64
64
  }
65
65
 
66
- const { body } = path.node
66
+ const body = path.node.body
67
67
  if (!t.isBlockStatement(body)) {
68
68
  return false
69
69
  }
@@ -4,11 +4,11 @@ import type { NodePath, Visitor } from '@babel/traverse'
4
4
  import * as t from '@babel/types'
5
5
  import type { File } from '@babel/types'
6
6
 
7
- import type { TransformContext } from 'src/options'
8
- import { isInsideWith } from 'src/utils/ast'
9
- import { isCalleeOrTagOf, isInStrictContext, referencesOrWritesVariable } from 'src/utils/paths'
10
- import { mulberry32 } from 'src/utils/random'
11
- import { StringGenerator } from 'src/utils/string-generator'
7
+ import type { TransformContext } from '../options'
8
+ import { isInsideWith } from '../utils/ast'
9
+ import { isCalleeOrTagOf, isInStrictContext, referencesOrWritesVariable } from '../utils/paths'
10
+ import { mulberry32 } from '../utils/random'
11
+ import { StringGenerator } from '../utils/string-generator'
12
12
 
13
13
  /**
14
14
  * Serializes the whole program to a string and rebuilds it at runtime through
@@ -110,7 +110,7 @@ function packProgram(programPath: NodePath<t.Program>, ctx: TransformContext): b
110
110
  t.memberExpression(t.identifier(objectName), t.stringLiteral(property), true)
111
111
 
112
112
  const isRoutable = (path: NodePath<t.Identifier>): boolean => {
113
- const { name } = path.node
113
+ const name = path.node.name
114
114
  // The wrapper parameter stays as written. `arguments` and `eval` are never
115
115
  // routed: `arguments` binds to its own function's object, and leaving `eval`
116
116
  // bare keeps a direct eval reading the body scope rather than the global one.
@@ -147,7 +147,7 @@ function packProgram(programPath: NodePath<t.Program>, ctx: TransformContext): b
147
147
  if (isBareDeleteArgument(path) || !isRoutable(path)) {
148
148
  return
149
149
  }
150
- const { name } = path.node
150
+ const name = path.node.name
151
151
  if (isWriteReference(path)) {
152
152
  settable.add(name)
153
153
  }
@@ -163,7 +163,7 @@ function packProgram(programPath: NodePath<t.Program>, ctx: TransformContext): b
163
163
 
164
164
  // The script completion value is its trailing expression; returning it keeps
165
165
  // `eval` of the packed output producing the same value.
166
- const { body } = programNode
166
+ const body = programNode.body
167
167
  const lastStatement = body.at(-1)
168
168
  if (lastStatement && t.isExpressionStatement(lastStatement)) {
169
169
  body[body.length - 1] = t.returnStatement(lastStatement.expression)
@@ -252,7 +252,7 @@ function isWriteReference(path: NodePath<t.Identifier>): boolean {
252
252
  if (!parent) {
253
253
  return false
254
254
  }
255
- const { node } = path
255
+ const node = path.node
256
256
  if (parent.isAssignmentExpression() && parent.node.left === node) {
257
257
  return true
258
258
  }
@@ -295,9 +295,8 @@ interface AccessorObjectSpec {
295
295
  }
296
296
 
297
297
  function buildAccessorObject(spec: AccessorObjectSpec): t.ObjectExpression {
298
- const { readProperties, setterParam, settable, strict, typeofProperties } = spec
299
298
  const properties: t.ObjectMethod[] = []
300
- for (const [name, property] of readProperties) {
299
+ for (const [name, property] of spec.readProperties) {
301
300
  properties.push(
302
301
  t.objectMethod(
303
302
  'get',
@@ -306,23 +305,28 @@ function buildAccessorObject(spec: AccessorObjectSpec): t.ObjectExpression {
306
305
  t.blockStatement([t.returnStatement(t.identifier(name))]),
307
306
  ),
308
307
  )
309
- if (settable.has(name)) {
308
+ if (spec.settable.has(name)) {
310
309
  const setterBody = t.blockStatement([
311
310
  t.expressionStatement(
312
- t.assignmentExpression('=', t.identifier(name), t.identifier(setterParam)),
311
+ t.assignmentExpression('=', t.identifier(name), t.identifier(spec.setterParam)),
313
312
  ),
314
313
  ])
315
314
  // A strict script becomes a sloppy output script, so the setter stays
316
315
  // strict to keep an undeclared-global write throwing.
317
- if (strict) {
316
+ if (spec.strict) {
318
317
  setterBody.directives.push(t.directive(t.directiveLiteral('use strict')))
319
318
  }
320
319
  properties.push(
321
- t.objectMethod('set', t.stringLiteral(property), [t.identifier(setterParam)], setterBody),
320
+ t.objectMethod(
321
+ 'set',
322
+ t.stringLiteral(property),
323
+ [t.identifier(spec.setterParam)],
324
+ setterBody,
325
+ ),
322
326
  )
323
327
  }
324
328
  }
325
- for (const [name, property] of typeofProperties) {
329
+ for (const [name, property] of spec.typeofProperties) {
326
330
  properties.push(
327
331
  t.objectMethod(
328
332
  'get',
@@ -2,8 +2,8 @@ import type { NodePath, Visitor } from '@babel/traverse'
2
2
  import * as t from '@babel/types'
3
3
  import type { File } from '@babel/types'
4
4
 
5
- import { traverseForChanges } from 'src/utils/change-tracking'
6
- import type { ChangeState } from 'src/utils/change-tracking'
5
+ import { traverseForChanges } from '../utils/change-tracking'
6
+ import type { ChangeState } from '../utils/change-tracking'
7
7
 
8
8
  /**
9
9
  * Removes a function expression's name when the body does not use its binding
@@ -25,7 +25,7 @@ export function removeAnonymousFunctionNames(ast: File): boolean {
25
25
 
26
26
  const visitor: Visitor<ChangeState> = {
27
27
  FunctionExpression(path, state) {
28
- const { id } = path.node
28
+ const id = path.node.id
29
29
  if (!id) {
30
30
  return
31
31
  }
@@ -48,8 +48,8 @@ const visitor: Visitor<ChangeState> = {
48
48
 
49
49
  // No inferred name means `.name` would become empty.
50
50
  function inferredName(path: NodePath<t.FunctionExpression>): string | null {
51
- const { node } = path
52
- const { parentPath } = path
51
+ const node = path.node
52
+ const parentPath = path.parentPath
53
53
  if (!parentPath) {
54
54
  return null
55
55
  }
@@ -2,8 +2,8 @@ import type { NodePath, Visitor } from '@babel/traverse'
2
2
  import * as t from '@babel/types'
3
3
  import type { File } from '@babel/types'
4
4
 
5
- import { traverseForChanges } from 'src/utils/change-tracking'
6
- import type { ChangeState } from 'src/utils/change-tracking'
5
+ import { traverseForChanges } from '../utils/change-tracking'
6
+ import type { ChangeState } from '../utils/change-tracking'
7
7
 
8
8
  /**
9
9
  * Removes statements after unconditional control flow in the same statement list.
@@ -72,7 +72,7 @@ function isCompletion(node: t.Node): boolean {
72
72
  // Hoisted bindings and referenced lexical TDZ remain observable from reachable
73
73
  // code. An unreferenced lexical declaration is inert.
74
74
  function isSafeToRemoveAfterCompletion(path: NodePath<t.Statement>): boolean {
75
- const { node } = path
75
+ const node = path.node
76
76
  if (t.isFunctionDeclaration(node) || (t.isVariableDeclaration(node) && node.kind === 'var')) {
77
77
  return false
78
78
  }
@@ -3,10 +3,10 @@ import type { NodePath, Scope, Visitor } from '@babel/traverse'
3
3
  import * as t from '@babel/types'
4
4
  import type { File } from '@babel/types'
5
5
 
6
- import { isSideEffectFree } from 'src/analysis/purity'
7
- import { isDirectEvalCall } from 'src/utils/ast'
8
- import type { ChangeState } from 'src/utils/change-tracking'
9
- import { hasAnnexBFunctionAlias } from 'src/utils/paths'
6
+ import { isSideEffectFree } from '../analysis/purity'
7
+ import { isDirectEvalCall } from '../utils/ast'
8
+ import type { ChangeState } from '../utils/change-tracking'
9
+ import { hasAnnexBFunctionAlias } from '../utils/paths'
10
10
 
11
11
  /**
12
12
  * Removes unused declarations and expression statements that have no effects.
@@ -150,12 +150,12 @@ function tryRemoveDeclarator(
150
150
  return false
151
151
  }
152
152
 
153
- const { id } = path.node
153
+ const id = path.node.id
154
154
  if (!t.isIdentifier(id)) {
155
155
  return false
156
156
  }
157
157
 
158
- const { init } = path.node
158
+ const init = path.node.init
159
159
  if (init && !isSideEffectFree(init, path.scope, path.get('init') as NodePath)) {
160
160
  return false
161
161
  }
@@ -196,7 +196,7 @@ function tryRemoveFunctionDecl(
196
196
  if (hasAnnexBFunctionAlias(path)) {
197
197
  return false
198
198
  }
199
- const { id } = path.node
199
+ const id = path.node.id
200
200
  if (!id) {
201
201
  return false
202
202
  }
@@ -228,7 +228,7 @@ function tryRemoveClassDecl(
228
228
  if (isExported(path)) {
229
229
  return false
230
230
  }
231
- const { id } = path.node
231
+ const id = path.node.id
232
232
  if (!id) {
233
233
  return false
234
234
  }