diff options
author | Alex Lam S.L <alexlamsl@gmail.com> | 2020-12-10 22:59:21 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-11 06:59:21 +0800 |
commit | 57105b299ec582bc731b58002703faa297f10063 (patch) | |
tree | 3e08387fd9e2e644e60461f47f9d782c51611692 /lib | |
parent | 77e1bda4265c9a3fe36937dd734fab85db38437c (diff) | |
download | tracifyjs-57105b299ec582bc731b58002703faa297f10063.tar.gz tracifyjs-57105b299ec582bc731b58002703faa297f10063.zip |
fix corner cases with spread syntax (#4358)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/compress.js | 86 |
1 files changed, 53 insertions, 33 deletions
diff --git a/lib/compress.js b/lib/compress.js index fbf6036c..d4b911ee 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -3662,6 +3662,20 @@ merge(Compressor.prototype, { ], }); + // Accomodate when compress option evaluate=false + // as well as the common constant expressions !0 and -1 + (function(def) { + def(AST_Node, return_false); + def(AST_Constant, return_true); + def(AST_RegExp, return_false); + var unaryPrefix = makePredicate("! ~ - + void"); + def(AST_UnaryPrefix, function() { + return unaryPrefix[this.operator] && this.expression instanceof AST_Constant; + }); + })(function(node, func) { + node.DEFMETHOD("is_constant", func); + }); + // methods to evaluate a constant expression (function(def) { // If the node has been successfully reduced to a constant, @@ -3686,18 +3700,6 @@ merge(Compressor.prototype, { if (typeof val == "function" || typeof val == "object") return this; return val; }); - var unaryPrefix = makePredicate("! ~ - + void"); - AST_Node.DEFMETHOD("is_constant", function() { - // Accomodate when compress option evaluate=false - // as well as the common constant expressions !0 and -1 - if (this instanceof AST_Constant) { - return !(this instanceof AST_RegExp); - } else { - return this instanceof AST_UnaryPrefix - && this.expression instanceof AST_Constant - && unaryPrefix[this.operator]; - } - }); var scan_modified = new TreeWalker(function(node) { if (node instanceof AST_Assign) modified(node.left); if (node instanceof AST_Unary && unary_arithmetic[node.operator]) modified(node.expression); @@ -6453,20 +6455,24 @@ merge(Compressor.prototype, { } }); var values = trim(exprs, compressor, first_in_statement, function(node, compressor, first_in_statement) { - var exp = node.expression; - if (exp instanceof AST_Object) return node; - if (exp instanceof AST_PropAccess) return node; + var exp = node.expression.tail_node(); if (exp instanceof AST_SymbolRef) { exp = exp.fixed_value(); if (!exp) return node; - if (exp instanceof AST_SymbolRef) return node; - if (exp instanceof AST_PropAccess) return node; - if (!(exp instanceof AST_Object)) return null; - return all(exp.properties, function(prop) { + exp = exp.tail_node(); + } + if (exp instanceof AST_Array + || exp.TYPE == "Binary" && !lazy_op[exp.operator] + || exp instanceof AST_Constant + || exp instanceof AST_Lambda + || exp instanceof AST_Object && all(exp.properties, function(prop) { return !(prop instanceof AST_ObjectGetter || prop instanceof AST_Spread); - }) ? null : node; + }) + || exp instanceof AST_This + || exp instanceof AST_Unary) { + return node.expression.drop_side_effect_free(compressor, first_in_statement); } - return exp.drop_side_effect_free(compressor, first_in_statement); + return node; }); if (!values) return null; if (values === exprs && !all(values, function(node) { @@ -10043,26 +10049,36 @@ merge(Compressor.prototype, { OPT(AST_Object, function(self, compressor) { if (!compressor.option("objects")) return self; var changed = false; - var computed_int = false; - var has_computed = false; + var found = false; + var generated = false; var keep_duplicate = compressor.has_directive("use strict"); var keys = new Dictionary(); var values = []; self.properties.forEach(function(prop) { if (!(prop instanceof AST_Spread)) return process(prop); + found = true; var exp = prop.expression; - if (exp instanceof AST_Object && all(exp.properties, function(node) { - return node instanceof AST_ObjectKeyVal; + if (compressor.option("spread") && exp instanceof AST_Object && all(exp.properties, function(prop) { + return !(prop instanceof AST_ObjectGetter || prop instanceof AST_Spread); })) { changed = true; - has_computed = true; - exp.properties.forEach(process); + exp.properties.forEach(function(prop) { + if (prop instanceof AST_ObjectKeyVal) process(prop); + }); } else { + generated = true; flush(); values.push(prop); } }); flush(); + if (!changed) return self; + if (found && generated && values.length == 1) { + var value = values[0]; + if (value instanceof AST_ObjectProperty && value.key instanceof AST_Number) { + value.key = "" + value.key.value; + } + } return changed ? make_node(AST_Object, self, { properties: values }) : self; @@ -10071,8 +10087,8 @@ merge(Compressor.prototype, { keys.each(function(props) { if (props.length == 1) return values.push(props[0]); changed = true; - var tail = keep_duplicate && props.pop(); - values.push(make_node(AST_ObjectKeyVal, self, { + var tail = keep_duplicate && !generated && props.pop(); + values.push(props.length == 1 ? props[0] : make_node(AST_ObjectKeyVal, self, { key: props[0].key, value: make_sequence(self, props.map(function(prop) { return prop.value; @@ -10086,9 +10102,13 @@ merge(Compressor.prototype, { function process(prop) { var key = prop.key; if (key instanceof AST_Node) { - has_computed = true; + found = true; key = key.evaluate(compressor); - if (key !== prop.key) key = prop.key = "" + key; + if (key === prop.key) { + generated = true; + } else { + key = prop.key = "" + key; + } } if (prop instanceof AST_ObjectKeyVal && typeof key == "string") { if (prop.value.has_side_effects(compressor)) flush(); @@ -10097,8 +10117,8 @@ merge(Compressor.prototype, { flush(); values.push(prop); } - if (has_computed && !computed_int && typeof key == "string" && /^[0-9]+$/.test(key)) { - computed_int = true; + if (found && !generated && typeof key == "string" && /^[0-9]+$/.test(key)) { + generated = true; prop.key = make_node(AST_Number, prop, { value: +key }); |