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:
@@ -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(){
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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")) {
|
||||||
|
|||||||
@@ -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()
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
|||||||
@@ -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"]);',
|
||||||
|
|||||||
Reference in New Issue
Block a user