diff options
author | Mihai Bazon <mihai@bazon.net> | 2013-09-22 13:12:34 +0300 |
---|---|---|
committer | Mihai Bazon <mihai@bazon.net> | 2013-09-22 13:14:42 +0300 |
commit | 583fac0a0f4f5ae9b71a051730b4834a190f6387 (patch) | |
tree | efb640e25e282cc9dac18052dc7c18f179121f87 /lib/compress.js | |
parent | e8158279ff08af915c634eeec4cfabda1ff4022e (diff) | |
download | tracifyjs-583fac0a0f4f5ae9b71a051730b4834a190f6387.tar.gz tracifyjs-583fac0a0f4f5ae9b71a051730b4834a190f6387.zip |
More dirty handling of [ ... ].join() in unsafe mode
Close #300
Diffstat (limited to 'lib/compress.js')
-rw-r--r-- | lib/compress.js | 72 |
1 files changed, 59 insertions, 13 deletions
diff --git a/lib/compress.js b/lib/compress.js index abf2001d..f71ba4ab 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -630,15 +630,20 @@ merge(Compressor.prototype, { // elements. If the node has been successfully reduced to a // constant, then the second element tells us the value; // otherwise the second element is missing. The first element - // of the array is always an AST_Node descendant; when + // of the array is always an AST_Node descendant; if // evaluation was successful it's a node that represents the - // constant; otherwise it's the original node. + // constant; otherwise it's the original or a replacement node. AST_Node.DEFMETHOD("evaluate", function(compressor){ if (!compressor.option("evaluate")) return [ this ]; try { var val = this._eval(compressor); - var ast = val instanceof AST_Binary ? val : make_node_from_constant(compressor, val, this); - return [ best_of(ast, this), val ]; + if (val instanceof AST_Node) { + // we didn't really reduce it to a constant, so + // the return array should contain only one + // node; but perhaps it's a better one. + return [ best_of(val, this) ]; + } + return [ best_of(make_node_from_constant(compressor, val, this), this), val ]; } catch(ex) { if (ex !== def) throw ex; return [ this ]; @@ -750,10 +755,56 @@ merge(Compressor.prototype, { if (this.expression instanceof AST_Dot && this.expression.expression instanceof AST_Array && this.expression.property == "join") { - var x = this.expression.expression.elements.map(function(el){ - return ev(el, compressor); + var separator = this.args.length == 0 ? "," : ev(this.args[0], compressor); + if (separator instanceof AST_Node) throw def; // not a constant + var elements = this.expression.expression.elements.map(function(el){ + return el.evaluate(compressor); // doesn't throw. + }); + elements = elements.reduce(function(a, el){ + if (a.length == 0 || el.length == 1) { + a.push(el); + } else { + var last = a[a.length - 1]; + if (last.length == 2) { + // it's a constant + var val = "" + last[1] + separator + el[1]; + a[a.length - 1] = [ + make_node_from_constant(compressor, val, last[0]), + val + ]; + } else { + a.push(el); + } + } + return a; + }, []); + if (elements.length == 0) return ""; + if (elements.length == 1) return elements[0][0]; + if (separator == "") { + var first; + if (elements[0][0] instanceof AST_String + || elements[1][0] instanceof AST_String) { + first = elements.shift()[0]; + } else { + first = make_node(AST_String, this, { value: "" }); + } + return elements.reduce(function(prev, el){ + return make_node(AST_Binary, el[0], { + operator : "+", + left : prev, + right : el[0], + }); + }, first); + } + // need this awkward cloning to not affect original element + // best_of will decide which one to get through. + var node = this.clone(); + node.expression = node.expression.clone(); + node.expression.expression = node.expression.expression.clone(); + node.expression.expression.elements = elements.map(function(el){ + return el[0]; }); - return x.join(ev(this.args[0], compressor)); + return node; } } throw def; @@ -1918,11 +1969,6 @@ merge(Compressor.prototype, { } break; } - var exp = self.evaluate(compressor); - if (exp.length > 1) { - if (best_of(exp[0], self) !== self) - return exp[0]; - } if (compressor.option("comparisons")) { if (!(compressor.parent() instanceof AST_Binary) || compressor.parent() instanceof AST_Assign) { @@ -1942,7 +1988,7 @@ merge(Compressor.prototype, { && self.left.operator == "+" && self.left.is_string(compressor)) { return self.left; } - return self; + return self.evaluate(compressor)[0]; }); OPT(AST_SymbolRef, function(self, compressor){ |