webfuscator 1.0.1 → 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 (156) hide show
  1. package/README.md +0 -2
  2. package/dist/analysis/constant.js +3 -3
  3. package/dist/analysis/constant.js.map +1 -1
  4. package/dist/analysis/inlineability.js +2 -2
  5. package/dist/analysis/inlineability.js.map +1 -1
  6. package/dist/analysis/purity.js +1 -1
  7. package/dist/analysis/purity.js.map +1 -1
  8. package/dist/index.d.ts +2 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/obfuscator.d.ts.map +1 -1
  12. package/dist/obfuscator.js +14 -0
  13. package/dist/obfuscator.js.map +1 -1
  14. package/dist/options.d.ts +14 -2
  15. package/dist/options.d.ts.map +1 -1
  16. package/dist/preparation/expand-destructuring.js +4 -3
  17. package/dist/preparation/expand-destructuring.js.map +1 -1
  18. package/dist/preparation/expand-template-literals.js +3 -2
  19. package/dist/preparation/expand-template-literals.js.map +1 -1
  20. package/dist/preparation/split-sequence-expressions.js +1 -1
  21. package/dist/preparation/split-sequence-expressions.js.map +1 -1
  22. package/dist/preparation/split-variable-declarations.js +1 -1
  23. package/dist/preparation/split-variable-declarations.js.map +1 -1
  24. package/dist/preparation/stringify-object-keys.js +1 -1
  25. package/dist/preparation/stringify-object-keys.js.map +1 -1
  26. package/dist/preparation/wrap-single-statements.js +2 -2
  27. package/dist/preparation/wrap-single-statements.js.map +1 -1
  28. package/dist/transforms/arguments-to-parameters.js +1 -1
  29. package/dist/transforms/arguments-to-parameters.js.map +1 -1
  30. package/dist/transforms/arrow-to-function.js.map +1 -1
  31. package/dist/transforms/collapse-single-use-temps.js +7 -7
  32. package/dist/transforms/collapse-single-use-temps.js.map +1 -1
  33. package/dist/transforms/const-let-to-var.js +3 -3
  34. package/dist/transforms/const-let-to-var.js.map +1 -1
  35. package/dist/transforms/const-to-let.js.map +1 -1
  36. package/dist/transforms/do-while-to-while.js +3 -3
  37. package/dist/transforms/do-while-to-while.js.map +1 -1
  38. package/dist/transforms/drop-console.js +4 -3
  39. package/dist/transforms/drop-console.js.map +1 -1
  40. package/dist/transforms/drop-debugger.js.map +1 -1
  41. package/dist/transforms/expand-binary-assignment.js +5 -3
  42. package/dist/transforms/expand-binary-assignment.js.map +1 -1
  43. package/dist/transforms/expand-logical-assignment.js +5 -3
  44. package/dist/transforms/expand-logical-assignment.js.map +1 -1
  45. package/dist/transforms/extract-object-properties.js +7 -7
  46. package/dist/transforms/extract-object-properties.js.map +1 -1
  47. package/dist/transforms/fold-builtin-methods.js +16 -15
  48. package/dist/transforms/fold-builtin-methods.js.map +1 -1
  49. package/dist/transforms/fold-constants.js +2 -2
  50. package/dist/transforms/fold-constants.js.map +1 -1
  51. package/dist/transforms/for-to-while.js +5 -5
  52. package/dist/transforms/for-to-while.js.map +1 -1
  53. package/dist/transforms/function-declaration-to-expression.js +3 -3
  54. package/dist/transforms/function-declaration-to-expression.js.map +1 -1
  55. package/dist/transforms/inline-functions.js +7 -7
  56. package/dist/transforms/inline-functions.js.map +1 -1
  57. package/dist/transforms/logical-to-ternary.js +2 -2
  58. package/dist/transforms/logical-to-ternary.js.map +1 -1
  59. package/dist/transforms/mangle-properties.d.ts.map +1 -1
  60. package/dist/transforms/mangle-properties.js +35 -86
  61. package/dist/transforms/mangle-properties.js.map +1 -1
  62. package/dist/transforms/nullish-coalescing-to-ternary.js +2 -2
  63. package/dist/transforms/nullish-coalescing-to-ternary.js.map +1 -1
  64. package/dist/transforms/numbers-to-strings.js +2 -2
  65. package/dist/transforms/numbers-to-strings.js.map +1 -1
  66. package/dist/transforms/object-method-to-property.js +1 -1
  67. package/dist/transforms/object-method-to-property.js.map +1 -1
  68. package/dist/transforms/optional-chaining-to-ternary.js +7 -4
  69. package/dist/transforms/optional-chaining-to-ternary.js.map +1 -1
  70. package/dist/transforms/pack-declarations-into-parameters.js +2 -2
  71. package/dist/transforms/pack-declarations-into-parameters.js.map +1 -1
  72. package/dist/transforms/pack.d.ts +33 -0
  73. package/dist/transforms/pack.d.ts.map +1 -0
  74. package/dist/transforms/pack.js +265 -0
  75. package/dist/transforms/pack.js.map +1 -0
  76. package/dist/transforms/remove-anonymous-function-names.js +3 -3
  77. package/dist/transforms/remove-anonymous-function-names.js.map +1 -1
  78. package/dist/transforms/remove-unreachable-code.js +1 -1
  79. package/dist/transforms/remove-unreachable-code.js.map +1 -1
  80. package/dist/transforms/remove-unused-code.js +4 -4
  81. package/dist/transforms/remove-unused-code.js.map +1 -1
  82. package/dist/transforms/rename-identifiers.d.ts.map +1 -1
  83. package/dist/transforms/rename-identifiers.js +4 -3
  84. package/dist/transforms/rename-identifiers.js.map +1 -1
  85. package/dist/transforms/specials-to-strings.d.ts.map +1 -1
  86. package/dist/transforms/specials-to-strings.js +2 -2
  87. package/dist/transforms/specials-to-strings.js.map +1 -1
  88. package/dist/transforms/switch-to-if.js +7 -7
  89. package/dist/transforms/switch-to-if.js.map +1 -1
  90. package/dist/transforms/ternary-to-if.js +7 -4
  91. package/dist/transforms/ternary-to-if.js.map +1 -1
  92. package/dist/transforms/update-to-assignment.js +4 -2
  93. package/dist/transforms/update-to-assignment.js.map +1 -1
  94. package/dist/transforms/yodify-conditions.js +3 -3
  95. package/dist/transforms/yodify-conditions.js.map +1 -1
  96. package/dist/utils/ast.d.ts.map +1 -1
  97. package/dist/utils/ast.js +7 -2
  98. package/dist/utils/ast.js.map +1 -1
  99. package/dist/utils/evaluation-order.js.map +1 -1
  100. package/dist/utils/logical-lowering.js +2 -2
  101. package/dist/utils/logical-lowering.js.map +1 -1
  102. package/dist/utils/loop-lowering.js +1 -1
  103. package/dist/utils/loop-lowering.js.map +1 -1
  104. package/dist/utils/string-generator.js +1 -1
  105. package/dist/utils/string-generator.js.map +1 -1
  106. package/package.json +11 -10
  107. package/src/analysis/constant.ts +4 -4
  108. package/src/analysis/inlineability.ts +4 -4
  109. package/src/analysis/purity.ts +3 -3
  110. package/src/index.ts +9 -2
  111. package/src/obfuscator.ts +57 -41
  112. package/src/options.ts +16 -2
  113. package/src/preparation/expand-destructuring.ts +5 -4
  114. package/src/preparation/expand-template-literals.ts +4 -3
  115. package/src/preparation/split-sequence-expressions.ts +2 -2
  116. package/src/preparation/split-variable-declarations.ts +1 -1
  117. package/src/preparation/stringify-object-keys.ts +2 -2
  118. package/src/preparation/wrap-single-statements.ts +2 -2
  119. package/src/transforms/arguments-to-parameters.ts +5 -5
  120. package/src/transforms/arrow-to-function.ts +3 -3
  121. package/src/transforms/collapse-single-use-temps.ts +14 -14
  122. package/src/transforms/const-let-to-var.ts +6 -6
  123. package/src/transforms/const-to-let.ts +4 -4
  124. package/src/transforms/do-while-to-while.ts +6 -6
  125. package/src/transforms/drop-console.ts +8 -7
  126. package/src/transforms/drop-debugger.ts +2 -2
  127. package/src/transforms/expand-binary-assignment.ts +8 -6
  128. package/src/transforms/expand-logical-assignment.ts +8 -6
  129. package/src/transforms/extract-object-properties.ts +12 -12
  130. package/src/transforms/fold-builtin-methods.ts +20 -19
  131. package/src/transforms/fold-constants.ts +8 -8
  132. package/src/transforms/for-to-while.ts +8 -8
  133. package/src/transforms/function-declaration-to-expression.ts +5 -5
  134. package/src/transforms/inline-functions.ts +14 -14
  135. package/src/transforms/logical-to-ternary.ts +7 -7
  136. package/src/transforms/mangle-properties.ts +43 -97
  137. package/src/transforms/nullish-coalescing-to-ternary.ts +6 -6
  138. package/src/transforms/numbers-to-strings.ts +4 -4
  139. package/src/transforms/object-method-to-property.ts +4 -4
  140. package/src/transforms/optional-chaining-to-ternary.ts +10 -7
  141. package/src/transforms/pack-declarations-into-parameters.ts +7 -7
  142. package/src/transforms/pack.ts +340 -0
  143. package/src/transforms/remove-anonymous-function-names.ts +5 -5
  144. package/src/transforms/remove-unreachable-code.ts +3 -3
  145. package/src/transforms/remove-unused-code.ts +8 -8
  146. package/src/transforms/rename-identifiers.ts +9 -8
  147. package/src/transforms/specials-to-strings.ts +7 -7
  148. package/src/transforms/switch-to-if.ts +12 -12
  149. package/src/transforms/ternary-to-if.ts +12 -9
  150. package/src/transforms/update-to-assignment.ts +7 -5
  151. package/src/transforms/yodify-conditions.ts +6 -6
  152. package/src/utils/ast.ts +9 -2
  153. package/src/utils/evaluation-order.ts +1 -1
  154. package/src/utils/logical-lowering.ts +3 -3
  155. package/src/utils/loop-lowering.ts +1 -1
  156. package/src/utils/string-generator.ts +1 -1
@@ -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
  }
@@ -175,7 +175,10 @@ function transformChain(path: OptionalPath): boolean {
175
175
  let check: t.Expression
176
176
 
177
177
  if (path.scope.isStatic(chain)) {
178
- check = chain
178
+ // The receiver stays in the member expression, so the check needs its own
179
+ // node. One node under two parents is visited twice, and a later in-place
180
+ // rewrite such as renameIdentifiers then applies itself twice to it.
181
+ check = t.cloneNode(chain)
179
182
  } else {
180
183
  const tmp = path.scope.generateUidIdentifierBasedOnNode(chain)
181
184
  path.scope.push({ id: t.cloneNode(tmp) })
@@ -190,7 +193,7 @@ function transformChain(path: OptionalPath): boolean {
190
193
  // A cached member call needs its original receiver as `this`.
191
194
  if (isCall && t.isMemberExpression(chain)) {
192
195
  const callNode = node as t.CallExpression
193
- const { object } = chain
196
+ const object = chain.object
194
197
  if (!t.isSuper(object)) {
195
198
  let context: t.Expression
196
199
  const memoized = path.scope.maybeGenerateMemoised(object)
@@ -212,7 +215,7 @@ function transformChain(path: OptionalPath): boolean {
212
215
  alternate = t.unaryExpression('delete', alternate)
213
216
  }
214
217
 
215
- const newTernary = t.conditionalExpression(condition, shortCircuit, alternate)
218
+ const newTernary = t.conditionalExpression(condition, t.cloneNode(shortCircuit), alternate)
216
219
  const replaced: NodePath<t.ConditionalExpression> = replacementPath.replaceWith(newTernary)[0]
217
220
  replacementPath = replaced.get('alternate')
218
221
  }
@@ -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
  }