[...].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
This commit is contained in:
Dan Wolff 2013-09-23 02:10:21 +02:00
parent afdaeba37d
commit 48d2f430ff
2 changed files with 81 additions and 22 deletions

View File

@ -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];
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()
});
} else {
first = make_node(AST_String, self, { value: "" });
break EXIT;
}
return elements.reduce(function(prev, el){
return make_node(AST_Binary, el[0], {
}
// 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[0],
right : el
});
}, first).transform(compressor);
}).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();

View File

@ -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");
}
}