From 48d2f430ffeb49f5c0fdf13a17dd1c34a7f99d17 Mon Sep 17 00:00:00 2001 From: Dan Wolff Date: Mon, 23 Sep 2013 02:10:21 +0200 Subject: [PATCH] [...].join() - handle null and better compress [...].join("str") * null, undefined, and holes in arrays are interpreted as an empty string by Array.prototype.join. This commit fixes various issues when compressing them, or values that can be null or undefined. * Compress [foo+"str","123"+bar].join("-") -> foo+"str-123"+bar --- lib/compress.js | 64 ++++++++++++++++++++++++++++++----------- test/compress/arrays.js | 39 +++++++++++++++++++++---- 2 files changed, 81 insertions(+), 22 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 37aba41e..ed3d683b 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1690,7 +1690,7 @@ merge(Compressor.prototype, { var last = a[a.length - 1]; if (last.length == 2) { // it's a constant - var val = "" + last[1] + separator + el[1]; + var val = "" + (last[1] == null ? "" : last[1] ) + separator + (el[1] == null ? "" : el[1]); a[a.length - 1] = [ make_node_from_constant(compressor, val, last[0]), val ]; } else { a.push(el); @@ -1699,23 +1699,55 @@ merge(Compressor.prototype, { return a; }, []); if (elements.length == 0) return make_node(AST_String, self, { value: "" }); - 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, self, { value: "" }); - } - return elements.reduce(function(prev, el){ - return make_node(AST_Binary, el[0], { - operator : "+", - left : prev, - right : el[0], + if (elements.length == 1) { + if (elements[0][0].is_string()) { + return elements[0][0]; + } else if (elements[0][0] instanceof AST_Constant) { + return make_node(AST_String, self, { + value: [elements[0][0].evaluate(compressor)[1]].join() }); - }, first).transform(compressor); + } else { + break EXIT; + } } + + // If all components are either strings or constants we can + // concatenate them with + + var all_string_or_constant = elements.every(function(el){ + return el[0] instanceof AST_Constant || el[0].is_string(compressor); + }); + if (all_string_or_constant) { + if (separator == "") { + if (!elements[0][0].is_string(compressor) + && !elements[1][0].is_string(compressor)) { + elements = elements.unshift([make_node(AST_String, self, { value: "" })]); + } + return elements.map(function(el){ return el[0] }).reduce(function(prev, el){ + if (el instanceof AST_Constant && el.getValue() == null) { + return prev; + } + return make_node(AST_Binary, el, { + operator : "+", + left : prev, + right : el + }); + }).transform(compressor); + } else { + var ast_separator = make_node_from_constant(compressor, ""+separator, self.args[0]); + return elements.map(function(el){ return el[0] }).reduce(function(prev, el){ + return make_node(AST_Binary, el, { + operator : "+", + left : make_node(AST_Binary, prev, { + operator : "+", + left : prev, + right : ast_separator + }), + right : el + }); + }).transform(compressor); + } + } + // need this awkward cloning to not affect original element // best_of will decide which one to get through. var node = self.clone(); diff --git a/test/compress/arrays.js b/test/compress/arrays.js index e636347f..5ef59693 100644 --- a/test/compress/arrays.js +++ b/test/compress/arrays.js @@ -23,8 +23,8 @@ constant_join: { var a1 = [ "foo", "bar", "baz" ].join(); var b = [ "foo", 1, 2, 3, "bar" ].join(""); var c = [ boo(), "foo", 1, 2, 3, "bar", bar() ].join(""); - var c1 = [ boo(), bar(), "foo", 1, 2, 3, "bar", bar() ].join(""); - var c2 = [ 1, 2, "foo", "bar", baz() ].join(""); + var c1 = [ boo() + bar() + "boo", "foo", 1, 2, 3, "bar", bar() + "foo" ].join(""); + var c2 = [ 1, 2, null, , undefined, "foo", "bar", baz() ].join(); var d = [ "foo", 1 + 2 + "bar", "baz" ].join("-"); var e = [].join(foo + bar); var f = [].join(""); @@ -34,9 +34,9 @@ constant_join: { var a = "foobarbaz"; var a1 = "foo,bar,baz"; var b = "foo123bar"; - var c = boo() + "foo123bar" + bar(); - var c1 = "" + boo() + bar() + "foo123bar" + bar(); - var c2 = "12foobar" + baz(); + var c = [ boo(), "foo123bar", bar() ].join(""); + var c1 = boo() + bar() + "boofoo123bar" + (bar() + "foo"); + var c2 = ["1,2,,,,foo,bar", baz()].join(); var d = "foo-3bar-baz"; var e = [].join(foo + bar); var f = ""; @@ -62,7 +62,7 @@ constant_join_2: { var f = [ "str", "str" + variable, "foo", "bar", "moo" + foo ].join(""); } expect: { - var a = "foobar" + boo() + "bazxy"; + var a = [ "foobar", boo(), "bazxy" ].join(""); var b = [ "foo-bar", boo(), "baz-x-y" ].join("-"); var c = [ "foo", "bar", boo(), "baz", "x", "y" ].join("really-long-separator"); var d = [ "foo-bar", boo(), "foo+1+2+3+bar-baz-x-y" ].join("-"); @@ -72,3 +72,30 @@ constant_join_2: { var f = "strstr" + variable + "foobarmoo" + foo; } } + +constant_join_3: { + options = { + unsafe : true, + evaluate : true + }; + input: { + var a = [ null ].join(); + var b = [ , ].join(); + var c = [ foo ].join(); + var d = [ foo, null, undefined, boo ].join("-"); + var e = [ foo, boo ].join(""); + var f = [ null, "foo", null, foo + "boo" ].join(""); + var g = [ null, "foo", null, foo + "boo" ].join("-"); + var h = [ "foo" + bar, null, baz + "boo" ].join(""); + } + expect: { + var a = ""; + var b = ""; + var c = [ foo ].join(); + var d = [ foo, "-", boo].join("-"); + var e = [ foo, boo ].join(""); + var f = "foo" + (foo + "boo"); + var g = "-foo--" + (foo + "boo"); + var h = "foo" + bar + (baz + "boo"); + } +}