diff --git a/lib/ast.js b/lib/ast.js index cd32ead7..2f598956 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -91,9 +91,20 @@ var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos }, null); var AST_Node = DEFNODE("Node", "start end", { - clone: function() { + _clone: function(deep) { + if (deep) { + var self = this.clone(); + return self.transform(new TreeTransformer(function(node) { + if (node !== self) { + return node.clone(true); + } + })); + } return new this.CTOR(this); }, + clone: function(deep) { + return this._clone(deep); + }, $documentation: "Base class of all AST nodes", $propdoc: { start: "[AST_Token] The first token of this node", @@ -199,6 +210,20 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", { this.label._walk(visitor); this.body._walk(visitor); }); + }, + clone: function(deep) { + var node = this._clone(deep); + if (deep) { + var refs = node.label.references; + var label = this.label; + node.walk(new TreeWalker(function(node) { + if (node instanceof AST_LoopControl + && node.label && node.label.thedef === label) { + refs.push(node); + } + })); + } + return node; } }, AST_StatementWithBody); diff --git a/lib/compress.js b/lib/compress.js index 11a1ff1c..1d1e9020 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -224,6 +224,7 @@ merge(Compressor.prototype, { AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan){ var reduce_vars = rescan && compressor.option("reduce_vars"); + var toplevel = compressor.option("toplevel"); var ie8 = !compressor.option("screw_ie8"); var safe_ids = []; push(); @@ -245,7 +246,8 @@ merge(Compressor.prototype, { if (node instanceof AST_SymbolRef) { var d = node.definition(); d.references.push(node); - if (!d.fixed || isModified(node, 0) || !is_safe(d)) { + if (!d.fixed || !is_safe(d) + || is_modified(node, 0, d.fixed instanceof AST_Lambda)) { d.fixed = false; } } @@ -265,6 +267,21 @@ merge(Compressor.prototype, { } } } + if (node instanceof AST_Defun) { + var d = node.name.definition(); + if (!toplevel && d.global || is_safe(d)) { + d.fixed = false; + } else { + d.fixed = node; + mark_as_safe(d); + } + var save_ids = safe_ids; + safe_ids = []; + push(); + descend(); + safe_ids = save_ids; + return true; + } var iife; if (node instanceof AST_Function && (iife = tw.parent()) instanceof AST_Call @@ -339,18 +356,22 @@ merge(Compressor.prototype, { } function reset_def(def) { - def.fixed = undefined; + if (toplevel || !def.global || def.orig[0] instanceof AST_SymbolConst) { + def.fixed = undefined; + } else { + def.fixed = false; + } def.references = []; def.should_replace = undefined; } - function isModified(node, level) { + function is_modified(node, level, func) { var parent = tw.parent(level); if (isLHS(node, parent) - || parent instanceof AST_Call && parent.expression === node) { + || !func && parent instanceof AST_Call && parent.expression === node) { return true; } else if (parent instanceof AST_PropAccess && parent.expression === node) { - return isModified(parent, level + 1); + return !func && is_modified(parent, level + 1); } } }); @@ -548,11 +569,14 @@ merge(Compressor.prototype, { // Constant single use vars can be replaced in any scope. if (var_decl.value.is_constant()) { var ctt = new TreeTransformer(function(node) { - if (node === ref - && !ctt.find_parent(AST_Destructuring) - && !ctt.find_parent(AST_ForIn)) { - return replace_var(node, ctt.parent(), true); + if (node instanceof AST_Destructuring) return node; + var parent = ctt.parent(); + if (parent instanceof AST_IterationStatement + && (parent.condition === node || parent.init === node)) { + return node; } + if (node === ref) + return replace_var(node, parent, true); }); stat.transform(ctt); continue; @@ -1325,14 +1349,7 @@ merge(Compressor.prototype, { def(AST_Statement, function(){ throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start)); }); - // XXX: AST_Accessor and AST_Function both inherit from AST_Scope, - // which itself inherits from AST_Statement; however, they aren't - // really statements. This could bite in other places too. :-( - // Wish JS had multiple inheritance. - def(AST_Accessor, function(){ - throw def; - }); - def(AST_Function, function(){ + def(AST_Lambda, function(){ throw def; }); def(AST_Arrow, function() { @@ -2714,6 +2731,24 @@ merge(Compressor.prototype, { OPT(AST_Call, function(self, compressor){ var exp = self.expression; + if (compressor.option("reduce_vars") + && exp instanceof AST_SymbolRef) { + var def = exp.definition(); + if (def.fixed instanceof AST_Defun) { + def.fixed = make_node(AST_Function, def.fixed, def.fixed).clone(true); + } + if (def.fixed instanceof AST_Function) { + exp = def.fixed; + if (compressor.option("unused") + && def.references.length == 1 + && compressor.find_parent(AST_Scope) === def.scope) { + if (!compressor.option("keep_fnames")) { + exp.name = null; + } + self.expression = exp; + } + } + } if (compressor.option("unused") && exp instanceof AST_Function && !exp.uses_arguments diff --git a/lib/output.js b/lib/output.js index cb2b62bb..7c4cc7ab 100644 --- a/lib/output.js +++ b/lib/output.js @@ -889,7 +889,9 @@ function OutputStream(options) { output.with_parens(function(){ self.condition.print(output); }); - output.semicolon(); + if (output.option("beautify") && output.option("screw_ie8")) { + output.semicolon(); + } }); DEFPRINT(AST_While, function(self, output){ output.print("while"); @@ -1096,15 +1098,6 @@ function OutputStream(options) { // adds the block brackets if needed. if (!self.body) return output.force_semicolon(); - if (self.body instanceof AST_Do) { - // Unconditionally use the if/do-while workaround for all browsers. - // https://github.com/mishoo/UglifyJS/issues/#issue/57 IE - // croaks with "syntax error" on code like this: if (foo) - // do ... while(cond); else ... we need block brackets - // around do/while - make_block(self.body, output); - return; - } var b = self.body; while (true) { if (b instanceof AST_If) { diff --git a/package.json b/package.json index 31aaf951..086b6910 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "homepage": "http://lisperator.net/uglifyjs", "author": "Mihai Bazon (http://lisperator.net/)", "license": "BSD-2-Clause", - "version": "2.8.7", + "version": "2.8.8", "engines": { "node": ">=0.8.0" }, diff --git a/test/benchmark.js b/test/benchmark.js index dc176a88..c150e5cf 100644 --- a/test/benchmark.js +++ b/test/benchmark.js @@ -24,26 +24,57 @@ var results = {}; var remaining = 2 * urls.length; function done() { if (!--remaining) { + var failures = []; urls.forEach(function(url) { + var info = results[url]; console.log(); console.log(url); - console.log(results[url].time); - console.log("SHA1:", results[url].sha1); + console.log(info.log); + var elapsed = 0; + info.log.replace(/: ([0-9]+\.[0-9]{3})s/g, function(match, time) { + elapsed += parseFloat(time); + }); + console.log("Run-time:", elapsed.toFixed(3), "s"); + console.log("Original:", info.input, "bytes"); + console.log("Uglified:", info.output, "bytes"); + console.log("SHA1 sum:", info.sha1); + if (info.code) { + failures.push(url); + } }); + if (failures.length) { + console.error("Benchmark failed:"); + failures.forEach(function(url) { + console.error(url); + }); + process.exit(1); + } } } urls.forEach(function(url) { - results[url] = { time: "" }; + results[url] = { + input: 0, + output: 0, + log: "" + }; require(url.slice(0, url.indexOf(":"))).get(url, function(res) { var uglifyjs = fork("bin/uglifyjs", args, { silent: true }); - res.pipe(uglifyjs.stdin); - uglifyjs.stdout.pipe(createHash("sha1")).on("data", function(data) { + res.on("data", function(data) { + results[url].input += data.length; + }).pipe(uglifyjs.stdin); + uglifyjs.stdout.on("data", function(data) { + results[url].output += data.length; + }).pipe(createHash("sha1")).on("data", function(data) { results[url].sha1 = data.toString("hex"); done(); }); uglifyjs.stderr.setEncoding("utf8"); uglifyjs.stderr.on("data", function(data) { - results[url].time += data; - }).on("end", done) + results[url].log += data; + }); + uglifyjs.on("exit", function(code) { + results[url].code = code; + done(); + }); }); }); diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 6d9961ff..d526170e 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -344,9 +344,9 @@ collapse_vars_do_while: { } input: { function f1(y) { - // The constant do-while condition `c` will be replaced. + // The constant do-while condition `c` will not be replaced. var c = 9; - do { } while (c === 77); + do {} while (c === 77); } function f2(y) { // The non-constant do-while condition `c` will not be replaced. @@ -381,7 +381,8 @@ collapse_vars_do_while: { } expect: { function f1(y) { - do ; while (false); + var c = 9; + do ; while (77 === c); } function f2(y) { var c = 5 - y; @@ -418,9 +419,9 @@ collapse_vars_do_while_drop_assign: { } input: { function f1(y) { - // The constant do-while condition `c` will be replaced. + // The constant do-while condition `c` will be not replaced. var c = 9; - do { } while (c === 77); + do {} while (c === 77); } function f2(y) { // The non-constant do-while condition `c` will not be replaced. @@ -455,7 +456,8 @@ collapse_vars_do_while_drop_assign: { } expect: { function f1(y) { - do ; while (false); + var c = 9; + do ; while (77 === c); } function f2(y) { var c = 5 - y; @@ -1309,8 +1311,8 @@ collapse_vars_regexp: { }; } (function(){ - var result, rx = /ab*/g; - while (result = rx.exec('acdabcdeabbb')) + var result, s = "acdabcdeabbb", rx = /ab*/g; + while (result = rx.exec(s)) console.log(result[0]); })(); } @@ -1421,3 +1423,35 @@ issue_1537_destructuring_for_of: { })(); } } + +issue_1562: { + options = { + collapse_vars: true, + } + input: { + var v = 1, B = 2; + for (v in objs) f(B); + + var x = 3, C = 10; + while(x + 2) bar(C); + + var y = 4, D = 20; + do bar(D); while(y + 2); + + var z = 5, E = 30; + for (; f(z + 2) ;) bar(E); + } + expect: { + var v = 1; + for (v in objs) f(2); + + var x = 3; + while(x + 2) bar(10); + + var y = 4; + do bar(20); while(y + 2); + + var z = 5; + for (; f(z + 2) ;) bar(30); + } +} diff --git a/test/compress/dead-code.js b/test/compress/dead-code.js index 134212f0..fa52496d 100644 --- a/test/compress/dead-code.js +++ b/test/compress/dead-code.js @@ -145,6 +145,7 @@ dead_code_const_annotation: { conditionals : true, evaluate : true, reduce_vars : true, + toplevel : true, }; input: { var unused; @@ -194,6 +195,7 @@ dead_code_const_annotation_complex_scope: { conditionals : true, evaluate : true, reduce_vars : true, + toplevel : true, }; input: { var unused_var; diff --git a/test/compress/loops.js b/test/compress/loops.js index e26dc79f..2d04e235 100644 --- a/test/compress/loops.js +++ b/test/compress/loops.js @@ -240,3 +240,159 @@ issue_1532: { } } } + +issue_186: { + beautify = { + beautify: false, + screw_ie8: true, + } + input: { + var x = 3; + if (foo()) + do + do + alert(x); + while (--x); + while (x); + else + bar(); + } + expect_exact: 'var x=3;if(foo())do do alert(x);while(--x)while(x)else bar();' +} + +issue_186_ie8: { + beautify = { + beautify: false, + screw_ie8: false, + } + input: { + var x = 3; + if (foo()) + do + do + alert(x); + while (--x); + while (x); + else + bar(); + } + expect_exact: 'var x=3;if(foo())do do alert(x);while(--x)while(x)else bar();' +} + +issue_186_beautify: { + beautify = { + beautify: true, + screw_ie8: true, + } + input: { + var x = 3; + if (foo()) + do + do + alert(x); + while (--x); + while (x); + else + bar(); + } + expect_exact: 'var x = 3;\n\nif (foo()) do do alert(x); while (--x); while (x); else bar();' +} + +issue_186_beautify_ie8: { + beautify = { + beautify: true, + screw_ie8: false, + } + input: { + var x = 3; + if (foo()) + do + do + alert(x); + while (--x); + while (x); + else + bar(); + } + expect_exact: 'var x = 3;\n\nif (foo()) do do alert(x); while (--x) while (x) else bar();' +} + +issue_186_bracketize: { + beautify = { + beautify: false, + bracketize: true, + screw_ie8: true, + } + input: { + var x = 3; + if (foo()) + do + do + alert(x); + while (--x); + while (x); + else + bar(); + } + expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}' +} + +issue_186_bracketize_ie8: { + beautify = { + beautify: false, + bracketize: true, + screw_ie8: false, + } + input: { + var x = 3; + if (foo()) + do + do + alert(x); + while (--x); + while (x); + else + bar(); + } + expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}' +} + +issue_186_beautify_bracketize: { + beautify = { + beautify: true, + bracketize: true, + screw_ie8: true, + } + input: { + var x = 3; + if (foo()) + do + do + alert(x); + while (--x); + while (x); + else + bar(); + } + expect_exact: 'var x = 3;\n\nif (foo()) {\n do {\n do {\n alert(x);\n } while (--x);\n } while (x);\n} else {\n bar();\n}' +} + +issue_186_beautify_bracketize_ie8: { + beautify = { + beautify: true, + bracketize: true, + screw_ie8: false, + } + input: { + var x = 3; + if (foo()) + do + do + alert(x); + while (--x); + while (x); + else + bar(); + } + expect_exact: 'var x = 3;\n\nif (foo()) {\n do {\n do {\n alert(x);\n } while (--x)\n } while (x)\n} else {\n bar();\n}' +} diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 70e915d3..53e28152 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -6,6 +6,7 @@ reduce_vars: { C : 0 }, reduce_vars : true, + toplevel : true, unused : true } input: { @@ -452,22 +453,26 @@ multi_def_2: { reduce_vars: true, } input: { - if (code == 16) - var bitsLength = 2, bitsOffset = 3, what = len; - else if (code == 17) - var bitsLength = 3, bitsOffset = 3, what = (len = 0); - else if (code == 18) - var bitsLength = 7, bitsOffset = 11, what = (len = 0); - var repeatLength = this.getBits(bitsLength) + bitsOffset; + function f(){ + if (code == 16) + var bitsLength = 2, bitsOffset = 3, what = len; + else if (code == 17) + var bitsLength = 3, bitsOffset = 3, what = (len = 0); + else if (code == 18) + var bitsLength = 7, bitsOffset = 11, what = (len = 0); + var repeatLength = this.getBits(bitsLength) + bitsOffset; + } } expect: { - if (16 == code) - var bitsLength = 2, bitsOffset = 3, what = len; - else if (17 == code) - var bitsLength = 3, bitsOffset = 3, what = (len = 0); - else if (18 == code) - var bitsLength = 7, bitsOffset = 11, what = (len = 0); - var repeatLength = this.getBits(bitsLength) + bitsOffset; + function f(){ + if (16 == code) + var bitsLength = 2, bitsOffset = 3, what = len; + else if (17 == code) + var bitsLength = 3, bitsOffset = 3, what = (len = 0); + else if (18 == code) + var bitsLength = 7, bitsOffset = 11, what = (len = 0); + var repeatLength = this.getBits(bitsLength) + bitsOffset; + } } } @@ -477,12 +482,16 @@ use_before_var: { reduce_vars: true, } input: { - console.log(t); - var t = 1; + function f(){ + console.log(t); + var t = 1; + } } expect: { - console.log(t); - var t = 1; + function f(){ + console.log(t); + var t = 1; + } } } @@ -492,22 +501,20 @@ inner_var_if: { reduce_vars: true, } input: { - function f(){ - return 0; + function f(a){ + if (a) + var t = 1; + if (!t) + console.log(t); } - if (f()) - var t = 1; - if (!t) - console.log(t); } expect: { - function f(){ - return 0; + function f(a){ + if (a) + var t = 1; + if (!t) + console.log(t); } - if (f()) - var t = 1; - if (!t) - console.log(t); } } @@ -517,24 +524,22 @@ inner_var_label: { reduce_vars: true, } input: { - function f(){ - return 1; + function f(a){ + l: { + if (a) break l; + var t = 1; + } + console.log(t); } - l: { - if (f()) break l; - var t = 1; - } - console.log(t); } expect: { - function f(){ - return 1; + function f(a){ + l: { + if (a) break l; + var t = 1; + } + console.log(t); } - l: { - if (f()) break l; - var t = 1; - } - console.log(t); } } @@ -544,22 +549,26 @@ inner_var_for: { reduce_vars: true, } input: { - var a = 1; - x(a, b, d); - for (var b = 2, c = 3; x(a, b, c, d); x(a, b, c, d)) { - var d = 4, e = 5; + function f() { + var a = 1; + x(a, b, d); + for (var b = 2, c = 3; x(a, b, c, d); x(a, b, c, d)) { + var d = 4, e = 5; + x(a, b, c, d, e); + } x(a, b, c, d, e); } - x(a, b, c, d, e) } expect: { - var a = 1; - x(1, b, d); - for (var b = 2, c = 3; x(1, b, 3, d); x(1, b, 3, d)) { - var d = 4, e = 5; + function f() { + var a = 1; + x(1, b, d); + for (var b = 2, c = 3; x(1, b, 3, d); x(1, b, 3, d)) { + var d = 4, e = 5; + x(1, b, 3, d, e); + } x(1, b, 3, d, e); } - x(1, b, 3, d, e); } } @@ -569,24 +578,28 @@ inner_var_for_in_1: { reduce_vars: true, } input: { - var a = 1, b = 2; - for (b in (function() { - return x(a, b, c); - })()) { - var c = 3, d = 4; + function f() { + var a = 1, b = 2; + for (b in (function() { + return x(a, b, c); + })()) { + var c = 3, d = 4; + x(a, b, c, d); + } x(a, b, c, d); } - x(a, b, c, d); } expect: { - var a = 1, b = 2; - for (b in (function() { - return x(1, b, c); - })()) { - var c = 3, d = 4; + function f() { + var a = 1, b = 2; + for (b in (function() { + return x(1, b, c); + })()) { + var c = 3, d = 4; + x(1, b, c, d); + } x(1, b, c, d); } - x(1, b, c, d); } } @@ -596,12 +609,16 @@ inner_var_for_in_2: { reduce_vars: true, } input: { - for (var long_name in {}) - console.log(long_name); + function f() { + for (var long_name in {}) + console.log(long_name); + } } expect: { - for (var long_name in {}) - console.log(long_name); + function f() { + for (var long_name in {}) + console.log(long_name); + } } } @@ -611,20 +628,24 @@ inner_var_catch: { reduce_vars: true, } input: { - try { - a(); - } catch (e) { - var b = 1; + function f() { + try { + a(); + } catch (e) { + var b = 1; + } + console.log(b); } - console.log(b); } expect: { - try { - a(); - } catch (e) { - var b = 1; + function f() { + try { + a(); + } catch (e) { + var b = 1; + } + console.log(b); } - console.log(b); } } @@ -634,14 +655,18 @@ issue_1533_1: { reduce_vars: true, } input: { - var id = ""; - for (id in {break: "me"}) - console.log(id); + function f() { + var id = ""; + for (id in {break: "me"}) + console.log(id); + } } expect: { - var id = ""; - for (id in {break: "me"}) - console.log(id); + function f() { + var id = ""; + for (id in {break: "me"}) + console.log(id); + } } } @@ -651,15 +676,449 @@ issue_1533_2: { reduce_vars: true, } input: { - var id = ""; - for (var id in {break: "me"}) + function f() { + var id = ""; + for (var id in {break: "me"}) + console.log(id); console.log(id); - console.log(id); + } } expect: { - var id = ""; - for (var id in {break: "me"}) + function f() { + var id = ""; + for (var id in {break: "me"}) + console.log(id); console.log(id); - console.log(id); + } + } +} + +toplevel_on: { + options = { + evaluate: true, + reduce_vars: true, + toplevel:true, + unused: true, + } + input: { + var x = 3; + console.log(x); + } + expect: { + console.log(3); + } +} + +toplevel_off: { + options = { + evaluate: true, + reduce_vars: true, + toplevel:false, + unused: true, + } + input: { + var x = 3; + console.log(x); + } + expect: { + var x = 3; + console.log(x); + } +} + +toplevel_on_loops_1: { + options = { + evaluate: true, + loops: true, + reduce_vars: true, + toplevel:true, + unused: true, + } + input: { + function bar() { + console.log("bar:", --x); + } + var x = 3; + do + bar(); + while (x); + } + expect: { + var x = 3; + do + (function() { + console.log("bar:", --x); + })(); + while (x); + } +} + +toplevel_off_loops_1: { + options = { + evaluate: true, + loops: true, + reduce_vars: true, + toplevel:false, + unused: true, + } + input: { + function bar() { + console.log("bar:", --x); + } + var x = 3; + do + bar(); + while (x); + } + expect: { + function bar() { + console.log("bar:", --x); + } + var x = 3; + do + bar(); + while (x); + } +} + +toplevel_on_loops_2: { + options = { + evaluate: true, + loops: true, + reduce_vars: true, + toplevel:true, + unused: true, + } + input: { + function bar() { + console.log("bar:"); + } + var x = 3; + do + bar(); + while (x); + } + expect: { + for (;;) (function() { + console.log("bar:"); + })(); + } +} + +toplevel_off_loops_2: { + options = { + evaluate: true, + loops: true, + reduce_vars: true, + toplevel:false, + unused: true, + } + input: { + function bar() { + console.log("bar:"); + } + var x = 3; + do + bar(); + while (x); + } + expect: { + function bar() { + console.log("bar:"); + } + var x = 3; + do + bar(); + while (x); + } +} + +toplevel_on_loops_3: { + options = { + evaluate: true, + loops: true, + reduce_vars: true, + toplevel:true, + unused: true, + } + input: { + var x = 3; + while (x) bar(); + } + expect: { + for (;;) bar(); + } +} + +toplevel_off_loops_3: { + options = { + evaluate: true, + loops: true, + reduce_vars: true, + toplevel:false, + unused: true, + } + input: { + var x = 3; + while (x) bar(); + } + expect: { + var x = 3; + for (;x;) bar(); + } +} + +defun_reference: { + options = { + evaluate: true, + reduce_vars: true, + } + input: { + function f() { + function g() { + x(); + return a; + } + var a = h(); + var b = 2; + return a + b; + function h() { + y(); + return b; + } + } + } + expect: { + function f() { + function g() { + x(); + return a; + } + var a = h(); + var b = 2; + return a + b; + function h() { + y(); + return b; + } + } + } +} + +defun_inline_1: { + options = { + reduce_vars: true, + unused: true, + } + input: { + function f() { + return g(2) + h(); + function g(b) { + return b; + } + function h() { + return h(); + } + } + } + expect: { + function f() { + return function(b) { + return b; + }(2) + h(); + function h() { + return h(); + } + } + } +} + +defun_inline_2: { + options = { + reduce_vars: true, + unused: true, + } + input: { + function f() { + function g(b) { + return b; + } + function h() { + return h(); + } + return g(2) + h(); + } + } + expect: { + function f() { + function h() { + return h(); + } + return function(b) { + return b; + }(2) + h(); + } + } +} + +defun_inline_3: { + options = { + evaluate: true, + passes: 2, + reduce_vars: true, + side_effects: true, + unused: true, + } + input: { + function f() { + return g(2); + function g(b) { + return b; + } + } + } + expect: { + function f() { + return 2; + } + } +} + +defun_call: { + options = { + reduce_vars: true, + unused: true, + } + input: { + function f() { + return g() + h(1) - h(g(), 2, 3); + function g() { + return 4; + } + function h(a) { + return a; + } + } + } + expect: { + function f() { + return 4 + h(1) - h(4); + function h(a) { + return a; + } + } + } +} + +defun_redefine: { + options = { + reduce_vars: true, + unused: true, + } + input: { + function f() { + function g() { + return 1; + } + function h() { + return 2; + } + g = function() { + return 3; + }; + return g() + h(); + } + } + expect: { + function f() { + function g() { + return 1; + } + g = function() { + return 3; + }; + return g() + 2; + } + } +} + +func_inline: { + options = { + reduce_vars: true, + unused: true, + } + input: { + function f() { + var g = function() { + return 1; + }; + console.log(g() + h()); + var h = function() { + return 2; + }; + } + } + expect: { + function f() { + console.log(1 + h()); + var h = function() { + return 2; + }; + } + } +} + +func_modified: { + options = { + reduce_vars: true, + unused: true, + } + input: { + function f(a) { + function a() { return 1; } + function b() { return 2; } + function c() { return 3; } + b.inject = []; + c = function() { return 4; }; + return a() + b() + c(); + } + } + expect: { + function f(a) { + function b() { return 2; } + function c() { return 3; } + b.inject = []; + c = function() { return 4; }; + return 1 + 2 + c(); + } + } +} + +defun_label: { + options = { + passes: 2, + reduce_vars: true, + unused: true, + } + input: { + !function() { + function f(a) { + L: { + if (a) break L; + return 1; + } + } + console.log(f(2)); + }(); + } + expect: { + !function() { + console.log(function(a) { + L: { + if (a) break L; + return 1; + } + }(2)); + }(); } } diff --git a/test/mocha/benchmark.js b/test/mocha/benchmark.js new file mode 100644 index 00000000..c2c7c02c --- /dev/null +++ b/test/mocha/benchmark.js @@ -0,0 +1,24 @@ +var assert = require("assert"); +var exec = require("child_process").exec; + +describe("test/benchmark.js", function() { + this.timeout(120000); + var command = '"' + process.argv[0] + '" test/benchmark.js '; + [ + "-b", + "-b bracketize", + "-m", + "-mc passes=3", + "-mc passes=3,toplevel", + "-mc passes=3,unsafe", + "-mc keep_fargs=false,passes=3", + "-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto", + ].forEach(function(args) { + it("Should pass with options " + args, function(done) { + exec(command + args, function(err) { + if (err) throw err; + done(); + }); + }); + }); +}); diff --git a/test/mocha/cli.js b/test/mocha/cli.js index c07eeee7..e8e07cb5 100644 --- a/test/mocha/cli.js +++ b/test/mocha/cli.js @@ -82,7 +82,7 @@ describe("bin/uglifyjs", function () { }); }); it("Should work with --keep-fnames (mangle & compress)", function (done) { - var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c'; + var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false'; exec(command, function (err, stdout) { if (err) throw err; diff --git a/test/mocha/glob.js b/test/mocha/glob.js index c2fc9464..30313656 100644 --- a/test/mocha/glob.js +++ b/test/mocha/glob.js @@ -3,17 +3,13 @@ var assert = require("assert"); describe("minify() with input file globs", function() { it("minify() with one input file glob string.", function() { - var result = Uglify.minify("test/input/issue-1242/foo.*", { - compress: { collapse_vars: true } - }); + var result = Uglify.minify("test/input/issue-1242/foo.*"); assert.strictEqual(result.code, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);'); }); it("minify() with an array of one input file glob.", function() { var result = Uglify.minify([ "test/input/issue-1242/b*.es5", - ], { - compress: { collapse_vars: true } - }); + ]); assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}'); }); it("minify() with an array of multiple input file globs.", function() { @@ -21,8 +17,8 @@ describe("minify() with input file globs", function() { "test/input/issue-1242/???.es5", "test/input/issue-1242/*.js", ], { - compress: { collapse_vars: true } + compress: { toplevel: true } }); - assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}function foo(n){print("Foo:",2*n)}var print=console.log.bind(console);print("qux",bar(3),baz(12)),foo(11);'); + assert.strictEqual(result.code, 'var print=console.log.bind(console);print("qux",function(n){return 3*n}(3),function(n){return n/2}(12)),function(n){print("Foo:",2*n)}(11);'); }); });