Skip to content

Commit 13062a4

Browse files
committed
implement group_voids
fixes mishoo#2585
1 parent 604caa0 commit 13062a4

File tree

3 files changed

+266
-4
lines changed

3 files changed

+266
-4
lines changed

lib/minify.js

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ function minify(files, options) {
7575
options.mangle = defaults(options.mangle, {
7676
cache: options.nameCache && (options.nameCache.vars || {}),
7777
eval: false,
78+
group_voids: false,
7879
ie8: false,
7980
keep_fnames: false,
8081
properties: false,

lib/scope.js

+67-4
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ AST_Symbol.DEFMETHOD("global", function(){
400400
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
401401
options = defaults(options, {
402402
eval : false,
403+
group_voids : false,
403404
ie8 : false,
404405
keep_fnames : false,
405406
reserved : [],
@@ -457,18 +458,30 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
457458
this.walk(tw);
458459
to_mangle.forEach(function(def){ def.mangle(options) });
459460

461+
if (options.group_voids) {
462+
base54.reset();
463+
base54.sort();
464+
if (options.toplevel) this.group_voids(options);
465+
else this.walk(new TreeWalker(function(node) {
466+
if (node instanceof AST_Scope && !(node instanceof AST_Toplevel)) {
467+
node.group_voids(options);
468+
return true;
469+
}
470+
}));
471+
}
472+
460473
function collect(symbol) {
461474
if (!member(symbol.name, options.reserved)) {
462475
to_mangle.push(symbol);
463476
}
464477
}
465478
});
466479

467-
AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
480+
AST_Scope.DEFMETHOD("find_colliding_names", function(options, all) {
468481
var cache = options.cache && options.cache.props;
469482
var avoid = Object.create(null);
470483
options.reserved.forEach(to_avoid);
471-
this.globals.each(add_def);
484+
if (this.globals) this.globals.each(add_def);
472485
this.walk(new TreeWalker(function(node) {
473486
if (node instanceof AST_Scope) node.variables.each(add_def);
474487
if (node instanceof AST_SymbolCatch) add_def(node.definition());
@@ -480,9 +493,9 @@ AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
480493
}
481494

482495
function add_def(def) {
483-
var name = def.name;
496+
var name = def.mangled_name || def.name;
484497
if (def.global && cache && cache.has(name)) name = cache.get(name);
485-
else if (!def.unmangleable(options)) return;
498+
else if (!all && !def.unmangleable(options)) return;
486499
to_avoid(name);
487500
}
488501
});
@@ -522,6 +535,56 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
522535
}
523536
});
524537

538+
AST_Scope.DEFMETHOD("group_voids", function(options) {
539+
var avoid = this.find_colliding_names(options, true);
540+
var cname = 0;
541+
var name;
542+
do {
543+
name = base54(cname++);
544+
} while (avoid[name] || !is_identifier(name));
545+
var count = 0;
546+
this.transform(new TreeTransformer(function(node) {
547+
if (node instanceof AST_Undefined
548+
|| node instanceof AST_UnaryPrefix
549+
&& node.operator == "void"
550+
&& node.expression.is_constant()) {
551+
count++;
552+
return new AST_SymbolRef({
553+
name: name,
554+
start: node.start,
555+
end: node.end
556+
});
557+
}
558+
}));
559+
if (count) {
560+
for (var i = 0, len = this.body.length; i < len; i++) {
561+
var stat = this.body[i];
562+
if (stat instanceof AST_Var) {
563+
stat.definitions.push(make_var_def(stat));
564+
return;
565+
}
566+
}
567+
this.body.push(new AST_Var({
568+
definitions: [ make_var_def(this) ],
569+
start: this.start,
570+
end: this.end
571+
}));
572+
}
573+
574+
function make_var_def(node) {
575+
return new AST_VarDef({
576+
name: new AST_SymbolVar({
577+
name: name,
578+
start: node.start,
579+
end: node.end
580+
}),
581+
value: null,
582+
start: node.start,
583+
end: node.end
584+
});
585+
}
586+
});
587+
525588
AST_Node.DEFMETHOD("tail_node", return_this);
526589
AST_Sequence.DEFMETHOD("tail_node", function() {
527590
return this.expressions[this.expressions.length - 1];

test/compress/group_voids.js

+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
group_voids: {
2+
options = {
3+
}
4+
mangle = {
5+
group_voids: true,
6+
toplevel: false,
7+
}
8+
input: {
9+
var a = 0;
10+
x = void 0;
11+
if (void 0 === b)
12+
c = void 0;
13+
function f1() {
14+
var a = 1;
15+
console.log(void 0);
16+
}
17+
function f2(undefined) {
18+
var a = 2;
19+
console.log(void 0);
20+
}
21+
function f3() {
22+
var undefined = 3;
23+
console.log(void 0);
24+
}
25+
function f4() {
26+
console.log(void 0);
27+
for (var a = 4;;);
28+
var b = 4;
29+
function f5() {
30+
var c = 5;
31+
var d = 5;
32+
console.log(void 0);
33+
}
34+
}
35+
function f6() {
36+
try {
37+
var a = 6;
38+
console.log(void 0);
39+
} catch (e) {
40+
console.log(void 0);
41+
}
42+
}
43+
}
44+
expect: {
45+
var a = 0;
46+
x = void 0;
47+
if (void 0 === b)
48+
c = void 0;
49+
function f1() {
50+
var o = 1, a;
51+
console.log(a);
52+
}
53+
function f2(o) {
54+
var n = 2, a;
55+
console.log(a);
56+
}
57+
function f3() {
58+
var o = 3, a;
59+
console.log(a);
60+
}
61+
function f4() {
62+
console.log(a);
63+
for(var o = 4;;);
64+
var n = 4, a;
65+
function v() {
66+
var o = 5;
67+
var n = 5;
68+
console.log(a);
69+
}
70+
}
71+
function f6() {
72+
try {
73+
var o = 6;
74+
console.log(a);
75+
} catch (o) {
76+
console.log(a);
77+
}
78+
var a;
79+
}
80+
}
81+
}
82+
83+
group_voids_toplevel: {
84+
options = {
85+
}
86+
mangle = {
87+
group_voids: true,
88+
toplevel: true,
89+
}
90+
input: {
91+
var a = 0;
92+
x = void 0;
93+
if (void 0 === b)
94+
c = void 0;
95+
function f1() {
96+
var a = 1;
97+
console.log(void 0);
98+
}
99+
function f2(undefined) {
100+
var a = 2;
101+
console.log(void 0);
102+
}
103+
function f3() {
104+
var undefined = 3;
105+
console.log(void 0);
106+
}
107+
function f4() {
108+
console.log(void 0);
109+
for (var a = 4;;);
110+
var b = 4;
111+
function f5() {
112+
var c = 5;
113+
var d = 5;
114+
console.log(void 0);
115+
}
116+
}
117+
function f6() {
118+
try {
119+
var a = 6;
120+
console.log(void 0);
121+
} catch (e) {
122+
console.log(void 0);
123+
}
124+
}
125+
}
126+
expect: {
127+
var o = 0, a;
128+
x = a;
129+
if (a === b)
130+
c = a;
131+
function n() {
132+
var o = 1;
133+
console.log(a);
134+
}
135+
function v(o) {
136+
var n = 2;
137+
console.log(a);
138+
}
139+
function i() {
140+
var o = 3;
141+
console.log(a);
142+
}
143+
function l() {
144+
console.log(a);
145+
for(var o = 4;;);
146+
var n = 4;
147+
function v() {
148+
var o = 5;
149+
var n = 5;
150+
console.log(a);
151+
}
152+
}
153+
function r() {
154+
try {
155+
var o = 6;
156+
console.log(a);
157+
} catch (o) {
158+
console.log(a);
159+
}
160+
}
161+
}
162+
}
163+
164+
group_voids_catch: {
165+
options = {
166+
}
167+
mangle = {
168+
group_voids: true,
169+
}
170+
input: {
171+
f();
172+
function f() {
173+
var a = 1;
174+
console.log(void 0);
175+
try {
176+
throw "FAIL";
177+
} catch (undefined) {
178+
console.log(void 0);
179+
}
180+
}
181+
}
182+
expect: {
183+
f();
184+
function f() {
185+
var o = 1, a;
186+
console.log(a);
187+
try {
188+
throw "FAIL";
189+
} catch (o) {
190+
console.log(a);
191+
}
192+
}
193+
}
194+
expect_stdout: [
195+
"undefined",
196+
"undefined",
197+
]
198+
}

0 commit comments

Comments
 (0)