Compare commits

..

4 Commits

Author SHA1 Message Date
Alex Lam S.L
5fd8244a2e v3.0.2 2017-05-10 01:52:00 +08:00
Alex Lam S.L
c14e280585 print error stack in CLI (#1890) 2017-05-09 16:36:44 +08:00
Alex Lam S.L
bc3fa78e8c mention minify().error 2017-05-09 16:09:48 +08:00
Alex Lam S.L
8c7c107765 update minify() usage in test/ufuzz.js (#1888)
fixes #1887
2017-05-09 15:58:46 +08:00
64 changed files with 454 additions and 8031 deletions

View File

@@ -525,9 +525,6 @@ can pass additional arguments that control the code output:
- `3` -- always use the original quotes
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
quotes from property names in object literals.
- `ecma` (default `5`) -- set output printing mode. This will only change the
output in direct control of the beautifier. Non-compatible features in the
abstract syntax tree will still be outputted as is.
### Keeping copyright notices or other comments
@@ -599,7 +596,8 @@ performs all the steps in a configurable manner.
Example:
```javascript
var result = UglifyJS.minify("var b = function() {};");
console.log(result.code); // minified output
console.log(result.code); // minified output
console.log(result.error); // runtime error
```
You can also compress multiple files:

View File

@@ -193,7 +193,7 @@ function run() {
}
}
} catch (ex) {
fatal("ERROR: " + ex.message);
fatal(ex.stack);
}
var result = UglifyJS.minify(files, options);
if (result.error) {
@@ -220,7 +220,7 @@ function run() {
console.error("Supported options:");
console.error(ex.defs);
}
fatal("ERROR: " + ex.message);
fatal(ex.stack);
} else if (program.output == "ast") {
console.log(JSON.stringify(result.ast, function(key, value) {
if (skip_key(key)) return;
@@ -263,7 +263,7 @@ function run() {
}
function fatal(message) {
console.error(message);
console.error(message.replace(/^\S*?Error:/, "ERROR:"));
process.exit(1);
}
@@ -303,7 +303,7 @@ function read_file(path, default_value) {
return fs.readFileSync(path, "utf8");
} catch (ex) {
if (ex.code == "ENOENT" && default_value != null) return default_value;
fatal("ERROR: " + ex.message);
fatal(ex.stack);
}
}

View File

@@ -157,7 +157,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
function walk_body(node, visitor) {
var body = node.body;
if (body instanceof AST_Node) {
if (body instanceof AST_Statement) {
body._walk(visitor);
}
else for (var i = 0, len = body.length; i < len; i++) {
@@ -284,10 +284,6 @@ var AST_ForIn = DEFNODE("ForIn", "init name object", {
}
}, AST_IterationStatement);
var AST_ForOf = DEFNODE("ForOf", null, {
$documentation: "A `for ... of` statement",
}, AST_ForIn);
var AST_With = DEFNODE("With", "expression", {
$documentation: "A `with` statement",
$propdoc: {
@@ -315,13 +311,6 @@ var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
},
get_defun_scope: function () {
var self = this;
while (self.is_block_scope() && self.parent_scope) {
self = self.parent_scope;
}
return self;
}
}, AST_Block);
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
@@ -342,111 +331,13 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
}
}, AST_Scope);
var AST_Expansion = DEFNODE("Expansion", "expression", {
$documentation: "An expandible argument, such as ...rest, a splat, such as [1,2,...all], or an expansion in a variable declaration, such as var [first, ...rest] = list",
$propdoc: {
expression: "AST_Symbol the thing to be expanded"
},
_walk: function(visitor) {
var self = this;
return visitor._visit(this, function(){
self.expression.walk(visitor);
});
}
});
var AST_ArrowParametersOrSeq = DEFNODE("ArrowParametersOrSeq", "expressions", {
$documentation: "A set of arrow function parameters or a sequence expression. This is used because when the parser sees a \"(\" it could be the start of a seq, or the start of a parameter list of an arrow function.",
$propdoc: {
expressions: "[AST_Expression|AST_Destructuring|AST_Expansion*] array of expressions or argument names or destructurings."
},
as_params: function (croak) {
// We don't want anything which doesn't belong in a destructuring
var root = this;
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) {
return insert_default(new AST_Destructuring({
start: ex.start,
end: ex.end,
is_array: false,
names: ex.properties.map(to_fun_args)
}), default_seen_above);
} else if (ex instanceof AST_ObjectKeyVal) {
if (ex.key instanceof AST_SymbolRef) {
ex.key = to_fun_args(ex.key, 0, [ex.key]);
}
ex.value = to_fun_args(ex.value, 0, [ex.key]);
return insert_default(ex, default_seen_above);
} else if (ex instanceof AST_Hole) {
return ex;
} else if (ex instanceof AST_Destructuring) {
ex.names = ex.names.map(to_fun_args);
return insert_default(ex, default_seen_above);
} else if (ex instanceof AST_SymbolRef) {
return insert_default(new AST_SymbolFunarg({
name: ex.name,
start: ex.start,
end: ex.end
}), default_seen_above);
} else if (ex instanceof AST_Expansion) {
ex.expression = to_fun_args(ex.expression);
return insert_default(ex, default_seen_above);
} else if (ex instanceof AST_Array) {
return insert_default(new AST_Destructuring({
start: ex.start,
end: ex.end,
is_array: true,
names: ex.elements.map(to_fun_args)
}), default_seen_above);
} else if (ex instanceof AST_Assign) {
return insert_default(to_fun_args(ex.left, undefined, undefined, ex.right), default_seen_above);
} else if (ex instanceof AST_DefaultAssign) {
ex.left = to_fun_args(ex.left, 0, [ex.left]);
return ex;
} else {
croak("Invalid function parameter", ex.start.line, ex.start.col);
}
});
},
as_expr: function() {
var exprs = this.expressions;
return exprs.length == 1 ? exprs[0] : new AST_Sequence({
expressions: exprs
});
}
});
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator", {
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
$documentation: "Base class for functions",
$propdoc: {
is_generator: "[boolean] is generatorFn or not",
name: "[AST_SymbolDeclaration?] the name of this function",
argnames: "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion|AST_DefaultAssign*] array of function arguments, destructurings, or expanding arguments",
argnames: "[AST_SymbolFunarg*] array of function arguments",
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
},
args_as_names: function () {
var out = [];
for (var i = 0; i < this.argnames.length; i++) {
if (this.argnames[i] instanceof AST_Destructuring) {
out = out.concat(this.argnames[i].all_symbols());
} else {
out.push(this.argnames[i]);
}
}
return out;
},
_walk: function(visitor) {
return visitor._visit(this, function(){
if (this.name) this.name._walk(visitor);
@@ -467,78 +358,10 @@ var AST_Function = DEFNODE("Function", null, {
$documentation: "A function expression"
}, AST_Lambda);
var AST_Arrow = DEFNODE("Arrow", null, {
$documentation: "An ES6 Arrow function ((a) => b)"
}, AST_Lambda);
var AST_Defun = DEFNODE("Defun", null, {
$documentation: "A function definition"
}, AST_Lambda);
/* -----[ DESTRUCTURING ]----- */
var AST_Destructuring = DEFNODE("Destructuring", "names is_array", {
$documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names",
$propdoc: {
"names": "[AST_Node*] Array of properties or elements",
"is_array": "[Boolean] Whether the destructuring represents an object or array"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.names.forEach(function(name){
name._walk(visitor);
});
});
},
all_symbols: function() {
var out = [];
this.walk(new TreeWalker(function (node) {
if (node instanceof AST_Symbol) {
out.push(node);
}
if (node instanceof AST_Expansion) {
out.push(node.expression);
}
}));
return out;
}
});
var AST_PrefixedTemplateString = DEFNODE("PrefixedTemplateString", "template_string prefix", {
$documentation: "A templatestring with a prefix, such as String.raw`foobarbaz`",
$propdoc: {
template_string: "[AST_TemplateString] The template string",
prefix: "[AST_SymbolRef|AST_PropAccess] The prefix, which can be a symbol such as `foo` or a dotted expression such as `String.raw`."
},
_walk: function(visitor) {
this.prefix._walk(visitor);
this.template_string._walk(visitor);
}
})
var AST_TemplateString = DEFNODE("TemplateString", "segments", {
$documentation: "A template string literal",
$propdoc: {
segments: "[AST_TemplateSegment|AST_Expression]* One or more segments, starting with AST_TemplateSegment. AST_Expression may follow AST_TemplateSegment, but each AST_Expression must be followed by AST_TemplateSegment."
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.segments.forEach(function(seg, i){
if (i % 2 !== 0) {
seg._walk(visitor);
}
});
});
}
});
var AST_TemplateSegment = DEFNODE("TemplateSegment", "value raw", {
$documentation: "A segment of a template string literal",
$propdoc: {
value: "Content of the segment",
raw: "Raw content of the segment"
}
});
/* -----[ JUMPS ]----- */
var AST_Jump = DEFNODE("Jump", null, {
@@ -658,7 +481,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
var AST_Catch = DEFNODE("Catch", "argname", {
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
$propdoc: {
argname: "[AST_SymbolCatch|AST_Destructuring|AST_Expansion|AST_DefaultAssign] symbol for the exception"
argname: "[AST_SymbolCatch] symbol for the exception"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
@@ -693,75 +516,14 @@ var AST_Var = DEFNODE("Var", null, {
$documentation: "A `var` statement"
}, AST_Definitions);
var AST_Let = DEFNODE("Let", null, {
$documentation: "A `let` statement"
}, AST_Definitions);
var AST_Const = DEFNODE("Const", null, {
$documentation: "A `const` statement"
}, AST_Definitions);
var AST_NameImport = DEFNODE("NameImport", "foreign_name name", {
$documentation: "The part of the import statement that imports names from a module.",
$propdoc: {
foreign_name: "[AST_SymbolImportForeign] The name being imported (as specified in the module)",
name: "[AST_SymbolImport] The name as it becomes available to this module."
},
_walk: function (visitor) {
return visitor._visit(this, function() {
this.foreign_name._walk(visitor);
this.name._walk(visitor);
});
}
})
var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", {
$documentation: "An `import` statement",
$propdoc: {
imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.",
imported_names: "[AST_NameImport*] The names of non-default imported variables",
module_name: "[AST_String] String literal describing where this module came from",
},
_walk: function(visitor) {
return visitor._visit(this, function() {
if (this.imported_name) {
this.imported_name._walk(visitor);
}
if (this.imported_names) {
this.imported_names.forEach(function (name_import) {
name_import._walk(visitor);
});
}
this.module_name._walk(visitor);
});
}
});
var AST_Export = DEFNODE("Export", "exported_definition exported_value is_default exported_names module_name", {
$documentation: "An `export` statement",
$propdoc: {
exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition",
exported_value: "[AST_Node?] An exported value",
exported_names: "[AST_NameImport*?] List of exported names",
module_name: "[AST_String?] Name of the file to load exports from",
is_default: "[Boolean] Whether this is the default exported value of this module"
},
_walk: function (visitor) {
visitor._visit(this, function () {
if (this.exported_definition) {
this.exported_definition._walk(visitor);
}
if (this.exported_value) {
this.exported_value._walk(visitor);
}
});
}
}, AST_Statement);
var AST_VarDef = DEFNODE("VarDef", "name value", {
$documentation: "A variable declaration; only appears in a AST_Definitions node",
$propdoc: {
name: "[AST_SymbolVar|AST_SymbolConst|AST_Destructuring] name of the variable",
name: "[AST_SymbolVar|AST_SymbolConst] name of the variable",
value: "[AST_Node?] initializer, or null of there's no initializer"
},
_walk: function(visitor) {
@@ -892,10 +654,6 @@ var AST_Assign = DEFNODE("Assign", null, {
$documentation: "An assignment expression — `a = b + 5`",
}, AST_Binary);
var AST_DefaultAssign = DEFNODE("DefaultAssign", null, {
$documentation: "A default assignment expression like in `(a = 3) => a`"
}, AST_Binary);
/* -----[ LITERALS ]----- */
var AST_Array = DEFNODE("Array", "elements", {
@@ -931,13 +689,11 @@ var AST_Object = DEFNODE("Object", "properties", {
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
$documentation: "Base class for literal object properties",
$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",
value: "[AST_Node] property value. For setters and getters this is an AST_Function."
key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.",
value: "[AST_Node] property value. For setters and getters this is an AST_Function."
},
_walk: function(visitor) {
return visitor._visit(this, function(){
if (this.key instanceof AST_Node)
this.key._walk(visitor);
this.value._walk(visitor);
});
}
@@ -950,72 +706,21 @@ var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
}
}, AST_ObjectProperty);
var AST_ObjectSetter = DEFNODE("ObjectSetter", "quote static", {
$propdoc: {
quote: "[string|undefined] the original quote character, if any",
static: "[boolean] whether this is a static setter (classes only)"
},
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
$documentation: "An object setter property",
}, AST_ObjectProperty);
var AST_ObjectGetter = DEFNODE("ObjectGetter", "quote static", {
$propdoc: {
quote: "[string|undefined] the original quote character, if any",
static: "[boolean] whether this is a static getter (classes only)"
},
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
$documentation: "An object getter property",
}, AST_ObjectProperty);
var AST_ConciseMethod = DEFNODE("ConciseMethod", "quote static is_generator", {
$propdoc: {
quote: "[string|undefined] the original quote character, if any",
static: "[boolean] whether this method is static (classes only)",
is_generator: "[boolean] is generatorFn or not",
},
$documentation: "An ES6 concise method inside an object or class"
}, AST_ObjectProperty);
var AST_Class = DEFNODE("Class", "name extends properties", {
$propdoc: {
name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.",
extends: "[AST_Node]? optional parent class",
properties: "[AST_ObjectProperty*] array of properties"
},
$documentation: "An ES6 class",
_walk: function(visitor) {
return visitor._visit(this, function(){
if (this.name) {
this.name._walk(visitor);
}
if (this.extends) {
this.extends._walk(visitor);
}
this.properties.forEach(function(prop){
prop._walk(visitor);
});
});
},
}, AST_Scope);
var AST_DefClass = DEFNODE("DefClass", null, {
$documentation: "A class definition",
}, AST_Class);
var AST_ClassExpression = DEFNODE("ClassExpression", null, {
$documentation: "A class expression."
}, AST_Class);
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
$propdoc: {
name: "[string] name of this symbol",
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
thedef: "[SymbolDef/S] the definition of this symbol"
},
$documentation: "Base class for all symbols"
});
var AST_NewTarget = DEFNODE("NewTarget", null, {
$documentation: "A reference to new.target"
$documentation: "Base class for all symbols",
});
var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
@@ -1030,17 +735,9 @@ var AST_SymbolVar = DEFNODE("SymbolVar", null, {
$documentation: "Symbol defining a variable",
}, AST_SymbolDeclaration);
var AST_SymbolBlockDeclaration = DEFNODE("SymbolBlockDeclaration", null, {
$documentation: "Base class for block-scoped declaration symbols"
}, AST_SymbolDeclaration);
var AST_SymbolConst = DEFNODE("SymbolConst", null, {
$documentation: "A constant declaration"
}, AST_SymbolBlockDeclaration);
var AST_SymbolLet = DEFNODE("SymbolLet", null, {
$documentation: "A block-scoped `let` declaration"
}, AST_SymbolBlockDeclaration);
}, AST_SymbolDeclaration);
var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
$documentation: "Symbol naming a function argument",
@@ -1050,33 +747,13 @@ var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
$documentation: "Symbol defining a function",
}, AST_SymbolDeclaration);
var AST_SymbolMethod = DEFNODE("SymbolMethod", null, {
$documentation: "Symbol in an object defining a method",
}, AST_Symbol);
var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
$documentation: "Symbol naming a function expression",
}, AST_SymbolDeclaration);
var AST_SymbolDefClass = DEFNODE("SymbolDefClass", null, {
$documentation: "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class."
}, AST_SymbolBlockDeclaration);
var AST_SymbolClass = DEFNODE("SymbolClass", null, {
$documentation: "Symbol naming a class's name. Lexically scoped to the class."
}, AST_SymbolDeclaration);
var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
$documentation: "Symbol naming the exception in catch",
}, AST_SymbolBlockDeclaration);
var AST_SymbolImport = DEFNODE("SymbolImport", null, {
$documentation: "Symbol refering to an imported name",
}, AST_SymbolBlockDeclaration);
var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, {
$documentation: "A symbol imported from a module, but it is defined in the other module, and its real name is irrelevant for this module's purposes",
}, AST_Symbol);
}, AST_SymbolDeclaration);
var AST_Label = DEFNODE("Label", "references", {
$documentation: "Symbol naming a label (declaration)",
@@ -1101,10 +778,6 @@ var AST_This = DEFNODE("This", null, {
$documentation: "The `this` symbol",
}, AST_Symbol);
var AST_Super = DEFNODE("Super", null, {
$documentation: "The `super` symbol",
}, AST_Symbol);
var AST_Constant = DEFNODE("Constant", null, {
$documentation: "Base class for all constants",
getValue: function() {
@@ -1178,21 +851,6 @@ var AST_True = DEFNODE("True", null, {
value: true
}, AST_Boolean);
/* -----[ Yield ]----- */
var AST_Yield = DEFNODE("Yield", "expression is_star", {
$documentation: "A `yield` statement",
$propdoc: {
expression: "[AST_Node?] the value returned or thrown by this statement; could be null (representing undefined) but only when is_star is set to false",
is_star: "[Boolean] Whether this is a yield or yield* statement"
},
_walk: function(visitor) {
return visitor._visit(this, this.expression && function(){
this.expression._walk(visitor);
});
}
});
/* -----[ TreeWalker ]----- */
function TreeWalker(callback) {
@@ -1220,17 +878,12 @@ TreeWalker.prototype = {
this.directives = Object.create(this.directives);
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
this.directives[node.value] = node;
} else if (node instanceof AST_Class) {
this.directives = Object.create(this.directives);
if (!this.directives["use strict"]) {
this.directives["use strict"] = node;
}
}
this.stack.push(node);
},
pop: function(node) {
this.stack.pop();
if (node instanceof AST_Lambda || node instanceof AST_Class) {
if (node instanceof AST_Lambda) {
this.directives = Object.getPrototypeOf(this.directives);
}
},
@@ -1248,7 +901,7 @@ TreeWalker.prototype = {
var dir = this.directives[type];
if (dir) return dir;
var node = this.stack[this.stack.length - 1];
if (node instanceof AST_Scope && node.body) {
if (node instanceof AST_Scope) {
for (var i = 0; i < node.body.length; ++i) {
var st = node.body[i];
if (!(st instanceof AST_Directive)) break;

View File

@@ -56,7 +56,6 @@ function Compressor(options, false_by_default) {
dead_code : !false_by_default,
drop_console : false,
drop_debugger : !false_by_default,
ecma : 5,
evaluate : !false_by_default,
expression : false,
global_defs : {},
@@ -298,42 +297,36 @@ merge(Compressor.prototype, {
node.definition().fixed = false;
}
if (node instanceof AST_VarDef) {
if (node.name instanceof AST_Destructuring) {
node.name.walk(suppressor);
} else {
var d = node.name.definition();
if (d.fixed === undefined || safe_to_assign(d, node.value)) {
if (node.value) {
d.fixed = function() {
return node.value;
};
mark(d, false);
descend();
} else {
d.fixed = null;
}
mark(d, true);
return true;
} else if (node.value) {
d.fixed = false;
}
}
}
if (node instanceof AST_Assign && node.operator == "=") {
if (node.left instanceof AST_Destructuring) {
node.left.walk(suppressor);
} else if (node.left instanceof AST_SymbolRef) {
var d = node.left.definition();
if (safe_to_assign(d, node.right)) {
d.references.push(node.left);
var d = node.name.definition();
if (d.fixed === undefined || safe_to_assign(d, node.value)) {
if (node.value) {
d.fixed = function() {
return node.right;
return node.value;
};
mark(d, false);
node.right.walk(tw);
mark(d, true);
return true;
descend();
} else {
d.fixed = null;
}
mark(d, true);
return true;
} else if (node.value) {
d.fixed = false;
}
}
if (node instanceof AST_Assign
&& node.operator == "="
&& node.left instanceof AST_SymbolRef) {
var d = node.left.definition();
if (safe_to_assign(d, node.right)) {
d.references.push(node.left);
d.fixed = function() {
return node.right;
};
mark(d, false);
node.right.walk(tw);
mark(d, true);
return true;
}
}
if (node instanceof AST_Defun) {
@@ -630,14 +623,6 @@ merge(Compressor.prototype, {
return false;
};
function can_be_evicted_from_block(node) {
return !(
node instanceof AST_DefClass ||
node instanceof AST_Let ||
node instanceof AST_Const
);
}
function loop_body(x) {
if (x instanceof AST_Switch) return x;
if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {
@@ -686,7 +671,7 @@ merge(Compressor.prototype, {
// Will not attempt to collapse assignments into or past code blocks
// which are not sequentially executed, e.g. loops and conditionals.
function collapse(statements, compressor) {
var scope = compressor.find_parent(AST_Scope).get_defun_scope();
var scope = compressor.find_parent(AST_Scope);
if (scope.uses_eval || scope.uses_with) return statements;
var candidates = [];
var stat_index = statements.length;
@@ -714,7 +699,6 @@ merge(Compressor.prototype, {
var parent = tt.parent();
if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
|| node instanceof AST_Debugger
|| node instanceof AST_Destructuring
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|| node instanceof AST_SymbolRef && node.undeclared()
|| node instanceof AST_Try
@@ -872,9 +856,9 @@ merge(Compressor.prototype, {
function references_in_scope(def) {
if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun) return true;
if (def.scope.get_defun_scope() !== scope) return false;
if (def.scope !== scope) return false;
return def.references.every(function(ref) {
return ref.scope.get_defun_scope() === scope;
return ref.scope === scope;
});
}
}
@@ -882,7 +866,7 @@ merge(Compressor.prototype, {
function eliminate_spurious_blocks(statements) {
var seen_dirs = [];
return statements.reduce(function(a, stat){
if (stat instanceof AST_BlockStatement && all(stat.body, can_be_evicted_from_block)) {
if (stat instanceof AST_BlockStatement) {
CHANGED = true;
a.push.apply(a, eliminate_spurious_blocks(stat.body));
} else if (stat instanceof AST_EmptyStatement) {
@@ -1207,7 +1191,7 @@ merge(Compressor.prototype, {
compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
}
stat.walk(new TreeWalker(function(node){
if (node instanceof AST_Var) {
if (node instanceof AST_Definitions) {
compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
node.remove_initializers();
target.push(node);
@@ -1348,9 +1332,6 @@ merge(Compressor.prototype, {
(function(def){
def(AST_Node, return_false);
def(AST_String, return_true);
def(AST_TemplateString, function(){
return this.segments.length === 1;
});
def(AST_UnaryPrefix, function(){
return this.operator == "typeof";
});
@@ -1522,12 +1503,6 @@ merge(Compressor.prototype, {
def(AST_Lambda, function(){
throw def;
});
def(AST_Arrow, function() {
throw def;
});
def(AST_Class, function() {
throw def;
});
function ev(node, compressor) {
if (!compressor) throw new Error("Compressor must be passed");
@@ -1539,10 +1514,6 @@ merge(Compressor.prototype, {
def(AST_Constant, function(){
return this.getValue();
});
def(AST_TemplateString, function() {
if (this.segments.length !== 1) throw def;
return this.segments[0].value;
});
def(AST_Array, function(compressor){
if (compressor.option("unsafe")) {
return this.elements.map(function(element) {
@@ -1578,8 +1549,7 @@ merge(Compressor.prototype, {
case "typeof":
// Function would be evaluated to an array and so typeof would
// incorrectly return 'object'. Hence making is a special case.
if (e instanceof AST_Function ||
e instanceof AST_Arrow) return typeof function(){};
if (e instanceof AST_Function) return typeof function(){};
e = ev(e, compressor);
@@ -1605,7 +1575,6 @@ merge(Compressor.prototype, {
case "^" : result = ev(left, c) ^ ev(right, c); break;
case "+" : result = ev(left, c) + ev(right, c); break;
case "*" : result = ev(left, c) * ev(right, c); break;
case "**" : result = Math.pow(ev(left, c), ev(right, c)); break;
case "/" : result = ev(left, c) / ev(right, c); break;
case "%" : result = ev(left, c) % ev(right, c); break;
case "-" : result = ev(left, c) - ev(right, c); break;
@@ -1811,8 +1780,6 @@ merge(Compressor.prototype, {
});
def(AST_Defun, return_true);
def(AST_Function, return_false);
def(AST_Class, return_false);
def(AST_DefClass, return_true);
def(AST_Binary, function(compressor){
return this.left.has_side_effects(compressor)
|| this.right.has_side_effects(compressor);
@@ -1835,9 +1802,6 @@ merge(Compressor.prototype, {
return any(this.properties, compressor);
});
def(AST_ObjectProperty, function(compressor){
if (this.key instanceof AST_ObjectKeyVal &&
this.key.has_side_effects(compressor))
return true;
return this.value.has_side_effects(compressor);
});
def(AST_Array, function(compressor){
@@ -1884,7 +1848,7 @@ merge(Compressor.prototype, {
return all(this.properties);
});
def(AST_ObjectProperty, function(){
return !(this.key instanceof AST_Node) && this.value.is_constant_expression();
return this.value.is_constant_expression();
});
})(function(node, func){
node.DEFMETHOD("is_constant_expression", func);
@@ -1901,7 +1865,6 @@ merge(Compressor.prototype, {
var n = this.body.length;
return n > 0 && aborts(this.body[n - 1]);
};
def(AST_Import, function(){ return null; });
def(AST_BlockStatement, block_aborts);
def(AST_SwitchBranch, block_aborts);
def(AST_If, function(){
@@ -1935,7 +1898,6 @@ merge(Compressor.prototype, {
});
OPT(AST_Block, function(self, compressor){
if (self.body instanceof AST_Node) { return self; }
self.body = tighten_body(self.body, compressor);
return self;
});
@@ -1943,11 +1905,7 @@ merge(Compressor.prototype, {
OPT(AST_BlockStatement, function(self, compressor){
self.body = tighten_body(self.body, compressor);
switch (self.body.length) {
case 1:
if (can_be_evicted_from_block(self.body[0])) {
return self.body[0];
}
break;
case 1: return self.body[0];
case 0: return make_node(AST_EmptyStatement, self);
}
return self;
@@ -1960,6 +1918,7 @@ merge(Compressor.prototype, {
if (self.uses_eval || self.uses_with) return;
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
if (!drop_funcs && !drop_vars) return;
var assign_as_unused = !/keep_assign/.test(compressor.option("unused"));
var in_use = [];
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
@@ -1973,17 +1932,15 @@ merge(Compressor.prototype, {
}
var var_defs_by_id = new Dictionary();
var initializations = new Dictionary();
var destructuring_value = null;
var in_definition = false;
// pass 1: find out which symbols are directly used in
// this scope (not in nested scopes).
var scope = this;
var tw = new TreeWalker(function(node, descend){
if (node !== self) {
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
if (node instanceof AST_Defun) {
if (!drop_funcs && scope === self) {
var node_def = node.name.definition();
if (node_def.global && !(node_def.id in in_use_ids)) {
if (!(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true;
in_use.push(node_def);
}
@@ -1993,31 +1950,18 @@ merge(Compressor.prototype, {
}
if (node instanceof AST_Definitions && scope === self) {
node.definitions.forEach(function(def){
var node_def = def.name.definition();
if (def.name instanceof AST_SymbolVar) {
var_defs_by_id.add(def.name.definition().id, def);
var_defs_by_id.add(node_def.id, def);
}
if (!drop_vars) {
def.name.walk(new TreeWalker(function(node) {
if (node instanceof AST_SymbolDeclaration) {
var def = node.definition();
if (def.global && !(def.id in in_use_ids)) {
in_use_ids[def.id] = true;
in_use.push(def);
}
}
}));
if (!(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true;
in_use.push(node_def);
}
}
if (def.value) {
if (def.name instanceof AST_Destructuring) {
var destructuring_cache = destructuring_value;
destructuring_value = def.value;
in_definition = true;
def.walk(tw);
in_definition = false;
destructuring_value = destructuring_cache;
} else {
initializations.add(def.name.name, def.value);
}
initializations.add(def.name.name, def.value);
if (def.value.has_side_effects(compressor)) {
def.value.walk(tw);
}
@@ -2048,41 +1992,6 @@ merge(Compressor.prototype, {
scope = save_scope;
return true;
}
if (node instanceof AST_Destructuring) {
if (!in_definition) {
return true;
}
for (var i = 0; i < node.names.length; i++) {
if (node.names[i] instanceof AST_Destructuring) {
node.names[i].walk(tw);
}
else if (node.names[i] instanceof AST_Expansion) {
if (node.names[i].expression instanceof AST_Symbol) {
initializations.add(node.names[i].expression.name, destructuring_value);
} else if (node.names[i].expression instanceof AST_Destructuring) {
node.names[i].expression.walk(tw);
} else {
throw new Error(string_template("Can't handle expansion of type: {type}", {
type: Object.getPrototypeOf(node.names[i].expression).TYPE
}));
}
}
else if (node.names[i] instanceof AST_Hole) {
continue;
}
else if (node.names[i] instanceof AST_ObjectKeyVal && typeof node.names[i].key === "string") {
initializations.add(node.names[i].key, destructuring_value);
}
else if (node.names[i] instanceof AST_Symbol) {
initializations.add(node.names[i].name, destructuring_value);
} else {
throw new Error(string_template("Unknown destructuring element of type: {type}", {
type: Object.getPrototypeOf(node.names[i]).TYPE
}));
}
}
return true;
}
}
});
self.walk(tw);
@@ -2124,18 +2033,7 @@ merge(Compressor.prototype, {
var trim = !compressor.option("keep_fargs");
for (var a = node.argnames, i = a.length; --i >= 0;) {
var sym = a[i];
if (sym instanceof AST_Expansion) {
sym = sym.expression;
}
if (sym instanceof AST_DefaultAssign) {
sym = sym.left;
}
// Do not drop destructuring arguments.
// They constitute a type assertion, so dropping
// them would stop that TypeError which would happen
// if someone called it with an incorrectly formatted
// parameter.
if (!(sym instanceof AST_Destructuring) && !(sym.definition().id in in_use_ids)) {
if (!(sym.definition().id in in_use_ids)) {
sym.__unused = true;
if (trim) {
a.pop();
@@ -2147,15 +2045,14 @@ merge(Compressor.prototype, {
}
}
}
if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
var keep = (node.name.definition().id in in_use_ids) || !drop_funcs && node.name.definition().global;
if (!keep) {
if (drop_funcs && node instanceof AST_Defun && node !== self) {
if (!(node.name.definition().id in in_use_ids)) {
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
return make_node(AST_EmptyStatement, node);
}
return node;
}
if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn && tt.parent().init === node)) {
if (drop_vars && node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn && tt.parent().init === node)) {
// place uninitialized names at the start
var body = [], head = [], tail = [];
// for unused names whose initialization has
@@ -2164,9 +2061,7 @@ merge(Compressor.prototype, {
var side_effects = [];
node.definitions.forEach(function(def) {
if (def.value) def.value = def.value.transform(tt);
if (def.name instanceof AST_Destructuring) return tail.push(def);
var sym = def.name.definition();
if (!drop_vars && sym.global) return tail.push(def);
if (sym.id in in_use_ids) {
if (def.name instanceof AST_SymbolVar) {
var var_defs = var_defs_by_id.get(sym.id);
@@ -2243,13 +2138,12 @@ merge(Compressor.prototype, {
});
}
}
if (assign_as_unused
if (drop_vars && assign_as_unused
&& node instanceof AST_Assign
&& node.operator == "="
&& node.left instanceof AST_SymbolRef) {
var def = node.left.definition();
if (!(def.id in in_use_ids)
&& (drop_vars || !def.global)
&& self.variables.get(def.name) === def) {
return maintain_this_binding(tt.parent(), node, node.right.transform(tt));
}
@@ -2284,12 +2178,6 @@ merge(Compressor.prototype, {
}
return node;
}
if (node instanceof AST_BlockStatement) {
descend(node, this);
if (in_list && all(node.body, can_be_evicted_from_block)) {
return MAP.splice(node.body);
}
}
if (node instanceof AST_Scope && node !== self)
return node;
@@ -2309,12 +2197,8 @@ merge(Compressor.prototype, {
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
var self = this;
if (compressor.has_directive("use asm")) return self;
// Hoisting makes no sense in an arrow func
if (!Array.isArray(self.body)) return self;
var hoist_funs = compressor.option("hoist_funs");
var hoist_vars = compressor.option("hoist_vars");
if (hoist_funs || hoist_vars) {
var dirs = [];
var hoisted = [];
@@ -2343,7 +2227,6 @@ merge(Compressor.prototype, {
}
if (node instanceof AST_Var && hoist_vars) {
node.definitions.forEach(function(def){
if (def.name instanceof AST_Destructuring) return;
vars.set(def.name.name, def);
++vars_found;
});
@@ -2376,7 +2259,7 @@ merge(Compressor.prototype, {
vars.each(function(def, name){
if (self instanceof AST_Lambda
&& find_if(function(x){ return x.name == def.name.name },
self.args_as_names())) {
self.argnames)) {
vars.del(name);
} else {
def = def.clone();
@@ -2945,7 +2828,7 @@ merge(Compressor.prototype, {
AST_Definitions.DEFMETHOD("to_assignments", function(compressor){
var reduce_vars = compressor.option("reduce_vars");
var assignments = this.definitions.reduce(function(a, def){
if (def.value && !(def.name instanceof AST_Destructuring)) {
if (def.value) {
var name = make_node(AST_SymbolRef, def.name, def.name);
a.push(make_node(AST_Assign, def, {
operator : "=",
@@ -2953,16 +2836,6 @@ merge(Compressor.prototype, {
right : def.value
}));
if (reduce_vars) name.definition().fixed = false;
} else if (def.value) {
// Because it's a destructuring, do not turn into an assignment.
var varDef = make_node(AST_VarDef, def, {
name: def.name,
value: def.value
});
var var_ = make_node(AST_Var, def, {
definitions: [ varDef ]
});
a.push(var_);
}
return a;
}, []);
@@ -2976,10 +2849,6 @@ merge(Compressor.prototype, {
return self;
});
OPT(AST_Import, function(self, compressor) {
return self;
});
OPT(AST_Call, function(self, compressor){
var exp = self.expression;
if (compressor.option("reduce_vars")
@@ -3105,7 +2974,7 @@ merge(Compressor.prototype, {
if (!fun) return self;
var args = fun.argnames.map(function(arg, i){
return make_node(AST_String, self.args[i], {
value: arg.print_to_string({ecma: compressor.option("ecma")})
value: arg.print_to_string()
});
});
var code = OutputStream();
@@ -3127,11 +2996,6 @@ merge(Compressor.prototype, {
}
}
break;
case "Symbol":
// Symbol's argument is only used for debugging.
self.args = [];
return self;
break;
}
}
else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
@@ -3214,7 +3078,7 @@ merge(Compressor.prototype, {
}
}
}
if (exp instanceof AST_Function && !self.expression.is_generator) {
if (exp instanceof AST_Function) {
if (exp.body[0] instanceof AST_Return) {
var value = exp.body[0].value;
if (!value || value.is_constant_expression()) {
@@ -4013,23 +3877,6 @@ merge(Compressor.prototype, {
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 === undefined) {
self = self.left;
} else if (evaluateRight !== self.right) {
evaluateRight = make_node_from_constant(evaluateRight, self.right);
self.right = best_of_expression(evaluateRight, self.right);
}
return self;
});
OPT(AST_Conditional, function(self, compressor){
if (!compressor.option("conditionals")) return self;
// This looks like lift_sequences(), should probably be under "sequences"
@@ -4311,27 +4158,6 @@ merge(Compressor.prototype, {
return self;
});
OPT(AST_Arrow, function(self, compressor){
if (self.body.length === 1 && self.body[0] instanceof AST_Return) {
var value = self.body[0].value;
self.body = value ? value : [];
}
return self;
});
OPT(AST_Class, function(self, compressor){
// HACK to avoid compress failure.
// AST_Class is not really an AST_Scope/AST_Block as it lacks a body.
return self;
});
OPT(AST_Yield, function(self, compressor){
if (self.expression && !self.is_star && is_undefined(self.expression, compressor)) {
self.expression = null;
}
return self;
});
OPT(AST_VarDef, function(self, compressor){
var defines = compressor.option("global_defs");
if (defines && HOP(defines, self.name.name)) {
@@ -4340,32 +4166,4 @@ merge(Compressor.prototype, {
return self;
});
OPT(AST_TemplateString, function(self, compressor){
if (!compressor.option("evaluate")
|| compressor.parent() instanceof AST_PrefixedTemplateString)
return self;
var segments = [];
for (var i = 0; i < self.segments.length; i++) {
var segment = self.segments[i];
if (segment instanceof AST_Node) {
var result = segment.evaluate(compressor);
// Evaluate to constant value
// Constant value shorter than ${segment}
if (result !== segment && (result + "").length <= segment.print_to_string().length + "${}".length) {
// There should always be a previous and next segment if segment is a node
segments[segments.length - 1].value = segments[segments.length - 1].value + result + self.segments[++i].value;
continue;
}
}
segments.push(segment);
}
self.segments = segments;
return self;
});
OPT(AST_PrefixedTemplateString, function(self, compressor){
return self;
});
})();

View File

@@ -54,11 +54,9 @@ function OutputStream(options) {
options = defaults(options, {
ascii_only : false,
ascii_identifiers: undefined,
beautify : false,
bracketize : false,
comments : false,
ecma : 5,
ie8 : false,
indent_level : 4,
indent_start : 0,
@@ -71,7 +69,6 @@ function OutputStream(options) {
quote_style : 0,
semicolons : true,
shebang : true,
shorthand : undefined,
source_map : null,
space_colon : true,
unescape_regexps : false,
@@ -79,12 +76,6 @@ function OutputStream(options) {
wrap_iife : false,
}, true);
if (typeof options.ascii_identifiers === 'undefined')
options.ascii_identifiers = options.ascii_only;
if (options.shorthand === undefined)
options.shorthand = options.ecma > 5;
// Convert comment option to RegExp if neccessary and set up comments filter
var comment_filter = return_false; // Default case, throw all comments away
if (options.comments) {
@@ -120,19 +111,9 @@ function OutputStream(options) {
var OUTPUT = "";
function to_ascii(str, identifier) {
return str.replace(/[\ud800-\udbff][\udc00-\udfff]|[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
var code = get_full_char_code(ch, 0).toString(16);
if ((identifier && code.length === 1 && options.ecma >= 6) || code.length > 4) {
if (options.ecma < 6) {
if (identifier) {
return ch; // no \u{} support
}
return "\\u" + ch.charCodeAt(0).toString(16) + "\\u"
+ ch.charCodeAt(1).toString(16);
}
return "\\u{" + code + "}";
} else if (code.length <= 2 && !identifier) {
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
var code = ch.charCodeAt(0).toString(16);
if (code.length <= 2 && !identifier) {
while (code.length < 2) code = "0" + code;
return "\\x" + code;
} else {
@@ -160,7 +141,7 @@ function OutputStream(options) {
case "\u2029": return "\\u2029";
case "\ufeff": return "\\ufeff";
case "\0":
return /[0-7]/.test(get_full_char(str, i+1)) ? "\\x00" : "\\0";
return /[0-7]/.test(str.charAt(i+1)) ? "\\x00" : "\\0";
}
return s;
});
@@ -170,11 +151,7 @@ function OutputStream(options) {
function quote_double() {
return '"' + str.replace(/\x22/g, '\\"') + '"';
}
function quote_template() {
return '`' + str.replace(/`/g, '\\`') + '`';
}
if (options.ascii_only) str = to_ascii(str);
if (quote === "`") return quote_template();
switch (options.quote_style) {
case 1:
return quote_single();
@@ -199,7 +176,7 @@ function OutputStream(options) {
function make_name(name) {
name = name.toString();
if (options.ascii_identifiers)
if (options.ascii_only)
name = to_ascii(name, true);
return name;
};
@@ -236,8 +213,8 @@ function OutputStream(options) {
function print(str) {
str = String(str);
var ch = get_full_char(str, 0);
var prev = get_full_char(last, last.length - 1);
var ch = str.charAt(0);
var prev = last.charAt(last.length - 1);
if (might_need_semicolon) {
might_need_semicolon = false;
@@ -301,10 +278,6 @@ function OutputStream(options) {
last = str;
};
var star = function(){
print("*");
}
var space = options.beautify ? function() {
print(" ");
} : function() {
@@ -424,7 +397,6 @@ function OutputStream(options) {
should_break : function() { return options.width && this.current_width() >= options.width },
newline : newline,
print : print,
star : star,
space : space,
comma : comma,
colon : colon,
@@ -444,10 +416,6 @@ function OutputStream(options) {
}
print(encoded);
},
print_template_string_chars: function(str) {
var encoded = encode_string(str, '`').replace(/\${/g, "\\${");
return print(encoded.substr(1, encoded.length - 2));
},
encode_string : encode_string,
next_indent : next_indent,
with_indent : with_indent,
@@ -608,11 +576,6 @@ function OutputStream(options) {
return false;
});
PARENS(AST_Arrow, function(output){
var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this;
});
// same goes for an object literal, because otherwise it would be
// interpreted as a block of code.
PARENS(AST_Object, function(output){
@@ -622,29 +585,20 @@ function OutputStream(options) {
PARENS(AST_Unary, function(output){
var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_Call && p.expression === this
|| p instanceof AST_Binary
&& p.operator === "**"
&& this instanceof AST_UnaryPrefix
&& p.left === this
&& this.operator !== "++"
&& this.operator !== "--";
|| p instanceof AST_Call && p.expression === this;
});
PARENS(AST_Sequence, function(output){
var p = output.parent();
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|| p instanceof AST_Unary // !(foo, bar, baz)
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|| 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_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
* ==> 20 (side effect, set a := 10 and b := 20) */
|| p instanceof AST_Arrow // x => (x, x)
|| p instanceof AST_DefaultAssign // x => (x = (0, function(){}))
|| (p instanceof AST_Class && p.extends === this) // class D extends (calls++, C) {}
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|| p instanceof AST_Unary // !(foo, bar, baz)
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|| 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_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
* ==> 20 (side effect, set a := 10 and b := 20) */
;
});
@@ -671,24 +625,6 @@ function OutputStream(options) {
}
});
PARENS(AST_Yield, function(output){
var p = output.parent();
// (yield 1) + (yield 2)
// a = yield 3
if (p instanceof AST_Binary && p.operator !== "=")
return true;
// (yield 1) ? yield 2 : yield 3
if (p instanceof AST_Conditional && p.condition === this)
return true;
// -(yield 4)
if (p instanceof AST_Unary)
return true;
// (yield x).foo
// (yield x)['foo']
if (p instanceof AST_PropAccess && p.expression === this)
return true;
});
PARENS(AST_PropAccess, function(output){
var p = output.parent();
if (p instanceof AST_New && p.expression === this) {
@@ -758,9 +694,6 @@ function OutputStream(options) {
// (a = foo)["prop"] —or— (a = foo).prop
if (p instanceof AST_PropAccess && p.expression === this)
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 ]----- */
@@ -769,28 +702,6 @@ function OutputStream(options) {
output.print_string(self.value, self.quote);
output.semicolon();
});
DEFPRINT(AST_Expansion, function (self, output) {
output.print('...');
self.expression.print(output);
});
DEFPRINT(AST_Destructuring, function (self, output) {
output.print(self.is_array ? "[" : "{");
var first = true;
var len = self.names.length;
self.names.forEach(function (name, i) {
if (first) first = false; else { output.comma(); output.space(); }
name.print(output);
// If the final element is a hole, we need to make sure it
// doesn't look like a trailing comma, by inserting an actual
// trailing comma.
if (i === len - 1 && name instanceof AST_Hole)
output.comma();
})
output.print(self.is_array ? "]" : "}");
});
DEFPRINT(AST_Debugger, function(self, output){
output.print("debugger");
output.semicolon();
@@ -915,11 +826,7 @@ function OutputStream(options) {
output.with_parens(function(){
self.init.print(output);
output.space();
if (self instanceof AST_ForOf) {
output.print("of");
} else {
output.print("in");
}
output.print("in");
output.space();
self.object.print(output);
});
@@ -941,19 +848,10 @@ function OutputStream(options) {
var self = this;
if (!nokeyword) {
output.print("function");
if (this.is_generator) {
output.star();
}
if (self.name) {
output.space();
}
}
if (self.name instanceof AST_Symbol) {
if (self.name) {
output.space();
self.name.print(output);
} else if (nokeyword && self.name instanceof AST_Node) {
output.with_square(function() {
self.name.print(output); // Computed method name
});
}
output.with_parens(function(){
self.argnames.forEach(function(arg, i){
@@ -968,56 +866,6 @@ function OutputStream(options) {
self._do_print(output);
});
DEFPRINT(AST_PrefixedTemplateString, function(self, output) {
self.prefix.print(output);
self.template_string.print(output);
});
DEFPRINT(AST_TemplateString, function(self, output) {
var is_tagged = output.parent() instanceof AST_PrefixedTemplateString;
output.print("`");
for (var i = 0; i < self.segments.length; i++) {
if (!(self.segments[i] instanceof AST_TemplateSegment)) {
output.print("${");
self.segments[i].print(output);
output.print("}");
} else if (is_tagged) {
output.print(self.segments[i].raw);
} else {
output.print_template_string_chars(self.segments[i].value);
}
}
output.print("`");
});
AST_Arrow.DEFMETHOD("_do_print", function(output){
var self = this;
var parent = output.parent();
var needs_parens = parent instanceof AST_Binary ||
parent instanceof AST_Unary ||
(parent instanceof AST_Call && self === parent.expression);
if (needs_parens) { output.print("(") }
if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) {
self.argnames[0].print(output);
} else {
output.with_parens(function(){
self.argnames.forEach(function(arg, i){
if (i) output.comma();
arg.print(output);
});
});
}
output.space();
output.print('=>');
output.space();
if (self.body instanceof AST_Node) {
this.body.print(output);
} else {
print_bracketed(this.body, output);
}
if (needs_parens) { output.print(")") }
});
/* -----[ exits ]----- */
AST_Exit.DEFMETHOD("_do_print", function(output, kind){
output.print(kind);
@@ -1034,17 +882,6 @@ function OutputStream(options) {
self._do_print(output, "throw");
});
/* -----[ yield ]----- */
DEFPRINT(AST_Yield, function(self, output){
var star = self.is_star ? "*" : "";
output.print("yield" + star);
if (self.expression) {
output.space();
self.expression.print(output);
}
});
/* -----[ loop control ]----- */
AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){
output.print(kind);
@@ -1193,107 +1030,12 @@ function OutputStream(options) {
if (!avoid_semicolon)
output.semicolon();
});
DEFPRINT(AST_Let, function(self, output){
self._do_print(output, "let");
});
DEFPRINT(AST_Var, function(self, output){
self._do_print(output, "var");
});
DEFPRINT(AST_Const, function(self, output){
self._do_print(output, "const");
});
DEFPRINT(AST_Import, function(self, output) {
output.print("import");
output.space();
if (self.imported_name) {
self.imported_name.print(output);
}
if (self.imported_name && self.imported_names) {
output.print(",");
output.space();
}
if (self.imported_names) {
if (self.imported_names.length === 1 && self.imported_names[0].foreign_name.name === "*") {
self.imported_names[0].print(output);
} else {
output.print("{");
self.imported_names.forEach(function (name_import, i) {
output.space();
name_import.print(output);
if (i < self.imported_names.length - 1) {
output.print(",");
output.space();
}
});
output.space();
output.print("}");
}
}
if (self.imported_name || self.imported_names) {
output.space();
output.print("from")
output.space();
}
self.module_name.print(output);
output.semicolon();
});
DEFPRINT(AST_NameImport, function(self, output) {
var definition = self.name.definition();
var names_are_different =
(definition && definition.mangled_name || self.name.name) !==
self.foreign_name.name;
if (names_are_different) {
output.print(self.foreign_name.name);
output.space();
output.print("as");
output.space();
self.name.print(output);
} else {
self.name.print(output);
}
});
DEFPRINT(AST_Export, function(self, output) {
output.print("export");
output.space();
if (self.is_default) {
output.print("default");
output.space();
}
if (self.exported_names) {
output.space();
if (self.exported_names.length === 1 && self.exported_names[0].name.name === "*") {
self.exported_names[0].print(output);
} else {
output.print("{");
self.exported_names.forEach(function (name_import, i) {
output.space();
name_import.print(output);
if (i < self.exported_names.length - 1) {
output.print(",");
output.space();
}
});
output.space();
output.print("}");
}
output.space();
}
else if (self.exported_value) {
self.exported_value.print(output);
} else if (self.exported_definition) {
self.exported_definition.print(output);
}
if (self.module_name) {
output.space();
output.print("from");
output.space();
self.module_name.print(output);
}
output.semicolon();
});
function parenthesize_for_noin(node, output, noin) {
if (!noin) node.print(output);
@@ -1466,35 +1208,9 @@ function OutputStream(options) {
});
else output.print("{}");
});
DEFPRINT(AST_Class, function(self, output){
output.print("class");
output.space();
if (self.name) {
self.name.print(output);
output.space();
}
if (self.extends) {
output.print("extends");
output.space();
self.extends.print(output);
output.space();
}
if (self.properties.length > 0) output.with_block(function(){
self.properties.forEach(function(prop, i){
if (i) {
output.newline();
}
output.indent();
prop.print(output);
});
output.newline();
});
else output.print("{}");
});
DEFPRINT(AST_NewTarget, function(self, output) {
output.print("new.target");
});
AST_ObjectProperty.DEFMETHOD("print_property_name", function(key, quote, output) {
DEFPRINT(AST_ObjectKeyVal, function(self, output){
var key = self.key;
var quote = self.quote;
if (output.option("quote_keys")) {
output.print_string(key + "");
} else if ((typeof key == "number"
@@ -1511,98 +1227,29 @@ function OutputStream(options) {
} else {
output.print_string(key, quote);
}
});
DEFPRINT(AST_ObjectKeyVal, function(self, output){
function get_name(self) {
var def = self.definition();
return def ? def.mangled_name || def.name : self.name;
}
var allowShortHand = output.option("shorthand");
if (allowShortHand &&
self.value instanceof AST_Symbol &&
is_identifier_string(self.key) &&
get_name(self.value) === self.key
) {
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 {
if (!(self.key instanceof AST_Node)) {
self.print_property_name(self.key, self.quote, output);
} else {
output.with_square(function() {
self.key.print(output);
});
}
output.colon();
self.value.print(output);
}
});
AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, self, output) {
if (self.static) {
output.print("static");
output.space();
}
output.print(type);
output.space();
if (self.key instanceof AST_SymbolMethod) {
self.print_property_name(self.key.name, self.quote, output);
} else {
output.with_square(function() {
self.key.print(output);
});
}
self.value._do_print(output, true);
output.colon();
self.value.print(output);
});
DEFPRINT(AST_ObjectSetter, function(self, output){
self._print_getter_setter("set", self, output);
});
DEFPRINT(AST_ObjectGetter, function(self, output){
self._print_getter_setter("get", self, output);
});
DEFPRINT(AST_ConciseMethod, function(self, output){
if (self.static) {
output.print("static");
output.space();
}
if (self.is_generator) {
output.print("*");
}
if (self.key instanceof AST_SymbolMethod) {
self.print_property_name(self.key.name, self.quote, output);
} else {
output.with_square(function() {
self.key.print(output);
});
}
output.print("set");
output.space();
self.key.print(output);
self.value._do_print(output, true);
});
AST_Symbol.DEFMETHOD("_do_print", function(output){
var def = this.definition();
output.print_name(def ? def.mangled_name || def.name : this.name);
DEFPRINT(AST_ObjectGetter, function(self, output){
output.print("get");
output.space();
self.key.print(output);
self.value._do_print(output, true);
});
DEFPRINT(AST_Symbol, function (self, output) {
self._do_print(output);
});
DEFPRINT(AST_SymbolDeclaration, function(self, output){
self._do_print(output);
DEFPRINT(AST_Symbol, function(self, output){
var def = self.definition();
output.print_name(def ? def.mangled_name || def.name : self.name);
});
DEFPRINT(AST_Hole, noop);
DEFPRINT(AST_This, function(self, output){
output.print("this");
});
DEFPRINT(AST_Super, function(self, output){
output.print("super");
});
DEFPRINT(AST_Constant, function(self, output){
output.print(self.getValue());
});

File diff suppressed because one or more lines are too long

View File

@@ -44,15 +44,6 @@
"use strict";
function find_builtins(reserved) {
// Compatibility fix for some standard defined globals not defined on every js environment
var new_globals = ["Symbol", "Map", "Promise", "Proxy", "Reflect", "Set", "WeakMap", "WeakSet"];
var objects = {};
new_globals.forEach(function (new_global) {
objects[new_global] = global[new_global] || new Function();
});
// NaN will be included due to Number.NaN
[
"null",
@@ -64,15 +55,7 @@ function find_builtins(reserved) {
].forEach(add);
[ Object, Array, Function, Number,
String, Boolean, Error, Math,
Date, RegExp, objects.Symbol, ArrayBuffer,
DataView, decodeURI, decodeURIComponent,
encodeURI, encodeURIComponent, eval, EvalError,
Float32Array, Float64Array, Int8Array, Int16Array,
Int32Array, isFinite, isNaN, JSON, objects.Map, parseFloat,
parseInt, objects.Promise, objects.Proxy, RangeError, ReferenceError,
objects.Reflect, objects.Set, SyntaxError, TypeError, Uint8Array,
Uint8ClampedArray, Uint16Array, Uint32Array, URIError,
objects.WeakMap, objects.WeakSet
Date, RegExp
].forEach(function(ctor){
Object.getOwnPropertyNames(ctor).map(add);
if (ctor.prototype) {
@@ -137,9 +120,6 @@ function mangle_properties(ast, options) {
else if (node instanceof AST_Sub) {
addStrings(node.property, keep_quoted);
}
else if (node instanceof AST_ConciseMethod) {
add(node.name.name);
}
}));
// step 2: transform the tree, renaming properties
@@ -159,11 +139,6 @@ function mangle_properties(ast, options) {
if (!keep_quoted)
node.property = mangleStrings(node.property);
}
else if (node instanceof AST_ConciseMethod) {
if (should_mangle(node.name.name)) {
node.name.name = mangle(node.name.name);
}
}
// else if (node instanceof AST_String) {
// if (should_mangle(node.value)) {
// AST_Node.warn(

View File

@@ -49,9 +49,7 @@ function SymbolDef(scope, index, orig) {
this.scope = scope;
this.references = [];
this.global = false;
this.export = false;
this.mangled_name = null;
this.object_destructuring_arg = false;
this.undeclared = false;
this.index = index;
this.id = SymbolDef.next_id++;
@@ -64,17 +62,11 @@ SymbolDef.prototype = {
if (!options) options = {};
return (this.global && !options.toplevel)
|| this.export
|| this.object_destructuring_arg
|| this.undeclared
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|| (options.keep_fnames
&& (this.orig[0] instanceof AST_SymbolLambda
|| this.orig[0] instanceof AST_SymbolDefun))
|| this.orig[0] instanceof AST_SymbolMethod
|| (options.keep_classnames
&& (this.orig[0] instanceof AST_SymbolClass
|| this.orig[0] instanceof AST_SymbolDefClass));
|| this.orig[0] instanceof AST_SymbolDefun));
},
mangle: function(options) {
var cache = options.cache && options.cache.props;
@@ -109,29 +101,15 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var scope = self.parent_scope = null;
var labels = new Dictionary();
var defun = null;
var in_destructuring = null;
var in_export = false;
var in_block = 0;
var tw = new TreeWalker(function(node, descend){
if (node.is_block_scope()) {
if (node instanceof AST_Catch) {
var save_scope = scope;
scope = new AST_Scope(node);
scope.init_scope_vars(save_scope);
if (!(node instanceof AST_Scope)) {
scope.uses_with = save_scope.uses_with;
scope.uses_eval = save_scope.uses_eval;
scope.directives = save_scope.directives;
}
descend();
scope = save_scope;
return true;
}
if (node instanceof AST_Destructuring && node.is_array === false) {
in_destructuring = node; // These don't nest
descend();
in_destructuring = null;
return true;
}
if (node instanceof AST_Scope) {
node.init_scope_vars(scope);
var save_scope = scope;
@@ -145,22 +123,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
labels = save_labels;
return true; // don't descend again in TreeWalker
}
if (node instanceof AST_Export) {
in_export = true;
descend();
in_export = false;
return true;
}
if (node instanceof AST_BlockStatement
|| node instanceof AST_Switch
|| node instanceof AST_Try
|| node instanceof AST_Catch
|| node instanceof AST_Finally) {
in_block++;
descend();
in_block--;
return true;
}
if (node instanceof AST_LabeledStatement) {
var l = node.label;
if (labels.has(l.name)) {
@@ -179,15 +141,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
if (node instanceof AST_Symbol) {
node.scope = scope;
}
if (node instanceof AST_SymbolFunarg) {
node.object_destructuring_arg = !!in_destructuring;
}
if (node instanceof AST_Label) {
node.thedef = node;
node.references = [];
}
if (node instanceof AST_SymbolLambda) {
defun.def_function(node, in_export, in_block);
defun.def_function(node);
}
else if (node instanceof AST_SymbolDefun) {
// Careful here, the scope where this should be defined is
@@ -195,28 +154,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// scope when we encounter the AST_Defun node (which is
// instanceof AST_Scope) but we get to the symbol a bit
// later.
var parent_lambda = defun.parent_scope;
while (parent_lambda.is_block_scope()) {
parent_lambda = parent_lambda.parent_scope;
}
(node.scope = parent_lambda).def_function(node, in_export, in_block);
}
else if (node instanceof AST_SymbolClass) {
defun.def_variable(node, in_export, in_block);
}
else if (node instanceof AST_SymbolImport) {
scope.def_variable(node, in_export, in_block);
}
else if (node instanceof AST_SymbolDefClass) {
// This deals with the name of the class being available
// inside the class.
(node.scope = defun.parent_scope).def_function(node, in_export, in_block);
(node.scope = defun.parent_scope).def_function(node);
}
else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolLet
|| node instanceof AST_SymbolConst) {
var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node, in_export, in_block);
def.destructuring = in_destructuring;
defun.def_variable(node);
if (defun !== scope) {
node.mark_enclosed(options);
var def = scope.find_variable(node);
@@ -227,7 +169,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
}
}
else if (node instanceof AST_SymbolCatch) {
scope.def_variable(node, in_export, in_block).defun = defun;
scope.def_variable(node).defun = defun;
}
else if (node instanceof AST_LabelRef) {
var sym = labels.get(node.name);
@@ -243,7 +185,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// pass 2: find back references and eval
var func = null;
var cls = null;
var globals = self.globals = new Dictionary();
var tw = new TreeWalker(function(node, descend){
if (node instanceof AST_Lambda) {
@@ -253,13 +194,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
func = prev_func;
return true;
}
if (node instanceof AST_Class) {
var prev_cls = cls;
cls = node;
descend();
cls = prev_cls;
return true;
}
if (node instanceof AST_LoopControl && node.label) {
node.label.thedef.references.push(node);
return true;
@@ -331,23 +265,6 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
this.cname = -1; // the current index for mangling functions/variables
});
AST_Node.DEFMETHOD("is_block_scope", function(){
return false; // Behaviour will be overridden by AST_Block
});
AST_Block.DEFMETHOD("is_block_scope", function(){
return (
!(this instanceof AST_Lambda) &&
!(this instanceof AST_Toplevel) &&
!(this instanceof AST_Class) &&
!(this instanceof AST_SwitchBranch)
);
});
AST_IterationStatement.DEFMETHOD("is_block_scope", function(){
return true;
});
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
this.uses_arguments = false;
@@ -384,24 +301,16 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
|| (this.parent_scope && this.parent_scope.find_variable(name));
});
AST_Scope.DEFMETHOD("def_function", function(symbol, in_export, in_block){
this.functions.set(symbol.name, this.def_variable(symbol, in_export, in_block));
AST_Scope.DEFMETHOD("def_function", function(symbol){
this.functions.set(symbol.name, this.def_variable(symbol));
});
AST_Scope.DEFMETHOD("def_variable", function(symbol, in_export, in_block){
AST_Scope.DEFMETHOD("def_variable", function(symbol){
var def;
if (!this.variables.has(symbol.name)) {
def = new SymbolDef(this, this.variables.size(), symbol);
this.variables.set(symbol.name, def);
def.object_destructuring_arg = symbol.object_destructuring_arg;
if (in_export) {
def.export = true;
}
if (in_block && symbol instanceof AST_SymbolBlockDeclaration) {
def.global = false;
} else {
def.global = !this.parent_scope;
}
def.global = !this.parent_scope;
} else {
def = this.variables.get(symbol.name);
def.orig.push(symbol);
@@ -449,8 +358,7 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
});
AST_Symbol.DEFMETHOD("unmangleable", function(options){
var def = this.definition();
return def && def.unmangleable(options);
return this.definition().unmangleable(options);
});
// property accessors are not mangleable
@@ -492,7 +400,6 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
return defaults(options, {
eval : false,
ie8 : false,
keep_classnames: false,
keep_fnames : false,
reserved : [],
toplevel : false,
@@ -544,19 +451,13 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
node.mangled_name = name;
return true;
}
var mangle_with_block_scope =
(!options.ie8 && node instanceof AST_SymbolCatch) ||
node instanceof AST_SymbolBlockDeclaration;
if (mangle_with_block_scope) {
if (!options.ie8 && node instanceof AST_SymbolCatch) {
to_mangle.push(node.definition());
return;
}
});
this.walk(tw);
to_mangle.forEach(function(def){
if (def.destructuring && !def.destructuring.is_array) return;
def.mangle(options);
});
to_mangle.forEach(function(def){ def.mangle(options) });
if (options.cache) {
options.cache.cname = this.cname;
@@ -607,27 +508,21 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
else if (node instanceof AST_With)
base54.consider("with");
else if (node instanceof AST_ObjectSetter)
base54.consider("set" + (typeof node.key === "string" ? node.key : ""));
base54.consider("set" + node.key);
else if (node instanceof AST_ObjectGetter)
base54.consider("get" + (typeof node.key === "string" ? node.key : ""));
else if (node instanceof AST_ObjectKeyVal && typeof node.key === "string")
base54.consider(node.key);
else if (node instanceof AST_ConciseMethod && typeof node.key === "string")
base54.consider("get" + node.key);
else if (node instanceof AST_ObjectKeyVal)
base54.consider(node.key);
else if (node instanceof AST_New)
base54.consider("new");
else if (node instanceof AST_This)
base54.consider("this");
else if (node instanceof AST_Super)
base54.consider("super");
else if (node instanceof AST_Try)
base54.consider("try");
else if (node instanceof AST_Catch)
base54.consider("catch");
else if (node instanceof AST_Finally)
base54.consider("finally");
else if (node instanceof AST_Yield)
base54.consider("yield");
else if (node instanceof AST_Symbol && node.unmangleable(options))
base54.consider(node.name);
else if (node instanceof AST_Unary || node instanceof AST_Binary)

View File

@@ -163,18 +163,10 @@ TreeTransformer.prototype = new TreeWalker;
if (self.value) self.value = self.value.transform(tw);
});
_(AST_Destructuring, function(self, tw) {
self.names = do_list(self.names, tw);
});
_(AST_Lambda, function(self, tw){
if (self.name) self.name = self.name.transform(tw);
self.argnames = do_list(self.argnames, tw);
if (self.body instanceof AST_Node) {
self.body = self.body.transform(tw);
} else {
self.body = do_list(self.body, tw);
}
self.body = do_list(self.body, tw);
});
_(AST_Call, function(self, tw){
@@ -195,10 +187,6 @@ TreeTransformer.prototype = new TreeWalker;
self.property = self.property.transform(tw);
});
_(AST_Yield, function(self, tw){
if (self.expression) self.expression = self.expression.transform(tw);
});
_(AST_Unary, function(self, tw){
self.expression = self.expression.transform(tw);
});
@@ -223,32 +211,7 @@ TreeTransformer.prototype = new TreeWalker;
});
_(AST_ObjectProperty, function(self, tw){
if (self.key instanceof AST_Node) {
self.key = self.key.transform(tw);
}
self.value = self.value.transform(tw);
});
_(AST_Class, function(self, tw){
if (self.name) self.name = self.name.transform(tw);
if (self.extends) self.extends = self.extends.transform(tw);
self.properties = do_list(self.properties, tw);
});
_(AST_Expansion, function(self, tw){
self.expression = self.expression.transform(tw);
});
_(AST_TemplateString, function(self, tw) {
for (var i = 0; i < self.segments.length; i++) {
if (!(self.segments[i] instanceof AST_TemplateSegment)) {
self.segments[i] = self.segments[i].transform(tw);
}
}
});
_(AST_PrefixedTemplateString, function(self, tw) {
self.template_string = self.template_string.transform(tw);
});
})();

View File

@@ -4,7 +4,7 @@
"homepage": "http://lisperator.net/uglifyjs",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.0.1",
"version": "3.0.2",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -1,5 +1,3 @@
// NOTE trailing comma doesn't contribute to length of an array
// That also means the array changes length if previous element is a hole too and got cut off
holes_and_undefined: {
input: {
w = [1,,];
@@ -93,79 +91,6 @@ constant_join_2: {
}
}
spread_with_variable_as_last_element: {
input: {
var values = [4, 5, 6];
var a = [1, 2, 3, ...values];
}
expect: {
var values = [4, 5, 6];
var a = [1, 2, 3, ...values];
}
}
spread_with_variable_in_middle: {
input: {
var values = [4, 5, 6];
var a = [1, 2, 3, ...values, 7,,,];
}
expect: {
var values = [4, 5, 6];
var a = [1, 2, 3, ...values, 7,,,];
}
}
spread_with_variable_at_front: {
input: {
var values = [1, 2, 3];
var a = [...values, 4, 5, 6];
}
expect: {
var values = [1, 2, 3];
var a = [...values, 4, 5, 6];
}
}
spread_with_variable_at_front_after_elisions: {
input: {
var values = [1, 2, 3];
var a = [,,,...values, 4, 5, 6];
}
expect: {
var values = [1, 2, 3];
var a = [,,,...values, 4, 5, 6];
}
}
spread_with_array_at_end: {
input: {
var a = [1, 2, ...[4, 5, 6]];
}
expect: {
var a = [1, 2, ...[4, 5, 6]];
}
}
spread_with_logical_expression_at_end: {
options = { evaluate: true }
input: {
var a = [1, 2, 3, ...[2+2]]
}
expect: {
var a = [1, 2, 3, ...[4]]
}
}
spread_with_logical_expression_at_middle: {
options = { evaluate: true }
input: {
var a = [1, 1, ...[1+1, 1+2, 2+3], 8]
}
expect: {
var a = [1, 1, ...[2, 3, 5], 8]
}
}
constant_join_3: {
options = {
unsafe: true,

View File

@@ -1,137 +0,0 @@
arrow_functions_without_body: {
input: {
var a1 = () => 42;
var a2 = (p) => p;
var a3 = p => p;
var a4 = (...p) => p;
var a5 = (b, c) => b + c;
var a6 = (b, ...c) => b + c[0];
var a7 = (...b) => b.join();
}
expect: {
var a1 = () => 42;
var a2 = (p) => p;
var a3 = p => p;
var a4 = (...p) => p;
var a5 = (b, c) => b + c;
var a6 = (b, ...c) => b + c[0];
var a7 = (...b) => b.join();
}
}
arrow_functions_with_body: {
input: {
var a1 = () => {
var a = 42 * Math.random();
return a;
};
var a2 = (p) => {
var a = Math.random() * p;
return a;
};
var a3 = p => {
var a = Math.random() * p;
return a;
};
var a4 = (...p) => {
var a = Math.random() * p;
return a;
};
var a5 = (b, c) => {
var result = b * c + b / c;
return result
};
var a6 = (b, ...c) => {
var result = b;
for (var i = 0; i < c.length; i++)
result += c[i];
return result
};
var a7 = (...b) => {
b.join();
}
}
expect: {
var a1 = () => {
var a = 42 * Math.random();
return a;
};
var a2 = (p) => {
var a = Math.random() * p;
return a;
};
var a3 = p => {
var a = Math.random() * p;
return a;
};
var a4 = (...p) => {
var a = Math.random() * p;
return a;
};
var a5 = (b, c) => {
var result = b * c + b / c;
return result
};
var a6 = (b, ...c) => {
var result = b;
for (var i = 0; i < c.length; i++)
result += c[i];
return result
};
var a7 = (...b) => {
b.join();
};
}
}
arrow_function_with_single_parameter_with_default: {
input: {
var foo = (a = 0) => doSomething(a);
}
expect_exact: "var foo=(a=0)=>doSomething(a);"
}
arrow_binding_pattern: {
input: {
var foo = ([]) => "foo";
var bar = ({}) => "bar";
var with_default = (foo = "default") => foo;
var object_with_default = ({foo = "default", bar: baz = "default"}) => foo;
var array_after_spread = (...[foo]) => foo;
var array_after_spread = (...{foo}) => foo;
var computed = ({ [compute()]: x }) => {};
var array_hole = ([, , ...x] = [1, 2]) => {};
var object_trailing_elision = ({foo,}) => {};
var spread_empty_array = (...[]) => "foo";
var spread_empty_object = (...{}) => "foo";
}
expect: {
var foo = ([]) => "foo";
var bar = ({}) => "bar";
var with_default = (foo = "default") => foo;
var object_with_default = ({foo = "default", bar: baz = "default"}) => foo;
var array_after_spread = (...[foo]) => foo;
var array_after_spread = (...{foo}) => foo;
var computed = ({ [compute()]: x }) => {};
var array_hole = ([, , ...x] = [1, 2]) => {};
var object_trailing_elision = ({foo,}) => {};
var spread_empty_array = (...[]) => "foo";
var spread_empty_object = (...{}) => "foo";
}
}
arrow_binding_pattern_strict: {
input: {
var foo = ([,]) => "foo";
}
expect_exact: 'var foo=([,])=>"foo";'
}
arrow_with_regexp: {
input: {
num => /\d{11,14}/.test( num )
}
expect: {
num => /\d{11,14}/.test( num )
}
}

View File

@@ -1,177 +0,0 @@
let_statement: {
input: {
let x = 6;
}
expect_exact: "let x=6;"
}
do_not_hoist_let: {
options = {
hoist_vars: true,
};
input: {
function x() {
if (FOO) {
let let1;
let let2;
var var1;
var var2;
}
}
}
expect: {
function x() {
var var1, var2;
if (FOO) {
let let1;
let let2;
}
}
}
}
do_not_remove_anon_blocks_if_they_have_decls: {
input: {
function x() {
{
let x;
}
{
var x;
}
{
const y;
class Zee {};
}
}
{
let y;
}
{
var y;
}
}
expect: {
function x(){
{
let x
}
var x;
{
const y;
class Zee {}
}
}
{
let y
}
var y;
}
}
remove_unused_in_global_block: {
options = {
unused: true,
}
input: {
{
let x;
const y;
class Zee {};
var w;
}
let ex;
const why;
class Zed {};
var wut;
console.log(x, y, Zee);
}
expect: {
var w;
let ex;
const why;
class Zed {};
var wut;
console.log(x, y, Zee);
}
}
regression_block_scope_resolves: {
mangle = { };
options = {
dead_code: false
};
input: {
(function () {
if(1) {
let x;
const y;
class Zee {};
}
if(1) {
let ex;
const why;
class Zi {};
}
console.log(x, y, Zee, ex, why, Zi);
}());
}
expect: {
(function () {
if (1) {
let o;
const n;
class c {};
}
if (1) {
let o;
const n;
class c {};
}
console.log(x, y, Zee, ex, why, Zi);
}());
}
}
switch_block_scope_mangler: {
mangle = {}
input: {
var fn = function(code) {
switch (code) {
case 1:
let apple = code + 1;
let dog = code + 4;
console.log(apple, dog);
break;
case 2:
let banana = code + 2;
console.log(banana);
break;
default:
let cat = code + 3;
console.log(cat);
}
};
}
expect: {
var fn = function(o) {
switch (o) {
case 1:
let e = o + 1
let c = o + 4;
console.log(e, c);
break;
case 2:
let l = o + 2;
console.log(l);
break;
default:
let a = o + 3;
console.log(a);
}
};
}
}

View File

@@ -1328,7 +1328,6 @@ collapse_vars_regexp: {
issue_1537: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var k = '';
@@ -1340,104 +1339,6 @@ issue_1537: {
}
}
issue_1537_for_of: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var k = '';
for (k of {prop: 'val'}){}
}
expect: {
var k = '';
for (k of {prop: 'val'});
}
}
issue_1537_destructuring_1: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var x = 1, y = 2;
[x] = [y];
}
expect: {
var x = 1, y = 2;
[x] = [y];
}
}
issue_1537_destructuring_2: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var x = foo();
[x] = [1];
}
expect: {
var x = foo();
[x] = [1];
}
}
issue_1537_destructuring_3: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var x = Math.random();
({p: x = 9} = {v: 1});
}
expect: {
var x = Math.random();
({p: x = 9} = {v: 1});
}
}
issue_1537_destructuring_for_in: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var x = 1, y = 2;
(function() {
for ([[x], y] in a);
})();
}
expect: {
var x = 1, y = 2;
(function() {
for ([[x], y] in a);
})();
}
}
issue_1537_destructuring_for_of: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var x = 1, y = 2;
(function() {
for ([[x], y] of a);
})();
}
expect: {
var x = 1, y = 2;
(function() {
for ([[x], y] of a);
})();
}
}
issue_1562: {
options = {
collapse_vars: true,
@@ -2203,10 +2104,11 @@ unused_orig: {
expect: {
var a = 1;
console.log(function(b) {
var a;
var c = b;
for (var d in c)
return --b + (a = c[0]);
for (var d in c) {
var a = c[0];
return --b + a;
}
a && a.NaN;
}([2]), a);
}

View File

@@ -90,28 +90,6 @@ dead_code_constant_boolean_should_warn_more: {
expect_stdout: true
}
dead_code_block_decls_die: {
options = {
dead_code : true,
conditionals : true,
booleans : true,
evaluate : true
};
input: {
if (0) {
let foo = 6;
const bar = 12;
class Baz {};
var qux;
}
console.log(foo, bar, Baz);
}
expect: {
var qux;
console.log(foo, bar, Baz);
}
}
dead_code_const_declaration: {
options = {
dead_code : true,

View File

@@ -1,317 +0,0 @@
destructuring_arrays: {
input: {
{const [aa, bb] = cc;}
{const [aa, [bb, cc]] = dd;}
{let [aa, bb] = cc;}
{let [aa, [bb, cc]] = dd;}
var [aa, bb] = cc;
var [aa, [bb, cc]] = dd;
var [,[,,,,,],,,zz,] = xx; // Trailing comma
var [,,zzz,,] = xxx; // Trailing comma after hole
}
expect: {
{const [aa, bb] = cc;}
{const [aa, [bb, cc]] = dd;}
{let [aa, bb] = cc;}
{let [aa, [bb, cc]] = dd;}
var [aa, bb] = cc;
var [aa, [bb, cc]] = dd;
var [,[,,,,,],,,zz] = xx;
var [,,zzz,,] = xxx;
}
}
destructuring_arrays_holes: {
input: {
var [,,,,] = a;
var [,,b,] = c;
var [d,,] = e;
}
expect_exact: "var[,,,,]=a;var[,,b]=c;var[d,,]=e;"
}
destructuring_objects: {
input: {
{const {aa, bb} = {aa:1, bb:2};}
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
{let {aa, bb} = {aa:1, bb:2};}
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
var {aa, bb} = {aa:1, bb:2};
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
}
expect: {
{const {aa, bb} = {aa:1, bb:2};}
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
{let {aa, bb} = {aa:1, bb:2};}
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
var {aa, bb} = {aa:1, bb:2};
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
}
}
destructuring_objects_trailing_elision: {
beautify = {
ecma: 6
}
input: {
var {cc,} = foo;
}
expect_exact: "var{cc}=foo;"
}
nested_destructuring_objects: {
beautify = {
ecma: 6
}
input: {
const [{a},b] = c;
let [{a},b] = c;
var [{a},b] = c;
}
expect_exact: 'const[{a},b]=c;let[{a},b]=c;var[{a},b]=c;';
}
destructuring_constdef_in_loops: {
beautify = {
ecma: 6
}
input: {
for (const [x,y] in pairs);
for (const [a] = 0;;);
for (const {c} of cees);
}
expect_exact: "for(const[x,y]in pairs);for(const[a]=0;;);for(const{c}of cees);"
}
destructuring_letdef_in_loops: {
beautify = {
ecma: 6
}
input: {
for (let [x,y] in pairs);
for (let [a] = 0;;);
for (let {c} of cees);
}
expect_exact: "for(let[x,y]in pairs);for(let[a]=0;;);for(let{c}of cees);"
}
destructuring_vardef_in_loops: {
beautify = {
ecma: 6
}
input: {
for (var [x,y] in pairs);
for (var [a] = 0;;);
for (var {c} of cees);
}
expect_exact: "for(var[x,y]in pairs);for(var[a]=0;;);for(var{c}of cees);"
}
destructuring_expressions: {
beautify = {
ecma: 6
}
input: {
({a, b});
[{a}];
f({x});
}
expect_exact: "({a,b});[{a}];f({x});"
}
destructuring_remove_unused_1: {
options = {
unused: true
}
input: {
function a() {
var unused = "foo";
var a = [1];
var [b] = a;
f(b);
}
function b() {
var unused = "foo";
var a = {b: 1};
var {b} = a;
f(b);
}
function c() {
var unused = "foo";
var a = [[1]];
var [[b]] = a;
f(b);
}
function d() {
var unused = "foo";
var a = {b: {b:1}};
var {b:{b}} = a;
f(b);
}
function e() {
var unused = "foo";
var a = [1, 2, 3, 4, 5];
var x = [[1, 2, 3]];
var y = {h: 1};
var [b, ...c] = a;
var [...[e, f]] = x;
var [...{g: h}] = y;
f(b, c, e, f, g);
}
}
expect: {
function a() {
var a = [1];
var [b] = a;
f(b);
}
function b() {
var a = {b: 1};
var {b} = a;
f(b);
}
function c() {
var a = [[1]];
var [[b]] = a;
f(b);
}
function d() {
var a = {b: {b:1}};
var {b:{b}} = a;
f(b);
}
function e() {
var a = [1, 2, 3, 4, 5];
var x = [[1, 2, 3]];
var y = {h: 1};
var [b, ...c] = a;
var [...[e, f]] = x;
var [...{g: h}] = y;
f(b, c, e, f, g);
}
}
}
destructuring_remove_unused_2: {
options = {
unused: true
}
input: {
function a() {
var unused = "foo";
var a = [,,1];
var [b] = a;
f(b);
}
function b() {
var unused = "foo";
var a = [{a: [1]}];
var [{b: a}] = a;
f(b);
}
}
expect: {
function a() {
var a = [,,1];
var [b] = a;
f(b);
}
function b() {
var a = [{a: [1]}];
var [{b: a}] = a;
f(b);
}
}
}
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;
}
}
reduce_vars: {
options = {
reduce_vars: true,
}
input: {
{const [aa, [bb, cc]] = dd;}
{let [aa, [bb, cc]] = dd;}
var [aa, [bb, cc]] = dd;
[aa, [bb, cc]] = dd;
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}});
const [{a},b] = c;
let [{a},b] = c;
var [{a},b] = c;
[{a},b] = c;
for (const [x,y] in pairs);
for (let [x,y] in pairs);
for (var [x,y] in pairs);
for ([x,y] in pairs);
}
expect: {
{const [aa, [bb, cc]] = dd;}
{let [aa, [bb, cc]] = dd;}
var [aa, [bb, cc]] = dd;
[aa, [bb, cc]] = dd;
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}});
const [{a},b] = c;
let [{a},b] = c;
var [{a},b] = c;
[{a},b] = c;
for (const [x,y] in pairs);
for (let [x,y] in pairs);
for (var [x,y] in pairs);
for ([x,y] in pairs);
}
}
unused: {
options = {
unused: true,
}
input: {
let { foo: [, , ...a] } = { foo: [1, 2, 3, 4], bar: 5 };
console.log(a);
}
expect: {
let { foo: [, , ...a] } = { foo: [1, 2, 3, 4], bar: 5 };
console.log(a);
}
}

View File

@@ -1,10 +0,0 @@
class_directives_compression: {
input: {
class foo {
foo() {
"use strict";
}
}
}
expect_exact: "class foo{foo(){}}"
}

View File

@@ -164,87 +164,6 @@ used_var_in_catch: {
}
}
unused_block_decls_in_catch: {
options = { unused: true };
input: {
function foo() {
try {
foo();
} catch(ex) {
let x = 10;
const y = 10;
class Zee {};
}
}
}
expect: {
function foo() {
try {
foo();
} catch(ex) {}
}
}
}
used_block_decls_in_catch: {
options = { unused: true };
input: {
function foo() {
try {
foo();
} catch(ex) {
let x = 10;
const y = 10;
class Zee {};
}
console.log(x, y, Zee);
}
}
expect: {
function foo() {
try {
foo();
} catch(ex) {}
console.log(x, y, Zee);
}
}
}
unused_block_decls: {
options = { unused: true };
input: {
function foo() {
{
const x;
}
{
let y;
}
console.log(x, y);
}
}
expect: {
function foo() {
console.log(x, y);
}
}
}
unused_keep_harmony_destructuring: {
options = { unused: true };
input: {
function foo() {
var {x, y} = foo;
var a = foo;
}
}
expect: {
function foo() {
var {x, y} = foo;
}
}
}
keep_fnames: {
options = { unused: true, keep_fnames: true, unsafe: true };
input: {

View File

@@ -224,100 +224,6 @@ positive_zero: {
expect_stdout: true
}
pow: {
options = { evaluate: true }
input: {
var a = 5 ** 3;
}
expect: {
var a = 125;
}
}
pow_sequence: {
options = {
evaluate: true
}
input: {
var a = 2 ** 3 ** 2;
}
expect: {
var a = 512;
}
}
pow_mixed: {
options = {
evaluate: true
}
input: {
var a = 5 + 2 ** 3 + 5;
var b = 5 * 3 ** 2;
var c = 5 ** 3 * 2;
var d = 5 ** +3;
}
expect: {
var a = 18;
var b = 45;
var c = 250;
var d = 125;
}
}
pow_with_right_side_evaluating_to_unary: {
options = {
evaluate: true
}
input: {
var a = (4 - 7) ** foo;
var b = ++bar ** 3;
var c = --baz ** 2;
}
expect_exact: "var a=(-3)**foo;var b=++bar**3;var c=--baz**2;"
}
pow_with_number_constants: {
options = {
evaluate: true
}
input: {
var a = 5 ** NaN;
/* NaN exponent results to NaN */
var b = 42 ** +0;
/* +0 exponent results to NaN */
var c = 42 ** -0;
/* -0 exponent results to NaN */
var d = NaN ** 1;
/* NaN with non-zero exponent is NaN */
var e = 2 ** Infinity;
/* abs(base) > 1 with Infinity as exponent is Infinity */
var f = 2 ** -Infinity;
/* abs(base) > 1 with -Infinity as exponent is +0 */
var g = (-7) ** (0.5);
var h = 2324334 ** 34343443;
var i = (-2324334) ** 34343443;
var j = 2 ** (-3);
var k = 2.0 ** -3;
var l = 2.0 ** (5 - 7);
var m = 3 ** -10; // Result will be 0.000016935087808430286, which is too long
}
expect: {
var a = NaN;
var b = 1;
var c = 1;
var d = NaN;
var e = 1/0;
var f = 0;
var g = NaN;
var h = 1/0;
var i = -1/0;
var j = .125;
var k = .125;
var l = .25;
var m = 3 ** -10;
}
}
unsafe_constant: {
options = {
evaluate : true,

View File

@@ -1,28 +0,0 @@
expand_arguments: {
input: {
func(a, ...rest);
func(...all);
}
expect_exact: "func(a,...rest);func(...all);"
}
expand_expression_arguments: {
input: {
f(...a.b);
f(...a.b());
f(...(a));
f(...(a.b));
f(...a[i]);
}
expect_exact: "f(...a.b);f(...a.b());f(...a);f(...a.b);f(...a[i]);"
}
expand_parameters: {
input: {
(function (a, ...b){});
(function (...args){});
}
expect_exact: "(function(a,...b){});(function(...args){});"
}

View File

@@ -1,52 +0,0 @@
pow: {
input: {
var a = 2 ** 7;
var b = 3;
b **= 2;
}
expect: {
var a = 2 ** 7;
var b = 3;
b **= 2;
}
}
pow_with_number_constants: {
input: {
var a = 5 ** NaN;
var b = 42 ** +0;
var c = 42 ** -0;
var d = NaN ** 1;
var e = 2 ** Infinity;
var f = 2 ** -Infinity;
}
expect: {
var a = 5 ** NaN;
var b = 42 ** +0;
var c = 42 ** -0;
var d = NaN ** 1;
var e = 2 ** (1/0);
var f = 2 ** (-1/0);
}
}
pow_with_parentheses: {
input: {
var g = (-7) ** (0.5);
var h = 2324334 ** 34343443;
var i = (-2324334) ** 34343443;
var j = 2 ** (-3);
var k = 2.0 ** -3;
var l = 2.0 ** (5 - 7);
}
expect_exact: "var g=(-7)**.5;var h=2324334**34343443;var i=(-2324334)**34343443;var j=2**-3;var k=2**-3;var l=2**(5-7);"
}
pow_with_unary_between_brackets: {
input: {
var a = (-(+5)) ** 3;
}
expect: {
var a = (-+5)**3;
}
}

View File

@@ -1,394 +0,0 @@
arrow_function_parens: {
input: {
something && (() => {});
}
expect_exact: "something&&(()=>{});"
}
arrow_function_parens_2: {
input: {
(() => null)();
}
expect_exact: "(()=>null)();"
}
typeof_arrow_functions: {
options = {
evaluate: true
}
input: {
var foo = typeof (x) => null;
}
expect_exact: "var foo=\"function\";"
}
classes: {
input: {
class SomeClass {
constructor() {
};
foo() {};
};
class NoSemi {
constructor(...args) {
}
foo() {}
};
class ChildClass extends SomeClass {};
var asExpression = class AsExpression {};
var nameless = class {};
}
expect_exact: "class SomeClass{constructor(){}foo(){}}class NoSemi{constructor(...args){}foo(){}}class ChildClass extends SomeClass{}var asExpression=class AsExpression{};var nameless=class{};"
}
class_statics: {
input: {
x = class {
static staticMethod() {}
static get foo() {}
static set bar() {}
static() { /* "static" can be a method name! */ }
get() { /* "get" can be a method name! */ }
set() { /* "set" can be a method name! */ }
}
}
expect_exact: "x=class{static staticMethod(){}static get foo(){}static set bar(){}static(){}get(){}set(){}};"
}
class_name_can_be_mangled: {
mangle = { };
input: {
function x() {
class Foo {
}
var class1 = Foo
var class2 = class Bar {}
}
}
expect: {
function x() {
class a { }
var n = a
var r = class a {}
}
}
}
class_name_can_be_preserved: {
mangle = {
keep_classnames: true
}
input: {
function x() {
(class Baz { });
class Foo {};
}
}
expect: {
function x() {
(class Baz { });
class Foo {};
}
}
}
classes_can_have_generators: {
input: {
class Foo {
*bar() {}
static *baz() {}
}
}
expect: {
class Foo {
*bar() {}
static *baz() {}
}
}
}
classes_can_have_computed_generators: {
input: {
class C4 {
*['constructor']() {}
}
}
expect: {
class C4 {
*['constructor']() {}
}
}
}
classes_can_have_computed_static: {
input: {
class C4 {
static ['constructor']() {}
}
}
expect: {
class C4 {
static ['constructor']() {}
}
}
}
class_methods_and_getters_with_keep_quoted_props_enabled: {
beautify = {
quote_style: 3,
keep_quoted_props: true,
}
input: {
class clss {
a() {}
"b"() {}
get c() { return "c"}
get "d"() { return "d"}
set e(a) { doSomething(a); }
set 'f'(a) { doSomething(b); }
static g() {}
static "h"() {}
}
}
expect_exact: 'class clss{a(){}"b"(){}get c(){return"c"}get"d"(){return"d"}set e(a){doSomething(a)}set\'f\'(a){doSomething(b)}static g(){}static"h"(){}}'
}
classes_with_expression_as_expand: {
input: {
class D extends (calls++, C) {}
}
expect_exact: "class D extends(calls++,C){}"
}
new_target: {
input: {
new.target;
new.target.name;
}
expect_exact: "new.target;new.target.name;"
}
number_literals: {
input: {
0b1001;
0B1001;
0o11;
0O11;
}
expect: {
9;
9;
9;
9;
}
}
import_statement: {
input: {
import "mod-name";
import Foo from "bar";
import { Bar, Baz } from 'lel';
import Bar, { Foo } from 'lel';
import { Bar as kex, Baz as food } from 'lel';
}
expect_exact: 'import"mod-name";import Foo from"bar";import{Bar,Baz}from"lel";import Bar,{Foo}from"lel";import{Bar as kex,Baz as food}from"lel";'
}
import_all_statement: {
input: {
import * from 'lel';
import * as Lel from 'lel';
}
expect_exact: 'import*from"lel";import*as Lel from"lel";'
}
export_statement: {
input: {
export default 1;
export var foo = 4;
export let foo = 6;
export const foo = 6;
export function foo() {};
export class foo { };
}
expect_exact: "export default 1;export var foo=4;export let foo=6;export const foo=6;export function foo(){};export class foo{};"
}
export_module_statement: {
input: {
export * from "a.js";
export {A} from "a.js";
export {A, B} from "a.js";
export {C};
}
expect_exact: 'export*from"a.js";export{A}from"a.js";export{A,B}from"a.js";export{C};'
}
import_statement_mangling: {
mangle = { toplevel: true };
input: {
import Foo from "foo";
import Bar, {Food} from "lel";
import {What as Whatever} from "lel";
Foo();
Bar();
Food();
Whatever();
}
expect: {
import l from "foo";
import e, {Food as o} from "lel";
import {What as f} from "lel";
l();
e();
o();
f();
}
}
export_statement_mangling: {
mangle = { };
input: {
export var foo = 6;
export function bar() { }
export class Baz { }
bar(foo, Baz)
}
expect: {
export var foo = 6;
export function bar() { }
export class Baz { }
bar(foo, Baz)
}
}
// https://github.com/mishoo/UglifyJS2/issues/1021
regression_for_of_const: {
input: {
for (const x of y) {}
for (const x in y) {}
}
expect: {
for (const x of y);for (const x in y);
}
}
// Fabio: My patches accidentally caused a crash whenever
// there's an extraneous set of parens around an object.
regression_cannot_destructure: {
input: {
var x = ({ x : 3 });
x(({ x: 3 }));
}
expect_exact: "var x={x:3};x({x:3});";
}
regression_cannot_use_of: {
input: {
function of() {
}
var of = "is a valid variable name";
of = { of: "is ok" };
x.of;
of: foo()
}
expect: {
function of(){}
var of="is a valid variable name";
of={of:"is ok"};
x.of;
foo(); /* Label statement missing? No prob. */
}
}
fat_arrow_as_param: {
input: {
foo(x => x);
foo(x => x, y => y);
foo(x => (x, x));
foo(x => (x, x), y => (y, y));
}
expect_exact: "foo(x=>x);foo(x=>x,y=>y);foo(x=>(x,x));foo(x=>(x,x),y=>(y,y));"
}
default_assign: {
options = {
keep_fargs: false,
unused: true,
}
input: {
function f(a, b = 3) {
console.log(a);
}
g = ([[] = 123]) => {};
h = ([[x, y, z] = [4, 5, 6]] = []) => {};
function i([[x, y, z] = [4, 5, 6]] = []) {
console.log(b);
};
}
expect: {
function f(a) {
console.log(a);
}
g = ([[] = 123]) => {};
h = ([[x, y, z] = [4, 5, 6]] = []) => {};
function i([[x, y, z] = [4, 5, 6]] = []) {
console.log(b);
};
}
}
expansion: {
options = {
keep_fargs: false,
unused: true,
}
input: {
function f(a, ...b) {
console.log(a);
}
}
expect: {
function f(a) {
console.log(a);
}
}
}
issue_1613: {
mangle = { toplevel: true };
input: {
const name = 1;
const foo = {
name
};
}
expect_exact: "const n=1;const c={name:n};"
}
format_methods: {
beautify = {
beautify: true,
}
input: {
class A extends B {constructor(a){x()} static s(b,c){y()} run(d,e,f){z()}}
}
expect_exact: [
"class A extends B {",
" constructor(a) {",
" x();",
" }",
" static s(b, c) {",
" y();",
" }",
" run(d, e, f) {",
" z();",
" }",
"}",
]
}

View File

@@ -1,85 +0,0 @@
hoist_vars: {
options = {
hoist_vars: true
}
input: {
function a() {
bar();
var var1;
var var2;
}
function b(anArg) {
bar();
var var1;
var anArg;
}
}
expect: {
function a() {
var var1, var2; // Vars go up and are joined
bar();
}
function b(anArg) {
var var1;
bar();
// But vars named like arguments go away!
}
}
}
hoist_funs: {
options = {
hoist_funs: true
}
input: {
function a() {
bar();
function foo() {}
}
}
expect: {
function a() {
function foo() {} // Funs go up
bar();
}
}
}
hoist_no_destructurings: {
options = {
hoist_vars: true,
hoist_funs: true
}
input: {
function a([anArg]) {
bar();
var var1;
var anArg; // Because anArg is already declared, this goes away!
}
}
expect: {
function a([anArg]) {
var var1;
bar();
}
}
}
dont_hoist_var_destructurings: {
options = {
hoist_vars: true,
hoist_funs: true
}
input: {
function x() {
// If foo is null or undefined, this should be an exception
var {x,y} = foo;
}
}
expect: {
function x() {
var {x,y} = foo;
}
}
}

View File

@@ -53,12 +53,3 @@ html_comment_in_string_literal: {
}
expect_exact: 'function f(){return"\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e"}';
}
html_comment_after_multiline_comment: {
input: {
var foo; /*
*/--> var bar;
var foobar;
}
expect_exact: "var foo;var foobar;"
}

View File

@@ -1,8 +0,0 @@
parenthesis_strings_in_parenthesis: {
input: {
var foo = ('(');
a(')');
}
expect_exact: 'var foo="(";a(")");'
}

View File

@@ -1,30 +0,0 @@
issue_1043: {
options = {
side_effects: true
};
input: {
function* range(start = 0, end = null, step = 1) {
if (end == null) {
end = start;
start = 0;
}
for (let i = start; i < end; i += step) {
yield i;
}
}
}
expect: {
function* range(start = 0, end = null, step = 1) {
if (null == end) {
end = start;
start = 0;
}
for (let i = start; i < end; i += step)
yield i;
}
}
}

View File

@@ -1,9 +0,0 @@
issue_1044: {
options = { evaluate: true, conditionals: true };
input: {
const mixed = Base ? class extends Base {} : class {}
}
expect: {
const mixed = Base ? class extends Base {} : class {}
}
}

View File

@@ -1,76 +0,0 @@
issue_1212_debug_false: {
options = {
global_defs : { DEBUG: false },
sequences : true,
properties : true,
dead_code : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
loops : true,
unused : true,
hoist_funs : true,
keep_fargs : true,
if_return : true,
join_vars : true,
cascade : true,
side_effects : true,
}
input: {
class foo {
bar() {
if (DEBUG)
console.log("DEV");
else
console.log("PROD");
}
}
new foo().bar();
}
expect: {
class foo{
bar() { console.log("PROD") }
}
(new foo).bar();
}
}
issue_1212_debug_true: {
options = {
global_defs : { DEBUG: true },
sequences : true,
properties : true,
dead_code : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
loops : true,
unused : true,
hoist_funs : true,
keep_fargs : true,
if_return : true,
join_vars : true,
cascade : true,
side_effects : true,
}
input: {
class foo {
bar() {
if (DEBUG)
console.log("DEV");
else
console.log("PROD");
}
}
new foo().bar();
}
expect: {
class foo{
bar() { console.log("DEV") }
}
(new foo).bar();
}
}

View File

@@ -1,291 +0,0 @@
same_variable_in_multiple_for_loop: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: true,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
for (let i = 0; i < 3; i++) {
let a = 100;
console.log(i, a);
for (let i = 0; i < 2; i++) {
console.log(i, a);
let c = 2;
console.log(c);
}
}
}
expect: {
for (let o = 0; o < 3; o++) {
let l = 100;
console.log(o, l);
for (let o = 0; o < 2; o++) {
console.log(o, l);
let c = 2;
console.log(c);
}
}
}
expect_stdout: true
}
same_variable_in_multiple_forOf: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: true,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
var test = [ "a", "b", "c" ];
for (let tmp of test) {
console.log(tmp);
let dd;
dd = [ "e", "f", "g" ];
for (let tmp of dd) {
console.log(tmp);
}
}
}
expect: {
var test = [ "a", "b", "c" ];
for (let o of test) {
console.log(o);
let e;
e = [ "e", "f", "g" ];
for (let o of e)
console.log(o);
}
}
expect_stdout: true
}
same_variable_in_multiple_forIn: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: false,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
var test = [ "a", "b", "c" ];
for (let tmp in test) {
console.log(tmp);
let dd;
dd = [ "e", "f", "g" ];
for (let tmp in test) {
console.log(tmp);
}
}
}
expect: {
var test = [ "a", "b", "c" ];
for (let o in test) {
console.log(o);
let e;
e = [ "e", "f", "g" ];
for (let o in test)
console.log(o);
}
}
expect_stdout: true
}
different_variable_in_multiple_for_loop: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: true,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
for (let i = 0; i < 3; i++) {
let a = 100;
console.log(i, a);
for (let j = 0; j < 2; j++) {
console.log(j, a);
let c = 2;
console.log(c);
}
}
}
expect: {
for (let o = 0; o < 3; o++) {
let l = 100;
console.log(o, l);
for (let o = 0; o < 2; o++) {
console.log(o, l);
let c = 2;
console.log(c);
}
}
}
expect_stdout: true
}
different_variable_in_multiple_forOf: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: true,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
var test = [ "a", "b", "c" ];
for (let tmp of test) {
console.log(tmp);
let dd;
dd = [ "e", "f", "g" ];
for (let t of dd) {
console.log(t);
}
}
}
expect: {
var test = [ "a", "b", "c" ];
for (let o of test) {
console.log(o);
let e;
e = [ "e", "f", "g" ];
for (let o of e)
console.log(o);
}
}
expect_stdout: true
}
different_variable_in_multiple_forIn: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: false,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
var test = [ "a", "b", "c" ];
for (let tmp in test) {
console.log(tmp);
let dd;
dd = [ "e", "f", "g" ];
for (let t in test) {
console.log(t);
}
}
}
expect: {
var test = [ "a", "b", "c" ];
for (let o in test) {
console.log(o);
let e;
e = [ "e", "f", "g" ];
for (let o in test)
console.log(o);
}
}
expect_stdout: true
}
more_variable_in_multiple_for: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: false,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
for (let a = 9, i = 0; i < 20; i += a) {
let b = a++ + i;
console.log(a, b, i);
for (let k = b, m = b*b, i = 0; i < 10; i++) {
console.log(a, b, m, k, i);
}
}
}
expect: {
for (let o = 9, l = 0; l < 20; l += o) {
let c = o++ + l;
console.log(o, c, l);
for (let l = c, e = c * c, f = 0; f < 10; f++)
console.log(o, c, e, l, f);
}
}
expect_stdout: true
}

View File

@@ -103,3 +103,137 @@ numeric_literal: {
"8 7 8",
]
}
identifier: {
mangle_props = {}
input: {
var obj = {
abstract: 1,
boolean: 2,
byte: 3,
char: 4,
class: 5,
double: 6,
enum: 7,
export: 8,
extends: 9,
final: 10,
float: 11,
goto: 12,
implements: 13,
import: 14,
int: 15,
interface: 16,
let: 17,
long: 18,
native: 19,
package: 20,
private: 21,
protected: 22,
public: 23,
short: 24,
static: 25,
super: 26,
synchronized: 27,
this: 28,
throws: 29,
transient: 30,
volatile: 31,
yield: 32,
false: 33,
null: 34,
true: 35,
break: 36,
case: 37,
catch: 38,
const: 39,
continue: 40,
debugger: 41,
default: 42,
delete: 43,
do: 44,
else: 45,
finally: 46,
for: 47,
function: 48,
if: 49,
in: 50,
instanceof: 51,
new: 52,
return: 53,
switch: 54,
throw: 55,
try: 56,
typeof: 57,
var: 58,
void: 59,
while: 60,
with: 61,
};
}
expect: {
var obj = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5,
f: 6,
g: 7,
h: 8,
i: 9,
j: 10,
k: 11,
l: 12,
m: 13,
n: 14,
o: 15,
p: 16,
q: 17,
r: 18,
s: 19,
t: 20,
u: 21,
v: 22,
w: 23,
x: 24,
y: 25,
z: 26,
A: 27,
B: 28,
C: 29,
D: 30,
F: 31,
G: 32,
false: 33,
null: 34,
true: 35,
H: 36,
I: 37,
J: 38,
K: 39,
L: 40,
M: 41,
N: 42,
O: 43,
P: 44,
Q: 45,
R: 46,
S: 47,
T: 48,
U: 49,
V: 50,
W: 51,
X: 52,
Y: 53,
Z: 54,
$: 55,
_: 56,
aa: 57,
ba: 58,
ca: 59,
da: 60,
ea: 61,
};
}
}

View File

@@ -1,34 +0,0 @@
compress_new_function: {
options = {
unsafe: true
}
input: {
new Function("aa, bb", 'return aa;');
}
expect: {
Function("a", "b", "return a");
}
}
compress_new_function_with_destruct: {
options = {
unsafe: true,
ecma: 6
}
beautify = {
ecma: 6
}
input: {
new Function("aa, [bb]", 'return aa;');
new Function("aa, {bb}", 'return aa;');
new Function("[[aa]], [{bb}]", 'return aa;');
}
expect: {
Function("a", "[b]", "return a");
Function("a", "{bb}", "return a");
Function("[[a]]", "[{bb}]", 'return a');
}
}

View File

@@ -1,9 +0,0 @@
template_strings: {
input: {
foo(
`<span>${contents}</span>`,
`<a href="${url}">${text}</a>`
);
}
expect_exact: "foo(`<span>${contents}</span>`,`<a href=\"${url}\">${text}</a>`);"
}

View File

@@ -1,40 +0,0 @@
only_vars: {
options = { join_vars: true };
input: {
let netmaskBinary = '';
for (let i = 0; i < netmaskBits; ++i) {
netmaskBinary += '1';
}
}
expect: {
let netmaskBinary = '';
for (let i = 0; i < netmaskBits; ++i) netmaskBinary += '1';
}
}
issue_1079_with_vars: {
options = { join_vars: true };
input: {
var netmaskBinary = '';
for (var i = 0; i < netmaskBits; ++i) {
netmaskBinary += '1';
}
}
expect: {
for (var netmaskBinary = '', i = 0; i < netmaskBits; ++i) netmaskBinary += '1';
}
}
issue_1079_with_mixed: {
options = { join_vars: true };
input: {
var netmaskBinary = '';
for (let i = 0; i < netmaskBits; ++i) {
netmaskBinary += '1';
}
}
expect: {
var netmaskBinary = ''
for (let i = 0; i < netmaskBits; ++i) netmaskBinary += '1';
}
}

View File

@@ -82,19 +82,3 @@ new_with_unary_prefix: {
}
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]);
}
}

View File

@@ -1,512 +0,0 @@
getter_setter: {
input: {
var get = "bar";
var a = {
get,
set: "foo",
get bar() {
return this.get;
},
get 5() {
return "five";
},
get 0xf55() {
return "f five five";
},
get "five"() {
return 5;
},
set one(value) {
this._one = value;
},
set 9(value) {
this._nine = value;
},
set 0b1010(value) {
this._ten = value;
},
set "eleven"(value) {
this._eleven = value;
}
};
var b = {
get() { return "gift"; },
set: function(code) { return "Storing code " + code; }
};
var c = {
["get"]: "foo",
["set"]: "bar"
};
var d = {
get: "foo",
set: "bar"
};
}
expect: {
var get = "bar";
var a = {
get,
set: "foo",
get bar() {
return this.get;
},
get 5() {
return "five";
},
get 0xf55() {
return "f five five";
},
get "five"() {
return 5;
},
set one(value) {
this._one = value;
},
set 9(value) {
this._nine = value;
},
set 0b1010(value) {
this._ten = value;
},
set "eleven"(value) {
this._eleven = value;
}
};
var b = {
get() { return "gift"; },
set: function(code) { return "Storing code " + code; }
};
var c = {
["get"]: "foo",
["set"]: "bar"
};
var d = {
get: "foo",
set: "bar"
};
}
}
getter_setter_mangler: {
mangle = {}
beautify = {
ecma: 6
}
input: {
function f(get,set) {
return {
get,
set,
get g(){},
set s(n){},
c,
a:1,
m(){}
};
}
}
expect_exact: "function f(n,t){return{get:n,set:t,get g(){},set s(n){},c,a:1,m(){}}}"
}
use_shorthand_opportunity: {
beautify = {
ecma: 6
}
input: {
var foo = 123;
var obj = {foo: foo};
}
expect_exact: "var foo=123;var obj={foo};"
}
computed_property_names: {
input: {
obj({ ["x" + "x"]: 6 });
}
expect_exact: 'obj({["x"+"x"]:6});'
}
computed_property_names_evaluated_1: {
options = {
evaluate: true
}
input: {
obj({
[1 + 1]: 2,
["x" + "x"]: 6
});
}
expect_exact: 'obj({[2]:2,["xx"]:6});'
}
computed_property_names_evaluated_2: {
options = {
evaluate: true
}
input: {
var foo = something();
var obj = {
[foo]() {
return "blah";
}
}
}
expect_exact: 'var foo=something();var obj={[foo](){return"blah"}};'
}
shorthand_properties: {
mangle = true;
input: {
(function() {
var prop = 1;
const value = {prop};
return value;
})();
}
expect: {
(function() {
var n = 1;
const r = {prop:n};
return r;
})();
}
}
concise_methods: {
beautify = {
ecma: 6
}
input: {
x = {
foo(a, b) {
return x;
}
}
y = {
foo([{a}]) {
return a;
},
bar(){}
}
}
expect_exact: "x={foo(a,b){return x}};y={foo([{a}]){return a},bar(){}};"
}
concise_methods_with_computed_property: {
options = {
evaluate: true
}
input: {
var foo = {
[Symbol.iterator]() {
return { /* stuff */ }
},
[1 + 2]() {
return 3;
},
["1" + "4"]() {
return 14;
}
}
}
expect: {
var foo = {
[Symbol.iterator]() {
return { /* stuff */ }
},
[3]() {
return 3;
},
["14"]() {
return 14;
}
}
}
}
concise_methods_with_computed_property2: {
options = {
evaluate: true
}
input: {
var foo = {
[[1]](){
return "success";
}
};
doSomething(foo[[1]]());
}
expect_exact: 'var foo={[[1]](){return"success"}};doSomething(foo[[1]]());'
}
concise_methods_with_various_property_names: {
input: {
var get = "bar";
var a = {
bar() {
return this.get;
},
5() {
return "five";
},
0xf55() {
return "f five five";
},
"five"() {
return 5;
},
0b1010(value) {
this._ten = value;
}
};
}
expect: {
var get = "bar";
var a = {
bar() {
return this.get;
},
5() {
return "five";
},
0xf55() {
return "f five five";
},
"five"() {
return 5;
},
0b1010(value) {
this._ten = value;
}
};
}
}
concise_methods_and_mangle_props: {
mangle_props = {
regex: /_/
};
input: {
function x() {
obj = {
_foo() { return 1; }
}
}
}
expect: {
function x() {
obj = {
a() { return 1; }
}
}
}
}
concise_generators: {
beautify = {
ecma: 6
}
input: {
x = {
*foo(a, b) {
return x;
}
}
y = {
*foo([{a}]) {
yield a;
},
bar(){}
}
}
expect_exact: "x={*foo(a,b){return x}};y={*foo([{a}]){yield a},bar(){}};"
}
concise_methods_and_keyword_names: {
input: {
x = {
catch() {},
throw() {}
}
}
expect: {
x={catch(){},throw(){}};
}
}
getter_setter_with_computed_value: {
input: {
class C {
get ['a']() {
return 'A';
}
set ['a'](value) {
do_something(a);
}
}
var x = {
get [a.b]() {
return 42;
}
};
class MyArray extends Array {
get [Symbol.species]() {
return Array;
}
}
}
expect_exact: 'class C{get["a"](){return"A"}set["a"](value){do_something(a)}}var x={get[a.b](){return 42}};class MyArray extends Array{get[Symbol.species](){return Array}}'
}
property_with_operator_value: {
input: {
var foo = {
"*": 1,
get "*"() {
return 2;
},
*"*"() {
return 3;
},
"%": 1,
get "%"() {
return 2;
},
*"%"() {
return 3;
}
}
class bar {
get "*"() {
return 1
}
*"*"() {
return 2;
}
get "%"() {
return 1
}
*"%"() {
return 2;
}
}
}
expect_exact: 'var foo={"*":1,get"*"(){return 2},*"*"(){return 3},"%":1,get"%"(){return 2},*"%"(){return 3}};class bar{get"*"(){return 1}*"*"(){return 2}get"%"(){return 1}*"%"(){return 2}}'
}
property_with_unprintable: {
input: {
var foo = {
"\x00\x01": "foo",
get "\x00\x01"() {
return "bar";
},
set "\x00\x01"(foo) {
save(foo);
},
*"\x00\x01"() {
return "foobar";
}
}
class bar {
get "\x00\x01"() {
return "bar"
}
set "\x00\x01"(foo) {
save(foo);
}
*"\x00\x01"() {
return "foobar";
}
}
}
expect_exact: 'var foo={"\\0\x01":"foo",get"\\0\x01"(){return"bar"},set"\\0\x01"(foo){save(foo)},*"\\0\x01"(){return"foobar"}};class bar{get"\\0\x01"(){return"bar"}set"\\0\x01"(foo){save(foo)}*"\\0\x01"(){return"foobar"}}'
}
property_with_unprintable_ascii_only: {
beautify = {
ascii_only: true,
}
input: {
var foo = {
"\x00\x01": "foo",
get "\x00\x01"() {
return "bar";
},
set "\x00\x01"(foo) {
save(foo);
},
*"\x00\x01"() {
return "foobar";
}
}
class bar {
get "\x00\x01"() {
return "bar"
}
set "\x00\x01"(foo) {
save(foo);
}
*"\x00\x01"() {
return "foobar";
}
}
}
expect_exact: 'var foo={"\\0\\x01":"foo",get"\\0\\x01"(){return"bar"},set"\\0\\x01"(foo){save(foo)},*"\\0\\x01"(){return"foobar"}};class bar{get"\\0\\x01"(){return"bar"}set"\\0\\x01"(foo){save(foo)}*"\\0\\x01"(){return"foobar"}}'
}
property_with_unprintable_ascii_only_static: {
beautify = {
ascii_only: true
}
input: {
class foo {
static get "\x02\x03"() {
return "bar";
}
static set "\x04\x05"(foo) {
save(foo);
}
}
}
expect_exact: 'class foo{static get"\\x02\\x03"(){return"bar"}static set"\\x04\\x05"(foo){save(foo)}}'
}
methods_and_getters_with_keep_quoted_props_enabled: {
beautify = {
quote_style: 3,
keep_quoted_props: true,
}
input: {
var obj = {
a() {},
"b"() {},
get c() { return "c"},
get "d"() { return "d"},
set e(a) { doSomething(a); },
set f(a) { doSomething(b); }
}
}
expect_exact: 'var obj={a(){},"b"(){},get c(){return"c"},get"d"(){return"d"},set e(a){doSomething(a)},set f(a){doSomething(b)}};'
}
allow_assignments_to_property_values: {
input: {
var foo = {123: foo = 123} = {foo: "456"};
}
expect: {
var foo = {123: foo = 123} = {foo: "456"};
}
}
variable_as_computed_property: {
input: {
function getLine(header) {
return {
[header]: {}
};
}
}
expect_exact: "function getLine(header){return{[header]:{}}}"
}

View File

@@ -1,180 +0,0 @@
arrow_functions: {
input: {
(a) => b; // 1 args
(a, b) => c; // n args
() => b; // 0 args
(a) => (b) => c; // func returns func returns func
(a) => ((b) => c); // So these parens are dropped
() => (b,c) => d; // func returns func returns func
a=>{return b;}
a => 'lel'; // Dropping the parens
}
expect_exact: "a=>b;(a,b)=>c;()=>b;a=>b=>c;a=>b=>c;()=>(b,c)=>d;a=>b;a=>\"lel\";"
}
arrow_return: {
input: {
() => {};
() => { return; };
a => { return 1; }
a => { return -b }
a => { return b; var b; }
(x, y) => { return x - y; }
}
expect_exact: "()=>{};()=>{};a=>1;a=>-b;a=>{return b;var b};(x,y)=>x-y;"
}
regression_arrow_functions_and_hoist: {
options = {
hoist_vars: true,
hoist_funs: true
}
input: {
(a) => b;
}
expect_exact: "a=>b;"
}
regression_assign_arrow_functions: {
input: {
oninstall = e => false;
oninstall = () => false;
}
expect: {
oninstall=e=>false;
oninstall=()=>false;
}
}
destructuring_arguments_1: {
input: {
(function ( a ) { });
(function ( [ a ] ) { });
(function ( [ a, b ] ) { });
(function ( [ [ a ] ] ) { });
(function ( [ [ a, b ] ] ) { });
(function ( [ a, [ b ] ] ) { });
(function ( [ [ b ], a ] ) { });
(function ( { a } ) { });
(function ( { a, b } ) { });
(function ( [ { a } ] ) { });
(function ( [ { a, b } ] ) { });
(function ( [ a, { b } ] ) { });
(function ( [ { b }, a ] ) { });
( [ a ] ) => { };
( [ a, b ] ) => { };
( { a } ) => { };
( { a, b, c, d, e } ) => { };
( [ a ] ) => b;
( [ a, b ] ) => c;
( { a } ) => b;
( { a, b } ) => c;
}
expect: {
(function(a){});
(function([a]){});
(function([a,b]){});
(function([[a]]){});
(function([[a,b]]){});
(function([a,[b]]){});
(function([[b],a]){});
(function({a}){});
(function({a,b}){});
(function([{a}]){});
(function([{a,b}]){});
(function([a,{b}]){});
(function([{b},a]){});
([a])=>{};
([a,b])=>{};
({a})=>{};
({a,b,c,d,e})=>{};
([a])=>b;
([a,b])=>c;
({a})=>b;
({a,b})=>c;
}
}
destructuring_arguments_2: {
input: {
(function([]) {});
(function({}) {});
(function([,,,,,]) {});
(function ([a, {b: c}]) {});
(function ([...args]) {});
(function ({x,}) {});
class a { *method({ [thrower()]: x } = {}) {}};
(function(a, b, c, d, [{e: [...f]}]){})(1, 2, 3, 4, [{e: [1, 2, 3]}]);
}
expect: {
(function([]) {});
(function({}) {});
(function([,,,,,]) {});
(function ([a, {b: c}]) {});
(function ([...args]) {});
(function ({x,}) {});
class a { *method({ [thrower()]: x } = {}) {}};
(function(a, b, c, d, [{e: [...f]}]){})(1, 2, 3, 4, [{e: [1, 2, 3]}]);
}
}
destructuring_arguments_3: {
beautify = {
ecma: 6
}
input: {
function fn3({x: {y: {z: {} = 42}}}) {}
const { cover = (function () {}), xCover = (0, function() {}) } = {};
let { cover = (function () {}), xCover = (0, function() {}) } = {};
var { cover = (function () {}), xCover = (0, function() {}) } = {};
}
expect_exact: "function fn3({x:{y:{z:{}=42}}}){}const{cover=function(){},xCover=(0,function(){})}={};let{cover=function(){},xCover=(0,function(){})}={};var{cover=function(){},xCover=(0,function(){})}={};"
}
default_arguments: {
beautify = {
ecma: 6
}
input: {
function x(a = 6) { }
function x(a = (6 + 5)) { }
function x({ foo } = {}, [ bar ] = [ 1 ]) { }
}
expect_exact: "function x(a=6){}function x(a=6+5){}function x({foo}={},[bar]=[1]){}"
}
default_values_in_destructurings: {
beautify = {
ecma: 6
}
input: {
function x({a=(4), b}) {}
function x([b, c=(12)]) {}
var { x = (6), y } = x;
var [ x, y = (6) ] = x;
}
expect_exact: "function x({a=4,b}){}function x([b,c=12]){}var{x=6,y}=x;var[x,y=6]=x;"
}
accept_duplicated_parameters_in_non_strict_without_spread_or_default_assignment: {
input: {
function a(b, b){}
function b({c: test, c: test}){}
}
expect: {
function a(b, b){}
function b({c: test, c: test}){}
}
}

View File

@@ -148,7 +148,6 @@ mangle_unquoted_properties: {
properties: false
}
mangle_props = {
builtins: true,
keep_quoted: true
}
beautify = {
@@ -239,7 +238,6 @@ mangle_debug_suffix_keep_quoted: {
properties: false
}
mangle_props = {
builtins: true,
keep_quoted: true,
debug: "XYZ",
reserved: []

View File

@@ -1,9 +0,0 @@
super_can_be_parsed: {
input: {
super(1,2);
super.meth();
}
expect_exact: "super(1,2);super.meth();"
}

View File

@@ -1,402 +0,0 @@
template_strings: {
beautify = {
quote_style: 3
}
input: {
``;
`xx\`x`;
`${ foo + 2 }`;
` foo ${ bar + `baz ${ qux }` }`;
}
expect_exact: "``;`xx\\`x`;`${foo+2}`;` foo ${bar+`baz ${qux}`}`;";
}
template_string_prefixes: {
beautify = {
quote_style: 3
}
input: {
String.raw`foo`;
foo `bar`;
}
expect_exact: "String.raw`foo`;foo`bar`;";
}
template_strings_ascii_only: {
beautify = {
ascii_only: true,
quote_style: 3
}
input: {
var foo = `foo
bar
ↂωↂ`;
var bar = `\``;
}
expect_exact: "var foo=`foo\\n bar\\n \\u2182\\u03c9\\u2182`;var bar=`\\``;"
}
template_strings_without_ascii_only: {
beautify = {
quote_style: 3
}
input: {
var foo = `foo
bar
ↂωↂ`
}
expect_exact: "var foo=`foo\\n bar\\n ↂωↂ`;"
}
template_string_with_constant_expression: {
options = {
evaluate: true
}
beautify = {
quote_style: 3
}
input: {
var foo = `${4 + 4} equals 4 + 4`;
}
expect: {
var foo = `8 equals 4 + 4`;
}
}
template_string_with_predefined_constants: {
options = {
evaluate: true
}
beautify = {
quote_style: 3
}
input: {
var foo = `This is ${undefined}`;
var bar = `This is ${NaN}`;
var baz = `This is ${null}`;
var foofoo = `This is ${Infinity}`;
var foobar = "This is ${1/0}";
var foobaz = 'This is ${1/0}';
var barfoo = "This is ${NaN}";
var bazfoo = "This is ${null}";
var bazbaz = `This is ${1/0}`;
var barbar = `This is ${0/0}`;
var barbar = "This is ${0/0}";
var barber = 'This is ${0/0}';
var a = `${4**11}`; // 8 in template vs 7 chars - 4194304
var b = `${4**12}`; // 8 in template vs 8 chars - 16777216
var c = `${4**14}`; // 8 in template vs 9 chars - 268435456
}
expect: {
var foo = `This is undefined`;
var bar = `This is NaN`;
var baz = `This is null`;
var foofoo = `This is ${1/0}`;
var foobar = "This is ${1/0}";
var foobaz = 'This is ${1/0}';
var barfoo = "This is ${NaN}";
var bazfoo = "This is ${null}";
var bazbaz = `This is ${1/0}`;
var barbar = `This is NaN`;
var barbar = "This is ${0/0}";
var barber = 'This is ${0/0}';
var a = `4194304`;
var b = `16777216`; // Potential for further concatentation
var c = `${4**14}`; // Not worth converting
}
}
template_string_evaluate_with_many_segments: {
options = {
evaluate: true
}
beautify = {
quote_style: 3
}
input: {
var foo = `Hello ${guest()}, welcome to ${location()}${"."}`;
var bar = `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
var buzz = `${1}${foobar()}${2}${foobar()}${3}${foobar()}`;
}
expect: {
var foo = `Hello ${guest()}, welcome to ${location()}.`;
var bar = `1234567890`;
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
var buzz = `1${foobar()}2${foobar()}3${foobar()}`;
}
}
template_string_with_many_segments: {
beautify = {
quote_style: 3
}
input: {
var foo = `Hello ${guest()}, welcome to ${location()}${"."}`;
var bar = `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
var buzz = `${1}${foobar()}${2}${foobar()}${3}${foobar()}`;
}
expect: {
var foo = `Hello ${guest()}, welcome to ${location()}${"."}`;
var bar = `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
var buzz = `${1}${foobar()}${2}${foobar()}${3}${foobar()}`;
}
}
template_string_to_normal_string: {
options = {
evaluate: true
}
beautify = {
quote_style: 0
}
input: {
var foo = `This is ${undefined}`;
var bar = "Decimals " + `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
}
expect: {
var foo = `This is undefined`;
var bar = "Decimals 1234567890";
}
}
template_concattenating_string: {
options = {
evaluate: true
}
beautify = {
quote_style: 3 // Yes, keep quotes
}
input: {
var foo = "Have a nice " + `day. ${`day. ` + `day.`}`;
var bar = "Have a nice " + `${day()}`;
}
expect: {
var foo = "Have a nice day. day. day.";
var bar = "Have a nice " + `${day()}`;
}
}
evaluate_nested_templates: {
options = {
evaluate: true
}
beautify = {
quote_style: 0
}
input: {
var baz = `${`${`${`foo`}`}`}`;
}
expect: {
var baz = `foo`;
}
}
enforce_double_quotes: {
beautify = {
quote_style: 1
}
input: {
var foo = `Hello world`;
var bar = `Hello ${'world'}`;
var baz = `Hello ${world()}`;
}
expect: {
var foo = `Hello world`;
var bar = `Hello ${"world"}`;
var baz = `Hello ${world()}`;
}
}
enforce_single_quotes: {
beautify = {
quote_style: 2
}
input: {
var foo = `Hello world`;
var bar = `Hello ${"world"}`;
var baz = `Hello ${world()}`;
}
expect: {
var foo = `Hello world`;
var bar = `Hello ${'world'}`;
var baz = `Hello ${world()}`;
}
}
enforce_double_quotes_and_evaluate: {
beautify = {
quote_style: 1
}
options = {
evaluate: true
}
input: {
var foo = `Hello world`;
var bar = `Hello ${'world'}`;
var baz = `Hello ${world()}`;
}
expect: {
var foo = `Hello world`;
var bar = `Hello world`;
var baz = `Hello ${world()}`;
}
}
enforce_single_quotes_and_evaluate: {
beautify = {
quote_style: 2
}
options = {
evaluate: true
}
input: {
var foo = `Hello world`;
var bar = `Hello ${"world"}`;
var baz = `Hello ${world()}`;
}
expect: {
var foo = `Hello world`;
var bar = `Hello world`;
var baz = `Hello ${world()}`;
}
}
respect_inline_script: {
beautify = {
inline_script: true,
quote_style: 3
}
input: {
var foo = `</script>${content}`;
var bar = `<!--`;
var baz = `-->`;
}
expect_exact: "var foo=`<\\/script>${content}`;var bar=`\\x3c!--`;var baz=`--\\x3e`;";
}
do_not_optimize_tagged_template_1: {
beautify = {
quote_style: 0
}
options = {
evaluate: true
}
input: {
var foo = tag`Shall not be optimized. ${"But " + "this " + "is " + "fine."}`;
var bar = tag`Don't even mind changing my quotes!`;
}
expect_exact:
'var foo=tag`Shall not be optimized. ${"But this is fine."}`;var bar=tag`Don\'t even mind changing my quotes!`;';
}
do_not_optimize_tagged_template_2: {
options = {
evaluate: true
}
input: {
var foo = tag`test` + " something out";
}
expect_exact: 'var foo=tag`test`+" something out";';
}
keep_raw_content_in_tagged_template: {
options = {
evaluate: true
}
input: {
var foo = tag`\u0020\u{20}\u{00020}\x20\40\040 `;
}
expect_exact: "var foo=tag`\\u0020\\u{20}\\u{00020}\\x20\\40\\040 `;";
}
allow_chained_templates: {
input: {
var foo = tag`a``b``c``d`;
}
expect: {
var foo = tag`a``b``c``d`;
}
}
check_escaped_chars: {
input: {
var foo = `\u0020\u{20}\u{00020}\x20\40\040 `;
}
expect_exact: "var foo=` `;";
}
escape_dollar_curly: {
options = {
evaluate: true
}
input: {
console.log(`\$\{ beep \}`)
console.log(`${1-0}\${2-0}$\{3-0}${4-0}`)
console.log(`$${""}{not an expression}`)
}
expect_exact: "console.log(`\\${ beep }`);console.log(`1\\${2-0}\\${3-0}4`);console.log(`\\${not an expression}`);"
}
template_starting_with_newline: {
options = {
dead_code: true
}
input: {
function foo(e) {
return `
this is a template string!`;
};
}
expect_exact: "function foo(e){return`\\nthis is a template string!`}"
}
template_with_newline: {
options = {
dead_code: true
}
input: {
function foo(e) {
return `yep,
this is a template string!`;
};
}
expect_exact: "function foo(e){return`yep,\\nthis is a template string!`}"
}
template_ending_with_newline: {
options = {
dead_code: true
}
input: {
function foo(e) {
return `this is a template string!
`;
};
}
expect_exact: "function foo(e){return`this is a template string!\\n`}"
}
issue_1856: {
beautify = {
ascii_only: false,
}
input: {
console.log(`\\n\\r\\u2028\\u2029\n\r\u2028\u2029`);
}
expect_exact: "console.log(`\\\\n\\\\r\\\\u2028\\\\u2029\\n\\r\\u2028\\u2029`);"
}
issue_1856_ascii_only: {
beautify = {
ascii_only: true,
}
input: {
console.log(`\\n\\r\\u2028\\u2029\n\r\u2028\u2029`);
}
expect_exact: "console.log(`\\\\n\\\\r\\\\u2028\\\\u2029\\n\\r\\u2028\\u2029`);"
}

View File

@@ -1,12 +0,0 @@
catch_destructuring_with_sequence: {
beautify = {
ecma: 6
}
input: {
try {
throw {};
} catch ({xCover = (0, function() {})} ) {
}
}
expect_exact: "try{throw{}}catch({xCover=(0,function(){})}){}"
}

View File

@@ -15,106 +15,3 @@ unicode_parse_variables: {
var l = 3;
}
}
unicode_escaped_identifier: {
beautify = {ecma: 6}
input: {
var \u{61} = "foo";
var \u{10000} = "bar";
}
expect_exact: 'var a="foo";var \u{10000}="bar";';
}
unicode_identifier_ascii_only: {
beautify = {ascii_only: true, ecma: 6}
input: {
var \u{0061} = "hi";
var bar = "h\u{0065}llo";
var \u{10000} = "testing \u{101111}";
}
expect_exact: 'var a="hi";var bar="hello";var \\u{10000}="testing \\u{101111}";'
}
unicode_string_literals: {
beautify = {ascii_only: true, ecma: 6}
input: {
var a = "6 length unicode character: \u{101111}";
}
expect_exact: 'var a="6 length unicode character: \\u{101111}";'
}
// Don't escape identifiers below es6 (or in this case double escaped in expect_exact)
unicode_output_es5_surrogates: {
beautify = {ascii_only: true, ecma: 5}
input: {
var \u{10000} = "6 length unicode character: \u{10FFFF}";
}
expect_exact: 'var \u{10000}="6 length unicode character: \\udbff\\udfff";'
}
check_escape_style: {
beautify = {ascii_only: true, ecma: 6}
input: {
var a = "\x01";
var \ua0081 = "\x10"; // \u0081 only in ID_Continue
var \u0100 = "\u0100";
var \u1000 = "\u1000";
var \u{10000} = "\u{10000}";
var \u{2f800} = "\u{100000}";
}
expect_exact: 'var a="\\x01";var \\ua0081="\\x10";var \\u0100="\\u0100";var \\u1000="\\u1000";var \\u{10000}="\\u{10000}";var \\u{2f800}="\\u{100000}";'
}
// Don't escape identifiers below es6, no escaped identifiers support and no \u{} syntax
check_escape_style_es5: {
beautify = {ascii_only: true, ecma: 5}
input: {
var a = "\x01";
var \ua0081 = "\x10"; // \u0081 only in ID_Continue
var \u0100 = "\u0100";
var \u1000 = "\u1000";
var \u{10000} = "\u{10000}"; // Identifier won't be escaped in es 5.1
var \u{2f800} = "\u{100000}"; // Same
}
expect_exact: 'var a="\\x01";var \\ua0081="\\x10";var \\u0100="\\u0100";var \\u1000="\\u1000";var \ud800\udc00="\\ud800\\udc00";var \ud87e\udc00="\\udbc0\\udc00";'
}
ID_continue_with_surrogate_pair: {
beautify = {ascii_only: true, ecma: 6}
input: {
var \u{2f800}\u{2f800}\u{2f800}\u{2f800} = "\u{100000}\u{100000}\u{100000}\u{100000}\u{100000}";
}
expect_exact: 'var \\u{2f800}\\u{2f800}\\u{2f800}\\u{2f800}="\\u{100000}\\u{100000}\\u{100000}\\u{100000}\\u{100000}";'
}
escape_non_escaped_identifier: {
beautify = {ascii_only: true, ecma: 6}
input: {
var µþ = "µþ";
}
expect_exact: 'var \\u00b5\\u00fe="\\xb5\\xfe";'
}
non_escape_2_non_escape: {
beautify = {ascii_only: false, ecma: 6}
input: {
var µþ = "µþ";
}
expect_exact: 'var µþ="µþ";'
}
non_escape_2_half_escape1: {
beautify = {ascii_only: false, ascii_identifiers: true, ecma: 6}
input: {
var µþ = "µþ";
}
expect_exact: 'var \\u00b5\\u00fe="µþ";'
}
non_escape_2_half_escape2: {
beautify = {ascii_only: true, ascii_identifiers: false, ecma: 6}
input: {
var µþ = "µþ";
}
expect_exact: 'var µþ="\\xb5\\xfe";'
}

View File

@@ -1,192 +0,0 @@
generators: {
input: {
function* fn() {};
}
expect_exact: "function*fn(){}"
}
generators_yield: {
input: {
function* fn() {
yield remote();
}
}
expect_exact: "function*fn(){yield remote()}"
}
generators_yield_assign: {
input: {
function* fn() {
var x = {};
x.prop = yield 5;
}
}
expect_exact: "function*fn(){var x={};x.prop=yield 5}"
}
generator_yield_undefined: {
input: {
function* fn() {
yield;
}
}
expect_exact: "function*fn(){yield}"
}
yield_optimize_expression: {
options = {
}
input: {
function* f1() { yield; }
function* f2() { yield undefined; }
function* f3() { yield null; }
function* f4() { yield* undefined; }
}
expect: {
function* f1() { yield }
function* f2() { yield; }
function* f3() { yield null; }
function* f4() { yield* void 0; }
}
}
yield_statements: {
input: {
function* fn() {
var a = (yield 1) + (yield 2);
var b = (yield 3) === (yield 4);
var c = (yield 5) << (yield 6);
var d = yield 7;
var e = (yield 8) ? yield 9 : yield 10;
var f = -(yield 11);
}
}
expect_exact: "function*fn(){var a=(yield 1)+(yield 2);var b=(yield 3)===(yield 4);var c=(yield 5)<<(yield 6);var d=yield 7;var e=(yield 8)?yield 9:yield 10;var f=-(yield 11)}"
}
yield_as_identifier_in_function_in_generator: {
input: {
var g = function*() {
function h() {
yield = 1;
}
};
}
expect: {
var g = function*() {
function h() {
yield = 1;
}
};
}
}
yield_before_punctuators: {
input: {
iter = (function*() {
assignmentResult = [ x = yield ] = value;
})();
function* g1() { (yield) }
function* g2() { [yield] }
function* g3() { return {yield} } // Added return to avoid {} drop
function* g4() { yield, yield; }
function* g5() { (yield) ? yield : yield; }
}
expect: {
iter = (function*() {
assignmentResult = [ x = yield ] = value;
})();
function* g1() { (yield) }
function* g2() { [yield] }
function* g3() { return {yield} }
function* g4() { yield, yield; }
function* g5() { (yield) ? yield : yield; }
}
}
yield_as_identifier_outside_strict_mode: {
input: {
import yield from "bar";
yield = 123;
while (true) {
yield:
for(;;) break yield;
foo();
}
while (true)
yield: for(;;) continue yield;
function yield(){}
function foo(...yield){}
try { new Error("") } catch (yield) {}
var yield = "foo";
}
expect: {
import yield from "bar";
yield = 123;
while (true) {
yield:
for(;;) break yield;
foo();
}
while (true)
yield: for(;;) continue yield;
function yield(){}
function foo(...yield){}
try { new Error("") } catch (yield) {}
var yield = "foo";
}
}
empty_generator_as_parameter_with_side_effects: {
options = {
side_effects: true
}
input: {
var GeneratorPrototype = Object.getPrototypeOf(
Object.getPrototypeOf(function*() {}())
);
evaluate(GeneratorPrototype);
}
expect_exact: "var GeneratorPrototype=Object.getPrototypeOf(Object.getPrototypeOf(function*(){}()));evaluate(GeneratorPrototype);"
}
empty_generator_as_parameter_without_side_effects: {
options = {
side_effects: false
}
input: {
var GeneratorPrototype = Object.getPrototypeOf(
Object.getPrototypeOf(function*() {}())
);
evaluate(GeneratorPrototype);
}
expect_exact: "var GeneratorPrototype=Object.getPrototypeOf(Object.getPrototypeOf(function*(){}()));evaluate(GeneratorPrototype);"
}
yield_dot: {
options = {
}
input: {
function* foo(){
yield x.foo;
(yield x).foo;
yield (yield obj.foo()).bar();
}
}
expect_exact: "function*foo(){yield x.foo;(yield x).foo;yield(yield obj.foo()).bar()}"
}
yield_sub: {
options = {
}
input: {
function* foo(){
yield x['foo'];
(yield x)['foo'];
yield (yield obj.foo())['bar']();
}
}
expect_exact: 'function*foo(){yield x["foo"];(yield x)["foo"];yield(yield obj.foo())["bar"]()}'
}

View File

@@ -16,8 +16,8 @@ describe("Accessor tokens", function() {
assert.equal(node.start.pos, 12);
assert.equal(node.end.endpos, 46);
assert(node.key instanceof UglifyJS.AST_SymbolMethod);
assert.equal(node.key.start.pos, 12);
assert(node.key instanceof UglifyJS.AST_SymbolRef);
assert.equal(node.key.start.pos, 16);
assert.equal(node.key.end.endpos, 22);
assert(node.value instanceof UglifyJS.AST_Accessor);

View File

@@ -27,253 +27,4 @@ describe("arguments", function() {
assert.strictEqual(ast.body[0].body[0].uses_arguments, true);
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);
});
});
});

View File

@@ -1,402 +0,0 @@
var assert = require("assert");
var uglify = require("../node");
describe("Arrow functions", function() {
it("Should not accept spread tokens on non-last parameters or without arguments parentheses", function() {
var tests = [
"var a = ...a => {return a.join()}",
"var b = (a, ...b, c) => { return a + b.join() + c}",
"var c = (...a, b) => a.join()"
];
var test = function(code) {
return function() {
uglify.parse(code);
}
}
var error = function(e) {
return e instanceof uglify.JS_Parse_Error &&
e.message === "Unexpected token: expand (...)";
}
for (var i = 0; i < tests.length; i++) {
assert.throws(test(tests[i]), error);
}
});
it("Should not accept holes in object binding patterns, while still allowing a trailing elision", function() {
var tests = [
"f = ({, , ...x} = [1, 2]) => {};"
];
var test = function(code) {
return function() {
uglify.parse(code);
}
}
var error = function(e) {
return e instanceof uglify.JS_Parse_Error &&
e.message === "Unexpected token: punc (,)";
}
for (var i = 0; i < tests.length; i++) {
assert.throws(test(tests[i]), error);
}
});
it("Should not accept newlines before arrow token", function() {
var tests = [
"f = foo\n=> 'foo';",
"f = (foo, bar)\n=> 'foo';",
"f = ()\n=> 'foo';",
"foo((bar)\n=>'baz';);"
];
var test = function(code) {
return function() {
uglify.parse(code);
}
}
var error = function(e) {
return e instanceof uglify.JS_Parse_Error &&
e.message === "Unexpected newline before arrow (=>)";
}
for (var i = 0; i < tests.length; i++) {
assert.throws(test(tests[i]), error);
}
});
it("Should not accept arrow functions in the middle or end of an expression", function() {
var tests = [
"typeof x => 0",
"0 + x => 0"
];
var test = function(code) {
return function() {
uglify.parse(code);
}
}
var error = function(e) {
return e instanceof uglify.JS_Parse_Error &&
e.message === "Unexpected token: arrow (=>)";
}
for (var i = 0; i < tests.length; i++) {
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);
});
it("Should handle arrow function with bind", function() {
function minify(code) {
return uglify.minify(code, {
mangle: false
}).code;
}
assert.strictEqual(
minify(minify("test(((index) => { console.log(this, index); }).bind(this, 1));")),
"test((index=>{console.log(this,index)}).bind(this,1));"
);
assert.strictEqual(
minify(minify('test(((index) => { console.log(this, index); })["bind"](this, 1));')),
"test((index=>{console.log(this,index)}).bind(this,1));"
);
});
});

View File

@@ -1,34 +0,0 @@
var UglifyJS = require("../../");
var assert = require("assert");
describe("builtins", function() {
it ("Should not mangle builtins", function() {
var test = "function foo(something){\n" +
" return [Object,Array,Function,Number,String,Boolean,Error,Math,Date,RegExp,Symbol,Map,Promise,Proxy,Reflect,Set,WeakMap,WeakSet,Float32Array,something];\n" +
"};";
var result = UglifyJS.minify(test, {parse: {bare_returns: true}}).code;
assert.strictEqual(result.indexOf("something"), -1);
assert.notEqual(result.indexOf("Object"), -1);
assert.notEqual(result.indexOf("Array"), -1);
assert.notEqual(result.indexOf("Function"), -1);
assert.notEqual(result.indexOf("Number"), -1);
assert.notEqual(result.indexOf("String"), -1);
assert.notEqual(result.indexOf("Boolean"), -1);
assert.notEqual(result.indexOf("Error"), -1);
assert.notEqual(result.indexOf("Math"), -1);
assert.notEqual(result.indexOf("Date"), -1);
assert.notEqual(result.indexOf("RegExp"), -1);
assert.notEqual(result.indexOf("Symbol"), -1);
assert.notEqual(result.indexOf("Promise"), -1);
assert.notEqual(result.indexOf("Proxy"), -1);
assert.notEqual(result.indexOf("Reflect"), -1);
assert.notEqual(result.indexOf("Set"), -1);
assert.notEqual(result.indexOf("WeakMap"), -1);
assert.notEqual(result.indexOf("WeakSet"), -1);
assert.notEqual(result.indexOf("Map"), -1);
assert.notEqual(result.indexOf("Float32Array"), -1);
});
});

View File

@@ -1,57 +0,0 @@
var assert = require("assert");
var uglify = require("../node");
describe("Class", function() {
it("Should not accept spread on non-last parameters in methods", function() {
var tests = [
"class foo { bar(...a, b) { return a.join(b) } }",
"class foo { bar(a, b, ...c, d) { return c.join(a + b) + d } }",
"class foo { *bar(...a, b) { return a.join(b) } }",
"class foo { *bar(a, b, ...c, d) { return c.join(a + b) + d } }"
];
var test = function(code) {
return function() {
uglify.parse(code);
}
}
var error = function(e) {
return e instanceof uglify.JS_Parse_Error &&
/^Unexpected token: /.test(e.message);
}
for (var i = 0; i < tests.length; i++) {
assert.throws(test(tests[i]), error);
}
});
it("Should return the correct token for class methods", function() {
var tests = [
{
code: "class foo{static test(){}}",
token_value_start: "static",
token_value_end: "}"
},
{
code: "class bar{*procedural(){}}",
token_value_start: "*",
token_value_end: "}"
},
{
code: "class foobar{aMethod(){}}",
token_value_start: "aMethod",
token_value_end: "}"
},
{
code: "class foobaz{get something(){}}",
token_value_start: "get",
token_value_end: "}"
}
];
for (var i = 0; i < tests.length; i++) {
var ast = uglify.parse(tests[i].code);
assert.strictEqual(ast.body[0].properties[0].start.value, tests[i].token_value_start);
assert.strictEqual(ast.body[0].properties[0].end.value, tests[i].token_value_end);
}
});
});

View File

@@ -185,7 +185,7 @@ describe("bin/uglifyjs", function () {
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr, "ERROR: inline source map only works with singular input\n");
assert.strictEqual(stderr.split(/\n/)[0], "ERROR: inline source map only works with singular input");
done();
});
});
@@ -464,7 +464,7 @@ describe("bin/uglifyjs", function () {
"Parse error at test/input/invalid/try.js:7,18",
" try {} catch (eval) {}",
" ^",
"ERROR: Unexpected eval identifier as parameter inside strict mode"
"ERROR: Unexpected eval in strict mode"
].join("\n"));
done();
});

View File

@@ -31,8 +31,7 @@ describe("Comment", function() {
"/*Some comment 2\r\n\r\n\r\n*/\r\n>\n\n\n\n\n\n",
"/*Some comment 3\r\r\r*/\r>\n\n\n\n\n\n",
"/*Some comment 4\u2028\u2028\u2028*/\u2028>\n\n\n\n\n\n",
"/*Some comment 5\u2029\u2029\u2029*/\u2029>\n\n\n\n\n\n",
"/*Some comment 6\udbff\udfff\udbff\udfff\n\n\n*/\n>\n\n\n\n\n"
"/*Some comment 5\u2029\u2029\u2029*/\u2029>\n\n\n\n\n\n"
];
var fail = function(e) {

View File

@@ -1,138 +0,0 @@
var assert = require("assert");
var uglify = require("../node");
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
);
}
}
}
});
});

View File

@@ -62,10 +62,10 @@ describe("Directives", function() {
it("Should know which strings are directive and which ones are not", function() {
var test_directive = function(tokenizer, test) {
test.directives.map(function(directive) {
assert.strictEqual(tokenizer.has_directive(directive), true, "Didn't found directive `" + directive + "` at the end of `" + test.input + '`');
assert.strictEqual(tokenizer.has_directive(directive), true, directive + " in " + test.input);
});
test.non_directives.map(function(fake_directive) {
assert.strictEqual(tokenizer.has_directive(fake_directive), false, "Unexpectedly found directive `" + fake_directive + "` at the end of `" + test.input + '`');
assert.strictEqual(tokenizer.has_directive(fake_directive), false, fake_directive + " in " + test.input);
});
}
@@ -156,16 +156,6 @@ describe("Directives", function() {
input: '"use strict";try{"use asm";',
directives: ["use strict"],
non_directives: ["use\nstrict", "use \nstrict", "use asm"]
},
{
input: 'class foo {',
directives: ["use strict"],
non_directives: ["use\nstrict", "use asm"]
},
{
input: 'class foo {}',
directives: [],
non_directives: ["use strict", "use asm", "use\nstrict"]
}
];
@@ -378,44 +368,4 @@ describe("Directives", function() {
);
}
});
it("Should be detect implicit usages of strict mode from tree walker", function() {
var tests = [
{
input: 'class foo {bar(){_check_}}',
directives: ["use strict"],
non_directives: ["use bar"]
},
{
input: 'class foo {bar(){}}_check_',
directives: [],
non_directives: ["use strict", "use bar"]
}
];
var i = 0;
var checked;
var checkWalker = new uglify.TreeWalker(function(node, descend) {
if (node instanceof uglify.AST_Symbol && node.name === "_check_") {
checked = true;
for (var j = 0; j < tests[i].directives.length; j++) {
assert.ok(checkWalker.has_directive(tests[i].directives[j]),
"Did not found directive '" + tests[i].directives[j] + "' in test " + tests[i].input)
}
for (var k = 0; k < tests[i].non_directives.length; k++) {
assert.equal(checkWalker.has_directive(tests[i].non_directives[k]), undefined,
"Found directive '" + tests[i].non_directives[k] + "' in test " + tests[i].input)
}
}
});
for (; i < tests.length; i++) {
// Do tests - iterate the ast in each test - check only when _check_ occurs - fail when no _check_ has been found
checked = false;
var ast = uglify.parse(tests[i].input);
ast.walk(checkWalker);
if (!checked) {
throw "No _check_ symbol found in " + tests[i].input;
}
}
});
});

View File

@@ -1,35 +0,0 @@
var assert = require("assert");
var uglify = require("../node");
describe("EOF", function() {
it("Should test code for at least throwing syntax error when incomplete", function() {
var error = function(e) {
return e instanceof uglify.JS_Parse_Error;
}
var parse = function(test) {
return function() {
uglify.parse(test);
}
}
// Chops off 1 char at a time until limit or start of string is reached
// The passed code must still be valid when unchopped
var test_eol = function(input, chopLimit) {
if (chopLimit === undefined) {
chopLimit = input.length - 1;
}
assert.doesNotThrow(parse(input), "Expected valid code for \n" + input);
for (var i = input.length - 1; chopLimit > 0; chopLimit--, i--) {
var code = input.substr(0, i);
assert.throws(parse(code), error, code);
}
}
test_eol("var \\u1234", 7); // Incomplete identifier
test_eol("'Incomplete string'");
test_eol("/Unterminated regex/");
test_eol("` Unterminated template string`");
test_eol("/* Unfinishing multiline comment */");
});
});

View File

@@ -1,40 +0,0 @@
var assert = require("assert");
var uglify = require("../node");
describe("Export", function() {
it ("Should parse export directives", function() {
var inputs = [
['export * from "a.js"', ['*'], "a.js"],
['export {A} from "a.js"', ['A'], "a.js"],
['export {A as X} from "a.js"', ['X'], "a.js"],
['export {A as Foo, B} from "a.js"', ['Foo', 'B'], "a.js"],
['export {A, B} from "a.js"', ['A', 'B'], "a.js"],
];
var test = function(code) {
return uglify.parse(code);
};
var extractNames = function(symbols) {
var ret = [];
for (var i = 0; i < symbols.length; i++) {
ret.push(symbols[i].name.name)
}
return ret;
};
for (var i = 0; i < inputs.length; i++) {
var ast = test(inputs[i][0]);
var names = inputs[i][1];
var filename = inputs[i][2];
assert(ast instanceof uglify.AST_Toplevel);
assert.equal(ast.body.length, 1);
var st = ast.body[0];
assert(st instanceof uglify.AST_Export);
var actualNames = extractNames(st.exported_names);
assert.deepEqual(actualNames, names);
assert.equal(st.module_name.value, filename)
}
})
});

View File

@@ -1,32 +0,0 @@
var assert = require("assert");
var uglify = require("../node");
describe("Expression", function() {
it("Should not allow the first exponentiation operator to be prefixed with an unary operator", function() {
var tests = [
"+5 ** 3",
"-5 ** 3",
"~5 ** 3",
"!5 ** 3",
"void 5 ** 3",
"typeof 5 ** 3",
"delete 5 ** 3",
"var a = -(5) ** 3;"
];
var fail = function(e) {
return e instanceof uglify.JS_Parse_Error &&
/^Unexpected token: operator \((?:[!+~-]|void|typeof|delete)\)/.test(e.message);
}
var exec = function(test) {
return function() {
uglify.parse(test);
}
}
for (var i = 0; i < tests.length; i++) {
assert.throws(exec(tests[i]), fail, tests[i]);
}
});
});

View File

@@ -1,252 +0,0 @@
var assert = require("assert");
var uglify = require("../node");
describe("Function", function() {
it ("Should parse binding patterns correctly", function() {
// Function argument nodes are correct
function get_args(args) {
return args.map(function (arg) {
return [arg.TYPE, arg.name];
});
}
// Destructurings as arguments
var destr_fun1 = uglify.parse('(function ({a, b}) {})').body[0].body;
var destr_fun2 = uglify.parse('(function ([a, [b]]) {})').body[0].body;
var destr_fun3 = uglify.parse('({a, b}) => null').body[0].body;
var destr_fun4 = uglify.parse('([a, [b]]) => null').body[0].body;
assert.equal(destr_fun1.argnames.length, 1);
assert.equal(destr_fun2.argnames.length, 1);
assert.equal(destr_fun3.argnames.length, 1);
assert.equal(destr_fun4.argnames.length, 1);
var destruct1 = destr_fun1.argnames[0];
var destruct2 = destr_fun2.argnames[0];
var destruct3 = destr_fun3.argnames[0];
var destruct4 = destr_fun4.argnames[0];
assert(destruct1 instanceof uglify.AST_Destructuring);
assert(destruct2 instanceof uglify.AST_Destructuring);
assert(destruct3 instanceof uglify.AST_Destructuring);
assert(destruct4 instanceof uglify.AST_Destructuring);
assert(destruct2.names[1] instanceof uglify.AST_Destructuring);
assert(destruct4.names[1] instanceof uglify.AST_Destructuring);
assert.equal(destruct1.start.value, '{');
assert.equal(destruct1.end.value, '}');
assert.equal(destruct2.start.value, '[');
assert.equal(destruct2.end.value, ']');
assert.equal(destruct3.start.value, '{');
assert.equal(destruct3.end.value, '}');
assert.equal(destruct4.start.value, '[');
assert.equal(destruct4.end.value, ']');
assert.equal(destruct1.is_array, false);
assert.equal(destruct2.is_array, true);
assert.equal(destruct3.is_array, false);
assert.equal(destruct4.is_array, true);
// destruct 1
assert.deepEqual(
[
destruct1.names[0].TYPE,
destruct1.names[0].key,
destruct1.names[0].value.name
],
['ObjectKeyVal', 'a', 'a']
);
assert.deepEqual(
[
destruct1.names[1].TYPE,
destruct1.names[1].key,
destruct1.names[1].value.name
],
['ObjectKeyVal', 'b', 'b']
);
// destruct 2
assert.deepEqual(
[
destruct2.names[0].TYPE,
destruct2.names[0].name
],
['SymbolFunarg', 'a']
);
assert.deepEqual(
[
destruct2.names[1].names[0].TYPE,
destruct2.names[1].names[0].name
],
['SymbolFunarg', 'b']
);
// destruct 3
assert.strictEqual(typeof destruct3.names[0].key, "string");
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(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(
[
destruct4.names[0].TYPE,
destruct4.names[0].name
],
['SymbolFunarg', 'a']
);
assert.strictEqual(destruct4.names[1].TYPE, "Destructuring");
assert.deepEqual(
[
destruct4.names[1].names[0].TYPE,
destruct4.names[1].names[0].name
],
['SymbolFunarg', 'b']
);
assert.deepEqual(
get_args(destr_fun1.args_as_names()),
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
);
assert.deepEqual(
get_args(destr_fun2.args_as_names()),
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
);
assert.deepEqual(
get_args(destr_fun3.args_as_names()),
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
);
assert.deepEqual(
get_args(destr_fun4.args_as_names()),
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
);
// Making sure we don't accidentally accept things which
// Aren't argument destructurings
assert.throws(function () {
uglify.parse('(function ( { a, [ b ] } ) { })')
});
assert.throws(function () {
uglify.parse('(function (1) { })');
}, /Invalid function parameter/);
assert.throws(function () {
uglify.parse('(function (this) { })');
});
assert.throws(function () {
uglify.parse('(function ([1]) { })');
}, /Invalid function parameter/);
assert.throws(function () {
uglify.parse('(function [a] { })');
});
// generators
var generators_def = uglify.parse('function* fn() {}').body[0];
assert.equal(generators_def.is_generator, true);
assert.throws(function () {
uglify.parse('function* (){ }');
});
var generators_yield_def = uglify.parse('function* fn() {\nyield remote();\}').body[0].body[0];
assert.strictEqual(generators_yield_def.body.is_star, false);
});
it("Should not accept spread on non-last parameters", function() {
var tests = [
"var a = function(...a, b) { return a.join(b) }",
"var b = function(a, b, ...c, d) { return c.join(a + b) + d }",
"function foo(...a, b) { return a.join(b) }",
"function bar(a, b, ...c, d) { return c.join(a + b) + d }",
"var a = function*(...a, b) { return a.join(b) }",
"var b = function*(a, b, ...c, d) { return c.join(a + b) + d }",
"function* foo(...a, b) { return a.join(b) }",
"function* bar(a, b, ...c, d) { return c.join(a + b) + d }"
];
var test = function(code) {
return function() {
uglify.parse(code);
}
}
var error = function(e) {
return e instanceof uglify.JS_Parse_Error &&
/^Unexpected token: /.test(e.message);
}
for (var i = 0; i < tests.length; i++) {
assert.throws(test(tests[i]), error);
}
});
it("Should not accept empty parameters after elision", function() {
var tests = [
"(function(,){})()",
"(function(a,){})()",
];
var test = function(code) {
return function() {
uglify.parse(code);
}
}
var error = function(e) {
return e instanceof uglify.JS_Parse_Error &&
e.message === "Invalid function parameter";
}
for (var i = 0; i < tests.length; i++) {
assert.throws(test(tests[i]), error);
}
});
it("Should not accept an initializer when parameter is a rest parameter", function() {
var tests = [
"(function(...a = b){})()",
"(function(a, ...b = [c, d]))"
];
var test = function(code) {
return function () {
uglify.parse(code);
}
}
var error = function (e) {
return e instanceof uglify.JS_Parse_Error;
}
for (var i = 0; i < tests.length; i++) {
assert.throws(test(tests[i]), error, tests[i]);
}
});
it("Shoult not accept duplicated identifiers inside parameters in strict mode or when using default assigment or spread", function() {
// From: ES2016 9.2.12 FunctionDeclarationInstantiation (func, argumentsList)
// NOTE Early errors ensure that duplicate parameter names can only occur
// in non-strict functions that do not have parameter default values or
// rest parameters.
var tests = [
"(function(a = 1, a){})()",
"(function(a, [a = 3]){})()",
"(function(a, b, c, d, [{e: [...a]}]){})()",
"'use strict'; (function(a, a){})",
"(function({a, a = b}))",
"(function(a, [...a]){})",
"(function(a, ...a){})",
"(function(a, [a, ...b]){})",
"(function(a, {b: a, c: [...d]}){})",
"(function(a, a, {b: [...c]}){})"
];
var test = function(code) {
return function () {
uglify.parse(code);
}
}
var error = function (e) {
return e instanceof uglify.JS_Parse_Error &&
/^Parameter [a-zA-Z]+ was used already$/.test(e.message);
}
for (var i = 0; i < tests.length; i++) {
assert.throws(test(tests[i]), error, tests[i]);
}
});
});

View File

@@ -71,7 +71,7 @@ describe("Getters and setters", function() {
var fail = function(data) {
return function (e) {
return e instanceof UglifyJS.JS_Parse_Error &&
/^Unexpected token: /.test(e.message);
e.message === "Invalid getter/setter name: " + data.operator;
};
};

View File

@@ -1,265 +0,0 @@
var assert = require("assert");
var uglify = require("../node");
describe("Left-hand side expressions", function () {
it("Should parse destructuring with const/let/var correctly", function () {
var decls = uglify.parse('var {a,b} = foo, { c, d } = bar');
assert.equal(decls.body[0].TYPE, 'Var');
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].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];
assert.equal(nested_def.name.names[0].names[0].TYPE, 'ObjectKeyVal');
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];
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');
var expanding_def = uglify.parse('var [first, ...rest] = [1,2,3]').body[0].definitions[0];
assert.equal(expanding_def.name.names[0].TYPE, 'SymbolVar');
assert.equal(expanding_def.name.names[1].TYPE, 'Expansion');
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]", "Spread must the be last element in destructuring array");
// Multiple spreads are not allowed in destructuring array
expect("[...a, ...b] = [1, 2, 3, 4]", "Spread must the be last element in destructuring array");
// Spread in obvious object pattern
expect("({...a} = foo)", "Unexpected token: expand (...)");
// Spread in block should not be allowed
expect("{...a} = foo", "Unexpected token: expand (...)");
// Not in standard yet
expect("let foo = {bar: 42}, bar; bar = {...foo}", "Unexpected token: expand (...)");
});
});

View File

@@ -1,5 +1,5 @@
var assert = require("assert");
var uglify = require("../node");
var uglify = require("../../");
describe("New", function() {
it("Should add trailing parentheses for new expressions with zero arguments in beautify mode", function() {
@@ -83,11 +83,4 @@ describe("New", function() {
);
}
});
it("Should check target in new.target", function() {
assert.throws(function() {uglify.parse("new.blah")}, function(e) {
return e instanceof uglify.JS_Parse_Error
&& e.message === "Unexpected token name «blah», expected name «target»";
});
});
});

View File

@@ -1,131 +0,0 @@
var Uglify = require("../node");
var assert = require("assert");
describe("Object", function() {
it("Should allow objects to have a methodDefinition as property", function() {
var code = "var a = {test() {return true;}}";
assert.equal(Uglify.minify(code).code, "var a={test(){return!0}};");
});
it("Should not allow objects to use static keywords like in classes", function() {
var code = "{static test() {}}";
var parse = function() {
Uglify.parse(code);
}
var expect = function(e) {
return e instanceof Uglify.JS_Parse_Error;
}
assert.throws(parse, expect);
});
it("Should not allow objects to have static computed properties like in classes", function() {
var code = "var foo = {static [123](){}}";
var parse = function() {
console.log(Uglify.parse(code).body[0].body[0]);
}
var expect = function(e) {
return e instanceof Uglify.JS_Parse_Error;
}
assert.throws(parse, expect);
});
it("Should not accept operator tokens as property/getter/setter name", function() {
var illegalOperators = [
"++",
"--",
"+",
"-",
"!",
"~",
"&",
"|",
"^",
"*",
"/",
"%",
">>",
"<<",
">>>",
"<",
">",
"<=",
">=",
"==",
"===",
"!=",
"!==",
"?",
"=",
"+=",
"-=",
"/=",
"*=",
"%=",
">>=",
"<<=",
">>>=",
"|=",
"^=",
"&=",
"&&",
"||"
];
var generator = function() {
var results = [];
for (var i in illegalOperators) {
results.push({
code: "var obj = { get " + illegalOperators[i] + "() { return test; }};",
operator: illegalOperators[i],
method: "get"
});
results.push({
code: "var obj = { set " + illegalOperators[i] + "(value) { test = value}};",
operator: illegalOperators[i],
method: "set"
});
results.push({
code: "var obj = { " + illegalOperators[i] + ': "123"};',
operator: illegalOperators[i],
method: "key"
});
results.push({
code: "var obj = { " + illegalOperators[i] + "(){ return test; }};",
operator: illegalOperators[i],
method: "method"
});
}
return results;
};
var testCase = function(data) {
return function() {
Uglify.parse(data.code);
};
};
var fail = function(data) {
return function (e) {
return e instanceof Uglify.JS_Parse_Error && (
e.message === "Unexpected token: operator (" + data.operator + ")" ||
(e.message === "Unterminated regular expression" && data.operator[0] === "/") ||
(e.message === "Unexpected token: punc (()" && data.operator === "*")
);
};
};
var errorMessage = function(data) {
return "Expected but didn't get a syntax error while parsing following line:\n" + data.code;
};
var tests = generator();
for (var i = 0; i < tests.length; i++) {
var test = tests[i];
assert.throws(testCase(test), fail(test), errorMessage(test));
}
});
it("Should be able to use shorthand properties", function() {
var ast = Uglify.parse("var foo = 123\nvar obj = {foo: foo}");
assert.strictEqual(ast.print_to_string({ecma: 6}), "var foo=123;var obj={foo};");
})
});

View File

@@ -1,33 +0,0 @@
var assert = require("assert");
var uglify = require("../node");
describe("Template string", function() {
it("Should not accept invalid sequences", function() {
var tests = [
// Stress invalid expression
"var foo = `Hello ${]}`",
"var foo = `Test 123 ${>}`",
"var foo = `Blah ${;}`",
// Stress invalid template_substitution after expression
"var foo = `Blablabla ${123 456}`",
"var foo = `Blub ${123;}`",
"var foo = `Bleh ${a b}`"
];
var exec = function(test) {
return function() {
uglify.parse(test);
}
};
var fail = function(e) {
return e instanceof uglify.JS_Parse_Error
&& /^Unexpected token: /.test(e.message);
};
for (var i = 0; i < tests.length; i++) {
assert.throws(exec(tests[i]), fail, tests[i]);
}
});
});

View File

@@ -1,22 +0,0 @@
var assert = require("assert");
var uglify = require("../node");
describe("Try", function() {
it("Should not allow catch with an empty parameter", function() {
var tests = [
"try {} catch() {}"
];
var test = function(code) {
return function () {
uglify.parse(code);
}
}
var error = function (e) {
return e instanceof uglify.JS_Parse_Error;
}
for (var i = 0; i < tests.length; i++) {
assert.throws(test(tests[i]), error, tests[i]);
}
});
});

View File

@@ -1,145 +0,0 @@
var assert = require("assert");
var uglify = require("../node");
describe("Unicode", function() {
it("Should not accept invalid code ranges in unicode escape", function() {
var tests = [
"\\u{110000}", // A bit over the unicode range
"\\u{100000061} = 'foo'", // 32-bit overflow resulting in "a"
"\\u{fffffffffff}", // A bit too much over the unicode range
];
var exec = function(test) {
return function() {
uglify.parse(test);
}
}
var fail = function(e) {
return e instanceof uglify.JS_Parse_Error
&& e.message === "Unicode reference out of bounce";
}
for (var i = 0; i < tests.length; i++) {
assert.throws(exec(tests[i]), fail);
}
});
it("Should not accept invalid unicode sequences", function() {
var tests = [
"var foo = '\\u-111'",
"var bar = '\\u{-1}'",
"var baz = '\\ugggg'"
];
var exec = function(test) {
return function() {
uglify.parse(test);
}
}
var fail = function(e) {
return e instanceof uglify.JS_Parse_Error
&& e.message === "Invalid hex-character pattern in string";
}
for (var i = 0; i < tests.length; i++) {
assert.throws(exec(tests[i]), fail);
}
});
it("Should throw error if escaped first identifier char is not part of ID_start", function() {
var tests = [
'var \\u{0} = "foo";',
'var \\u{10ffff} = "bar";',
'var \\u000a = "what\'s up";',
// Valid ID_Start, but using up 2 escaped characters and not fitting in IdentifierStart
'var \\ud800\\udc00 = "Hello";',
'var \\udbff\\udfff = "Unicode";', // Same as previous test
'var \\ud800\udc01 = "Weird unicode";', // Same as above, but mixed escaped with unicode chars
];
var exec = function(test) {
return function() {
uglify.parse(test);
}
}
var fail = function(e) {
return e instanceof uglify.JS_Parse_Error
&& e.message === "First identifier char is an invalid identifier char";
}
for (var i = 0; i < tests.length; i++) {
assert.throws(exec(tests[i]), fail);
}
});
it("Should throw error if escaped non-first identifier char is not part of ID_start", function() {
var tests = [
'var a\\u{0} = "foo";',
'var a\\u{10ffff} = "bar";',
'var z\\u000a = "what\'s up";'
];
var exec = function(test) {
return function() {
uglify.parse(test);
}
}
var fail = function(e) {
return e instanceof uglify.JS_Parse_Error
&& e.message === "Invalid escaped identifier char";
}
for (var i = 0; i < tests.length; i++) {
assert.throws(exec(tests[i]), fail);
}
});
it("Should throw error if identifier is a keyword with a escape sequences", function() {
var tests = [
'var \\u0069\\u006e = "foo"', // in
'var \\u0076\\u0061\\u0072 = "bar"', // var
'var \\u{66}\\u{6f}\\u{72} = "baz"', // for
'var \\u0069\\u{66} = "foobar"', // if
'var \\u{73}uper' // super
];
var exec = function(test) {
return function() {
uglify.parse(test);
}
}
var fail = function(e) {
return e instanceof uglify.JS_Parse_Error
&& e.message === "Escaped characters are not allowed in keywords";
}
for (var i = 0; i < tests.length; i++) {
assert.throws(exec(tests[i]), fail);
}
});
it("Should read strings containing surigates correctly", function() {
var tests = [
['var a = "\ud800\udc00";', 'var a="\\u{10000}";'],
['var b = "\udbff\udfff";', 'var b="\\u{10ffff}";']
];
for (var i = 0; i < tests.length; i++) {
assert.strictEqual(uglify.minify(tests[i][0], {
output: { ascii_only: true, ecma: 6 }
}).code, tests[i][1]);
}
});
it("Should parse raw characters correctly", function() {
var ast = uglify.parse('console.log("\\udbff");');
assert.strictEqual(ast.print_to_string(), 'console.log("\udbff");');
ast = uglify.parse(ast.print_to_string());
assert.strictEqual(ast.print_to_string(), 'console.log("\udbff");');
});
});

View File

@@ -1,106 +0,0 @@
var UglifyJS = require("../node");
var assert = require("assert");
describe("Yield", function() {
it("Should not delete statements after yield", function() {
var js = 'function *foo(bar) { yield 1; yield 2; return 3; }';
var result = UglifyJS.minify(js);
assert.strictEqual(result.code, 'function*foo(e){return yield 1,yield 2,3}');
});
it("Should not allow yield as labelIdentifier within generators", function() {
var js = "function* g() {yield: 1}"
var test = function() {
UglifyJS.parse(js);
}
var expect = function(e) {
return e instanceof UglifyJS.JS_Parse_Error &&
e.message === "Yield cannot be used as label inside generators";
}
assert.throws(test, expect);
});
it("Should not allow yield* followed by a semicolon in generators", function() {
var js = "function* test() {yield*\n;}";
var test = function() {
UglifyJS.parse(js);
}
var expect = function(e) {
return e instanceof UglifyJS.JS_Parse_Error &&
e.message === "Unexpected token: punc (;)";
}
assert.throws(test, expect);
});
it("Should not allow yield with next token star on next line", function() {
var js = "function* test() {yield\n*123;}";
var test = function() {
UglifyJS.parse(js);
}
var expect = function(e) {
return e instanceof UglifyJS.JS_Parse_Error &&
e.message === "Unexpected token: operator (*)";
}
assert.throws(test, expect);
});
it("Should be able to compress its expression", function() {
assert.strictEqual(
UglifyJS.minify("function *f() { yield 3-4; }", {compress: true}).code,
"function*f(){yield-1}"
);
});
it("Should keep undefined after yield without compression if found in ast", function() {
assert.strictEqual(
UglifyJS.minify("function *f() { yield undefined; yield; yield* undefined; yield void 0}", {compress: false}).code,
"function*f(){yield undefined;yield;yield*undefined;yield void 0}"
);
});
it("Should be able to drop undefined after yield if necessary with compression", function() {
assert.strictEqual(
UglifyJS.minify("function *f() { yield undefined; yield; yield* undefined; yield void 0}", {compress: true}).code,
"function*f(){yield,yield,yield*void 0,yield}"
);
});
it("Should not allow yield to be used as symbol, identifier or property outside generators in strict mode", function() {
var tests = [
// Fail as as_symbol
'"use strict"; import yield from "bar";',
'"use strict"; yield = 123;',
'"use strict"; yield: "123";',
'"use strict"; for(;;){break yield;}',
'"use strict"; for(;;){continue yield;}',
'"use strict"; function yield(){}',
'"use strict"; function foo(...yield){}',
'"use strict"; try { new Error("")} catch (yield) {}',
'"use strict"; var yield = "foo";',
'"use strict"; class yield {}',
// Fail as maybe_assign
'"use strict"; var foo = yield;',
'"use strict"; var foo = bar = yield',
// Fail as as_property_name
'"use strict"; var foo = {yield};',
'"use strict"; var bar = {yield: "foo"};'
];
var fail = function(e) {
return e instanceof UglifyJS.JS_Parse_Error &&
/^Unexpected yield identifier (?:as parameter )?inside strict mode/.test(e.message);
}
var test = function(input) {
return function() {
UglifyJS.parse(input);
}
}
for (var i = 0; i < tests.length; i++) {
assert.throws(test(tests[i]), fail, tests[i]);
}
});
});

View File

@@ -856,23 +856,21 @@ function createVarName(maybe, dontStore) {
}
function try_beautify(code, result) {
try {
var beautified = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
beautify: true,
bracketize: true,
},
}).code;
if (sandbox.same_stdout(sandbox.run_code(beautified), result)) {
console.log("// (beautified)");
console.log(beautified);
return;
}
} catch (e) {
var beautified = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
beautify: true,
bracketize: true,
},
});
if (beautified.error) {
console.log("// !!! beautify failed !!!");
console.log(e.stack);
console.log(beautified.error.stack);
} else if (sandbox.same_stdout(sandbox.run_code(beautified.code), result)) {
console.log("// (beautified)");
console.log(beautified.code);
return;
}
console.log("//");
console.log(code);
@@ -908,12 +906,13 @@ function log_suspects(minify_options, component) {
var o = JSON.parse(JSON.stringify(options));
o[name] = false;
m[component] = o;
try {
var r = sandbox.run_code(UglifyJS.minify(original_code, m).code);
return sandbox.same_stdout(original_result, r);
} catch (e) {
var result = UglifyJS.minify(original_code, m);
if (result.error) {
console.log("Error testing options." + component + "." + name);
console.log(e);
console.log(result.error);
} else {
var r = sandbox.run_code(result.code);
return sandbox.same_stdout(original_result, r);
}
}
});
@@ -981,18 +980,16 @@ for (var round = 1; round <= num_iterations; round++) {
original_code = createTopLevelCode();
original_result = sandbox.run_code(original_code);
(typeof original_result != "string" ? fallback_options : minify_options).forEach(function(options) {
try {
uglify_code = UglifyJS.minify(original_code, JSON.parse(options)).code;
} catch (e) {
uglify_code = e;
}
ok = typeof uglify_code == "string";
if (ok) {
uglify_code = UglifyJS.minify(original_code, JSON.parse(options));
if (!uglify_code.error) {
uglify_code = uglify_code.code;
uglify_result = sandbox.run_code(uglify_code);
ok = sandbox.same_stdout(original_result, uglify_result);
} else if (typeof original_result != "string") {
ok = uglify_code.name == original_result.name;
} else {
uglify_code = uglify_code.error;
if (typeof original_result != "string") {
ok = uglify_code.name == original_result.name;
}
}
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
else if (verbose_error && typeof original_result != "string") {