@dacely/toildefender 0.1.6 → 0.1.7
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 +1 -1
- package/esutils.js +12 -8
- package/obfuscator.js +101 -12
- package/package.json +1 -1
- package/processors/deadCode.js +32 -0
- package/processors/flattener.js +73 -8
- package/processors/identifiers.js +26 -6
- package/processors/literals.js +82 -2
- package/processors/methods.js +47 -34
- package/processors/modules.js +2 -2
- package/processors/normalizer.js +435 -69
- package/processors/numericVm.js +270 -83
- package/processors/postprocessing.js +4 -4
- package/processors/scopes.js +366 -50
- package/processors/uglifier.js +22 -2
- package/processors/variables.js +51 -8
|
@@ -10,9 +10,9 @@ var utils = require("../utils");
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Merges nested bind calls like
|
|
13
|
-
*
|
|
13
|
+
* toildefender$bind(toildefender$bind(main, 1234), 5678)
|
|
14
14
|
* to
|
|
15
|
-
*
|
|
15
|
+
* toildefender$bind(main, 1234, 5678)
|
|
16
16
|
* @param {Node} node
|
|
17
17
|
* @returns {Node}
|
|
18
18
|
*/
|
|
@@ -27,7 +27,7 @@ function mergeNestedBinds(node) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Checks whether node is a call to
|
|
30
|
+
* Checks whether node is a call to toildefender$bind.
|
|
31
31
|
* @param {Node} node
|
|
32
32
|
* @returns {boolean}
|
|
33
33
|
*/
|
|
@@ -36,7 +36,7 @@ function isBindCall(node) {
|
|
|
36
36
|
|
|
37
37
|
return node.type == "CallExpression"
|
|
38
38
|
&& node.callee.type == "Identifier"
|
|
39
|
-
&& node.callee.name == "
|
|
39
|
+
&& node.callee.name == "toildefender$bind";
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
module.exports = class Postprocessing {
|
package/processors/scopes.js
CHANGED
|
@@ -19,11 +19,137 @@ function isClassMethodScope(scope) {
|
|
|
19
19
|
if (node.type == "MethodDefinition" || node.type == "ClassBody") {
|
|
20
20
|
return true;
|
|
21
21
|
}
|
|
22
|
-
node = node.
|
|
22
|
+
node = node.toildefender$parent;
|
|
23
23
|
}
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
function isNumericVmInternalNode(node) {
|
|
28
|
+
while (node) {
|
|
29
|
+
if (node.toildefender$numericVmInternal === true) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
node = node.toildefender$parent;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isNumericVmInternalFunction(stack) {
|
|
38
|
+
return stack.some(frame => frame.node && isNumericVmInternalNode(frame.node));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isNumericVmInternalScope(scope) {
|
|
42
|
+
return isNumericVmInternalNode(scope && scope.block);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function scopeReference(scopeVarName, index) {
|
|
46
|
+
return {
|
|
47
|
+
type: "MemberExpression",
|
|
48
|
+
object: { type: "Identifier", name: scopeVarName },
|
|
49
|
+
property: { type: "Literal", value: index },
|
|
50
|
+
computed: true,
|
|
51
|
+
toildefender$scopeObjectReference: true
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function isReferenceIdentifier(node, stack) {
|
|
56
|
+
var parentFrame = stack[1];
|
|
57
|
+
if (!parentFrame) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
var parent = parentFrame.node;
|
|
62
|
+
var key = parentFrame.key;
|
|
63
|
+
|
|
64
|
+
if ((parent.type == "FunctionDeclaration" || parent.type == "FunctionExpression") && (key == "id" || key == "params")) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if ((parent.type == "ClassDeclaration" || parent.type == "ClassExpression") && key == "id") {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
if (parent.type == "VariableDeclarator" && key == "id") {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (parent.type == "CatchClause" && key == "param") {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
if ((parent.type == "MemberExpression" || parent.type == "Property") && key == "property" && parent.computed === false) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
if (parent.type == "Property" && key == "key" && parent.computed === false) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if ((parent.type == "MethodDefinition" || parent.type == "PropertyDefinition" || parent.type == "FieldDefinition") && key == "key" && parent.computed === false) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
if ((parent.type == "LabeledStatement" || parent.type == "BreakStatement" || parent.type == "ContinueStatement") && key == "label") {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function isInsideNestedScope(stack, root, scopeBlocks) {
|
|
93
|
+
return stack.some(frame => frame.node != root && scopeBlocks.has(frame.node));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function isMovableVariable(variable) {
|
|
97
|
+
return variable.defs.some(def => {
|
|
98
|
+
if (isNumericVmInternalNode(def.node)) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
if (def.type == "Variable" || def.type == "CatchClause") {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
return def.type == "FunctionName" && def.node.type != "FunctionExpression";
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function markPropertyValueReplacement(stack) {
|
|
109
|
+
var parentFrame = stack[1];
|
|
110
|
+
if (!parentFrame) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
var parent = parentFrame.node;
|
|
114
|
+
if (parent.type == "Property" && parent.shorthand === true && parentFrame.key == "value") {
|
|
115
|
+
parent.shorthand = false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function isReferenceInsideNestedFunction(scopeBlock, identifier) {
|
|
120
|
+
var current = identifier && identifier.toildefender$parent;
|
|
121
|
+
while (current && current != scopeBlock) {
|
|
122
|
+
if (estest.isFunction(current)) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
current = current.toildefender$parent;
|
|
126
|
+
}
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function normalizeRatio(value) {
|
|
131
|
+
var ratio = Number(value);
|
|
132
|
+
if (!Number.isFinite(ratio)) {
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
if (ratio < 0) {
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
if (ratio > 1) {
|
|
139
|
+
return 1;
|
|
140
|
+
}
|
|
141
|
+
return ratio;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function hashString32(value) {
|
|
145
|
+
var h = 0x811c9dc5;
|
|
146
|
+
for (var i = 0; i < value.length; i += 1) {
|
|
147
|
+
h ^= value.charCodeAt(i);
|
|
148
|
+
h = Math.imul(h, 0x01000193) >>> 0;
|
|
149
|
+
}
|
|
150
|
+
return h >>> 0;
|
|
151
|
+
}
|
|
152
|
+
|
|
27
153
|
module.exports = class Scopes {
|
|
28
154
|
|
|
29
155
|
constructor (logger) {
|
|
@@ -41,19 +167,216 @@ module.exports = class Scopes {
|
|
|
41
167
|
* @param {Node} ast Root node
|
|
42
168
|
* @param {ScopeManager} scopeManager Scope manager
|
|
43
169
|
*/
|
|
44
|
-
createScopeObjects (ast, scopeManager) {
|
|
170
|
+
createScopeObjects (ast, scopeManager, options) {
|
|
45
171
|
assert.ok(estest.isNode(ast));
|
|
46
172
|
|
|
47
173
|
this.esutils.setParentsRecursive(ast);
|
|
174
|
+
options = options || {};
|
|
175
|
+
var ratio = normalizeRatio(options.ratio);
|
|
176
|
+
var seed = options.seed || "toildefender-scope";
|
|
177
|
+
var forceProgram = options.forceProgram === true;
|
|
48
178
|
var scopes = scopeManager.acquireAll(ast);
|
|
49
179
|
var rngAlpha = new utils.UniqueRandomAlpha(3);
|
|
180
|
+
var replacements = new WeakMap();
|
|
181
|
+
var referencesByVariable = new Map();
|
|
182
|
+
var fallbackReplacementsByName = new Map();
|
|
183
|
+
var scopeBlocks = new WeakSet();
|
|
184
|
+
scopes.forEach(scope => {
|
|
185
|
+
if (scope && scope.block) {
|
|
186
|
+
scopeBlocks.add(scope.block);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
function cloneReplacement(node) {
|
|
191
|
+
return utils.cloneISwearIKnowWhatImDoing(node);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function addFallbackReplacement(name, replacement, block, scopeDecl) {
|
|
195
|
+
var entries = fallbackReplacementsByName.get(name);
|
|
196
|
+
if (!entries) {
|
|
197
|
+
entries = [];
|
|
198
|
+
fallbackReplacementsByName.set(name, entries);
|
|
199
|
+
}
|
|
200
|
+
entries.push({
|
|
201
|
+
block: block,
|
|
202
|
+
scopeDecl: scopeDecl,
|
|
203
|
+
replacement: replacement
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function ancestorDistance(ancestor, node) {
|
|
208
|
+
var distance = 0;
|
|
209
|
+
var current = node;
|
|
210
|
+
while (current) {
|
|
211
|
+
if (current == ancestor) {
|
|
212
|
+
return distance;
|
|
213
|
+
}
|
|
214
|
+
current = current.toildefender$parent;
|
|
215
|
+
distance += 1;
|
|
216
|
+
}
|
|
217
|
+
return -1;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function fallbackReplacementForName(name, node) {
|
|
221
|
+
var entries = fallbackReplacementsByName.get(name);
|
|
222
|
+
if (!entries) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
var best = null;
|
|
227
|
+
var bestDistance = Infinity;
|
|
228
|
+
entries.forEach(entry => {
|
|
229
|
+
var liveBlock = entry.scopeDecl && entry.scopeDecl.toildefender$parent;
|
|
230
|
+
var distance = liveBlock ? ancestorDistance(liveBlock, node) : -1;
|
|
231
|
+
if (distance < 0) {
|
|
232
|
+
distance = ancestorDistance(entry.block, node);
|
|
233
|
+
}
|
|
234
|
+
if (distance >= 0 && distance < bestDistance) {
|
|
235
|
+
best = entry.replacement;
|
|
236
|
+
bestDistance = distance;
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
if (best) {
|
|
240
|
+
return best;
|
|
241
|
+
}
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function addResolvedReference(variable, reference) {
|
|
246
|
+
if (!variable || !reference || !reference.identifier) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
var references = referencesByVariable.get(variable);
|
|
250
|
+
if (!references) {
|
|
251
|
+
references = new Set();
|
|
252
|
+
referencesByVariable.set(variable, references);
|
|
253
|
+
}
|
|
254
|
+
references.add(reference);
|
|
255
|
+
}
|
|
256
|
+
|
|
50
257
|
scopeManager.scopes.forEach(scope => {
|
|
51
|
-
|
|
258
|
+
scope.variables.forEach(variable => {
|
|
259
|
+
variable.references.forEach(reference => addResolvedReference(variable, reference));
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
scope.references.forEach(reference => {
|
|
263
|
+
addResolvedReference(reference.resolved, reference);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
scope.through.forEach(reference => {
|
|
267
|
+
addResolvedReference(reference.resolved, reference);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
function referencesFor(variable) {
|
|
272
|
+
var references = referencesByVariable.get(variable);
|
|
273
|
+
references = references ? Array.from(references) : variable.references;
|
|
274
|
+
return references.filter(reference => reference.resolved === variable);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function shouldFlattenScope(scope, movableVariables, index) {
|
|
278
|
+
if (forceProgram && scope && scope.block && scope.block.type == "Program") {
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
if (movableVariables.some(variable => referencesFor(variable).some(reference => isReferenceInsideNestedFunction(scope.block, reference.identifier)))) {
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
if (ratio >= 1) {
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
if (ratio <= 0) {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
var blockType = scope && scope.block && scope.block.type || "";
|
|
291
|
+
var variableNames = movableVariables.map(variable => variable.name).sort().join(",");
|
|
292
|
+
var score = hashString32(`${seed}:${index}:${scope.type}:${blockType}:${variableNames}`) / 0x100000000;
|
|
293
|
+
return score < ratio;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function rewriteKnownReferences(node) {
|
|
297
|
+
if (!node) {
|
|
298
|
+
return node;
|
|
299
|
+
}
|
|
300
|
+
return traverser.traverse(node, [], (child, stack) => {
|
|
301
|
+
if (isNumericVmInternalFunction(stack)) {
|
|
302
|
+
return child;
|
|
303
|
+
}
|
|
304
|
+
if (child.type == "Identifier" && replacements.has(child)) {
|
|
305
|
+
markPropertyValueReplacement(stack);
|
|
306
|
+
return cloneReplacement(replacements.get(child));
|
|
307
|
+
}
|
|
308
|
+
return child;
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
scopeManager.scopes.forEach((scope, scopeIndex) => {
|
|
313
|
+
if (!this.esutils.canInsertIntoScope(scope) || isClassMethodScope(scope) || isNumericVmInternalScope(scope)) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
var movableVariables = scope.variables.filter(isMovableVariable);
|
|
317
|
+
if (movableVariables.length == 0) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (!shouldFlattenScope(scope, movableVariables, scopeIndex)) {
|
|
52
321
|
return;
|
|
53
322
|
}
|
|
54
323
|
var scopeVarName = `$$scope$${rngAlpha.get()}`;
|
|
55
324
|
|
|
56
325
|
var counter = 0;
|
|
326
|
+
var indexes = new Map();
|
|
327
|
+
var localReplacementsByName = new Map();
|
|
328
|
+
movableVariables.forEach(variable => {
|
|
329
|
+
indexes.set(variable, counter++);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
movableVariables.forEach(variable => {
|
|
333
|
+
var index = indexes.get(variable);
|
|
334
|
+
variable.defs.forEach(def => {
|
|
335
|
+
if (def.type == "Variable") {
|
|
336
|
+
var replacement = scopeReference(scopeVarName, index);
|
|
337
|
+
localReplacementsByName.set(variable.name, replacement);
|
|
338
|
+
referencesFor(variable).forEach(reference => {
|
|
339
|
+
replacements.set(reference.identifier, scopeReference(scopeVarName, index));
|
|
340
|
+
});
|
|
341
|
+
} else if (def.type == "CatchClause") {
|
|
342
|
+
referencesFor(variable).forEach(reference => {
|
|
343
|
+
replacements.set(reference.identifier, scopeReference(scopeVarName, index));
|
|
344
|
+
});
|
|
345
|
+
} else if (def.type == "FunctionName" && def.node.type != "FunctionExpression") {
|
|
346
|
+
referencesFor(variable).forEach(reference => {
|
|
347
|
+
replacements.set(reference.identifier, {
|
|
348
|
+
type: "CallExpression",
|
|
349
|
+
callee: { type: "Identifier", name: "toildefender$bind" },
|
|
350
|
+
arguments: [
|
|
351
|
+
{ type: "Identifier", name: reference.identifier.name },
|
|
352
|
+
{ type: "Identifier", name: scopeVarName }
|
|
353
|
+
]
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
var rewriteLocalReferencesByName = () => {
|
|
361
|
+
this.esutils.setParentsRecursive(scope.block);
|
|
362
|
+
traverser.traverse(scope.block, [], (node, stack) => {
|
|
363
|
+
if (isNumericVmInternalFunction(stack)) {
|
|
364
|
+
return node;
|
|
365
|
+
}
|
|
366
|
+
if (isInsideNestedScope(stack, scope.block, scopeBlocks)) {
|
|
367
|
+
return node;
|
|
368
|
+
}
|
|
369
|
+
if (node.type == "Identifier" && isReferenceIdentifier(node, stack)) {
|
|
370
|
+
var replacement = localReplacementsByName.get(node.name);
|
|
371
|
+
if (replacement) {
|
|
372
|
+
markPropertyValueReplacement(stack);
|
|
373
|
+
return cloneReplacement(replacement);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return node;
|
|
377
|
+
});
|
|
378
|
+
};
|
|
379
|
+
|
|
57
380
|
var scopeDecl = {
|
|
58
381
|
type: "VariableDeclaration",
|
|
59
382
|
kind: "var",
|
|
@@ -64,13 +387,16 @@ module.exports = class Scopes {
|
|
|
64
387
|
init: { type: "ArrayExpression", elements: [] }
|
|
65
388
|
}
|
|
66
389
|
],
|
|
67
|
-
|
|
390
|
+
toildefender$scopeObject: true
|
|
68
391
|
};
|
|
69
392
|
|
|
70
393
|
this.esutils.insertIntoScope(scope, scopeDecl);
|
|
394
|
+
localReplacementsByName.forEach((replacement, name) => {
|
|
395
|
+
addFallbackReplacement(name, replacement, scope.block, scopeDecl);
|
|
396
|
+
});
|
|
71
397
|
|
|
72
|
-
|
|
73
|
-
var index =
|
|
398
|
+
movableVariables.forEach(variable => {
|
|
399
|
+
var index = indexes.get(variable);
|
|
74
400
|
|
|
75
401
|
variable.defs.forEach(def => {
|
|
76
402
|
if (def.type == "Variable") {
|
|
@@ -88,9 +414,9 @@ module.exports = class Scopes {
|
|
|
88
414
|
object: { type: "Identifier", name: scopeVarName },
|
|
89
415
|
property: { type: "Literal", value: index },
|
|
90
416
|
computed: true,
|
|
91
|
-
|
|
417
|
+
toildefender$scopeObjectReference: true
|
|
92
418
|
},
|
|
93
|
-
right: def.node.init
|
|
419
|
+
right: rewriteKnownReferences(def.node.init)
|
|
94
420
|
}
|
|
95
421
|
});
|
|
96
422
|
}
|
|
@@ -104,25 +430,13 @@ module.exports = class Scopes {
|
|
|
104
430
|
} else {
|
|
105
431
|
this.esutils.replaceNode(scope.block, def.parent, { type: "BlockStatement", body: replacement });
|
|
106
432
|
}
|
|
107
|
-
variable.
|
|
433
|
+
referencesFor(variable).forEach(reference => {
|
|
108
434
|
// References can not be replaced via replaceNodeEx for whatever reason
|
|
109
|
-
this.esutils.replaceNode(scope.block, reference.identifier,
|
|
110
|
-
type: "MemberExpression",
|
|
111
|
-
object: { type: "Identifier", name: scopeVarName },
|
|
112
|
-
property: { type: "Literal", value: index },
|
|
113
|
-
computed: true,
|
|
114
|
-
veilmark$scopeObjectReference: true
|
|
115
|
-
});
|
|
435
|
+
this.esutils.replaceNode(scope.block, reference.identifier, cloneReplacement(replacements.get(reference.identifier) || scopeReference(scopeVarName, index)));
|
|
116
436
|
});
|
|
117
437
|
} else if (def.type == "CatchClause") {
|
|
118
|
-
Object.defineProperty(scope.block, "
|
|
119
|
-
value:
|
|
120
|
-
type: "MemberExpression",
|
|
121
|
-
object: { type: "Identifier", name: scopeVarName },
|
|
122
|
-
property: { type: "Literal", value: index },
|
|
123
|
-
computed: true,
|
|
124
|
-
veilmark$scopeObjectReference: true
|
|
125
|
-
},
|
|
438
|
+
Object.defineProperty(scope.block, "toildefender$exception", {
|
|
439
|
+
value: scopeReference(scopeVarName, index),
|
|
126
440
|
configurable: true
|
|
127
441
|
});
|
|
128
442
|
this.esutils.insertIntoScope(scope, {
|
|
@@ -130,49 +444,32 @@ module.exports = class Scopes {
|
|
|
130
444
|
expression: {
|
|
131
445
|
type: "AssignmentExpression",
|
|
132
446
|
operator: "=",
|
|
133
|
-
left:
|
|
134
|
-
type: "MemberExpression",
|
|
135
|
-
object: { type: "Identifier", name: scopeVarName },
|
|
136
|
-
property: { type: "Literal", value: index },
|
|
137
|
-
computed: true,
|
|
138
|
-
veilmark$scopeObjectReference: true
|
|
139
|
-
},
|
|
447
|
+
left: scopeReference(scopeVarName, index),
|
|
140
448
|
right: def.name
|
|
141
449
|
}
|
|
142
450
|
}, 1);
|
|
143
|
-
variable.
|
|
144
|
-
this.esutils.replaceNode(scope.block, reference.identifier,
|
|
145
|
-
type: "MemberExpression",
|
|
146
|
-
object: { type: "Identifier", name: scopeVarName },
|
|
147
|
-
property: { type: "Literal", value: index },
|
|
148
|
-
computed: true,
|
|
149
|
-
veilmark$scopeObjectReference: true
|
|
150
|
-
});
|
|
451
|
+
referencesFor(variable).forEach(reference => {
|
|
452
|
+
this.esutils.replaceNode(scope.block, reference.identifier, cloneReplacement(replacements.get(reference.identifier) || scopeReference(scopeVarName, index)));
|
|
151
453
|
});
|
|
152
454
|
} else if (def.type == "FunctionName") {
|
|
153
455
|
if (def.node.type == "FunctionExpression") {
|
|
154
456
|
return;
|
|
155
457
|
}
|
|
156
|
-
variable.
|
|
157
|
-
this.esutils.replaceNode(scope.block, reference.identifier,
|
|
158
|
-
type: "CallExpression",
|
|
159
|
-
callee: { type: "Identifier", name: "veilmark$bind" },
|
|
160
|
-
arguments: [
|
|
161
|
-
reference.identifier,
|
|
162
|
-
{ type: "Identifier", name: scopeVarName }
|
|
163
|
-
]
|
|
164
|
-
});
|
|
458
|
+
referencesFor(variable).forEach(reference => {
|
|
459
|
+
this.esutils.replaceNode(scope.block, reference.identifier, cloneReplacement(replacements.get(reference.identifier)));
|
|
165
460
|
});
|
|
166
461
|
}
|
|
167
462
|
});
|
|
168
463
|
});
|
|
464
|
+
|
|
465
|
+
rewriteLocalReferencesByName();
|
|
169
466
|
|
|
170
467
|
traverser.traverse(scope.block, [], (node, stack) => {
|
|
171
468
|
if (scope.block == node) {
|
|
172
469
|
return node;
|
|
173
470
|
}
|
|
174
471
|
|
|
175
|
-
if (isClassMethodFunction(stack)) {
|
|
472
|
+
if (isClassMethodFunction(stack) || isNumericVmInternalFunction(stack)) {
|
|
176
473
|
return node;
|
|
177
474
|
}
|
|
178
475
|
|
|
@@ -186,7 +483,7 @@ module.exports = class Scopes {
|
|
|
186
483
|
if (node.type == "FunctionExpression") {
|
|
187
484
|
return {
|
|
188
485
|
type: "CallExpression",
|
|
189
|
-
callee: { type: "Identifier", name: "
|
|
486
|
+
callee: { type: "Identifier", name: "toildefender$bind" },
|
|
190
487
|
arguments: [
|
|
191
488
|
node,
|
|
192
489
|
{ type: "Identifier", name: scopeVarName }
|
|
@@ -197,6 +494,25 @@ module.exports = class Scopes {
|
|
|
197
494
|
return node;
|
|
198
495
|
});
|
|
199
496
|
});
|
|
497
|
+
|
|
498
|
+
this.esutils.setParentsRecursive(ast);
|
|
499
|
+
traverser.traverse(ast, [], (node, stack) => {
|
|
500
|
+
var parentFrame = stack[1];
|
|
501
|
+
if (
|
|
502
|
+
node.type == "Identifier" &&
|
|
503
|
+
node.name.indexOf("$$var$") == 0 &&
|
|
504
|
+
parentFrame &&
|
|
505
|
+
parentFrame.node.type == "CallExpression" &&
|
|
506
|
+
parentFrame.key == "callee" &&
|
|
507
|
+
isReferenceIdentifier(node, stack)
|
|
508
|
+
) {
|
|
509
|
+
var replacement = fallbackReplacementForName(node.name, node);
|
|
510
|
+
if (replacement) {
|
|
511
|
+
return cloneReplacement(replacement);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return node;
|
|
515
|
+
});
|
|
200
516
|
}
|
|
201
517
|
|
|
202
518
|
};
|
package/processors/uglifier.js
CHANGED
|
@@ -81,10 +81,29 @@ function shortName(index) {
|
|
|
81
81
|
return name;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
function
|
|
84
|
+
function collectUnresolvedNames(scopeManager) {
|
|
85
|
+
var names = new Set();
|
|
86
|
+
scopeManager.scopes.forEach(scope => {
|
|
87
|
+
scope.through.forEach(reference => {
|
|
88
|
+
if (!reference.resolved) {
|
|
89
|
+
names.add(reference.identifier.name);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
return names;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function isRenamableVariable(scope, variable, unresolvedNames) {
|
|
85
97
|
if (scope.type == "global") {
|
|
86
98
|
return false;
|
|
87
99
|
}
|
|
100
|
+
if (
|
|
101
|
+
typeof variable.name == "string"
|
|
102
|
+
&& variable.name.indexOf("toildefender$anon$") === 0
|
|
103
|
+
&& unresolvedNames.has(variable.name)
|
|
104
|
+
) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
88
107
|
if (variable.name == "arguments" || variable.name == "undefined") {
|
|
89
108
|
return false;
|
|
90
109
|
}
|
|
@@ -161,10 +180,11 @@ function modernMangle(ast) {
|
|
|
161
180
|
sourceType: "script"
|
|
162
181
|
});
|
|
163
182
|
|
|
183
|
+
var unresolvedNames = collectUnresolvedNames(scopeManager);
|
|
164
184
|
var variables = [];
|
|
165
185
|
scopeManager.scopes.forEach(scope => {
|
|
166
186
|
scope.variables.forEach(variable => {
|
|
167
|
-
if (isRenamableVariable(scope, variable)) {
|
|
187
|
+
if (isRenamableVariable(scope, variable, unresolvedNames)) {
|
|
168
188
|
variables.push({ scope: scope, variable: variable });
|
|
169
189
|
}
|
|
170
190
|
});
|