diff --git a/lib/compress.js b/lib/compress.js index 10335634..904a15e9 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -2021,7 +2021,7 @@ merge(Compressor.prototype, { var tw = new TreeWalker(function(node, descend){ if (node !== self) { if (node instanceof AST_Defun || node instanceof AST_DefClass) { - if ((!drop_funcs || tw.parent() instanceof AST_Export) && scope === self) { + if (!drop_funcs && scope === self) { var node_def = node.name.definition(); if (node_def.global && !(node_def.id in in_use_ids)) { in_use_ids[node_def.id] = true; @@ -2157,9 +2157,11 @@ merge(Compressor.prototype, { // pass 3: we should drop declarations not in_use var tt = new TreeTransformer( function before(node, descend, in_list) { - if (node instanceof AST_Function - && node.name - && !compressor.option("keep_fnames")) { + var parent = tt.parent(); + if (!compressor.option("keep_fnames") + && ((node instanceof AST_Function || node instanceof AST_ClassExpression) && node.name + || (node instanceof AST_Defun || node instanceof AST_DefClass) + && parent instanceof AST_Export && parent.is_default)) { var def = node.name.definition(); // any declarations with same name will overshadow // name of this anonymous function and can therefore @@ -2194,7 +2196,7 @@ merge(Compressor.prototype, { } } } - if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) { + if ((node instanceof AST_Defun || node instanceof AST_DefClass) && !(parent instanceof AST_Export) && node !== self) { var keep = (node.name.definition().id in in_use_ids) || !drop_funcs && node.name.definition().global; if (!keep) { compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name)); @@ -2202,7 +2204,7 @@ merge(Compressor.prototype, { } return node; } - if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn && tt.parent().init === node)) { + if (node instanceof AST_Definitions && !(parent instanceof AST_ForIn && parent.init === node)) { // place uninitialized names at the start var body = [], head = [], tail = []; // for unused names whose initialization has @@ -2298,7 +2300,7 @@ merge(Compressor.prototype, { if (!(def.id in in_use_ids) && (drop_vars || !def.global) && self.variables.get(def.name) === def) { - return maintain_this_binding(tt.parent(), node, node.right.transform(tt)); + return maintain_this_binding(parent, node, node.right.transform(tt)); } } // certain combination of unused name + side effect leads to: diff --git a/lib/parse.js b/lib/parse.js index 469e14a6..d5012adc 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -2417,14 +2417,26 @@ function parse($TEXT, options) { } } - var is_definition = is("keyword", "var") - || is("keyword", "let") - || is("keyword", "const") - || is("keyword", "function") && !is_default; + var is_definition = is("keyword", "var") || is("keyword", "let") || is("keyword", "const"); if (is_definition) { + if (is_default) unexpected(); exported_definition = statement(); + } else if (is("keyword", "class")) { + var cls = expr_atom(false); + if (cls.name) { + cls.name = new AST_SymbolDefClass(cls.name); + exported_definition = new AST_DefClass(cls); + } else { + exported_value = cls; + } } else if (is("keyword", "function")) { - exported_value = expr_atom(false); + var func = expr_atom(false); + if (func.name) { + func.name = new AST_SymbolDefun(func.name); + exported_definition = new AST_Defun(func); + } else { + exported_value = func; + } } else { exported_value = expression(false); semicolon(); diff --git a/lib/scope.js b/lib/scope.js index 028481c7..39a4a1a7 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -230,7 +230,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ } function mark_export(def, level) { - def.export = tw.parent(level) instanceof AST_Export; + var node = tw.parent(level); + def.export = node instanceof AST_Export && !node.is_default; } }); self.walk(tw); diff --git a/test/compress/issue-2001.js b/test/compress/issue-2001.js index cdc19e4a..0109641b 100644 --- a/test/compress/issue-2001.js +++ b/test/compress/issue-2001.js @@ -1,6 +1,7 @@ export_func_1: { options = { hoist_funs: true, + toplevel: true, unused: true, } input: { @@ -13,6 +14,7 @@ export_func_2: { options = { hoist_funs: true, side_effects: false, + toplevel: true, unused: true, } input: { @@ -25,6 +27,7 @@ export_func_3: { options = { hoist_funs: true, side_effects: true, + toplevel: true, unused: true, } input: { @@ -36,6 +39,7 @@ export_func_3: { export_default_func_1: { options = { hoist_funs: true, + toplevel: true, unused: true, } input: { @@ -48,6 +52,7 @@ export_default_func_2: { options = { hoist_funs: true, side_effects: false, + toplevel: true, unused: true, } input: { @@ -60,6 +65,7 @@ export_default_func_3: { options = { hoist_funs: true, side_effects: true, + toplevel: true, unused: true, } input: { @@ -68,6 +74,82 @@ export_default_func_3: { expect_exact: "export default function(){};" } +export_class_1: { + options = { + hoist_funs: true, + toplevel: true, + unused: true, + } + input: { + export class C {}; + } + expect_exact: "export class C{};" +} + +export_class_2: { + options = { + hoist_funs: true, + side_effects: false, + toplevel: true, + unused: true, + } + input: { + export class C {}(1); + } + expect_exact: "export class C{};1;" +} + +export_class_3: { + options = { + hoist_funs: true, + side_effects: true, + toplevel: true, + unused: true, + } + input: { + export class C {}(1); + } + expect_exact: "export class C{};" +} + +export_default_class_1: { + options = { + hoist_funs: true, + toplevel: true, + unused: true, + } + input: { + export default class C {}; + } + expect_exact: "export default class{};" +} + +export_default_class_2: { + options = { + hoist_funs: true, + side_effects: false, + toplevel: true, + unused: true, + } + input: { + export default class C {}(1); + } + expect_exact: "export default class{};1;" +} + +export_default_class_3: { + options = { + hoist_funs: true, + side_effects: true, + toplevel: true, + unused: true, + } + input: { + export default class C {}(1); + } + expect_exact: "export default class{};" +} + export_mangle_1: { mangle = { toplevel: true, @@ -89,7 +171,7 @@ export_mangle_2: { return one - two; }; } - expect_exact: "export default function n(r,t){return r-t};" + expect_exact: "export default function n(n,r){return n-r};" } export_mangle_3: { @@ -125,7 +207,7 @@ export_mangle_4: { } }; } - expect_exact: "export default class C{go(n,r){return n-r+n}};" + expect_exact: "export default class n{go(n,r){return n-r+n}};" } export_mangle_5: { @@ -181,6 +263,19 @@ export_toplevel_2: { } expect: { export class B {}; - export default class C {}; + export default class {}; } } + +export_default_func_ref: { + options = { + hoist_funs: true, + toplevel: true, + unused: true, + } + input: { + export default function f(){}; + f(); + } + expect_exact: "export default function f(){};f();" +}