Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9ef659bcb | ||
|
|
35c2149dbd | ||
|
|
89a35f9fcd | ||
|
|
1a4e99dc2d | ||
|
|
cb870f6fd6 | ||
|
|
a0c0c294c5 | ||
|
|
fbdb7eeda3 | ||
|
|
1bc0fccc8c | ||
|
|
20252c6483 | ||
|
|
e396912ea2 | ||
|
|
5ebfa78f56 | ||
|
|
950609f578 |
16
README.md
16
README.md
@@ -1373,3 +1373,19 @@ To allow for better optimizations, the compiler makes various assumptions:
|
||||
// TypeError: const 'a' has already been declared
|
||||
```
|
||||
UglifyJS may modify the input which in turn may suppress those errors.
|
||||
- Later versions of Chrome and Node.js will give incorrect results with the
|
||||
following:
|
||||
```javascript
|
||||
try {
|
||||
class A {
|
||||
static 42;
|
||||
static get 42() {}
|
||||
}
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL");
|
||||
}
|
||||
// Expected: "PASS"
|
||||
// Actual: "FAIL"
|
||||
```
|
||||
UglifyJS may modify the input which in turn may suppress those errors.
|
||||
|
||||
@@ -649,7 +649,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
if (!HOP(tw.safe_ids, def.id)) {
|
||||
if (!safe) return false;
|
||||
if (safe.read) {
|
||||
if (safe.read || tw.in_loop) {
|
||||
var scope = tw.find_parent(AST_BlockScope);
|
||||
if (scope instanceof AST_Class) return false;
|
||||
if (def.scope.resolve() !== scope.resolve()) return false;
|
||||
@@ -6081,18 +6081,15 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
if (node instanceof AST_Call) {
|
||||
var exp = node.expression;
|
||||
var tail = exp.tail_node();
|
||||
if (!(tail instanceof AST_LambdaExpression)) {
|
||||
if (exp instanceof AST_LambdaExpression) {
|
||||
node.args.forEach(function(arg) {
|
||||
arg.walk(tw);
|
||||
});
|
||||
exp.walk(tw);
|
||||
} else {
|
||||
descend();
|
||||
return mark_expression(exp);
|
||||
mark_expression(exp);
|
||||
}
|
||||
if (exp !== tail) exp.expressions.slice(0, -1).forEach(function(node) {
|
||||
node.walk(tw);
|
||||
});
|
||||
node.args.forEach(function(arg) {
|
||||
arg.walk(tw);
|
||||
});
|
||||
tail.walk(tw);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Class) {
|
||||
@@ -6105,9 +6102,10 @@ Compressor.prototype.compress = function(node) {
|
||||
if (prop.static) {
|
||||
prop.value.walk(tw);
|
||||
} else {
|
||||
push(tw);
|
||||
push();
|
||||
segment.block = node;
|
||||
prop.value.walk(tw);
|
||||
pop(tw);
|
||||
pop();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
@@ -6172,6 +6170,8 @@ Compressor.prototype.compress = function(node) {
|
||||
if (node === self) root = segment;
|
||||
if (node instanceof AST_Lambda) {
|
||||
if (node.name) references[node.name.definition().id] = false;
|
||||
var parent = tw.parent();
|
||||
var in_iife = parent && parent.TYPE == "Call" && parent.expression === node;
|
||||
var marker = node.uses_arguments && !tw.has_directive("use strict") ? function(node) {
|
||||
if (node instanceof AST_SymbolFunarg) references[node.definition().id] = false;
|
||||
} : function(node) {
|
||||
@@ -6187,11 +6187,13 @@ Compressor.prototype.compress = function(node) {
|
||||
|| node.parent_scope.find_variable(ref.name) === def)) {
|
||||
references[def.id] = false;
|
||||
references[ldef.id] = false;
|
||||
} else {
|
||||
} else if (in_iife) {
|
||||
var save = segment;
|
||||
pop();
|
||||
mark(ref, true);
|
||||
segment = save;
|
||||
} else {
|
||||
mark(ref, true);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
@@ -6214,7 +6216,8 @@ Compressor.prototype.compress = function(node) {
|
||||
} else {
|
||||
descend();
|
||||
}
|
||||
return mark_expression(exp);
|
||||
mark_expression(exp);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Switch) {
|
||||
node.expression.walk(tw);
|
||||
@@ -6246,9 +6249,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if (node instanceof AST_Try) {
|
||||
var save_try = in_try;
|
||||
in_try = node;
|
||||
var save = segment;
|
||||
walk_body(node, tw);
|
||||
segment = save;
|
||||
if (node.bcatch) {
|
||||
if (node.bcatch.argname) node.bcatch.argname.mark_symbol(function(node) {
|
||||
if (node instanceof AST_SymbolCatch) {
|
||||
@@ -6266,7 +6267,6 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
}
|
||||
in_try = save_try;
|
||||
segment = save;
|
||||
if (node.bfinally) node.bfinally.walk(tw);
|
||||
return true;
|
||||
}
|
||||
@@ -6316,11 +6316,9 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
|
||||
function mark_expression(exp) {
|
||||
if (compressor.option("ie")) {
|
||||
var sym = root_expr(exp);
|
||||
if (sym instanceof AST_SymbolRef) sym.walk(tw);
|
||||
}
|
||||
return true;
|
||||
if (!compressor.option("ie")) return;
|
||||
var sym = root_expr(exp);
|
||||
if (sym instanceof AST_SymbolRef) sym.walk(tw);
|
||||
}
|
||||
|
||||
function walk_cond(condition, consequent, alternative) {
|
||||
@@ -11142,9 +11140,15 @@ Compressor.prototype.compress = function(node) {
|
||||
&& assign instanceof AST_Assign
|
||||
&& assign.operator == "="
|
||||
&& self.left.equivalent_to(assign.left)) {
|
||||
self.right = assign.right;
|
||||
assign.right = self;
|
||||
return assign;
|
||||
return make_node(AST_Assign, self, {
|
||||
operator: "=",
|
||||
left: assign.left,
|
||||
right: make_node(AST_Binary, self, {
|
||||
operator: self.operator,
|
||||
left: self.left,
|
||||
right: assign.right,
|
||||
}),
|
||||
}).optimize(compressor);
|
||||
}
|
||||
}
|
||||
if (compressor.option("comparisons")) switch (self.operator) {
|
||||
@@ -13382,7 +13386,7 @@ Compressor.prototype.compress = function(node) {
|
||||
});
|
||||
var body = [];
|
||||
fn.variables.each(function(def, name) {
|
||||
if (name == "arguments") return;
|
||||
if (!arrow && name == "arguments" && def.orig.length == 1) return;
|
||||
names.set(name, true);
|
||||
scope.enclosed.push(def);
|
||||
scope.variables.set(name, def);
|
||||
|
||||
@@ -469,6 +469,7 @@ AST_Lambda.DEFMETHOD("init_vars", function(parent_scope) {
|
||||
this.uses_arguments = false;
|
||||
this.def_variable(new AST_SymbolFunarg({
|
||||
name: "arguments",
|
||||
scope: this,
|
||||
start: this.start,
|
||||
end: this.end,
|
||||
}));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.15.4",
|
||||
"version": "3.15.5",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -1018,3 +1018,91 @@ issue_5356: {
|
||||
expect_stdout: "NaN"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_5414_1: {
|
||||
options = {
|
||||
arrows: true,
|
||||
if_return: true,
|
||||
inline: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
(() => {
|
||||
(() => {
|
||||
if (!console)
|
||||
var arguments = 42;
|
||||
while (console.log(arguments));
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(() => {
|
||||
if (!console)
|
||||
var arguments = 42;
|
||||
while (console.log(arguments));
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_5414_2: {
|
||||
options = {
|
||||
arrows: true,
|
||||
inline: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
(() => {
|
||||
(() => {
|
||||
if (!console)
|
||||
var arguments = 42;
|
||||
while (console.log(arguments));
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(() => {
|
||||
if (!console)
|
||||
var arguments = 42;
|
||||
while (console.log(arguments));
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_5416: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
loops: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var f = () => {
|
||||
while ((() => {
|
||||
console;
|
||||
var a = function g(arguments) {
|
||||
console.log(arguments);
|
||||
}();
|
||||
})());
|
||||
};
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
var f = () => {
|
||||
{
|
||||
arguments = void 0;
|
||||
console;
|
||||
console.log(arguments);
|
||||
var arguments;
|
||||
}
|
||||
};
|
||||
f();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
@@ -2571,3 +2571,33 @@ issue_5389: {
|
||||
expect_stdout: "PASS PASS"
|
||||
node_version: ">=12"
|
||||
}
|
||||
|
||||
issue_5436: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
class A {
|
||||
p = a;
|
||||
}
|
||||
var b = "FAIL";
|
||||
A == b && b();
|
||||
return new A();
|
||||
}
|
||||
console.log(f("PASS").p);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
class A {
|
||||
p = a;
|
||||
}
|
||||
var b = "FAIL";
|
||||
A == b && b();
|
||||
return new A();
|
||||
}
|
||||
console.log(f("PASS").p);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=12"
|
||||
}
|
||||
|
||||
@@ -3535,3 +3535,34 @@ issue_5405_2: {
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_5423: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a, b;
|
||||
function f({
|
||||
[function() {
|
||||
if (++a)
|
||||
return 42;
|
||||
}()]: c
|
||||
}) {}
|
||||
f(b = f);
|
||||
console.log(typeof b);
|
||||
}
|
||||
expect: {
|
||||
var a, b;
|
||||
function f({
|
||||
[function() {
|
||||
if (++a)
|
||||
return 42;
|
||||
}()]: c
|
||||
}) {}
|
||||
f(b = f);
|
||||
console.log(typeof b);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
@@ -3702,3 +3702,33 @@ issue_5182: {
|
||||
]
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_5420: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
do {
|
||||
var a = "FAIL 1";
|
||||
a && a.p;
|
||||
a = "FAIL 2";
|
||||
try {
|
||||
continue;
|
||||
} catch (e) {}
|
||||
var b = "FAIL 3";
|
||||
} while (console.log(b || "PASS"));
|
||||
}
|
||||
expect: {
|
||||
do {
|
||||
var a = "FAIL 1";
|
||||
a && a.p;
|
||||
a = "FAIL 2";
|
||||
try {
|
||||
continue;
|
||||
} catch (e) {}
|
||||
var b = "FAIL 3";
|
||||
} while (console.log(b || "PASS"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -7861,3 +7861,38 @@ issue_5324: {
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_5434: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
for (var i = 0; i < 2; i++) {
|
||||
var b = "FAIL";
|
||||
f && f();
|
||||
a = b;
|
||||
var f = function() {
|
||||
b = "PASS";
|
||||
};
|
||||
}
|
||||
return a;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
for (var i = 0; i < 2; i++) {
|
||||
var b = "FAIL";
|
||||
f && f();
|
||||
a = b;
|
||||
var f = function() {
|
||||
b = "PASS";
|
||||
};
|
||||
}
|
||||
return a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -1525,3 +1525,25 @@ issue_5385_2: {
|
||||
]
|
||||
node_version: ">=10"
|
||||
}
|
||||
|
||||
issue_5425: {
|
||||
options = {
|
||||
assignments: true,
|
||||
ie: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
yields: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
var b = function* f() {}(a ? a = "PASS" : 42);
|
||||
console.log(a, typeof f);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
(function* f() {})(a && (a = "PASS"));
|
||||
console.log(a, typeof f);
|
||||
}
|
||||
expect_stdout: "PASS undefined"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
@@ -52,8 +52,11 @@ exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expec
|
||||
return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual);
|
||||
};
|
||||
exports.patch_module_statements = function(code) {
|
||||
var count = 0, has_default = "", imports = [];
|
||||
code = code.replace(/\bexport(?:\s*\{[^{}]*}\s*?(?:$|\n|;)|\s+default\b(?:\s*(\(|\{|class\s*\{|class\s+(?=extends\b)|(?:async\s+)?function\s*(?:\*\s*)?\())?|\b)/g, function(match, header) {
|
||||
var count = 0, has_default = "", imports = [], strict_mode = "";
|
||||
code = code.replace(/^\s*("|')use strict\1\s*;?/, function(match) {
|
||||
strict_mode = match;
|
||||
return "";
|
||||
}).replace(/\bexport(?:\s*\{[^{}]*}\s*?(?:$|\n|;)|\s+default\b(?:\s*(\(|\{|class\s*\{|class\s+(?=extends\b)|(?:async\s+)?function\s*(?:\*\s*)?\())?|\b)/g, function(match, header) {
|
||||
if (/^export\s+default/.test(match)) has_default = "var _uglify_export_default_;";
|
||||
if (!header) return "";
|
||||
if (header.length == 1) return "0, " + header;
|
||||
@@ -78,7 +81,7 @@ exports.patch_module_statements = function(code) {
|
||||
return "";
|
||||
});
|
||||
imports.push("");
|
||||
return has_default + imports.join("\n") + code;
|
||||
return strict_mode + has_default + imports.join("\n") + code;
|
||||
};
|
||||
|
||||
function is_error(result) {
|
||||
|
||||
@@ -128,7 +128,7 @@ for (var i = 2; i < process.argv.length; ++i) {
|
||||
|
||||
var SUPPORT = function(matrix) {
|
||||
for (var name in matrix) {
|
||||
matrix[name] = typeof sandbox.run_code(matrix[name]) == "string";
|
||||
matrix[name] = !sandbox.is_error(sandbox.run_code(matrix[name]));
|
||||
}
|
||||
return matrix;
|
||||
}({
|
||||
@@ -1824,7 +1824,13 @@ function createClassLiteral(recurmax, stmtDepth, canThrow, name) {
|
||||
declared.push(internal);
|
||||
}
|
||||
if (SUPPORT.class_field && rng(2)) {
|
||||
s += internal || createObjectKey(recurmax, stmtDepth, canThrow);
|
||||
if (internal) {
|
||||
s += internal;
|
||||
} else if (fixed && bug_static_class_field) {
|
||||
s += getDotKey();
|
||||
} else {
|
||||
s += createObjectKey(recurmax, stmtDepth, canThrow);
|
||||
}
|
||||
if (rng(5)) {
|
||||
async = bug_async_class_await && fixed && 0;
|
||||
generator = false;
|
||||
@@ -2110,7 +2116,7 @@ function try_beautify(code, toplevel, result, printfn, options) {
|
||||
} else if (options) {
|
||||
var uglified = UglifyJS.minify(beautified.code, JSON.parse(options));
|
||||
var expected, actual;
|
||||
if (typeof uglify_code != "string" || uglified.error) {
|
||||
if (sandbox.is_error(uglify_code) || uglified.error) {
|
||||
expected = uglify_code;
|
||||
actual = uglified.error;
|
||||
} else {
|
||||
@@ -2147,7 +2153,7 @@ function log_suspects(minify_options, component) {
|
||||
m[component] = o;
|
||||
m.validate = true;
|
||||
var result = UglifyJS.minify(original_code, m);
|
||||
if (typeof uglify_code != "string") {
|
||||
if (sandbox.is_error(uglify_code)) {
|
||||
return !sandbox.same_stdout(uglify_code, result.error);
|
||||
} else if (result.error) {
|
||||
errorln("Error testing options." + component + "." + name);
|
||||
@@ -2175,7 +2181,7 @@ function log_suspects_global(options, toplevel) {
|
||||
m[component] = false;
|
||||
m.validate = true;
|
||||
var result = UglifyJS.minify(original_code, m);
|
||||
if (typeof uglify_code != "string") {
|
||||
if (sandbox.is_error(uglify_code)) {
|
||||
return !sandbox.same_stdout(uglify_code, result.error);
|
||||
} else if (result.error) {
|
||||
errorln("Error testing options." + component);
|
||||
@@ -2204,7 +2210,16 @@ function log(options) {
|
||||
errorln();
|
||||
errorln();
|
||||
errorln("//-------------------------------------------------------------");
|
||||
if (typeof uglify_code == "string") {
|
||||
if (sandbox.is_error(uglify_code)) {
|
||||
errorln("// !!! uglify failed !!!");
|
||||
errorln(uglify_code);
|
||||
if (original_erred) {
|
||||
errorln();
|
||||
errorln();
|
||||
errorln("original stacktrace:");
|
||||
errorln(original_result);
|
||||
}
|
||||
} else {
|
||||
errorln("// uglified code");
|
||||
try_beautify(uglify_code, toplevel, uglify_result, errorln);
|
||||
errorln();
|
||||
@@ -2213,15 +2228,6 @@ function log(options) {
|
||||
errorln(original_result);
|
||||
errorln("uglified result:");
|
||||
errorln(uglify_result);
|
||||
} else {
|
||||
errorln("// !!! uglify failed !!!");
|
||||
errorln(uglify_code);
|
||||
if (errored) {
|
||||
errorln();
|
||||
errorln();
|
||||
errorln("original stacktrace:");
|
||||
errorln(original_result);
|
||||
}
|
||||
}
|
||||
errorln("//-------------------------------------------------------------");
|
||||
if (!ok) {
|
||||
@@ -2426,22 +2432,23 @@ var beautify_options = {
|
||||
},
|
||||
};
|
||||
var minify_options = require("./options.json");
|
||||
if (typeof sandbox.run_code("A:if (0) B:; else B:;") != "string") {
|
||||
if (sandbox.is_error(sandbox.run_code("A:if (0) B:; else B:;"))) {
|
||||
minify_options.forEach(function(o) {
|
||||
if (!("mangle" in o)) o.mangle = {};
|
||||
if (o.mangle) o.mangle.v8 = true;
|
||||
});
|
||||
}
|
||||
var bug_async_arrow_rest = function() {};
|
||||
if (SUPPORT.arrow && SUPPORT.async && SUPPORT.rest && typeof sandbox.run_code("async (a = f(...[], b)) => 0;") != "string") {
|
||||
if (SUPPORT.arrow && SUPPORT.async && SUPPORT.rest && sandbox.is_error(sandbox.run_code("async (a = f(...[], b)) => 0;"))) {
|
||||
bug_async_arrow_rest = function(ex) {
|
||||
return ex.name == "SyntaxError" && ex.message == "Rest parameter must be last formal parameter";
|
||||
};
|
||||
}
|
||||
var bug_async_class_await = SUPPORT.async && SUPPORT.class_field && typeof sandbox.run_code("var await; async function f() { class A { static p = await; } }") != "string";
|
||||
var bug_for_of_async = SUPPORT.for_await_of && typeof sandbox.run_code("var async; for (async of []);") != "string";
|
||||
var bug_for_of_var = SUPPORT.for_of && SUPPORT.let && typeof sandbox.run_code("try {} catch (e) { for (var e of []); }") != "string";
|
||||
if (SUPPORT.destructuring && typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") {
|
||||
var bug_async_class_await = SUPPORT.async && SUPPORT.class_field && sandbox.is_error(sandbox.run_code("var await; async function f() { class A { static p = await; } }"));
|
||||
var bug_for_of_async = SUPPORT.for_await_of && sandbox.is_error(sandbox.run_code("var async; for (async of []);"));
|
||||
var bug_for_of_var = SUPPORT.for_of && SUPPORT.let && sandbox.is_error(sandbox.run_code("try {} catch (e) { for (var e of []); }"));
|
||||
var bug_static_class_field = SUPPORT.class_field && sandbox.is_error(sandbox.run_code("class A { static 42; static get 42() {} }"));
|
||||
if (SUPPORT.destructuring && sandbox.is_error(sandbox.run_code("console.log([ 1 ], {} = 2);"))) {
|
||||
beautify_options.output.v8 = true;
|
||||
minify_options.forEach(function(o) {
|
||||
if (!("output" in o)) o.output = {};
|
||||
@@ -2450,7 +2457,7 @@ if (SUPPORT.destructuring && typeof sandbox.run_code("console.log([ 1 ], {} = 2)
|
||||
}
|
||||
beautify_options = JSON.stringify(beautify_options);
|
||||
minify_options = minify_options.map(JSON.stringify);
|
||||
var original_code, original_result, errored;
|
||||
var original_code, original_result, original_erred;
|
||||
var uglify_code, uglify_result, ok;
|
||||
for (var round = 1; round <= num_iterations; round++) {
|
||||
process.stdout.write(round + " of " + num_iterations + "\r");
|
||||
@@ -2458,7 +2465,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
original_code = createTopLevelCode();
|
||||
var orig_result = [ run_code(original_code), run_code(original_code, true) ];
|
||||
if (orig_result.some(function(result, toplevel) {
|
||||
if (typeof result == "string") return;
|
||||
if (!sandbox.is_error(result)) return;
|
||||
println();
|
||||
println();
|
||||
println("//=============================================================");
|
||||
@@ -2480,19 +2487,20 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
o.validate = true;
|
||||
uglify_code = UglifyJS.minify(original_code, o);
|
||||
original_result = orig_result[toplevel ? 1 : 0];
|
||||
errored = typeof original_result != "string";
|
||||
original_erred = sandbox.is_error(original_result);
|
||||
if (!uglify_code.error) {
|
||||
uglify_code = uglify_code.code;
|
||||
uglify_result = run_code(uglify_code, toplevel);
|
||||
ok = sandbox.same_stdout(original_result, uglify_result);
|
||||
var uglify_erred = sandbox.is_error(uglify_result);
|
||||
// ignore v8 parser bug
|
||||
if (!ok && bug_async_arrow_rest(uglify_result)) ok = true;
|
||||
if (!ok && uglify_erred && bug_async_arrow_rest(uglify_result)) ok = true;
|
||||
// ignore runtime platform bugs
|
||||
if (!ok && uglify_result.message == "Script execution aborted.") ok = true;
|
||||
if (!ok && uglify_erred && uglify_result.message == "Script execution aborted.") ok = true;
|
||||
// handle difference caused by time-outs
|
||||
if (!ok) {
|
||||
if (errored && is_error_timeout(original_result)) {
|
||||
if (is_error_timeout(uglify_result)) {
|
||||
if (original_erred && is_error_timeout(original_result)) {
|
||||
if (uglify_erred && is_error_timeout(uglify_result)) {
|
||||
// ignore difference in error message
|
||||
ok = true;
|
||||
} else {
|
||||
@@ -2500,21 +2508,23 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
if (!orig_result[toplevel ? 3 : 2]) orig_result[toplevel ? 3 : 2] = run_code(original_code, toplevel, 10000);
|
||||
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
|
||||
}
|
||||
} else if (is_error_timeout(uglify_result)) {
|
||||
} else if (uglify_erred && is_error_timeout(uglify_result)) {
|
||||
// ignore spurious time-outs
|
||||
var waited_result = run_code(uglify_code, toplevel, 10000);
|
||||
ok = sandbox.same_stdout(original_result, waited_result);
|
||||
}
|
||||
}
|
||||
// ignore declaration order of global variables
|
||||
if (!ok && !toplevel && uglify_result.name != "SyntaxError" && original_result.name != "SyntaxError") {
|
||||
ok = sandbox.same_stdout(run_code(sort_globals(original_code)), run_code(sort_globals(uglify_code)));
|
||||
if (!ok && !toplevel) {
|
||||
if (!(original_erred && original_result.name == "SyntaxError") && !(uglify_erred && uglify_result.name == "SyntaxError")) {
|
||||
ok = sandbox.same_stdout(run_code(sort_globals(original_code)), run_code(sort_globals(uglify_code)));
|
||||
}
|
||||
}
|
||||
// ignore numerical imprecision caused by `unsafe_math`
|
||||
if (!ok && o.compress && o.compress.unsafe_math && typeof original_result == typeof uglify_result) {
|
||||
if (typeof original_result == "string") {
|
||||
if (!ok && o.compress && o.compress.unsafe_math) {
|
||||
if (typeof original_result == "string" && typeof uglify_result == "string") {
|
||||
ok = fuzzy_match(original_result, uglify_result);
|
||||
} else if (sandbox.is_error(original_result)) {
|
||||
} else if (original_erred && uglify_erred) {
|
||||
ok = original_result.name == uglify_result.name && fuzzy_match(original_result.message, uglify_result.message);
|
||||
}
|
||||
if (!ok) {
|
||||
@@ -2523,19 +2533,19 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
}
|
||||
}
|
||||
// ignore difference in error message caused by Temporal Dead Zone
|
||||
if (!ok && errored && uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError") ok = true;
|
||||
if (!ok && original_erred && uglify_erred && original_result.name == "ReferenceError" && uglify_result.name == "ReferenceError") ok = true;
|
||||
// ignore difference due to implicit strict-mode in `class`
|
||||
if (!ok && /\bclass\b/.test(original_code)) {
|
||||
var original_strict = run_code('"use strict";\n' + original_code, toplevel);
|
||||
if (/^(Syntax|Type)Error$/.test(uglify_result.name)) {
|
||||
ok = typeof original_strict != "string";
|
||||
if (uglify_erred && /^(Syntax|Type)Error$/.test(uglify_result.name)) {
|
||||
ok = sandbox.is_error(original_strict);
|
||||
} else {
|
||||
ok = sandbox.same_stdout(original_strict, uglify_result);
|
||||
}
|
||||
}
|
||||
// ignore difference in error message caused by `import` symbol redeclaration
|
||||
if (!ok && errored && /\bimport\b/.test(original_code)) {
|
||||
if (is_error_redeclaration(uglify_result) && is_error_redeclaration(original_result)) ok = true;
|
||||
if (!ok && original_erred && uglify_erred && /\bimport\b/.test(original_code)) {
|
||||
if (is_error_redeclaration(original_result) && is_error_redeclaration(uglify_result)) ok = true;
|
||||
}
|
||||
// ignore difference due to `__proto__` assignment
|
||||
if (!ok && /\b__proto__\b/.test(original_code)) {
|
||||
@@ -2544,24 +2554,32 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
ok = sandbox.same_stdout(original_proto, uglify_proto);
|
||||
}
|
||||
// ignore difference in error message caused by `in`
|
||||
if (!ok && errored && is_error_in(uglify_result) && is_error_in(original_result)) ok = true;
|
||||
if (!ok && original_erred && uglify_erred) {
|
||||
if (is_error_in(original_result) && is_error_in(uglify_result)) ok = true;
|
||||
}
|
||||
// ignore difference in error message caused by spread syntax
|
||||
if (!ok && errored && is_error_spread(uglify_result) && is_error_spread(original_result)) ok = true;
|
||||
if (!ok && original_erred && uglify_erred) {
|
||||
if (is_error_spread(original_result) && is_error_spread(uglify_result)) ok = true;
|
||||
}
|
||||
// ignore difference in depth of termination caused by infinite recursion
|
||||
if (!ok && errored && is_error_recursion(original_result)) {
|
||||
if (is_error_recursion(uglify_result) || typeof uglify_result == "string") ok = true;
|
||||
if (!ok && original_erred && is_error_recursion(original_result)) {
|
||||
if (!uglify_erred || is_error_recursion(uglify_result)) ok = true;
|
||||
}
|
||||
// ignore difference in error message caused by destructuring
|
||||
if (!ok && errored && is_error_destructuring(uglify_result) && is_error_destructuring(original_result)) {
|
||||
ok = true;
|
||||
if (!ok && original_erred && uglify_erred) {
|
||||
if (is_error_destructuring(original_result) && is_error_destructuring(uglify_result)) ok = true;
|
||||
}
|
||||
// ignore difference in error message caused by call on class
|
||||
if (!ok && errored && is_error_class_constructor(uglify_result) && is_error_class_constructor(original_result)) {
|
||||
ok = true;
|
||||
if (!ok && original_erred && uglify_erred) {
|
||||
if (is_error_class_constructor(original_result) && is_error_class_constructor(uglify_result)) {
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
// ignore difference in error message caused by setting getter-only property
|
||||
if (!ok && errored && is_error_getter_only_property(uglify_result) && is_error_getter_only_property(original_result)) {
|
||||
ok = true;
|
||||
if (!ok && original_erred && uglify_erred) {
|
||||
if (is_error_getter_only_property(original_result) && is_error_getter_only_property(uglify_result)) {
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
// ignore errors above when caught by try-catch
|
||||
if (!ok) {
|
||||
@@ -2573,7 +2591,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
}
|
||||
} else {
|
||||
uglify_code = uglify_code.error;
|
||||
ok = errored && uglify_code.name == original_result.name;
|
||||
ok = original_erred && uglify_code.name == original_result.name;
|
||||
}
|
||||
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
|
||||
if (!ok && isFinite(num_iterations)) {
|
||||
|
||||
Reference in New Issue
Block a user