aboutsummaryrefslogtreecommitdiff
path: root/lib/compress.js
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2017-10-22 20:10:13 +0800
committerGitHub <noreply@github.com>2017-10-22 20:10:13 +0800
commit24aa07855bc608f29cca2a58a40af1988256b116 (patch)
tree52428c6db4496e196b2837dbe7b73324e32558b5 /lib/compress.js
parent5fd723f14394b74f899e7b33bc9084317bf01d7d (diff)
downloadtracifyjs-24aa07855bc608f29cca2a58a40af1988256b116.tar.gz
tracifyjs-24aa07855bc608f29cca2a58a40af1988256b116.zip
safer `properties` transform (#2391)
`{ a: x, b: y }.a` => `[ x, y ][0]` - `x` cannot be function containing `this` `[ x, y, z ][1]` => `(x, z, y)` - only if `z` is side-effect-free
Diffstat (limited to 'lib/compress.js')
-rw-r--r--lib/compress.js100
1 files changed, 73 insertions, 27 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 8bc0e262..eb0e2016 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -4452,20 +4452,56 @@ merge(Compressor.prototype, {
});
OPT(AST_Sub, function(self, compressor){
- var prop = self.property;
- if (prop instanceof AST_String && compressor.option("properties")) {
- prop = prop.getValue();
- if (is_identifier_string(prop)) {
- return make_node(AST_Dot, self, {
- expression : self.expression,
- property : prop
- }).optimize(compressor);
+ if (compressor.option("properties")) {
+ var prop = self.property;
+ if (prop instanceof AST_String) {
+ prop = prop.getValue();
+ if (is_identifier_string(prop)) {
+ return make_node(AST_Dot, self, {
+ expression : self.expression,
+ property : prop
+ }).optimize(compressor);
+ }
+ var v = parseFloat(prop);
+ if (!isNaN(v) && v.toString() == prop) {
+ self.property = make_node(AST_Number, self.property, {
+ value: v
+ });
+ }
}
- var v = parseFloat(prop);
- if (!isNaN(v) && v.toString() == prop) {
- self.property = make_node(AST_Number, self.property, {
- value: v
- });
+ if (prop instanceof AST_Number && self.expression instanceof AST_Array) {
+ prop = prop.getValue();
+ var elements = self.expression.elements;
+ if (prop in elements) {
+ var flatten = true;
+ var values = [];
+ for (var i = elements.length; --i > prop;) {
+ var value = elements[i].drop_side_effect_free(compressor);
+ if (value) {
+ values.unshift(value);
+ if (flatten && value.has_side_effects(compressor)) flatten = false;
+ }
+ }
+ var retValue = elements[prop];
+ retValue = retValue instanceof AST_Hole ? make_node(AST_Undefined, retValue) : retValue;
+ if (!flatten) values.unshift(retValue);
+ while (--i >= 0) {
+ var value = elements[i].drop_side_effect_free(compressor);
+ if (value) values.unshift(value);
+ else prop--;
+ }
+ if (flatten) {
+ values.push(retValue);
+ return make_sequence(self, values).optimize(compressor);
+ } else return make_node(AST_Sub, self, {
+ expression: make_node(AST_Array, self.expression, {
+ elements: values
+ }),
+ property: make_node(AST_Number, self.property, {
+ value: prop
+ })
+ });
+ }
}
}
if (is_lhs(self, compressor.parent())) return self;
@@ -4493,20 +4529,6 @@ merge(Compressor.prototype, {
if (def) {
return def.optimize(compressor);
}
- if (is_lhs(self, compressor.parent())) return self;
- if (compressor.option("unsafe") && self.expression instanceof AST_Object) {
- var values = self.expression.properties;
- for (var i = values.length; --i >= 0;) {
- if (values[i].key === self.property) {
- var value = values[i].value;
- if (value instanceof AST_Function ? value.contains_this() : value.has_side_effects(compressor)) break;
- var obj = self.expression.clone();
- obj.properties = obj.properties.slice();
- obj.properties.splice(i, 1);
- return make_sequence(self, [ obj, value ]).optimize(compressor);
- }
- }
- }
if (compressor.option("unsafe_proto")
&& self.expression instanceof AST_Dot
&& self.expression.property == "prototype") {
@@ -4529,6 +4551,30 @@ merge(Compressor.prototype, {
break;
}
}
+ if (is_lhs(self, compressor.parent())) return self;
+ if (compressor.option("properties") && self.expression instanceof AST_Object) {
+ var props = self.expression.properties;
+ for (var i = props.length; --i >= 0;) {
+ var prop = props[i];
+ if (prop.key === self.property) {
+ if (!all(props, function(prop) {
+ return prop instanceof AST_ObjectKeyVal;
+ })) break;
+ var value = prop.value;
+ if (value instanceof AST_Function && value.contains_this()) break;
+ return make_node(AST_Sub, self, {
+ expression: make_node(AST_Array, self.expression, {
+ elements: props.map(function(prop) {
+ return prop.value;
+ })
+ }),
+ property: make_node(AST_Number, self, {
+ value: i
+ })
+ }).optimize(compressor);
+ }
+ }
+ }
var ev = self.evaluate(compressor);
if (ev !== self) {
ev = make_node_from_constant(ev, self).optimize(compressor);