diff options
author | Alex Lam S.L <alexlamsl@gmail.com> | 2017-10-22 20:10:13 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-22 20:10:13 +0800 |
commit | 24aa07855bc608f29cca2a58a40af1988256b116 (patch) | |
tree | 52428c6db4496e196b2837dbe7b73324e32558b5 /lib/compress.js | |
parent | 5fd723f14394b74f899e7b33bc9084317bf01d7d (diff) | |
download | tracifyjs-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.js | 100 |
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); |