compress undefined property names (#2811)

- enforce property names as string
- handle `void 0` as `undefined` in `hoist_props` & `reduce_vars`
This commit is contained in:
Alex Lam S.L
2018-01-19 00:36:30 +08:00
committed by GitHub
parent 983e69128b
commit 082e004b87
6 changed files with 46 additions and 16 deletions

View File

@@ -689,8 +689,8 @@ var AST_Object = DEFNODE("Object", "properties", {
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", { var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
$documentation: "Base class for literal object properties", $documentation: "Base class for literal object properties",
$propdoc: { $propdoc: {
key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an AST_SymbolAccessor.", key: "[string|AST_SymbolAccessor] property name. For ObjectKeyVal this is a string. For getters and setters this is an AST_SymbolAccessor.",
value: "[AST_Node] property value. For setters and getters this is an AST_Accessor." value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function(){

View File

@@ -404,14 +404,15 @@ merge(Compressor.prototype, {
} }
function read_property(obj, key) { function read_property(obj, key) {
if (key instanceof AST_Constant) key = key.getValue(); key = get_value(key);
if (key instanceof AST_Node) return null; if (key instanceof AST_Node) return;
var value; var value;
if (obj instanceof AST_Array) { if (obj instanceof AST_Array) {
var elements = obj.elements; var elements = obj.elements;
if (key == "length") return make_node_from_constant(elements.length, obj); if (key == "length") return make_node_from_constant(elements.length, obj);
if (typeof key == "number" && key in elements) value = elements[key]; if (typeof key == "number" && key in elements) value = elements[key];
} else if (obj instanceof AST_Object) { } else if (obj instanceof AST_Object) {
key = "" + key;
var props = obj.properties; var props = obj.properties;
for (var i = props.length; --i >= 0;) { for (var i = props.length; --i >= 0;) {
var prop = props[i]; var prop = props[i];
@@ -1855,6 +1856,18 @@ merge(Compressor.prototype, {
})); }));
}; };
function get_value(key) {
if (key instanceof AST_Constant) {
return key.getValue();
}
if (key instanceof AST_UnaryPrefix
&& key.operator == "void"
&& key.expression instanceof AST_Constant) {
return;
}
return key;
}
function is_undefined(node, compressor) { function is_undefined(node, compressor) {
return node.is_undefined return node.is_undefined
|| node instanceof AST_Undefined || node instanceof AST_Undefined
@@ -3295,9 +3308,7 @@ merge(Compressor.prototype, {
if (node instanceof AST_PropAccess && node.expression instanceof AST_SymbolRef) { if (node instanceof AST_PropAccess && node.expression instanceof AST_SymbolRef) {
var defs = defs_by_id[node.expression.definition().id]; var defs = defs_by_id[node.expression.definition().id];
if (defs) { if (defs) {
var key = node.property; var def = defs.get(get_value(node.property));
if (key instanceof AST_Node) key = key.getValue();
var def = defs.get(key);
var sym = make_node(AST_SymbolRef, node, { var sym = make_node(AST_SymbolRef, node, {
name: def.name, name: def.name,
scope: node.expression.scope, scope: node.expression.scope,

View File

@@ -1349,11 +1349,8 @@ function OutputStream(options) {
function print_property_name(key, quote, output) { function print_property_name(key, quote, output) {
if (output.option("quote_keys")) { if (output.option("quote_keys")) {
output.print_string(key + ""); output.print_string(key);
} else if ((typeof key == "number" } else if ("" + +key == key && key >= 0) {
|| !output.option("beautify")
&& +key + "" == key)
&& parseFloat(key) >= 0) {
output.print(make_num(key)); output.print(make_num(key));
} else if (RESERVED_WORDS(key) ? !output.option("ie8") : is_identifier_string(key)) { } else if (RESERVED_WORDS(key) ? !output.option("ie8") : is_identifier_string(key)) {
if (quote && output.option("keep_quoted_props")) { if (quote && output.option("keep_quoted_props")) {

View File

@@ -1365,7 +1365,7 @@ function parse($TEXT, options) {
if (type == "name" && !is("punc", ":")) { if (type == "name" && !is("punc", ":")) {
var key = new AST_SymbolAccessor({ var key = new AST_SymbolAccessor({
start: S.token, start: S.token,
name: as_property_name(), name: "" + as_property_name(),
end: prev() end: prev()
}); });
if (name == "get") { if (name == "get") {
@@ -1391,7 +1391,7 @@ function parse($TEXT, options) {
a.push(new AST_ObjectKeyVal({ a.push(new AST_ObjectKeyVal({
start : start, start : start,
quote : start.quote, quote : start.quote,
key : name, key : "" + name,
value : expression(false), value : expression(false),
end : prev() end : prev()
})); }));

View File

@@ -664,3 +664,25 @@ issue_2519: {
} }
expect_stdout: "5.5" expect_stdout: "5.5"
} }
undefined_key: {
options = {
evaluate: true,
hoist_props: true,
join_vars: true,
passes: 4,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a, o = {};
o[a] = 1;
o.b = 2;
console.log(o[a] + o.b);
}
expect: {
console.log(3);
}
expect_stdout: "3"
}

View File

@@ -84,12 +84,12 @@ numeric_literal: {
' 0: 0,', ' 0: 0,',
' "-0": 1,', ' "-0": 1,',
' 42: 2,', ' 42: 2,',
' "42": 3,', ' 42: 3,',
' 37: 4,', ' 37: 4,',
' o: 5,', ' o: 5,',
' 1e42: 6,', ' 1e42: 6,',
' b: 7,', ' b: 7,',
' "1e+42": 8', ' 1e42: 8',
'};', '};',
'', '',
'console.log(obj[-0], obj[-""], obj["-0"]);', 'console.log(obj[-0], obj[-""], obj["-0"]);',