Compare commits
21 Commits
harmony-v3
...
harmony-v3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
402954bdf3 | ||
|
|
f5931866e0 | ||
|
|
f67a6b0e43 | ||
|
|
471db8a717 | ||
|
|
8ba9e4e0da | ||
|
|
71556d00b5 | ||
|
|
8709753bfb | ||
|
|
db877e8729 | ||
|
|
11923e3ae8 | ||
|
|
62d1fbf645 | ||
|
|
343ea326c2 | ||
|
|
849ba79dee | ||
|
|
a298bcce02 | ||
|
|
daaf1273fa | ||
|
|
1c150c632f | ||
|
|
0a0f4f5591 | ||
|
|
931daa85bf | ||
|
|
00e4f7b3c1 | ||
|
|
11e63bc335 | ||
|
|
3fa862ce19 | ||
|
|
33405bb24b |
32
lib/ast.js
32
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) {
|
||||||
@@ -656,7 +656,7 @@ var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", {
|
|||||||
this.imported_name._walk(visitor);
|
this.imported_name._walk(visitor);
|
||||||
}
|
}
|
||||||
if (this.imported_names) {
|
if (this.imported_names) {
|
||||||
this.imported_names.forEach(function (name_import) {
|
this.imported_names.forEach(function(name_import) {
|
||||||
name_import._walk(visitor);
|
name_import._walk(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);
|
||||||
|
|||||||
446
lib/compress.js
446
lib/compress.js
@@ -129,7 +129,9 @@ function Compressor(options, false_by_default) {
|
|||||||
this.toplevel.funcs = /funcs/.test(toplevel);
|
this.toplevel.funcs = /funcs/.test(toplevel);
|
||||||
this.toplevel.vars = /vars/.test(toplevel);
|
this.toplevel.vars = /vars/.test(toplevel);
|
||||||
} else {
|
} else {
|
||||||
this.toplevel = toplevel ? return_true : return_false;
|
this.toplevel = toplevel ? function(def) {
|
||||||
|
return !def.export;
|
||||||
|
} : return_false;
|
||||||
this.toplevel.funcs = this.toplevel.vars = toplevel;
|
this.toplevel.funcs = this.toplevel.vars = toplevel;
|
||||||
}
|
}
|
||||||
var sequences = this.options["sequences"];
|
var sequences = this.options["sequences"];
|
||||||
@@ -141,6 +143,7 @@ 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) {
|
toplevel: function(def) {
|
||||||
|
if (def.export) return false;
|
||||||
for (var i = 0, len = def.orig.length; i < len; i++)
|
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 false;
|
||||||
@@ -672,7 +675,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 +700,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 +755,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)
|
||||||
@@ -818,7 +822,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)
|
||||||
@@ -921,59 +924,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 {
|
} else i++;
|
||||||
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,81 +986,71 @@ 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 (value && !stat.alternative && next instanceof AST_Return && next.value) {
|
||||||
if (ret[0] instanceof AST_Return && value && ret[0].value && !stat.alternative) {
|
CHANGED = true;
|
||||||
CHANGED = true;
|
stat = stat.clone();
|
||||||
stat = stat.clone();
|
stat.alternative = next;
|
||||||
stat.alternative = ret[0];
|
statements.splice(i, 2, stat.transform(compressor));
|
||||||
ret[0] = stat.transform(compressor);
|
continue;
|
||||||
continue loop;
|
}
|
||||||
}
|
//---
|
||||||
//---
|
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
||||||
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
if (multiple_if_returns && in_lambda && value && !stat.alternative
|
||||||
if (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return)
|
&& (!next || next instanceof AST_Return)) {
|
||||||
&& value && !stat.alternative && in_lambda) {
|
CHANGED = true;
|
||||||
CHANGED = true;
|
stat = stat.clone();
|
||||||
stat = stat.clone();
|
stat.alternative = next || make_node(AST_Return, stat, {
|
||||||
stat.alternative = ret[0] || make_node(AST_Return, stat, {
|
value: null
|
||||||
value: null
|
});
|
||||||
});
|
statements.splice(i, next ? 2 : 1, stat.transform(compressor));
|
||||||
ret[0] = stat.transform(compressor);
|
continue;
|
||||||
continue loop;
|
}
|
||||||
}
|
//---
|
||||||
//---
|
// 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;
|
//
|
||||||
//
|
// 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.
|
var prev = statements[i - 1];
|
||||||
if (compressor.option("sequences")
|
if (compressor.option("sequences") && in_lambda && !stat.alternative
|
||||||
&& i > 0 && statements[i - 1] instanceof AST_If && statements[i - 1].body instanceof AST_Return
|
&& prev instanceof AST_If && prev.body instanceof AST_Return
|
||||||
&& ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement
|
&& i + 2 == statements.length && next instanceof AST_SimpleStatement) {
|
||||||
&& !stat.alternative) {
|
CHANGED = true;
|
||||||
CHANGED = true;
|
statements.push(make_node(AST_Return, next, {
|
||||||
ret.push(make_node(AST_Return, ret[0], {
|
value: null
|
||||||
value: null
|
}).transform(compressor));
|
||||||
}).transform(compressor));
|
continue;
|
||||||
ret.unshift(stat);
|
|
||||||
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 +1068,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 +1100,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);
|
if (stat instanceof AST_LoopControl) {
|
||||||
} else {
|
var lct = compressor.loopcontrol_target(stat);
|
||||||
if (stat instanceof AST_LoopControl) {
|
if (stat instanceof AST_Break
|
||||||
var lct = compressor.loopcontrol_target(stat);
|
&& !(lct instanceof AST_IterationStatement)
|
||||||
if ((stat instanceof AST_Break
|
&& loop_body(lct) === self
|
||||||
&& !(lct instanceof AST_IterationStatement)
|
|| stat instanceof AST_Continue
|
||||||
&& loop_body(lct) === self) || (stat instanceof AST_Continue
|
&& loop_body(lct) === self) {
|
||||||
&& loop_body(lct) === self)) {
|
if (stat.label) {
|
||||||
if (stat.label) {
|
remove(stat.label.thedef.references, stat);
|
||||||
remove(stat.label.thedef.references, stat);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a.push(stat);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
a.push(stat);
|
statements[n++] = stat;
|
||||||
}
|
}
|
||||||
if (aborts(stat)) has_quit = true;
|
} else {
|
||||||
|
statements[n++] = stat;
|
||||||
}
|
}
|
||||||
return a;
|
if (aborts(stat)) {
|
||||||
}, []);
|
has_quit = statements.slice(i + 1);
|
||||||
CHANGED = statements.length != orig;
|
break;
|
||||||
return statements;
|
}
|
||||||
};
|
}
|
||||||
|
statements.length = n;
|
||||||
|
CHANGED = n != len;
|
||||||
|
if (has_quit) has_quit.forEach(function(stat) {
|
||||||
|
extract_declarations_from_unreachable_code(compressor, stat, 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 +1153,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 +1174,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 +1189,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 +1211,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 +1229,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;
|
|
||||||
}, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
statements.length = j + 1;
|
||||||
return funs;
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
||||||
@@ -2050,13 +2047,12 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Block, function(self, compressor){
|
OPT(AST_Block, function(self, compressor){
|
||||||
if (self.body instanceof AST_Node) { return self; }
|
if (!(self.body instanceof AST_Node)) 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
|
||||||
@@ -2097,7 +2093,8 @@ merge(Compressor.prototype, {
|
|||||||
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 +2105,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);
|
||||||
}
|
}
|
||||||
@@ -2233,11 +2231,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 +2267,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 +2275,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 +3053,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 +3110,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;
|
||||||
@@ -3330,20 +3342,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.value;
|
||||||
var value = stat && 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 +3374,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 +3407,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;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
|
||||||
value = self;
|
value = self;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
function matches(ref) {
|
value.walk(tw);
|
||||||
return ref && ref.scope.parent_scope === fn.parent_scope;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
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,6 +3560,7 @@ 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";
|
||||||
@@ -4041,6 +4071,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) {
|
||||||
|
|||||||
@@ -1280,7 +1280,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 +1295,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) {
|
||||||
output.print(self.foreign_name.name);
|
if (is_import) {
|
||||||
|
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();
|
||||||
self.name.print(output);
|
if (is_import) {
|
||||||
|
self.name.print(output);
|
||||||
|
} else {
|
||||||
|
output.print(self.foreign_name.name);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.name.print(output);
|
self.name.print(output);
|
||||||
}
|
}
|
||||||
@@ -1320,24 +1328,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);
|
||||||
|
|||||||
156
lib/parse.js
156
lib/parse.js
@@ -2012,7 +2012,7 @@ 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();
|
unexpected();
|
||||||
}
|
}
|
||||||
@@ -2109,7 +2109,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 +2231,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 +2302,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 +2326,32 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function import_name() {
|
function map_name(is_import) {
|
||||||
|
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 = as_symbol(foreign_type);
|
||||||
|
} else {
|
||||||
|
name = as_symbol(type);
|
||||||
|
}
|
||||||
|
if (is("name", "as")) {
|
||||||
next(); // The "as" word
|
next(); // The "as" word
|
||||||
}
|
if (is_import) {
|
||||||
name = as_symbol(AST_SymbolImport);
|
name = as_symbol(type);
|
||||||
|
} else {
|
||||||
if (foreign_name === undefined) {
|
foreign_name = as_symbol(foreign_type);
|
||||||
foreign_name = new AST_SymbolImportForeign({
|
}
|
||||||
name: name.name,
|
} else if (is_import) {
|
||||||
start: name.start,
|
name = new type(foreign_name);
|
||||||
end: name.end,
|
} else {
|
||||||
});
|
foreign_name = new foreign_type(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +2359,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 +2386,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 +2401,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,72 +2413,60 @@ 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 (is("name", "from")) {
|
||||||
|
next();
|
||||||
|
|
||||||
if (exported_names) {
|
var mod_str = S.token;
|
||||||
if (is("name", "from")) {
|
if (mod_str.type !== 'string') {
|
||||||
next();
|
unexpected();
|
||||||
|
|
||||||
var mod_str = S.token;
|
|
||||||
if (mod_str.type !== 'string') {
|
|
||||||
unexpected();
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
|
|
||||||
return new AST_Export({
|
|
||||||
start: start,
|
|
||||||
is_default: is_default,
|
|
||||||
exported_names: exported_names,
|
|
||||||
module_name: new AST_String({
|
|
||||||
start: mod_str,
|
|
||||||
value: mod_str.value,
|
|
||||||
quote: mod_str.quote,
|
|
||||||
end: mod_str,
|
|
||||||
}),
|
|
||||||
end: prev(),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return new AST_Export({
|
|
||||||
start: start,
|
|
||||||
is_default: is_default,
|
|
||||||
exported_names: exported_names,
|
|
||||||
end: prev(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
next();
|
||||||
|
|
||||||
|
return new AST_Export({
|
||||||
|
start: start,
|
||||||
|
is_default: is_default,
|
||||||
|
exported_names: exported_names,
|
||||||
|
module_name: new AST_String({
|
||||||
|
start: mod_str,
|
||||||
|
value: mod_str.value,
|
||||||
|
quote: mod_str.quote,
|
||||||
|
end: mod_str,
|
||||||
|
}),
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new AST_Export({
|
||||||
|
start: start,
|
||||||
|
is_default: is_default,
|
||||||
|
exported_names: exported_names,
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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({
|
||||||
|
|||||||
32
lib/scope.js
32
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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -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);
|
||||||
@@ -255,6 +273,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);
|
||||||
|
|
||||||
|
|||||||
@@ -243,9 +243,22 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
self.expression = self.expression.transform(tw);
|
self.expression = self.expression.transform(tw);
|
||||||
});
|
});
|
||||||
|
|
||||||
_(AST_Export, function(self, 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) {
|
||||||
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.19",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -185,6 +185,51 @@ async_identifiers: {
|
|||||||
node_version: ">=8"
|
node_version: ">=8"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: add test when supported by parser
|
/* FIXME: add test when supported by parser
|
||||||
async_arrow: {
|
async_arrow: {
|
||||||
input: {
|
input: {
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
|||||||
156
test/compress/export.js
Normal file
156
test/compress/export.js
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
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 a = 1;
|
||||||
|
const c = 2;
|
||||||
|
var n = 3;
|
||||||
|
export { a as LET, c as CONST, n 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 f } from "stuff";
|
||||||
|
console.log(o, f);
|
||||||
|
export { o as qux };
|
||||||
|
export { f 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 = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
|||||||
@@ -664,3 +664,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{};"
|
||||||
|
}
|
||||||
|
|||||||
@@ -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: {
|
||||||
@@ -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(n,o){return n-o};"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_mangle_3: {
|
export_mangle_3: {
|
||||||
@@ -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(n,r){return n-r+n}};"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_mangle_5: {
|
export_mangle_5: {
|
||||||
@@ -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 {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -178,3 +178,66 @@ 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"
|
||||||
|
}
|
||||||
|
|||||||
@@ -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(){};
|
||||||
3
test/input/invalid/import.js
Normal file
3
test/input/invalid/import.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
import A from "B";
|
||||||
|
}
|
||||||
@@ -533,6 +533,66 @@ 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 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,
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ var assert = require("assert");
|
|||||||
var uglify = require("../node");
|
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);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user