diff --git a/lib/compress.js b/lib/compress.js index 717f931e..07d3b4b5 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -4596,7 +4596,7 @@ merge(Compressor.prototype, { var has_special_symbol = false; self.walk(new TreeWalker(function(node) { if (has_special_symbol) return true; - if (node instanceof AST_Symbol && !node.definition()) { + if (node instanceof AST_Super || node instanceof AST_This) { has_special_symbol = true; return true; } @@ -4656,6 +4656,36 @@ merge(Compressor.prototype, { return self; }); + AST_Lambda.DEFMETHOD("contains_this", function() { + var result; + var self = this; + self.walk(new TreeWalker(function(node) { + if (result) return true; + if (node instanceof AST_This) return result = true; + if (node !== self && node instanceof AST_Scope && !(node instanceof AST_Arrow)) return true; + })); + return result; + }); + + OPT(AST_ConciseMethod, function(self, compressor){ + // p(){return x;} ---> p:()=>x + if (compressor.option("arrows") + && compressor.parent() instanceof AST_Object + && self.value.body.length == 1 + && self.value.body[0] instanceof AST_Return + && self.value.body[0].value + && !self.value.contains_this()) { + var arrow = make_node(AST_Arrow, self.value, self.value); + arrow.async = self.async; + arrow.is_generator = self.is_generator; + return make_node(AST_ObjectKeyVal, self, { + key: self.key instanceof AST_SymbolMethod ? self.key.name : self.key, + value: arrow + }); + } + return self; + }); + OPT(AST_ObjectKeyVal, function(self, compressor){ // p:function(){} ---> p(){} // p:function*(){} ---> *p(){} @@ -4667,7 +4697,7 @@ merge(Compressor.prototype, { var value = self.value; var is_arrow_with_block = value instanceof AST_Arrow && Array.isArray(value.body) - && !contains_this(value); + && !value.contains_this(); if ((is_arrow_with_block || value instanceof AST_Function) && !value.name) { return make_node(AST_ConciseMethod, self, { async: value.async, @@ -4680,16 +4710,5 @@ merge(Compressor.prototype, { } } return self; - - function contains_this(node) { - var result; - var tw = new TreeWalker(function(node) { - if (node instanceof AST_This) { - return result = true; - } - }); - node.walk(tw); - return result; - } }); })(); diff --git a/test/compress/arrow.js b/test/compress/arrow.js index b081fe22..44581ecf 100644 --- a/test/compress/arrow.js +++ b/test/compress/arrow.js @@ -313,8 +313,7 @@ issue_2105_1: { }); } expect: { - // TODO: outer function should be an arrow function - (function() { + (() => { var quux = () => { console.log("PASS"); }; @@ -541,3 +540,60 @@ issue_2084: { expect_stdout: "0" node_version: ">=4" } + +export_default_object_expression: { + options = { + arrows: true, + evaluate: true, + } + input: { + export default { + foo: 1 + 2, + bar() { return 4; }, + get baz() { return this.foo; }, + }; + } + expect_exact: "export default{foo:3,bar:()=>4,get baz(){return this.foo}};" +} + +concise_methods_with_computed_property2: { + options = { + arrows: true, + evaluate: true, + } + input: { + var foo = { + [[1]](v) { + return v; + } + }; + console.log(foo[[1]]("PASS")); + } + expect_exact: 'var foo={[[1]]:v=>v};console.log(foo[[1]]("PASS"));' + expect_stdout: "PASS" + node_version: ">=4" +} + +async_object_literal: { + options = { + arrows: true, + ecma: 6, + evaluate: true, + } + input: { + var obj = { + async a() { + return await foo(1 + 0); + }, + anon: async function() { + return await foo(2 + 0); + } + }; + } + expect: { + var obj = { + a: async () => await foo(1), + anon: async () => await foo(2) + }; + } +} diff --git a/test/compress/object.js b/test/compress/object.js index 52d7ad77..f7ce136a 100644 --- a/test/compress/object.js +++ b/test/compress/object.js @@ -561,6 +561,32 @@ prop_arrow_to_concise_method: { node_version: ">=6" } +concise_method_to_prop_arrow: { + options = { + arrows: true, + ecma: 6, + } + input: { + console.log(({ a: () => 1 }).a()); + console.log(({ a: () => { return 2; } }).a()); + console.log(({ a() { return 3; } }).a()); + console.log(({ a() { return this.b; }, b: 4 }).a()); + } + expect: { + console.log({ a: () => 1 }.a()); + console.log({ a: () => 2 }.a()); + console.log({ a: () => 3 }.a()); + console.log({ a() { return this.b; }, b: 4 }.a()); + } + expect_stdout: [ + "1", + "2", + "3", + "4", + ] + node_version: ">=4" +} + prop_func_to_async_concise_method: { options = { ecma: 8, @@ -648,19 +674,71 @@ prop_arrow_with_this: { ecma: 6, } input: { - ({ + function run(arg) { + console.log(arg === this ? "global" : arg === foo ? "foo" : arg); + } + var foo = { func_no_this: function() { run(); }, func_with_this: function() { run(this); }, arrow_no_this: () => { run(); }, arrow_with_this: () => { run(this); }, - }); + }; + for (var key in foo) foo[key](); } expect: { - ({ + function run(arg) { + console.log(arg === this ? "global" : arg === foo ? "foo" : arg); + } + var foo = { func_no_this() { run(); }, func_with_this() { run(this); }, arrow_no_this() { run(); }, arrow_with_this: () => { run(this); }, - }); + }; + for (var key in foo) foo[key](); } + expect_stdout: [ + "undefined", + "foo", + "undefined", + "global", + ] + node_version: ">=4" +} + +prop_arrow_with_nested_this: { + options = { + ecma: 6, + } + input: { + function run(arg) { + console.log(arg === this ? "global" : arg === foo ? "foo" : arg); + } + var foo = { + func_func_this: function() { (function() { run(this); })(); }, + func_arrow_this: function() { (() => { run(this); })(); }, + arrow_func_this: () => { (function() { run(this); })(); }, + arrow_arrow_this: () => { (() => { run(this); })(); }, + }; + for (var key in foo) foo[key](); + } + expect: { + function run(arg) { + console.log(arg === this ? "global" : arg === foo ? "foo" : arg); + } + var foo = { + func_func_this() { (function() { run(this); })(); }, + func_arrow_this() { (() => { run(this); })(); }, + arrow_func_this() { (function() { run(this); })(); }, + arrow_arrow_this: () => { (() => { run(this); })(); }, + }; + for (var key in foo) foo[key](); + } + expect_stdout: [ + "global", + "foo", + "global", + "global", + ] + node_version: ">=4" } diff --git a/test/mocha/object.js b/test/mocha/object.js index 995b9eac..61ae8c36 100644 --- a/test/mocha/object.js +++ b/test/mocha/object.js @@ -4,7 +4,11 @@ var assert = require("assert"); describe("Object", function() { it("Should allow objects to have a methodDefinition as property", function() { var code = "var a = {test() {return true;}}"; - assert.equal(Uglify.minify(code).code, "var a={test(){return!0}};"); + assert.equal(Uglify.minify(code, { + compress: { + arrows: false + } + }).code, "var a={test(){return!0}};"); }); it("Should not allow objects to use static keywords like in classes", function() {