diff --git a/lib/compress.js b/lib/compress.js index b515c4259ce..7b26e728be1 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -210,10 +210,19 @@ Compressor.prototype = new TreeTransformer(function(node, descend) { // output and performance. descend(node, this); var opt = node.optimize(this); - if (is_scope && opt === node && !this.has_directive("use asm") && !opt.pinned()) { - opt.drop_unused(this); - if (opt.merge_variables(this)) opt.drop_unused(this); - descend(opt, this); + if (is_scope) { + if (opt === node && !this.has_directive("use asm") && !opt.pinned()) { + opt.drop_unused(this); + if (opt.merge_variables(this)) opt.drop_unused(this); + descend(opt, this); + } + if (this.option("arrows") && is_arrow(opt) && opt.body.length == 1) { + var stat = opt.body[0]; + if (stat instanceof AST_Return) { + opt.body.length = 0; + opt.value = stat.value; + } + } } if (opt === node) opt._squeezed = true; return opt; @@ -6462,29 +6471,6 @@ Compressor.prototype.compress = function(node) { return self; }); - function opt_arrow(self, compressor) { - if (!compressor.option("arrows")) return self; - drop_rest_farg(self, compressor); - if (self.value) self.body = [ self.first_statement() ]; - var body = tighten_body(self.body, compressor); - switch (body.length) { - case 1: - var stat = body[0]; - if (stat instanceof AST_Return) { - self.body.length = 0; - self.value = stat.value; - break; - } - default: - self.body = body; - self.value = null; - break; - } - return self; - } - OPT(AST_Arrow, opt_arrow); - OPT(AST_AsyncArrow, opt_arrow); - OPT(AST_Function, function(self, compressor) { drop_rest_farg(self, compressor); self.body = tighten_body(self.body, compressor); @@ -11125,6 +11111,16 @@ Compressor.prototype.compress = function(node) { return make_sequence(self, convert_args()).optimize(compressor); } } + if (compressor.option("arrows") + && compressor.option("module") + && (exp instanceof AST_AsyncFunction || exp instanceof AST_Function) + && !exp.name + && !exp.uses_arguments + && !exp.pinned() + && !exp.contains_this()) { + self.expression = make_node(is_async(exp) ? AST_AsyncArrow : AST_Arrow, exp, exp).transform(compressor); + return self; + } if (compressor.option("drop_console")) { if (exp instanceof AST_PropAccess) { var name = exp.expression; diff --git a/test/compress/arrows.js b/test/compress/arrows.js index b20316f8807..8d778addb9b 100644 --- a/test/compress/arrows.js +++ b/test/compress/arrows.js @@ -749,6 +749,86 @@ instanceof_lambda_4: { node_version: ">=4" } +func_to_arrow: { + options = { + arrows: true, + module: true, + } + input: { + console.log(function(a, b, c) { + return b + a + c + c; + }("A", "P", "S")); + } + expect: { + console.log(((a, b, c) => b + a + c + c)("A", "P", "S")); + } + expect_stdout: "PASS" + node_version: ">=4" +} + +func_to_arrow_var: { + options = { + arrows: true, + module: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var f = function(a, b, c) { + return b + a + c + c; + }; + console.log(f("A", "P", "S")); + } + expect: { + console.log(((a, b, c) => b + a + c + c)("A", "P", "S")); + } + expect_stdout: "PASS" + node_version: ">=4" +} + +keep_new: { + options = { + arrows: true, + module: true, + } + input: { + new function(a, b, c) { + console.log(b + a + c + c); + }("A", "P", "S"); + } + expect: { + new function(a, b, c) { + console.log(b + a + c + c); + }("A", "P", "S"); + } + expect_stdout: "PASS" + node_version: ">=4" +} + +keep_new_var: { + options = { + arrows: true, + module: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var f = function(a, b, c) { + console.log(b + a + c + c); + }; + new f("A", "P", "S"); + } + expect: { + new function(a, b, c) { + console.log(b + a + c + c); + }("A", "P", "S"); + } + expect_stdout: "PASS" + node_version: ">=4" +} + issue_4388: { options = { inline: true, @@ -1175,13 +1255,11 @@ issue_5416_1: { } expect: { var f = () => { - { - console; - arguments = void 0, - console.log(arguments); - var arguments; - return; - } + console; + arguments = void 0, + console.log(arguments); + var arguments; + return; }; f(); } @@ -1210,12 +1288,10 @@ issue_5416_2: { } expect: { var f = () => { - { - console; - var arguments = void 0; - for (; console.log(arguments);); - return; - } + console; + var arguments = void 0; + for (; console.log(arguments);); + return; }; f(); } @@ -1311,9 +1387,7 @@ issue_5653: { })()); } expect: { - console.log((a => { - return +{}; - })()); + console.log((a => +{})()); } expect_stdout: "NaN" node_version: ">=4" diff --git a/test/compress/awaits.js b/test/compress/awaits.js index 45d5dd3eca1..aafddaece8f 100644 --- a/test/compress/awaits.js +++ b/test/compress/awaits.js @@ -1407,6 +1407,30 @@ instanceof_lambda_4: { node_version: ">=8" } +async_to_arrow: { + options = { + arrows: true, + module: true, + reduce_vars: true, + unused: true, + } + input: { + (async function() { + var f = async function(a, b, c) { + return b + a + c + c; + }; + console.log(await f("A", "P", "S")); + })(); + } + expect: { + (async () => { + console.log(await (async (a, b, c) => b + a + c + c)("A", "P", "S")); + })(); + } + expect_stdout: "PASS" + node_version: ">=8" +} + issue_4335_1: { options = { inline: true, diff --git a/test/compress/yields.js b/test/compress/yields.js index ab850f0658d..eebdf4b8cb6 100644 --- a/test/compress/yields.js +++ b/test/compress/yields.js @@ -970,6 +970,61 @@ instanceof_lambda: { node_version: ">=4" } +keep_yield: { + options = { + arrows: true, + module: true, + } + input: { + console.log(function*() { + yield "PASS"; + }().next().value); + } + expect: { + console.log(function*() { + yield "PASS"; + }().next().value); + } + expect_stdout: "PASS" + node_version: ">=4" +} + +func_to_arrow_arg: { + options = { + arrows: true, + module: true, + } + input: { + console.log(function(yield) { + return yield; + }("PASS")); + } + expect: { + console.log((yield => yield)("PASS")); + } + expect_stdout: "PASS" + node_version: ">=4" +} + +func_to_arrow_var: { + options = { + arrows: true, + module: true, + } + input: { + var yield = "PASS"; + console.log(function() { + return yield; + }()); + } + expect: { + var yield = "PASS"; + console.log((() => yield)()); + } + expect_stdout: "PASS" + node_version: ">=4" +} + issue_4454_1: { rename = false options = { diff --git a/test/mocha/cli.js b/test/mocha/cli.js index 2e7f8fe517f..ecc5cfc39c7 100644 --- a/test/mocha/cli.js +++ b/test/mocha/cli.js @@ -16,8 +16,9 @@ describe("bin/uglifyjs", function() { var command = [ uglifyjscmd, "--self", - semver.satisfies(process.version, "<=0.12") ? "-mc hoist_funs" : "-mc", "--wrap WrappedUglifyJS", + semver.satisfies(process.version, "<4") ? "--no-module" : "--module", + semver.satisfies(process.version, "<=0.12") ? "-mc hoist_funs" : "-mc", ].join(" "); exec(command, { maxBuffer: 1048576 }, function(err, stdout) { if (err) throw err; @@ -61,7 +62,7 @@ describe("bin/uglifyjs", function() { "--mangle", ].join(" "), function(err, stdout) { if (err) throw err; - assert.strictEqual(stdout, "function(n){for(;n(););return 42}(A)\n"); + assert.strictEqual(stdout, "(r=>{for(;r(););return 42})(A)\n"); done(); }).stdin.end([ "function(x) {", @@ -1066,7 +1067,7 @@ describe("bin/uglifyjs", function() { "return obj25.p + obj121.p + obj1024.p;", "}());", ]).join("\n"); - exec(uglifyjscmd + " -mc", function(err, stdout) { + exec(uglifyjscmd + " --no-module -mc", function(err, stdout) { if (err) throw err; assert.strictEqual(stdout, "console.log(function(){var p={p:25},n={p:121},o={p:1024};return p.p+n.p+o.p}());\n"); assert.strictEqual(run_code(stdout), run_code(code)); diff --git a/test/mocha/minify.js b/test/mocha/minify.js index e63acd82d26..a9ef993980e 100644 --- a/test/mocha/minify.js +++ b/test/mocha/minify.js @@ -239,7 +239,7 @@ describe("minify", function() { }, }); var code = result.code; - assert.strictEqual(code, "var a=function(){foo()}();"); + assert.strictEqual(code, "var a=(()=>{foo()})();"); }); }); @@ -325,20 +325,30 @@ describe("minify", function() { }); describe("module", function() { - it("Should not inline `await` variables", function() { - if (semver.satisfies(process.version, "<8")) return; - var code = [ - "console.log(function() {", - " return typeof await;", - "}());", - ].join("\n"); - assert.strictEqual(run_code("(async function(){" + code + "})();"), "undefined\n"); + var code = [ + "console.log(function() {", + " return typeof await;", + "}());", + ].join("\n"); + it("Should inline `await` variables", function() { + var result = UglifyJS.minify(code, { + module: false, + }); + if (result.error) throw result.error; + assert.strictEqual(result.code, "console.log(typeof await);"); + assert.strictEqual(run_code(code), "undefined\n"); + assert.strictEqual(run_code(result.code), "undefined\n"); + }); + it("Should not inline `await` variables in ES modules", function() { var result = UglifyJS.minify(code, { module: true, }); if (result.error) throw result.error; - assert.strictEqual(result.code, "console.log(function(){return typeof await}());"); - assert.strictEqual(run_code("(async function(){" + result.code + "})();"), "undefined\n"); + assert.strictEqual(result.code, "console.log((()=>typeof await)());"); + if (semver.satisfies(process.version, ">=8")) { + assert.strictEqual(run_code("(async function(){" + code + "})();"), "undefined\n"); + assert.strictEqual(run_code("(async function(){" + result.code + "})();"), "undefined\n"); + } }); }); diff --git a/test/mocha/reduce.js b/test/mocha/reduce.js index 528d365e77a..4dba6156f08 100644 --- a/test/mocha/reduce.js +++ b/test/mocha/reduce.js @@ -224,14 +224,20 @@ describe("test/reduce.js", function() { ].join("\n")); }); it("Should ignore difference in Error.message", function() { - var result = reduce_test("null[function() {\n}];"); + var result = reduce_test("null[function() {\n}];", { + module: false, + }); if (result.error) throw result.error; assert.strictEqual(result.code, (semver.satisfies(process.version, "<=0.10") ? [ "// Can't reproduce test failure", - "// minify options: {}", + "// minify options: {", + '// "module": false', + "// }", ] : [ "// No differences except in error message", - "// minify options: {}", + "// minify options: {", + '// "module": false', + "// }", ]).join("\n")); }); it("Should report trailing whitespace difference in stringified format", function() { @@ -245,6 +251,7 @@ describe("test/reduce.js", function() { unsafe_math: true, }, mangle: false, + module: false, }); if (result.error) throw result.error; assert.strictEqual(result.code, [ @@ -257,7 +264,8 @@ describe("test/reduce.js", function() { '// "compress": {', '// "unsafe_math": true', '// },', - '// "mangle": false', + '// "mangle": false,', + '// "module": false', "// }", ].join("\n")); }); diff --git a/test/mocha/spidermonkey.js b/test/mocha/spidermonkey.js index 79b0f29fd76..9babfc710f7 100644 --- a/test/mocha/spidermonkey.js +++ b/test/mocha/spidermonkey.js @@ -7,20 +7,21 @@ describe("spidermonkey export/import sanity test", function() { it("Should produce a functional build when using --self with spidermonkey", function(done) { this.timeout(120000); var uglifyjs = '"' + process.argv[0] + '" bin/uglifyjs'; - var options = semver.satisfies(process.version, "<=0.12") ? "-mc hoist_funs" : "-mc"; + var options = [ + semver.satisfies(process.version, "<4") ? "--no-module" : "--module", + semver.satisfies(process.version, "<=0.12") ? "-mc hoist_funs" : "-mc", + ]; var command = [ [ uglifyjs, "--self", - options, "--wrap SpiderUglify", "-o spidermonkey", - ].join(" "), + ].concat(options).join(" "), [ uglifyjs, "-p spidermonkey", - options, - ].join(" "), + ].concat(options).join(" "), ].join(" | "); exec(command, { maxBuffer: 1048576 }, function(err, stdout) { if (err) throw err;