Compare commits

...

19 Commits

Author SHA1 Message Date
Alex Lam S.L
4a44d95f09 v3.15.4 2022-04-10 01:16:11 +08:00
David Luhmer
36718948be rename reserved keyword await (#5413) 2022-04-08 00:31:29 +08:00
Alex Lam S.L
21bd4c4a9d fix corner cases in collapse_vars & hoist_vars (#5412)
fixes #5411
2022-04-07 04:12:03 +08:00
Alex Lam S.L
998c9792da fix corner case in inline (#5410)
fixes #5409
2022-04-06 12:23:47 +08:00
Alex Lam S.L
ccd77d70db fix corner case in reduce_vars (#5408)
fixes #5407
2022-04-05 10:09:25 +08:00
Alex Lam S.L
d75a946707 fix corner case in reduce_vars (#5406)
fixes #5405
2022-04-03 21:57:37 +08:00
Alex Lam S.L
696a20f10d patch export default within sandbox correctly (#5404)
fixes #5403
2022-04-03 19:56:19 +08:00
Alex Lam S.L
224c91b6c1 fix corner case in inline (#5402)
fixes #5401
2022-04-03 01:12:53 +08:00
Alex Lam S.L
8065e27a7d patch export default within sandbox correctly (#5400)
fixes #5399
2022-04-02 21:59:28 +08:00
Alex Lam S.L
584e253f33 enahnce collapse_vars (#5398) 2022-04-01 20:26:27 +08:00
Alex Lam S.L
fb5e08e4ec fix corner case in collapse_vars (#5397)
fixes #5396
2022-03-31 20:02:56 +08:00
Alex Lam S.L
e3d328f741 fix corner case in collapse_vars (#5395)
fixes #5394
2022-03-30 01:22:57 +08:00
Alex Lam S.L
8922f08fbf fix corner cases in keep_fnames (#5393) 2022-03-29 03:01:01 +08:00
Alex Lam S.L
15a4074d1a fix corner case in unused (#5392)
fixes #5391
2022-03-28 05:46:43 +08:00
Alex Lam S.L
c624b43739 fix corner case in collapse_vars (#5390)
fixes #5389
2022-03-22 13:05:57 +08:00
Alex Lam S.L
a8e040b133 fix corner case in properties (#5388)
fixes #5387
2022-03-21 00:01:42 +08:00
Alex Lam S.L
5e30f3a48b fix corner case in inline (#5386)
fixes #5385
2022-03-20 22:50:28 +08:00
Alex Lam S.L
46570a4eb6 fix corner case in side_effects (#5383)
fixes #5382
2022-03-12 14:14:30 +08:00
Alex Lam S.L
01b84074d7 fix corner case in evaluate (#5381)
fixes #5380
2022-03-12 13:08:29 +08:00
20 changed files with 738 additions and 144 deletions

View File

@@ -851,6 +851,9 @@ var AST_DefClass = DEFNODE("DefClass", null, {
$propdoc: {
name: "[AST_SymbolDefClass] the name of this class",
},
resolve: function(def_class) {
return def_class ? this : this.parent_scope.resolve();
},
_validate: function() {
if (!(this.name instanceof AST_SymbolDefClass)) throw new Error("name must be AST_SymbolDefClass");
},

View File

@@ -751,6 +751,34 @@ Compressor.prototype.compress = function(node) {
});
}
function make_fixed(save, fn) {
var prev_save, prev_value;
return function() {
var current = save();
if (prev_save !== current) {
prev_save = current;
prev_value = fn(current);
}
return prev_value;
};
}
function make_fixed_default(compressor, node, save) {
var prev_save, prev_seq;
return function() {
var current = save();
var ev;
if (!is_undefined(current, compressor) && (ev = fuzzy_eval(compressor, current, true)) !== undefined) {
return ev instanceof AST_Node ? node : current;
}
if (prev_save !== current) {
prev_save = current;
prev_seq = make_sequence(node, [ current, node.value ]);
}
return prev_seq;
};
}
function scan_declaration(tw, compressor, lhs, fixed, visit) {
var scanner = new TreeWalker(function(node) {
if (node instanceof AST_DefaultValue) {
@@ -759,15 +787,7 @@ Compressor.prototype.compress = function(node) {
node.value.walk(tw);
pop(tw);
var save = fixed;
if (save) fixed = function() {
var value = save();
var ev;
if (is_undefined(value, compressor)
|| (ev = fuzzy_eval(compressor, value, true)) === undefined) {
return make_sequence(node, [ value, node.value ]);
}
return ev instanceof AST_Node ? node : value;
};
if (save) fixed = make_fixed_default(compressor, node, save);
node.name.walk(scanner);
fixed = save;
return true;
@@ -777,18 +797,17 @@ Compressor.prototype.compress = function(node) {
var save = fixed;
node.elements.forEach(function(node, index) {
if (node instanceof AST_Hole) return reset_flags(node);
if (save) fixed = function() {
if (save) fixed = make_fixed(save, function(value) {
return make_node(AST_Sub, node, {
expression: save(),
expression: value,
property: make_node(AST_Number, node, { value: index }),
});
};
});
node.walk(scanner);
});
if (node.rest) {
var fixed_node;
if (save) fixed = compressor.option("rests") && function() {
var value = save();
if (save) fixed = compressor.option("rests") && make_fixed(save, function(value) {
if (!(value instanceof AST_Array)) return node;
for (var i = 0, len = node.elements.length; i < len; i++) {
if (value.elements[i] instanceof AST_Spread) return node;
@@ -796,7 +815,7 @@ Compressor.prototype.compress = function(node) {
if (!fixed_node) fixed_node = make_node(AST_Array, node);
fixed_node.elements = value.elements.slice(len);
return fixed_node;
};
});
node.rest.walk(scanner);
}
fixed = save;
@@ -812,7 +831,7 @@ Compressor.prototype.compress = function(node) {
node.key.walk(tw);
pop(tw);
}
if (save) fixed = function() {
if (save) fixed = make_fixed(save, function(value) {
var key = node.key;
var type = AST_Sub;
if (typeof key == "string") {
@@ -823,10 +842,10 @@ Compressor.prototype.compress = function(node) {
}
}
return make_node(type, node, {
expression: save(),
property: key
expression: value,
property: key,
});
});
};
node.value.walk(scanner);
});
if (node.rest) {
@@ -2040,13 +2059,17 @@ Compressor.prototype.compress = function(node) {
if (is_lhs(node, parent)) {
if (value_def && !hit_rhs) assign_used = true;
return node;
} else if (value_def) {
}
if (!hit_rhs && verify_ref && node.fixed !== lhs.fixed) {
abort = true;
return node;
}
if (value_def) {
if (stop_if_hit && assign_pos == 0) assign_pos = remaining - replaced;
if (!hit_rhs) replaced++;
return node;
} else {
replaced++;
}
replaced++;
changed = abort = true;
AST_Node.info("Collapsing {node} [{file}:{line},{col}]", {
node: node,
@@ -2221,6 +2244,7 @@ Compressor.prototype.compress = function(node) {
var candidate = hit_stack[hit_stack.length - 1];
var assign_pos = -1;
var assign_used = false;
var verify_ref = false;
var remaining;
var value_def = null;
var stop_after = null;
@@ -2248,8 +2272,11 @@ Compressor.prototype.compress = function(node) {
var lvalues = get_lvalues(candidate);
var lhs_local = is_lhs_local(lhs);
var rhs_value = get_rvalue(candidate);
var rvalue = !compound && rhs_value instanceof AST_Sequence ? rhs_value.tail_node() : rhs_value;
if (!side_effects) side_effects = value_has_side_effects();
var rvalue = rhs_value;
if (!side_effects) {
if (!compound && rvalue instanceof AST_Sequence) rvalue = rvalue.tail_node();
side_effects = value_has_side_effects();
}
var check_destructured = in_try || !lhs_local ? function(node) {
return node instanceof AST_Destructured;
} : return_false;
@@ -2936,6 +2963,7 @@ Compressor.prototype.compress = function(node) {
if (matches < remaining) {
remaining = matches;
assign_pos = 0;
verify_ref = true;
}
}
if (expr.operator == "=") mangleable_var(expr.right);
@@ -3163,47 +3191,42 @@ Compressor.prototype.compress = function(node) {
return;
}
var end = hit_stack.length - 1;
if (hit_stack[end - 1].body === hit_stack[end]) end--;
var last = hit_stack[end];
if (last instanceof AST_VarDef || hit_stack[end - 1].body === last) end--;
var tt = new TreeTransformer(function(node, descend, in_list) {
if (hit) return node;
if (node !== hit_stack[hit_index]) return node;
hit_index++;
if (hit_index <= end) return handle_custom_scan_order(node, tt);
hit = true;
if (node instanceof AST_VarDef) {
declare_only.set(node.name.name, (declare_only.get(node.name.name) || 0) + 1);
if (node instanceof AST_Definitions) {
declare_only.set(last.name.name, (declare_only.get(last.name.name) || 0) + 1);
if (value_def) value_def.replaced++;
var defns = node.definitions;
var index = defns.indexOf(last);
var defn = last.clone();
defn.value = null;
if (!value) {
node.definitions[index] = defn;
return node;
}
var body = [ make_node(AST_SimpleStatement, value, { body: value }) ];
if (index > 0) {
var head = node.clone();
head.definitions = defns.slice(0, index);
body.unshift(head);
node = node.clone();
node.value = null;
return value ? List.splice([ value, node ]) : node;
node.definitions = defns.slice(index);
}
body.push(node);
node.definitions[0] = defn;
return in_list ? List.splice(body) : make_node(AST_BlockStatement, node, { body: body });
}
if (!value) return in_list ? List.skip : null;
return is_statement(node) ? make_node(AST_SimpleStatement, value, { body: value }) : value;
}, function(node, in_list) {
if (node instanceof AST_Definitions) {
var body = [], defns = node.definitions;
for (var index = 0, pos = 0; index < defns.length; index++) {
var defn = defns[index];
if (defn instanceof AST_VarDef) continue;
flush();
pos = index + 1;
body.push(make_node(AST_SimpleStatement, defn, { body: defn }));
}
if (pos == 0) return;
flush();
if (body.length == 1) return body[0];
return in_list ? List.splice(body) : make_node(AST_BlockStatement, node, { body: body });
}
if (node instanceof AST_For) return patch_for_init(node, in_list);
return patch_sequence(node, this);
function flush() {
if (pos < index) {
var cropped = node.clone();
cropped.definitions = defns.slice(pos, index);
body.push(cropped);
}
}
return patch_sequence(node, tt);
});
abort = false;
hit = false;
@@ -3249,9 +3272,13 @@ Compressor.prototype.compress = function(node) {
}
var def = lhs.definition();
if (def.references.length - def.replaced == referenced) return true;
return def.fixed && lhs.fixed && def.references.filter(function(ref) {
if (!def.fixed) return false;
if (!lhs.fixed) return false;
if (def.references.filter(function(ref) {
return ref.fixed === lhs.fixed;
}).length == referenced;
}).length != referenced) return false;
verify_ref = true;
return true;
}
function symbol_in_lvalues(sym, parent) {
@@ -3269,7 +3296,7 @@ Compressor.prototype.compress = function(node) {
if (def.scope.resolve() !== scope) return true;
if (modify_toplevel && compressor.exposed(def)) return true;
return !all(def.references, function(ref) {
return ref.scope.resolve() === scope;
return ref.scope.resolve(true) === scope;
});
}
@@ -4767,6 +4794,7 @@ Compressor.prototype.compress = function(node) {
});
var scan_modified = new TreeWalker(function(node) {
if (node instanceof AST_Assign) modified(node.left);
if (node instanceof AST_ForEnumeration) modified(node.init);
if (node instanceof AST_Unary && UNARY_POSTFIX[node.operator]) modified(node.expression);
});
function modified(node) {
@@ -5425,7 +5453,6 @@ Compressor.prototype.compress = function(node) {
return !(prop instanceof AST_ObjectGetter || prop instanceof AST_Spread);
});
});
def(AST_ObjectIdentity, return_true);
def(AST_Sequence, function() {
return this.tail_node().safe_to_spread();
});
@@ -6847,7 +6874,14 @@ Compressor.prototype.compress = function(node) {
});
}
}
if (node instanceof AST_Call) calls_to_drop_args.push(node);
if (node instanceof AST_Call) {
calls_to_drop_args.push(node);
node.args = node.args.map(function(arg) {
return arg.transform(tt);
});
node.expression = node.expression.transform(tt);
return node;
}
if (scope !== self) return;
if (drop_funcs && node !== self && node instanceof AST_DefClass) {
var def = node.name.definition();
@@ -7114,6 +7148,7 @@ Compressor.prototype.compress = function(node) {
if (def.orig.length > 1) return null;
if (def.assignments > 0) return false;
if (def.name == name) return def;
if (compressor.option("keep_fnames")) return false;
var forbidden;
switch (name) {
case "await":
@@ -7818,7 +7853,7 @@ Compressor.prototype.compress = function(node) {
var consts = new Dictionary();
var dirs = [];
var hoisted = [];
var vars = new Dictionary(), vars_found = 0;
var vars = new Dictionary();
var tt = new TreeTransformer(function(node, descend, in_list) {
if (node === self) return;
if (node instanceof AST_Directive) {
@@ -7846,7 +7881,6 @@ Compressor.prototype.compress = function(node) {
})) return node;
node.definitions.forEach(function(defn) {
vars.set(defn.name.name, defn);
++vars_found;
});
var seq = node.to_assignments();
if (p instanceof AST_ForEnumeration && p.init === node) {
@@ -7865,7 +7899,7 @@ Compressor.prototype.compress = function(node) {
}
});
self.transform(tt);
if (vars_found > 0) {
if (vars.size() > 0) {
// collect only vars which don't show up in self's arguments list
var defns = [];
if (self instanceof AST_Lambda) self.each_argname(function(argname) {
@@ -9633,8 +9667,16 @@ Compressor.prototype.compress = function(node) {
fixed.escaped = def.escaped;
name.fixed = fixed;
def.references.forEach(function(ref) {
var assigns = ref.fixed && ref.fixed.assigns;
if (assigns && assigns[0] === defn) assigns[0] = assign;
if (!ref.fixed) return;
var assigns = ref.fixed.assigns;
if (!assigns) return;
if (assigns[0] !== defn) return;
if (assigns.length > 1 || ref.fixed.to_binary || ref.fixed.to_prefix) {
assigns[0] = assign;
} else {
ref.fixed = fixed;
if (def.fixed === ref.fixed) def.fixed = fixed;
}
});
def.references.push(name);
}
@@ -12901,15 +12943,16 @@ Compressor.prototype.compress = function(node) {
AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
if (!compressor.option("properties")) return;
if (key === "__proto__") return;
var expr = this.expression;
if (expr instanceof AST_Object) {
var self = this;
var expr = self.expression;
if (!(expr instanceof AST_Object)) return;
var props = expr.properties;
for (var i = props.length; --i >= 0;) {
var prop = props[i];
if (prop.key !== key) continue;
if (!all(props, can_hoist_property)) return;
if (!safe_to_flatten(prop.value, compressor)) return;
var scope, values = [];
var call, scope, values = [];
for (var j = 0; j < props.length; j++) {
var value = props[j].value;
if (props[j] instanceof AST_ObjectMethod) {
@@ -12924,21 +12967,21 @@ Compressor.prototype.compress = function(node) {
var ctor;
if (arrow) {
ctor = is_async(value) ? AST_AsyncArrow : AST_Arrow;
} else if (i === j && !(compressor.parent() instanceof AST_Call)) {
return;
} else {
} else if (i != j
|| (call = compressor.parent()) instanceof AST_Call && call.expression === self) {
ctor = value.CTOR;
} else {
return;
}
value = make_node(ctor, value, value);
}
values.push(value);
}
return make_node(AST_Sub, this, {
return make_node(AST_Sub, self, {
expression: make_node(AST_Array, expr, { elements: values }),
property: make_node(AST_Number, this, { value: i }),
property: make_node(AST_Number, self, { value: i }),
});
}
}
});
OPT(AST_Dot, function(self, compressor) {
@@ -13134,6 +13177,19 @@ Compressor.prototype.compress = function(node) {
return found;
}
function insert_assign(def, assign) {
var visited = [];
def.references.forEach(function(ref) {
var fixed = ref.fixed;
if (!fixed || !push_uniq(visited, fixed)) return;
if (fixed.assigns) {
fixed.assigns.unshift(assign);
} else {
fixed.assigns = [ assign ];
}
});
}
function init_ref(compressor, name) {
var sym = make_node(AST_SymbolRef, name, name);
var assign = make_node(AST_Assign, name, {
@@ -13147,16 +13203,7 @@ Compressor.prototype.compress = function(node) {
return assign.right;
};
sym.fixed.assigns = [ assign ];
var visited = [];
def.references.forEach(function(ref) {
var fixed = ref.fixed;
if (!fixed || !push_uniq(visited, fixed)) return;
if (fixed.assigns) {
fixed.assigns.unshift(assign);
} else {
fixed.assigns = [ assign ];
}
});
insert_assign(def, assign);
}
def.assignments++;
def.references.push(sym);
@@ -13260,6 +13307,7 @@ Compressor.prototype.compress = function(node) {
if (fn.body[0] instanceof AST_Directive) return;
if (fn.contains_this()) return;
if (!scope) scope = find_scope(compressor);
if (in_async_generator(scope)) return;
var defined = new Dictionary();
defined.set("NaN", true);
while (!(scope instanceof AST_Scope)) {
@@ -13364,12 +13412,12 @@ Compressor.prototype.compress = function(node) {
if (value) body.push(make_node(AST_SimpleStatement, call, { body: value }));
return;
}
body.push(make_node(AST_Var, call, {
definitions: [ make_node(AST_VarDef, call, {
var defn = make_node(AST_VarDef, call, {
name: argname.convert_symbol(AST_SymbolVar, process),
value: value || make_node(AST_Undefined, call).transform(compressor),
}) ],
}));
});
if (argname instanceof AST_SymbolFunarg) insert_assign(argname.definition(), defn);
body.push(make_node(AST_Var, call, { definitions: [ defn ] }));
});
if (values.length) body.push(make_node(AST_SimpleStatement, call, {
body: make_sequence(call, values),
@@ -13500,6 +13548,12 @@ Compressor.prototype.compress = function(node) {
def(AST_LabeledStatement, function(compressor, scope, no_return, in_loop) {
var body = this.body.try_inline(compressor, scope, no_return, in_loop);
if (!body) return;
if (this.body instanceof AST_IterationStatement && body instanceof AST_BlockStatement) {
var loop = body.body.pop();
this.body = loop;
body.body.push(this);
return body;
}
this.body = body;
return this;
});

View File

@@ -96,15 +96,14 @@ function minify(files, options) {
}, true);
if (options.validate) AST_Node.enable_validation();
var timings = options.timings && { start: Date.now() };
if (options.rename === undefined) options.rename = options.compress && options.mangle;
if (options.annotations !== undefined) set_shorthand("annotations", options, [ "compress", "output" ]);
if (options.ie8) options.ie = options.ie || options.ie8;
if (options.ie) set_shorthand("ie", options, [ "compress", "mangle", "output" ]);
if (options.keep_fargs) set_shorthand("keep_fargs", options, [ "compress", "mangle" ]);
if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle" ]);
if (options.v8) set_shorthand("v8", options, [ "mangle", "output" ]);
if (options.webkit) set_shorthand("webkit", options, [ "compress", "mangle", "output" ]);
if (options.ie) set_shorthand("ie", options, [ "compress", "mangle", "output", "rename" ]);
if (options.keep_fargs) set_shorthand("keep_fargs", options, [ "compress", "mangle", "rename" ]);
if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle", "rename" ]);
if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle", "rename" ]);
if (options.v8) set_shorthand("v8", options, [ "mangle", "output", "rename" ]);
if (options.webkit) set_shorthand("webkit", options, [ "compress", "mangle", "output", "rename" ]);
var quoted_props;
if (options.mangle) {
options.mangle = defaults(options.mangle, {
@@ -135,6 +134,7 @@ function minify(files, options) {
init_cache(options.mangle.cache);
init_cache(options.mangle.properties.cache);
}
if (options.rename === undefined) options.rename = options.compress && options.mangle;
if (options.sourceMap) {
options.sourceMap = defaults(options.sourceMap, {
content: null,
@@ -190,8 +190,8 @@ function minify(files, options) {
if (options.validate) toplevel.validate_ast();
if (timings) timings.rename = Date.now();
if (options.rename) {
toplevel.figure_out_scope(options.mangle);
toplevel.expand_names(options.mangle);
toplevel.figure_out_scope(options.rename);
toplevel.expand_names(options.rename);
}
if (timings) timings.compress = Date.now();
if (options.compress) {

View File

@@ -1194,10 +1194,10 @@ function parse($TEXT, options) {
}
function for_() {
var await = is("name", "await") && next();
var await_token = is("name", "await") && next();
expect("(");
var init = null;
if (await || !is("punc", ";")) {
if (await_token || !is("punc", ";")) {
init = is("keyword", "const")
? (next(), const_(true))
: is("name", "let") && is_vardefs()
@@ -1206,7 +1206,7 @@ function parse($TEXT, options) {
? (next(), var_(true))
: expression(true);
var ctor;
if (await) {
if (await_token) {
expect_token("name", "of");
ctor = AST_ForAwaitOf;
} else if (is("operator", "in")) {

View File

@@ -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.3",
"version": "3.15.4",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -183,13 +183,11 @@ function parse_test(file) {
function reminify(orig_options, input_code, input_formatted, stdout) {
for (var i = 0; i < minify_options.length; i++) {
var options = JSON.parse(minify_options[i]);
if (options.compress) [
[
"keep_fargs",
"keep_fnames",
].forEach(function(name) {
if (name in orig_options) {
options.compress[name] = orig_options[name];
}
if (name in orig_options) options[name] = orig_options[name];
});
var options_formatted = JSON.stringify(options, null, 4);
options.validate = true;

View File

@@ -939,6 +939,8 @@ keep_fnames: {
class Foo {}
console.log(Foo.name, class Bar {}.name);
}
expect_stdout: "Foo Bar"
node_version: ">=4"
}
issue_805_1: {
@@ -2502,3 +2504,70 @@ issue_5352: {
expect_stdout: "PASS"
node_version: ">=12"
}
issue_5387: {
options = {
properties: true,
}
input: {
"use strict";
(function(a) {
try {
class A extends a {}
} catch (e) {
console.log("PASS");
}
})({
f() {
return this;
}
}.f);
}
expect: {
"use strict";
(function(a) {
try {
class A extends a {}
} catch (e) {
console.log("PASS");
}
})({
f() {
return this;
}
}.f);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5389: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
function log(m, n) {
console.log(m, n);
}
var a = log;
class A {
[a = "FAIL"] = a = "PASS";
}
var b = new A();
log(a, b.FAIL);
}
expect: {
function log(m, n) {
console.log(m, n);
}
var a = log;
class A {
[a = "FAIL"] = a = "PASS";
}
var b = new A();
log(a, b.FAIL);
}
expect_stdout: "PASS PASS"
node_version: ">=12"
}

View File

@@ -9925,3 +9925,57 @@ issue_5309_2: {
}
expect_stdout: "PASS"
}
issue_5394: {
options = {
collapse_vars: true,
evaluate: true,
}
input: {
try {
throw A.p = (console.log("FAIL"), []), !1;
} catch (e) {
console.log(typeof e);
}
}
expect: {
try {
throw !(A.p = (console.log("FAIL"), []));
} catch (e) {
console.log(typeof e);
}
}
expect_stdout: "object"
}
issue_5396: {
options = {
collapse_vars: true,
merge_vars: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var a, b;
function f() {}
b = 0;
new function g(c) {
var d = a && g(e), e = ++d, i = [ 42 ];
for (var j in i)
console.log("PASS"),
i;
}();
}
expect: {
var a, b;
function f() {}
b = 0;
(function g(c) {
a && g();
for (var j in [ 42 ])
console.log("PASS");
})();
}
expect_stdout: "PASS"
}

View File

@@ -2209,3 +2209,33 @@ issue_5340_3: {
expect_stdout: "undefined"
node_version: ">=6"
}
issue_5407: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
(function(a) {
for (var i = 0; i < 2; i++)
(function(b = 4) {
console.log(b);
a = 2;
})(a);
})();
}
expect: {
(function(a) {
for (var i = 0; i < 2; i++)
(function(b = 4) {
console.log(b);
a = 2;
})(a);
})();
}
expect_stdout: [
"4",
"2",
]
node_version: ">=6"
}

View File

@@ -3497,3 +3497,41 @@ issue_5370: {
expect_stdout: true
node_version: ">=6"
}
issue_5405_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var [ a ] = [ {} ];
console.log(a === a ? "PASS" : "FAIL");
}
expect: {
var [ a ] = [ {} ];
console.log(true ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5405_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var { p: a } = { p: [] };
console.log(a === a ? "PASS" : "FAIL");
}
expect: {
var { p: a } = { p: [] };
console.log(true ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -3349,3 +3349,30 @@ issue_5362_2: {
}
expect_stdout: "true"
}
issue_5380: {
options = {
evaluate: true,
keep_fnames: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = function f(b) {
return function g() {
for (b in { PASS: 42 });
}(), b;
}("FAIL");
console.log(a);
}
expect: {
var a = function f(b) {
return function g() {
for (b in { PASS: 42 });
}(), b;
}("FAIL");
console.log(a);
}
expect_stdout: "PASS"
}

View File

@@ -3557,6 +3557,27 @@ functions_inner_var: {
expect_stdout: "undefined undefined"
}
functions_keep_fnames: {
options = {
functions: true,
keep_fnames: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var FAIL = function PASS() {};
FAIL.p = 42;
console.log(FAIL.name, FAIL.p);
}
expect: {
var FAIL = function PASS() {};
FAIL.p = 42;
console.log(FAIL.name, FAIL.p);
}
expect_stdout: "PASS 42"
}
issue_2437: {
options = {
collapse_vars: true,
@@ -8329,3 +8350,51 @@ issue_5376_2: {
}
expect_stdout: Error("PASS")
}
issue_5401: {
options = {
inline: true,
}
input: {
L: for (var a in function() {
while (console.log("PASS"));
}(), a) do {
continue L;
} while (console.log("FAIL"));
}
expect: {
while (console.log("PASS"));
L: for (var a in a) do {
continue L;
} while (console.log("FAIL"));
}
expect_stdout: "PASS"
}
issue_5409: {
options = {
inline: true,
merge_vars: true,
reduce_vars: true,
unused: true,
}
input: {
(function(a) {
(a = console) || FAIL(a);
(function(b) {
console.log(b && b);
while (!console);
})();
})();
}
expect: {
(function(a) {
(a = console) || FAIL(a);
a = void 0;
console.log(a && a);
while (!console);
return;
})();
}
expect_stdout: "undefined"
}

View File

@@ -224,8 +224,7 @@ issue_4489: {
console.log(k);
}
expect: {
!(A = 0);
for (var k in true);
for (var k in !(A = 0));
console.log(k);
}
expect_stdout: "undefined"
@@ -407,9 +406,9 @@ issue_4893_2: {
expect: {
try{
(function() {
var b;
b = null;
b.p += 42;
var a;
a = null;
a.p += 42;
})();
} catch (e) {
console.log("PASS");
@@ -530,3 +529,77 @@ issue_5378: {
"undefined",
]
}
issue_5411_1: {
options = {
collapse_vars: true,
dead_code: true,
hoist_vars: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a = "PASS";
b++;
b = a;
var b = b, c = c && c[b];
console.log(b);
}
expect: {
var b, c, a = "PASS";
b++;
b = a;
c = c && c[b];
console.log(b);
}
expect_stdout: "PASS"
}
issue_5411_2: {
options = {
collapse_vars: true,
dead_code: true,
evaluate: true,
hoist_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS";
b++;
b = a;
var b = b, c = c && c[b];
console.log(b);
}
expect: {
var b, c;
b++;
b = "PASS",
c = c && c[b];
console.log(b);
}
expect_stdout: "PASS"
}
issue_5411_3: {
options = {
collapse_vars: true,
hoist_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = console;
a++;
var a = A = a;
console.log(A);
}
expect: {
var a = console;
a = A = ++a;
console.log(A);
}
expect_stdout: "NaN"
}

View File

@@ -1258,8 +1258,7 @@ issues_3267_1: {
}
expect: {
!function() {
var i = Object();
if (i)
if (Object())
return console.log("PASS");
throw "FAIL";
}();

View File

@@ -6689,8 +6689,7 @@ issues_3267_1: {
}
expect: {
!function(x) {
var i = Object();
if (i)
if (Object())
return console.log("PASS");
throw "FAIL";
}();

View File

@@ -1323,3 +1323,43 @@ issue_5370: {
expect_stdout: true
node_version: ">=6"
}
issue_5391: {
options = {
evaluate: true,
keep_fargs: false,
objects: true,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a, b = function f({
p: {},
...c
}) {
while (c.q);
}({
p: {
r: a++,
r: 0,
}
});
console.log(a);
}
expect: {
(function({
p: {},
...c
}) {
while (c.q);
})({
p: 0,
});
console.log(NaN);
}
expect_stdout: "NaN"
node_version: ">=8.3.0"
}

View File

@@ -1166,3 +1166,31 @@ issue_5006: {
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5382: {
options = {
side_effects: true,
}
input: {
({
f() {
({ ...this });
},
get p() {
console.log("PASS");
},
}).f();
}
expect: {
({
f() {
({ ...this });
},
get p() {
console.log("PASS");
},
}).f();
}
expect_stdout: "PASS"
node_version: ">=8.3.0"
}

View File

@@ -1451,3 +1451,77 @@ issue_5177: {
expect_stdout: "function"
node_version: ">=4"
}
issue_5385_1: {
options = {
inline: true,
}
input: {
(async function*() {
(function() {
try {
return console.log("foo");
} finally {
return console.log("bar");
}
console.log("baz");
})();
})().next();
console.log("moo");
}
expect: {
(async function*() {
(function() {
try {
return console.log("foo");
} finally {
return console.log("bar");
}
console.log("baz");
})();
})().next();
console.log("moo");
}
expect_stdout: [
"foo",
"bar",
"moo",
]
node_version: ">=10"
}
issue_5385_2: {
options = {
inline: true,
}
input: {
(async function*() {
return function() {
try {
return console.log("foo");
} finally {
return console.log("bar");
}
}();
})().next();
console.log("moo");
}
expect: {
(async function*() {
return function() {
try {
return console.log("foo");
} finally {
return console.log("bar");
}
}();
})().next();
console.log("moo");
}
expect_stdout: [
"foo",
"bar",
"moo",
]
node_version: ">=10"
}

View File

@@ -434,7 +434,7 @@ describe("test/reduce.js", function() {
"// }",
].join("\n"));
});
it("Should transform `export default` correctly", function() {
it("Should transform `export default class` correctly", function() {
var result = reduce_test(read("test/input/reduce/export_default.js"), {
compress: false,
toplevel: true,
@@ -448,4 +448,41 @@ describe("test/reduce.js", function() {
"// }",
].join("\n"));
});
it("Should transform `export default function` correctly", function() {
var code = [
"for (var k in this)",
" console.log(k);",
"export default (function f() {});",
"console.log(k);",
].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"));
});
it("Should transform `export default (42)` correctly", function() {
var code = [
"export default (42);",
"for (var k in this)",
" console.log(k);",
].join("\n");
var result = reduce_test(code, {
compress: false,
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"// Can't reproduce test failure",
"// minify options: {",
'// "compress": false,',
'// "mangle": false',
"// }",
].join("\n"));
});
});

View File

@@ -52,12 +52,14 @@ 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, imports = [];
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) {
if (/^export\s+default/.test(match)) has_default = "var _uglify_export_default_;";
if (!header) return "";
if (header.length == 1) return "0, " + header;
do {
var name = "_export_default_" + ++count;
var name = "_uglify_export_default_";
if (/^class\b/.test(header)) do {
name = "_uglify_export_default_" + ++count;
} while (code.indexOf(name) >= 0);
return header.slice(0, -1) + " " + name + header.slice(-1);
}).replace(/\bimport\.meta\b/g, function() {
@@ -76,7 +78,7 @@ exports.patch_module_statements = function(code) {
return "";
});
imports.push("");
return imports.join("\n") + code;
return has_default + imports.join("\n") + code;
};
function is_error(result) {