webfuscator 1.2.0 → 1.3.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/dist/analysis/constant.js +3 -4
- package/dist/analysis/constant.js.map +1 -1
- package/dist/analysis/inlineability.d.ts.map +1 -1
- package/dist/analysis/inlineability.js +37 -25
- package/dist/analysis/inlineability.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/obfuscator.d.ts +2 -1
- package/dist/obfuscator.d.ts.map +1 -1
- package/dist/obfuscator.js +47 -12
- package/dist/obfuscator.js.map +1 -1
- package/dist/options.d.ts +24 -4
- package/dist/options.d.ts.map +1 -1
- package/dist/preparation/expand-destructuring.d.ts +3 -3
- package/dist/preparation/expand-destructuring.js +6 -6
- package/dist/preparation/expand-destructuring.js.map +1 -1
- package/dist/transforms/arrow-to-function.js +3 -5
- package/dist/transforms/arrow-to-function.js.map +1 -1
- package/dist/transforms/conceal-strings.d.ts +57 -0
- package/dist/transforms/conceal-strings.d.ts.map +1 -0
- package/dist/transforms/conceal-strings.js +361 -0
- package/dist/transforms/conceal-strings.js.map +1 -0
- package/dist/transforms/const-let-to-var.d.ts +3 -3
- package/dist/transforms/const-let-to-var.d.ts.map +1 -1
- package/dist/transforms/const-let-to-var.js +36 -9
- package/dist/transforms/const-let-to-var.js.map +1 -1
- package/dist/transforms/const-to-let.d.ts +2 -3
- package/dist/transforms/const-to-let.d.ts.map +1 -1
- package/dist/transforms/const-to-let.js +3 -5
- package/dist/transforms/const-to-let.js.map +1 -1
- package/dist/transforms/fold-builtin-methods.d.ts.map +1 -1
- package/dist/transforms/fold-builtin-methods.js +48 -10
- package/dist/transforms/fold-builtin-methods.js.map +1 -1
- package/dist/transforms/fold-constants.js +3 -0
- package/dist/transforms/fold-constants.js.map +1 -1
- package/dist/transforms/hoist-variables.d.ts +30 -0
- package/dist/transforms/hoist-variables.d.ts.map +1 -0
- package/dist/transforms/hoist-variables.js +224 -0
- package/dist/transforms/hoist-variables.js.map +1 -0
- package/dist/transforms/inline-functions.js +3 -4
- package/dist/transforms/inline-functions.js.map +1 -1
- package/dist/transforms/mangle-properties.js +7 -4
- package/dist/transforms/mangle-properties.js.map +1 -1
- package/dist/transforms/merge-variable-declarations.d.ts +17 -0
- package/dist/transforms/merge-variable-declarations.d.ts.map +1 -0
- package/dist/transforms/merge-variable-declarations.js +68 -0
- package/dist/transforms/merge-variable-declarations.js.map +1 -0
- package/dist/transforms/numbers-to-strings.d.ts.map +1 -1
- package/dist/transforms/numbers-to-strings.js +1 -8
- package/dist/transforms/numbers-to-strings.js.map +1 -1
- package/dist/transforms/pack-declarations-into-parameters.js +1 -5
- package/dist/transforms/pack-declarations-into-parameters.js.map +1 -1
- package/dist/transforms/pack.d.ts +5 -7
- package/dist/transforms/pack.d.ts.map +1 -1
- package/dist/transforms/pack.js +194 -32
- package/dist/transforms/pack.js.map +1 -1
- package/dist/transforms/remove-unused-code.d.ts.map +1 -1
- package/dist/transforms/remove-unused-code.js +7 -39
- 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 +29 -17
- package/dist/transforms/rename-identifiers.js.map +1 -1
- package/dist/transforms/reorder-function-declarations.d.ts +25 -0
- package/dist/transforms/reorder-function-declarations.d.ts.map +1 -0
- package/dist/transforms/reorder-function-declarations.js +64 -0
- package/dist/transforms/reorder-function-declarations.js.map +1 -0
- package/dist/transforms/specials-to-strings.js +4 -3
- package/dist/transforms/specials-to-strings.js.map +1 -1
- package/dist/transforms/update-to-assignment.js +1 -16
- package/dist/transforms/update-to-assignment.js.map +1 -1
- package/dist/utils/ast.d.ts +1 -2
- package/dist/utils/ast.d.ts.map +1 -1
- package/dist/utils/ast.js +12 -42
- package/dist/utils/ast.js.map +1 -1
- package/dist/utils/literal.d.ts.map +1 -1
- package/dist/utils/literal.js +74 -2
- package/dist/utils/literal.js.map +1 -1
- package/dist/utils/statement-lists.d.ts +9 -0
- package/dist/utils/statement-lists.d.ts.map +1 -0
- package/dist/utils/statement-lists.js +27 -0
- package/dist/utils/statement-lists.js.map +1 -0
- package/package.json +12 -13
- package/src/analysis/constant.ts +3 -6
- package/src/analysis/inlineability.ts +40 -32
- package/src/index.ts +1 -0
- package/src/obfuscator.ts +51 -14
- package/src/options.ts +28 -3
- package/src/preparation/expand-destructuring.ts +6 -6
- package/src/transforms/arrow-to-function.ts +3 -5
- package/src/transforms/conceal-strings.ts +530 -0
- package/src/transforms/const-let-to-var.ts +37 -9
- package/src/transforms/const-to-let.ts +3 -5
- package/src/transforms/fold-builtin-methods.ts +67 -12
- package/src/transforms/fold-constants.ts +3 -0
- package/src/transforms/hoist-variables.ts +272 -0
- package/src/transforms/inline-functions.ts +3 -4
- package/src/transforms/mangle-properties.ts +7 -7
- package/src/transforms/merge-variable-declarations.ts +91 -0
- package/src/transforms/numbers-to-strings.ts +2 -12
- package/src/transforms/pack-declarations-into-parameters.ts +1 -5
- package/src/transforms/pack.ts +202 -35
- package/src/transforms/remove-unused-code.ts +9 -64
- package/src/transforms/rename-identifiers.ts +42 -17
- package/src/transforms/reorder-function-declarations.ts +80 -0
- package/src/transforms/specials-to-strings.ts +4 -3
- package/src/transforms/update-to-assignment.ts +1 -17
- package/src/utils/ast.ts +15 -51
- package/src/utils/literal.ts +91 -2
- package/src/utils/statement-lists.ts +45 -0
- package/DISCLOSURE +0 -9
- package/README.md +0 -62
|
@@ -3,7 +3,6 @@ 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 '../utils/ast'
|
|
7
6
|
import { hasAnnexBFunctionAlias, referencesOrWritesVariable } from '../utils/paths'
|
|
8
7
|
|
|
9
8
|
export interface InlineCandidate {
|
|
@@ -15,7 +14,10 @@ export interface InlineCandidate {
|
|
|
15
14
|
declarationPath: NodePath
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
//
|
|
17
|
+
// Inlining splices a deep clone of the callee body, so any call that clone
|
|
18
|
+
// contains expands again. Expansion stops only when the graph below is acyclic,
|
|
19
|
+
// so this pass drops every candidate on a cycle before the inliner reaches a
|
|
20
|
+
// call site.
|
|
19
21
|
export function analyzeInlineability(ast: File): Map<string, InlineCandidate> {
|
|
20
22
|
const rawCandidates: InlineCandidate[] = []
|
|
21
23
|
|
|
@@ -75,34 +77,45 @@ export function analyzeInlineability(ast: File): Map<string, InlineCandidate> {
|
|
|
75
77
|
candidateByName.set(candidate.name, candidate)
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
const edges = buildExpansionGraph(candidateByName)
|
|
81
|
+
for (const scc of tarjanSCC([...candidateByName.keys()], edges)) {
|
|
82
|
+
// Tarjan reports an acyclic node as a singleton too, so a self-recursive
|
|
83
|
+
// candidate shows up only as an edge back to itself.
|
|
84
|
+
if (scc.length === 1 && !edges.get(scc[0]!)!.has(scc[0]!)) {
|
|
85
|
+
continue
|
|
86
|
+
}
|
|
87
|
+
for (const name of scc) {
|
|
88
|
+
candidateByName.delete(name)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return candidateByName
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// A clone keeps the whole body, so a reference inside a closure, an object
|
|
95
|
+
// method, or a getter is as live in the copy as one at the top level. Walking
|
|
96
|
+
// out to every enclosing candidate, rather than stopping at the innermost, also
|
|
97
|
+
// covers a candidate declared inside another candidate's body.
|
|
98
|
+
function buildExpansionGraph(
|
|
99
|
+
candidateByName: Map<string, InlineCandidate>,
|
|
100
|
+
): Map<string, Set<string>> {
|
|
101
|
+
const nameByFnNode = new Map<t.Function, string>()
|
|
79
102
|
const edges = new Map<string, Set<string>>()
|
|
80
|
-
for (const candidate of
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (t.isIdentifier(node) && node.name !== candidate.name && candidateByName.has(node.name)) {
|
|
84
|
-
callees.add(node.name)
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
edges.set(candidate.name, callees)
|
|
103
|
+
for (const [name, candidate] of candidateByName) {
|
|
104
|
+
nameByFnNode.set(candidate.fnNode, name)
|
|
105
|
+
edges.set(name, new Set())
|
|
88
106
|
}
|
|
89
107
|
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
inCycle.add(name)
|
|
108
|
+
for (const [name, candidate] of candidateByName) {
|
|
109
|
+
for (const ref of candidate.binding.referencePaths) {
|
|
110
|
+
for (let owner = ref.parentPath; owner; owner = owner.parentPath) {
|
|
111
|
+
const ownerName = owner.isFunction() ? nameByFnNode.get(owner.node) : undefined
|
|
112
|
+
if (ownerName !== undefined) {
|
|
113
|
+
edges.get(ownerName)!.add(name)
|
|
114
|
+
}
|
|
98
115
|
}
|
|
99
116
|
}
|
|
100
117
|
}
|
|
101
|
-
|
|
102
|
-
for (const name of inCycle) {
|
|
103
|
-
candidateByName.delete(name)
|
|
104
|
-
}
|
|
105
|
-
return candidateByName
|
|
118
|
+
return edges
|
|
106
119
|
}
|
|
107
120
|
|
|
108
121
|
function checkCandidate(
|
|
@@ -142,7 +155,7 @@ function checkCandidate(
|
|
|
142
155
|
return null
|
|
143
156
|
}
|
|
144
157
|
|
|
145
|
-
const analysis = analyzeBody(
|
|
158
|
+
const analysis = analyzeBody(fnPath as NodePath<t.Function>)
|
|
146
159
|
if (analysis.unsafe || analysis.closureCapture) {
|
|
147
160
|
return null
|
|
148
161
|
}
|
|
@@ -200,9 +213,8 @@ interface BodyAnalysis {
|
|
|
200
213
|
closureCapture: boolean
|
|
201
214
|
}
|
|
202
215
|
|
|
203
|
-
function analyzeBody(
|
|
216
|
+
function analyzeBody(fnPath: NodePath<t.Function>): BodyAnalysis {
|
|
204
217
|
const state: AnalyzeBodyState = {
|
|
205
|
-
candidateName: name,
|
|
206
218
|
outerScope: fnPath.scope,
|
|
207
219
|
innerFnDepth: 0,
|
|
208
220
|
unsafe: false,
|
|
@@ -216,7 +228,6 @@ function analyzeBody(name: string, fnPath: NodePath<t.Function>): BodyAnalysis {
|
|
|
216
228
|
}
|
|
217
229
|
|
|
218
230
|
interface AnalyzeBodyState {
|
|
219
|
-
candidateName: string
|
|
220
231
|
outerScope: NodePath<t.Function>['scope']
|
|
221
232
|
innerFnDepth: number
|
|
222
233
|
unsafe: boolean
|
|
@@ -268,10 +279,7 @@ const analyzeBodyVisitor: Visitor<AnalyzeBodyState> = {
|
|
|
268
279
|
},
|
|
269
280
|
Identifier(path, state) {
|
|
270
281
|
const name = path.node.name
|
|
271
|
-
if (
|
|
272
|
-
state.innerFnDepth === 0 &&
|
|
273
|
-
(name === 'arguments' || name === 'eval' || name === state.candidateName)
|
|
274
|
-
) {
|
|
282
|
+
if (state.innerFnDepth === 0 && name === 'arguments') {
|
|
275
283
|
state.unsafe = true
|
|
276
284
|
path.stop()
|
|
277
285
|
return
|
package/src/index.ts
CHANGED
package/src/obfuscator.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { wrapSingleStatements } from './preparation/wrap-single-statements'
|
|
|
14
14
|
import { argumentsToParameters } from './transforms/arguments-to-parameters'
|
|
15
15
|
import { arrowToFunction } from './transforms/arrow-to-function'
|
|
16
16
|
import { collapseSingleUseTemps } from './transforms/collapse-single-use-temps'
|
|
17
|
+
import { concealStrings } from './transforms/conceal-strings'
|
|
17
18
|
import { constLetToVar } from './transforms/const-let-to-var'
|
|
18
19
|
import { constToLet } from './transforms/const-to-let'
|
|
19
20
|
import { doWhileToWhile } from './transforms/do-while-to-while'
|
|
@@ -26,9 +27,11 @@ import { foldBuiltinMethods } from './transforms/fold-builtin-methods'
|
|
|
26
27
|
import { foldConstants } from './transforms/fold-constants'
|
|
27
28
|
import { forToWhile } from './transforms/for-to-while'
|
|
28
29
|
import { functionDeclarationToExpression } from './transforms/function-declaration-to-expression'
|
|
30
|
+
import { hoistVariables } from './transforms/hoist-variables'
|
|
29
31
|
import { inlineFunctions } from './transforms/inline-functions'
|
|
30
32
|
import { logicalToTernary } from './transforms/logical-to-ternary'
|
|
31
33
|
import { mangleProperties } from './transforms/mangle-properties'
|
|
34
|
+
import { mergeVariableDeclarations } from './transforms/merge-variable-declarations'
|
|
32
35
|
import { nullishCoalescingToTernary } from './transforms/nullish-coalescing-to-ternary'
|
|
33
36
|
import { numbersToStrings } from './transforms/numbers-to-strings'
|
|
34
37
|
import { objectMethodToProperty } from './transforms/object-method-to-property'
|
|
@@ -39,6 +42,7 @@ import { removeAnonymousFunctionNames } from './transforms/remove-anonymous-func
|
|
|
39
42
|
import { removeUnreachableCode } from './transforms/remove-unreachable-code'
|
|
40
43
|
import { removeUnusedCode } from './transforms/remove-unused-code'
|
|
41
44
|
import { renameIdentifiers } from './transforms/rename-identifiers'
|
|
45
|
+
import { reorderFunctionDeclarations } from './transforms/reorder-function-declarations'
|
|
42
46
|
import { specialsToStrings } from './transforms/specials-to-strings'
|
|
43
47
|
import { switchToIf } from './transforms/switch-to-if'
|
|
44
48
|
import { ternaryToIf } from './transforms/ternary-to-if'
|
|
@@ -48,8 +52,6 @@ import type { StringGeneratorModeOption } from './utils/string-generator'
|
|
|
48
52
|
|
|
49
53
|
const parserOptions: ParserOptions = { sourceType: 'unambiguous' }
|
|
50
54
|
|
|
51
|
-
const PRESERVED_COMMENT_RE = /^!|@(?:license|preserve)\b|^#\s*source(?:Mapping)?URL=/iu
|
|
52
|
-
|
|
53
55
|
const DEFAULT_STRING_GENERATOR_MODE: StringGeneratorModeOption = 'mangled'
|
|
54
56
|
const DEFAULT_SEED = 0
|
|
55
57
|
|
|
@@ -76,11 +78,10 @@ const PREPARATION: readonly Phase[] = [
|
|
|
76
78
|
['dotToBracket', asBoolean(dotToBracket)],
|
|
77
79
|
]
|
|
78
80
|
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
// `ObjectMethod` makes extraction refuse the whole literal.
|
|
81
|
+
// `constLetToVar` must precede the fixed point because folds need function-scoped
|
|
82
|
+
// bindings. `argumentsToParameters` must precede parameter renaming.
|
|
83
|
+
// `objectMethodToProperty` must precede extraction because one `ObjectMethod`
|
|
84
|
+
// blocks the whole object literal.
|
|
84
85
|
const PRE_LOOP: readonly ConfigurablePhase[] = [
|
|
85
86
|
['dropDebugger', dropDebugger],
|
|
86
87
|
['dropConsole', dropConsole],
|
|
@@ -124,15 +125,25 @@ const LOWERING: readonly ConfigurablePhase[] = [
|
|
|
124
125
|
['ternaryToIf', ternaryToIf],
|
|
125
126
|
]
|
|
126
127
|
|
|
127
|
-
//
|
|
128
|
-
//
|
|
128
|
+
// `packDeclarationsIntoParameters` must precede declaration motion and merging.
|
|
129
|
+
// `reorderFunctionDeclarations` follows `functionDeclarationToExpression`, so it
|
|
130
|
+
// moves only declarations still needed for hoisting. `hoistVariables` must run
|
|
131
|
+
// before `mergeVariableDeclarations`. `numbersToStrings` follows the fixed point,
|
|
132
|
+
// yodification, and `specialsToStrings` because they need or create numbers.
|
|
129
133
|
const POST_PROCESS: readonly ConfigurablePhase[] = [
|
|
130
134
|
['packDeclarationsIntoParameters', packDeclarationsIntoParameters],
|
|
135
|
+
['reorderFunctionDeclarations', reorderFunctionDeclarations],
|
|
136
|
+
['hoistVariables', hoistVariables],
|
|
137
|
+
['mergeVariableDeclarations', mergeVariableDeclarations],
|
|
131
138
|
['yodifyConditions', yodifyConditions],
|
|
132
139
|
['specialsToStrings', specialsToStrings],
|
|
133
140
|
['numbersToStrings', numbersToStrings],
|
|
134
141
|
]
|
|
135
142
|
|
|
143
|
+
// Conceal strings after every string-producing pass, but before renaming so the
|
|
144
|
+
// generated vault bindings use the caller's name generator.
|
|
145
|
+
const PROTECTION: readonly ConfigurablePhase[] = [['concealStrings', concealStrings]]
|
|
146
|
+
|
|
136
147
|
// Renaming runs last because later transforms depend on recognizable bindings.
|
|
137
148
|
const RENAME: readonly ConfigurablePhase[] = [['renameIdentifiers', renameIdentifiers]]
|
|
138
149
|
|
|
@@ -141,6 +152,19 @@ const RENAME: readonly ConfigurablePhase[] = [['renameIdentifiers', renameIdenti
|
|
|
141
152
|
// every other rewrite, including renaming.
|
|
142
153
|
const PACK: readonly ConfigurablePhase[] = [['pack', pack]]
|
|
143
154
|
|
|
155
|
+
// Tests derive their all-transforms setup from this list. The phase tables remain
|
|
156
|
+
// the only source of pipeline order.
|
|
157
|
+
export const CONFIGURABLE_TRANSFORM_NAMES: readonly TransformName[] = [
|
|
158
|
+
...BEFORE_PREPARATION,
|
|
159
|
+
...PRE_LOOP,
|
|
160
|
+
...FIXED_POINT,
|
|
161
|
+
...LOWERING,
|
|
162
|
+
...POST_PROCESS,
|
|
163
|
+
...PROTECTION,
|
|
164
|
+
...RENAME,
|
|
165
|
+
...PACK,
|
|
166
|
+
].map(([name]) => name)
|
|
167
|
+
|
|
144
168
|
/** Parses, transforms, and prints JavaScript without mutating external state. */
|
|
145
169
|
export function obfuscate(code: string, options: ObfuscatorOptions = {}): string {
|
|
146
170
|
const log = options.verbose ? makeLogger() : null
|
|
@@ -184,6 +208,13 @@ export function obfuscate(code: string, options: ObfuscatorOptions = {}): string
|
|
|
184
208
|
run(log, name, () => fn(ast, ctxFor(name, options, baseCtx)))
|
|
185
209
|
}
|
|
186
210
|
|
|
211
|
+
for (const [name, fn] of PROTECTION) {
|
|
212
|
+
if (!isEnabled(name, options)) {
|
|
213
|
+
continue
|
|
214
|
+
}
|
|
215
|
+
run(log, name, () => fn(ast, ctxFor(name, options, baseCtx)))
|
|
216
|
+
}
|
|
217
|
+
|
|
187
218
|
for (const [name, fn] of RENAME) {
|
|
188
219
|
if (!isEnabled(name, options)) {
|
|
189
220
|
continue
|
|
@@ -201,7 +232,13 @@ export function obfuscate(code: string, options: ObfuscatorOptions = {}): string
|
|
|
201
232
|
return run(
|
|
202
233
|
log,
|
|
203
234
|
'generate',
|
|
204
|
-
() =>
|
|
235
|
+
() =>
|
|
236
|
+
generate(ast, {
|
|
237
|
+
comments: false,
|
|
238
|
+
minified: options.minify ?? false,
|
|
239
|
+
// `comments: false` still allows @license and @preserve.
|
|
240
|
+
shouldPrintComment: () => false,
|
|
241
|
+
}).code,
|
|
205
242
|
)
|
|
206
243
|
}
|
|
207
244
|
|
|
@@ -216,6 +253,10 @@ function ctxFor(
|
|
|
216
253
|
options: ObfuscatorOptions,
|
|
217
254
|
base: TransformContext,
|
|
218
255
|
): TransformContext {
|
|
256
|
+
if (name === 'concealStrings') {
|
|
257
|
+
const entry = options.transforms?.concealStrings
|
|
258
|
+
return entry && typeof entry === 'object' ? { ...base, concealStrings: entry } : base
|
|
259
|
+
}
|
|
219
260
|
const entry = options.transforms?.[name]
|
|
220
261
|
let context = base
|
|
221
262
|
if (entry && typeof entry === 'object' && entry.stringGeneratorMode !== undefined) {
|
|
@@ -261,10 +302,6 @@ function asBoolean(fn: (ast: File) => unknown): TransformFn {
|
|
|
261
302
|
}
|
|
262
303
|
}
|
|
263
304
|
|
|
264
|
-
function shouldPrintComment(value: string): boolean {
|
|
265
|
-
return PRESERVED_COMMENT_RE.test(value)
|
|
266
|
-
}
|
|
267
|
-
|
|
268
305
|
type Logger = <T>(name: string, fn: () => T) => T
|
|
269
306
|
|
|
270
307
|
function run<T>(log: Logger | null, name: string, fn: () => T): T {
|
package/src/options.ts
CHANGED
|
@@ -21,6 +21,9 @@ export type TransformName =
|
|
|
21
21
|
| 'collapseSingleUseTemps'
|
|
22
22
|
| 'arrowToFunction'
|
|
23
23
|
| 'functionDeclarationToExpression'
|
|
24
|
+
| 'reorderFunctionDeclarations'
|
|
25
|
+
| 'hoistVariables'
|
|
26
|
+
| 'mergeVariableDeclarations'
|
|
24
27
|
| 'switchToIf'
|
|
25
28
|
| 'forToWhile'
|
|
26
29
|
| 'doWhileToWhile'
|
|
@@ -35,6 +38,7 @@ export type TransformName =
|
|
|
35
38
|
| 'yodifyConditions'
|
|
36
39
|
| 'specialsToStrings'
|
|
37
40
|
| 'numbersToStrings'
|
|
41
|
+
| 'concealStrings'
|
|
38
42
|
| 'mangleProperties'
|
|
39
43
|
| 'renameIdentifiers'
|
|
40
44
|
| 'pack'
|
|
@@ -61,8 +65,8 @@ export interface ManglePropertiesOptions {
|
|
|
61
65
|
/** Custom property-name generator. It takes precedence over `stringGeneratorMode`. */
|
|
62
66
|
nameGenerator?: PropertyNameGenerator
|
|
63
67
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
68
|
+
* Mangle only names with an exact standalone `/*@__MANGLE_PROP__*\/` or
|
|
69
|
+
* `/*#__MANGLE_PROP__*\/` annotation. Default `false`.
|
|
66
70
|
*/
|
|
67
71
|
onlyAnnotated?: boolean
|
|
68
72
|
/** Only names already present in `cache` may be mangled. Default `false`. */
|
|
@@ -84,16 +88,36 @@ export interface PackOptions {
|
|
|
84
88
|
* source is strict. This deliberately changes behavior. Default `false`.
|
|
85
89
|
*/
|
|
86
90
|
escapeStrict?: boolean
|
|
91
|
+
/**
|
|
92
|
+
* Free names to leave un-routed because they resolve to the real global from
|
|
93
|
+
* inside a detached Function body. `true` uses the built-in standard-globals
|
|
94
|
+
* list; an array names your own set. Stripped imports always route regardless,
|
|
95
|
+
* since a Function body cannot reach them. Default routes every free name.
|
|
96
|
+
*/
|
|
97
|
+
skipGlobals?: boolean | readonly string[]
|
|
87
98
|
/** Override the default string-generator mode for the names pack creates. */
|
|
88
99
|
stringGeneratorMode?: StringGeneratorModeOption
|
|
89
100
|
}
|
|
90
101
|
|
|
102
|
+
/** Options for the string vault generated by `concealStrings`. */
|
|
103
|
+
export interface ConcealStringsOptions {
|
|
104
|
+
/** Cache each decoded string in its vault. Default `true`. */
|
|
105
|
+
cache?: boolean
|
|
106
|
+
/** Choose how much of the UTF-16 range pads each pool. Default `'regional'`. */
|
|
107
|
+
cover?: 'full' | 'regional' | 'used'
|
|
108
|
+
/** Reuse one vault entry for equal strings. Default `true`. */
|
|
109
|
+
deduplicate?: boolean
|
|
110
|
+
/** Use one program vault or a separate vault per function. Default `'program'`. */
|
|
111
|
+
scope?: 'function' | 'program'
|
|
112
|
+
}
|
|
113
|
+
|
|
91
114
|
type SimpleTransform = Exclude<
|
|
92
115
|
TransformName,
|
|
93
|
-
'mangleProperties' | 'pack' | 'renameIdentifiers' | 'specialsToStrings'
|
|
116
|
+
'concealStrings' | 'mangleProperties' | 'pack' | 'renameIdentifiers' | 'specialsToStrings'
|
|
94
117
|
>
|
|
95
118
|
|
|
96
119
|
type TransformsMap = Partial<Record<SimpleTransform, boolean>> & {
|
|
120
|
+
concealStrings?: boolean | ConcealStringsOptions
|
|
97
121
|
mangleProperties?: boolean | ManglePropertiesOptions
|
|
98
122
|
pack?: boolean | PackOptions
|
|
99
123
|
renameIdentifiers?: TransformEntry
|
|
@@ -122,6 +146,7 @@ export interface ObfuscatorOptions {
|
|
|
122
146
|
|
|
123
147
|
// Resolved per-call defaults handed to every transform.
|
|
124
148
|
export interface TransformContext {
|
|
149
|
+
concealStrings?: ConcealStringsOptions
|
|
125
150
|
mangleProperties?: ManglePropertiesOptions
|
|
126
151
|
pack?: PackOptions
|
|
127
152
|
seed: number
|
|
@@ -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 {
|
|
6
|
+
import { isInsideWith } from '../utils/ast'
|
|
7
7
|
|
|
8
8
|
type Kind = t.VariableDeclaration['kind']
|
|
9
9
|
|
|
@@ -18,9 +18,9 @@ type BindingTarget = t.Identifier | t.ObjectPattern | t.ArrayPattern | t.Assignm
|
|
|
18
18
|
* The source, computed keys, and getters keep their original evaluation counts.
|
|
19
19
|
* Defaults compare against `void 0` because `undefined` can be shadowed.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* Patterns inside `with` stay untouched because an object property can capture
|
|
22
|
+
* a generated temporary. The `RequireObjectCoercible` guard runs before computed
|
|
23
|
+
* keys to preserve ObjectBindingPattern evaluation order.
|
|
24
24
|
*
|
|
25
25
|
* @example
|
|
26
26
|
* // ◀️ before
|
|
@@ -42,8 +42,8 @@ const visitor = {
|
|
|
42
42
|
if (typeof path.listKey !== 'string') {
|
|
43
43
|
return
|
|
44
44
|
}
|
|
45
|
-
//
|
|
46
|
-
if (isInsideWith(path)
|
|
45
|
+
// A `with` property can capture the generated temporary.
|
|
46
|
+
if (isInsideWith(path)) {
|
|
47
47
|
return
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -2,7 +2,7 @@ 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 {
|
|
5
|
+
import { isInsideWith } from '../utils/ast'
|
|
6
6
|
import { traverseForChanges } from '../utils/change-tracking'
|
|
7
7
|
import type { ChangeState } from '../utils/change-tracking'
|
|
8
8
|
|
|
@@ -65,10 +65,8 @@ const visitor: Visitor<ChangeState> = {
|
|
|
65
65
|
arrowReferencesSuper(path) ||
|
|
66
66
|
inUnsafeCaptureContext(path) ||
|
|
67
67
|
usesReassignedArguments(path) ||
|
|
68
|
-
// `with` can
|
|
69
|
-
|
|
70
|
-
isInsideWith(path) ||
|
|
71
|
-
enclosingScopeHasDirectEval(path)
|
|
68
|
+
// `with` can capture Babel's `this` or `arguments` alias.
|
|
69
|
+
isInsideWith(path)
|
|
72
70
|
) {
|
|
73
71
|
return
|
|
74
72
|
}
|