Compare commits
38 Commits
harmony-v3
...
harmony-v3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96f9b8cba3 | ||
|
|
11afa816e3 | ||
|
|
8b4dcd8f3e | ||
|
|
285401ced8 | ||
|
|
9db4c42380 | ||
|
|
49f3de8397 | ||
|
|
94f93ad82d | ||
|
|
d1f085bce7 | ||
|
|
7b95b63ca1 | ||
|
|
94e5e00c03 | ||
|
|
dc6bcaa18e | ||
|
|
d58b184835 | ||
|
|
137e4c4753 | ||
|
|
b3a57ff019 | ||
|
|
3d5bc08185 | ||
|
|
0692435f01 | ||
|
|
b163b13a0b | ||
|
|
402954bdf3 | ||
|
|
f5931866e0 | ||
|
|
f67a6b0e43 | ||
|
|
471db8a717 | ||
|
|
8ba9e4e0da | ||
|
|
71556d00b5 | ||
|
|
8709753bfb | ||
|
|
db877e8729 | ||
|
|
11923e3ae8 | ||
|
|
62d1fbf645 | ||
|
|
343ea326c2 | ||
|
|
849ba79dee | ||
|
|
a298bcce02 | ||
|
|
daaf1273fa | ||
|
|
1c150c632f | ||
|
|
0a0f4f5591 | ||
|
|
931daa85bf | ||
|
|
00e4f7b3c1 | ||
|
|
11e63bc335 | ||
|
|
3fa862ce19 | ||
|
|
33405bb24b |
@@ -102,6 +102,7 @@ a double dash to prevent input files being used as option arguments:
|
|||||||
sequences.
|
sequences.
|
||||||
--config-file <file> Read `minify()` options from JSON file.
|
--config-file <file> Read `minify()` options from JSON file.
|
||||||
-d, --define <expr>[=value] Global definitions.
|
-d, --define <expr>[=value] Global definitions.
|
||||||
|
--ecma <version> Specifiy ECMAScript release: 5, 6, 7 or 8.
|
||||||
--ie8 Support non-standard Internet Explorer 8.
|
--ie8 Support non-standard Internet Explorer 8.
|
||||||
Equivalent to setting `ie8: true` in `minify()`
|
Equivalent to setting `ie8: true` in `minify()`
|
||||||
for `compress`, `mangle` and `output` options.
|
for `compress`, `mangle` and `output` options.
|
||||||
@@ -590,6 +591,10 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
|
|
||||||
- `evaluate` -- attempt to evaluate constant expressions
|
- `evaluate` -- attempt to evaluate constant expressions
|
||||||
|
|
||||||
|
- `arrows` (default `true`) -- convert ES5 style anonymous function expressions
|
||||||
|
to arrow functions if permissible by language semantics.
|
||||||
|
Note: `arrows` requires that the `ecma` compress option is set to `6` or greater.
|
||||||
|
|
||||||
- `booleans` -- various optimizations for boolean context, for example `!!a
|
- `booleans` -- various optimizations for boolean context, for example `!!a
|
||||||
? b : c → a ? b : c`
|
? b : c → a ? b : c`
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ program.option("-o, --output <file>", "Output file (default STDOUT).");
|
|||||||
program.option("--comments [filter]", "Preserve copyright comments in the output.");
|
program.option("--comments [filter]", "Preserve copyright comments in the output.");
|
||||||
program.option("--config-file <file>", "Read minify() options from JSON file.");
|
program.option("--config-file <file>", "Read minify() options from JSON file.");
|
||||||
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
|
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
|
||||||
|
program.option("--ecma <version>", "Specifiy ECMAScript release: 5, 6, 7 or 8.");
|
||||||
program.option("--ie8", "Support non-standard Internet Explorer 8.");
|
program.option("--ie8", "Support non-standard Internet Explorer 8.");
|
||||||
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
|
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
|
||||||
program.option("--name-cache <file>", "File to hold mangled name mappings.");
|
program.option("--name-cache <file>", "File to hold mangled name mappings.");
|
||||||
@@ -73,6 +74,10 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
|
|||||||
options[name] = program[name];
|
options[name] = program[name];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if ("ecma" in program) {
|
||||||
|
if (program.ecma != (program.ecma | 0)) fatal("ERROR: ecma must be an integer");
|
||||||
|
options.ecma = program.ecma | 0;
|
||||||
|
}
|
||||||
if (program.beautify) {
|
if (program.beautify) {
|
||||||
options.output = typeof program.beautify == "object" ? program.beautify : {};
|
options.output = typeof program.beautify == "object" ? program.beautify : {};
|
||||||
if (!("beautify" in options.output)) {
|
if (!("beautify" in options.output)) {
|
||||||
|
|||||||
30
lib/ast.js
30
lib/ast.js
@@ -629,11 +629,11 @@ var AST_Const = DEFNODE("Const", null, {
|
|||||||
$documentation: "A `const` statement"
|
$documentation: "A `const` statement"
|
||||||
}, AST_Definitions);
|
}, AST_Definitions);
|
||||||
|
|
||||||
var AST_NameImport = DEFNODE("NameImport", "foreign_name name", {
|
var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", {
|
||||||
$documentation: "The part of the import statement that imports names from a module.",
|
$documentation: "The part of the export/import statement that declare names from a module.",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
foreign_name: "[AST_SymbolImportForeign] The name being imported (as specified in the module)",
|
foreign_name: "[AST_SymbolExportForeign|AST_SymbolImportForeign] The name being exported/imported (as specified in the module)",
|
||||||
name: "[AST_SymbolImport] The name as it becomes available to this module."
|
name: "[AST_SymbolExport|AST_SymbolImport] The name as it is visible to this module."
|
||||||
},
|
},
|
||||||
_walk: function (visitor) {
|
_walk: function (visitor) {
|
||||||
return visitor._visit(this, function() {
|
return visitor._visit(this, function() {
|
||||||
@@ -647,7 +647,7 @@ var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", {
|
|||||||
$documentation: "An `import` statement",
|
$documentation: "An `import` statement",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.",
|
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",
|
imported_names: "[AST_NameMapping*] The names of non-default imported variables",
|
||||||
module_name: "[AST_String] String literal describing where this module came from",
|
module_name: "[AST_String] String literal describing where this module came from",
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
@@ -670,7 +670,7 @@ var AST_Export = DEFNODE("Export", "exported_definition exported_value is_defaul
|
|||||||
$propdoc: {
|
$propdoc: {
|
||||||
exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition",
|
exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition",
|
||||||
exported_value: "[AST_Node?] An exported value",
|
exported_value: "[AST_Node?] An exported value",
|
||||||
exported_names: "[AST_NameImport*?] List of exported names",
|
exported_names: "[AST_NameMapping*?] List of exported names",
|
||||||
module_name: "[AST_String?] Name of the file to load exports from",
|
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"
|
is_default: "[Boolean] Whether this is the default exported value of this module"
|
||||||
},
|
},
|
||||||
@@ -682,6 +682,14 @@ var AST_Export = DEFNODE("Export", "exported_definition exported_value is_defaul
|
|||||||
if (this.exported_value) {
|
if (this.exported_value) {
|
||||||
this.exported_value._walk(visitor);
|
this.exported_value._walk(visitor);
|
||||||
}
|
}
|
||||||
|
if (this.exported_names) {
|
||||||
|
this.exported_names.forEach(function(name_export) {
|
||||||
|
name_export._walk(visitor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.module_name) {
|
||||||
|
this.module_name._walk(visitor);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
@@ -996,7 +1004,7 @@ var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
|
|||||||
}, AST_SymbolBlockDeclaration);
|
}, AST_SymbolBlockDeclaration);
|
||||||
|
|
||||||
var AST_SymbolImport = DEFNODE("SymbolImport", null, {
|
var AST_SymbolImport = DEFNODE("SymbolImport", null, {
|
||||||
$documentation: "Symbol refering to an imported name",
|
$documentation: "Symbol referring to an imported name",
|
||||||
}, AST_SymbolBlockDeclaration);
|
}, AST_SymbolBlockDeclaration);
|
||||||
|
|
||||||
var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, {
|
var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, {
|
||||||
@@ -1018,6 +1026,14 @@ var AST_SymbolRef = DEFNODE("SymbolRef", null, {
|
|||||||
$documentation: "Reference to some symbol (not definition/declaration)",
|
$documentation: "Reference to some symbol (not definition/declaration)",
|
||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|
||||||
|
var AST_SymbolExport = DEFNODE("SymbolExport", null, {
|
||||||
|
$documentation: "Symbol referring to a name to export",
|
||||||
|
}, AST_SymbolRef);
|
||||||
|
|
||||||
|
var AST_SymbolExportForeign = DEFNODE("SymbolExportForeign", null, {
|
||||||
|
$documentation: "A symbol exported from this module, but it is used in the other module, and its real name is irrelevant for this module's purposes",
|
||||||
|
}, AST_Symbol);
|
||||||
|
|
||||||
var AST_LabelRef = DEFNODE("LabelRef", null, {
|
var AST_LabelRef = DEFNODE("LabelRef", null, {
|
||||||
$documentation: "Reference to a label symbol",
|
$documentation: "Reference to a label symbol",
|
||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|||||||
495
lib/compress.js
495
lib/compress.js
@@ -48,6 +48,7 @@ function Compressor(options, false_by_default) {
|
|||||||
return new Compressor(options, false_by_default);
|
return new Compressor(options, false_by_default);
|
||||||
TreeTransformer.call(this, this.before, this.after);
|
TreeTransformer.call(this, this.before, this.after);
|
||||||
this.options = defaults(options, {
|
this.options = defaults(options, {
|
||||||
|
arrows : !false_by_default,
|
||||||
booleans : !false_by_default,
|
booleans : !false_by_default,
|
||||||
cascade : !false_by_default,
|
cascade : !false_by_default,
|
||||||
collapse_vars : !false_by_default,
|
collapse_vars : !false_by_default,
|
||||||
@@ -125,13 +126,13 @@ function Compressor(options, false_by_default) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
var toplevel = this.options["toplevel"];
|
var toplevel = this.options["toplevel"];
|
||||||
if (typeof toplevel == "string") {
|
this.toplevel = typeof toplevel == "string" ? {
|
||||||
this.toplevel.funcs = /funcs/.test(toplevel);
|
funcs: /funcs/.test(toplevel),
|
||||||
this.toplevel.vars = /vars/.test(toplevel);
|
vars: /vars/.test(toplevel)
|
||||||
} else {
|
} : {
|
||||||
this.toplevel = toplevel ? return_true : return_false;
|
funcs: toplevel,
|
||||||
this.toplevel.funcs = this.toplevel.vars = toplevel;
|
vars: toplevel
|
||||||
}
|
};
|
||||||
var sequences = this.options["sequences"];
|
var sequences = this.options["sequences"];
|
||||||
this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
|
this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
|
||||||
this.warnings_produced = {};
|
this.warnings_produced = {};
|
||||||
@@ -140,11 +141,12 @@ function Compressor(options, false_by_default) {
|
|||||||
Compressor.prototype = new TreeTransformer;
|
Compressor.prototype = new TreeTransformer;
|
||||||
merge(Compressor.prototype, {
|
merge(Compressor.prototype, {
|
||||||
option: function(key) { return this.options[key] },
|
option: function(key) { return this.options[key] },
|
||||||
toplevel: function(def) {
|
exposed: function(def) {
|
||||||
for (var i = 0, len = def.orig.length; i < len; i++)
|
if (def.export) return true;
|
||||||
|
if (def.global) for (var i = 0, len = def.orig.length; i < len; i++)
|
||||||
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
|
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
|
||||||
return false;
|
|
||||||
return true;
|
return true;
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
compress: function(node) {
|
compress: function(node) {
|
||||||
if (this.option("expression")) {
|
if (this.option("expression")) {
|
||||||
@@ -280,11 +282,11 @@ merge(Compressor.prototype, {
|
|||||||
var reduce_vars = rescan && compressor.option("reduce_vars");
|
var reduce_vars = rescan && compressor.option("reduce_vars");
|
||||||
var safe_ids = Object.create(null);
|
var safe_ids = Object.create(null);
|
||||||
var suppressor = new TreeWalker(function(node) {
|
var suppressor = new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_Symbol) {
|
if (!(node instanceof AST_Symbol)) return;
|
||||||
var d = node.definition();
|
var d = node.definition();
|
||||||
|
if (!d) return;
|
||||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
if (node instanceof AST_SymbolRef) d.references.push(node);
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
node._squeezed = false;
|
node._squeezed = false;
|
||||||
@@ -352,7 +354,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Defun) {
|
if (node instanceof AST_Defun) {
|
||||||
var d = node.name.definition();
|
var d = node.name.definition();
|
||||||
if (d.global && !compressor.toplevel(d) || safe_to_read(d)) {
|
if (compressor.exposed(d) || safe_to_read(d)) {
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
} else {
|
} else {
|
||||||
d.fixed = node;
|
d.fixed = node;
|
||||||
@@ -527,7 +529,7 @@ merge(Compressor.prototype, {
|
|||||||
def.escaped = false;
|
def.escaped = false;
|
||||||
if (def.scope.uses_eval) {
|
if (def.scope.uses_eval) {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
} else if (!def.global || def.orig[0] instanceof AST_SymbolConst || compressor.toplevel(def)) {
|
} else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) {
|
||||||
def.fixed = undefined;
|
def.fixed = undefined;
|
||||||
} else {
|
} else {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
@@ -557,8 +559,25 @@ merge(Compressor.prototype, {
|
|||||||
return fixed();
|
return fixed();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_SymbolRef.DEFMETHOD("is_immutable", function() {
|
||||||
|
var orig = this.definition().orig;
|
||||||
|
return orig.length == 1 && orig[0] instanceof AST_SymbolLambda;
|
||||||
|
});
|
||||||
|
|
||||||
function is_lhs_read_only(lhs) {
|
function is_lhs_read_only(lhs) {
|
||||||
return lhs instanceof AST_SymbolRef && lhs.definition().orig[0] instanceof AST_SymbolLambda;
|
if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda;
|
||||||
|
if (lhs instanceof AST_PropAccess) {
|
||||||
|
lhs = lhs.expression;
|
||||||
|
if (lhs instanceof AST_SymbolRef) {
|
||||||
|
if (lhs.is_immutable()) return false;
|
||||||
|
lhs = lhs.fixed_value();
|
||||||
|
}
|
||||||
|
if (!lhs) return true;
|
||||||
|
if (lhs instanceof AST_RegExp) return false;
|
||||||
|
if (lhs instanceof AST_Constant) return true;
|
||||||
|
return is_lhs_read_only(lhs);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_ref_of(ref, type) {
|
function is_ref_of(ref, type) {
|
||||||
@@ -672,7 +691,9 @@ merge(Compressor.prototype, {
|
|||||||
node instanceof AST_DefClass ||
|
node instanceof AST_DefClass ||
|
||||||
node instanceof AST_Defun ||
|
node instanceof AST_Defun ||
|
||||||
node instanceof AST_Let ||
|
node instanceof AST_Let ||
|
||||||
node instanceof AST_Const
|
node instanceof AST_Const ||
|
||||||
|
node instanceof AST_Export ||
|
||||||
|
node instanceof AST_Import
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -695,26 +716,24 @@ merge(Compressor.prototype, {
|
|||||||
var CHANGED, max_iter = 10;
|
var CHANGED, max_iter = 10;
|
||||||
do {
|
do {
|
||||||
CHANGED = false;
|
CHANGED = false;
|
||||||
statements = eliminate_spurious_blocks(statements);
|
eliminate_spurious_blocks(statements);
|
||||||
if (compressor.option("dead_code")) {
|
if (compressor.option("dead_code")) {
|
||||||
statements = eliminate_dead_code(statements, compressor);
|
eliminate_dead_code(statements, compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("if_return")) {
|
if (compressor.option("if_return")) {
|
||||||
statements = handle_if_return(statements, compressor);
|
handle_if_return(statements, compressor);
|
||||||
}
|
}
|
||||||
if (compressor.sequences_limit > 0) {
|
if (compressor.sequences_limit > 0) {
|
||||||
statements = sequencesize(statements, compressor);
|
sequencesize(statements, compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("join_vars")) {
|
if (compressor.option("join_vars")) {
|
||||||
statements = join_consecutive_vars(statements, compressor);
|
join_consecutive_vars(statements, compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("collapse_vars")) {
|
if (compressor.option("collapse_vars")) {
|
||||||
statements = collapse(statements, compressor);
|
collapse(statements, compressor);
|
||||||
}
|
}
|
||||||
} while (CHANGED && max_iter-- > 0);
|
} while (CHANGED && max_iter-- > 0);
|
||||||
|
|
||||||
return statements;
|
|
||||||
|
|
||||||
// Search from right to left for assignment-like expressions:
|
// Search from right to left for assignment-like expressions:
|
||||||
// - `var a = x;`
|
// - `var a = x;`
|
||||||
// - `a = x;`
|
// - `a = x;`
|
||||||
@@ -752,6 +771,7 @@ merge(Compressor.prototype, {
|
|||||||
var parent = tt.parent();
|
var parent = tt.parent();
|
||||||
if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
|
if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
|
||||||
|| node instanceof AST_Await
|
|| node instanceof AST_Await
|
||||||
|
|| node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
|
||||||
|| node instanceof AST_Debugger
|
|| node instanceof AST_Debugger
|
||||||
|| node instanceof AST_Destructuring
|
|| node instanceof AST_Destructuring
|
||||||
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
||||||
@@ -778,7 +798,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (candidate instanceof AST_VarDef) {
|
if (candidate instanceof AST_VarDef) {
|
||||||
var def = candidate.name.definition();
|
var def = candidate.name.definition();
|
||||||
if (def.references.length == 1 && (!def.global || compressor.toplevel(def))) {
|
if (def.references.length == 1 && !compressor.exposed(def)) {
|
||||||
return maintain_this_binding(parent, node, candidate.value);
|
return maintain_this_binding(parent, node, candidate.value);
|
||||||
}
|
}
|
||||||
return make_node(AST_Assign, candidate, {
|
return make_node(AST_Assign, candidate, {
|
||||||
@@ -818,7 +838,6 @@ merge(Compressor.prototype, {
|
|||||||
if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
|
if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return statements;
|
|
||||||
|
|
||||||
function extract_candidates(expr) {
|
function extract_candidates(expr) {
|
||||||
if (expr instanceof AST_Assign && !expr.left.has_side_effects(compressor)
|
if (expr instanceof AST_Assign && !expr.left.has_side_effects(compressor)
|
||||||
@@ -841,7 +860,7 @@ merge(Compressor.prototype, {
|
|||||||
if (expr instanceof AST_VarDef && expr.name instanceof AST_SymbolDeclaration) {
|
if (expr instanceof AST_VarDef && expr.name instanceof AST_SymbolDeclaration) {
|
||||||
var def = expr.name.definition();
|
var def = expr.name.definition();
|
||||||
if (def.orig.length > 1
|
if (def.orig.length > 1
|
||||||
|| def.references.length == 1 && (!def.global || compressor.toplevel(def))) {
|
|| def.references.length == 1 && !compressor.exposed(def)) {
|
||||||
return make_node(AST_SymbolRef, expr.name, expr.name);
|
return make_node(AST_SymbolRef, expr.name, expr.name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -921,59 +940,60 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function eliminate_spurious_blocks(statements) {
|
function eliminate_spurious_blocks(statements) {
|
||||||
var seen_dirs = [];
|
var seen_dirs = [];
|
||||||
return statements.reduce(function(a, stat){
|
for (var i = 0; i < statements.length;) {
|
||||||
|
var stat = statements[i];
|
||||||
if (stat instanceof AST_BlockStatement && all(stat.body, can_be_evicted_from_block)) {
|
if (stat instanceof AST_BlockStatement && all(stat.body, can_be_evicted_from_block)) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
a.push.apply(a, eliminate_spurious_blocks(stat.body));
|
eliminate_spurious_blocks(stat.body);
|
||||||
|
[].splice.apply(statements, [i, 1].concat(stat.body));
|
||||||
|
i += stat.body.length;
|
||||||
} else if (stat instanceof AST_EmptyStatement) {
|
} else if (stat instanceof AST_EmptyStatement) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
|
statements.splice(i, 1);
|
||||||
} else if (stat instanceof AST_Directive) {
|
} else if (stat instanceof AST_Directive) {
|
||||||
if (seen_dirs.indexOf(stat.value) < 0) {
|
if (seen_dirs.indexOf(stat.value) < 0) {
|
||||||
a.push(stat);
|
i++;
|
||||||
seen_dirs.push(stat.value);
|
seen_dirs.push(stat.value);
|
||||||
} else {
|
} else {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
|
statements.splice(i, 1);
|
||||||
|
}
|
||||||
|
} else i++;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
a.push(stat);
|
|
||||||
}
|
}
|
||||||
return a;
|
|
||||||
}, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
function handle_if_return(statements, compressor) {
|
function handle_if_return(statements, compressor) {
|
||||||
var self = compressor.self();
|
var self = compressor.self();
|
||||||
var multiple_if_returns = has_multiple_if_returns(statements);
|
var multiple_if_returns = has_multiple_if_returns(statements);
|
||||||
var in_lambda = self instanceof AST_Lambda;
|
var in_lambda = self instanceof AST_Lambda;
|
||||||
var ret = []; // Optimized statements, build from tail to front
|
for (var i = statements.length; --i >= 0;) {
|
||||||
loop: for (var i = statements.length; --i >= 0;) {
|
|
||||||
var stat = statements[i];
|
var stat = statements[i];
|
||||||
switch (true) {
|
var next = statements[i + 1];
|
||||||
case (in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0):
|
|
||||||
|
if (in_lambda && stat instanceof AST_Return && !stat.value && !next) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
// note, ret.length is probably always zero
|
statements.length--;
|
||||||
// because we drop unreachable code before this
|
continue;
|
||||||
// step. nevertheless, it's good to check.
|
}
|
||||||
continue loop;
|
|
||||||
case stat instanceof AST_If:
|
if (stat instanceof AST_If) {
|
||||||
var ab = aborts(stat.body);
|
var ab = aborts(stat.body);
|
||||||
if (can_merge_flow(ab)) {
|
if (can_merge_flow(ab)) {
|
||||||
if (ab.label) {
|
if (ab.label) {
|
||||||
remove(ab.label.thedef.references, ab);
|
remove(ab.label.thedef.references, ab);
|
||||||
}
|
}
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
var funs = extract_functions_from_statement_array(ret);
|
|
||||||
var body = as_statement_array_with_return(stat.body, ab);
|
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.condition = stat.condition.negate(compressor);
|
stat.condition = stat.condition.negate(compressor);
|
||||||
|
var body = as_statement_array_with_return(stat.body, ab);
|
||||||
stat.body = make_node(AST_BlockStatement, stat, {
|
stat.body = make_node(AST_BlockStatement, stat, {
|
||||||
body: as_statement_array(stat.alternative).concat(ret)
|
body: as_statement_array(stat.alternative).concat(extract_functions())
|
||||||
});
|
});
|
||||||
stat.alternative = make_node(AST_BlockStatement, stat, {
|
stat.alternative = make_node(AST_BlockStatement, stat, {
|
||||||
body: body
|
body: body
|
||||||
});
|
});
|
||||||
ret = [ stat.transform(compressor) ].concat(funs);
|
statements[i] = stat.transform(compressor);
|
||||||
continue loop;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ab = aborts(stat.alternative);
|
var ab = aborts(stat.alternative);
|
||||||
@@ -982,53 +1002,52 @@ merge(Compressor.prototype, {
|
|||||||
remove(ab.label.thedef.references, ab);
|
remove(ab.label.thedef.references, ab);
|
||||||
}
|
}
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
var funs = extract_functions_from_statement_array(ret);
|
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.body = make_node(AST_BlockStatement, stat.body, {
|
stat.body = make_node(AST_BlockStatement, stat.body, {
|
||||||
body: as_statement_array(stat.body).concat(ret)
|
body: as_statement_array(stat.body).concat(extract_functions())
|
||||||
});
|
});
|
||||||
var body = as_statement_array_with_return(stat.alternative, ab);
|
var body = as_statement_array_with_return(stat.alternative, ab);
|
||||||
stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
|
stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
|
||||||
body: body
|
body: body
|
||||||
});
|
});
|
||||||
ret = [ stat.transform(compressor) ].concat(funs);
|
statements[i] = stat.transform(compressor);
|
||||||
continue loop;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat.body instanceof AST_Return) {
|
if (stat instanceof AST_If && stat.body instanceof AST_Return) {
|
||||||
var value = stat.body.value;
|
var value = stat.body.value;
|
||||||
//---
|
//---
|
||||||
// pretty silly case, but:
|
// pretty silly case, but:
|
||||||
// if (foo()) return; return; ==> foo(); return;
|
// if (foo()) return; return; ==> foo(); return;
|
||||||
if ((in_lambda && ret.length == 0 || ret[0] instanceof AST_Return && !ret[0].value)
|
if (!value && !stat.alternative
|
||||||
&& !value && !stat.alternative) {
|
&& (in_lambda && !next || next instanceof AST_Return && !next.value)) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
var cond = make_node(AST_SimpleStatement, stat.condition, {
|
statements[i] = make_node(AST_SimpleStatement, stat.condition, {
|
||||||
body: stat.condition
|
body: stat.condition
|
||||||
});
|
});
|
||||||
ret.unshift(cond);
|
continue;
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
// if (foo()) return x; return y; ==> return foo() ? x : y;
|
// if (foo()) return x; return y; ==> return foo() ? x : y;
|
||||||
if (ret[0] instanceof AST_Return && value && ret[0].value && !stat.alternative) {
|
if (value && !stat.alternative && next instanceof AST_Return && next.value) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = ret[0];
|
stat.alternative = next;
|
||||||
ret[0] = stat.transform(compressor);
|
statements.splice(i, 2, stat.transform(compressor));
|
||||||
continue loop;
|
continue;
|
||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
||||||
if (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return)
|
if (multiple_if_returns && in_lambda && value && !stat.alternative
|
||||||
&& value && !stat.alternative && in_lambda) {
|
&& (!next || next instanceof AST_Return)) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = ret[0] || make_node(AST_Return, stat, {
|
stat.alternative = next || make_node(AST_Return, stat, {
|
||||||
value: null
|
value: null
|
||||||
});
|
});
|
||||||
ret[0] = stat.transform(compressor);
|
statements.splice(i, next ? 2 : 1, stat.transform(compressor));
|
||||||
continue loop;
|
continue;
|
||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
||||||
@@ -1036,27 +1055,18 @@ merge(Compressor.prototype, {
|
|||||||
// if sequences is not enabled, this can lead to an endless loop (issue #866).
|
// if sequences is not enabled, this can lead to an endless loop (issue #866).
|
||||||
// however, with sequences on this helps producing slightly better output for
|
// however, with sequences on this helps producing slightly better output for
|
||||||
// the example code.
|
// the example code.
|
||||||
if (compressor.option("sequences")
|
var prev = statements[i - 1];
|
||||||
&& i > 0 && statements[i - 1] instanceof AST_If && statements[i - 1].body instanceof AST_Return
|
if (compressor.option("sequences") && in_lambda && !stat.alternative
|
||||||
&& ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement
|
&& prev instanceof AST_If && prev.body instanceof AST_Return
|
||||||
&& !stat.alternative) {
|
&& i + 2 == statements.length && next instanceof AST_SimpleStatement) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
ret.push(make_node(AST_Return, ret[0], {
|
statements.push(make_node(AST_Return, next, {
|
||||||
value: null
|
value: null
|
||||||
}).transform(compressor));
|
}).transform(compressor));
|
||||||
ret.unshift(stat);
|
continue;
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.unshift(stat);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret.unshift(stat);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
function has_multiple_if_returns(statements) {
|
function has_multiple_if_returns(statements) {
|
||||||
var n = 0;
|
var n = 0;
|
||||||
@@ -1074,15 +1084,29 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function can_merge_flow(ab) {
|
function can_merge_flow(ab) {
|
||||||
if (!ab || !all(ret, function(stat) {
|
if (!ab) return false;
|
||||||
return !(stat instanceof AST_Const || stat instanceof AST_Let);
|
for (var j = i + 1, len = statements.length; j < len; j++) {
|
||||||
})) return false;
|
var stat = statements[j];
|
||||||
|
if (stat instanceof AST_Const || stat instanceof AST_Let) return false;
|
||||||
|
}
|
||||||
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null;
|
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null;
|
||||||
return ab instanceof AST_Return && in_lambda && is_return_void(ab.value)
|
return ab instanceof AST_Return && in_lambda && is_return_void(ab.value)
|
||||||
|| ab instanceof AST_Continue && self === loop_body(lct)
|
|| ab instanceof AST_Continue && self === loop_body(lct)
|
||||||
|| ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct;
|
|| ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extract_functions() {
|
||||||
|
var tail = statements.slice(i + 1);
|
||||||
|
statements.length = i + 1;
|
||||||
|
return tail.filter(function(stat) {
|
||||||
|
if (stat instanceof AST_Defun) {
|
||||||
|
statements.push(stat);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function as_statement_array_with_return(node, ab) {
|
function as_statement_array_with_return(node, ab) {
|
||||||
var body = as_statement_array(node).slice(0, -1);
|
var body = as_statement_array(node).slice(0, -1);
|
||||||
if (ab.value) {
|
if (ab.value) {
|
||||||
@@ -1092,49 +1116,52 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function eliminate_dead_code(statements, compressor) {
|
function eliminate_dead_code(statements, compressor) {
|
||||||
var has_quit = false;
|
var has_quit;
|
||||||
var orig = statements.length;
|
|
||||||
var self = compressor.self();
|
var self = compressor.self();
|
||||||
statements = statements.reduce(function(a, stat){
|
for (var i = 0, n = 0, len = statements.length; i < len; i++) {
|
||||||
if (has_quit) {
|
var stat = statements[i];
|
||||||
extract_declarations_from_unreachable_code(compressor, stat, a);
|
|
||||||
} else {
|
|
||||||
if (stat instanceof AST_LoopControl) {
|
if (stat instanceof AST_LoopControl) {
|
||||||
var lct = compressor.loopcontrol_target(stat);
|
var lct = compressor.loopcontrol_target(stat);
|
||||||
if ((stat instanceof AST_Break
|
if (stat instanceof AST_Break
|
||||||
&& !(lct instanceof AST_IterationStatement)
|
&& !(lct instanceof AST_IterationStatement)
|
||||||
&& loop_body(lct) === self) || (stat instanceof AST_Continue
|
&& loop_body(lct) === self
|
||||||
&& loop_body(lct) === self)) {
|
|| stat instanceof AST_Continue
|
||||||
|
&& loop_body(lct) === self) {
|
||||||
if (stat.label) {
|
if (stat.label) {
|
||||||
remove(stat.label.thedef.references, stat);
|
remove(stat.label.thedef.references, stat);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
a.push(stat);
|
statements[n++] = stat;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
a.push(stat);
|
statements[n++] = stat;
|
||||||
}
|
}
|
||||||
if (aborts(stat)) has_quit = true;
|
if (aborts(stat)) {
|
||||||
|
has_quit = statements.slice(i + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statements.length = n;
|
||||||
|
CHANGED = n != len;
|
||||||
|
if (has_quit) has_quit.forEach(function(stat) {
|
||||||
|
extract_declarations_from_unreachable_code(compressor, stat, statements);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return a;
|
|
||||||
}, []);
|
|
||||||
CHANGED = statements.length != orig;
|
|
||||||
return statements;
|
|
||||||
};
|
|
||||||
|
|
||||||
function sequencesize(statements, compressor) {
|
function sequencesize(statements, compressor) {
|
||||||
if (statements.length < 2) return statements;
|
if (statements.length < 2) return;
|
||||||
var seq = [], ret = [];
|
var seq = [], n = 0;
|
||||||
function push_seq() {
|
function push_seq() {
|
||||||
if (!seq.length) return;
|
if (!seq.length) return;
|
||||||
var body = make_sequence(seq[0], seq);
|
var body = make_sequence(seq[0], seq);
|
||||||
ret.push(make_node(AST_SimpleStatement, body, { body: body }));
|
statements[n++] = make_node(AST_SimpleStatement, body, { body: body });
|
||||||
seq = [];
|
seq = [];
|
||||||
};
|
}
|
||||||
statements.forEach(function(stat){
|
for (var i = 0, len = statements.length; i < len; i++) {
|
||||||
|
var stat = statements[i];
|
||||||
if (stat instanceof AST_SimpleStatement) {
|
if (stat instanceof AST_SimpleStatement) {
|
||||||
if (seq.length >= compressor.sequences_limit) push_seq();
|
if (seq.length >= compressor.sequences_limit) push_seq();
|
||||||
var body = stat.body;
|
var body = stat.body;
|
||||||
@@ -1142,18 +1169,18 @@ merge(Compressor.prototype, {
|
|||||||
if (body) merge_sequence(seq, body);
|
if (body) merge_sequence(seq, body);
|
||||||
} else {
|
} else {
|
||||||
push_seq();
|
push_seq();
|
||||||
ret.push(stat);
|
statements[n++] = stat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
push_seq();
|
push_seq();
|
||||||
ret = sequencesize_2(ret, compressor);
|
statements.length = n;
|
||||||
CHANGED = ret.length != statements.length;
|
sequencesize_2(statements, compressor);
|
||||||
return ret;
|
CHANGED = statements.length != len;
|
||||||
};
|
}
|
||||||
|
|
||||||
function sequencesize_2(statements, compressor) {
|
function sequencesize_2(statements, compressor) {
|
||||||
function cons_seq(right) {
|
function cons_seq(right) {
|
||||||
ret.pop();
|
n--;
|
||||||
var left = prev.body;
|
var left = prev.body;
|
||||||
if (!(left instanceof AST_Sequence)) {
|
if (!(left instanceof AST_Sequence)) {
|
||||||
left = make_node(AST_Sequence, left, {
|
left = make_node(AST_Sequence, left, {
|
||||||
@@ -1163,8 +1190,9 @@ merge(Compressor.prototype, {
|
|||||||
merge_sequence(left.expressions, right);
|
merge_sequence(left.expressions, right);
|
||||||
return left.transform(compressor);
|
return left.transform(compressor);
|
||||||
};
|
};
|
||||||
var ret = [], prev = null;
|
var n = 0, prev;
|
||||||
statements.forEach(function(stat){
|
for (var i = 0, len = statements.length; i < len; i++) {
|
||||||
|
var stat = statements[i];
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (stat instanceof AST_For) {
|
if (stat instanceof AST_For) {
|
||||||
try {
|
try {
|
||||||
@@ -1177,7 +1205,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
else if (!stat.init) {
|
else if (!stat.init) {
|
||||||
stat.init = prev.body.drop_side_effect_free(compressor);
|
stat.init = prev.body.drop_side_effect_free(compressor);
|
||||||
ret.pop();
|
n--;
|
||||||
}
|
}
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex !== cons_seq) throw ex;
|
if (ex !== cons_seq) throw ex;
|
||||||
@@ -1199,15 +1227,16 @@ merge(Compressor.prototype, {
|
|||||||
stat.expression = cons_seq(stat.expression);
|
stat.expression = cons_seq(stat.expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret.push(stat);
|
statements[n++] = stat;
|
||||||
prev = stat instanceof AST_SimpleStatement ? stat : null;
|
prev = stat instanceof AST_SimpleStatement ? stat : null;
|
||||||
});
|
}
|
||||||
return ret;
|
statements.length = n;
|
||||||
};
|
}
|
||||||
|
|
||||||
function join_consecutive_vars(statements, compressor) {
|
function join_consecutive_vars(statements, compressor) {
|
||||||
var prev = null;
|
for (var i = 0, j = -1, len = statements.length; i < len; i++) {
|
||||||
return statements.reduce(function(a, stat){
|
var stat = statements[i];
|
||||||
|
var prev = statements[j];
|
||||||
if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
|
if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
|
||||||
prev.definitions = prev.definitions.concat(stat.definitions);
|
prev.definitions = prev.definitions.concat(stat.definitions);
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
@@ -1216,35 +1245,19 @@ merge(Compressor.prototype, {
|
|||||||
&& prev instanceof AST_Var
|
&& prev instanceof AST_Var
|
||||||
&& (!stat.init || stat.init.TYPE == prev.TYPE)) {
|
&& (!stat.init || stat.init.TYPE == prev.TYPE)) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
a.pop();
|
|
||||||
if (stat.init) {
|
if (stat.init) {
|
||||||
stat.init.definitions = prev.definitions.concat(stat.init.definitions);
|
stat.init.definitions = prev.definitions.concat(stat.init.definitions);
|
||||||
} else {
|
} else {
|
||||||
stat.init = prev;
|
stat.init = prev;
|
||||||
}
|
}
|
||||||
a.push(stat);
|
statements[j] = stat;
|
||||||
prev = stat;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
prev = stat;
|
statements[++j] = stat;
|
||||||
a.push(stat);
|
|
||||||
}
|
}
|
||||||
return a;
|
}
|
||||||
}, []);
|
statements.length = j + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
function extract_functions_from_statement_array(statements) {
|
|
||||||
var funs = [];
|
|
||||||
for (var i = statements.length - 1; i >= 0; --i) {
|
|
||||||
var stat = statements[i];
|
|
||||||
if (stat instanceof AST_Defun) {
|
|
||||||
statements.splice(i, 1);
|
|
||||||
funs.unshift(stat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return funs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
||||||
@@ -1336,6 +1349,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_SymbolRef, function(pure_getters) {
|
def(AST_SymbolRef, function(pure_getters) {
|
||||||
if (this.is_undefined) return true;
|
if (this.is_undefined) return true;
|
||||||
if (!is_strict(pure_getters)) return false;
|
if (!is_strict(pure_getters)) return false;
|
||||||
|
if (this.is_immutable()) return false;
|
||||||
var fixed = this.fixed_value();
|
var fixed = this.fixed_value();
|
||||||
return !fixed || fixed._throw_on_access(pure_getters);
|
return !fixed || fixed._throw_on_access(pure_getters);
|
||||||
});
|
});
|
||||||
@@ -2050,13 +2064,12 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Block, function(self, compressor){
|
OPT(AST_Block, function(self, compressor){
|
||||||
if (self.body instanceof AST_Node) { return self; }
|
tighten_body(self.body, compressor);
|
||||||
self.body = tighten_body(self.body, compressor);
|
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_BlockStatement, function(self, compressor){
|
OPT(AST_BlockStatement, function(self, compressor){
|
||||||
self.body = tighten_body(self.body, compressor);
|
tighten_body(self.body, compressor);
|
||||||
switch (self.body.length) {
|
switch (self.body.length) {
|
||||||
case 1:
|
case 1:
|
||||||
if (!compressor.has_directive("use strict") && compressor.parent() instanceof AST_If
|
if (!compressor.has_directive("use strict") && compressor.parent() instanceof AST_If
|
||||||
@@ -2090,14 +2103,14 @@ merge(Compressor.prototype, {
|
|||||||
var var_defs_by_id = new Dictionary();
|
var var_defs_by_id = new Dictionary();
|
||||||
var initializations = new Dictionary();
|
var initializations = new Dictionary();
|
||||||
var destructuring_value = null;
|
var destructuring_value = null;
|
||||||
var in_definition = false;
|
|
||||||
// pass 1: find out which symbols are directly used in
|
// pass 1: find out which symbols are directly used in
|
||||||
// this scope (not in nested scopes).
|
// this scope (not in nested scopes).
|
||||||
var scope = this;
|
var scope = this;
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node !== self) {
|
if (node !== self) {
|
||||||
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
|
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
|
||||||
if (!drop_funcs && scope === self) {
|
var in_export = tw.parent() instanceof AST_Export;
|
||||||
|
if (in_export || !drop_funcs && scope === self) {
|
||||||
var node_def = node.name.definition();
|
var node_def = node.name.definition();
|
||||||
if (node_def.global && !(node_def.id in in_use_ids)) {
|
if (node_def.global && !(node_def.id in in_use_ids)) {
|
||||||
in_use_ids[node_def.id] = true;
|
in_use_ids[node_def.id] = true;
|
||||||
@@ -2108,15 +2121,16 @@ merge(Compressor.prototype, {
|
|||||||
return true; // don't go in nested scopes
|
return true; // don't go in nested scopes
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Definitions && scope === self) {
|
if (node instanceof AST_Definitions && scope === self) {
|
||||||
|
var in_export = tw.parent() instanceof AST_Export;
|
||||||
node.definitions.forEach(function(def){
|
node.definitions.forEach(function(def){
|
||||||
if (def.name instanceof AST_SymbolVar) {
|
if (def.name instanceof AST_SymbolVar) {
|
||||||
var_defs_by_id.add(def.name.definition().id, def);
|
var_defs_by_id.add(def.name.definition().id, def);
|
||||||
}
|
}
|
||||||
if (!drop_vars) {
|
if (in_export || !drop_vars) {
|
||||||
def.name.walk(new TreeWalker(function(node) {
|
def.name.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_SymbolDeclaration) {
|
if (node instanceof AST_SymbolDeclaration) {
|
||||||
var def = node.definition();
|
var def = node.definition();
|
||||||
if (def.global && !(def.id in in_use_ids)) {
|
if ((in_export || def.global) && !(def.id in in_use_ids)) {
|
||||||
in_use_ids[def.id] = true;
|
in_use_ids[def.id] = true;
|
||||||
in_use.push(def);
|
in_use.push(def);
|
||||||
}
|
}
|
||||||
@@ -2127,9 +2141,7 @@ merge(Compressor.prototype, {
|
|||||||
if (def.name instanceof AST_Destructuring) {
|
if (def.name instanceof AST_Destructuring) {
|
||||||
var destructuring_cache = destructuring_value;
|
var destructuring_cache = destructuring_value;
|
||||||
destructuring_value = def.value;
|
destructuring_value = def.value;
|
||||||
in_definition = true;
|
|
||||||
def.walk(tw);
|
def.walk(tw);
|
||||||
in_definition = false;
|
|
||||||
destructuring_value = destructuring_cache;
|
destructuring_value = destructuring_cache;
|
||||||
} else {
|
} else {
|
||||||
initializations.add(def.name.name, def.value);
|
initializations.add(def.name.name, def.value);
|
||||||
@@ -2165,46 +2177,8 @@ merge(Compressor.prototype, {
|
|||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Destructuring) {
|
if (node.destructuring && destructuring_value) {
|
||||||
if (!in_definition) {
|
initializations.add(node.name, destructuring_value);
|
||||||
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_ObjectKeyVal) {
|
|
||||||
if (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 if (node.names[i] instanceof AST_DefaultAssign) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (node.names[i] instanceof AST_Hole) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error(string_template("Unknown destructuring element of type: {type}", {
|
|
||||||
type: Object.getPrototypeOf(node.names[i]).TYPE
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -2233,11 +2207,8 @@ merge(Compressor.prototype, {
|
|||||||
// pass 3: we should drop declarations not in_use
|
// pass 3: we should drop declarations not in_use
|
||||||
var tt = new TreeTransformer(
|
var tt = new TreeTransformer(
|
||||||
function before(node, descend, in_list) {
|
function before(node, descend, in_list) {
|
||||||
var parent = tt.parent();
|
|
||||||
if (!compressor.option("keep_fnames")
|
if (!compressor.option("keep_fnames")
|
||||||
&& ((node instanceof AST_Function || node instanceof AST_ClassExpression) && node.name
|
&& node.name && (node instanceof AST_Function || node instanceof AST_ClassExpression)) {
|
||||||
|| (node instanceof AST_Defun || node instanceof AST_DefClass)
|
|
||||||
&& parent instanceof AST_Export && parent.is_default)) {
|
|
||||||
var def = node.name.definition();
|
var def = node.name.definition();
|
||||||
// any declarations with same name will overshadow
|
// any declarations with same name will overshadow
|
||||||
// name of this anonymous function and can therefore
|
// name of this anonymous function and can therefore
|
||||||
@@ -2272,7 +2243,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((node instanceof AST_Defun || node instanceof AST_DefClass) && !(parent instanceof AST_Export) && node !== self) {
|
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;
|
var keep = (node.name.definition().id in in_use_ids) || !drop_funcs && node.name.definition().global;
|
||||||
if (!keep) {
|
if (!keep) {
|
||||||
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
||||||
@@ -2280,6 +2251,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
var parent = tt.parent();
|
||||||
if (node instanceof AST_Definitions
|
if (node instanceof AST_Definitions
|
||||||
&& !(parent instanceof AST_ForIn && parent.init === node)
|
&& !(parent instanceof AST_ForIn && parent.init === node)
|
||||||
&& (drop_vars || !(parent instanceof AST_Toplevel) && !(node instanceof AST_Var))) {
|
&& (drop_vars || !(parent instanceof AST_Toplevel) && !(node instanceof AST_Var))) {
|
||||||
@@ -3057,7 +3029,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Try, function(self, compressor){
|
OPT(AST_Try, function(self, compressor){
|
||||||
self.body = tighten_body(self.body, compressor);
|
tighten_body(self.body, compressor);
|
||||||
if (self.bcatch && self.bfinally && all(self.bfinally.body, is_empty)) self.bfinally = null;
|
if (self.bcatch && self.bfinally && all(self.bfinally.body, is_empty)) self.bfinally = null;
|
||||||
if (all(self.body, is_empty)) {
|
if (all(self.body, is_empty)) {
|
||||||
var body = [];
|
var body = [];
|
||||||
@@ -3114,18 +3086,34 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
OPT(AST_Call, function(self, compressor){
|
OPT(AST_Call, function(self, compressor){
|
||||||
var exp = self.expression;
|
var exp = self.expression;
|
||||||
if (compressor.option("reduce_vars") && exp instanceof AST_SymbolRef) {
|
var fn = exp;
|
||||||
var fixed = exp.fixed_value();
|
var simple_args = all(self.args, function(arg) {
|
||||||
if (fixed instanceof AST_Function) exp = fixed;
|
return !(arg instanceof AST_Expansion);
|
||||||
}
|
});
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& exp instanceof AST_Function
|
&& simple_args
|
||||||
&& !exp.uses_arguments
|
&& (fn instanceof AST_Function
|
||||||
&& !exp.uses_eval) {
|
|| compressor.option("reduce_vars")
|
||||||
|
&& fn instanceof AST_SymbolRef
|
||||||
|
&& (fn = fn.fixed_value()) instanceof AST_Function)
|
||||||
|
&& !fn.uses_arguments
|
||||||
|
&& !fn.uses_eval) {
|
||||||
var pos = 0, last = 0;
|
var pos = 0, last = 0;
|
||||||
for (var i = 0, len = self.args.length; i < len; i++) {
|
for (var i = 0, len = self.args.length; i < len; i++) {
|
||||||
var trim = i >= exp.argnames.length;
|
if (fn.argnames[i] instanceof AST_Expansion) {
|
||||||
if (trim || exp.argnames[i].__unused) {
|
if (fn.argnames[i].__unused) while (i < len) {
|
||||||
|
var node = self.args[i++].drop_side_effect_free(compressor);
|
||||||
|
if (node) {
|
||||||
|
self.args[pos++] = node;
|
||||||
|
}
|
||||||
|
} else while (i < len) {
|
||||||
|
self.args[pos++] = self.args[i++];
|
||||||
|
}
|
||||||
|
last = pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var trim = i >= fn.argnames.length;
|
||||||
|
if (trim || fn.argnames[i].__unused) {
|
||||||
var node = self.args[i].drop_side_effect_free(compressor);
|
var node = self.args[i].drop_side_effect_free(compressor);
|
||||||
if (node) {
|
if (node) {
|
||||||
self.args[pos++] = node;
|
self.args[pos++] = node;
|
||||||
@@ -3298,15 +3286,18 @@ merge(Compressor.prototype, {
|
|||||||
var comp = new Compressor(compressor.options);
|
var comp = new Compressor(compressor.options);
|
||||||
ast = ast.transform(comp);
|
ast = ast.transform(comp);
|
||||||
ast.figure_out_scope(mangle);
|
ast.figure_out_scope(mangle);
|
||||||
ast.mangle_names();
|
base54.reset();
|
||||||
|
ast.compute_char_frequency(mangle);
|
||||||
|
ast.mangle_names(mangle);
|
||||||
var fun;
|
var fun;
|
||||||
ast.walk(new TreeWalker(function(node) {
|
ast.walk(new TreeWalker(function(node) {
|
||||||
if (fun) return true;
|
if (fun) return true;
|
||||||
if (node instanceof AST_Lambda) {
|
if (node instanceof AST_Function) {
|
||||||
fun = node;
|
fun = node;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
if (!fun) return self;
|
||||||
var args = fun.argnames.map(function(arg, i) {
|
var args = fun.argnames.map(function(arg, i) {
|
||||||
return make_node(AST_String, self.args[i], {
|
return make_node(AST_String, self.args[i], {
|
||||||
value: arg.print_to_string()
|
value: arg.print_to_string()
|
||||||
@@ -3330,20 +3321,21 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (exp instanceof AST_Function && !self.expression.is_generator && !self.expression.async) {
|
var stat = fn instanceof AST_Function && fn.body[0];
|
||||||
var stat = exp.body[0];
|
|
||||||
if (compressor.option("inline") && stat instanceof AST_Return) {
|
if (compressor.option("inline") && stat instanceof AST_Return) {
|
||||||
var value = stat && stat.value;
|
var value = stat.value;
|
||||||
if (!value || value.is_constant_expression()) {
|
if (!value || value.is_constant_expression()) {
|
||||||
var args = self.args.concat(value || make_node(AST_Undefined, self));
|
var args = self.args.concat(value || make_node(AST_Undefined, self));
|
||||||
return make_sequence(self, args).transform(compressor);
|
return make_sequence(self, args).transform(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (exp instanceof AST_Function && !exp.is_generator && !exp.async) {
|
||||||
if (compressor.option("inline")
|
if (compressor.option("inline")
|
||||||
&& !exp.name
|
&& !exp.name
|
||||||
&& exp.body.length == 1
|
&& exp.body.length == 1
|
||||||
&& !exp.uses_arguments
|
&& !exp.uses_arguments
|
||||||
&& !exp.uses_eval
|
&& !exp.uses_eval
|
||||||
|
&& simple_args
|
||||||
&& !self.has_pure_annotation(compressor)) {
|
&& !self.has_pure_annotation(compressor)) {
|
||||||
var value;
|
var value;
|
||||||
if (stat instanceof AST_Return) {
|
if (stat instanceof AST_Return) {
|
||||||
@@ -3361,16 +3353,29 @@ merge(Compressor.prototype, {
|
|||||||
if (exp.argnames.length > 0) {
|
if (exp.argnames.length > 0) {
|
||||||
fn.body.push(make_node(AST_Var, self, {
|
fn.body.push(make_node(AST_Var, self, {
|
||||||
definitions: exp.argnames.map(function(sym, i) {
|
definitions: exp.argnames.map(function(sym, i) {
|
||||||
|
if (sym instanceof AST_Expansion) {
|
||||||
|
return make_node(AST_VarDef, sym, {
|
||||||
|
name: sym.expression,
|
||||||
|
value: make_node(AST_Array, self, {
|
||||||
|
elements: self.args.slice(i).map(function(arg) {
|
||||||
|
return arg.clone(true);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var arg = self.args[i];
|
||||||
return make_node(AST_VarDef, sym, {
|
return make_node(AST_VarDef, sym, {
|
||||||
name: sym,
|
name: sym,
|
||||||
value: self.args[i] || make_node(AST_Undefined, self)
|
value: arg ? arg.clone(true) : make_node(AST_Undefined, self)
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if (self.args.length > exp.argnames.length) {
|
if (self.args.length > exp.argnames.length && !(exp.argnames[exp.argnames.length - 1] instanceof AST_Expansion)) {
|
||||||
fn.body.push(make_node(AST_SimpleStatement, self, {
|
fn.body.push(make_node(AST_SimpleStatement, self, {
|
||||||
body: make_sequence(self, self.args.slice(exp.argnames.length))
|
body: make_sequence(self, self.args.slice(exp.argnames.length).map(function(node) {
|
||||||
|
return node.clone(true);
|
||||||
|
}))
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
fn.body.push(make_node(AST_Return, self, {
|
fn.body.push(make_node(AST_Return, self, {
|
||||||
@@ -3381,18 +3386,21 @@ merge(Compressor.prototype, {
|
|||||||
if (body.length == 1 && body[0] instanceof AST_Return) {
|
if (body.length == 1 && body[0] instanceof AST_Return) {
|
||||||
value = body[0].value;
|
value = body[0].value;
|
||||||
if (!value) return make_node(AST_Undefined, self);
|
if (!value) return make_node(AST_Undefined, self);
|
||||||
value.walk(new TreeWalker(function(node) {
|
var tw = new TreeWalker(function(node) {
|
||||||
if (value === self) return true;
|
if (value === self) return true;
|
||||||
if (node instanceof AST_SymbolRef && matches(node.scope.find_variable(node))
|
if (node instanceof AST_SymbolRef) {
|
||||||
|| node instanceof AST_This && matches(node)) {
|
var ref = node.scope.find_variable(node);
|
||||||
|
if (ref && ref.scope.parent_scope === fn.parent_scope) {
|
||||||
value = self;
|
value = self;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function matches(ref) {
|
|
||||||
return ref && ref.scope.parent_scope === fn.parent_scope;
|
|
||||||
}
|
}
|
||||||
}));
|
if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
|
||||||
|
value = self;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
value.walk(tw);
|
||||||
if (value !== self) value = best_of(compressor, value, self);
|
if (value !== self) value = best_of(compressor, value, self);
|
||||||
} else {
|
} else {
|
||||||
value = self;
|
value = self;
|
||||||
@@ -3531,9 +3539,12 @@ merge(Compressor.prototype, {
|
|||||||
field = "left";
|
field = "left";
|
||||||
}
|
}
|
||||||
} else if (cdr instanceof AST_Call
|
} else if (cdr instanceof AST_Call
|
||||||
|
&& !(left instanceof AST_PropAccess && cdr.expression.equivalent_to(left))
|
||||||
|| cdr instanceof AST_PropAccess
|
|| cdr instanceof AST_PropAccess
|
||||||
|| cdr instanceof AST_Unary && !unary_side_effects(cdr.operator)) {
|
|| cdr instanceof AST_Unary && !unary_side_effects(cdr.operator)) {
|
||||||
field = "expression";
|
field = "expression";
|
||||||
|
} else if (cdr instanceof AST_Conditional) {
|
||||||
|
field = "condition";
|
||||||
} else {
|
} else {
|
||||||
expressions[++i] = expressions[j];
|
expressions[++i] = expressions[j];
|
||||||
break;
|
break;
|
||||||
@@ -4041,6 +4052,10 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
OPT(AST_SymbolExport, function(self, compressor){
|
||||||
|
return self;
|
||||||
|
});
|
||||||
|
|
||||||
OPT(AST_SymbolRef, function(self, compressor){
|
OPT(AST_SymbolRef, function(self, compressor){
|
||||||
var def = self.resolve_defines(compressor);
|
var def = self.resolve_defines(compressor);
|
||||||
if (def) {
|
if (def) {
|
||||||
@@ -4064,7 +4079,7 @@ merge(Compressor.prototype, {
|
|||||||
var d = self.definition();
|
var d = self.definition();
|
||||||
var fixed = self.fixed_value();
|
var fixed = self.fixed_value();
|
||||||
if (fixed instanceof AST_Defun) {
|
if (fixed instanceof AST_Defun) {
|
||||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed).clone(true);
|
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
||||||
}
|
}
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& fixed instanceof AST_Function
|
&& fixed instanceof AST_Function
|
||||||
@@ -4072,7 +4087,7 @@ merge(Compressor.prototype, {
|
|||||||
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
||||||
&& !d.scope.uses_eval
|
&& !d.scope.uses_eval
|
||||||
&& compressor.find_parent(AST_Scope) === fixed.parent_scope) {
|
&& compressor.find_parent(AST_Scope) === fixed.parent_scope) {
|
||||||
return fixed;
|
return fixed.clone(true);
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate") && fixed) {
|
if (compressor.option("evaluate") && fixed) {
|
||||||
if (d.should_replace === undefined) {
|
if (d.should_replace === undefined) {
|
||||||
@@ -4095,7 +4110,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
var name_length = d.name.length;
|
var name_length = d.name.length;
|
||||||
var overhead = 0;
|
var overhead = 0;
|
||||||
if (compressor.option("unused") && (!d.global || compressor.toplevel(d))) {
|
if (compressor.option("unused") && !compressor.exposed(d)) {
|
||||||
overhead = (name_length + 2 + value_length) / d.references.length;
|
overhead = (name_length + 2 + value_length) / d.references.length;
|
||||||
}
|
}
|
||||||
d.should_replace = value_length <= name_length + overhead ? fn : false;
|
d.should_replace = value_length <= name_length + overhead ? fn : false;
|
||||||
@@ -4506,13 +4521,37 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Arrow, function(self, compressor){
|
OPT(AST_Arrow, function(self, compressor){
|
||||||
if (self.body.length === 1 && self.body[0] instanceof AST_Return) {
|
if (!(self.body instanceof AST_Node)) tighten_body(self.body, compressor);
|
||||||
|
if (compressor.option("arrows")
|
||||||
|
&& self.body.length == 1
|
||||||
|
&& self.body[0] instanceof AST_Return) {
|
||||||
var value = self.body[0].value;
|
var value = self.body[0].value;
|
||||||
self.body = value ? value : [];
|
self.body = value ? value : [];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
OPT(AST_Function, function(self, compressor){
|
||||||
|
tighten_body(self.body, compressor);
|
||||||
|
if (compressor.option("arrows")
|
||||||
|
&& compressor.option("ecma") >= 6
|
||||||
|
&& !self.name
|
||||||
|
&& !self.is_generator
|
||||||
|
&& !self.uses_arguments
|
||||||
|
&& !self.uses_eval) {
|
||||||
|
var has_special_symbol = false;
|
||||||
|
self.walk(new TreeWalker(function(node) {
|
||||||
|
if (has_special_symbol) return true;
|
||||||
|
if (node instanceof AST_Symbol && !node.definition()) {
|
||||||
|
has_special_symbol = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
if (!has_special_symbol) return make_node(AST_Arrow, self, self).optimize(compressor);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
});
|
||||||
|
|
||||||
OPT(AST_Class, function(self, compressor){
|
OPT(AST_Class, function(self, compressor){
|
||||||
// HACK to avoid compress failure.
|
// HACK to avoid compress failure.
|
||||||
// AST_Class is not really an AST_Scope/AST_Block as it lacks a body.
|
// AST_Class is not really an AST_Scope/AST_Block as it lacks a body.
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ function minify(files, options) {
|
|||||||
try {
|
try {
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
compress: {},
|
compress: {},
|
||||||
|
ecma: undefined,
|
||||||
ie8: false,
|
ie8: false,
|
||||||
keep_fnames: false,
|
keep_fnames: false,
|
||||||
mangle: {},
|
mangle: {},
|
||||||
@@ -46,6 +47,7 @@ function minify(files, options) {
|
|||||||
var timings = options.timings && {
|
var timings = options.timings && {
|
||||||
start: Date.now()
|
start: Date.now()
|
||||||
};
|
};
|
||||||
|
set_shorthand("ecma", options, [ "parse", "compress", "output" ]);
|
||||||
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
|
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
|
||||||
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
||||||
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
||||||
|
|||||||
@@ -533,6 +533,7 @@ function OutputStream(options) {
|
|||||||
use_asm = prev_use_asm;
|
use_asm = prev_use_asm;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("print_to_string", function(options){
|
AST_Node.DEFMETHOD("print_to_string", function(options){
|
||||||
var s = OutputStream(options);
|
var s = OutputStream(options);
|
||||||
@@ -978,12 +979,12 @@ function OutputStream(options) {
|
|||||||
AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){
|
AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){
|
||||||
var self = this;
|
var self = this;
|
||||||
if (!nokeyword) {
|
if (!nokeyword) {
|
||||||
if (this.async) {
|
if (self.async) {
|
||||||
output.print("async");
|
output.print("async");
|
||||||
output.space();
|
output.space();
|
||||||
}
|
}
|
||||||
output.print("function");
|
output.print("function");
|
||||||
if (this.is_generator) {
|
if (self.is_generator) {
|
||||||
output.star();
|
output.star();
|
||||||
}
|
}
|
||||||
if (self.name) {
|
if (self.name) {
|
||||||
@@ -1038,6 +1039,10 @@ function OutputStream(options) {
|
|||||||
var needs_parens = parent instanceof AST_Binary ||
|
var needs_parens = parent instanceof AST_Binary ||
|
||||||
parent instanceof AST_Unary ||
|
parent instanceof AST_Unary ||
|
||||||
(parent instanceof AST_Call && self === parent.expression);
|
(parent instanceof AST_Call && self === parent.expression);
|
||||||
|
if (self.async) {
|
||||||
|
output.print("async");
|
||||||
|
output.space();
|
||||||
|
}
|
||||||
if (needs_parens) { output.print("(") }
|
if (needs_parens) { output.print("(") }
|
||||||
if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) {
|
if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) {
|
||||||
self.argnames[0].print(output);
|
self.argnames[0].print(output);
|
||||||
@@ -1053,9 +1058,9 @@ function OutputStream(options) {
|
|||||||
output.print('=>');
|
output.print('=>');
|
||||||
output.space();
|
output.space();
|
||||||
if (self.body instanceof AST_Node) {
|
if (self.body instanceof AST_Node) {
|
||||||
this.body.print(output);
|
self.body.print(output);
|
||||||
} else {
|
} else {
|
||||||
print_bracketed(this.body, output);
|
print_bracketed(self.body, output);
|
||||||
}
|
}
|
||||||
if (needs_parens) { output.print(")") }
|
if (needs_parens) { output.print(")") }
|
||||||
});
|
});
|
||||||
@@ -1280,7 +1285,6 @@ function OutputStream(options) {
|
|||||||
name_import.print(output);
|
name_import.print(output);
|
||||||
if (i < self.imported_names.length - 1) {
|
if (i < self.imported_names.length - 1) {
|
||||||
output.print(",");
|
output.print(",");
|
||||||
output.space();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
@@ -1296,17 +1300,26 @@ function OutputStream(options) {
|
|||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFPRINT(AST_NameImport, function(self, output) {
|
DEFPRINT(AST_NameMapping, function(self, output) {
|
||||||
|
var is_import = output.parent() instanceof AST_Import;
|
||||||
var definition = self.name.definition();
|
var definition = self.name.definition();
|
||||||
var names_are_different =
|
var names_are_different =
|
||||||
(definition && definition.mangled_name || self.name.name) !==
|
(definition && definition.mangled_name || self.name.name) !==
|
||||||
self.foreign_name.name;
|
self.foreign_name.name;
|
||||||
if (names_are_different) {
|
if (names_are_different) {
|
||||||
|
if (is_import) {
|
||||||
output.print(self.foreign_name.name);
|
output.print(self.foreign_name.name);
|
||||||
|
} else {
|
||||||
|
self.name.print(output);
|
||||||
|
}
|
||||||
output.space();
|
output.space();
|
||||||
output.print("as");
|
output.print("as");
|
||||||
output.space();
|
output.space();
|
||||||
|
if (is_import) {
|
||||||
self.name.print(output);
|
self.name.print(output);
|
||||||
|
} else {
|
||||||
|
output.print(self.foreign_name.name);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.name.print(output);
|
self.name.print(output);
|
||||||
}
|
}
|
||||||
@@ -1320,24 +1333,20 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
}
|
}
|
||||||
if (self.exported_names) {
|
if (self.exported_names) {
|
||||||
output.space();
|
|
||||||
|
|
||||||
if (self.exported_names.length === 1 && self.exported_names[0].name.name === "*") {
|
if (self.exported_names.length === 1 && self.exported_names[0].name.name === "*") {
|
||||||
self.exported_names[0].print(output);
|
self.exported_names[0].print(output);
|
||||||
} else {
|
} else {
|
||||||
output.print("{");
|
output.print("{");
|
||||||
self.exported_names.forEach(function (name_import, i) {
|
self.exported_names.forEach(function(name_export, i) {
|
||||||
output.space();
|
output.space();
|
||||||
name_import.print(output);
|
name_export.print(output);
|
||||||
if (i < self.exported_names.length - 1) {
|
if (i < self.exported_names.length - 1) {
|
||||||
output.print(",");
|
output.print(",");
|
||||||
output.space();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
output.print("}");
|
output.print("}");
|
||||||
}
|
}
|
||||||
output.space();
|
|
||||||
}
|
}
|
||||||
else if (self.exported_value) {
|
else if (self.exported_value) {
|
||||||
self.exported_value.print(output);
|
self.exported_value.print(output);
|
||||||
|
|||||||
236
lib/parse.js
236
lib/parse.js
@@ -856,6 +856,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
bare_returns : false,
|
bare_returns : false,
|
||||||
|
ecma : 8,
|
||||||
expression : false,
|
expression : false,
|
||||||
filename : null,
|
filename : null,
|
||||||
html5_comments : true,
|
html5_comments : true,
|
||||||
@@ -1229,9 +1230,12 @@ function parse($TEXT, options) {
|
|||||||
var is_in = is("operator", "in");
|
var is_in = is("operator", "in");
|
||||||
var is_of = is("name", "of");
|
var is_of = is("name", "of");
|
||||||
if (is_in || is_of) {
|
if (is_in || is_of) {
|
||||||
if ((init instanceof AST_Definitions) &&
|
if (init instanceof AST_Definitions) {
|
||||||
init.definitions.length > 1)
|
if (init.definitions.length > 1)
|
||||||
croak("Only one variable declaration allowed in for..in loop");
|
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||||
|
} else if (!(is_assignable(init) || (init = to_destructuring(init)) instanceof AST_Destructuring)) {
|
||||||
|
croak("Invalid left-hand side in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||||
|
}
|
||||||
next();
|
next();
|
||||||
if (is_in) {
|
if (is_in) {
|
||||||
return for_in(init);
|
return for_in(init);
|
||||||
@@ -1281,18 +1285,19 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var arrow_function = function(start, argnames) {
|
var arrow_function = function(start, argnames, is_async) {
|
||||||
if (S.token.nlb) {
|
if (S.token.nlb) {
|
||||||
croak("Unexpected newline before arrow (=>)");
|
croak("Unexpected newline before arrow (=>)");
|
||||||
}
|
}
|
||||||
|
|
||||||
expect_token("arrow", "=>");
|
expect_token("arrow", "=>");
|
||||||
|
|
||||||
var body = _function_body(is("punc", "{"));
|
var body = _function_body(is("punc", "{"), false, is_async);
|
||||||
|
|
||||||
return new AST_Arrow({
|
return new AST_Arrow({
|
||||||
start : start,
|
start : start,
|
||||||
end : body.end,
|
end : body.end,
|
||||||
|
async : is_async,
|
||||||
argnames : argnames,
|
argnames : argnames,
|
||||||
body : body
|
body : body
|
||||||
});
|
});
|
||||||
@@ -1385,22 +1390,20 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function parameters() {
|
function parameters() {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var first = true;
|
|
||||||
var params = [];
|
var params = [];
|
||||||
var used_parameters = track_used_binding_identifiers(true, S.input.has_directive("use strict"));
|
var used_parameters = track_used_binding_identifiers(true, S.input.has_directive("use strict"));
|
||||||
|
|
||||||
expect("(");
|
expect("(");
|
||||||
|
|
||||||
while (!is("punc", ")")) {
|
while (!is("punc", ")")) {
|
||||||
if (first) {
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
expect(",");
|
|
||||||
}
|
|
||||||
|
|
||||||
var param = parameter(used_parameters);
|
var param = parameter(used_parameters);
|
||||||
params.push(param);
|
params.push(param);
|
||||||
|
|
||||||
|
if (!is("punc", ")")) {
|
||||||
|
expect(",");
|
||||||
|
if (is("punc", ")") && options.ecma < 8) unexpected();
|
||||||
|
}
|
||||||
|
|
||||||
if (param instanceof AST_Expansion) {
|
if (param instanceof AST_Expansion) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1616,25 +1619,40 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function params_or_seq_() {
|
function params_or_seq_(allow_arrows, maybe_sequence) {
|
||||||
var first = true;
|
var spread_token;
|
||||||
|
var invalid_sequence;
|
||||||
|
var trailing_comma;
|
||||||
var a = [];
|
var a = [];
|
||||||
|
expect("(");
|
||||||
while (!is("punc", ")")) {
|
while (!is("punc", ")")) {
|
||||||
if (first) first = false; else expect(",");
|
if (spread_token) unexpected(spread_token);
|
||||||
if (is("expand", "...")) {
|
if (is("expand", "...")) {
|
||||||
var spread_token = S.token;
|
spread_token = S.token;
|
||||||
|
if (maybe_sequence) invalid_sequence = S.token;
|
||||||
next();
|
next();
|
||||||
a.push(new AST_Expansion({
|
a.push(new AST_Expansion({
|
||||||
start: prev(),
|
start: prev(),
|
||||||
expression: expression(),
|
expression: expression(),
|
||||||
end: S.token,
|
end: S.token,
|
||||||
}));
|
}));
|
||||||
if (!is("punc", ")")) {
|
|
||||||
unexpected(spread_token);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
a.push(expression());
|
a.push(expression());
|
||||||
}
|
}
|
||||||
|
if (!is("punc", ")")) {
|
||||||
|
expect(",");
|
||||||
|
if (is("punc", ")")) {
|
||||||
|
if (options.ecma < 8) unexpected();
|
||||||
|
trailing_comma = prev();
|
||||||
|
if (maybe_sequence) invalid_sequence = trailing_comma;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(")");
|
||||||
|
if (allow_arrows && is("arrow", "=>")) {
|
||||||
|
if (spread_token && trailing_comma) unexpected(trailing_comma);
|
||||||
|
} else if (invalid_sequence) {
|
||||||
|
unexpected(invalid_sequence);
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@@ -1882,7 +1900,7 @@ function parse($TEXT, options) {
|
|||||||
var newexp = expr_atom(false), args;
|
var newexp = expr_atom(false), args;
|
||||||
if (is("punc", "(")) {
|
if (is("punc", "(")) {
|
||||||
next();
|
next();
|
||||||
args = expr_list(")");
|
args = expr_list(")", options.ecma >= 8);
|
||||||
} else {
|
} else {
|
||||||
args = [];
|
args = [];
|
||||||
}
|
}
|
||||||
@@ -1989,21 +2007,24 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var expr_atom = function(allow_calls) {
|
var expr_atom = function(allow_calls, allow_arrows) {
|
||||||
if (is("operator", "new")) {
|
if (is("operator", "new")) {
|
||||||
return new_(allow_calls);
|
return new_(allow_calls);
|
||||||
}
|
}
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
|
var async = is("name", "async") && as_atom_node();
|
||||||
if (is("punc")) {
|
if (is("punc")) {
|
||||||
switch (start.value) {
|
switch (S.token.value) {
|
||||||
case "(":
|
case "(":
|
||||||
next();
|
if (async && !allow_calls) break;
|
||||||
var exprs = params_or_seq_();
|
var exprs = params_or_seq_(allow_arrows, !async);
|
||||||
expect(")");
|
if (allow_arrows && is("arrow", "=>")) {
|
||||||
if (is("arrow", "=>")) {
|
return arrow_function(start, exprs.map(to_fun_args), !!async);
|
||||||
return arrow_function(start, exprs.map(to_fun_args));
|
|
||||||
}
|
}
|
||||||
var ex = exprs.length == 1 ? exprs[0] : new AST_Sequence({
|
var ex = async ? new AST_Call({
|
||||||
|
expression: async,
|
||||||
|
args: exprs
|
||||||
|
}) : exprs.length == 1 ? exprs[0] : new AST_Sequence({
|
||||||
expressions: exprs
|
expressions: exprs
|
||||||
});
|
});
|
||||||
ex.start = start;
|
ex.start = start;
|
||||||
@@ -2012,25 +2033,27 @@ function parse($TEXT, options) {
|
|||||||
case "[":
|
case "[":
|
||||||
return subscripts(array_(), allow_calls);
|
return subscripts(array_(), allow_calls);
|
||||||
case "{":
|
case "{":
|
||||||
return subscripts(object_or_object_destructuring_(), allow_calls);
|
return subscripts(object_or_destructuring_(), allow_calls);
|
||||||
}
|
}
|
||||||
unexpected();
|
if (!async) unexpected();
|
||||||
}
|
}
|
||||||
if (is("name", "async") && is_token(peek(), "keyword", "function")) {
|
if (allow_arrows && is("name") && is_token(peek(), "arrow")) {
|
||||||
|
var param = new AST_SymbolFunarg({
|
||||||
|
name: S.token.value,
|
||||||
|
start: start,
|
||||||
|
end: start,
|
||||||
|
});
|
||||||
next();
|
next();
|
||||||
next();
|
return arrow_function(start, [param], !!async);
|
||||||
var func = function_(AST_Function, false, true);
|
|
||||||
func.start = start;
|
|
||||||
func.end = prev();
|
|
||||||
return subscripts(func, allow_calls);
|
|
||||||
}
|
}
|
||||||
if (is("keyword", "function")) {
|
if (is("keyword", "function")) {
|
||||||
next();
|
next();
|
||||||
var func = function_(AST_Function);
|
var func = function_(AST_Function, false, !!async);
|
||||||
func.start = start;
|
func.start = start;
|
||||||
func.end = prev();
|
func.end = prev();
|
||||||
return subscripts(func, allow_calls);
|
return subscripts(func, allow_calls);
|
||||||
}
|
}
|
||||||
|
if (async) return subscripts(async, allow_calls);
|
||||||
if (is("keyword", "class")) {
|
if (is("keyword", "class")) {
|
||||||
next();
|
next();
|
||||||
var cls = class_(AST_ClassExpression);
|
var cls = class_(AST_ClassExpression);
|
||||||
@@ -2109,7 +2132,7 @@ function parse($TEXT, options) {
|
|||||||
return function_(AST_Accessor, is_generator, is_async);
|
return function_(AST_Accessor, is_generator, is_async);
|
||||||
});
|
});
|
||||||
|
|
||||||
var object_or_object_destructuring_ = embed_tokens(function() {
|
var object_or_destructuring_ = embed_tokens(function object_or_destructuring_() {
|
||||||
var start = S.token, first = true, a = [];
|
var start = S.token, first = true, a = [];
|
||||||
expect("{");
|
expect("{");
|
||||||
while (!is("punc", "}")) {
|
while (!is("punc", "}")) {
|
||||||
@@ -2231,7 +2254,7 @@ function parse($TEXT, options) {
|
|||||||
property_token = S.token;
|
property_token = S.token;
|
||||||
name = as_property_name();
|
name = as_property_name();
|
||||||
}
|
}
|
||||||
if (name === "async" && !is("punc", "(")) {
|
if (name === "async" && !is("punc", "(") && !is("punc", ",") && !is("punc", "}")) {
|
||||||
is_async = true;
|
is_async = true;
|
||||||
property_token = S.token;
|
property_token = S.token;
|
||||||
name = as_property_name();
|
name = as_property_name();
|
||||||
@@ -2302,7 +2325,7 @@ function parse($TEXT, options) {
|
|||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
imported_names = import_names(true);
|
imported_names = map_names(true);
|
||||||
|
|
||||||
if (imported_names || imported_name) {
|
if (imported_names || imported_name) {
|
||||||
expect_token("name", "from");
|
expect_token("name", "from");
|
||||||
@@ -2326,26 +2349,40 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function import_name() {
|
function map_name(is_import) {
|
||||||
|
function make_symbol(type) {
|
||||||
|
return new type({
|
||||||
|
name: as_property_name(),
|
||||||
|
start: prev(),
|
||||||
|
end: prev()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var foreign_type = is_import ? AST_SymbolImportForeign : AST_SymbolExportForeign;
|
||||||
|
var type = is_import ? AST_SymbolImport : AST_SymbolExport;
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var foreign_name;
|
var foreign_name;
|
||||||
var name;
|
var name;
|
||||||
|
|
||||||
if (peek().value === "as" && peek().type === "name") {
|
if (is_import) {
|
||||||
foreign_name = as_symbol(AST_SymbolImportForeign);
|
foreign_name = make_symbol(foreign_type);
|
||||||
|
} else {
|
||||||
|
name = make_symbol(type);
|
||||||
|
}
|
||||||
|
if (is("name", "as")) {
|
||||||
next(); // The "as" word
|
next(); // The "as" word
|
||||||
|
if (is_import) {
|
||||||
|
name = make_symbol(type);
|
||||||
|
} else {
|
||||||
|
foreign_name = make_symbol(foreign_type);
|
||||||
}
|
}
|
||||||
name = as_symbol(AST_SymbolImport);
|
} else if (is_import) {
|
||||||
|
name = new type(foreign_name);
|
||||||
if (foreign_name === undefined) {
|
} else {
|
||||||
foreign_name = new AST_SymbolImportForeign({
|
foreign_name = new foreign_type(name);
|
||||||
name: name.name,
|
|
||||||
start: name.start,
|
|
||||||
end: name.end,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AST_NameImport({
|
return new AST_NameMapping({
|
||||||
start: start,
|
start: start,
|
||||||
foreign_name: foreign_name,
|
foreign_name: foreign_name,
|
||||||
name: name,
|
name: name,
|
||||||
@@ -2353,26 +2390,26 @@ function parse($TEXT, options) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function import_nameAsterisk(name) {
|
function map_nameAsterisk(is_import, name) {
|
||||||
|
var foreign_type = is_import ? AST_SymbolImportForeign : AST_SymbolExportForeign;
|
||||||
|
var type = is_import ? AST_SymbolImport : AST_SymbolExport;
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var foreign_name;
|
var foreign_name;
|
||||||
|
|
||||||
|
|
||||||
var end = prev();
|
var end = prev();
|
||||||
|
|
||||||
name = name || new AST_SymbolImport({
|
name = name || new type({
|
||||||
name: '*',
|
name: '*',
|
||||||
start: start,
|
start: start,
|
||||||
end: end,
|
end: end,
|
||||||
});
|
});
|
||||||
|
|
||||||
foreign_name = new AST_SymbolImportForeign({
|
foreign_name = new foreign_type({
|
||||||
name: '*',
|
name: '*',
|
||||||
start: start,
|
start: start,
|
||||||
end: end,
|
end: end,
|
||||||
});
|
});
|
||||||
|
|
||||||
return new AST_NameImport({
|
return new AST_NameMapping({
|
||||||
start: start,
|
start: start,
|
||||||
foreign_name: foreign_name,
|
foreign_name: foreign_name,
|
||||||
name: name,
|
name: name,
|
||||||
@@ -2380,13 +2417,13 @@ function parse($TEXT, options) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function import_names(allow_as) {
|
function map_names(is_import) {
|
||||||
var names;
|
var names;
|
||||||
if (is("punc", "{")) {
|
if (is("punc", "{")) {
|
||||||
next();
|
next();
|
||||||
names = [];
|
names = [];
|
||||||
while (!is("punc", "}")) {
|
while (!is("punc", "}")) {
|
||||||
names.push(import_name());
|
names.push(map_name(is_import));
|
||||||
if (is("punc", ",")) {
|
if (is("punc", ",")) {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
@@ -2395,11 +2432,11 @@ function parse($TEXT, options) {
|
|||||||
} else if (is("operator", "*")) {
|
} else if (is("operator", "*")) {
|
||||||
var name;
|
var name;
|
||||||
next();
|
next();
|
||||||
if (allow_as && is("name", "as")) {
|
if (is_import && is("name", "as")) {
|
||||||
next(); // The "as" word
|
next(); // The "as" word
|
||||||
name = as_symbol(AST_SymbolImportForeign);
|
name = as_symbol(AST_SymbolImportForeign);
|
||||||
}
|
}
|
||||||
names = [import_nameAsterisk(name)];
|
names = [map_nameAsterisk(is_import, name)];
|
||||||
}
|
}
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
@@ -2407,17 +2444,12 @@ function parse($TEXT, options) {
|
|||||||
function export_() {
|
function export_() {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var is_default;
|
var is_default;
|
||||||
var exported_value;
|
|
||||||
var exported_definition;
|
|
||||||
var exported_names;
|
var exported_names;
|
||||||
|
|
||||||
if (is("keyword", "default")) {
|
if (is("keyword", "default")) {
|
||||||
is_default = true;
|
is_default = true;
|
||||||
next();
|
next();
|
||||||
} else {
|
} else if (exported_names = map_names(false)) {
|
||||||
exported_names = import_names(false);
|
|
||||||
|
|
||||||
if (exported_names) {
|
|
||||||
if (is("name", "from")) {
|
if (is("name", "from")) {
|
||||||
next();
|
next();
|
||||||
|
|
||||||
@@ -2448,31 +2480,24 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var is_definition = is("keyword", "var") || is("keyword", "let") || is("keyword", "const");
|
var node;
|
||||||
if (is_definition) {
|
var exported_value;
|
||||||
if (is_default) unexpected();
|
var exported_definition;
|
||||||
exported_definition = statement();
|
if (is("punc", "{")
|
||||||
} else if (is("keyword", "class")) {
|
|| is_default
|
||||||
var cls = expr_atom(false);
|
&& (is("keyword", "class") || is("keyword", "function"))
|
||||||
if (cls.name) {
|
&& is_token(peek(), "punc")) {
|
||||||
cls.name = new AST_SymbolDefClass(cls.name);
|
|
||||||
exported_definition = new AST_DefClass(cls);
|
|
||||||
} else {
|
|
||||||
exported_value = cls;
|
|
||||||
}
|
|
||||||
} else if (is("keyword", "function")) {
|
|
||||||
var func = expr_atom(false);
|
|
||||||
if (func.name) {
|
|
||||||
func.name = new AST_SymbolDefun(func.name);
|
|
||||||
exported_definition = new AST_Defun(func);
|
|
||||||
} else {
|
|
||||||
exported_value = func;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
exported_value = expression(false);
|
exported_value = expression(false);
|
||||||
semicolon();
|
semicolon();
|
||||||
|
} else if ((node = statement()) instanceof AST_Definitions && is_default) {
|
||||||
|
unexpected(node.start);
|
||||||
|
} else if (node instanceof AST_Definitions || node instanceof AST_Defun || node instanceof AST_DefClass) {
|
||||||
|
exported_definition = node;
|
||||||
|
} else if (node instanceof AST_SimpleStatement) {
|
||||||
|
exported_value = node.body;
|
||||||
|
} else {
|
||||||
|
unexpected(node.start);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AST_Export({
|
return new AST_Export({
|
||||||
@@ -2598,11 +2623,9 @@ function parse($TEXT, options) {
|
|||||||
return expr;
|
return expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
var call_args = embed_tokens(function call_args() {
|
var call_args = embed_tokens(function _call_args() {
|
||||||
var first = true;
|
|
||||||
var args = [];
|
var args = [];
|
||||||
while (!is("punc", ")")) {
|
while (!is("punc", ")")) {
|
||||||
if (first) first = false; else expect(",");
|
|
||||||
if (is("expand", "...")) {
|
if (is("expand", "...")) {
|
||||||
next();
|
next();
|
||||||
args.push(new AST_Expansion({
|
args.push(new AST_Expansion({
|
||||||
@@ -2612,12 +2635,16 @@ function parse($TEXT, options) {
|
|||||||
} else {
|
} else {
|
||||||
args.push(expression(false));
|
args.push(expression(false));
|
||||||
}
|
}
|
||||||
|
if (!is("punc", ")")) {
|
||||||
|
expect(",");
|
||||||
|
if (is("punc", ")") && options.ecma < 8) unexpected();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
return args;
|
return args;
|
||||||
});
|
});
|
||||||
|
|
||||||
var maybe_unary = function(allow_calls) {
|
var maybe_unary = function(allow_calls, allow_arrows) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
if (start.type == "name" && start.value == "await") {
|
if (start.type == "name" && start.value == "await") {
|
||||||
if (is_in_async()) {
|
if (is_in_async()) {
|
||||||
@@ -2635,8 +2662,9 @@ function parse($TEXT, options) {
|
|||||||
ex.end = prev();
|
ex.end = prev();
|
||||||
return ex;
|
return ex;
|
||||||
}
|
}
|
||||||
var val = expr_atom(allow_calls);
|
var val = expr_atom(allow_calls, allow_arrows);
|
||||||
while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
|
while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
|
||||||
|
if (val instanceof AST_Arrow) unexpected();
|
||||||
val = make_unary(AST_UnaryPostfix, S.token, val);
|
val = make_unary(AST_UnaryPostfix, S.token, val);
|
||||||
val.start = start;
|
val.start = start;
|
||||||
val.end = S.token;
|
val.end = S.token;
|
||||||
@@ -2684,7 +2712,7 @@ function parse($TEXT, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function expr_ops(no_in) {
|
function expr_ops(no_in) {
|
||||||
return expr_op(maybe_unary(true), 0, no_in);
|
return expr_op(maybe_unary(true, true), 0, no_in);
|
||||||
};
|
};
|
||||||
|
|
||||||
var maybe_conditional = function(no_in) {
|
var maybe_conditional = function(no_in) {
|
||||||
@@ -2765,22 +2793,6 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start.type == "punc" && start.value == "(" && peek().value == ")") {
|
|
||||||
next();
|
|
||||||
next();
|
|
||||||
return arrow_function(start, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is("name") && is_token(peek(), "arrow")) {
|
|
||||||
var param = new AST_SymbolFunarg({
|
|
||||||
name: start.value,
|
|
||||||
start: start,
|
|
||||||
end: start,
|
|
||||||
});
|
|
||||||
next();
|
|
||||||
return arrow_function(start, [param]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var left = maybe_conditional(no_in);
|
var left = maybe_conditional(no_in);
|
||||||
var val = S.token.value;
|
var val = S.token.value;
|
||||||
|
|
||||||
|
|||||||
169
lib/scope.js
169
lib/scope.js
@@ -85,7 +85,7 @@ SymbolDef.prototype = {
|
|||||||
if (options.ie8 && sym instanceof AST_SymbolLambda)
|
if (options.ie8 && sym instanceof AST_SymbolLambda)
|
||||||
s = s.parent_scope;
|
s = s.parent_scope;
|
||||||
var def;
|
var def;
|
||||||
if (this.defun && (def = this.defun.variables.get(this.name))) {
|
if (def = this.redefined()) {
|
||||||
this.mangled_name = def.mangled_name || def.name;
|
this.mangled_name = def.mangled_name || def.name;
|
||||||
} else
|
} else
|
||||||
this.mangled_name = s.next_mangled(options, this);
|
this.mangled_name = s.next_mangled(options, this);
|
||||||
@@ -93,6 +93,9 @@ SymbolDef.prototype = {
|
|||||||
cache.set(this.name, this.mangled_name);
|
cache.set(this.name, this.mangled_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
redefined: function() {
|
||||||
|
return this.defun && this.defun.variables.get(this.name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -129,7 +132,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Destructuring && node.is_array === false) {
|
if (node instanceof AST_Destructuring) {
|
||||||
in_destructuring = node; // These don't nest
|
in_destructuring = node; // These don't nest
|
||||||
descend();
|
descend();
|
||||||
in_destructuring = null;
|
in_destructuring = null;
|
||||||
@@ -223,10 +226,25 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
}));
|
}));
|
||||||
node.thedef = sym;
|
node.thedef = sym;
|
||||||
}
|
}
|
||||||
|
if (!(scope instanceof AST_Toplevel) && (node instanceof AST_Export || node instanceof AST_Import)) {
|
||||||
|
js_error(
|
||||||
|
node.TYPE + " statement may only appear at top level",
|
||||||
|
node.start.file,
|
||||||
|
node.start.line,
|
||||||
|
node.start.col,
|
||||||
|
node.start.pos
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function mark_export(def, level) {
|
function mark_export(def, level) {
|
||||||
|
if (in_destructuring) {
|
||||||
|
var i = 0;
|
||||||
|
do {
|
||||||
|
level++;
|
||||||
|
} while (tw.parent(i++) !== in_destructuring);
|
||||||
|
}
|
||||||
var node = tw.parent(level);
|
var node = tw.parent(level);
|
||||||
def.export = node instanceof AST_Export && !node.is_default;
|
def.export = node instanceof AST_Export;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
@@ -245,8 +263,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
s.uses_eval = true;
|
s.uses_eval = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var sym = node.scope.find_variable(name);
|
var sym;
|
||||||
if (!sym) {
|
if (tw.parent() instanceof AST_NameMapping && tw.parent(1).module_name
|
||||||
|
|| !(sym = node.scope.find_variable(name))) {
|
||||||
sym = self.def_global(node);
|
sym = self.def_global(node);
|
||||||
} else if (sym.scope instanceof AST_Lambda && name == "arguments") {
|
} else if (sym.scope instanceof AST_Lambda && name == "arguments") {
|
||||||
sym.scope.uses_arguments = true;
|
sym.scope.uses_arguments = true;
|
||||||
@@ -255,6 +274,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
node.reference(options);
|
node.reference(options);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// ensure mangling works if catch reuses a scope variable
|
||||||
|
var def;
|
||||||
|
if (node instanceof AST_SymbolCatch && (def = node.definition().redefined())) {
|
||||||
|
var s = node.scope;
|
||||||
|
while (s) {
|
||||||
|
push_uniq(s.enclosed, def);
|
||||||
|
if (s === def.scope) break;
|
||||||
|
s = s.parent_scope;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
|
|
||||||
@@ -421,7 +450,7 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
|||||||
|
|
||||||
AST_Symbol.DEFMETHOD("unmangleable", function(options){
|
AST_Symbol.DEFMETHOD("unmangleable", function(options){
|
||||||
var def = this.definition();
|
var def = this.definition();
|
||||||
return def && def.unmangleable(options);
|
return !def || def.unmangleable(options);
|
||||||
});
|
});
|
||||||
|
|
||||||
// labels are always mangleable
|
// labels are always mangleable
|
||||||
@@ -526,113 +555,69 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
||||||
options = this._default_mangler_options(options);
|
options = this._default_mangler_options(options);
|
||||||
var tw = new TreeWalker(function(node){
|
try {
|
||||||
if (node instanceof AST_Constant)
|
AST_Node.prototype.print = function(stream, force_parens) {
|
||||||
base54.consider(node.print_to_string());
|
this._print(stream, force_parens);
|
||||||
else if (node instanceof AST_Return)
|
if (this instanceof AST_Symbol && !this.unmangleable(options)) {
|
||||||
base54.consider("return");
|
base54.consider(this.name, -1);
|
||||||
else if (node instanceof AST_Throw)
|
} else if (options.properties) {
|
||||||
base54.consider("throw");
|
if (this instanceof AST_Dot) {
|
||||||
else if (node instanceof AST_Continue)
|
base54.consider(this.property, -1);
|
||||||
base54.consider("continue");
|
} else if (this instanceof AST_Sub) {
|
||||||
else if (node instanceof AST_Break)
|
skip_string(this.property);
|
||||||
base54.consider("break");
|
}
|
||||||
else if (node instanceof AST_Debugger)
|
}
|
||||||
base54.consider("debugger");
|
};
|
||||||
else if (node instanceof AST_Directive)
|
base54.consider(this.print_to_string(), 1);
|
||||||
base54.consider(node.value);
|
} finally {
|
||||||
else if (node instanceof AST_While)
|
AST_Node.prototype.print = AST_Node.prototype._print;
|
||||||
base54.consider("while");
|
|
||||||
else if (node instanceof AST_Do)
|
|
||||||
base54.consider("do while");
|
|
||||||
else if (node instanceof AST_If) {
|
|
||||||
base54.consider("if");
|
|
||||||
if (node.alternative) base54.consider("else");
|
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_Var)
|
|
||||||
base54.consider("var");
|
|
||||||
else if (node instanceof AST_Const)
|
|
||||||
base54.consider("const");
|
|
||||||
else if (node instanceof AST_Lambda)
|
|
||||||
base54.consider("function");
|
|
||||||
else if (node instanceof AST_For)
|
|
||||||
base54.consider("for");
|
|
||||||
else if (node instanceof AST_ForIn)
|
|
||||||
base54.consider("for in");
|
|
||||||
else if (node instanceof AST_Switch)
|
|
||||||
base54.consider("switch");
|
|
||||||
else if (node instanceof AST_Case)
|
|
||||||
base54.consider("case");
|
|
||||||
else if (node instanceof AST_Default)
|
|
||||||
base54.consider("default");
|
|
||||||
else if (node instanceof AST_With)
|
|
||||||
base54.consider("with");
|
|
||||||
else if (node instanceof AST_ObjectSetter)
|
|
||||||
base54.consider("set" + (typeof node.key === "string" ? 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(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_Await)
|
|
||||||
base54.consider("await");
|
|
||||||
else if (node instanceof AST_Symbol && node.unmangleable(options))
|
|
||||||
base54.consider(node.name);
|
|
||||||
else if (node instanceof AST_Unary || node instanceof AST_Binary)
|
|
||||||
base54.consider(node.operator);
|
|
||||||
else if (node instanceof AST_Dot)
|
|
||||||
base54.consider(node.property);
|
|
||||||
});
|
|
||||||
this.walk(tw);
|
|
||||||
base54.sort();
|
base54.sort();
|
||||||
|
|
||||||
|
function skip_string(node) {
|
||||||
|
if (node instanceof AST_String) {
|
||||||
|
base54.consider(node.value, -1);
|
||||||
|
} else if (node instanceof AST_Conditional) {
|
||||||
|
skip_string(node.consequent);
|
||||||
|
skip_string(node.alternative);
|
||||||
|
} else if (node instanceof AST_Sequence) {
|
||||||
|
skip_string(node.expressions[node.expressions.length - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var base54 = (function() {
|
var base54 = (function() {
|
||||||
var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
|
var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split("");
|
||||||
|
var digits = "0123456789".split("");
|
||||||
var chars, frequency;
|
var chars, frequency;
|
||||||
function reset() {
|
function reset() {
|
||||||
frequency = Object.create(null);
|
frequency = Object.create(null);
|
||||||
chars = string.split("").map(function(ch){ return ch.charCodeAt(0) });
|
leading.forEach(function(ch) {
|
||||||
chars.forEach(function(ch){ frequency[ch] = 0 });
|
frequency[ch] = 0;
|
||||||
|
});
|
||||||
|
digits.forEach(function(ch) {
|
||||||
|
frequency[ch] = 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
base54.consider = function(str){
|
base54.consider = function(str, delta) {
|
||||||
for (var i = str.length; --i >= 0;) {
|
for (var i = str.length; --i >= 0;) {
|
||||||
var code = str.charCodeAt(i);
|
frequency[str[i]] += delta;
|
||||||
if (code in frequency) ++frequency[code];
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
base54.sort = function() {
|
function compare(a, b) {
|
||||||
chars = mergeSort(chars, function(a, b){
|
|
||||||
if (is_digit(a) && !is_digit(b)) return 1;
|
|
||||||
if (is_digit(b) && !is_digit(a)) return -1;
|
|
||||||
return frequency[b] - frequency[a];
|
return frequency[b] - frequency[a];
|
||||||
});
|
}
|
||||||
|
base54.sort = function() {
|
||||||
|
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
|
||||||
};
|
};
|
||||||
base54.reset = reset;
|
base54.reset = reset;
|
||||||
reset();
|
reset();
|
||||||
base54.get = function(){ return chars };
|
|
||||||
base54.freq = function(){ return frequency };
|
|
||||||
function base54(num) {
|
function base54(num) {
|
||||||
var ret = "", base = 54;
|
var ret = "", base = 54;
|
||||||
num++;
|
num++;
|
||||||
do {
|
do {
|
||||||
num--;
|
num--;
|
||||||
ret += String.fromCharCode(chars[num % base]);
|
ret += chars[num % base];
|
||||||
num = Math.floor(num / base);
|
num = Math.floor(num / base);
|
||||||
base = 64;
|
base = 64;
|
||||||
} while (num > 0);
|
} while (num > 0);
|
||||||
|
|||||||
@@ -243,9 +243,22 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
self.expression = self.expression.transform(tw);
|
self.expression = self.expression.transform(tw);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_(AST_NameMapping, function(self, tw) {
|
||||||
|
self.foreign_name = self.foreign_name.transform(tw);
|
||||||
|
self.name = self.name.transform(tw);
|
||||||
|
});
|
||||||
|
|
||||||
|
_(AST_Import, function(self, tw) {
|
||||||
|
if (self.imported_name) self.imported_name = self.imported_name.transform(tw);
|
||||||
|
if (self.imported_names) do_list(self.imported_names, tw);
|
||||||
|
self.module_name = self.module_name.transform(tw);
|
||||||
|
});
|
||||||
|
|
||||||
_(AST_Export, function(self, tw) {
|
_(AST_Export, function(self, tw) {
|
||||||
if (self.exported_definition) self.exported_definition = self.exported_definition.transform(tw);
|
if (self.exported_definition) self.exported_definition = self.exported_definition.transform(tw);
|
||||||
if (self.exported_value) self.exported_value = self.exported_value.transform(tw);
|
if (self.exported_value) self.exported_value = self.exported_value.transform(tw);
|
||||||
|
if (self.exported_names) do_list(self.exported_names, tw);
|
||||||
|
if (self.module_name) self.module_name = self.module_name.transform(tw);
|
||||||
});
|
});
|
||||||
|
|
||||||
_(AST_TemplateString, function(self, tw) {
|
_(AST_TemplateString, function(self, tw) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
|
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.0.17",
|
"version": "3.0.20",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -202,3 +202,81 @@ arrow_unused_toplevel: {
|
|||||||
expect_stdout: [ "0", "1", "2", "9" ]
|
expect_stdout: [ "0", "1", "2", "9" ]
|
||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
no_leading_parentheses: {
|
||||||
|
input: {
|
||||||
|
(x,y) => x(y);
|
||||||
|
async (x,y) => await x(y);
|
||||||
|
}
|
||||||
|
expect_exact: "(x,y)=>x(y);async(x,y)=>await x(y);"
|
||||||
|
}
|
||||||
|
|
||||||
|
async_identifiers: {
|
||||||
|
options = {
|
||||||
|
arrows: true,
|
||||||
|
ecma: 6,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var async = function(x){ console.log("async", x); };
|
||||||
|
var await = function(x){ console.log("await", x); };
|
||||||
|
async(1);
|
||||||
|
await(2);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var async = x => { console.log("async", x); };
|
||||||
|
var await = x => { console.log("await", x); };
|
||||||
|
async(1);
|
||||||
|
await(2);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"async 1",
|
||||||
|
"await 2",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
async_function_expression: {
|
||||||
|
options = {
|
||||||
|
arrows: true,
|
||||||
|
ecma: 6,
|
||||||
|
evaluate: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var named = async function foo() {
|
||||||
|
await bar(1 + 0) + (2 + 0);
|
||||||
|
}
|
||||||
|
var anon = async function() {
|
||||||
|
await (1 + 0) + bar(2 + 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var named = async function foo() {
|
||||||
|
await bar(1);
|
||||||
|
};
|
||||||
|
var anon = async () => {
|
||||||
|
await 1, bar(2);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_27: {
|
||||||
|
options = {
|
||||||
|
arrows: true,
|
||||||
|
collapse_vars: true,
|
||||||
|
ecma: 6,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(jQuery) {
|
||||||
|
var $;
|
||||||
|
$ = jQuery;
|
||||||
|
$("body").addClass("foo");
|
||||||
|
})(jQuery);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(jQuery => {
|
||||||
|
jQuery("body").addClass("foo");
|
||||||
|
})(jQuery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -167,14 +167,14 @@ async_inline: {
|
|||||||
|
|
||||||
async_identifiers: {
|
async_identifiers: {
|
||||||
input: {
|
input: {
|
||||||
let async = function(x){ console.log("async", x); };
|
var async = function(x){ console.log("async", x); };
|
||||||
let await = function(x){ console.log("await", x); };
|
var await = function(x){ console.log("await", x); };
|
||||||
async(1);
|
async(1);
|
||||||
await(2);
|
await(2);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
let async = function(x){ console.log("async", x); };
|
var async = function(x){ console.log("async", x); };
|
||||||
let await = function(x){ console.log("await", x); };
|
var await = function(x){ console.log("await", x); };
|
||||||
async(1);
|
async(1);
|
||||||
await(2);
|
await(2);
|
||||||
}
|
}
|
||||||
@@ -182,19 +182,73 @@ async_identifiers: {
|
|||||||
"async 1",
|
"async 1",
|
||||||
"await 2",
|
"await 2",
|
||||||
]
|
]
|
||||||
node_version: ">=8"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: add test when supported by parser
|
async_shorthand_property: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function print(o) { console.log(o.async + " " + o.await); }
|
||||||
|
var async = "Async", await = "Await";
|
||||||
|
|
||||||
|
print({ async });
|
||||||
|
print({ await });
|
||||||
|
print({ async, await });
|
||||||
|
print({ await, async });
|
||||||
|
|
||||||
|
print({ async: async });
|
||||||
|
print({ await: await });
|
||||||
|
print({ async: async, await: await });
|
||||||
|
print({ await: await, async: async });
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function a(a) { console.log(a.async + " " + a.await); }
|
||||||
|
var n = "Async", c = "Await";
|
||||||
|
|
||||||
|
a({ async: n });
|
||||||
|
a({ await: c });
|
||||||
|
a({ async: n, await: c });
|
||||||
|
a({ await: c, async: n });
|
||||||
|
|
||||||
|
a({ async: n });
|
||||||
|
a({ await: c });
|
||||||
|
a({ async: n, await: c });
|
||||||
|
a({ await: c, async: n });
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"Async undefined",
|
||||||
|
"undefined Await",
|
||||||
|
"Async Await",
|
||||||
|
"Async Await",
|
||||||
|
"Async undefined",
|
||||||
|
"undefined Await",
|
||||||
|
"Async Await",
|
||||||
|
"Async Await",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
async_arrow: {
|
async_arrow: {
|
||||||
input: {
|
input: {
|
||||||
let a1 = async x => await foo(x);
|
let a1 = async x => await foo(x);
|
||||||
let a2 = async () => await bar();
|
let a2 = async () => await bar();
|
||||||
let a3 = async (x) => await baz(x);
|
let a3 = async (x) => await baz(x);
|
||||||
let a4 = async (x, y) => { await far(x, y); }
|
let a4 = async (x, y) => { await far(x, y); }
|
||||||
let a5 = async ({x = [1], y: z = 2}) => { await wow(x, y); }
|
let a5 = async ({x = [1], y: z = 2}) => { await wow(x, z); }
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
let a1 = async x => await foo(x);
|
||||||
|
let a2 = async () => await bar();
|
||||||
|
let a3 = async (x) => await baz(x);
|
||||||
|
let a4 = async (x, y) => { await far(x, y); }
|
||||||
|
let a5 = async ({x = [1], y: z = 2}) => { await wow(x, z); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
async_arrow_wait: {
|
||||||
|
input: {
|
||||||
|
var a = async (x, y) => await x(y);
|
||||||
|
}
|
||||||
|
expect_exact: "var a=async(x,y)=>await x(y);"
|
||||||
|
}
|
||||||
|
|||||||
@@ -106,32 +106,34 @@ regression_block_scope_resolves: {
|
|||||||
(function () {
|
(function () {
|
||||||
if (1) {
|
if (1) {
|
||||||
let x;
|
let x;
|
||||||
const y;
|
const y = 1;
|
||||||
class Zee {};
|
class Zee {};
|
||||||
}
|
}
|
||||||
if (1) {
|
if (1) {
|
||||||
let ex;
|
let ex;
|
||||||
const why;
|
const why = 2;
|
||||||
class Zi {};
|
class Zi {};
|
||||||
}
|
}
|
||||||
console.log(x, y, Zee, ex, why, Zi);
|
console.log(typeof x, typeof y, typeof Zee, typeof ex, typeof why, typeof Zi);
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function () {
|
(function () {
|
||||||
if (1) {
|
if (1) {
|
||||||
let o;
|
let e;
|
||||||
const n;
|
const o = 1;
|
||||||
class c {};
|
class t {};
|
||||||
}
|
}
|
||||||
if (1) {
|
if (1) {
|
||||||
let o;
|
let e;
|
||||||
const n;
|
const o = 2;
|
||||||
class c {};
|
class t {};
|
||||||
}
|
}
|
||||||
console.log(x, y, Zee, ex, why, Zi);
|
console.log(typeof x, typeof y, typeof Zee, typeof ex, typeof why, typeof Zi);
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
|
expect_stdout: "undefined undefined undefined undefined undefined undefined"
|
||||||
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
switch_block_scope_mangler: {
|
switch_block_scope_mangler: {
|
||||||
@@ -153,25 +155,37 @@ switch_block_scope_mangler: {
|
|||||||
console.log(cat);
|
console.log(cat);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
fn(1);
|
||||||
|
fn(2);
|
||||||
|
fn(3);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var fn = function(o) {
|
var fn = function(e) {
|
||||||
switch (o) {
|
switch (e) {
|
||||||
case 1:
|
case 1:
|
||||||
let e = o + 1
|
let l = e + 1
|
||||||
let c = o + 4;
|
let o = e + 4;
|
||||||
console.log(e, c);
|
console.log(l, o);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
let l = o + 2;
|
let n = e + 2;
|
||||||
console.log(l);
|
console.log(n);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
let a = o + 3;
|
let c = e + 3;
|
||||||
console.log(a);
|
console.log(c);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
fn(1);
|
||||||
|
fn(2);
|
||||||
|
fn(3);
|
||||||
}
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"2 5",
|
||||||
|
"4",
|
||||||
|
"6",
|
||||||
|
]
|
||||||
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -425,8 +425,8 @@ mangle_destructuring_decl: {
|
|||||||
expect: {
|
expect: {
|
||||||
function test(t) {
|
function test(t) {
|
||||||
let e = t.a || { e: 7, n: 8 };
|
let e = t.a || { e: 7, n: 8 };
|
||||||
let {t: n, e: o, n: s, s: a = 9, o: c, r: l} = e;
|
let {t: n, e: o, n: s, s: l = 9, o: a, r: c} = e;
|
||||||
console.log(n, o, s, a, c, l);
|
console.log(n, o, s, l, a, c);
|
||||||
}
|
}
|
||||||
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
||||||
test({});
|
test({});
|
||||||
@@ -462,15 +462,15 @@ mangle_destructuring_assign_toplevel_true: {
|
|||||||
test({});
|
test({});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function n(n) {
|
function e(e) {
|
||||||
let t, a, c;
|
let l, s, a;
|
||||||
let l = n.a || { e: 7, n: 8 };
|
let c = e.a || { e: 7, n: 8 };
|
||||||
({t: o, e, n: s, s: t = 9, o: a, r: c} = l);
|
({t: n, e: o, n: t, s: l = 9, o: s, r: a} = c);
|
||||||
console.log(o, e, s, t, a, c);
|
console.log(n, o, t, l, s, a);
|
||||||
}
|
}
|
||||||
let o, e, s;
|
let n, o, t;
|
||||||
n({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
e({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
||||||
n({});
|
e({});
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
"1 2 3 4 5 6",
|
"1 2 3 4 5 6",
|
||||||
@@ -504,10 +504,10 @@ mangle_destructuring_assign_toplevel_false: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function test(o) {
|
function test(o) {
|
||||||
let s, a, c;
|
let s, l, a;
|
||||||
let l = o.a || { e: 7, n: 8 };
|
let c = o.a || { e: 7, n: 8 };
|
||||||
({t, e, n, s = 9, o: a, r: c} = l);
|
({t, e, n, s = 9, o: l, r: a} = c);
|
||||||
console.log(t, e, n, s, a, c);
|
console.log(t, e, n, s, l, a);
|
||||||
}
|
}
|
||||||
let t, e, n;
|
let t, e, n;
|
||||||
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
||||||
@@ -588,8 +588,8 @@ arrow_func_with_destructuring_args: {
|
|||||||
})({bar: 5 - 0}, [, 6]);
|
})({bar: 5 - 0}, [, 6]);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(({foo: o = 1, bar: n = 2}, [a = 3, b = 4]) => {
|
(({foo: o = 1, bar: a = 2}, [b = 3, l = 4]) => {
|
||||||
console.log(o, n, a, b);
|
console.log(o, a, b, l);
|
||||||
})({bar: 5}, [, 6]);
|
})({bar: 5}, [, 6]);
|
||||||
}
|
}
|
||||||
expect_stdout: "1 5 3 6"
|
expect_stdout: "1 5 3 6"
|
||||||
@@ -639,3 +639,23 @@ issue_2044_ecma_6_beautify: {
|
|||||||
}
|
}
|
||||||
expect_exact: "({x: a = 1, y = 2 + b, z = 3 - c} = obj);"
|
expect_exact: "({x: a = 1, y = 2 + b, z = 3 - c} = obj);"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2140: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function() {
|
||||||
|
var t = {};
|
||||||
|
console.log(([t.a] = [42])[0]);
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function() {
|
||||||
|
var t = {};
|
||||||
|
console.log(([t.a] = [42])[0]);
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1294,3 +1294,118 @@ issue_2063: {
|
|||||||
var a;
|
var a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2105: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function(factory) {
|
||||||
|
factory();
|
||||||
|
}( function() {
|
||||||
|
return function(fn) {
|
||||||
|
fn()().prop();
|
||||||
|
}( function() {
|
||||||
|
function bar() {
|
||||||
|
var quux = function() {
|
||||||
|
console.log("PASS");
|
||||||
|
}, foo = function() {
|
||||||
|
console.log;
|
||||||
|
quux();
|
||||||
|
};
|
||||||
|
return { prop: foo };
|
||||||
|
}
|
||||||
|
return bar;
|
||||||
|
} );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!void function() {
|
||||||
|
var quux = function() {
|
||||||
|
console.log("PASS");
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
prop: function() {
|
||||||
|
console.log;
|
||||||
|
quux();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}().prop();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2136_1: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function(a, ...b) {
|
||||||
|
console.log(b);
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function(a, ...b) {
|
||||||
|
console.log(b);
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "[]"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2136_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x) {
|
||||||
|
console.log(x);
|
||||||
|
}
|
||||||
|
!function(a, ...b) {
|
||||||
|
f(b[0]);
|
||||||
|
}(1, 2, 3);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x) {
|
||||||
|
console.log(x);
|
||||||
|
}
|
||||||
|
f([2,3][0]);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2136_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 3,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x) {
|
||||||
|
console.log(x);
|
||||||
|
}
|
||||||
|
!function(a, ...b) {
|
||||||
|
f(b[0]);
|
||||||
|
}(1, 2, 3);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|||||||
228
test/compress/export.js
Normal file
228
test/compress/export.js
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
issue_2038_1: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
export var V = 1;
|
||||||
|
export let L = 2;
|
||||||
|
export const C = 3;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
export var V = 1;
|
||||||
|
export let L = 2;
|
||||||
|
export const C = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2038_2: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
let LET = 1;
|
||||||
|
const CONST = 2;
|
||||||
|
var VAR = 3;
|
||||||
|
export { LET, CONST, VAR };
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
let t = 1;
|
||||||
|
const e = 2;
|
||||||
|
var o = 3;
|
||||||
|
export { t as LET, e as CONST, o as VAR };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2126: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
import { foo as bar, cat as dog } from "stuff";
|
||||||
|
console.log(bar, dog);
|
||||||
|
export { bar as qux };
|
||||||
|
export { dog };
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
import { foo as o, cat as s } from "stuff";
|
||||||
|
console.log(o, s);
|
||||||
|
export { o as qux };
|
||||||
|
export { s as dog };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
beautify: {
|
||||||
|
beautify = {
|
||||||
|
beautify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
export { A as B, C as D };
|
||||||
|
}
|
||||||
|
expect_exact: "export { A as B, C as D };"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2131: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function no() {
|
||||||
|
console.log(42);
|
||||||
|
}
|
||||||
|
function go() {
|
||||||
|
console.log(42);
|
||||||
|
}
|
||||||
|
var X = 1, Y = 2;
|
||||||
|
export function main() {
|
||||||
|
go(X);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function go() {
|
||||||
|
console.log(42);
|
||||||
|
}
|
||||||
|
var X = 1;
|
||||||
|
export function main() {
|
||||||
|
go(X);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2129: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
export const { keys } = Object;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
export const { keys } = Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async_func: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: false,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
export async function Foo(x){};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
export async function Foo(){};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2134_1: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: false,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
export function Foo(x){};
|
||||||
|
Foo.prototype = {};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
export function Foo(){};
|
||||||
|
Foo.prototype = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2134_2: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: false,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
export async function Foo(x){};
|
||||||
|
Foo.prototype = {};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
export async function Foo(){};
|
||||||
|
Foo.prototype = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
redirection: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
let foo = 1, bar = 2;
|
||||||
|
export { foo as delete };
|
||||||
|
export { bar as default };
|
||||||
|
export { foo as var } from "module.js";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
let e = 1, o = 2;
|
||||||
|
export { e as delete };
|
||||||
|
export { o as default };
|
||||||
|
export { foo as var } from "module.js";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword_invalid_1: {
|
||||||
|
input: {
|
||||||
|
export { default };
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
export { default };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword_invalid_2: {
|
||||||
|
input: {
|
||||||
|
export { default as Alias };
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
export { default as Alias };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword_invalid_3: {
|
||||||
|
input: {
|
||||||
|
export { default as default };
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
export { default as default };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword_valid_1: {
|
||||||
|
input: {
|
||||||
|
export { default } from "module.js";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
export { default } from "module.js";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword_valid_2: {
|
||||||
|
input: {
|
||||||
|
export { default as Alias } from "module.js";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
export { default as Alias } from "module.js";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword_valid_3: {
|
||||||
|
input: {
|
||||||
|
export { default as default } from "module.js";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
export { default as default } from "module.js";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -265,7 +265,7 @@ issue_203: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var m = {};
|
var m = {};
|
||||||
var fn = Function("a", "b", "b.exports=42");
|
var fn = Function("n", "o", "o.exports=42");
|
||||||
fn(null, m, m.exports);
|
fn(null, m, m.exports);
|
||||||
console.log(m.exports);
|
console.log(m.exports);
|
||||||
}
|
}
|
||||||
@@ -414,3 +414,99 @@ inner_ref: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1 undefined"
|
expect_stdout: "1 undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2107: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = 0;
|
||||||
|
!function() {
|
||||||
|
c++;
|
||||||
|
}(c++ + new function() {
|
||||||
|
this.a = 0;
|
||||||
|
var a = (c = c + 1) + (c = 1 + c);
|
||||||
|
return c++ + a;
|
||||||
|
}());
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = 0;
|
||||||
|
c++, new function() {
|
||||||
|
this.a = 0, c = 1 + (c += 1), c++;
|
||||||
|
}(), c++, console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "5"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2114_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
if_return: true,
|
||||||
|
inline: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = 0;
|
||||||
|
!function(a) {
|
||||||
|
a = 0;
|
||||||
|
}([ {
|
||||||
|
0: c = c + 1,
|
||||||
|
length: c = 1 + c
|
||||||
|
}, typeof void function a() {
|
||||||
|
var b = function f1(a) {
|
||||||
|
}(b && (b.b += (c = c + 1, 0)));
|
||||||
|
}() ]);
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = 0;
|
||||||
|
!function() {
|
||||||
|
0;
|
||||||
|
}((c += 1, c = 1 + c, function() {
|
||||||
|
var b = void (b && (b.b += (c += 1, 0)));
|
||||||
|
}()));
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2114_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
if_return: true,
|
||||||
|
inline: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
passes: 2,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = 0;
|
||||||
|
!function(a) {
|
||||||
|
a = 0;
|
||||||
|
}([ {
|
||||||
|
0: c = c + 1,
|
||||||
|
length: c = 1 + c
|
||||||
|
}, typeof void function a() {
|
||||||
|
var b = function f1(a) {
|
||||||
|
}(b && (b.b += (c = c + 1, 0)));
|
||||||
|
}() ]);
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = 0;
|
||||||
|
c = 1 + (c += 1), function() {
|
||||||
|
var b = void (b && (b.b += (c += 1, 0)));
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,9 +16,12 @@ typeof_arrow_functions: {
|
|||||||
evaluate: true
|
evaluate: true
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var foo = typeof (x) => null;
|
var foo = typeof (x => null);
|
||||||
|
console.log(foo);
|
||||||
}
|
}
|
||||||
expect_exact: "var foo=\"function\";"
|
expect_exact: "var foo=\"function\";console.log(foo);"
|
||||||
|
expect_stdout: "function"
|
||||||
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
classes: {
|
classes: {
|
||||||
@@ -60,15 +63,15 @@ class_name_can_be_mangled: {
|
|||||||
function x() {
|
function x() {
|
||||||
class Foo {
|
class Foo {
|
||||||
}
|
}
|
||||||
var class1 = Foo
|
var class1 = Foo;
|
||||||
var class2 = class Bar {}
|
var class2 = class Bar {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function x() {
|
function x() {
|
||||||
class a { }
|
class a { }
|
||||||
var n = a
|
var s = a;
|
||||||
var r = class a {}
|
var c = class a {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,12 +290,12 @@ import_statement_mangling: {
|
|||||||
Whatever();
|
Whatever();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
import l from "foo";
|
import o from "foo";
|
||||||
import e, {Food as o} from "lel";
|
import m, {Food as r} from "lel";
|
||||||
import {What as f} from "lel";
|
import {What as f} from "lel";
|
||||||
l();
|
|
||||||
e();
|
|
||||||
o();
|
o();
|
||||||
|
m();
|
||||||
|
r();
|
||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -466,10 +469,10 @@ issue_1898: {
|
|||||||
expect: {
|
expect: {
|
||||||
class Foo {
|
class Foo {
|
||||||
bar() {
|
bar() {
|
||||||
for (const n of [ 6, 5 ])
|
for (const f of [ 6, 5 ])
|
||||||
for (let r of [ 4, 3 ])
|
for (let r of [ 4, 3 ])
|
||||||
for (var o of [ 2, 1 ])
|
for (var o of [ 2, 1 ])
|
||||||
console.log(n, r, o);
|
console.log(f, r, o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new Foo().bar();
|
new Foo().bar();
|
||||||
@@ -494,9 +497,9 @@ issue_1753: {
|
|||||||
expect: {
|
expect: {
|
||||||
class SomeClass {
|
class SomeClass {
|
||||||
constructor(r) {
|
constructor(r) {
|
||||||
let a = [];
|
let s = [];
|
||||||
for (let s = 0; s < 6; s++)
|
for (let a = 0; a < 6; a++)
|
||||||
a.push({
|
s.push({
|
||||||
mainDrawNumbers: [],
|
mainDrawNumbers: [],
|
||||||
extraDrawNumbers: []
|
extraDrawNumbers: []
|
||||||
});
|
});
|
||||||
@@ -523,9 +526,9 @@ issue_1753_disable: {
|
|||||||
expect: {
|
expect: {
|
||||||
class SomeClass {
|
class SomeClass {
|
||||||
constructor(r) {
|
constructor(r) {
|
||||||
let a = [];
|
let s = [];
|
||||||
for (let r = 0; r < 6; r++)
|
for (let r = 0; r < 6; r++)
|
||||||
a.push({
|
s.push({
|
||||||
mainDrawNumbers: [],
|
mainDrawNumbers: [],
|
||||||
extraDrawNumbers: []
|
extraDrawNumbers: []
|
||||||
});
|
});
|
||||||
@@ -664,3 +667,31 @@ class_expression_statement_unused_toplevel: {
|
|||||||
}
|
}
|
||||||
expect_exact: ""
|
expect_exact: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export_default_function_decl: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
passes: 3,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
// do not drop "unused" exports
|
||||||
|
export default function Foo() {};
|
||||||
|
export function Far() {};
|
||||||
|
}
|
||||||
|
expect_exact: "export default function Foo(){};export function Far(){};"
|
||||||
|
}
|
||||||
|
|
||||||
|
export_default_class_decl: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
passes: 3,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
// do not drop "unused" exports
|
||||||
|
export default class Car {};
|
||||||
|
export class Cab {};
|
||||||
|
}
|
||||||
|
expect_exact: "export default class Car{};export class Cab{};"
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ issue_1321_no_debug: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.b = 1;
|
x.o = 1;
|
||||||
x["a"] = 2 * x.b;
|
x["a"] = 2 * x.o;
|
||||||
console.log(x.b, x["a"]);
|
console.log(x.o, x["a"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -30,9 +30,9 @@ issue_1321_debug: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.a = 1;
|
x.o = 1;
|
||||||
x["_$foo$_"] = 2 * x.a;
|
x["_$foo$_"] = 2 * x.o;
|
||||||
console.log(x.a, x["_$foo$_"]);
|
console.log(x.o, x["_$foo$_"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -49,9 +49,9 @@ issue_1321_with_quoted: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.a = 1;
|
x.o = 1;
|
||||||
x["b"] = 2 * x.a;
|
x["x"] = 2 * x.o;
|
||||||
console.log(x.a, x["b"]);
|
console.log(x.o, x["x"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ same_variable_in_multiple_for_loop: {
|
|||||||
console.log(o, l);
|
console.log(o, l);
|
||||||
for (let o = 0; o < 2; o++) {
|
for (let o = 0; o < 2; o++) {
|
||||||
console.log(o, l);
|
console.log(o, l);
|
||||||
let c = 2;
|
let e = 2;
|
||||||
console.log(c);
|
console.log(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,12 +114,12 @@ same_variable_in_multiple_forIn: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var test = [ "a", "b", "c" ];
|
var test = [ "a", "b", "c" ];
|
||||||
for (let o in test) {
|
for (let e in test) {
|
||||||
console.log(o);
|
console.log(e);
|
||||||
let e;
|
let t;
|
||||||
e = [ "e", "f", "g" ];
|
t = [ "e", "f", "g" ];
|
||||||
for (let o in test)
|
for (let e in test)
|
||||||
console.log(o);
|
console.log(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
@@ -160,8 +160,8 @@ different_variable_in_multiple_for_loop: {
|
|||||||
console.log(o, l);
|
console.log(o, l);
|
||||||
for (let o = 0; o < 2; o++) {
|
for (let o = 0; o < 2; o++) {
|
||||||
console.log(o, l);
|
console.log(o, l);
|
||||||
let c = 2;
|
let e = 2;
|
||||||
console.log(c);
|
console.log(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,12 +241,12 @@ different_variable_in_multiple_forIn: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var test = [ "a", "b", "c" ];
|
var test = [ "a", "b", "c" ];
|
||||||
for (let o in test) {
|
for (let e in test) {
|
||||||
console.log(o);
|
console.log(e);
|
||||||
let e;
|
let t;
|
||||||
e = [ "e", "f", "g" ];
|
t = [ "e", "f", "g" ];
|
||||||
for (let o in test)
|
for (let e in test)
|
||||||
console.log(o);
|
console.log(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
@@ -281,10 +281,10 @@ more_variable_in_multiple_for: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
for (let o = 9, l = 0; l < 20; l += o) {
|
for (let o = 9, l = 0; l < 20; l += o) {
|
||||||
let c = o++ + l;
|
let e = o++ + l;
|
||||||
console.log(o, c, l);
|
console.log(o, e, l);
|
||||||
for (let l = c, e = c * c, f = 0; f < 10; f++)
|
for (let l = e, t = e * e, c = 0; c < 10; c++)
|
||||||
console.log(o, c, e, l, f);
|
console.log(o, e, t, l, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ numeric_literal: {
|
|||||||
' 42: 2,',
|
' 42: 2,',
|
||||||
' "42": 3,',
|
' "42": 3,',
|
||||||
' 37: 4,',
|
' 37: 4,',
|
||||||
' a: 5,',
|
' o: 5,',
|
||||||
' 1e42: 6,',
|
' 1e42: 6,',
|
||||||
' b: 7,',
|
' b: 7,',
|
||||||
' "1e+42": 8',
|
' "1e+42": 8',
|
||||||
@@ -92,7 +92,7 @@ numeric_literal: {
|
|||||||
'',
|
'',
|
||||||
'console.log(obj[42], obj["42"]);',
|
'console.log(obj[42], obj["42"]);',
|
||||||
'',
|
'',
|
||||||
'console.log(obj[37], obj["a"], obj[37], obj["37"]);',
|
'console.log(obj[37], obj["o"], obj[37], obj["37"]);',
|
||||||
'',
|
'',
|
||||||
'console.log(obj[1e42], obj["b"], obj["1e+42"]);',
|
'console.log(obj[1e42], obj["b"], obj["1e+42"]);',
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export_default_func_1: {
|
|||||||
input: {
|
input: {
|
||||||
export default function f(){};
|
export default function f(){};
|
||||||
}
|
}
|
||||||
expect_exact: "export default function(){};"
|
expect_exact: "export default function f(){};"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_default_func_2: {
|
export_default_func_2: {
|
||||||
@@ -58,7 +58,7 @@ export_default_func_2: {
|
|||||||
input: {
|
input: {
|
||||||
export default function f(){}(1);
|
export default function f(){}(1);
|
||||||
}
|
}
|
||||||
expect_exact: "export default function(){};1;"
|
expect_exact: "export default function f(){};1;"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_default_func_3: {
|
export_default_func_3: {
|
||||||
@@ -71,7 +71,7 @@ export_default_func_3: {
|
|||||||
input: {
|
input: {
|
||||||
export default function f(){}(1);
|
export default function f(){}(1);
|
||||||
}
|
}
|
||||||
expect_exact: "export default function(){};"
|
expect_exact: "export default function f(){};"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_class_1: {
|
export_class_1: {
|
||||||
@@ -121,7 +121,7 @@ export_default_class_1: {
|
|||||||
input: {
|
input: {
|
||||||
export default class C {};
|
export default class C {};
|
||||||
}
|
}
|
||||||
expect_exact: "export default class{};"
|
expect_exact: "export default class C{};"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_default_class_2: {
|
export_default_class_2: {
|
||||||
@@ -134,7 +134,7 @@ export_default_class_2: {
|
|||||||
input: {
|
input: {
|
||||||
export default class C {}(1);
|
export default class C {}(1);
|
||||||
}
|
}
|
||||||
expect_exact: "export default class{};1;"
|
expect_exact: "export default class C{};1;"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_default_class_3: {
|
export_default_class_3: {
|
||||||
@@ -147,7 +147,7 @@ export_default_class_3: {
|
|||||||
input: {
|
input: {
|
||||||
export default class C {}(1);
|
export default class C {}(1);
|
||||||
}
|
}
|
||||||
expect_exact: "export default class{};"
|
expect_exact: "export default class C{};"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_mangle_1: {
|
export_mangle_1: {
|
||||||
@@ -159,7 +159,7 @@ export_mangle_1: {
|
|||||||
return one - two;
|
return one - two;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
expect_exact: "export function foo(n,o){return n-o};"
|
expect_exact: "export function foo(o,n){return o-n};"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_mangle_2: {
|
export_mangle_2: {
|
||||||
@@ -171,7 +171,7 @@ export_mangle_2: {
|
|||||||
return one - two;
|
return one - two;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
expect_exact: "export default function n(n,r){return n-r};"
|
expect_exact: "export default function foo(o,t){return o-t};"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_mangle_3: {
|
export_mangle_3: {
|
||||||
@@ -189,7 +189,7 @@ export_mangle_3: {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
expect_exact: "export class C{go(n,r){return n-r+n}};"
|
expect_exact: "export class C{go(r,e){return r-e+r}};"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_mangle_4: {
|
export_mangle_4: {
|
||||||
@@ -207,7 +207,7 @@ export_mangle_4: {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
expect_exact: "export default class n{go(n,r){return n-r+n}};"
|
expect_exact: "export default class C{go(e,r){return e-r+e}};"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_mangle_5: {
|
export_mangle_5: {
|
||||||
@@ -221,7 +221,7 @@ export_mangle_5: {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
expect_exact: "export default{prop:function(n,r){return n-r}};"
|
expect_exact: "export default{prop:function(r,t){return r-t}};"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_mangle_6: {
|
export_mangle_6: {
|
||||||
@@ -232,7 +232,7 @@ export_mangle_6: {
|
|||||||
var baz = 2;
|
var baz = 2;
|
||||||
export let foo = 1, bar = baz;
|
export let foo = 1, bar = baz;
|
||||||
}
|
}
|
||||||
expect_exact: "var a=2;export let foo=1,bar=a;"
|
expect_exact: "var o=2;export let foo=1,bar=o;"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_toplevel_1: {
|
export_toplevel_1: {
|
||||||
@@ -247,7 +247,7 @@ export_toplevel_1: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
export function g(){};
|
export function g(){};
|
||||||
export default function(){};
|
export default function h(){};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +263,7 @@ export_toplevel_2: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
export class B {};
|
export class B {};
|
||||||
export default class {};
|
export default class C {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ compress_new_function: {
|
|||||||
new Function("aa, bb", 'return aa;');
|
new Function("aa, bb", 'return aa;');
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
Function("a", "b", "return a");
|
Function("n", "r", "return n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,8 +27,30 @@ compress_new_function_with_destruct: {
|
|||||||
new Function("[[aa]], [{bb}]", 'return aa;');
|
new Function("[[aa]], [{bb}]", 'return aa;');
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
Function("a", "[b]", "return a");
|
Function("n", "[r]", "return n");
|
||||||
Function("a", "{bb:b}", "return a");
|
Function("n", "{bb:b}", "return n");
|
||||||
Function("[[a]]", "[{bb:b}]", 'return a');
|
Function("[[n]]", "[{bb:b}]", "return n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compress_new_function_with_destruct_arrows: {
|
||||||
|
options = {
|
||||||
|
arrows: true,
|
||||||
|
unsafe: true,
|
||||||
|
unsafe_Func: 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("aa, [bb]", 'return aa;');
|
||||||
|
Function("aa, {bb}", 'return aa;');
|
||||||
|
Function("[[aa]], [{bb}]", 'return aa;');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,41 @@
|
|||||||
dont_reuse_prop: {
|
dont_reuse_prop: {
|
||||||
mangle_props = {
|
mangle_props = {
|
||||||
regex: /asd/
|
regex: /asd/
|
||||||
};
|
}
|
||||||
|
|
||||||
input: {
|
input: {
|
||||||
|
"aaaaaaaaaabbbbb";
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.a = 123;
|
obj.a = 123;
|
||||||
obj.asd = 256;
|
obj.asd = 256;
|
||||||
console.log(obj.a);
|
console.log(obj.a);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
"aaaaaaaaaabbbbb";
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.a = 123;
|
obj.a = 123;
|
||||||
obj.b = 256;
|
obj.b = 256;
|
||||||
console.log(obj.a);
|
console.log(obj.a);
|
||||||
}
|
}
|
||||||
|
expect_stdout: "123"
|
||||||
}
|
}
|
||||||
|
|
||||||
unmangleable_props_should_always_be_reserved: {
|
unmangleable_props_should_always_be_reserved: {
|
||||||
mangle_props = {
|
mangle_props = {
|
||||||
regex: /asd/
|
regex: /asd/
|
||||||
};
|
}
|
||||||
|
|
||||||
input: {
|
input: {
|
||||||
|
"aaaaaaaaaabbbbb";
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.asd = 256;
|
obj.asd = 256;
|
||||||
obj.a = 123;
|
obj.a = 123;
|
||||||
console.log(obj.a);
|
console.log(obj.a);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
"aaaaaaaaaabbbbb";
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.b = 256;
|
obj.b = 256;
|
||||||
obj.a = 123;
|
obj.a = 123;
|
||||||
console.log(obj.a);
|
console.log(obj.a);
|
||||||
}
|
}
|
||||||
|
expect_stdout: "123"
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ getter_setter_mangler: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_exact: "function f(n,t){return{get:n,set:t,get g(){},set s(n){},c,a:1,m(){}}}"
|
expect_exact: "function f(t,e){return{get:t,set:e,get g(){},set s(t){},c,a:1,m(){}}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
use_shorthand_opportunity: {
|
use_shorthand_opportunity: {
|
||||||
@@ -297,7 +297,7 @@ concise_methods_and_mangle_props: {
|
|||||||
expect: {
|
expect: {
|
||||||
function x() {
|
function x() {
|
||||||
obj = {
|
obj = {
|
||||||
a() { return 1; }
|
o() { return 1; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
arrow_functions: {
|
arrow_functions: {
|
||||||
|
options = {
|
||||||
|
arrows: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
(a) => b; // 1 args
|
(a) => b; // 1 args
|
||||||
(a, b) => c; // n args
|
(a, b) => c; // n args
|
||||||
@@ -13,6 +16,9 @@ arrow_functions: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
arrow_return: {
|
arrow_return: {
|
||||||
|
options = {
|
||||||
|
arrows: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
() => {};
|
() => {};
|
||||||
() => { return; };
|
() => { return; };
|
||||||
|
|||||||
@@ -135,11 +135,11 @@ mangle_properties: {
|
|||||||
a['run']({color: "blue", foo: "baz"});
|
a['run']({color: "blue", foo: "baz"});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
a["a"] = "bar";
|
a["o"] = "bar";
|
||||||
a.b = "red";
|
a.a = "red";
|
||||||
x = {c: 10};
|
x = {r: 10};
|
||||||
a.d(x.c, a.a);
|
a.b(x.r, a.o);
|
||||||
a['d']({b: "blue", a: "baz"});
|
a['b']({a: "blue", o: "baz"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,16 +178,16 @@ mangle_unquoted_properties: {
|
|||||||
function f1() {
|
function f1() {
|
||||||
a["foo"] = "bar";
|
a["foo"] = "bar";
|
||||||
a.color = "red";
|
a.color = "red";
|
||||||
a.b = 2;
|
a.o = 2;
|
||||||
x = {"bar": 10, c: 7};
|
x = {"bar": 10, f: 7};
|
||||||
a.c = 9;
|
a.f = 9;
|
||||||
}
|
}
|
||||||
function f2() {
|
function f2() {
|
||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
a['color'] = "red";
|
a['color'] = "red";
|
||||||
x = {bar: 10, c: 7};
|
x = {bar: 10, f: 7};
|
||||||
a.c = 9;
|
a.f = 9;
|
||||||
a.b = 3;
|
a.o = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,3 +178,210 @@ impure_getter_2: {
|
|||||||
}
|
}
|
||||||
expect: {}
|
expect: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2110_1: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
function f() {}
|
||||||
|
function g() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
f.g = g;
|
||||||
|
return f.g();
|
||||||
|
}
|
||||||
|
console.log(typeof f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
function f() {}
|
||||||
|
return f.g = function() {
|
||||||
|
return this;
|
||||||
|
}, f.g();
|
||||||
|
}
|
||||||
|
console.log(typeof f());
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2110_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
function f() {}
|
||||||
|
function g() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
f.g = g;
|
||||||
|
return f.g();
|
||||||
|
}
|
||||||
|
console.log(typeof f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
function f() {}
|
||||||
|
f.g = function() {
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
return f.g();
|
||||||
|
}
|
||||||
|
console.log(typeof f());
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_immutable_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
1..foo += "";
|
||||||
|
if (1..foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_immutable_2: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_immutable_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
1..foo += "";
|
||||||
|
if (1..foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
set_immutable_4: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
set_mutable_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function a() {
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("PASS");
|
||||||
|
else console.log("FAIL");
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function a() {
|
||||||
|
if (a.foo += "") console.log("PASS");
|
||||||
|
else console.log("FAIL");
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_mutable_2: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function a() {
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("PASS");
|
||||||
|
else console.log("FAIL");
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function a() {
|
||||||
|
(a.foo += "") ? console.log("PASS") : console.log("FAIL");
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -2625,3 +2625,28 @@ issue_2090_2: {
|
|||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for_in_prop: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = {
|
||||||
|
foo: function() {
|
||||||
|
for (this.b in [1, 2]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
a.foo();
|
||||||
|
console.log(a.b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = {
|
||||||
|
foo: function() {
|
||||||
|
for (this.b in [1, 2]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
a.foo();
|
||||||
|
console.log(a.b);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -255,3 +255,73 @@ issue_1586_2: {
|
|||||||
}
|
}
|
||||||
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
|
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2120_1: {
|
||||||
|
mangle = {
|
||||||
|
ie8: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"aaaaaaaa";
|
||||||
|
var a = 1, b = "FAIL";
|
||||||
|
try {
|
||||||
|
throw 1;
|
||||||
|
} catch (c) {
|
||||||
|
try {
|
||||||
|
throw 0;
|
||||||
|
} catch (a) {
|
||||||
|
if (c) b = "PASS";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"aaaaaaaa";
|
||||||
|
var a = 1, b = "FAIL";
|
||||||
|
try {
|
||||||
|
throw 1;
|
||||||
|
} catch (t) {
|
||||||
|
try {
|
||||||
|
throw 0;
|
||||||
|
} catch (a) {
|
||||||
|
if (t) b = "PASS";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2120_2: {
|
||||||
|
mangle = {
|
||||||
|
ie8: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"aaaaaaaa";
|
||||||
|
var a = 1, b = "FAIL";
|
||||||
|
try {
|
||||||
|
throw 1;
|
||||||
|
} catch (c) {
|
||||||
|
try {
|
||||||
|
throw 0;
|
||||||
|
} catch (a) {
|
||||||
|
if (c) b = "PASS";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"aaaaaaaa";
|
||||||
|
var a = 1, b = "FAIL";
|
||||||
|
try {
|
||||||
|
throw 1;
|
||||||
|
} catch (c) {
|
||||||
|
try {
|
||||||
|
throw 0;
|
||||||
|
} catch (a) {
|
||||||
|
if (c) b = "PASS";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
3
test/input/invalid/export_1.js
Normal file
3
test/input/invalid/export_1.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
export var V = 1;
|
||||||
|
}
|
||||||
1
test/input/invalid/export_2.js
Normal file
1
test/input/invalid/export_2.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export class{};
|
||||||
1
test/input/invalid/export_3.js
Normal file
1
test/input/invalid/export_3.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export function(){};
|
||||||
4
test/input/invalid/for-in_1.js
Normal file
4
test/input/invalid/for-in_1.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
var a, b = [1, 2];
|
||||||
|
for (1, 2, a in b) {
|
||||||
|
console.log(a, b[a]);
|
||||||
|
}
|
||||||
4
test/input/invalid/for-in_2.js
Normal file
4
test/input/invalid/for-in_2.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
var c = [1, 2];
|
||||||
|
for (var a, b in c) {
|
||||||
|
console.log(a, c[a]);
|
||||||
|
}
|
||||||
3
test/input/invalid/import.js
Normal file
3
test/input/invalid/import.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
import A from "B";
|
||||||
|
}
|
||||||
1
test/input/invalid/sequence.js
Normal file
1
test/input/invalid/sequence.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
(a, ...b);
|
||||||
@@ -62,23 +62,20 @@ describe("Arrow functions", function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
it("Should not accept arrow functions in the middle or end of an expression", function() {
|
it("Should not accept arrow functions in the middle or end of an expression", function() {
|
||||||
var tests = [
|
[
|
||||||
|
"0 + x => 0",
|
||||||
|
"0 + async x => 0",
|
||||||
"typeof x => 0",
|
"typeof x => 0",
|
||||||
"0 + x => 0"
|
"typeof async x => 0",
|
||||||
];
|
"typeof (x) => null",
|
||||||
var test = function(code) {
|
"typeof async (x) => null",
|
||||||
return function() {
|
].forEach(function(code) {
|
||||||
|
assert.throws(function() {
|
||||||
uglify.parse(code);
|
uglify.parse(code);
|
||||||
}
|
}, function(e) {
|
||||||
}
|
return e instanceof uglify.JS_Parse_Error && /^Unexpected /.test(e.message);
|
||||||
var error = function(e) {
|
}, code);
|
||||||
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() {
|
it("Should parse a function containing default assignment correctly", function() {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
var exec = require("child_process").exec;
|
var exec = require("child_process").exec;
|
||||||
var readFileSync = require("fs").readFileSync;
|
var readFileSync = require("fs").readFileSync;
|
||||||
|
var semver = require("semver");
|
||||||
|
|
||||||
function read(path) {
|
function read(path) {
|
||||||
return readFileSync(path, "utf8");
|
return readFileSync(path, "utf8");
|
||||||
@@ -9,9 +10,11 @@ function read(path) {
|
|||||||
describe("bin/uglifyjs", function () {
|
describe("bin/uglifyjs", function () {
|
||||||
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
|
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
|
||||||
it("should produce a functional build when using --self", function (done) {
|
it("should produce a functional build when using --self", function (done) {
|
||||||
this.timeout(30000);
|
this.timeout(60000);
|
||||||
|
|
||||||
var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS';
|
var command = uglifyjscmd + ' --self -mc ecma=';
|
||||||
|
command += semver.satisfies(process.version, ">=4") ? "6" : "5";
|
||||||
|
command += ',passes=3,keep_fargs=false,unsafe --wrap WrappedUglifyJS';
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
@@ -533,6 +536,111 @@ describe("bin/uglifyjs", function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("Should throw syntax error (block-level export)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/export_1.js -m';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/export_1.js:2,4",
|
||||||
|
" export var V = 1;",
|
||||||
|
" ^",
|
||||||
|
"ERROR: Export statement may only appear at top level"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should throw syntax error (block-level import)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/import.js -m';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/import.js:2,4",
|
||||||
|
' import A from "B";',
|
||||||
|
" ^",
|
||||||
|
"ERROR: Import statement may only appear at top level"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should throw syntax error (anonymous class)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/export_2.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/export_2.js:1,12",
|
||||||
|
"export class{};",
|
||||||
|
" ^",
|
||||||
|
"ERROR: Unexpected token: punc ({)"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should throw syntax error (anonymous function)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/export_3.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/export_3.js:1,15",
|
||||||
|
"export function(){};",
|
||||||
|
" ^",
|
||||||
|
"ERROR: Unexpected token: punc (()"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should throw syntax error (spread in sequence)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/sequence.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/sequence.js:1,4",
|
||||||
|
"(a, ...b);",
|
||||||
|
" ^",
|
||||||
|
"ERROR: Unexpected token: expand (...)"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should throw syntax error (for-in init)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/for-in_1.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/for-in_1.js:2,5",
|
||||||
|
"for (1, 2, a in b) {",
|
||||||
|
" ^",
|
||||||
|
"ERROR: Invalid left-hand side in for..in loop"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should throw syntax error (for-in var)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/for-in_2.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/for-in_2.js:2,5",
|
||||||
|
"for (var a, b in c) {",
|
||||||
|
" ^",
|
||||||
|
"ERROR: Only one variable declaration allowed in for..in loop"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
it("Should handle literal string as source map input", function(done) {
|
it("Should handle literal string as source map input", function(done) {
|
||||||
var command = [
|
var command = [
|
||||||
uglifyjscmd,
|
uglifyjscmd,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ var uglify = require("../node");
|
|||||||
|
|
||||||
describe("Export", function() {
|
describe("Export", function() {
|
||||||
it("Should parse export directives", function() {
|
it("Should parse export directives", function() {
|
||||||
|
|
||||||
var inputs = [
|
var inputs = [
|
||||||
['export * from "a.js"', ['*'], "a.js"],
|
['export * from "a.js"', ['*'], "a.js"],
|
||||||
['export {A} from "a.js"', ['A'], "a.js"],
|
['export {A} from "a.js"', ['A'], "a.js"],
|
||||||
@@ -12,17 +11,17 @@ describe("Export", function() {
|
|||||||
['export {A, B} from "a.js"', ['A', 'B'], "a.js"],
|
['export {A, B} from "a.js"', ['A', 'B'], "a.js"],
|
||||||
];
|
];
|
||||||
|
|
||||||
var test = function(code) {
|
function test(code) {
|
||||||
return uglify.parse(code);
|
return uglify.parse(code);
|
||||||
};
|
}
|
||||||
|
|
||||||
var extractNames = function(symbols) {
|
function extractNames(symbols) {
|
||||||
var ret = [];
|
var ret = [];
|
||||||
for (var i = 0; i < symbols.length; i++) {
|
for (var i = 0; i < symbols.length; i++) {
|
||||||
ret.push(symbols[i].name.name)
|
ret.push(symbols[i].foreign_name.name);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
};
|
}
|
||||||
|
|
||||||
for (var i = 0; i < inputs.length; i++) {
|
for (var i = 0; i < inputs.length; i++) {
|
||||||
var ast = test(inputs[i][0]);
|
var ast = test(inputs[i][0]);
|
||||||
@@ -34,7 +33,7 @@ describe("Export", function() {
|
|||||||
assert(st instanceof uglify.AST_Export);
|
assert(st instanceof uglify.AST_Export);
|
||||||
var actualNames = extractNames(st.exported_names);
|
var actualNames = extractNames(st.exported_names);
|
||||||
assert.deepEqual(actualNames, names);
|
assert.deepEqual(actualNames, names);
|
||||||
assert.equal(st.module_name.value, filename)
|
assert.equal(st.module_name.value, filename);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
@@ -191,15 +191,51 @@ describe("Function", function() {
|
|||||||
];
|
];
|
||||||
var test = function(code) {
|
var test = function(code) {
|
||||||
return function() {
|
return function() {
|
||||||
uglify.parse(code);
|
uglify.parse(code, { ecma: 5 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var error = function(e) {
|
var error = function(e) {
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
return e instanceof uglify.JS_Parse_Error;
|
||||||
e.message === "Invalid function parameter";
|
|
||||||
}
|
}
|
||||||
for (var i = 0; i < tests.length; i++) {
|
for (var i = 0; i < tests.length; i++) {
|
||||||
assert.throws(test(tests[i]), error);
|
assert.throws(test(tests[i]), error, tests[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it("Should accept trailing commas only for ES8", function() {
|
||||||
|
[
|
||||||
|
"new Foo(a, );",
|
||||||
|
"async(...[1, 2], );",
|
||||||
|
"console.log(...[1, 2], );",
|
||||||
|
"!function(a, b, ){ console.log(a + b); }(3, 4, );",
|
||||||
|
].forEach(function(code) {
|
||||||
|
uglify.parse(code, { ecma: 8 });
|
||||||
|
assert.throws(function() {
|
||||||
|
uglify.parse(code, { ecma: 6 });
|
||||||
|
}, function(e) {
|
||||||
|
return e instanceof uglify.JS_Parse_Error;
|
||||||
|
}, code);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should not accept invalid trailing commas", function() {
|
||||||
|
var tests = [
|
||||||
|
"f(, );",
|
||||||
|
"(, ) => {};",
|
||||||
|
"(...p, ) => {};",
|
||||||
|
"function f(, ) {}",
|
||||||
|
"function f(...p, ) {}",
|
||||||
|
"function foo(a, b, , ) {}",
|
||||||
|
'console.log("hello", , );',
|
||||||
|
];
|
||||||
|
var test = function(code) {
|
||||||
|
return function() {
|
||||||
|
uglify.parse(code, { ecma: 8 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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("Should not accept an initializer when parameter is a rest parameter", function() {
|
it("Should not accept an initializer when parameter is a rest parameter", function() {
|
||||||
|
|||||||
@@ -2,29 +2,37 @@ var Uglify = require('../../');
|
|||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
|
|
||||||
describe("let", function() {
|
describe("let", function() {
|
||||||
it("Should not produce `let` as a variable name in mangle", function(done) {
|
it("Should not produce reserved keywords as variable name in mangle", function(done) {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
// Produce a lot of variables in a function and run it through mangle.
|
// Produce a lot of variables in a function and run it through mangle.
|
||||||
var s = '"use strict"; function foo() {';
|
var s = '"dddddeeeeelllllooooottttt"; function foo() {';
|
||||||
for (var i = 0; i < 21000; ++i) {
|
for (var i = 0; i < 18000; i++) {
|
||||||
s += "var v" + i + "=0;";
|
s += "var v" + i + "=0;";
|
||||||
}
|
}
|
||||||
s += '}';
|
s += '}';
|
||||||
var result = Uglify.minify(s, {compress: false});
|
var result = Uglify.minify(s, {compress: false});
|
||||||
|
|
||||||
// Verify that select keywords and reserved keywords not produced
|
// Verify that select keywords and reserved keywords not produced
|
||||||
assert.strictEqual(result.code.indexOf("var let="), -1);
|
[
|
||||||
assert.strictEqual(result.code.indexOf("var do="), -1);
|
"do",
|
||||||
assert.strictEqual(result.code.indexOf("var var="), -1);
|
"let",
|
||||||
|
"var",
|
||||||
|
].forEach(function(name) {
|
||||||
|
assert.strictEqual(result.code.indexOf("var " + name + "="), -1);
|
||||||
|
});
|
||||||
|
|
||||||
// Verify that the variable names that appeared immediately before
|
// Verify that the variable names that appeared immediately before
|
||||||
// and after the erroneously generated `let` variable name still exist
|
// and after the erroneously generated variable name still exist
|
||||||
// to show the test generated enough symbols.
|
// to show the test generated enough symbols.
|
||||||
assert(result.code.indexOf("var ket=") >= 0);
|
[
|
||||||
assert(result.code.indexOf("var met=") >= 0);
|
"to", "eo",
|
||||||
|
"eet", "fet",
|
||||||
|
"rar", "oar",
|
||||||
|
].forEach(function(name) {
|
||||||
|
assert.ok(result.code.indexOf("var " + name + "=") >= 0);
|
||||||
|
});
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ function run_compress_tests() {
|
|||||||
log_start_file(file);
|
log_start_file(file);
|
||||||
function test_case(test) {
|
function test_case(test) {
|
||||||
log_test(test.name);
|
log_test(test.name);
|
||||||
U.base54.reset();
|
|
||||||
var output_options = test.beautify || {};
|
var output_options = test.beautify || {};
|
||||||
var expect;
|
var expect;
|
||||||
if (test.expect) {
|
if (test.expect) {
|
||||||
@@ -101,9 +100,6 @@ function run_compress_tests() {
|
|||||||
quote_style: 3,
|
quote_style: 3,
|
||||||
keep_quoted_props: true
|
keep_quoted_props: true
|
||||||
});
|
});
|
||||||
if (test.mangle_props) {
|
|
||||||
input = U.mangle_properties(input, test.mangle_props);
|
|
||||||
}
|
|
||||||
var options = U.defaults(test.options, {
|
var options = U.defaults(test.options, {
|
||||||
warnings: false
|
warnings: false
|
||||||
});
|
});
|
||||||
@@ -118,10 +114,16 @@ function run_compress_tests() {
|
|||||||
var cmp = new U.Compressor(options, true);
|
var cmp = new U.Compressor(options, true);
|
||||||
var output = cmp.compress(input);
|
var output = cmp.compress(input);
|
||||||
output.figure_out_scope(test.mangle);
|
output.figure_out_scope(test.mangle);
|
||||||
if (test.mangle) {
|
if (test.mangle || test.mangle_props) {
|
||||||
|
U.base54.reset();
|
||||||
output.compute_char_frequency(test.mangle);
|
output.compute_char_frequency(test.mangle);
|
||||||
|
}
|
||||||
|
if (test.mangle) {
|
||||||
output.mangle_names(test.mangle);
|
output.mangle_names(test.mangle);
|
||||||
}
|
}
|
||||||
|
if (test.mangle_props) {
|
||||||
|
output = U.mangle_properties(output, test.mangle_props);
|
||||||
|
}
|
||||||
output = make_code(output, output_options);
|
output = make_code(output, output_options);
|
||||||
if (expect != output) {
|
if (expect != output) {
|
||||||
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
|
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
|
||||||
|
|||||||
Reference in New Issue
Block a user