Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6335b5fd8a | ||
|
|
daa8319b8a | ||
|
|
d5599604e8 | ||
|
|
072933f1d5 | ||
|
|
39df3a1680 | ||
|
|
03c5ecb2e3 | ||
|
|
40ef074cb3 | ||
|
|
78e3936cd4 | ||
|
|
e7be38b42a | ||
|
|
44394e61c9 | ||
|
|
f9055df44d | ||
|
|
51bdb7281b |
268
lib/compress.js
268
lib/compress.js
@@ -814,14 +814,91 @@ merge(Compressor.prototype, {
|
||||
def(AST_Assign, function(tw, descend, compressor) {
|
||||
var node = this;
|
||||
var left = node.left;
|
||||
if (node.operator == "=" && left.equivalent_to(node.right) && !left.has_side_effects(compressor)) {
|
||||
node.right.walk(tw);
|
||||
walk_prop(left);
|
||||
node.__drop = true;
|
||||
} else if (!(left instanceof AST_Destructured || left instanceof AST_SymbolRef)) {
|
||||
var scan = left instanceof AST_Destructured || left instanceof AST_SymbolRef;
|
||||
switch (node.operator) {
|
||||
case "=":
|
||||
if (left.equivalent_to(node.right) && !left.has_side_effects(compressor)) {
|
||||
node.right.walk(tw);
|
||||
walk_prop(left);
|
||||
node.__drop = true;
|
||||
return true;
|
||||
}
|
||||
if (scan) {
|
||||
walk_assign();
|
||||
return true;
|
||||
}
|
||||
mark_assignment_to_arguments(left);
|
||||
return;
|
||||
} else if (node.operator == "=") {
|
||||
case "&&=":
|
||||
case "||=":
|
||||
case "??=":
|
||||
left.walk(tw);
|
||||
push(tw);
|
||||
if (scan) {
|
||||
walk_assign();
|
||||
} else {
|
||||
mark_assignment_to_arguments(left);
|
||||
node.right.walk(tw);
|
||||
}
|
||||
pop(tw);
|
||||
return true;
|
||||
default:
|
||||
if (!scan) {
|
||||
mark_assignment_to_arguments(left);
|
||||
return;
|
||||
}
|
||||
var d = left.definition();
|
||||
d.assignments++;
|
||||
var fixed = d.fixed;
|
||||
if (is_modified(compressor, tw, node, node, 0)) {
|
||||
d.fixed = false;
|
||||
return;
|
||||
}
|
||||
var safe = safe_to_read(tw, d);
|
||||
node.right.walk(tw);
|
||||
if (safe && !left.in_arg && safe_to_assign(tw, d)) {
|
||||
push_ref(d, left);
|
||||
mark(tw, d);
|
||||
if (d.single_use) d.single_use = false;
|
||||
left.fixed = d.fixed = function() {
|
||||
return make_node(AST_Binary, node, {
|
||||
operator: node.operator.slice(0, -1),
|
||||
left: make_ref(left, fixed),
|
||||
right: node.right
|
||||
});
|
||||
};
|
||||
left.fixed.assigns = !fixed || !fixed.assigns ? [] : fixed.assigns.slice();
|
||||
left.fixed.assigns.push(node);
|
||||
} else {
|
||||
left.walk(tw);
|
||||
d.fixed = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function walk_prop(lhs) {
|
||||
if (lhs instanceof AST_Dot) {
|
||||
walk_prop(lhs.expression);
|
||||
} else if (lhs instanceof AST_Sub) {
|
||||
walk_prop(lhs.expression);
|
||||
lhs.property.walk(tw);
|
||||
} else if (lhs instanceof AST_SymbolRef) {
|
||||
var d = lhs.definition();
|
||||
push_ref(d, lhs);
|
||||
if (d.fixed) {
|
||||
lhs.fixed = d.fixed;
|
||||
if (lhs.fixed.assigns) {
|
||||
lhs.fixed.assigns.push(node);
|
||||
} else {
|
||||
lhs.fixed.assigns = [ node ];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lhs.walk(tw);
|
||||
}
|
||||
}
|
||||
|
||||
function walk_assign() {
|
||||
node.right.walk(tw);
|
||||
scan_declaration(tw, compressor, left, function() {
|
||||
return node.right;
|
||||
@@ -849,56 +926,6 @@ merge(Compressor.prototype, {
|
||||
d.fixed = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var d = left.definition();
|
||||
d.assignments++;
|
||||
var fixed = d.fixed;
|
||||
if (is_modified(compressor, tw, node, node, 0)) {
|
||||
d.fixed = false;
|
||||
return;
|
||||
}
|
||||
var safe = safe_to_read(tw, d);
|
||||
node.right.walk(tw);
|
||||
if (safe && !left.in_arg && safe_to_assign(tw, d)) {
|
||||
push_ref(d, left);
|
||||
mark(tw, d);
|
||||
if (d.single_use) d.single_use = false;
|
||||
left.fixed = d.fixed = function() {
|
||||
return make_node(AST_Binary, node, {
|
||||
operator: node.operator.slice(0, -1),
|
||||
left: make_ref(left, fixed),
|
||||
right: node.right
|
||||
});
|
||||
};
|
||||
left.fixed.assigns = !fixed || !fixed.assigns ? [] : fixed.assigns.slice();
|
||||
left.fixed.assigns.push(node);
|
||||
} else {
|
||||
left.walk(tw);
|
||||
d.fixed = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
function walk_prop(lhs) {
|
||||
if (lhs instanceof AST_Dot) {
|
||||
walk_prop(lhs.expression);
|
||||
} else if (lhs instanceof AST_Sub) {
|
||||
walk_prop(lhs.expression);
|
||||
lhs.property.walk(tw);
|
||||
} else if (lhs instanceof AST_SymbolRef) {
|
||||
var d = lhs.definition();
|
||||
push_ref(d, lhs);
|
||||
if (d.fixed) {
|
||||
lhs.fixed = d.fixed;
|
||||
if (lhs.fixed.assigns) {
|
||||
lhs.fixed.assigns.push(node);
|
||||
} else {
|
||||
lhs.fixed.assigns = [ node ];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lhs.walk(tw);
|
||||
}
|
||||
}
|
||||
});
|
||||
def(AST_Binary, function(tw) {
|
||||
@@ -971,7 +998,7 @@ merge(Compressor.prototype, {
|
||||
if (prop.key instanceof AST_Node) prop.key.walk(tw);
|
||||
return prop.value;
|
||||
}).forEach(function(prop) {
|
||||
if (prop.static) {
|
||||
if (prop.static && (prop.value instanceof AST_Lambda || !prop.value.contains_this())) {
|
||||
prop.value.walk(tw);
|
||||
} else {
|
||||
push(tw);
|
||||
@@ -1799,6 +1826,18 @@ merge(Compressor.prototype, {
|
||||
can_replace = replace;
|
||||
return signal_abort(node);
|
||||
}
|
||||
// Scan but don't replace inside block scope with colliding variable
|
||||
if (node instanceof AST_BlockScope
|
||||
&& !(node instanceof AST_Scope)
|
||||
&& !(node.variables && node.variables.all(function(def) {
|
||||
return !lvalues.has(def.name);
|
||||
}))) {
|
||||
var replace = can_replace;
|
||||
can_replace = false;
|
||||
if (!handle_custom_scan_order(node, scanner)) descend(node, scanner);
|
||||
can_replace = replace;
|
||||
return signal_abort(node);
|
||||
}
|
||||
return handle_custom_scan_order(node, scanner);
|
||||
}, signal_abort);
|
||||
var multi_replacer = new TreeTransformer(function(node) {
|
||||
@@ -1937,13 +1976,6 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
// Skip (non-executed) functions
|
||||
if (node instanceof AST_Scope) return node;
|
||||
// Stop upon collision with block-scoped variables
|
||||
if (!(node.variables && node.variables.all(function(def) {
|
||||
return !lvalues.has(def.name);
|
||||
}))) {
|
||||
abort = true;
|
||||
return node;
|
||||
}
|
||||
// Scan object only in a for-in/of statement
|
||||
if (node instanceof AST_ForEnumeration) {
|
||||
node.object = node.object.transform(tt);
|
||||
@@ -1979,7 +2011,9 @@ merge(Compressor.prototype, {
|
||||
|
||||
function should_stop(node, parent) {
|
||||
if (node === rvalue) return true;
|
||||
if (parent instanceof AST_For) return node !== parent.init;
|
||||
if (parent instanceof AST_For) {
|
||||
if (node !== parent.init) return true;
|
||||
}
|
||||
if (node instanceof AST_Assign) {
|
||||
return node.operator != "=" && lhs.equivalent_to(node.left);
|
||||
}
|
||||
@@ -2014,7 +2048,8 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function in_conditional(node, parent) {
|
||||
if (parent instanceof AST_Binary) return lazy_op[parent.operator] && parent.left !== node;
|
||||
if (parent instanceof AST_Assign) return parent.left !== node && lazy_op[parent.operator.slice(0, -1)];
|
||||
if (parent instanceof AST_Binary) return parent.left !== node && lazy_op[parent.operator];
|
||||
if (parent instanceof AST_Case) return parent.expression !== node;
|
||||
if (parent instanceof AST_Conditional) return parent.condition !== node;
|
||||
return parent instanceof AST_If && parent.condition !== node;
|
||||
@@ -2356,21 +2391,36 @@ merge(Compressor.prototype, {
|
||||
return null;
|
||||
}
|
||||
|
||||
function find_stop_logical(parent, op, level) {
|
||||
var node;
|
||||
do {
|
||||
node = parent;
|
||||
parent = scanner.parent(++level);
|
||||
} while (parent instanceof AST_Assign && parent.operator.slice(0, -1) == op
|
||||
|| parent instanceof AST_Binary && parent.operator == op);
|
||||
return node;
|
||||
}
|
||||
|
||||
function find_stop_value(node, level) {
|
||||
var parent = scanner.parent(level);
|
||||
if (parent instanceof AST_Array) return find_stop_value(parent, level + 1);
|
||||
if (parent instanceof AST_Assign) return may_throw(parent) || parent.left.match_symbol(function(ref) {
|
||||
return ref instanceof AST_SymbolRef && (lhs.name == ref.name || value_def.name == ref.name);
|
||||
}) ? node : find_stop_value(parent, level + 1);
|
||||
if (parent instanceof AST_Binary) {
|
||||
if (lazy_op[parent.operator] && parent.left !== node) {
|
||||
do {
|
||||
node = parent;
|
||||
parent = scanner.parent(++level);
|
||||
} while (parent instanceof AST_Binary && parent.operator == node.operator);
|
||||
return node;
|
||||
if (parent instanceof AST_Assign) {
|
||||
if (may_throw(parent)) return node;
|
||||
if (parent.left.match_symbol(function(ref) {
|
||||
return ref instanceof AST_SymbolRef && (lhs.name == ref.name || value_def.name == ref.name);
|
||||
})) return node;
|
||||
var op;
|
||||
if (parent.left === node || !lazy_op[op = parent.operator.slice(0, -1)]) {
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
return find_stop_value(parent, level + 1);
|
||||
return find_stop_logical(parent, op, level);
|
||||
}
|
||||
if (parent instanceof AST_Binary) {
|
||||
var op;
|
||||
if (parent.left === node || !lazy_op[op = parent.operator]) {
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
return find_stop_logical(parent, op, level);
|
||||
}
|
||||
if (parent instanceof AST_Call) return parent;
|
||||
if (parent instanceof AST_Case) {
|
||||
@@ -3659,20 +3709,25 @@ merge(Compressor.prototype, {
|
||||
(function(def) {
|
||||
def(AST_Node, return_false);
|
||||
def(AST_Array, return_true);
|
||||
def(AST_Assign, function(compressor) {
|
||||
return this.operator != "=" || this.right.is_defined(compressor);
|
||||
});
|
||||
def(AST_Binary, function(compressor) {
|
||||
switch (this.operator) {
|
||||
function is_binary_defined(compressor, op, node) {
|
||||
switch (op) {
|
||||
case "&&":
|
||||
return this.left.is_defined(compressor) && this.right.is_defined(compressor);
|
||||
return node.left.is_defined(compressor) && node.right.is_defined(compressor);
|
||||
case "||":
|
||||
return this.left.is_truthy() || this.right.is_defined(compressor);
|
||||
return node.left.is_truthy() || node.right.is_defined(compressor);
|
||||
case "??":
|
||||
return this.left.is_defined(compressor) || this.right.is_defined(compressor);
|
||||
return node.left.is_defined(compressor) || node.right.is_defined(compressor);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
def(AST_Assign, function(compressor) {
|
||||
var op = this.operator;
|
||||
if (op == "=") return this.right.is_defined(compressor);
|
||||
return is_binary_defined(compressor, op.slice(0, -1), this);
|
||||
});
|
||||
def(AST_Binary, function(compressor) {
|
||||
return is_binary_defined(compressor, this.operator, this);
|
||||
});
|
||||
def(AST_Conditional, function(compressor) {
|
||||
return this.consequent.is_defined(compressor) && this.alternative.is_defined(compressor);
|
||||
@@ -5285,8 +5340,9 @@ merge(Compressor.prototype, {
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
if (node instanceof AST_Assign) {
|
||||
var lhs = node.left;
|
||||
var rhs = node.right;
|
||||
if (lhs instanceof AST_Destructured) {
|
||||
node.right.walk(tw);
|
||||
rhs.walk(tw);
|
||||
var marker = new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Destructured) return;
|
||||
if (node instanceof AST_DefaultValue) {
|
||||
@@ -5314,9 +5370,17 @@ merge(Compressor.prototype, {
|
||||
lhs.walk(marker);
|
||||
return true;
|
||||
}
|
||||
if (lazy_op[node.operator.slice(0, -1)]) {
|
||||
lhs.walk(tw);
|
||||
push();
|
||||
rhs.walk(tw);
|
||||
if (lhs instanceof AST_SymbolRef) mark(lhs);
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
if (lhs instanceof AST_SymbolRef) {
|
||||
if (node.operator != "=") mark(lhs, true);
|
||||
node.right.walk(tw);
|
||||
rhs.walk(tw);
|
||||
mark(lhs);
|
||||
return true;
|
||||
}
|
||||
@@ -6191,6 +6255,7 @@ merge(Compressor.prototype, {
|
||||
&& var_defs[sym.id] == 1
|
||||
&& sym.assignments == 0
|
||||
&& value instanceof AST_LambdaExpression
|
||||
&& !is_arguments(sym)
|
||||
&& !is_arrow(value)
|
||||
&& assigned_once(value, sym.references)
|
||||
&& can_declare_defun(value)
|
||||
@@ -7211,9 +7276,14 @@ merge(Compressor.prototype, {
|
||||
if (compressor.has_directive("use strict") && expr.is_constant()) return this;
|
||||
}
|
||||
if (left.has_side_effects(compressor)) return this;
|
||||
this.write_only = true;
|
||||
if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) {
|
||||
return this.right.drop_side_effect_free(compressor);
|
||||
var right = this.right;
|
||||
if (lazy_op[this.operator.slice(0, -1)]) {
|
||||
this.write_only = !right.has_side_effects(compressor);
|
||||
} else {
|
||||
this.write_only = true;
|
||||
if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) {
|
||||
return right.drop_side_effect_free(compressor);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
});
|
||||
@@ -7340,10 +7410,18 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
def(AST_Class, function(compressor, first_in_statement) {
|
||||
var exprs = [], values = [];
|
||||
this.properties.forEach(function(prop) {
|
||||
var props = this.properties;
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
var prop = props[i];
|
||||
if (prop.key instanceof AST_Node) exprs.push(prop.key);
|
||||
if (prop instanceof AST_ClassField && prop.static && prop.value) values.push(prop.value);
|
||||
});
|
||||
if (prop instanceof AST_ClassField
|
||||
&& prop.static
|
||||
&& prop.value
|
||||
&& !(prop.value instanceof AST_Lambda)) {
|
||||
if (prop.value.contains_this()) return this;
|
||||
values.push(prop.value);
|
||||
}
|
||||
}
|
||||
var base = this.extends;
|
||||
if (base) {
|
||||
if (base instanceof AST_SymbolRef) base = base.fixed_value();
|
||||
@@ -8752,7 +8830,7 @@ merge(Compressor.prototype, {
|
||||
var can_inline = can_drop && compressor.option("inline") && !self.is_expr_pure(compressor);
|
||||
if (can_inline && stat instanceof AST_Return) {
|
||||
var value = stat.value;
|
||||
if (exp === fn && (!value || value.is_constant_expression()) && safe_from_await_yield(fn)) {
|
||||
if (exp === fn && !fn.name && (!value || value.is_constant_expression()) && safe_from_await_yield(fn)) {
|
||||
return make_sequence(self, convert_args(value)).optimize(compressor);
|
||||
}
|
||||
}
|
||||
@@ -11352,7 +11430,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
AST_Arrow.DEFMETHOD("contains_this", return_false);
|
||||
AST_AsyncArrow.DEFMETHOD("contains_this", return_false);
|
||||
AST_Scope.DEFMETHOD("contains_this", function() {
|
||||
AST_Node.DEFMETHOD("contains_this", function() {
|
||||
var result;
|
||||
var self = this;
|
||||
self.walk(new TreeWalker(function(node) {
|
||||
|
||||
@@ -104,12 +104,15 @@ var OPERATORS = makePredicate([
|
||||
">>=",
|
||||
"<<=",
|
||||
">>>=",
|
||||
"&=",
|
||||
"|=",
|
||||
"^=",
|
||||
"&=",
|
||||
"&&",
|
||||
"||",
|
||||
"??",
|
||||
"&&=",
|
||||
"||=",
|
||||
"??=",
|
||||
]);
|
||||
|
||||
var NEWLINE_CHARS = "\n\r\u2028\u2029";
|
||||
@@ -653,7 +656,7 @@ var UNARY_PREFIX = makePredicate("typeof void delete -- ++ ! ~ - +");
|
||||
|
||||
var UNARY_POSTFIX = makePredicate("-- ++");
|
||||
|
||||
var ASSIGNMENT = makePredicate("= += -= /= *= %= **= >>= <<= >>>= |= ^= &=");
|
||||
var ASSIGNMENT = makePredicate("= += -= /= *= %= **= >>= <<= >>>= &= |= ^= &&= ||= ??=");
|
||||
|
||||
var PRECEDENCE = function(a, ret) {
|
||||
for (var i = 0; i < a.length;) {
|
||||
|
||||
@@ -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.13.2",
|
||||
"version": "3.13.3",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -475,3 +475,200 @@ issue_4521: {
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
logical_assignments: {
|
||||
input: {
|
||||
var a = 42, b = null, c;
|
||||
a &&= "foo";
|
||||
b ||= "bar";
|
||||
c ??= "baz";
|
||||
console.log(a, b, c);
|
||||
}
|
||||
expect_exact: 'var a=42,b=null,c;a&&="foo";b||="bar";c??="baz";console.log(a,b,c);'
|
||||
expect_stdout: "foo bar baz"
|
||||
node_version: ">=15"
|
||||
}
|
||||
|
||||
logical_collapse_vars: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL", b = false;
|
||||
a = "PASS";
|
||||
b ??= a;
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL", b = false;
|
||||
a = "PASS";
|
||||
b ??= a;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=15"
|
||||
}
|
||||
|
||||
logical_reduce_vars: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS", b = 42;
|
||||
b ??= a = "FAIL";
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS", b = 42;
|
||||
b ??= a = "FAIL";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=15"
|
||||
}
|
||||
|
||||
logical_side_effects: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS", b = 42;
|
||||
b ??= a = "FAIL";
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS", b = 42;
|
||||
b ??= a = "FAIL";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=15"
|
||||
}
|
||||
|
||||
issue_4815_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
42..p &&= a = "FAIL";
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
42..p &&= a = "FAIL";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=15"
|
||||
}
|
||||
|
||||
issue_4815_2: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
42..p &&= a = "FAIL";
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
42..p &&= a = "FAIL";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=15"
|
||||
}
|
||||
|
||||
issue_4819: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
}
|
||||
input: {
|
||||
console.log(void 0 === ([].p &&= 42));
|
||||
}
|
||||
expect: {
|
||||
console.log(void 0 === ([].p &&= 42));
|
||||
}
|
||||
expect_stdout: "true"
|
||||
node_version: ">=15"
|
||||
}
|
||||
|
||||
issue_4827_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
A = "FAIL";
|
||||
var a = A, b = "PASS", c;
|
||||
c &&= b = a, console.log(b);
|
||||
}
|
||||
expect: {
|
||||
A = "FAIL";
|
||||
var a = A, b = "PASS", c;
|
||||
c &&= b = a, console.log(b);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=15"
|
||||
}
|
||||
|
||||
issue_4827_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b = "PASS";
|
||||
function f(c) {
|
||||
a++,
|
||||
c &&= b = a;
|
||||
}
|
||||
f();
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var a = 0, b = "PASS";
|
||||
a++,
|
||||
c &&= b = a;
|
||||
var c;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=15"
|
||||
}
|
||||
|
||||
issue_4827_3: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b, c;
|
||||
a++;
|
||||
c &&= b = a;
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var a = 0, b, c;
|
||||
a++;
|
||||
c &&= b = a;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
node_version: ">=15"
|
||||
}
|
||||
|
||||
@@ -1296,3 +1296,51 @@ issue_4756: {
|
||||
]
|
||||
node_version: ">=12"
|
||||
}
|
||||
|
||||
issue_4821_1: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
class A {
|
||||
static p = void (a = this);
|
||||
}
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
class A {
|
||||
static p = void (a = this);
|
||||
}
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
node_version: ">=12"
|
||||
}
|
||||
|
||||
issue_4821_2: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
class A {
|
||||
static p = void (a = this);
|
||||
}
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
(class {
|
||||
static p = void (a = this);
|
||||
});
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
node_version: ">=12"
|
||||
}
|
||||
|
||||
@@ -2868,7 +2868,7 @@ lvalues_def: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
compound_assignment: {
|
||||
compound_assignment_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
@@ -2887,6 +2887,23 @@ compound_assignment: {
|
||||
expect_stdout: "4"
|
||||
}
|
||||
|
||||
compound_assignment_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
a = 1;
|
||||
for (a += a + 2; console.log(a););
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
a = 1;
|
||||
for (a += a + 2; console.log(a););
|
||||
}
|
||||
expect_stdout: "4"
|
||||
}
|
||||
|
||||
issue_2187_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
|
||||
@@ -1661,3 +1661,23 @@ issue_4588_2_evaluate: {
|
||||
expect_stdout: "1"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4817: {
|
||||
options = {
|
||||
ie8: true,
|
||||
inline: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function f(a = console.log(typeof f)) {
|
||||
return 42;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function f(a = console.log(typeof f)) {
|
||||
return 42;
|
||||
})();
|
||||
}
|
||||
expect_stdout: "function"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
@@ -5991,3 +5991,33 @@ issue_4788: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4823: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function() {
|
||||
{
|
||||
function f() {}
|
||||
var arguments = f();
|
||||
function g() {}
|
||||
var arguments = g;
|
||||
}
|
||||
return f && arguments;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function() {
|
||||
{
|
||||
function f() {}
|
||||
arguments = f();
|
||||
var arguments = function() {};
|
||||
}
|
||||
return f && arguments;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
@@ -172,3 +172,32 @@ issue_4054: {
|
||||
}
|
||||
expect_stdout: "{ p: [Setter] }"
|
||||
}
|
||||
|
||||
issue_4811_1: {
|
||||
input: {
|
||||
for (var PASS in this);
|
||||
console.log(PASS, this, {} < this);
|
||||
}
|
||||
expect: {
|
||||
for (var PASS in this);
|
||||
console.log(PASS, this, {} < this);
|
||||
}
|
||||
expect_stdout: "PASS [object global] true"
|
||||
}
|
||||
|
||||
issue_4811_2: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
(async function() {});
|
||||
for (var PASS in this);
|
||||
console.log(PASS, this, {} < this);
|
||||
}
|
||||
expect: {
|
||||
for (var PASS in this);
|
||||
console.log(PASS, this, {} < this);
|
||||
}
|
||||
expect_stdout: "PASS [object global] true"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
@@ -361,4 +361,22 @@ describe("test/reduce.js", function() {
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, read("test/input/reduce/destructured_catch.reduced.js"));
|
||||
});
|
||||
it("Should not enumerate `toString` over global context", function() {
|
||||
if (semver.satisfies(process.version, "<8")) return;
|
||||
var code = [
|
||||
"(async function() {});",
|
||||
"for (var k in this);",
|
||||
"console.log(k, 42 + this);",
|
||||
].join("\n");
|
||||
var result = reduce_test(code, {
|
||||
mangle: false,
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, [
|
||||
"// Can't reproduce test failure",
|
||||
"// minify options: {",
|
||||
'// "mangle": false',
|
||||
"// }",
|
||||
].join("\n"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
echo "::group::GitHub Environment Variables"
|
||||
echo "CI: $CI"
|
||||
echo "GITHUB_WORKFLOW: $GITHUB_WORKFLOW"
|
||||
echo "GITHUB_RUN_ID: $GITHUB_RUN_ID"
|
||||
echo "GITHUB_RUN_NUMBER: $GITHUB_RUN_NUMBER"
|
||||
echo "GITHUB_ACTION: $GITHUB_ACTION"
|
||||
echo "GITHUB_ACTIONS: $GITHUB_ACTIONS"
|
||||
echo "GITHUB_ACTOR: $GITHUB_ACTOR"
|
||||
echo "GITHUB_REPOSITORY: $GITHUB_REPOSITORY"
|
||||
echo "GITHUB_EVENT_NAME: $GITHUB_EVENT_NAME"
|
||||
echo "GITHUB_EVENT_PATH: $GITHUB_EVENT_PATH"
|
||||
echo "GITHUB_WORKSPACE: $GITHUB_WORKSPACE"
|
||||
echo "GITHUB_SHA: $GITHUB_SHA"
|
||||
echo "GITHUB_REF: $GITHUB_REF"
|
||||
echo "GITHUB_HEAD_REF: $GITHUB_HEAD_REF"
|
||||
echo "GITHUB_BASE_REF: $GITHUB_BASE_REF"
|
||||
echo "GITHUB_SERVER_URL: $GITHUB_SERVER_URL"
|
||||
echo "GITHUB_API_URL: $GITHUB_API_URL"
|
||||
echo "GITHUB_GRAPHQL_URL: $GITHUB_GRAPHQL_URL"
|
||||
echo "::endgroup::"
|
||||
|
||||
if command -v timeout &> /dev/null; then NATIVE=1; fi
|
||||
timeout() {
|
||||
T=$1
|
||||
|
||||
@@ -200,9 +200,13 @@ function setup(global, builtins, setup_log, setup_tty) {
|
||||
});
|
||||
Object.defineProperties(global, props);
|
||||
// for Node.js v8+
|
||||
global.toString = function() {
|
||||
return "[object global]";
|
||||
};
|
||||
if (global.toString !== Object.prototype.toString) {
|
||||
global.__proto__ = Object.defineProperty(Object.create(global.__proto__), "toString", {
|
||||
value: function() {
|
||||
return "[object global]";
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function self() {
|
||||
return this;
|
||||
|
||||
@@ -149,6 +149,7 @@ var SUPPORT = function(matrix) {
|
||||
for_of: "for (var a of []);",
|
||||
generator: "function* f(){}",
|
||||
let: "let a;",
|
||||
logical_assignment: "[].p ??= 0;",
|
||||
new_target: "function f() { new.target; }",
|
||||
nullish: "0 ?? 0",
|
||||
rest: "var [...a] = [];",
|
||||
@@ -262,10 +263,13 @@ ASSIGNMENTS = ASSIGNMENTS.concat([
|
||||
">>=",
|
||||
">>>=",
|
||||
]);
|
||||
if (SUPPORT.exponentiation) {
|
||||
ASSIGNMENTS = ASSIGNMENTS.concat(ASSIGNMENTS);
|
||||
ASSIGNMENTS.push("**=");
|
||||
}
|
||||
ASSIGNMENTS = ASSIGNMENTS.concat(ASSIGNMENTS);
|
||||
if (SUPPORT.exponentiation) ASSIGNMENTS.push("**=");
|
||||
if (SUPPORT.logical_assignment) ASSIGNMENTS = ASSIGNMENTS.concat([
|
||||
"&&=",
|
||||
"||=",
|
||||
"??=",
|
||||
]);
|
||||
|
||||
var UNARY_SAFE = [
|
||||
"+",
|
||||
@@ -2202,8 +2206,7 @@ function log(options) {
|
||||
function sort_globals(code) {
|
||||
var globals = run_code("throw Object.keys(this).sort(" + function(global) {
|
||||
return function(m, n) {
|
||||
return (n == "toString") - (m == "toString")
|
||||
|| (typeof global[n] == "function") - (typeof global[m] == "function")
|
||||
return (typeof global[n] == "function") - (typeof global[m] == "function")
|
||||
|| (m < n ? -1 : m > n ? 1 : 0);
|
||||
};
|
||||
} + "(this));" + code);
|
||||
|
||||
Reference in New Issue
Block a user