Destructuring consistency fixes (#1417)
- Use AST_Destructuring for lhf assignment patterns - Use AST_DefaultAssign for default assignments - Add more checks for lhs expressions - Add lots of testing - Cleanup ast (e.g. remove default property) - Fix #1402 based on a patch from @kzc - Refine spread allowance in array destructring pattern - Add destructuring AST tree checker
This commit is contained in:
committed by
Alex Lam S.L
parent
85c1cba760
commit
07734b000a
75
lib/ast.js
75
lib/ast.js
@@ -392,46 +392,56 @@ var AST_ArrowParametersOrSeq = DEFNODE("ArrowParametersOrSeq", "expressions", {
|
|||||||
// We don't want anything which doesn't belong in a destructuring
|
// We don't want anything which doesn't belong in a destructuring
|
||||||
var root = this;
|
var root = this;
|
||||||
return this.expressions.map(function to_fun_args(ex, _, __, default_seen_above) {
|
return this.expressions.map(function to_fun_args(ex, _, __, default_seen_above) {
|
||||||
|
var insert_default = function(ex, default_value) {
|
||||||
|
if (default_value) {
|
||||||
|
return new AST_DefaultAssign({
|
||||||
|
start: ex.start,
|
||||||
|
left: ex,
|
||||||
|
operator: "=",
|
||||||
|
right: default_value,
|
||||||
|
end: default_value.end
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return ex;
|
||||||
|
}
|
||||||
if (ex instanceof AST_Object) {
|
if (ex instanceof AST_Object) {
|
||||||
return new AST_Destructuring({
|
return insert_default(new AST_Destructuring({
|
||||||
start: ex.start,
|
start: ex.start,
|
||||||
end: ex.end,
|
end: ex.end,
|
||||||
is_array: false,
|
is_array: false,
|
||||||
default: default_seen_above,
|
|
||||||
names: ex.properties.map(to_fun_args)
|
names: ex.properties.map(to_fun_args)
|
||||||
});
|
}), default_seen_above);
|
||||||
} else if (ex instanceof AST_ObjectKeyVal) {
|
} else if (ex instanceof AST_ObjectKeyVal) {
|
||||||
if (ex.key instanceof AST_SymbolRef) {
|
if (ex.key instanceof AST_SymbolRef) {
|
||||||
ex.key = to_fun_args(ex.key, 0, [ex.key], ex.default);
|
ex.key = to_fun_args(ex.key, 0, [ex.key]);
|
||||||
}
|
}
|
||||||
ex.value = to_fun_args(ex.value, 0, [ex.key], ex.default);
|
ex.value = to_fun_args(ex.value, 0, [ex.key]);
|
||||||
return ex;
|
return insert_default(ex, default_seen_above);
|
||||||
} else if (ex instanceof AST_Hole) {
|
} else if (ex instanceof AST_Hole) {
|
||||||
return ex;
|
return ex;
|
||||||
} else if (ex instanceof AST_Destructuring) {
|
} else if (ex instanceof AST_Destructuring) {
|
||||||
if (ex.names.length == 0)
|
if (ex.names.length == 0)
|
||||||
croak("Invalid destructuring function parameter", ex.start.line, ex.start.col);
|
croak("Invalid destructuring function parameter", ex.start.line, ex.start.col);
|
||||||
ex.names = ex.names.map(to_fun_args);
|
ex.names = ex.names.map(to_fun_args);
|
||||||
return ex;
|
return insert_default(ex, default_seen_above);
|
||||||
} else if (ex instanceof AST_SymbolRef) {
|
} else if (ex instanceof AST_SymbolRef) {
|
||||||
return new AST_SymbolFunarg({
|
return insert_default(new AST_SymbolFunarg({
|
||||||
name: ex.name,
|
name: ex.name,
|
||||||
default: default_seen_above,
|
|
||||||
start: ex.start,
|
start: ex.start,
|
||||||
end: ex.end
|
end: ex.end
|
||||||
});
|
}), default_seen_above);
|
||||||
} else if (ex instanceof AST_Expansion) {
|
} else if (ex instanceof AST_Expansion) {
|
||||||
return ex;
|
ex.expression = to_fun_args(ex.expression);
|
||||||
|
return insert_default(ex, default_seen_above);
|
||||||
} else if (ex instanceof AST_Array) {
|
} else if (ex instanceof AST_Array) {
|
||||||
return new AST_Destructuring({
|
return insert_default(new AST_Destructuring({
|
||||||
start: ex.start,
|
start: ex.start,
|
||||||
end: ex.end,
|
end: ex.end,
|
||||||
is_array: true,
|
is_array: true,
|
||||||
default: default_seen_above,
|
|
||||||
names: ex.elements.map(to_fun_args)
|
names: ex.elements.map(to_fun_args)
|
||||||
});
|
}), default_seen_above);
|
||||||
} else if (ex instanceof AST_Assign) {
|
} else if (ex instanceof AST_Assign) {
|
||||||
return to_fun_args(ex.left, undefined, undefined, ex.right);
|
return insert_default(to_fun_args(ex.left, undefined, undefined, ex.right), default_seen_above);
|
||||||
} else {
|
} else {
|
||||||
croak("Invalid function parameter", ex.start.line, ex.start.col);
|
croak("Invalid function parameter", ex.start.line, ex.start.col);
|
||||||
}
|
}
|
||||||
@@ -447,7 +457,7 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator",
|
|||||||
$propdoc: {
|
$propdoc: {
|
||||||
is_generator: "[boolean] is generatorFn or not",
|
is_generator: "[boolean] is generatorFn or not",
|
||||||
name: "[AST_SymbolDeclaration?] the name of this function",
|
name: "[AST_SymbolDeclaration?] the name of this function",
|
||||||
argnames: "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion*] array of function arguments, destructurings, or expanding arguments",
|
argnames: "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion|AST_DefaultAssign*] array of function arguments, destructurings, or expanding arguments",
|
||||||
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
|
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
|
||||||
},
|
},
|
||||||
args_as_names: function () {
|
args_as_names: function () {
|
||||||
@@ -489,12 +499,11 @@ var AST_Defun = DEFNODE("Defun", null, {
|
|||||||
}, AST_Lambda);
|
}, AST_Lambda);
|
||||||
|
|
||||||
/* -----[ DESTRUCTURING ]----- */
|
/* -----[ DESTRUCTURING ]----- */
|
||||||
var AST_Destructuring = DEFNODE("Destructuring", "names is_array default", {
|
var AST_Destructuring = DEFNODE("Destructuring", "names is_array", {
|
||||||
$documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names",
|
$documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
"names": "[AST_Destructuring|AST_Expansion|AST_Hole|AST_ObjectKeyVal|AST_Symbol] Array of properties or elements",
|
"names": "[AST_Node*] Array of properties or elements",
|
||||||
"is_array": "[Boolean] Whether the destructuring represents an object or array",
|
"is_array": "[Boolean] Whether the destructuring represents an object or array"
|
||||||
"default": "[AST_Node?] Default assign value"
|
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
@@ -672,7 +681,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
|
|||||||
var AST_Catch = DEFNODE("Catch", "argname", {
|
var AST_Catch = DEFNODE("Catch", "argname", {
|
||||||
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
argname: "[AST_SymbolCatch] symbol for the exception"
|
argname: "[AST_SymbolCatch|AST_Destructuring|AST_Expansion|AST_DefaultAssign] symbol for the exception"
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
@@ -957,6 +966,10 @@ var AST_Assign = DEFNODE("Assign", null, {
|
|||||||
$documentation: "An assignment expression — `a = b + 5`",
|
$documentation: "An assignment expression — `a = b + 5`",
|
||||||
}, AST_Binary);
|
}, AST_Binary);
|
||||||
|
|
||||||
|
var AST_DefaultAssign = DEFNODE("DefaultAssign", null, {
|
||||||
|
$documentation: "A default assignment expression like in `(a = 3) => a`"
|
||||||
|
}, AST_Binary);
|
||||||
|
|
||||||
/* -----[ LITERALS ]----- */
|
/* -----[ LITERALS ]----- */
|
||||||
|
|
||||||
var AST_Array = DEFNODE("Array", "elements", {
|
var AST_Array = DEFNODE("Array", "elements", {
|
||||||
@@ -991,8 +1004,7 @@ 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|AST_Node] the property name converted to a string for ObjectKeyVal. For setters, getters and computed property this is an arbitrary AST_Node",
|
key: "[string|AST_Node] the property name converted to a string for ObjectKeyVal. For setters, getters and computed property this is an arbitrary AST_Node",
|
||||||
value: "[AST_Node] property value. For setters and getters this is an AST_Function.",
|
value: "[AST_Node] property value. For setters and getters this is an AST_Function."
|
||||||
default: "[AST_Expression] The default for this parameter, only used when nested inside a binding pattern"
|
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
@@ -1003,11 +1015,10 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote default", {
|
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
||||||
$documentation: "A key: value object property",
|
$documentation: "A key: value object property",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
quote: "[string] the original quote character",
|
quote: "[string] the original quote character"
|
||||||
default: "[AST_Expression] The default parameter value, only used when nested inside a binding pattern"
|
|
||||||
}
|
}
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
|
|
||||||
@@ -1066,19 +1077,13 @@ var AST_ClassExpression = DEFNODE("ClassExpression", null, {
|
|||||||
$documentation: "A class expression."
|
$documentation: "A class expression."
|
||||||
}, AST_Class);
|
}, AST_Class);
|
||||||
|
|
||||||
var AST_Symbol = DEFNODE("Symbol", "scope name thedef default", {
|
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[string] name of this symbol",
|
name: "[string] name of this symbol",
|
||||||
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
|
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
|
||||||
thedef: "[SymbolDef/S] the definition of this symbol",
|
thedef: "[SymbolDef/S] the definition of this symbol"
|
||||||
default: "[AST_Expression] The default parameter value, only used when nested inside a binding pattern"
|
|
||||||
},
|
},
|
||||||
$documentation: "Base class for all symbols",
|
$documentation: "Base class for all symbols"
|
||||||
_walk: function (visitor) {
|
|
||||||
return visitor._visit(this, function() {
|
|
||||||
if (this.default) this.default._walk(visitor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var AST_NewTarget = DEFNODE("NewTarget", null, {
|
var AST_NewTarget = DEFNODE("NewTarget", null, {
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ function Compressor(options, false_by_default) {
|
|||||||
pure_funcs : null,
|
pure_funcs : null,
|
||||||
negate_iife : !false_by_default,
|
negate_iife : !false_by_default,
|
||||||
screw_ie8 : true,
|
screw_ie8 : true,
|
||||||
|
ecma : 5,
|
||||||
drop_console : false,
|
drop_console : false,
|
||||||
angular : false,
|
angular : false,
|
||||||
warnings : true,
|
warnings : true,
|
||||||
@@ -2317,7 +2318,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!fun) return self;
|
if (!fun) return self;
|
||||||
var args = fun.argnames.map(function(arg, i){
|
var args = fun.argnames.map(function(arg, i){
|
||||||
return make_node(AST_String, self.args[i], {
|
return make_node(AST_String, self.args[i], {
|
||||||
value: arg.print_to_string()
|
value: arg.print_to_string({ecma: compressor.option("ecma")})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
var code = OutputStream();
|
var code = OutputStream();
|
||||||
@@ -2886,6 +2887,22 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
OPT(AST_DefaultAssign, function(self, compressor){
|
||||||
|
if (!compressor.option("evaluate")) {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
var evaluateRight = self.right.evaluate(compressor);
|
||||||
|
|
||||||
|
// `[x = undefined] = foo` ---> `[x] = foo`
|
||||||
|
if (evaluateRight.length > 1 && evaluateRight[1] === undefined) {
|
||||||
|
self = self.left;
|
||||||
|
} else {
|
||||||
|
self.right = evaluateRight[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
});
|
||||||
|
|
||||||
OPT(AST_Conditional, function(self, compressor){
|
OPT(AST_Conditional, function(self, compressor){
|
||||||
if (!compressor.option("conditionals")) return self;
|
if (!compressor.option("conditionals")) return self;
|
||||||
if (self.condition instanceof AST_Seq) {
|
if (self.condition instanceof AST_Seq) {
|
||||||
|
|||||||
@@ -641,13 +641,10 @@ function OutputStream(options) {
|
|||||||
|| p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
|| p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||||
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||||
|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|
|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|
||||||
|| (p instanceof AST_SymbolConst && p.default === this) // const { xCover = (0, function() {}) }
|
|
||||||
|| (p instanceof AST_SymbolLet && p.default === this) // let { xCover = (0, function() {}) }
|
|
||||||
|| (p instanceof AST_SymbolVar && p.default === this) // var { xCover = (0, function() {}) }
|
|
||||||
|| (p instanceof AST_SymbolCatch && p.default === this) // } catch (xCover = (0, function() {}) ) {
|
|
||||||
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
|
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||||
* ==> 20 (side effect, set a := 10 and b := 20) */
|
* ==> 20 (side effect, set a := 10 and b := 20) */
|
||||||
|| p instanceof AST_Arrow // x => (x, x)
|
|| p instanceof AST_Arrow // x => (x, x)
|
||||||
|
|| p instanceof AST_DefaultAssign // x => (x = (0, function(){}))
|
||||||
;
|
;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -761,6 +758,9 @@ function OutputStream(options) {
|
|||||||
// (a = foo)["prop"] —or— (a = foo).prop
|
// (a = foo)["prop"] —or— (a = foo).prop
|
||||||
if (p instanceof AST_PropAccess && p.expression === this)
|
if (p instanceof AST_PropAccess && p.expression === this)
|
||||||
return true;
|
return true;
|
||||||
|
// ({a, b} = {a: 1, b: 2}), a destructuring assignment
|
||||||
|
if (this instanceof AST_Assign && this.left instanceof AST_Destructuring && this.left.is_array === false)
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ PRINTERS ]----- */
|
/* -----[ PRINTERS ]----- */
|
||||||
@@ -789,12 +789,6 @@ function OutputStream(options) {
|
|||||||
output.comma();
|
output.comma();
|
||||||
})
|
})
|
||||||
output.print(self.is_array ? "]" : "}");
|
output.print(self.is_array ? "]" : "}");
|
||||||
if (self.default) {
|
|
||||||
output.space();
|
|
||||||
output.print('=');
|
|
||||||
output.space();
|
|
||||||
self.default.print(output)
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFPRINT(AST_Debugger, function(self, output){
|
DEFPRINT(AST_Debugger, function(self, output){
|
||||||
@@ -1003,7 +997,7 @@ function OutputStream(options) {
|
|||||||
parent instanceof AST_Unary ||
|
parent instanceof AST_Unary ||
|
||||||
(parent instanceof AST_Call && self === parent.expression);
|
(parent instanceof AST_Call && self === parent.expression);
|
||||||
if (needs_parens) { output.print("(") }
|
if (needs_parens) { output.print("(") }
|
||||||
if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol && !self.argnames[0].default) {
|
if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) {
|
||||||
self.argnames[0].print(output);
|
self.argnames[0].print(output);
|
||||||
} else {
|
} else {
|
||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
@@ -1497,15 +1491,27 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
DEFPRINT(AST_ObjectKeyVal, function(self, output){
|
DEFPRINT(AST_ObjectKeyVal, function(self, output){
|
||||||
function get_name(self) {
|
function get_name(self) {
|
||||||
var def = self.value.definition();
|
var def = self.definition();
|
||||||
return def ? def.mangled_name || def.name : self.value.name;
|
return def ? def.mangled_name || def.name : self.name;
|
||||||
}
|
}
|
||||||
if (output.option("shorthand") &&
|
|
||||||
|
var allowShortHand = output.option("shorthand");
|
||||||
|
if (allowShortHand &&
|
||||||
self.value instanceof AST_Symbol &&
|
self.value instanceof AST_Symbol &&
|
||||||
is_identifier_string(self.key) &&
|
is_identifier_string(self.key) &&
|
||||||
get_name(self) === self.key
|
get_name(self.value) === self.key
|
||||||
) {
|
) {
|
||||||
self.print_property_name(self.key, self.quote, output);
|
self.print_property_name(self.key, self.quote, output);
|
||||||
|
|
||||||
|
} else if (allowShortHand &&
|
||||||
|
self.value instanceof AST_DefaultAssign &&
|
||||||
|
self.value.left instanceof AST_Symbol &&
|
||||||
|
is_identifier_string(self.key) &&
|
||||||
|
get_name(self.value.left) === self.key
|
||||||
|
) {
|
||||||
|
self.print_property_name(self.key, self.quote, output);
|
||||||
|
output.print("=");
|
||||||
|
self.value.right.print(output);
|
||||||
} else {
|
} else {
|
||||||
if (!(self.key instanceof AST_Node)) {
|
if (!(self.key instanceof AST_Node)) {
|
||||||
self.print_property_name(self.key, self.quote, output);
|
self.print_property_name(self.key, self.quote, output);
|
||||||
@@ -1517,12 +1523,6 @@ function OutputStream(options) {
|
|||||||
output.colon();
|
output.colon();
|
||||||
self.value.print(output);
|
self.value.print(output);
|
||||||
}
|
}
|
||||||
if (self.default) {
|
|
||||||
output.space();
|
|
||||||
output.print('=');
|
|
||||||
output.space();
|
|
||||||
self.default.print(output);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, self, output) {
|
AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, self, output) {
|
||||||
if (self.static) {
|
if (self.static) {
|
||||||
@@ -1573,12 +1573,6 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
DEFPRINT(AST_SymbolDeclaration, function(self, output){
|
DEFPRINT(AST_SymbolDeclaration, function(self, output){
|
||||||
self._do_print(output);
|
self._do_print(output);
|
||||||
if (self.default) {
|
|
||||||
output.space();
|
|
||||||
output.print('=');
|
|
||||||
output.space();
|
|
||||||
self.default.print(output)
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Undefined, function(self, output){
|
DEFPRINT(AST_Undefined, function(self, output){
|
||||||
output.print("void 0");
|
output.print("void 0");
|
||||||
|
|||||||
175
lib/parse.js
175
lib/parse.js
@@ -1106,11 +1106,9 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
case "export":
|
case "export":
|
||||||
return export_();
|
return export_();
|
||||||
|
|
||||||
default:
|
|
||||||
unexpected();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unexpected();
|
||||||
});
|
});
|
||||||
|
|
||||||
function labeled_statement() {
|
function labeled_statement() {
|
||||||
@@ -1384,7 +1382,13 @@ function parse($TEXT, options) {
|
|||||||
if (is("operator", "=") && expand === false) {
|
if (is("operator", "=") && expand === false) {
|
||||||
used_parameters.mark_default_assignment(S.token);
|
used_parameters.mark_default_assignment(S.token);
|
||||||
next();
|
next();
|
||||||
param.default = expression(false);
|
param = new AST_DefaultAssign({
|
||||||
|
start: param.start,
|
||||||
|
left: param,
|
||||||
|
operator: "=",
|
||||||
|
right: expression(false),
|
||||||
|
end: S.token
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expand !== false) {
|
if (expand !== false) {
|
||||||
@@ -1458,7 +1462,13 @@ function parse($TEXT, options) {
|
|||||||
if (is("operator", "=") && is_expand === false) {
|
if (is("operator", "=") && is_expand === false) {
|
||||||
used_parameters.mark_default_assignment(S.token);
|
used_parameters.mark_default_assignment(S.token);
|
||||||
next();
|
next();
|
||||||
elements[elements.length - 1].default = expression(false);
|
elements[elements.length - 1] = new AST_DefaultAssign({
|
||||||
|
start: elements[elements.length - 1].start,
|
||||||
|
left: elements[elements.length - 1],
|
||||||
|
operator: "=",
|
||||||
|
right: expression(false),
|
||||||
|
end: S.token
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (is_expand) {
|
if (is_expand) {
|
||||||
if (!is("punc", "]")) {
|
if (!is("punc", "]")) {
|
||||||
@@ -1489,10 +1499,15 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
if (is("name") && (is_token(peek(), "punc") || is_token(peek(), "operator")) && [",", "}", "="].indexOf(peek().value) !== -1) {
|
if (is("name") && (is_token(peek(), "punc") || is_token(peek(), "operator")) && [",", "}", "="].indexOf(peek().value) !== -1) {
|
||||||
used_parameters.add_parameter(S.token);
|
used_parameters.add_parameter(S.token);
|
||||||
elements.push(new symbol_type({
|
elements.push(new AST_ObjectKeyVal({
|
||||||
start: S.token,
|
start: prev(),
|
||||||
name: S.token.value,
|
key: S.token.value,
|
||||||
end: S.token
|
value: new symbol_type({
|
||||||
|
start: S.token,
|
||||||
|
name: S.token.value,
|
||||||
|
end: S.token
|
||||||
|
}),
|
||||||
|
end: prev()
|
||||||
}));
|
}));
|
||||||
next();
|
next();
|
||||||
} else if (is("punc", "}")) {
|
} else if (is("punc", "}")) {
|
||||||
@@ -1503,9 +1518,14 @@ function parse($TEXT, options) {
|
|||||||
if (property === null) {
|
if (property === null) {
|
||||||
unexpected(prev());
|
unexpected(prev());
|
||||||
} else if (prev().type === "name" && !is("punc", ":")) {
|
} else if (prev().type === "name" && !is("punc", ":")) {
|
||||||
elements.push(new AST_SymbolFunarg({
|
elements.push(new AST_ObjectKeyVal({
|
||||||
start: prev(),
|
start: prev(),
|
||||||
name: property_token,
|
key: property,
|
||||||
|
value: new symbol_type({
|
||||||
|
start: prev(),
|
||||||
|
name: property,
|
||||||
|
end: prev()
|
||||||
|
}),
|
||||||
end: prev()
|
end: prev()
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
@@ -1513,16 +1533,22 @@ function parse($TEXT, options) {
|
|||||||
elements.push(new AST_ObjectKeyVal({
|
elements.push(new AST_ObjectKeyVal({
|
||||||
start: property_token,
|
start: property_token,
|
||||||
quote: property_token.quote,
|
quote: property_token.quote,
|
||||||
end: prev(),
|
|
||||||
key: property,
|
key: property,
|
||||||
value: binding_element(used_parameters, symbol_type)
|
value: binding_element(used_parameters, symbol_type),
|
||||||
|
end: prev()
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is("operator", "=")) {
|
if (is("operator", "=")) {
|
||||||
used_parameters.mark_default_assignment(S.token);
|
used_parameters.mark_default_assignment(S.token);
|
||||||
next();
|
next();
|
||||||
elements[elements.length - 1].default = expression(false);
|
elements[elements.length - 1].value = new AST_DefaultAssign({
|
||||||
|
start: elements[elements.length - 1].value.start,
|
||||||
|
left: elements[elements.length - 1].value,
|
||||||
|
operator: "=",
|
||||||
|
right: expression(false),
|
||||||
|
end: S.token
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect("}");
|
expect("}");
|
||||||
@@ -1558,7 +1584,7 @@ function parse($TEXT, options) {
|
|||||||
next();
|
next();
|
||||||
a.push(new AST_Expansion({
|
a.push(new AST_Expansion({
|
||||||
start: prev(),
|
start: prev(),
|
||||||
expression: binding_element(undefined, AST_SymbolFunarg),
|
expression: expression(false),
|
||||||
end: S.token,
|
end: S.token,
|
||||||
}));
|
}));
|
||||||
if (!is("punc", ")")) {
|
if (!is("punc", ")")) {
|
||||||
@@ -1943,7 +1969,7 @@ function parse($TEXT, options) {
|
|||||||
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||||
} else if (is("expand", "...")) {
|
} else if (is("expand", "...")) {
|
||||||
next();
|
next();
|
||||||
a.push(new AST_Expansion({start: S.token, expression: expression(),end: S.token}));
|
a.push(new AST_Expansion({start: prev(), expression: expression(),end: S.token}));
|
||||||
} else {
|
} else {
|
||||||
a.push(expression(false));
|
a.push(expression(false));
|
||||||
}
|
}
|
||||||
@@ -1970,63 +1996,51 @@ function parse($TEXT, options) {
|
|||||||
start = S.token;
|
start = S.token;
|
||||||
var type = start.type;
|
var type = start.type;
|
||||||
var name = as_property_name();
|
var name = as_property_name();
|
||||||
|
var value;
|
||||||
|
|
||||||
|
// Check property and fetch value
|
||||||
if (!is("punc", ":")) {
|
if (!is("punc", ":")) {
|
||||||
var concise = concise_method_or_getset(name, start);
|
var concise = concise_method_or_getset(name, start);
|
||||||
if (concise) {
|
if (concise) {
|
||||||
a.push(concise);
|
a.push(concise);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!(start.type !== name)) {
|
||||||
|
unexpected(S.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
value = new AST_SymbolRef({
|
||||||
|
start: prev(),
|
||||||
|
name: name,
|
||||||
|
end: prev()
|
||||||
|
});
|
||||||
} else if (name === null) {
|
} else if (name === null) {
|
||||||
unexpected(prev());
|
unexpected(prev());
|
||||||
|
} else {
|
||||||
|
next(); // `:` - see first condition
|
||||||
|
value = expression(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == "punc" && start.value == "[") {
|
// Check for default value and alter value accordingly if necessary
|
||||||
expect(":");
|
|
||||||
a.push(new AST_ObjectKeyVal({
|
|
||||||
start: start,
|
|
||||||
key: name,
|
|
||||||
value: expression(false),
|
|
||||||
end: prev()
|
|
||||||
}));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is("operator", "=")) {
|
if (is("operator", "=")) {
|
||||||
next();
|
next();
|
||||||
a.push(new AST_Assign({
|
value = new AST_Assign({
|
||||||
start: start,
|
start: start,
|
||||||
// Symbol class doesn't matter. This is only meant to carry the symbol name into .as_params() since this is not normally valid.
|
left: value,
|
||||||
left: new AST_SymbolRef({
|
|
||||||
start: start,
|
|
||||||
end: start,
|
|
||||||
name: name
|
|
||||||
}),
|
|
||||||
operator: "=",
|
operator: "=",
|
||||||
right: expression(false),
|
right: expression(false),
|
||||||
end: prev()
|
end: prev()
|
||||||
}));
|
});
|
||||||
} else if (!is("punc", ":")) {
|
|
||||||
// It's one of those object destructurings, the value is its own name
|
|
||||||
a.push(new AST_ObjectKeyVal({
|
|
||||||
start: start,
|
|
||||||
key: name,
|
|
||||||
value: new AST_SymbolRef({
|
|
||||||
start: start,
|
|
||||||
end: prev(),
|
|
||||||
name: name
|
|
||||||
}),
|
|
||||||
end: start,
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
expect(":");
|
|
||||||
a.push(new AST_ObjectKeyVal({
|
|
||||||
start : start,
|
|
||||||
quote : start.quote,
|
|
||||||
key : name,
|
|
||||||
value : expression(false),
|
|
||||||
end : prev()
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create property
|
||||||
|
a.push(new AST_ObjectKeyVal({
|
||||||
|
start: start,
|
||||||
|
quote: start.quote,
|
||||||
|
key: name,
|
||||||
|
value: value,
|
||||||
|
end: prev()
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
return new AST_Object({ properties: a })
|
return new AST_Object({ properties: a })
|
||||||
@@ -2493,6 +2507,55 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
if (is("operator") && ASSIGNMENT(val)) {
|
if (is("operator") && ASSIGNMENT(val)) {
|
||||||
if (is_assignable(left)) {
|
if (is_assignable(left)) {
|
||||||
|
|
||||||
|
var walk = function(node) {
|
||||||
|
var newNode;
|
||||||
|
if (node instanceof AST_Object) {
|
||||||
|
newNode = new AST_Destructuring({
|
||||||
|
start: node.start,
|
||||||
|
names: node.properties.map(walk),
|
||||||
|
is_array: false,
|
||||||
|
end: node.end
|
||||||
|
});
|
||||||
|
node = newNode;
|
||||||
|
} else if (node instanceof AST_Array) {
|
||||||
|
var names = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < node.elements.length; i++) {
|
||||||
|
// Only allow expansion as last element
|
||||||
|
if (node.elements[i] instanceof AST_Expansion) {
|
||||||
|
if (i + 1 !== node.elements.length) {
|
||||||
|
token_error(node.elements[i].start, "SyntaxError: Spread must the be last element in destructuring array");
|
||||||
|
}
|
||||||
|
node.elements[i].expression = walk(node.elements[i].expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
names.push(walk(node.elements[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode = new AST_Destructuring({
|
||||||
|
start: node.start,
|
||||||
|
names: names,
|
||||||
|
is_array: true,
|
||||||
|
end: node.end
|
||||||
|
});
|
||||||
|
node = newNode;
|
||||||
|
} else if (node instanceof AST_ObjectProperty) {
|
||||||
|
node.value = walk(node.value);
|
||||||
|
} else if (node instanceof AST_Assign) {
|
||||||
|
node = new AST_DefaultAssign({
|
||||||
|
start: node.start,
|
||||||
|
left: node.left,
|
||||||
|
operator: "=",
|
||||||
|
right: node.right,
|
||||||
|
end: node.end
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
left = walk(left);
|
||||||
|
|
||||||
next();
|
next();
|
||||||
return new AST_Assign({
|
return new AST_Assign({
|
||||||
start : start,
|
start : start,
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ destructuring_objects: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destructuring_objects_trailing_elision: {
|
destructuring_objects_trailing_elision: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
var {cc,} = foo;
|
var {cc,} = foo;
|
||||||
}
|
}
|
||||||
@@ -57,6 +60,9 @@ destructuring_objects_trailing_elision: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nested_destructuring_objects: {
|
nested_destructuring_objects: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
const [{a},b] = c;
|
const [{a},b] = c;
|
||||||
let [{a},b] = c;
|
let [{a},b] = c;
|
||||||
@@ -66,6 +72,9 @@ nested_destructuring_objects: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destructuring_constdef_in_loops: {
|
destructuring_constdef_in_loops: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
for (const [x,y] in pairs);
|
for (const [x,y] in pairs);
|
||||||
for (const [a] = 0;;);
|
for (const [a] = 0;;);
|
||||||
@@ -75,6 +84,9 @@ destructuring_constdef_in_loops: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destructuring_letdef_in_loops: {
|
destructuring_letdef_in_loops: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
for (let [x,y] in pairs);
|
for (let [x,y] in pairs);
|
||||||
for (let [a] = 0;;);
|
for (let [a] = 0;;);
|
||||||
@@ -84,6 +96,9 @@ destructuring_letdef_in_loops: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destructuring_vardef_in_loops: {
|
destructuring_vardef_in_loops: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
for (var [x,y] in pairs);
|
for (var [x,y] in pairs);
|
||||||
for (var [a] = 0;;);
|
for (var [a] = 0;;);
|
||||||
@@ -200,3 +215,39 @@ destructuring_remove_unused_2: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object_destructuring_may_need_parentheses: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({a, b} = {a: 1, b: 2});
|
||||||
|
}
|
||||||
|
expect_exact: "({a,b}={a:1,b:2});"
|
||||||
|
}
|
||||||
|
|
||||||
|
destructuring_with_undefined_as_default_assignment: {
|
||||||
|
options = {
|
||||||
|
evaluate: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
[foo = undefined] = bar;
|
||||||
|
[foo = void 0] = bar;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
[foo] = bar;
|
||||||
|
[foo] = bar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destructuring_dont_evaluate_with_undefined_as_default_assignment: {
|
||||||
|
options = {
|
||||||
|
evaluate: false
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
[foo = undefined] = bar;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
[foo = void 0] = bar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ compress_new_function: {
|
|||||||
|
|
||||||
compress_new_function_with_destruct: {
|
compress_new_function_with_destruct: {
|
||||||
options = {
|
options = {
|
||||||
unsafe: true
|
unsafe: true,
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
new Function("aa, [bb]", 'return aa;');
|
new Function("aa, [bb]", 'return aa;');
|
||||||
|
|||||||
@@ -82,3 +82,19 @@ new_with_unary_prefix: {
|
|||||||
}
|
}
|
||||||
expect_exact: 'var bar=(+new Date).toString(32);';
|
expect_exact: 'var bar=(+new Date).toString(32);';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_with_assignement_expression: {
|
||||||
|
options = {
|
||||||
|
evaluate: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
new x(a = 5 * 2, b = [1, 2, 3], c = {a: "a", b: "b", cd: "c" + "d"});
|
||||||
|
new y([a, b] = [3, 4]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
new x(a = 10, b = [1, 2, 3], c = {a: "a", b: "b", cd: "cd"});
|
||||||
|
new y([a, b] = [3, 4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -170,6 +170,9 @@ shorthand_properties: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
concise_methods: {
|
concise_methods: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
x = {
|
x = {
|
||||||
foo(a, b) {
|
foo(a, b) {
|
||||||
@@ -299,6 +302,9 @@ concise_methods_and_mangle_props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
concise_generators: {
|
concise_generators: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
x = {
|
x = {
|
||||||
*foo(a, b) {
|
*foo(a, b) {
|
||||||
|
|||||||
@@ -119,6 +119,9 @@ destructuring_arguments_2: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destructuring_arguments_3: {
|
destructuring_arguments_3: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
function fn3({x: {y: {z: {} = 42}}}) {}
|
function fn3({x: {y: {z: {} = 42}}}) {}
|
||||||
const { cover = (function () {}), xCover = (0, function() {}) } = {};
|
const { cover = (function () {}), xCover = (0, function() {}) } = {};
|
||||||
@@ -129,6 +132,9 @@ destructuring_arguments_3: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default_arguments: {
|
default_arguments: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
function x(a = 6) { }
|
function x(a = 6) { }
|
||||||
function x(a = (6 + 5)) { }
|
function x(a = (6 + 5)) { }
|
||||||
@@ -138,6 +144,9 @@ default_arguments: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default_values_in_destructurings: {
|
default_values_in_destructurings: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
function x({a=(4), b}) {}
|
function x({a=(4), b}) {}
|
||||||
function x([b, c=(12)]) {}
|
function x([b, c=(12)]) {}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
catch_destructuring_with_sequence: {
|
catch_destructuring_with_sequence: {
|
||||||
|
beautify = {
|
||||||
|
ecma: 6
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
try {
|
try {
|
||||||
throw {};
|
throw {};
|
||||||
|
|||||||
@@ -27,4 +27,253 @@ describe("arguments", function() {
|
|||||||
assert.strictEqual(ast.body[0].body[0].uses_arguments, true);
|
assert.strictEqual(ast.body[0].body[0].uses_arguments, true);
|
||||||
assert.strictEqual(ast.body[0].body[0].body[0].uses_arguments, false);
|
assert.strictEqual(ast.body[0].body[0].body[0].uses_arguments, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should parse a function containing default assignment correctly", function() {
|
||||||
|
var ast = UglifyJS.parse("function foo(a = 123) {}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// First argument
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].argnames[0].left instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].operator, "=");
|
||||||
|
assert(ast.body[0].argnames[0].right instanceof UglifyJS.AST_Number);
|
||||||
|
|
||||||
|
ast = UglifyJS.parse("function foo(a = a) {}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// First argument
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].argnames[0].left instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].operator, "=");
|
||||||
|
assert(ast.body[0].argnames[0].right instanceof UglifyJS.AST_SymbolRef);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should parse a function containing default assignments in destructuring correctly", function() {
|
||||||
|
var ast = UglifyJS.parse("function foo([a = 123]) {}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// First argument
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].is_array, true);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names.length, 1);
|
||||||
|
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].argnames[0].names[0].left instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[0].operator, "=");
|
||||||
|
assert(ast.body[0].argnames[0].names[0].right instanceof UglifyJS.AST_Number);
|
||||||
|
|
||||||
|
|
||||||
|
ast = UglifyJS.parse("function foo({a = 123}) {}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// First argument
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].is_array, false);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names.length, 1);
|
||||||
|
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[0].key, "a");
|
||||||
|
|
||||||
|
// Property a of first argument
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value.left instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[0].value.operator, "=");
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value.right instanceof UglifyJS.AST_Number);
|
||||||
|
|
||||||
|
|
||||||
|
ast = UglifyJS.parse("function foo({a: a = 123}) {}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// First argument
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].is_array, false);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names.length, 1);
|
||||||
|
|
||||||
|
// Content destructuring of first argument
|
||||||
|
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[0].key, "a");
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
||||||
|
|
||||||
|
// Property a of first argument
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value.left instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[0].value.operator, "=");
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value.right instanceof UglifyJS.AST_Number);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should parse a function containing default assignments in complex destructuring correctly", function() {
|
||||||
|
var ast = UglifyJS.parse("function foo([a, [b = 123]]){}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first argument
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].is_array, true);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names.length, 2);
|
||||||
|
|
||||||
|
// Check whole destructuring structure of first argument
|
||||||
|
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].argnames[0].names[1] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[1].is_array, true);
|
||||||
|
|
||||||
|
// Check content of second destructuring element (which is the nested destructuring pattern)
|
||||||
|
assert(ast.body[0].argnames[0].names[1].names[0] instanceof UglifyJS.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].argnames[0].names[1].names[0].left instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[1].names[0].operator, "=");
|
||||||
|
assert(ast.body[0].argnames[0].names[1].names[0].right instanceof UglifyJS.AST_Number);
|
||||||
|
|
||||||
|
|
||||||
|
ast = UglifyJS.parse("function foo([a, {b: c = 123}]){}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first argument
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].is_array, true);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names.length, 2);
|
||||||
|
|
||||||
|
// Check whole destructuring structure of first argument
|
||||||
|
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].argnames[0].names[1] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[1].is_array, false);
|
||||||
|
|
||||||
|
// Check content of second destructuring element (which is the nested destructuring pattern)
|
||||||
|
assert(ast.body[0].argnames[0].names[1].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[1].names[0].key, "b");
|
||||||
|
assert(ast.body[0].argnames[0].names[1].names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
||||||
|
|
||||||
|
// Property b of second argument
|
||||||
|
assert(ast.body[0].argnames[0].names[1].names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].argnames[0].names[1].names[0].value.left instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[1].names[0].value.operator, "=");
|
||||||
|
assert(ast.body[0].argnames[0].names[1].names[0].value.right instanceof UglifyJS.AST_Number);
|
||||||
|
|
||||||
|
|
||||||
|
ast = UglifyJS.parse("function foo({a, b: {b = 123}}){}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first argument
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].is_array, false);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names.length, 2);
|
||||||
|
|
||||||
|
// Check whole destructuring structure of first argument
|
||||||
|
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[0].key, "a");
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].argnames[0].names[1] instanceof UglifyJS.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[1].key, "b");
|
||||||
|
assert(ast.body[0].argnames[0].names[1].value instanceof UglifyJS.AST_Destructuring);
|
||||||
|
|
||||||
|
// Check content of nested destructuring in first parameter
|
||||||
|
var content = ast.body[0].argnames[0].names[1].value
|
||||||
|
assert.strictEqual(content.is_array, false);
|
||||||
|
assert.strictEqual(content.names.length, 1);
|
||||||
|
assert(content.names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(content.names[0].key, "b");
|
||||||
|
assert(content.names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
||||||
|
assert(content.names[0].value.left instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(content.names[0].value.operator, "=");
|
||||||
|
assert(content.names[0].value.right instanceof UglifyJS.AST_Number);
|
||||||
|
|
||||||
|
|
||||||
|
ast = UglifyJS.parse("function foo({a: {b = 123}}){}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first argument
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].is_array, false);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names.length, 1);
|
||||||
|
|
||||||
|
// Check whole destructuring structure of first argument
|
||||||
|
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[0].key, "a");
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_Destructuring);
|
||||||
|
|
||||||
|
// Check content of nested destructuring
|
||||||
|
content = ast.body[0].argnames[0].names[0].value
|
||||||
|
assert.strictEqual(content.is_array, false);
|
||||||
|
assert.strictEqual(content.names.length, 1);
|
||||||
|
assert(content.names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(content.names[0].key, "b");
|
||||||
|
assert(content.names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
||||||
|
assert(content.names[0].value.left instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(content.names[0].value.operator, "=");
|
||||||
|
assert(content.names[0].value.right instanceof UglifyJS.AST_Number);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should parse spread correctly", function() {
|
||||||
|
var ast = UglifyJS.parse("function foo(a, b, ...c){}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 3);
|
||||||
|
|
||||||
|
// Check parameters
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].argnames[1] instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].argnames[2] instanceof UglifyJS.AST_Expansion);
|
||||||
|
assert(ast.body[0].argnames[2].expression instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
|
||||||
|
|
||||||
|
ast = UglifyJS.parse("function foo([a, b, ...c]){}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first parameter
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].is_array, true);
|
||||||
|
|
||||||
|
// Check content first parameter
|
||||||
|
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].argnames[0].names[1] instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].argnames[0].names[2] instanceof UglifyJS.AST_Expansion);
|
||||||
|
assert(ast.body[0].argnames[0].names[2].expression instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
|
||||||
|
|
||||||
|
ast = UglifyJS.parse("function foo([a, b, [c, ...d]]){}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first parameter
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].is_array, true);
|
||||||
|
|
||||||
|
// Check content outer destructuring array
|
||||||
|
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].argnames[0].names[1] instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].argnames[0].names[2] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[2].is_array, true);
|
||||||
|
|
||||||
|
// Check content nested destructuring array
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[2].names.length, 2);
|
||||||
|
assert(ast.body[0].argnames[0].names[2].names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].argnames[0].names[2].names[1] instanceof UglifyJS.AST_Expansion);
|
||||||
|
assert(ast.body[0].argnames[0].names[2].names[1].expression instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
|
||||||
|
|
||||||
|
ast = UglifyJS.parse("function foo({a: [b, ...c]}){}");
|
||||||
|
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first parameter
|
||||||
|
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].is_array, false);
|
||||||
|
|
||||||
|
// Check outer destructuring object
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names.length, 1);
|
||||||
|
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[0].key, "a");
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[0].value.is_array, true);
|
||||||
|
|
||||||
|
// Check content nested destructuring array
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].names[0].value.names.length, 2);
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value.names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value.names[1] instanceof UglifyJS.AST_Expansion);
|
||||||
|
assert(ast.body[0].argnames[0].names[0].value.names[1].expression instanceof UglifyJS.AST_SymbolFunarg);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -80,4 +80,306 @@ describe("Arrow functions", function() {
|
|||||||
assert.throws(test(tests[i]), error);
|
assert.throws(test(tests[i]), error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should parse a function containing default assignment correctly", function() {
|
||||||
|
var ast = uglify.parse("var a = (a = 123) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// First argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].left instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].operator, "=");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].right instanceof uglify.AST_Number);
|
||||||
|
|
||||||
|
ast = uglify.parse("var a = (a = a) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// First argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].left instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].operator, "=");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].right instanceof uglify.AST_SymbolRef);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should parse a function containing default assignments in destructuring correctly", function() {
|
||||||
|
var ast = uglify.parse("var a = ([a = 123]) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// First argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, true);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].left instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].operator, "=");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].right instanceof uglify.AST_Number);
|
||||||
|
|
||||||
|
|
||||||
|
ast = uglify.parse("var a = ({a = 123}) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// First argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, false);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_ObjectKeyVal);
|
||||||
|
|
||||||
|
// First object element in first argument
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].key, "a");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.left instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].value.operator, "=");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.right instanceof uglify.AST_Number);
|
||||||
|
|
||||||
|
|
||||||
|
ast = uglify.parse("var a = ({a: a = 123}) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// First argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, false);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 1);
|
||||||
|
|
||||||
|
// Content destructuring of first argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_ObjectProperty);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].key, "a");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.left instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].value.operator, "=");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.right instanceof uglify.AST_Number);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should parse a function containing default assignments in complex destructuring correctly", function() {
|
||||||
|
var ast = uglify.parse("var a = ([a, [b = 123]]) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, true);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 2);
|
||||||
|
|
||||||
|
// Check whole destructuring structure of first argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].is_array, true);
|
||||||
|
|
||||||
|
// Check content of second destructuring element (which is the nested destructuring pattern)
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0] instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].left instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].operator, "=");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].right instanceof uglify.AST_Number);
|
||||||
|
|
||||||
|
|
||||||
|
ast = uglify.parse("var a = ([a, {b: c = 123}]) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, true);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 2);
|
||||||
|
|
||||||
|
// Check whole destructuring structure of first argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].is_array, false);
|
||||||
|
|
||||||
|
// Check content of second destructuring element (which is the nested destructuring pattern)
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0] instanceof uglify.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].key, "b");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].value instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].value.left instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].value.operator, "=");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].value.right instanceof uglify.AST_Number);
|
||||||
|
|
||||||
|
|
||||||
|
ast = uglify.parse("var a = ({a, b: {b = 123}}) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, false);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 2);
|
||||||
|
|
||||||
|
// First argument, property 1
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].key, "a");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value instanceof uglify.AST_SymbolFunarg);
|
||||||
|
|
||||||
|
// First argument, property 2
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1] instanceof uglify.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].key, "b");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1].value instanceof uglify.AST_Destructuring);
|
||||||
|
|
||||||
|
// Check content of nested destructuring
|
||||||
|
var content = ast.body[0].definitions[0].value.argnames[0].names[1].value
|
||||||
|
assert.strictEqual(content.is_array, false);
|
||||||
|
assert.strictEqual(content.names.length, 1);
|
||||||
|
assert(content.names[0] instanceof uglify.AST_ObjectKeyVal);
|
||||||
|
|
||||||
|
// Content of first property in nested destructuring
|
||||||
|
assert.strictEqual(content.names[0].key, "b");
|
||||||
|
assert(content.names[0].value instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(content.names[0].value.left instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(content.names[0].value.operator, "=");
|
||||||
|
assert(content.names[0].value.right instanceof uglify.AST_Number);
|
||||||
|
|
||||||
|
|
||||||
|
ast = uglify.parse("var a = ({a: {b = 123}}) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, false);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 1);
|
||||||
|
|
||||||
|
// Check whole destructuring structure of first argument
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].key, "a");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value instanceof uglify.AST_Destructuring);
|
||||||
|
|
||||||
|
// Check content of nested destructuring
|
||||||
|
content = ast.body[0].definitions[0].value.argnames[0].names[0].value
|
||||||
|
assert.strictEqual(content.is_array, false);
|
||||||
|
assert.strictEqual(content.names.length, 1);
|
||||||
|
assert(content.names[0] instanceof uglify.AST_ObjectKeyVal);
|
||||||
|
|
||||||
|
// Check first property of nested destructuring
|
||||||
|
assert.strictEqual(content.names[0].key, "b");
|
||||||
|
assert(content.names[0].value instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(content.names[0].value.left instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert.strictEqual(content.names[0].value.operator, "=");
|
||||||
|
assert(content.names[0].value.right instanceof uglify.AST_Number);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should parse spread correctly", function() {
|
||||||
|
var ast = uglify.parse("var a = (a, b, ...c) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 3);
|
||||||
|
|
||||||
|
// Check parameters
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[1] instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[2] instanceof uglify.AST_Expansion);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[2].expression instanceof uglify.AST_SymbolFunarg);
|
||||||
|
|
||||||
|
|
||||||
|
ast = uglify.parse("var a = ([a, b, ...c]) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first parameter
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, true);
|
||||||
|
|
||||||
|
// Check content first parameter
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1] instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[2] instanceof uglify.AST_Expansion);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[2].expression instanceof uglify.AST_SymbolFunarg);
|
||||||
|
|
||||||
|
|
||||||
|
ast = uglify.parse("var a = ([a, b, [c, ...d]]) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first parameter
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, true);
|
||||||
|
|
||||||
|
// Check content outer destructuring array
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[1] instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[2] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[2].is_array, true);
|
||||||
|
|
||||||
|
// Check content nested destructuring array
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[2].names.length, 2);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[2].names[0] instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[2].names[1] instanceof uglify.AST_Expansion);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[2].names[1].expression instanceof uglify.AST_SymbolFunarg);
|
||||||
|
|
||||||
|
|
||||||
|
ast = uglify.parse("var a = ({a: [b, ...c]}) => {}");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert.strictEqual(ast.body[0].definitions.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
||||||
|
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
||||||
|
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
||||||
|
|
||||||
|
// Check first parameter
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, false);
|
||||||
|
|
||||||
|
// Check outer destructuring object
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 1);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_ObjectKeyVal);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].key, "a");
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].value.is_array, true);
|
||||||
|
|
||||||
|
// Check content nested destructuring array
|
||||||
|
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].value.names.length, 2);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.names[0] instanceof uglify.AST_SymbolFunarg);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.names[1] instanceof uglify.AST_Expansion);
|
||||||
|
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.names[1].expression instanceof uglify.AST_SymbolFunarg);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
138
test/mocha/destructuring.js
Normal file
138
test/mocha/destructuring.js
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var uglify = require("../../");
|
||||||
|
|
||||||
|
describe("Destructuring", function() {
|
||||||
|
it("Should generate similar trees for destructuring in left hand side expressions, definitions, functions and arrow functions", function() {
|
||||||
|
var patterns = [
|
||||||
|
"[]",
|
||||||
|
"{}",
|
||||||
|
|
||||||
|
"[a, b, c]",
|
||||||
|
"{a: b, c: d}",
|
||||||
|
"{a}",
|
||||||
|
"{a, b}",
|
||||||
|
|
||||||
|
"{a: {}}",
|
||||||
|
"{a: []}",
|
||||||
|
"[{}]",
|
||||||
|
"[[]]",
|
||||||
|
"{a: {b}}",
|
||||||
|
|
||||||
|
// Can't do `a = 123` with lhs expression, so only test in destructuring
|
||||||
|
"[foo = bar]",
|
||||||
|
"{a = 123}",
|
||||||
|
"[{foo: abc = 123}]",
|
||||||
|
"{foo: [abc = 123]}",
|
||||||
|
|
||||||
|
"[...foo]",
|
||||||
|
"[...{}]",
|
||||||
|
"[...[]]"
|
||||||
|
|
||||||
|
// Can't do `...` because that is an invalid lhs expression, spread in array destructuring should be fine though
|
||||||
|
];
|
||||||
|
|
||||||
|
var types = [
|
||||||
|
{
|
||||||
|
name: "lhs",
|
||||||
|
symbolType: uglify.AST_SymbolRef,
|
||||||
|
tree: function (ast) {
|
||||||
|
return ast.body[0].body.left;
|
||||||
|
},
|
||||||
|
generate: function (code) {
|
||||||
|
return "(" + code + " = a)";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "var",
|
||||||
|
symbolType: uglify.AST_SymbolVar,
|
||||||
|
tree: function (ast) {
|
||||||
|
return ast.body[0].definitions[0].name;
|
||||||
|
},
|
||||||
|
generate: function (code) {
|
||||||
|
return "var " + code + " = a";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "function",
|
||||||
|
symbolType: uglify.AST_SymbolFunarg,
|
||||||
|
tree: function (ast) {
|
||||||
|
return ast.body[0].argnames[0];
|
||||||
|
},
|
||||||
|
generate: function (code) {
|
||||||
|
return "function a(" + code + ") {}";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "arrow",
|
||||||
|
symbolType: uglify.AST_SymbolFunarg,
|
||||||
|
tree: function (ast) {
|
||||||
|
return ast.body[0].definitions[0].value.argnames[0];
|
||||||
|
},
|
||||||
|
generate: function (code) {
|
||||||
|
return "var a = (" + code + ") => {}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var walker = function(type, ref, code, result) {
|
||||||
|
var w = new uglify.TreeWalker(function(node) {
|
||||||
|
if (w.parent() instanceof uglify.AST_DefaultAssign &&
|
||||||
|
w.parent().right === node
|
||||||
|
) {
|
||||||
|
return true; // Don't check the content of the default assignment
|
||||||
|
|
||||||
|
} else if (node instanceof uglify.AST_Symbol) {
|
||||||
|
assert(node instanceof type.symbolType,
|
||||||
|
node.TYPE + " while " + type.symbolType.TYPE + " expected at pos " +
|
||||||
|
node.start.pos + " in `" + code + "` (" + ref + ")"
|
||||||
|
);
|
||||||
|
|
||||||
|
result.push([
|
||||||
|
new uglify.AST_Symbol({
|
||||||
|
start: node.start,
|
||||||
|
name: node.name,
|
||||||
|
end: node.end
|
||||||
|
}),
|
||||||
|
w.parent()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push([node, w.parent()]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return w;
|
||||||
|
};
|
||||||
|
|
||||||
|
var getNodeType = function(node) {
|
||||||
|
return node[0].TYPE + (node[1] ? " " + node[1].TYPE : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < patterns.length; i++) {
|
||||||
|
var results = [];
|
||||||
|
|
||||||
|
for (var j = 0; j < types.length; j++) {
|
||||||
|
var code = types[j].generate(patterns[i])
|
||||||
|
var ast = types[j].tree(
|
||||||
|
uglify.parse(code)
|
||||||
|
);
|
||||||
|
results.push([]);
|
||||||
|
ast.walk(walker(
|
||||||
|
types[j],
|
||||||
|
"`" + patterns[i] + "` on " + types[j].name,
|
||||||
|
code,
|
||||||
|
results[j]
|
||||||
|
));
|
||||||
|
|
||||||
|
if (j > 0) {
|
||||||
|
assert.deepEqual(
|
||||||
|
results[0].map(getNodeType),
|
||||||
|
results[j].map(getNodeType),
|
||||||
|
"AST disagree on " + patterns[i] + " with " + types[j].name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -47,64 +47,83 @@ describe("Function", function() {
|
|||||||
assert.equal(destruct3.is_array, false);
|
assert.equal(destruct3.is_array, false);
|
||||||
assert.equal(destruct4.is_array, true);
|
assert.equal(destruct4.is_array, true);
|
||||||
|
|
||||||
var aAndB = [
|
// destruct 1
|
||||||
['SymbolFunarg', 'a'],
|
|
||||||
['SymbolFunarg', 'b']
|
|
||||||
];
|
|
||||||
|
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
[
|
[
|
||||||
destruct1.names[0].TYPE,
|
destruct1.names[0].TYPE,
|
||||||
destruct1.names[0].name
|
destruct1.names[0].key,
|
||||||
|
destruct1.names[0].value.name
|
||||||
],
|
],
|
||||||
aAndB[0]);
|
['ObjectKeyVal', 'a', 'a']
|
||||||
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
[
|
[
|
||||||
destruct1.names[1].TYPE,
|
destruct1.names[1].TYPE,
|
||||||
destruct1.names[1].name
|
destruct1.names[1].key,
|
||||||
|
destruct1.names[1].value.name
|
||||||
],
|
],
|
||||||
aAndB[1]);
|
['ObjectKeyVal', 'b', 'b']
|
||||||
|
);
|
||||||
|
|
||||||
|
// destruct 2
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
[
|
[
|
||||||
destruct2.names[0].TYPE,
|
destruct2.names[0].TYPE,
|
||||||
destruct2.names[0].name
|
destruct2.names[0].name
|
||||||
],
|
],
|
||||||
aAndB[0]);
|
['SymbolFunarg', 'a']
|
||||||
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
[
|
[
|
||||||
destruct2.names[1].names[0].TYPE,
|
destruct2.names[1].names[0].TYPE,
|
||||||
destruct2.names[1].names[0].name
|
destruct2.names[1].names[0].name
|
||||||
],
|
],
|
||||||
aAndB[1]);
|
['SymbolFunarg', 'b']
|
||||||
|
);
|
||||||
|
|
||||||
|
// destruct 3
|
||||||
assert.strictEqual(typeof destruct3.names[0].key, "string");
|
assert.strictEqual(typeof destruct3.names[0].key, "string");
|
||||||
assert.strictEqual(destruct3.names[0].key, "a");
|
assert.strictEqual(destruct3.names[0].key, "a");
|
||||||
|
assert.strictEqual(destruct3.names[0].value.TYPE, "SymbolFunarg");
|
||||||
|
assert.strictEqual(destruct3.names[0].value.name, "a");
|
||||||
assert.strictEqual(typeof destruct3.names[1].key, "string");
|
assert.strictEqual(typeof destruct3.names[1].key, "string");
|
||||||
assert.strictEqual(destruct3.names[1].key, "b");
|
assert.strictEqual(destruct3.names[1].key, "b");
|
||||||
|
assert.strictEqual(destruct3.names[1].value.TYPE, "SymbolFunarg");
|
||||||
|
assert.strictEqual(destruct3.names[1].value.name, "b");
|
||||||
|
|
||||||
|
// destruct 4
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
[
|
[
|
||||||
destruct4.names[0].TYPE,
|
destruct4.names[0].TYPE,
|
||||||
destruct4.names[0].name
|
destruct4.names[0].name
|
||||||
],
|
],
|
||||||
aAndB[0]);
|
['SymbolFunarg', 'a']
|
||||||
|
);
|
||||||
|
assert.strictEqual(destruct4.names[1].TYPE, "Destructuring");
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
[
|
[
|
||||||
destruct4.names[1].names[0].TYPE,
|
destruct4.names[1].names[0].TYPE,
|
||||||
destruct4.names[1].names[0].name
|
destruct4.names[1].names[0].name
|
||||||
],
|
],
|
||||||
aAndB[1]);
|
['SymbolFunarg', 'b']
|
||||||
|
);
|
||||||
|
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
get_args(destr_fun1.args_as_names()),
|
get_args(destr_fun1.args_as_names()),
|
||||||
aAndB);
|
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
|
||||||
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
get_args(destr_fun2.args_as_names()),
|
get_args(destr_fun2.args_as_names()),
|
||||||
aAndB);
|
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
|
||||||
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
get_args(destr_fun3.args_as_names()),
|
get_args(destr_fun3.args_as_names()),
|
||||||
aAndB);
|
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
|
||||||
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
get_args(destr_fun4.args_as_names()),
|
get_args(destr_fun4.args_as_names()),
|
||||||
aAndB);
|
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
|
||||||
|
);
|
||||||
|
|
||||||
// Making sure we don't accidentally accept things which
|
// Making sure we don't accidentally accept things which
|
||||||
// Aren't argument destructurings
|
// Aren't argument destructurings
|
||||||
|
|||||||
@@ -7,17 +7,26 @@ describe("Left-hand side expressions", function () {
|
|||||||
|
|
||||||
assert.equal(decls.body[0].TYPE, 'Var');
|
assert.equal(decls.body[0].TYPE, 'Var');
|
||||||
assert.equal(decls.body[0].definitions.length, 2);
|
assert.equal(decls.body[0].definitions.length, 2);
|
||||||
|
|
||||||
|
// Item 1
|
||||||
assert.equal(decls.body[0].definitions[0].name.TYPE, 'Destructuring');
|
assert.equal(decls.body[0].definitions[0].name.TYPE, 'Destructuring');
|
||||||
assert.equal(decls.body[0].definitions[0].value.TYPE, 'SymbolRef');
|
assert.equal(decls.body[0].definitions[0].value.TYPE, 'SymbolRef');
|
||||||
|
|
||||||
|
// Item 2
|
||||||
|
assert.equal(decls.body[0].definitions[1].name.TYPE, 'Destructuring');
|
||||||
|
assert.equal(decls.body[0].definitions[1].value.TYPE, 'SymbolRef');
|
||||||
|
|
||||||
var nested_def = uglify.parse('var [{x}] = foo').body[0].definitions[0];
|
var nested_def = uglify.parse('var [{x}] = foo').body[0].definitions[0];
|
||||||
|
|
||||||
assert.equal(nested_def.name.names[0].names[0].TYPE, 'SymbolVar');
|
assert.equal(nested_def.name.names[0].names[0].TYPE, 'ObjectKeyVal');
|
||||||
assert.equal(nested_def.name.names[0].names[0].name, 'x');
|
assert.equal(nested_def.name.names[0].names[0].value.TYPE, 'SymbolVar');
|
||||||
|
assert.equal(nested_def.name.names[0].names[0].key, 'x');
|
||||||
|
assert.equal(nested_def.name.names[0].names[0].value.name, 'x');
|
||||||
|
|
||||||
var holey_def = uglify.parse('const [,,third] = [1,2,3]').body[0].definitions[0];
|
var holey_def = uglify.parse('const [,,third] = [1,2,3]').body[0].definitions[0];
|
||||||
|
|
||||||
assert.equal(holey_def.name.names[0].TYPE, 'Hole');
|
assert.equal(holey_def.name.names[0].TYPE, 'Hole');
|
||||||
|
assert.equal(holey_def.name.names[1].TYPE, 'Hole');
|
||||||
assert.equal(holey_def.name.names[2].TYPE, 'SymbolConst');
|
assert.equal(holey_def.name.names[2].TYPE, 'SymbolConst');
|
||||||
|
|
||||||
var expanding_def = uglify.parse('var [first, ...rest] = [1,2,3]').body[0].definitions[0];
|
var expanding_def = uglify.parse('var [first, ...rest] = [1,2,3]').body[0].definitions[0];
|
||||||
@@ -26,4 +35,231 @@ describe("Left-hand side expressions", function () {
|
|||||||
assert.equal(expanding_def.name.names[1].TYPE, 'Expansion');
|
assert.equal(expanding_def.name.names[1].TYPE, 'Expansion');
|
||||||
assert.equal(expanding_def.name.names[1].expression.TYPE, 'SymbolVar');
|
assert.equal(expanding_def.name.names[1].expression.TYPE, 'SymbolVar');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Parser should use AST_Array for array literals", function() {
|
||||||
|
var ast = uglify.parse('["foo", "bar"]');
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Array);
|
||||||
|
|
||||||
|
ast = uglify.parse('a = ["foo"]');
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[0].body.left instanceof uglify.AST_SymbolRef);
|
||||||
|
assert.equal(ast.body[0].body.operator, "=");
|
||||||
|
assert(ast.body[0].body.right instanceof uglify.AST_Array);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Parser should use AST_Object for object literals", function() {
|
||||||
|
var ast = uglify.parse('({foo: "bar"})');
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Object);
|
||||||
|
|
||||||
|
// This example should be fine though
|
||||||
|
ast = uglify.parse('a = {foo: "bar"}');
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[0].body.left instanceof uglify.AST_SymbolRef);
|
||||||
|
assert.equal(ast.body[0].body.operator, "=");
|
||||||
|
assert(ast.body[0].body.right instanceof uglify.AST_Object);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Parser should use AST_Destructuring for array assignment patterns", function() {
|
||||||
|
var ast = uglify.parse('[foo, bar] = [1, 2]');
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.is_array, true);
|
||||||
|
assert.equal(ast.body[0].body.operator, "=");
|
||||||
|
assert(ast.body[0].body.right instanceof uglify.AST_Array);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Parser should use AST_Destructuring for object assignment patterns", function() {
|
||||||
|
var ast = uglify.parse('({a: b, b: c} = {b: "c", c: "d"})');
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.is_array, false);
|
||||||
|
assert.equal(ast.body[0].body.operator, "=");
|
||||||
|
assert(ast.body[0].body.right instanceof uglify.AST_Object);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Parser should be able to handle nested destructuring", function() {
|
||||||
|
var ast = uglify.parse('[{a,b},[d, e, f, {g, h}]] = [{a: 1, b: 2}, [3, 4, 5, {g: 6, h: 7}]]');
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.is_array, true);
|
||||||
|
assert.equal(ast.body[0].body.operator, "=");
|
||||||
|
assert(ast.body[0].body.right instanceof uglify.AST_Array);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[0] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.names[0].is_array, false);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[1] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.names[1].is_array, true);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[1].names[3] instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.names[1].names[3].is_array, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should handle spread operator in destructuring", function() {
|
||||||
|
var ast = uglify.parse("[a, b, ...c] = [1, 2, 3, 4, 5]");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.is_array, true);
|
||||||
|
assert.equal(ast.body[0].body.operator, "=");
|
||||||
|
assert(ast.body[0].body.right instanceof uglify.AST_Array);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[0] instanceof uglify.AST_SymbolRef);
|
||||||
|
assert(ast.body[0].body.left.names[1] instanceof uglify.AST_SymbolRef);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[2] instanceof uglify.AST_Expansion);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should handle default assignments in destructuring", function() {
|
||||||
|
var ast = uglify.parse("({x: v, z = z + 5} = obj);");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.is_array, false);
|
||||||
|
assert.equal(ast.body[0].body.operator, "=");
|
||||||
|
assert(ast.body[0].body.right instanceof uglify.AST_SymbolRef);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[0].value instanceof uglify.AST_SymbolRef);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.names[0].start.value, "x");
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[1].value instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.names[1].start.value, "z");
|
||||||
|
assert(ast.body[0].body.left.names[1].value.left instanceof uglify.AST_SymbolRef);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.names[1].value.operator, "=");
|
||||||
|
assert(ast.body[0].body.left.names[1].value.right instanceof uglify.AST_Binary);
|
||||||
|
|
||||||
|
|
||||||
|
ast = uglify.parse("({x = 123} = obj);");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.is_array, false);
|
||||||
|
assert.equal(ast.body[0].body.operator, "=");
|
||||||
|
assert(ast.body[0].body.right instanceof uglify.AST_SymbolRef);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[0].value instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.names[0].value.operator, "=");
|
||||||
|
assert(ast.body[0].body.left.names[0].value.left instanceof uglify.AST_SymbolRef);
|
||||||
|
|
||||||
|
|
||||||
|
ast = uglify.parse("[x, y = 5] = foo");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.is_array, true);
|
||||||
|
assert.equal(ast.body[0].body.operator, "=");
|
||||||
|
assert(ast.body[0].body.right instanceof uglify.AST_SymbolRef);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[0] instanceof uglify.AST_SymbolRef);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.names[0].start.value, "x");
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[1] instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].body.left.names[1].left instanceof uglify.AST_SymbolRef);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.names[1].start.value, "y");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should handle default assignments containing assignments in a destructuring", function() {
|
||||||
|
var ast = uglify.parse("[x, y = z = 2] = a;");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.is_array, true);
|
||||||
|
assert.equal(ast.body[0].body.operator, "=");
|
||||||
|
assert(ast.body[0].body.right instanceof uglify.AST_SymbolRef);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[0] instanceof uglify.AST_SymbolRef);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[1] instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].body.left.names[1].left instanceof uglify.AST_SymbolRef);
|
||||||
|
assert.equal(ast.body[0].body.left.names[1].operator, "=");
|
||||||
|
assert(ast.body[0].body.left.names[1].right instanceof uglify.AST_Assign);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[1].right.left instanceof uglify.AST_SymbolRef);
|
||||||
|
assert.equal(ast.body[0].body.left.names[1].right.operator, "=");
|
||||||
|
assert(ast.body[0].body.left.names[1].right.right instanceof uglify.AST_Number);
|
||||||
|
|
||||||
|
ast = uglify.parse("({a: a = 123} = obj)");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
||||||
|
|
||||||
|
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.is_array, false);
|
||||||
|
assert.equal(ast.body[0].body.operator, "=");
|
||||||
|
assert(ast.body[0].body.right instanceof uglify.AST_SymbolRef);
|
||||||
|
|
||||||
|
assert(ast.body[0].body.left.names[0] instanceof uglify.AST_ObjectProperty);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.names[0].key, "a");
|
||||||
|
assert(ast.body[0].body.left.names[0].value instanceof uglify.AST_DefaultAssign);
|
||||||
|
assert(ast.body[0].body.left.names[0].value.left instanceof uglify.AST_SymbolRef);
|
||||||
|
assert.strictEqual(ast.body[0].body.left.names[0].value.operator, "=");
|
||||||
|
assert(ast.body[0].body.left.names[0].value.right instanceof uglify.AST_Number);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should allow multiple spread in array literals", function() {
|
||||||
|
var ast = uglify.parse("var a = [1, 2, 3], b = [4, 5, 6], joined; joined = [...a, ...b]");
|
||||||
|
assert(ast.body[0] instanceof uglify.AST_Var);
|
||||||
|
assert(ast.body[1] instanceof uglify.AST_SimpleStatement);
|
||||||
|
|
||||||
|
// Check statement containing array with spreads
|
||||||
|
assert(ast.body[1].body instanceof uglify.AST_Assign);
|
||||||
|
assert(ast.body[1].body.left instanceof uglify.AST_SymbolRef);
|
||||||
|
assert.equal(ast.body[1].body.operator, "=");
|
||||||
|
assert(ast.body[1].body.right instanceof uglify.AST_Array);
|
||||||
|
|
||||||
|
// Check array content
|
||||||
|
assert.strictEqual(ast.body[1].body.right.elements.length, 2);
|
||||||
|
assert(ast.body[1].body.right.elements[0] instanceof uglify.AST_Expansion);
|
||||||
|
assert(ast.body[1].body.right.elements[0].expression instanceof uglify.AST_SymbolRef);
|
||||||
|
assert(ast.body[1].body.right.elements[0].expression.name, "a");
|
||||||
|
assert(ast.body[1].body.right.elements[1] instanceof uglify.AST_Expansion);
|
||||||
|
assert(ast.body[1].body.right.elements[1].expression instanceof uglify.AST_SymbolRef);
|
||||||
|
assert(ast.body[1].body.right.elements[1].expression.name, "b");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not allow spread on invalid locations", function() {
|
||||||
|
var expect = function(input, expected) {
|
||||||
|
var execute = function(input) {
|
||||||
|
return function() {
|
||||||
|
uglify.parse(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var check = function(e) {
|
||||||
|
return e instanceof uglify.JS_Parse_Error &&
|
||||||
|
e.message === expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.throws(execute(input), check);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spreads are not allowed in destructuring array if it's not the last element
|
||||||
|
expect("[...a, ...b] = [1, 2, 3, 4]", "SyntaxError: Spread must the be last element in destructuring array");
|
||||||
|
|
||||||
|
// Multiple spreads are not allowed in destructuring array
|
||||||
|
expect("[...a, ...b] = [1, 2, 3, 4]", "SyntaxError: Spread must the be last element in destructuring array");
|
||||||
|
|
||||||
|
// Spread in obvious object pattern
|
||||||
|
expect("({...a} = foo)", "SyntaxError: Unexpected token: expand (...)");
|
||||||
|
|
||||||
|
// Spread in block should not be allowed
|
||||||
|
expect("{...a} = foo", "SyntaxError: Unexpected token: expand (...)");
|
||||||
|
|
||||||
|
// Not in standard yet
|
||||||
|
expect("let foo = {bar: 42}, bar; bar = {...foo}", "SyntaxError: Unexpected token: expand (...)");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user