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
@@ -1,13 +1,13 @@
1
1
  import type { Binding, NodePath, Scope } from '@babel/traverse'
2
2
  import * as t from '@babel/types'
3
3
 
4
+ import { enclosingScopeHasDirectEval, isInsideWith } from '../utils/ast'
4
5
  import {
5
6
  declarationReaches,
6
7
  initializerReaches,
7
8
  readCrossesFunctionBoundary,
8
- } from 'src/analysis/document-order'
9
- import { isSideEffectFree } from 'src/analysis/purity'
10
- import { enclosingScopeHasDirectEval, isInsideWith } from 'src/utils/ast'
9
+ } from './document-order'
10
+ import { isSideEffectFree } from './purity'
11
11
 
12
12
  export type Evaluation = { known: true; value: unknown } | { known: false }
13
13
 
@@ -48,7 +48,7 @@ const EVALUATORS: Partial<Record<t.Node['type'], Evaluator>> = {
48
48
  if (template.expressions.length > 0) {
49
49
  return UNKNOWN
50
50
  }
51
- const [quasi] = template.quasis
51
+ const quasi = template.quasis[0]
52
52
  return { known: true, value: quasi?.value.cooked ?? quasi?.value.raw ?? '' }
53
53
  },
54
54
  UnaryExpression: evaluateUnary,
@@ -3,8 +3,8 @@ import type { Binding, NodePath, Visitor } from '@babel/traverse'
3
3
  import * as t from '@babel/types'
4
4
  import type { File } from '@babel/types'
5
5
 
6
- import { walkOwnFunctionScope } from 'src/utils/ast'
7
- import { hasAnnexBFunctionAlias, referencesOrWritesVariable } from 'src/utils/paths'
6
+ import { walkOwnFunctionScope } from '../utils/ast'
7
+ import { hasAnnexBFunctionAlias, referencesOrWritesVariable } from '../utils/paths'
8
8
 
9
9
  export interface InlineCandidate {
10
10
  name: string
@@ -47,7 +47,7 @@ export function analyzeInlineability(ast: File): Map<string, InlineCandidate> {
47
47
  if (!t.isIdentifier(path.node.id)) {
48
48
  return
49
49
  }
50
- const { init } = path.node
50
+ const init = path.node.init
51
51
  if (!t.isFunctionExpression(init)) {
52
52
  return
53
53
  }
@@ -267,7 +267,7 @@ const analyzeBodyVisitor: Visitor<AnalyzeBodyState> = {
267
267
  path.stop()
268
268
  },
269
269
  Identifier(path, state) {
270
- const { name } = path.node
270
+ const name = path.node.name
271
271
  if (
272
272
  state.innerFnDepth === 0 &&
273
273
  (name === 'arguments' || name === 'eval' || name === state.candidateName)
@@ -1,13 +1,13 @@
1
1
  import type { Binding, NodePath, Scope } from '@babel/traverse'
2
2
  import * as t from '@babel/types'
3
3
 
4
+ import { isInsideWith } from '../utils/ast'
5
+ import { isPrimitiveLiteral } from '../utils/literal'
4
6
  import {
5
7
  declarationReaches,
6
8
  initializerReaches,
7
9
  readCrossesFunctionBoundary,
8
- } from 'src/analysis/document-order'
9
- import { isInsideWith } from 'src/utils/ast'
10
- import { isPrimitiveLiteral } from 'src/utils/literal'
10
+ } from './document-order'
11
11
 
12
12
  // Purity also requires deterministic repetition and no throw. Identifier reads
13
13
  // need scope and reference paths to prove resolution, initialization, and the
package/src/index.ts CHANGED
@@ -1,2 +1,9 @@
1
- export { obfuscate } from 'src/obfuscator'
2
- export type { ManglePropertiesOptions, ObfuscatorOptions, PropertyNameGenerator } from 'src/options'
1
+ export { obfuscate } from './obfuscator'
2
+ export type {
3
+ ManglePropertiesOptions,
4
+ ObfuscatorOptions,
5
+ PackOptions,
6
+ PropertyNameGenerator,
7
+ TransformName,
8
+ } from './options'
9
+ export type { StringGeneratorMode, StringGeneratorModeOption } from './utils/string-generator'
package/src/obfuscator.ts CHANGED
@@ -3,47 +3,48 @@ import { parse } from '@babel/parser'
3
3
  import type { ParserOptions } from '@babel/parser'
4
4
  import type { File } from '@babel/types'
5
5
 
6
- import type { ObfuscatorOptions, TransformContext, TransformName } from 'src/options'
7
- import { dotToBracket } from 'src/preparation/dot-to-bracket'
8
- import { expandDestructuring } from 'src/preparation/expand-destructuring'
9
- import { expandTemplateLiterals } from 'src/preparation/expand-template-literals'
10
- import { splitSequenceExpressions } from 'src/preparation/split-sequence-expressions'
11
- import { splitVariableDeclarations } from 'src/preparation/split-variable-declarations'
12
- import { stringifyObjectKeys } from 'src/preparation/stringify-object-keys'
13
- import { wrapSingleStatements } from 'src/preparation/wrap-single-statements'
14
- import { argumentsToParameters } from 'src/transforms/arguments-to-parameters'
15
- import { arrowToFunction } from 'src/transforms/arrow-to-function'
16
- import { collapseSingleUseTemps } from 'src/transforms/collapse-single-use-temps'
17
- import { constLetToVar } from 'src/transforms/const-let-to-var'
18
- import { constToLet } from 'src/transforms/const-to-let'
19
- import { doWhileToWhile } from 'src/transforms/do-while-to-while'
20
- import { dropConsole } from 'src/transforms/drop-console'
21
- import { dropDebugger } from 'src/transforms/drop-debugger'
22
- import { expandBinaryAssignment } from 'src/transforms/expand-binary-assignment'
23
- import { expandLogicalAssignment } from 'src/transforms/expand-logical-assignment'
24
- import { extractObjectProperties } from 'src/transforms/extract-object-properties'
25
- import { foldBuiltinMethods } from 'src/transforms/fold-builtin-methods'
26
- import { foldConstants } from 'src/transforms/fold-constants'
27
- import { forToWhile } from 'src/transforms/for-to-while'
28
- import { functionDeclarationToExpression } from 'src/transforms/function-declaration-to-expression'
29
- import { inlineFunctions } from 'src/transforms/inline-functions'
30
- import { logicalToTernary } from 'src/transforms/logical-to-ternary'
31
- import { mangleProperties } from 'src/transforms/mangle-properties'
32
- import { nullishCoalescingToTernary } from 'src/transforms/nullish-coalescing-to-ternary'
33
- import { numbersToStrings } from 'src/transforms/numbers-to-strings'
34
- import { objectMethodToProperty } from 'src/transforms/object-method-to-property'
35
- import { optionalChainingToTernary } from 'src/transforms/optional-chaining-to-ternary'
36
- import { packDeclarationsIntoParameters } from 'src/transforms/pack-declarations-into-parameters'
37
- import { removeAnonymousFunctionNames } from 'src/transforms/remove-anonymous-function-names'
38
- import { removeUnreachableCode } from 'src/transforms/remove-unreachable-code'
39
- import { removeUnusedCode } from 'src/transforms/remove-unused-code'
40
- import { renameIdentifiers } from 'src/transforms/rename-identifiers'
41
- import { specialsToStrings } from 'src/transforms/specials-to-strings'
42
- import { switchToIf } from 'src/transforms/switch-to-if'
43
- import { ternaryToIf } from 'src/transforms/ternary-to-if'
44
- import { updateToAssignment } from 'src/transforms/update-to-assignment'
45
- import { yodifyConditions } from 'src/transforms/yodify-conditions'
46
- import type { StringGeneratorModeOption } from 'src/utils/string-generator'
6
+ import type { ObfuscatorOptions, TransformContext, TransformName } from './options'
7
+ import { dotToBracket } from './preparation/dot-to-bracket'
8
+ import { expandDestructuring } from './preparation/expand-destructuring'
9
+ import { expandTemplateLiterals } from './preparation/expand-template-literals'
10
+ import { splitSequenceExpressions } from './preparation/split-sequence-expressions'
11
+ import { splitVariableDeclarations } from './preparation/split-variable-declarations'
12
+ import { stringifyObjectKeys } from './preparation/stringify-object-keys'
13
+ import { wrapSingleStatements } from './preparation/wrap-single-statements'
14
+ import { argumentsToParameters } from './transforms/arguments-to-parameters'
15
+ import { arrowToFunction } from './transforms/arrow-to-function'
16
+ import { collapseSingleUseTemps } from './transforms/collapse-single-use-temps'
17
+ import { constLetToVar } from './transforms/const-let-to-var'
18
+ import { constToLet } from './transforms/const-to-let'
19
+ import { doWhileToWhile } from './transforms/do-while-to-while'
20
+ import { dropConsole } from './transforms/drop-console'
21
+ import { dropDebugger } from './transforms/drop-debugger'
22
+ import { expandBinaryAssignment } from './transforms/expand-binary-assignment'
23
+ import { expandLogicalAssignment } from './transforms/expand-logical-assignment'
24
+ import { extractObjectProperties } from './transforms/extract-object-properties'
25
+ import { foldBuiltinMethods } from './transforms/fold-builtin-methods'
26
+ import { foldConstants } from './transforms/fold-constants'
27
+ import { forToWhile } from './transforms/for-to-while'
28
+ import { functionDeclarationToExpression } from './transforms/function-declaration-to-expression'
29
+ import { inlineFunctions } from './transforms/inline-functions'
30
+ import { logicalToTernary } from './transforms/logical-to-ternary'
31
+ import { mangleProperties } from './transforms/mangle-properties'
32
+ import { nullishCoalescingToTernary } from './transforms/nullish-coalescing-to-ternary'
33
+ import { numbersToStrings } from './transforms/numbers-to-strings'
34
+ import { objectMethodToProperty } from './transforms/object-method-to-property'
35
+ import { optionalChainingToTernary } from './transforms/optional-chaining-to-ternary'
36
+ import { pack } from './transforms/pack'
37
+ import { packDeclarationsIntoParameters } from './transforms/pack-declarations-into-parameters'
38
+ import { removeAnonymousFunctionNames } from './transforms/remove-anonymous-function-names'
39
+ import { removeUnreachableCode } from './transforms/remove-unreachable-code'
40
+ import { removeUnusedCode } from './transforms/remove-unused-code'
41
+ import { renameIdentifiers } from './transforms/rename-identifiers'
42
+ import { specialsToStrings } from './transforms/specials-to-strings'
43
+ import { switchToIf } from './transforms/switch-to-if'
44
+ import { ternaryToIf } from './transforms/ternary-to-if'
45
+ import { updateToAssignment } from './transforms/update-to-assignment'
46
+ import { yodifyConditions } from './transforms/yodify-conditions'
47
+ import type { StringGeneratorModeOption } from './utils/string-generator'
47
48
 
48
49
  const parserOptions: ParserOptions = { sourceType: 'unambiguous' }
49
50
 
@@ -135,6 +136,11 @@ const POST_PROCESS: readonly ConfigurablePhase[] = [
135
136
  // Renaming runs last because later transforms depend on recognizable bindings.
136
137
  const RENAME: readonly ConfigurablePhase[] = [['renameIdentifiers', renameIdentifiers]]
137
138
 
139
+ // Packing serializes the finished program to a string and rebuilds it through
140
+ // the Function constructor. It must see final names and shapes, so it runs after
141
+ // every other rewrite, including renaming.
142
+ const PACK: readonly ConfigurablePhase[] = [['pack', pack]]
143
+
138
144
  /** Parses, transforms, and prints JavaScript without mutating external state. */
139
145
  export function obfuscate(code: string, options: ObfuscatorOptions = {}): string {
140
146
  const log = options.verbose ? makeLogger() : null
@@ -185,6 +191,13 @@ export function obfuscate(code: string, options: ObfuscatorOptions = {}): string
185
191
  run(log, name, () => fn(ast, ctxFor(name, options, baseCtx)))
186
192
  }
187
193
 
194
+ for (const [name, fn] of PACK) {
195
+ if (!isEnabled(name, options)) {
196
+ continue
197
+ }
198
+ run(log, name, () => fn(ast, ctxFor(name, options, baseCtx)))
199
+ }
200
+
188
201
  return run(
189
202
  log,
190
203
  'generate',
@@ -211,6 +224,9 @@ function ctxFor(
211
224
  if (name === 'mangleProperties' && entry && typeof entry === 'object') {
212
225
  return { ...context, mangleProperties: entry }
213
226
  }
227
+ if (name === 'pack' && entry && typeof entry === 'object') {
228
+ return { ...context, pack: entry }
229
+ }
214
230
  return context
215
231
  }
216
232
 
package/src/options.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { StringGeneratorModeOption } from 'src/utils/string-generator'
1
+ import type { StringGeneratorModeOption } from './utils/string-generator'
2
2
 
3
3
  /**
4
4
  * Exported transform entry points. Preparation passes are always enabled and
@@ -37,6 +37,7 @@ export type TransformName =
37
37
  | 'numbersToStrings'
38
38
  | 'mangleProperties'
39
39
  | 'renameIdentifiers'
40
+ | 'pack'
40
41
 
41
42
  // An override enables the transform and replaces its string-generator mode.
42
43
  type TransformEntry = boolean | { stringGeneratorMode?: StringGeneratorModeOption }
@@ -76,13 +77,25 @@ export interface ManglePropertiesOptions {
76
77
  undeclared?: boolean
77
78
  }
78
79
 
80
+ /** Options for the `Function`-constructor packing transform. */
81
+ export interface PackOptions {
82
+ /**
83
+ * Skip the strict-mode directive so the packed body runs sloppy even when the
84
+ * source is strict. This deliberately changes behavior. Default `false`.
85
+ */
86
+ escapeStrict?: boolean
87
+ /** Override the default string-generator mode for the names pack creates. */
88
+ stringGeneratorMode?: StringGeneratorModeOption
89
+ }
90
+
79
91
  type SimpleTransform = Exclude<
80
92
  TransformName,
81
- 'mangleProperties' | 'renameIdentifiers' | 'specialsToStrings'
93
+ 'mangleProperties' | 'pack' | 'renameIdentifiers' | 'specialsToStrings'
82
94
  >
83
95
 
84
96
  type TransformsMap = Partial<Record<SimpleTransform, boolean>> & {
85
97
  mangleProperties?: boolean | ManglePropertiesOptions
98
+ pack?: boolean | PackOptions
86
99
  renameIdentifiers?: TransformEntry
87
100
  specialsToStrings?: TransformEntry
88
101
  }
@@ -110,6 +123,7 @@ export interface ObfuscatorOptions {
110
123
  // Resolved per-call defaults handed to every transform.
111
124
  export interface TransformContext {
112
125
  mangleProperties?: ManglePropertiesOptions
126
+ pack?: PackOptions
113
127
  seed: number
114
128
  stringGeneratorMode: StringGeneratorModeOption
115
129
  }
@@ -3,7 +3,7 @@ import type { NodePath, Scope } from '@babel/traverse'
3
3
  import * as t from '@babel/types'
4
4
  import type { File } from '@babel/types'
5
5
 
6
- import { enclosingScopeHasDirectEval, isInsideWith } from 'src/utils/ast'
6
+ import { enclosingScopeHasDirectEval, isInsideWith } from '../utils/ast'
7
7
 
8
8
  type Kind = t.VariableDeclaration['kind']
9
9
 
@@ -47,12 +47,13 @@ const visitor = {
47
47
  return
48
48
  }
49
49
 
50
- const { kind } = path.node
50
+ const kind = path.node.kind
51
51
  const replacement: t.Statement[] = []
52
52
  let changed = false
53
53
 
54
54
  for (const declarator of path.node.declarations) {
55
- const { id, init } = declarator
55
+ const id = declarator.id
56
+ const init = declarator.init
56
57
 
57
58
  if (
58
59
  !init ||
@@ -135,7 +136,7 @@ function expandPattern(
135
136
  if (t.isRestElement(prop)) {
136
137
  continue
137
138
  }
138
- const { key } = prop
139
+ const key = prop.key
139
140
  const useComputed = prop.computed || !t.isIdentifier(key)
140
141
  const access = t.memberExpression(
141
142
  t.cloneNode(src),
@@ -3,7 +3,7 @@ import type { Visitor } from '@babel/traverse'
3
3
  import * as t from '@babel/types'
4
4
  import type { File } from '@babel/types'
5
5
 
6
- import { isInDirectivePrologue } from 'src/utils/ast'
6
+ import { isInDirectivePrologue } from '../utils/ast'
7
7
 
8
8
  /**
9
9
  * Rewrites safe template literals as string concatenation. Tagged templates
@@ -31,12 +31,13 @@ export function expandTemplateLiterals(ast: File): void {
31
31
 
32
32
  const visitor: Visitor = {
33
33
  TemplateLiteral(path) {
34
- const { parent } = path
34
+ const parent = path.parent
35
35
  if (t.isTaggedTemplateExpression(parent) && parent.quasi === path.node) {
36
36
  return
37
37
  }
38
38
 
39
- const { quasis, expressions } = path.node
39
+ const quasis = path.node.quasis
40
+ const expressions = path.node.expressions
40
41
 
41
42
  if (expressions.length === 0) {
42
43
  // Rewriting a leading template as a string would create a directive.
@@ -3,7 +3,7 @@ import type { NodePath } from '@babel/traverse'
3
3
  import * as t from '@babel/types'
4
4
  import type { File } from '@babel/types'
5
5
 
6
- import { isInDirectivePrologue } from 'src/utils/ast'
6
+ import { isInDirectivePrologue } from '../utils/ast'
7
7
 
8
8
  /**
9
9
  * Splits comma-sequenced expression statements into one statement each.
@@ -30,7 +30,7 @@ const visitor = {
30
30
  return
31
31
  }
32
32
  // Splitting a leading string out of a sequence could create a directive.
33
- const [first] = path.node.expression.expressions
33
+ const first = path.node.expression.expressions[0]
34
34
  if (t.isStringLiteral(first) && isInDirectivePrologue(path)) {
35
35
  return
36
36
  }
@@ -32,7 +32,7 @@ const visitor = {
32
32
  if (path.node.declarations.length <= 1) {
33
33
  return
34
34
  }
35
- const { kind } = path.node
35
+ const kind = path.node.kind
36
36
  const replacements = path.node.declarations.map((decl) => t.variableDeclaration(kind, [decl]))
37
37
  path.replaceWithMultiple(replacements)
38
38
  },
@@ -3,7 +3,7 @@ import type { NodePath } from '@babel/traverse'
3
3
  import * as t from '@babel/types'
4
4
  import type { File } from '@babel/types'
5
5
 
6
- import { isProtoKey } from 'src/utils/ast'
6
+ import { isProtoKey } from '../utils/ast'
7
7
 
8
8
  /**
9
9
  * Rewrites property keys in object literals and classes as computed strings.
@@ -57,7 +57,7 @@ function keyOrderIsSpreadSensitive(path: NodePath<t.ObjectProperty | t.ObjectMet
57
57
  if (!object || !object.isObjectExpression()) {
58
58
  return false
59
59
  }
60
- const { properties } = object.node
60
+ const properties = object.node.properties
61
61
  const hasSpread = properties.some((prop) => t.isSpreadElement(prop))
62
62
  if (!hasSpread) {
63
63
  return false
@@ -36,7 +36,7 @@ export function wrapSingleStatements(ast: File): void {
36
36
 
37
37
  const visitor = {
38
38
  IfStatement(path: { node: t.IfStatement }) {
39
- const { node } = path
39
+ const node = path.node
40
40
  if (!t.isBlockStatement(node.consequent)) {
41
41
  node.consequent = t.blockStatement([node.consequent])
42
42
  }
@@ -48,7 +48,7 @@ const visitor = {
48
48
  wrapLoopBody(path.node)
49
49
  },
50
50
  ArrowFunctionExpression(path: { node: t.ArrowFunctionExpression }) {
51
- const { node } = path
51
+ const node = path.node
52
52
  if (!t.isBlockStatement(node.body)) {
53
53
  node.body = t.blockStatement([t.returnStatement(node.body)])
54
54
  node.expression = false
@@ -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 { hasDuplicateParamNames } from 'src/utils/ast'
6
- import { traverseForChanges } from 'src/utils/change-tracking'
7
- import type { ChangeState } from 'src/utils/change-tracking'
8
- import { isInStrictContext } from 'src/utils/paths'
5
+ import { hasDuplicateParamNames } from '../utils/ast'
6
+ import { traverseForChanges } from '../utils/change-tracking'
7
+ import type { ChangeState } from '../utils/change-tracking'
8
+ import { isInStrictContext } from '../utils/paths'
9
9
 
10
10
  /**
11
11
  * Replaces `arguments[i]` reads with their mapped parameter in sloppy functions
@@ -113,7 +113,7 @@ function processFunction(path: NodePath<t.Function>): boolean {
113
113
  if (path.isArrowFunctionExpression()) {
114
114
  return false
115
115
  }
116
- const { params } = path.node
116
+ const params = path.node.params
117
117
  // Rest, defaults, and destructuring make `arguments` unmapped.
118
118
  if (!params.every((param) => t.isIdentifier(param))) {
119
119
  return false
@@ -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 { enclosingScopeHasDirectEval, isInsideWith } from 'src/utils/ast'
6
- import { traverseForChanges } from 'src/utils/change-tracking'
7
- import type { ChangeState } from 'src/utils/change-tracking'
5
+ import { enclosingScopeHasDirectEval, 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
  * Lowers arrows with Babel's capture-aware `arrowFunctionToExpression`. Arrows
@@ -3,17 +3,17 @@ import type { Binding, NodePath, Scope } from '@babel/traverse'
3
3
  import * as t from '@babel/types'
4
4
  import type { File } from '@babel/types'
5
5
 
6
- import { evaluateConstant } from 'src/analysis/constant'
6
+ import { evaluateConstant } from '../analysis/constant'
7
7
  import {
8
8
  declarationReaches,
9
9
  initializerReaches,
10
10
  readCrossesFunctionBoundary,
11
- } from 'src/analysis/document-order'
12
- import { isPure } from 'src/analysis/purity'
13
- import { isInsideWith } from 'src/utils/ast'
14
- import { reorderableToStatement } from 'src/utils/evaluation-order'
15
- import { valueToLiteral } from 'src/utils/literal'
16
- import { isCalleeOrTagOf } from 'src/utils/paths'
11
+ } from '../analysis/document-order'
12
+ import { isPure } from '../analysis/purity'
13
+ import { isInsideWith } from '../utils/ast'
14
+ import { reorderableToStatement } from '../utils/evaluation-order'
15
+ import { valueToLiteral } from '../utils/literal'
16
+ import { isCalleeOrTagOf } from '../utils/paths'
17
17
 
18
18
  /**
19
19
  * Drops single-use temporaries through substitution, direct branch writes, or
@@ -125,7 +125,7 @@ function trySubstituteSingleUse(
125
125
  binding: Binding,
126
126
  declaratorPath: NodePath<t.VariableDeclarator>,
127
127
  ): boolean {
128
- const [readPath] = binding.referencePaths
128
+ const readPath = binding.referencePaths[0]
129
129
  if (!readPath || !isPathLive(readPath)) {
130
130
  return false
131
131
  }
@@ -138,7 +138,7 @@ function trySubstituteSingleUse(
138
138
  return false
139
139
  }
140
140
 
141
- const { init } = declaratorPath.node
141
+ const init = declaratorPath.node.init
142
142
  let writeStmt: NodePath
143
143
  let writeValueOwner: NodePath
144
144
  let writeRhs: t.Expression
@@ -255,7 +255,7 @@ function tryRenameWritesToReader(
255
255
  return false
256
256
  }
257
257
 
258
- const [readPath] = binding.referencePaths
258
+ const readPath = binding.referencePaths[0]
259
259
  if (!readPath || !isPathLive(readPath)) {
260
260
  return false
261
261
  }
@@ -389,7 +389,7 @@ function tryScatterIntoTerminator(
389
389
  return false
390
390
  }
391
391
 
392
- const [readPath] = binding.referencePaths
392
+ const readPath = binding.referencePaths[0]
393
393
  if (!readPath || !isPathLive(readPath)) {
394
394
  return false
395
395
  }
@@ -648,7 +648,7 @@ function combineFall(a: boolean | null, b: boolean | null): boolean | null {
648
648
  // Apart from redirected writes, the span must run no user code or observations.
649
649
  // Redirected right sides must also be pure.
650
650
  function spanStatementIsInert(path: NodePath, tempBinding: Binding): boolean {
651
- const { node } = path
651
+ const node = path.node
652
652
  if (t.isEmptyStatement(node) || t.isBreakStatement(node) || t.isContinueStatement(node)) {
653
653
  return true
654
654
  }
@@ -715,7 +715,7 @@ function tryPropagateConstant(
715
715
  return false
716
716
  }
717
717
 
718
- const { init } = declaratorPath.node
718
+ const init = declaratorPath.node.init
719
719
  let writeRhs: t.Expression
720
720
  let writeRhsPath: NodePath
721
721
  let writeStmtToRemove: NodePath | null
@@ -886,7 +886,7 @@ function subtreeReadsBinding(stmtPath: NodePath, target: Binding): boolean {
886
886
  }
887
887
 
888
888
  function isStatementMovementSafe(path: NodePath): boolean {
889
- const { node } = path
889
+ const node = path.node
890
890
  if (t.isEmptyStatement(node)) {
891
891
  return true
892
892
  }
@@ -3,9 +3,9 @@ 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 { initializerReaches } from 'src/analysis/document-order'
7
- import { enclosingScopeHasDirectEval, isInsideWith } from 'src/utils/ast'
8
- import { hasConstantViolation } from 'src/utils/paths'
6
+ import { initializerReaches } from '../analysis/document-order'
7
+ import { enclosingScopeHasDirectEval, isInsideWith } from '../utils/ast'
8
+ import { hasConstantViolation } from '../utils/paths'
9
9
 
10
10
  /**
11
11
  * Lifts safe lexical declarations to function-scoped `var`, renaming collisions
@@ -29,7 +29,7 @@ export function constLetToVar(ast: File): boolean {
29
29
  const state = { changed: false }
30
30
  traverse(ast, {
31
31
  VariableDeclaration(path) {
32
- const { kind } = path.node
32
+ const kind = path.node.kind
33
33
  if (kind !== 'let' && kind !== 'const') {
34
34
  return
35
35
  }
@@ -64,7 +64,7 @@ export function constLetToVar(ast: File): boolean {
64
64
  },
65
65
 
66
66
  ClassDeclaration(path) {
67
- const { id } = path.node
67
+ const id = path.node.id
68
68
  if (!id) {
69
69
  return
70
70
  }
@@ -72,7 +72,7 @@ export function constLetToVar(ast: File): boolean {
72
72
  return
73
73
  }
74
74
 
75
- const { scope } = path.parentPath
75
+ const scope = path.parentPath.scope
76
76
  if (!isVarScope(scope) && scope.parent!.hasBinding(id.name, { noUids: true })) {
77
77
  path.scope.rename(id.name)
78
78
  state.changed = true
@@ -1,10 +1,10 @@
1
1
  import type { Visitor } from '@babel/traverse'
2
2
  import type { File } from '@babel/types'
3
3
 
4
- import { enclosingScopeHasDirectEval } from 'src/utils/ast'
5
- import { traverseForChanges } from 'src/utils/change-tracking'
6
- import type { ChangeState } from 'src/utils/change-tracking'
7
- import { hasConstantViolation } from 'src/utils/paths'
4
+ import { enclosingScopeHasDirectEval } from '../utils/ast'
5
+ import { traverseForChanges } from '../utils/change-tracking'
6
+ import type { ChangeState } from '../utils/change-tracking'
7
+ import { hasConstantViolation } from '../utils/paths'
8
8
 
9
9
  /**
10
10
  * Changes `const` to `let` when no write can observe the lost TypeError. Direct
@@ -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 { traverseForChanges } from 'src/utils/change-tracking'
6
- import type { ChangeState } from 'src/utils/change-tracking'
7
- import { collectLoopLabels, generateLoopLabel, redirectContinues } from 'src/utils/loop-lowering'
5
+ import { traverseForChanges } from '../utils/change-tracking'
6
+ import type { ChangeState } from '../utils/change-tracking'
7
+ import { collectLoopLabels, generateLoopLabel, redirectContinues } from '../utils/loop-lowering'
8
8
 
9
9
  /**
10
10
  * Rewrites `do` loops as `while (true)` with an exit test after the body.
@@ -41,8 +41,8 @@ const visitor: Visitor<ChangeState> = {
41
41
  }
42
42
 
43
43
  function transformDoWhile(path: NodePath<t.DoWhileStatement>): void {
44
- const { node } = path
45
- const { ourLabels } = collectLoopLabels(path)
44
+ const node = path.node
45
+ const ourLabels = collectLoopLabels(path).ourLabels
46
46
  const innerLabel = generateLoopLabel(path, 'doIteration')
47
47
 
48
48
  const blockBody: t.BlockStatement = t.isBlockStatement(node.body)
@@ -58,7 +58,7 @@ function transformDoWhile(path: NodePath<t.DoWhileStatement>): void {
58
58
  t.blockStatement([labeledBlock, exitTest]),
59
59
  )
60
60
 
61
- const [newPath] = path.replaceWith(whileStmt)
61
+ const newPath = path.replaceWith(whileStmt)[0]
62
62
  const rewriteCount = redirectContinues(newPath, innerLabel, ourLabels)
63
63
 
64
64
  // Keep the block so body bindings cannot shadow names in the exit test.
@@ -3,10 +3,10 @@ import type { NodePath, 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 { isInsideWith } from 'src/utils/ast'
8
- import { traverseForChanges } from 'src/utils/change-tracking'
9
- import type { ChangeState } from 'src/utils/change-tracking'
6
+ import { isSideEffectFree } from '../analysis/purity'
7
+ import { isInsideWith } from '../utils/ast'
8
+ import { traverseForChanges } from '../utils/change-tracking'
9
+ import type { ChangeState } from '../utils/change-tracking'
10
10
 
11
11
  /**
12
12
  * Removes `console.*(...)` expression statements when `console` is not
@@ -61,7 +61,8 @@ function globalConsoleIsReassigned(ast: File): boolean {
61
61
  }
62
62
 
63
63
  function isWriteTarget(path: NodePath<t.Identifier>): boolean {
64
- const { node, parentPath } = path
64
+ const node = path.node
65
+ const parentPath = path.parentPath
65
66
  if (!parentPath) {
66
67
  return false
67
68
  }
@@ -81,11 +82,11 @@ const visitor: Visitor<ChangeState> = {
81
82
  if (!t.isCallExpression(expr) && !t.isOptionalCallExpression(expr)) {
82
83
  return
83
84
  }
84
- const { callee } = expr
85
+ const callee = expr.callee
85
86
  if (!t.isMemberExpression(callee) && !t.isOptionalMemberExpression(callee)) {
86
87
  return
87
88
  }
88
- const { object } = callee
89
+ const object = callee.object
89
90
  if (!t.isIdentifier(object) || object.name !== 'console') {
90
91
  return
91
92
  }