diff --git a/lib/compress.js b/lib/compress.js index 24d0d040..5cf16062 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -8290,17 +8290,26 @@ Compressor.prototype.compress = function(node) { if (!base && !values) return null; exprs = []; } - if (base) { + if (base || !compressor.has_directive("use strict")) { var node = to_class_expr(self, true); + if (!base) node.extends = null; node.properties = []; - if (exprs.length) node.properties.push(make_node(AST_ClassMethod, self, { - key: make_sequence(self, exprs), - value: make_node(AST_Function, self, { - argnames: [], - body: [], - }).init_vars(node), - })); - exprs = [ node ]; + if (values) { + node.properties.push(make_node(AST_ClassField, self, { + static: true, + key: exprs.length ? make_sequence(self, exprs) : "c", + value: make_sequence(self, values), + })); + } else if (exprs.length) { + node.properties.push(make_node(AST_ClassMethod, self, { + key: make_sequence(self, exprs), + value: make_node(AST_Function, self, { + argnames: [], + body: [], + }).init_vars(node), + })); + } + return node; } if (values) exprs.push(make_node(AST_Call, self, { expression: make_node(AST_Arrow, self, { diff --git a/test/compress/classes.js b/test/compress/classes.js index bad695f9..c55b41ff 100644 --- a/test/compress/classes.js +++ b/test/compress/classes.js @@ -434,6 +434,33 @@ static_side_effects: { console.log(a); } expect: { + var a = "FAIL 1"; + (class { + static c = a = "PASS"; + }); + console.log(a); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +static_side_effects_strict: { + options = { + inline: true, + toplevel: true, + unused: true, + } + input: { + "use strict"; + var a = "FAIL 1"; + class A { + static p = a = "PASS"; + q = a = "FAIL 2"; + } + console.log(a); + } + expect: { + "use strict"; var a = "FAIL 1"; a = "PASS"; console.log(a); @@ -807,6 +834,33 @@ unused_await: { })(); } expect: { + var await = "PASS"; + (async function() { + (class { + static c = console.log(await); + }); + })(); + } + expect_stdout: true + node_version: ">=12 <16" +} + +unused_await_strict: { + options = { + inline: true, + unused: true, + } + input: { + "use strict"; + var await = "PASS"; + (async function() { + class A { + static p = console.log(await); + } + })(); + } + expect: { + "use strict"; var await = "PASS"; (async function() { (() => console.log(await))(); @@ -1149,6 +1203,31 @@ issue_4705: { } } expect: { + (class { + [console.log("PASS")]() {} + }); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +issue_4705_strict: { + options = { + evaluate: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + "use strict"; + var a = "PASS"; + class A { + p = a = "FAIL"; + [console.log(a)]; + } + } + expect: { + "use strict"; console.log("PASS"); } expect_stdout: "PASS" @@ -1371,9 +1450,40 @@ issue_4756: { expect: { try { (class extends 42 { - [console.log("foo")]() {} - }), - (() => console.log("bar"))(); + static [console.log("foo")] = console.log("bar"); + }); + } catch (e) { + console.log("baz"); + } + } + expect_stdout: [ + "foo", + "baz", + ] + node_version: ">=12" +} + +issue_4756_strict: { + options = { + toplevel: true, + unused: true, + } + input: { + "use strict"; + try { + class A extends 42 { + static [console.log("foo")] = console.log("bar"); + } + } catch (e) { + console.log("baz"); + } + } + expect: { + "use strict"; + try { + (class extends 42 { + static [console.log("foo")] = console.log("bar"); + }); } catch (e) { console.log("baz"); } @@ -1440,7 +1550,7 @@ issue_4829_1: { input: { "use strict"; try { - class A extends { f(){} }.f {} + class A extends { f() {} }.f {} } catch (e) { console.log("PASS"); } @@ -1646,6 +1756,37 @@ issue_4962_1: { })(function g() {}); } expect: { + (function g() {}), + void class { + static c = function() { + while (console.log(typeof g)); + }(); + }; + } + expect_stdout: "undefined" + node_version: ">=12" +} + +issue_4962_1_strict: { + options = { + ie: true, + inline: true, + reduce_vars: true, + unused: true, + } + input: { + "use strict"; + (function() { + function f() { + while (console.log(typeof g)); + } + class A { + static p = f(); + } + })(function g() {}); + } + expect: { + "use strict"; (function g() {}); while (console.log(typeof g)); } @@ -1671,6 +1812,36 @@ issue_4962_2: { }, typeof g)); } expect: { + console.log(function f() {}(function g() { + (class { + static c = f; + }); + })); + } + expect_stdout: "undefined" + node_version: ">=12" +} + +issue_4962_2_strict: { + options = { + ie: true, + inline: true, + reduce_vars: true, + unused: true, + } + input: { + "use strict"; + console.log(function f() {}(function g() { + function h() { + f; + } + class A { + static p = h(); + } + }, typeof g)); + } + expect: { + "use strict"; console.log(function f() {}(function g() { f; })); @@ -2026,6 +2197,40 @@ issue_5082_1: { })(); } expect: { + (function() { + class A { + p = console.log("PASS"); + q() {} + } + (class { + static c = new A(); + }); + })(); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +issue_5082_1_strict: { + options = { + inline: true, + reduce_vars: true, + unused: true, + } + input: { + "use strict"; + (function() { + class A { + p = console.log("PASS"); + q() {} + } + class B { + static P = new A(); + } + })(); + } + expect: { + "use strict"; (function() { class A { p = console.log("PASS"); @@ -2057,6 +2262,41 @@ issue_5082_2: { })(); } expect: { + (function() { + class A { + p = console.log("PASS"); + q() {} + } + (class { + static c = new A(); + }); + })(); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +issue_5082_2_static: { + options = { + inline: true, + passes: 2, + reduce_vars: true, + unused: true, + } + input: { + "use strict"; + (function() { + class A { + p = console.log("PASS"); + q() {} + } + class B { + static P = new A(); + } + })(); + } + expect: { + "use strict"; void new class { p = console.log("PASS"); q() {} diff --git a/test/ufuzz/index.js b/test/ufuzz/index.js index 8747418d..d58c1967 100644 --- a/test/ufuzz/index.js +++ b/test/ufuzz/index.js @@ -2501,7 +2501,7 @@ for (var round = 1; round <= num_iterations; round++) { } } // ignore declaration order of global variables - if (!ok && !toplevel) { + 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))); } // ignore numerical imprecision caused by `unsafe_math` @@ -2519,14 +2519,8 @@ 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; // 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); - var uglify_strict = run_code('"use strict";\n' + uglify_code, toplevel); - if (typeof original_strict != "string") { - ok = typeof uglify_strict != "string"; - } else { - ok = sandbox.same_stdout(original_strict, uglify_strict); - } + if (!ok && uglify_result.name == "SyntaxError" && /\bclass\b/.test(original_code)) { + ok = typeof run_code('"use strict";\n' + original_code, toplevel) != "string"; } // ignore difference in error message caused by `import` symbol redeclaration if (!ok && errored && /\bimport\b/.test(original_code)) {