From ae0f117da635a481f30f0ce4ccf5d883f07a90fc Mon Sep 17 00:00:00 2001 From: kzc Date: Wed, 16 Aug 2017 10:51:26 -0400 Subject: [PATCH] Introduce new compress option `unsafe_arrows` (#2278) * Not always safe to convert a function expression to an arrow function when code depends on the function prototype existing. Fixes #2271 --- README.md | 13 +++++++++--- lib/compress.js | 3 ++- test/compress/arrow.js | 43 +++++++++++++++++++++++++++++++++----- test/compress/issue-203.js | 3 ++- 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ba7541bd..d7d376b2 100644 --- a/README.md +++ b/README.md @@ -646,9 +646,16 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u - `evaluate` -- attempt to evaluate constant expressions -- `arrows` (default `true`) -- convert ES5 style anonymous function expressions - to arrow functions if permissible by language semantics. - Note: `arrows` requires that the `ecma` compress option is set to `6` or greater. +- `arrows` (default `true`) -- Converts `()=>{return x}` to `()=>x`. Class + and object literal methods will also be converted to arrow expressions if + the resultant code is shorter: `m(){return x}` becomes `m:()=>x`. + This transform requires that the `ecma` compress option is set to `6` or greater. + +- `unsafe_arrows` (default `false`) -- Convert ES5 style anonymous function + expressions to arrow functions if the function body does not reference `this`. + Note: it is not always safe to perform this conversion if code relies on the + the function having a `prototype`, which arrow functions lack. + This transform requires that the `ecma` compress option is set to `6` or greater. - `booleans` -- various optimizations for boolean context, for example `!!a ? b : c → a ? b : c` diff --git a/lib/compress.js b/lib/compress.js index ff7d0059..4b8a2eeb 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -84,6 +84,7 @@ function Compressor(options, false_by_default) { toplevel : !!(options && options["top_retain"]), typeofs : !false_by_default, unsafe : false, + unsafe_arrows : false, unsafe_comps : false, unsafe_Func : false, unsafe_math : false, @@ -4748,7 +4749,7 @@ merge(Compressor.prototype, { OPT(AST_Function, function(self, compressor){ tighten_body(self.body, compressor); - if (compressor.option("arrows") + if (compressor.option("unsafe_arrows") && compressor.option("ecma") >= 6 && !self.name && !self.is_generator diff --git a/test/compress/arrow.js b/test/compress/arrow.js index 44581ecf..5f65f847 100644 --- a/test/compress/arrow.js +++ b/test/compress/arrow.js @@ -213,7 +213,7 @@ no_leading_parentheses: { async_identifiers: { options = { - arrows: true, + unsafe_arrows: true, ecma: 6, } input: { @@ -237,7 +237,7 @@ async_identifiers: { async_function_expression: { options = { - arrows: true, + unsafe_arrows: true, ecma: 6, evaluate: true, side_effects: true, @@ -262,7 +262,7 @@ async_function_expression: { issue_27: { options = { - arrows: true, + unsafe_arrows: true, collapse_vars: true, ecma: 6, unused: true, @@ -283,7 +283,7 @@ issue_27: { issue_2105_1: { options = { - arrows: true, + unsafe_arrows: true, collapse_vars: true, ecma: 6, inline: true, @@ -501,7 +501,7 @@ issue_485_crashing_1530: { issue_2084: { options = { - arrows: true, + unsafe_arrows: true, collapse_vars: true, conditionals: true, ecma: 6, @@ -577,6 +577,7 @@ concise_methods_with_computed_property2: { async_object_literal: { options = { arrows: true, + unsafe_arrows: true, ecma: 6, evaluate: true, } @@ -597,3 +598,35 @@ async_object_literal: { }; } } + +issue_2271: { + options = { + arrows: true, + ecma: 6, + evaluate: true, + unsafe_arrows: false, + } + input: { + var Foo = function() {}; + Foo.prototype.set = function(value) { + this.value = value; + return this; + } + Foo.prototype.print = function() { + console.log(this.value); + } + new Foo().set("PASS").print(); + } + expect: { + var Foo = function() {}; + Foo.prototype.set = function(value) { + this.value = value; + return this; + } + Foo.prototype.print = function() { + console.log(this.value); + } + new Foo().set("PASS").print(); + } + expect_stdout: "PASS" +} diff --git a/test/compress/issue-203.js b/test/compress/issue-203.js index a9f3dbf9..896982b5 100644 --- a/test/compress/issue-203.js +++ b/test/compress/issue-203.js @@ -36,9 +36,10 @@ compress_new_function_with_destruct: { compress_new_function_with_destruct_arrows: { options = { arrows: true, + unsafe_arrows: true, unsafe: true, unsafe_Func: true, - ecma: 6 + ecma: 6, } beautify = { ecma: 6