@dacely/toildefender 0.1.5 → 0.1.6
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/package.json +1 -1
- package/processors/normalizer.js +31 -4
- package/processors/uglifier.js +199 -2
package/package.json
CHANGED
package/processors/normalizer.js
CHANGED
|
@@ -46,8 +46,10 @@ function blockToArray (node) {
|
|
|
46
46
|
|
|
47
47
|
if (Array.isArray(node.body)) {
|
|
48
48
|
return node.body;
|
|
49
|
-
} else {
|
|
49
|
+
} else if (node.body) {
|
|
50
50
|
return [ node.body ];
|
|
51
|
+
} else {
|
|
52
|
+
return [ node ];
|
|
51
53
|
}
|
|
52
54
|
}
|
|
53
55
|
|
|
@@ -376,6 +378,28 @@ function containsThisExpression(node) {
|
|
|
376
378
|
return found;
|
|
377
379
|
}
|
|
378
380
|
|
|
381
|
+
function blockNeedsLexicalScope(node) {
|
|
382
|
+
if (node.type != "BlockStatement") {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
var needsScope = false;
|
|
387
|
+
traverser.traverseEx(node, [], function (child) {
|
|
388
|
+
if (child != node && estest.isFunction(child)) {
|
|
389
|
+
return child;
|
|
390
|
+
}
|
|
391
|
+
if (
|
|
392
|
+
(child.type == "VariableDeclaration" && child.kind != "var")
|
|
393
|
+
|| child.type == "ClassDeclaration"
|
|
394
|
+
) {
|
|
395
|
+
needsScope = true;
|
|
396
|
+
this.abort();
|
|
397
|
+
}
|
|
398
|
+
return child;
|
|
399
|
+
});
|
|
400
|
+
return needsScope;
|
|
401
|
+
}
|
|
402
|
+
|
|
379
403
|
module.exports = class Normalizer {
|
|
380
404
|
|
|
381
405
|
constructor (logger) {
|
|
@@ -439,10 +463,13 @@ module.exports = class Normalizer {
|
|
|
439
463
|
simplifyBlockStatement (node) {
|
|
440
464
|
assert.ok(estest.isNode(node));
|
|
441
465
|
|
|
442
|
-
function getBlockBodys(node) {
|
|
466
|
+
function getBlockBodys(node, isRoot) {
|
|
443
467
|
if (node.type == "Program" || node.type == "BlockStatement") {
|
|
468
|
+
if (!isRoot && blockNeedsLexicalScope(node)) {
|
|
469
|
+
return [ node ];
|
|
470
|
+
}
|
|
444
471
|
var stmts = [];
|
|
445
|
-
node.body.forEach(stmt => utils.push(stmts, getBlockBodys(stmt)));
|
|
472
|
+
node.body.forEach(stmt => utils.push(stmts, getBlockBodys(stmt, false)));
|
|
446
473
|
return stmts;
|
|
447
474
|
} else {
|
|
448
475
|
return [ node ];
|
|
@@ -451,7 +478,7 @@ module.exports = class Normalizer {
|
|
|
451
478
|
|
|
452
479
|
return {
|
|
453
480
|
type: node.type,
|
|
454
|
-
body: getBlockBodys(node)
|
|
481
|
+
body: getBlockBodys(node, true)
|
|
455
482
|
};
|
|
456
483
|
}
|
|
457
484
|
|
package/processors/uglifier.js
CHANGED
|
@@ -3,8 +3,202 @@
|
|
|
3
3
|
var assert = require("assert");
|
|
4
4
|
|
|
5
5
|
var esshorten = require("esshorten");
|
|
6
|
+
var escope = require("escope");
|
|
6
7
|
|
|
7
8
|
var estest = require("../estest");
|
|
9
|
+
var traverser = require("../traverser");
|
|
10
|
+
|
|
11
|
+
var RESERVED_WORDS = new Set([
|
|
12
|
+
"await",
|
|
13
|
+
"break",
|
|
14
|
+
"case",
|
|
15
|
+
"catch",
|
|
16
|
+
"class",
|
|
17
|
+
"const",
|
|
18
|
+
"continue",
|
|
19
|
+
"debugger",
|
|
20
|
+
"default",
|
|
21
|
+
"delete",
|
|
22
|
+
"do",
|
|
23
|
+
"else",
|
|
24
|
+
"enum",
|
|
25
|
+
"export",
|
|
26
|
+
"extends",
|
|
27
|
+
"false",
|
|
28
|
+
"finally",
|
|
29
|
+
"for",
|
|
30
|
+
"function",
|
|
31
|
+
"if",
|
|
32
|
+
"import",
|
|
33
|
+
"in",
|
|
34
|
+
"instanceof",
|
|
35
|
+
"new",
|
|
36
|
+
"null",
|
|
37
|
+
"return",
|
|
38
|
+
"super",
|
|
39
|
+
"switch",
|
|
40
|
+
"this",
|
|
41
|
+
"throw",
|
|
42
|
+
"true",
|
|
43
|
+
"try",
|
|
44
|
+
"typeof",
|
|
45
|
+
"var",
|
|
46
|
+
"void",
|
|
47
|
+
"while",
|
|
48
|
+
"with",
|
|
49
|
+
"yield",
|
|
50
|
+
"arguments",
|
|
51
|
+
"undefined"
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
var FIRST_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
|
|
55
|
+
var REST_CHARS = FIRST_CHARS + "0123456789";
|
|
56
|
+
|
|
57
|
+
function containsModernBindings(ast) {
|
|
58
|
+
var found = false;
|
|
59
|
+
traverser.traverseEx(ast, [], function (node) {
|
|
60
|
+
if (
|
|
61
|
+
(node.type == "VariableDeclaration" && node.kind != "var")
|
|
62
|
+
|| node.type == "ClassDeclaration"
|
|
63
|
+
|| node.type == "ClassExpression"
|
|
64
|
+
) {
|
|
65
|
+
found = true;
|
|
66
|
+
this.abort();
|
|
67
|
+
}
|
|
68
|
+
return node;
|
|
69
|
+
});
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function shortName(index) {
|
|
74
|
+
var name = FIRST_CHARS[index % FIRST_CHARS.length];
|
|
75
|
+
index = Math.floor(index / FIRST_CHARS.length);
|
|
76
|
+
while (index > 0) {
|
|
77
|
+
index -= 1;
|
|
78
|
+
name += REST_CHARS[index % REST_CHARS.length];
|
|
79
|
+
index = Math.floor(index / REST_CHARS.length);
|
|
80
|
+
}
|
|
81
|
+
return name;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function isRenamableVariable(scope, variable) {
|
|
85
|
+
if (scope.type == "global") {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
if (variable.name == "arguments" || variable.name == "undefined") {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
if (variable.tainted) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
if (!variable.identifiers || variable.identifiers.length == 0) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (variable.defs && variable.defs.some(def => def.type == "ClassName")) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function reserveUnrenamedNames(scopeManager, renamable) {
|
|
104
|
+
var reserved = new Set(RESERVED_WORDS);
|
|
105
|
+
scopeManager.scopes.forEach(scope => {
|
|
106
|
+
scope.variables.forEach(variable => {
|
|
107
|
+
if (!renamable.has(variable)) {
|
|
108
|
+
reserved.add(variable.name);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
scope.through.forEach(reference => {
|
|
112
|
+
if (!reference.resolved) {
|
|
113
|
+
reserved.add(reference.identifier.name);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
return reserved;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function buildParentMap(ast) {
|
|
121
|
+
var parents = new WeakMap();
|
|
122
|
+
traverser.traverse(ast, [], function (node, stack) {
|
|
123
|
+
var parentFrame = stack[1];
|
|
124
|
+
if (parentFrame) {
|
|
125
|
+
parents.set(node, parentFrame.node);
|
|
126
|
+
}
|
|
127
|
+
return node;
|
|
128
|
+
});
|
|
129
|
+
return parents;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function renameIdentifier(identifier, name, parents) {
|
|
133
|
+
var parent = parents.get(identifier);
|
|
134
|
+
if (
|
|
135
|
+
parent
|
|
136
|
+
&& parent.type == "Property"
|
|
137
|
+
&& parent.shorthand === true
|
|
138
|
+
&& (parent.key === identifier || parent.value === identifier)
|
|
139
|
+
) {
|
|
140
|
+
parent.shorthand = false;
|
|
141
|
+
parent.key = {
|
|
142
|
+
type: "Identifier",
|
|
143
|
+
name: identifier.name
|
|
144
|
+
};
|
|
145
|
+
parent.value = {
|
|
146
|
+
type: "Identifier",
|
|
147
|
+
name: name
|
|
148
|
+
};
|
|
149
|
+
parents.set(parent.key, parent);
|
|
150
|
+
parents.set(parent.value, parent);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
identifier.name = name;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function modernMangle(ast) {
|
|
158
|
+
var scopeManager = escope.analyze(ast, {
|
|
159
|
+
ecmaVersion: 6,
|
|
160
|
+
optimistic: true,
|
|
161
|
+
sourceType: "script"
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
var variables = [];
|
|
165
|
+
scopeManager.scopes.forEach(scope => {
|
|
166
|
+
scope.variables.forEach(variable => {
|
|
167
|
+
if (isRenamableVariable(scope, variable)) {
|
|
168
|
+
variables.push({ scope: scope, variable: variable });
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
variables.sort((left, right) => {
|
|
174
|
+
var leftWeight = left.variable.references.length + left.variable.identifiers.length;
|
|
175
|
+
var rightWeight = right.variable.references.length + right.variable.identifiers.length;
|
|
176
|
+
return rightWeight - leftWeight;
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
var renamable = new Set(variables.map(entry => entry.variable));
|
|
180
|
+
var used = reserveUnrenamedNames(scopeManager, renamable);
|
|
181
|
+
var parents = buildParentMap(ast);
|
|
182
|
+
var next = 0;
|
|
183
|
+
|
|
184
|
+
variables.forEach(entry => {
|
|
185
|
+
var name;
|
|
186
|
+
do {
|
|
187
|
+
name = shortName(next);
|
|
188
|
+
next += 1;
|
|
189
|
+
} while (used.has(name) || RESERVED_WORDS.has(name));
|
|
190
|
+
used.add(name);
|
|
191
|
+
|
|
192
|
+
entry.variable.identifiers.forEach(identifier => {
|
|
193
|
+
renameIdentifier(identifier, name, parents);
|
|
194
|
+
});
|
|
195
|
+
entry.variable.references.forEach(reference => {
|
|
196
|
+
renameIdentifier(reference.identifier, name, parents);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return ast;
|
|
201
|
+
}
|
|
8
202
|
|
|
9
203
|
module.exports = class Uglifier {
|
|
10
204
|
|
|
@@ -19,8 +213,11 @@ module.exports = class Uglifier {
|
|
|
19
213
|
*/
|
|
20
214
|
uglify (ast) {
|
|
21
215
|
assert.ok(estest.isNode(ast));
|
|
22
|
-
|
|
216
|
+
|
|
217
|
+
if (containsModernBindings(ast)) {
|
|
218
|
+
return modernMangle(ast);
|
|
219
|
+
}
|
|
23
220
|
return esshorten.mangle(ast);
|
|
24
221
|
}
|
|
25
222
|
|
|
26
|
-
};
|
|
223
|
+
};
|