Skip to content

Commit

Permalink
implement group_voids
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlamsl committed Feb 22, 2018
1 parent 604caa0 commit 13062a4
Show file tree
Hide file tree
Showing 3 changed files with 266 additions and 4 deletions.
1 change: 1 addition & 0 deletions lib/minify.js
Expand Up @@ -75,6 +75,7 @@ function minify(files, options) {
options.mangle = defaults(options.mangle, {
cache: options.nameCache && (options.nameCache.vars || {}),
eval: false,
group_voids: false,
ie8: false,
keep_fnames: false,
properties: false,
Expand Down
71 changes: 67 additions & 4 deletions lib/scope.js
Expand Up @@ -400,6 +400,7 @@ AST_Symbol.DEFMETHOD("global", function(){
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
options = defaults(options, {
eval : false,
group_voids : false,
ie8 : false,
keep_fnames : false,
reserved : [],
Expand Down Expand Up @@ -457,18 +458,30 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
this.walk(tw);
to_mangle.forEach(function(def){ def.mangle(options) });

if (options.group_voids) {
base54.reset();
base54.sort();
if (options.toplevel) this.group_voids(options);
else this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope && !(node instanceof AST_Toplevel)) {
node.group_voids(options);
return true;
}
}));
}

function collect(symbol) {
if (!member(symbol.name, options.reserved)) {
to_mangle.push(symbol);
}
}
});

AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
AST_Scope.DEFMETHOD("find_colliding_names", function(options, all) {
var cache = options.cache && options.cache.props;
var avoid = Object.create(null);
options.reserved.forEach(to_avoid);
this.globals.each(add_def);
if (this.globals) this.globals.each(add_def);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(add_def);
if (node instanceof AST_SymbolCatch) add_def(node.definition());
Expand All @@ -480,9 +493,9 @@ AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
}

function add_def(def) {
var name = def.name;
var name = def.mangled_name || def.name;
if (def.global && cache && cache.has(name)) name = cache.get(name);
else if (!def.unmangleable(options)) return;
else if (!all && !def.unmangleable(options)) return;
to_avoid(name);
}
});
Expand Down Expand Up @@ -522,6 +535,56 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
}
});

AST_Scope.DEFMETHOD("group_voids", function(options) {
var avoid = this.find_colliding_names(options, true);
var cname = 0;
var name;
do {
name = base54(cname++);
} while (avoid[name] || !is_identifier(name));
var count = 0;
this.transform(new TreeTransformer(function(node) {
if (node instanceof AST_Undefined
|| node instanceof AST_UnaryPrefix
&& node.operator == "void"
&& node.expression.is_constant()) {
count++;
return new AST_SymbolRef({
name: name,
start: node.start,
end: node.end
});
}
}));
if (count) {
for (var i = 0, len = this.body.length; i < len; i++) {
var stat = this.body[i];
if (stat instanceof AST_Var) {
stat.definitions.push(make_var_def(stat));
return;
}
}
this.body.push(new AST_Var({
definitions: [ make_var_def(this) ],
start: this.start,
end: this.end
}));
}

function make_var_def(node) {
return new AST_VarDef({
name: new AST_SymbolVar({
name: name,
start: node.start,
end: node.end
}),
value: null,
start: node.start,
end: node.end
});
}
});

AST_Node.DEFMETHOD("tail_node", return_this);
AST_Sequence.DEFMETHOD("tail_node", function() {
return this.expressions[this.expressions.length - 1];
Expand Down
198 changes: 198 additions & 0 deletions test/compress/group_voids.js
@@ -0,0 +1,198 @@
group_voids: {
options = {
}
mangle = {
group_voids: true,
toplevel: false,
}
input: {
var a = 0;
x = void 0;
if (void 0 === b)
c = void 0;
function f1() {
var a = 1;
console.log(void 0);
}
function f2(undefined) {
var a = 2;
console.log(void 0);
}
function f3() {
var undefined = 3;
console.log(void 0);
}
function f4() {
console.log(void 0);
for (var a = 4;;);
var b = 4;
function f5() {
var c = 5;
var d = 5;
console.log(void 0);
}
}
function f6() {
try {
var a = 6;
console.log(void 0);
} catch (e) {
console.log(void 0);
}
}
}
expect: {
var a = 0;
x = void 0;
if (void 0 === b)
c = void 0;
function f1() {
var o = 1, a;
console.log(a);
}
function f2(o) {
var n = 2, a;
console.log(a);
}
function f3() {
var o = 3, a;
console.log(a);
}
function f4() {
console.log(a);
for(var o = 4;;);
var n = 4, a;
function v() {
var o = 5;
var n = 5;
console.log(a);
}
}
function f6() {
try {
var o = 6;
console.log(a);
} catch (o) {
console.log(a);
}
var a;
}
}
}

group_voids_toplevel: {
options = {
}
mangle = {
group_voids: true,
toplevel: true,
}
input: {
var a = 0;
x = void 0;
if (void 0 === b)
c = void 0;
function f1() {
var a = 1;
console.log(void 0);
}
function f2(undefined) {
var a = 2;
console.log(void 0);
}
function f3() {
var undefined = 3;
console.log(void 0);
}
function f4() {
console.log(void 0);
for (var a = 4;;);
var b = 4;
function f5() {
var c = 5;
var d = 5;
console.log(void 0);
}
}
function f6() {
try {
var a = 6;
console.log(void 0);
} catch (e) {
console.log(void 0);
}
}
}
expect: {
var o = 0, a;
x = a;
if (a === b)
c = a;
function n() {
var o = 1;
console.log(a);
}
function v(o) {
var n = 2;
console.log(a);
}
function i() {
var o = 3;
console.log(a);
}
function l() {
console.log(a);
for(var o = 4;;);
var n = 4;
function v() {
var o = 5;
var n = 5;
console.log(a);
}
}
function r() {
try {
var o = 6;
console.log(a);
} catch (o) {
console.log(a);
}
}
}
}

group_voids_catch: {
options = {
}
mangle = {
group_voids: true,
}
input: {
f();
function f() {
var a = 1;
console.log(void 0);
try {
throw "FAIL";
} catch (undefined) {
console.log(void 0);
}
}
}
expect: {
f();
function f() {
var o = 1, a;
console.log(a);
try {
throw "FAIL";
} catch (o) {
console.log(a);
}
}
}
expect_stdout: [
"undefined",
"undefined",
]
}

0 comments on commit 13062a4

Please sign in to comment.