diff --git a/lib/compress.js b/lib/compress.js index a4232ed2..d1f17ae1 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -9255,6 +9255,13 @@ merge(Compressor.prototype, { }) : arg); } + function avoid_await_yield(parent_scope) { + var avoid = []; + if (is_async(parent_scope)) avoid.push("await"); + if (is_generator(parent_scope)) avoid.push("yield"); + return avoid.length && makePredicate(avoid); + } + OPT(AST_Call, function(self, compressor) { var exp = self.expression; var terminated = trim_optional_chain(self, compressor); @@ -9770,16 +9777,8 @@ merge(Compressor.prototype, { return args; } - function avoid_await_yield() { - var avoid = []; - var parent_scope = scope || compressor.find_parent(AST_Scope); - if (is_async(parent_scope)) avoid.push("await"); - if (is_generator(parent_scope)) avoid.push("yield"); - return avoid.length && makePredicate(avoid); - } - function safe_from_await_yield(node) { - var avoid = avoid_await_yield(); + var avoid = avoid_await_yield(scope || compressor.find_parent(AST_Scope)); if (!avoid) return true; var safe = true; var tw = new TreeWalker(function(node) { @@ -9856,7 +9855,7 @@ merge(Compressor.prototype, { return def.references.length - def.replaced < 2 && def.orig[0] instanceof AST_SymbolFunarg; })) return; var abort = false; - var avoid = avoid_await_yield(); + var avoid = avoid_await_yield(scope || compressor.find_parent(AST_Scope)); var begin; var in_order = []; var side_effects = false; @@ -12373,19 +12372,33 @@ merge(Compressor.prototype, { for (var i = props.length; --i >= 0;) { var prop = props[i]; if (prop.key !== key) continue; - if (!all(props, can_hoist_property)) break; - if (!safe_to_flatten(prop.value, compressor)) break; - props = props.map(function(prop) { - return prop.value; - }); - if (prop instanceof AST_ObjectMethod - && prop.value instanceof AST_Function - && !(compressor.parent() instanceof AST_Call)) { - if (prop.value.uses_arguments) break; - props[i] = make_node(AST_Arrow, prop.value, prop.value); + if (!all(props, can_hoist_property)) return; + if (!safe_to_flatten(prop.value, compressor)) return; + var values = []; + for (var j = 0; j < props.length; j++) { + var value = props[j].value; + if (props[j] instanceof AST_ObjectMethod) { + var arrow = !(value.uses_arguments || is_generator(value) || value.contains_this()); + if (arrow) { + var avoid = avoid_await_yield(compressor.find_parent(AST_Scope)); + value.each_argname(function(argname) { + if (avoid[argname.name]) arrow = false; + }); + } + var ctor; + if (arrow) { + ctor = is_async(value) ? AST_AsyncArrow : AST_Arrow; + } else if (i === j && !(compressor.parent() instanceof AST_Call)) { + return; + } else { + ctor = value.CTOR; + } + value = make_node(ctor, value, value); + } + values.push(value); } return make_node(AST_Sub, this, { - expression: make_node(AST_Array, expr, { elements: props }), + expression: make_node(AST_Array, expr, { elements: values }), property: make_node(AST_Number, this, { value: i }), }); } diff --git a/lib/output.js b/lib/output.js index c35c8ffc..d7927dbc 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1152,8 +1152,9 @@ function OutputStream(options) { }); } function print_arrow(self, output) { - if (self.argnames.length == 1 && self.argnames[0] instanceof AST_SymbolFunarg && !self.rest) { - self.argnames[0].print(output); + var argname = self.argnames.length == 1 && !self.rest && self.argnames[0]; + if (argname instanceof AST_SymbolFunarg && argname.name != "yield") { + argname.print(output); } else { print_funargs(self, output); } diff --git a/lib/parse.js b/lib/parse.js index 25487feb..1b23dc2e 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -1316,6 +1316,11 @@ function parse($TEXT, options) { } if (node instanceof AST_SymbolFunarg) return node; if (node instanceof AST_SymbolRef) return new AST_SymbolFunarg(node); + if (node instanceof AST_Yield) return new AST_SymbolFunarg({ + start: node.start, + name: "yield", + end: node.end, + }); token_error(node.start, "Invalid arrow parameter"); } diff --git a/test/compress/awaits.js b/test/compress/awaits.js index 466abc3e..7d79fe15 100644 --- a/test/compress/awaits.js +++ b/test/compress/awaits.js @@ -453,7 +453,7 @@ object_function: { }).f(); } expect: { - (async function() { + (async () => { console.log("PASS"); })(); } @@ -2212,3 +2212,29 @@ issue_5159_2: { ] node_version: ">=8" } + +issue_5177: { + options = { + properties: true, + } + input: { + (async function() { + return { + p(await) {}, + }.p; + })().then(function(a) { + console.log(typeof a); + }); + } + expect: { + (async function() { + return { + p(await) {}, + }.p; + })().then(function(a) { + console.log(typeof a); + }); + } + expect_stdout: "function" + node_version: ">=8" +} diff --git a/test/compress/properties.js b/test/compress/properties.js index fb0db99e..cbbe8985 100644 --- a/test/compress/properties.js +++ b/test/compress/properties.js @@ -1510,3 +1510,71 @@ issue_5093_quote_style: { expect_exact: 'console.log({a:true,\'42\':"PASS","null":[]}[6*7]);' expect_stdout: "PASS" } + +object_methods: { + options = { + properties: true, + } + input: { + ({ + p() { + console.log("FAIL 1"); + }, + *q() { + console.log("FAIL 2"); + }, + async r() { + console.log("FAIL 3"); + }, + async *s() { + console.log("PASS"); + }, + }).s().next(); + } + expect: { + [ + () => { + console.log("FAIL 1"); + }, + function*() { + console.log("FAIL 2"); + }, + async () => { + console.log("FAIL 3"); + }, + async function*() { + console.log("PASS"); + }, + ][3]().next(); + } + expect_stdout: "PASS" + node_version: ">=10" +} + +issue_5177: { + options = { + properties: true, + } + input: { + var a = "FAIL"; + var o = { a: "PASS" }; + o.p = { + q() { + return this.a; + }, + }.q; + console.log(o.p()); + } + expect: { + var a = "FAIL"; + var o = { a: "PASS" }; + o.p = { + q() { + return this.a; + }, + }.q; + console.log(o.p()); + } + expect_stdout: "PASS" + node_version: ">=4" +} diff --git a/test/compress/yields.js b/test/compress/yields.js index 37fd30e3..d10321e2 100644 --- a/test/compress/yields.js +++ b/test/compress/yields.js @@ -96,7 +96,7 @@ pause_resume: { node_version: ">=4" } -arrow_yield: { +arrow_yield_1: { input: { yield = "PASS"; console.log(function*() { @@ -108,6 +108,18 @@ arrow_yield: { node_version: ">=4" } +arrow_yield_2: { + input: { + console.log(typeof function *() { + // Syntax error on Node.js v6+ + return (yield) => {}; + }().next().value); + } + expect_exact: "console.log(typeof function*(){return(yield)=>{}}().next().value);" + expect_stdout: "function" + node_version: "4" +} + for_of: { input: { function* f() { @@ -1275,3 +1287,25 @@ issue_5076: { expect_stdout: "PASS" node_version: ">=6" } + +issue_5177: { + options = { + properties: true, + } + input: { + console.log(typeof function*() { + return { + p(yield) {}, + }.p; + }().next().value); + } + expect: { + console.log(typeof function*() { + return { + p(yield) {}, + }.p; + }().next().value); + } + expect_stdout: "function" + node_version: ">=4" +}