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.
- package/README.md +0 -2
- package/dist/analysis/constant.js +3 -3
- package/dist/analysis/constant.js.map +1 -1
- package/dist/analysis/inlineability.js +2 -2
- package/dist/analysis/inlineability.js.map +1 -1
- package/dist/analysis/purity.js +1 -1
- package/dist/analysis/purity.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/obfuscator.d.ts.map +1 -1
- package/dist/obfuscator.js +14 -0
- package/dist/obfuscator.js.map +1 -1
- package/dist/options.d.ts +14 -2
- package/dist/options.d.ts.map +1 -1
- package/dist/preparation/expand-destructuring.js +4 -3
- package/dist/preparation/expand-destructuring.js.map +1 -1
- package/dist/preparation/expand-template-literals.js +3 -2
- package/dist/preparation/expand-template-literals.js.map +1 -1
- package/dist/preparation/split-sequence-expressions.js +1 -1
- package/dist/preparation/split-sequence-expressions.js.map +1 -1
- package/dist/preparation/split-variable-declarations.js +1 -1
- package/dist/preparation/split-variable-declarations.js.map +1 -1
- package/dist/preparation/stringify-object-keys.js +1 -1
- package/dist/preparation/stringify-object-keys.js.map +1 -1
- package/dist/preparation/wrap-single-statements.js +2 -2
- package/dist/preparation/wrap-single-statements.js.map +1 -1
- package/dist/transforms/arguments-to-parameters.js +1 -1
- package/dist/transforms/arguments-to-parameters.js.map +1 -1
- package/dist/transforms/arrow-to-function.js.map +1 -1
- package/dist/transforms/collapse-single-use-temps.js +7 -7
- package/dist/transforms/collapse-single-use-temps.js.map +1 -1
- package/dist/transforms/const-let-to-var.js +3 -3
- package/dist/transforms/const-let-to-var.js.map +1 -1
- package/dist/transforms/const-to-let.js.map +1 -1
- package/dist/transforms/do-while-to-while.js +3 -3
- package/dist/transforms/do-while-to-while.js.map +1 -1
- package/dist/transforms/drop-console.js +4 -3
- package/dist/transforms/drop-console.js.map +1 -1
- package/dist/transforms/drop-debugger.js.map +1 -1
- package/dist/transforms/expand-binary-assignment.js +5 -3
- package/dist/transforms/expand-binary-assignment.js.map +1 -1
- package/dist/transforms/expand-logical-assignment.js +5 -3
- package/dist/transforms/expand-logical-assignment.js.map +1 -1
- package/dist/transforms/extract-object-properties.js +7 -7
- package/dist/transforms/extract-object-properties.js.map +1 -1
- package/dist/transforms/fold-builtin-methods.js +16 -15
- package/dist/transforms/fold-builtin-methods.js.map +1 -1
- package/dist/transforms/fold-constants.js +2 -2
- package/dist/transforms/fold-constants.js.map +1 -1
- package/dist/transforms/for-to-while.js +5 -5
- package/dist/transforms/for-to-while.js.map +1 -1
- package/dist/transforms/function-declaration-to-expression.js +3 -3
- package/dist/transforms/function-declaration-to-expression.js.map +1 -1
- package/dist/transforms/inline-functions.js +7 -7
- package/dist/transforms/inline-functions.js.map +1 -1
- package/dist/transforms/logical-to-ternary.js +2 -2
- package/dist/transforms/logical-to-ternary.js.map +1 -1
- package/dist/transforms/mangle-properties.d.ts.map +1 -1
- package/dist/transforms/mangle-properties.js +35 -86
- package/dist/transforms/mangle-properties.js.map +1 -1
- package/dist/transforms/nullish-coalescing-to-ternary.js +2 -2
- package/dist/transforms/nullish-coalescing-to-ternary.js.map +1 -1
- package/dist/transforms/numbers-to-strings.js +2 -2
- package/dist/transforms/numbers-to-strings.js.map +1 -1
- package/dist/transforms/object-method-to-property.js +1 -1
- package/dist/transforms/object-method-to-property.js.map +1 -1
- package/dist/transforms/optional-chaining-to-ternary.js +7 -4
- package/dist/transforms/optional-chaining-to-ternary.js.map +1 -1
- package/dist/transforms/pack-declarations-into-parameters.js +2 -2
- package/dist/transforms/pack-declarations-into-parameters.js.map +1 -1
- package/dist/transforms/pack.d.ts +33 -0
- package/dist/transforms/pack.d.ts.map +1 -0
- package/dist/transforms/pack.js +265 -0
- package/dist/transforms/pack.js.map +1 -0
- package/dist/transforms/remove-anonymous-function-names.js +3 -3
- package/dist/transforms/remove-anonymous-function-names.js.map +1 -1
- package/dist/transforms/remove-unreachable-code.js +1 -1
- package/dist/transforms/remove-unreachable-code.js.map +1 -1
- package/dist/transforms/remove-unused-code.js +4 -4
- package/dist/transforms/remove-unused-code.js.map +1 -1
- package/dist/transforms/rename-identifiers.d.ts.map +1 -1
- package/dist/transforms/rename-identifiers.js +4 -3
- package/dist/transforms/rename-identifiers.js.map +1 -1
- package/dist/transforms/specials-to-strings.d.ts.map +1 -1
- package/dist/transforms/specials-to-strings.js +2 -2
- package/dist/transforms/specials-to-strings.js.map +1 -1
- package/dist/transforms/switch-to-if.js +7 -7
- package/dist/transforms/switch-to-if.js.map +1 -1
- package/dist/transforms/ternary-to-if.js +7 -4
- package/dist/transforms/ternary-to-if.js.map +1 -1
- package/dist/transforms/update-to-assignment.js +4 -2
- package/dist/transforms/update-to-assignment.js.map +1 -1
- package/dist/transforms/yodify-conditions.js +3 -3
- package/dist/transforms/yodify-conditions.js.map +1 -1
- package/dist/utils/ast.d.ts.map +1 -1
- package/dist/utils/ast.js +7 -2
- package/dist/utils/ast.js.map +1 -1
- package/dist/utils/evaluation-order.js.map +1 -1
- package/dist/utils/logical-lowering.js +2 -2
- package/dist/utils/logical-lowering.js.map +1 -1
- package/dist/utils/loop-lowering.js +1 -1
- package/dist/utils/loop-lowering.js.map +1 -1
- package/dist/utils/string-generator.js +1 -1
- package/dist/utils/string-generator.js.map +1 -1
- package/package.json +11 -10
- package/src/analysis/constant.ts +4 -4
- package/src/analysis/inlineability.ts +4 -4
- package/src/analysis/purity.ts +3 -3
- package/src/index.ts +9 -2
- package/src/obfuscator.ts +57 -41
- package/src/options.ts +16 -2
- package/src/preparation/expand-destructuring.ts +5 -4
- package/src/preparation/expand-template-literals.ts +4 -3
- package/src/preparation/split-sequence-expressions.ts +2 -2
- package/src/preparation/split-variable-declarations.ts +1 -1
- package/src/preparation/stringify-object-keys.ts +2 -2
- package/src/preparation/wrap-single-statements.ts +2 -2
- package/src/transforms/arguments-to-parameters.ts +5 -5
- package/src/transforms/arrow-to-function.ts +3 -3
- package/src/transforms/collapse-single-use-temps.ts +14 -14
- package/src/transforms/const-let-to-var.ts +6 -6
- package/src/transforms/const-to-let.ts +4 -4
- package/src/transforms/do-while-to-while.ts +6 -6
- package/src/transforms/drop-console.ts +8 -7
- package/src/transforms/drop-debugger.ts +2 -2
- package/src/transforms/expand-binary-assignment.ts +8 -6
- package/src/transforms/expand-logical-assignment.ts +8 -6
- package/src/transforms/extract-object-properties.ts +12 -12
- package/src/transforms/fold-builtin-methods.ts +20 -19
- package/src/transforms/fold-constants.ts +8 -8
- package/src/transforms/for-to-while.ts +8 -8
- package/src/transforms/function-declaration-to-expression.ts +5 -5
- package/src/transforms/inline-functions.ts +14 -14
- package/src/transforms/logical-to-ternary.ts +7 -7
- package/src/transforms/mangle-properties.ts +43 -97
- package/src/transforms/nullish-coalescing-to-ternary.ts +6 -6
- package/src/transforms/numbers-to-strings.ts +4 -4
- package/src/transforms/object-method-to-property.ts +4 -4
- package/src/transforms/optional-chaining-to-ternary.ts +10 -7
- package/src/transforms/pack-declarations-into-parameters.ts +7 -7
- package/src/transforms/pack.ts +340 -0
- package/src/transforms/remove-anonymous-function-names.ts +5 -5
- package/src/transforms/remove-unreachable-code.ts +3 -3
- package/src/transforms/remove-unused-code.ts +8 -8
- package/src/transforms/rename-identifiers.ts +9 -8
- package/src/transforms/specials-to-strings.ts +7 -7
- package/src/transforms/switch-to-if.ts +12 -12
- package/src/transforms/ternary-to-if.ts +12 -9
- package/src/transforms/update-to-assignment.ts +7 -5
- package/src/transforms/yodify-conditions.ts +6 -6
- package/src/utils/ast.ts +9 -2
- package/src/utils/evaluation-order.ts +1 -1
- package/src/utils/logical-lowering.ts +3 -3
- package/src/utils/loop-lowering.ts +1 -1
- package/src/utils/string-generator.ts +1 -1
package/src/analysis/constant.ts
CHANGED
|
@@ -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 '
|
|
9
|
-
import { isSideEffectFree } from '
|
|
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
|
|
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 '
|
|
7
|
-
import { hasAnnexBFunctionAlias, referencesOrWritesVariable } from '
|
|
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
|
|
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
|
|
270
|
+
const name = path.node.name
|
|
271
271
|
if (
|
|
272
272
|
state.innerFnDepth === 0 &&
|
|
273
273
|
(name === 'arguments' || name === 'eval' || name === state.candidateName)
|
package/src/analysis/purity.ts
CHANGED
|
@@ -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 '
|
|
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 '
|
|
2
|
-
export type {
|
|
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 '
|
|
7
|
-
import { dotToBracket } from '
|
|
8
|
-
import { expandDestructuring } from '
|
|
9
|
-
import { expandTemplateLiterals } from '
|
|
10
|
-
import { splitSequenceExpressions } from '
|
|
11
|
-
import { splitVariableDeclarations } from '
|
|
12
|
-
import { stringifyObjectKeys } from '
|
|
13
|
-
import { wrapSingleStatements } from '
|
|
14
|
-
import { argumentsToParameters } from '
|
|
15
|
-
import { arrowToFunction } from '
|
|
16
|
-
import { collapseSingleUseTemps } from '
|
|
17
|
-
import { constLetToVar } from '
|
|
18
|
-
import { constToLet } from '
|
|
19
|
-
import { doWhileToWhile } from '
|
|
20
|
-
import { dropConsole } from '
|
|
21
|
-
import { dropDebugger } from '
|
|
22
|
-
import { expandBinaryAssignment } from '
|
|
23
|
-
import { expandLogicalAssignment } from '
|
|
24
|
-
import { extractObjectProperties } from '
|
|
25
|
-
import { foldBuiltinMethods } from '
|
|
26
|
-
import { foldConstants } from '
|
|
27
|
-
import { forToWhile } from '
|
|
28
|
-
import { functionDeclarationToExpression } from '
|
|
29
|
-
import { inlineFunctions } from '
|
|
30
|
-
import { logicalToTernary } from '
|
|
31
|
-
import { mangleProperties } from '
|
|
32
|
-
import { nullishCoalescingToTernary } from '
|
|
33
|
-
import { numbersToStrings } from '
|
|
34
|
-
import { objectMethodToProperty } from '
|
|
35
|
-
import { optionalChainingToTernary } from '
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
45
|
-
import {
|
|
46
|
-
import
|
|
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 '
|
|
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 '
|
|
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
|
|
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
|
|
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
|
|
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 '
|
|
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
|
|
34
|
+
const parent = path.parent
|
|
35
35
|
if (t.isTaggedTemplateExpression(parent) && parent.quasi === path.node) {
|
|
36
36
|
return
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const
|
|
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 '
|
|
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
|
|
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
|
|
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 '
|
|
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
|
|
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
|
|
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
|
|
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 '
|
|
6
|
-
import { traverseForChanges } from '
|
|
7
|
-
import type { ChangeState } from '
|
|
8
|
-
import { isInStrictContext } from '
|
|
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
|
|
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 '
|
|
6
|
-
import { traverseForChanges } from '
|
|
7
|
-
import type { ChangeState } from '
|
|
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 '
|
|
6
|
+
import { evaluateConstant } from '../analysis/constant'
|
|
7
7
|
import {
|
|
8
8
|
declarationReaches,
|
|
9
9
|
initializerReaches,
|
|
10
10
|
readCrossesFunctionBoundary,
|
|
11
|
-
} from '
|
|
12
|
-
import { isPure } from '
|
|
13
|
-
import { isInsideWith } from '
|
|
14
|
-
import { reorderableToStatement } from '
|
|
15
|
-
import { valueToLiteral } from '
|
|
16
|
-
import { isCalleeOrTagOf } from '
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 '
|
|
7
|
-
import { enclosingScopeHasDirectEval, isInsideWith } from '
|
|
8
|
-
import { hasConstantViolation } from '
|
|
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
|
|
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
|
|
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
|
|
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 '
|
|
5
|
-
import { traverseForChanges } from '
|
|
6
|
-
import type { ChangeState } from '
|
|
7
|
-
import { hasConstantViolation } from '
|
|
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 '
|
|
6
|
-
import type { ChangeState } from '
|
|
7
|
-
import { collectLoopLabels, generateLoopLabel, redirectContinues } from '
|
|
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
|
|
45
|
-
const
|
|
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
|
|
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 '
|
|
7
|
-
import { isInsideWith } from '
|
|
8
|
-
import { traverseForChanges } from '
|
|
9
|
-
import type { ChangeState } from '
|
|
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
|
|
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
|
|
85
|
+
const callee = expr.callee
|
|
85
86
|
if (!t.isMemberExpression(callee) && !t.isOptionalMemberExpression(callee)) {
|
|
86
87
|
return
|
|
87
88
|
}
|
|
88
|
-
const
|
|
89
|
+
const object = callee.object
|
|
89
90
|
if (!t.isIdentifier(object) || object.name !== 'console') {
|
|
90
91
|
return
|
|
91
92
|
}
|