@@ -751,6 +751,8 @@ to be `false` and all symbol names will be omitted.
|
||||
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
|
||||
example: `/*@__PURE__*/foo();`
|
||||
|
||||
- `spread` (default: `true`) -- flatten spread expressions.
|
||||
|
||||
- `strings` (default: `true`) -- compact string concatenations.
|
||||
|
||||
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
|
||||
|
||||
@@ -84,6 +84,7 @@ function Compressor(options, false_by_default) {
|
||||
reduce_vars : !false_by_default,
|
||||
sequences : !false_by_default,
|
||||
side_effects : !false_by_default,
|
||||
spread : !false_by_default,
|
||||
strings : !false_by_default,
|
||||
switches : !false_by_default,
|
||||
top_retain : null,
|
||||
@@ -9724,27 +9725,10 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
});
|
||||
|
||||
function is_integer(key) {
|
||||
return /^[0-9]+$/.test(key);
|
||||
}
|
||||
|
||||
OPT(AST_Spread, function(self, compressor) {
|
||||
if (compressor.option("properties")) {
|
||||
var exp = self.expression;
|
||||
if (compressor.parent() instanceof AST_Object) {
|
||||
if (exp instanceof AST_Object && all(exp.properties, function(node) {
|
||||
return node instanceof AST_ObjectKeyVal;
|
||||
})) return List.splice(exp.properties.map(function(node) {
|
||||
var key = node.key;
|
||||
if (!(key instanceof AST_Node) && is_integer(key)) {
|
||||
node = node.clone();
|
||||
node.key = make_node(AST_Number, node, {
|
||||
value: +key
|
||||
});
|
||||
}
|
||||
return node;
|
||||
}));
|
||||
} else if (exp instanceof AST_Array) return List.splice(exp.elements.map(function(node) {
|
||||
var exp = self.expression;
|
||||
if (compressor.option("spread") && exp instanceof AST_Array && !(compressor.parent() instanceof AST_Object)) {
|
||||
return List.splice(exp.elements.map(function(node) {
|
||||
return node instanceof AST_Hole ? make_node(AST_Undefined, node).optimize(compressor) : node;
|
||||
}));
|
||||
}
|
||||
@@ -10014,40 +9998,69 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_Object, function(self, compressor) {
|
||||
if (!compressor.option("objects") || compressor.has_directive("use strict")) return self;
|
||||
for (var i = self.properties.length; --i >= 0;) {
|
||||
var prop = self.properties[i];
|
||||
var key = prop.key;
|
||||
if (key instanceof AST_Node) key = key.evaluate(compressor);
|
||||
if (is_integer(key)) break;
|
||||
if (key !== prop.key) prop.key = "" + key;
|
||||
}
|
||||
if (!compressor.option("objects")) return self;
|
||||
var changed = false;
|
||||
var computed_int = false;
|
||||
var has_computed = false;
|
||||
var keep_duplicate = compressor.has_directive("use strict");
|
||||
var keys = new Dictionary();
|
||||
var values = [];
|
||||
self.properties.forEach(function(prop) {
|
||||
if (prop instanceof AST_ObjectKeyVal && typeof prop.key == "string") {
|
||||
if (prop.value.has_side_effects(compressor)) flush();
|
||||
keys.add(prop.key, prop.value);
|
||||
if (!(prop instanceof AST_Spread)) return process(prop);
|
||||
var exp = prop.expression;
|
||||
if (exp instanceof AST_Object && all(exp.properties, function(node) {
|
||||
return node instanceof AST_ObjectKeyVal;
|
||||
})) {
|
||||
changed = true;
|
||||
has_computed = true;
|
||||
exp.properties.forEach(process);
|
||||
} else {
|
||||
flush();
|
||||
values.push(prop);
|
||||
}
|
||||
});
|
||||
flush();
|
||||
if (self.properties.length != values.length) return make_node(AST_Object, self, {
|
||||
return changed ? make_node(AST_Object, self, {
|
||||
properties: values
|
||||
});
|
||||
return self;
|
||||
}) : self;
|
||||
|
||||
function flush() {
|
||||
keys.each(function(expressions, key) {
|
||||
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, {
|
||||
key: key,
|
||||
value: make_sequence(self, expressions)
|
||||
key: props[0].key,
|
||||
value: make_sequence(self, props.map(function(prop) {
|
||||
return prop.value;
|
||||
}))
|
||||
}));
|
||||
if (tail) values.push(tail);
|
||||
});
|
||||
keys = new Dictionary();
|
||||
}
|
||||
|
||||
function process(prop) {
|
||||
var key = prop.key;
|
||||
if (key instanceof AST_Node) {
|
||||
has_computed = true;
|
||||
key = key.evaluate(compressor);
|
||||
if (key !== prop.key) key = prop.key = "" + key;
|
||||
}
|
||||
if (prop instanceof AST_ObjectKeyVal && typeof key == "string") {
|
||||
if (prop.value.has_side_effects(compressor)) flush();
|
||||
keys.add(key, prop);
|
||||
} else {
|
||||
flush();
|
||||
values.push(prop);
|
||||
}
|
||||
if (has_computed && !computed_int && typeof key == "string" && /^[0-9]+$/.test(key)) {
|
||||
computed_int = true;
|
||||
prop.key = make_node(AST_Number, prop, {
|
||||
value: +key
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
OPT(AST_Return, function(self, compressor) {
|
||||
|
||||
@@ -45,8 +45,8 @@ duplicate_key_strict: {
|
||||
"use strict";
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
a: 3,
|
||||
b: 2,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
@@ -323,8 +323,8 @@ issue_4269_3: {
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
["foo"]: "bar",
|
||||
get 42() {
|
||||
foo: "bar",
|
||||
get [42]() {
|
||||
return "FAIL";
|
||||
},
|
||||
42: "PASS",
|
||||
@@ -353,8 +353,8 @@ issue_4269_4: {
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
["foo"]: "bar",
|
||||
42: "PASS",
|
||||
foo: "bar",
|
||||
[42]: "PASS",
|
||||
}[42]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
|
||||
@@ -105,8 +105,8 @@ dont_inline: {
|
||||
|
||||
do_inline: {
|
||||
options = {
|
||||
properties: true,
|
||||
inline: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
@@ -144,8 +144,8 @@ drop_empty_call_1: {
|
||||
|
||||
drop_empty_call_2: {
|
||||
options = {
|
||||
properties: true,
|
||||
side_effects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
(function() {})(...[ console.log("PASS") ]);
|
||||
@@ -159,7 +159,7 @@ drop_empty_call_2: {
|
||||
|
||||
convert_hole: {
|
||||
options = {
|
||||
properties: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
console.log(...[ "PASS", , 42 ]);
|
||||
@@ -295,7 +295,8 @@ keep_getter: {
|
||||
|
||||
keep_accessor: {
|
||||
options = {
|
||||
properties: true,
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
@@ -372,7 +373,8 @@ unused_var_side_effects: {
|
||||
|
||||
issue_4329: {
|
||||
options = {
|
||||
properties: true,
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
@@ -423,7 +425,7 @@ issue_4331: {
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4342: {
|
||||
@@ -447,3 +449,33 @@ issue_4342: {
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4345: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
...{
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
...{},
|
||||
42: "PASS",
|
||||
},
|
||||
}[42]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
...{
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
[42]: "PASS",
|
||||
},
|
||||
}[42]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user