From 80c8dfcde6cacd6ee3845fad710d80ff398591bd Mon Sep 17 00:00:00 2001 From: kzc Date: Sun, 17 Dec 2017 11:11:52 -0500 Subject: [PATCH] fix `export default` of anonymous generators and async functions (#2607) fixes #2606 --- lib/parse.js | 23 +++-- test/compress/export.js | 182 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+), 9 deletions(-) diff --git a/lib/parse.js b/lib/parse.js index 867383bf..eebc4967 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -982,7 +982,7 @@ function parse($TEXT, options) { } }; - var statement = embed_tokens(function() { + var statement = embed_tokens(function(is_export_default) { handle_regexp(); switch (S.token.type) { case "string": @@ -1011,7 +1011,7 @@ function parse($TEXT, options) { if (S.token.value == "async" && is_token(peek(), "keyword", "function")) { next(); next(); - return function_(AST_Defun, false, true); + return function_(AST_Defun, false, true, is_export_default); } if (S.token.value == "import" && !is_token(peek(), "punc", "(")) { next(); @@ -1085,7 +1085,7 @@ function parse($TEXT, options) { case "function": next(); - return function_(AST_Defun); + return function_(AST_Defun, false, false, is_export_default); case "if": next(); @@ -1308,9 +1308,9 @@ function parse($TEXT, options) { }); }; - var function_ = function(ctor, is_generator_property, is_async) { + var function_ = function(ctor, is_generator_property, is_async, is_export_default) { if (is_generator_property && is_async) croak("generators cannot be async"); - var start = S.token + var start = S.token; var in_statement = ctor === AST_Defun; var is_generator = is("operator", "*"); @@ -1319,8 +1319,13 @@ function parse($TEXT, options) { } var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null; - if (in_statement && !name) - unexpected(); + if (in_statement && !name) { + if (is_export_default) { + ctor = AST_Function; + } else { + unexpected(); + } + } if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration)) unexpected(prev()); @@ -2528,9 +2533,9 @@ function parse($TEXT, options) { && is_token(peek(), "punc")) { exported_value = expression(false); semicolon(); - } else if ((node = statement()) instanceof AST_Definitions && is_default) { + } else if ((node = statement(is_default)) instanceof AST_Definitions && is_default) { unexpected(node.start); - } else if (node instanceof AST_Definitions || node instanceof AST_Defun || node instanceof AST_DefClass) { + } else if (node instanceof AST_Definitions || node instanceof AST_Lambda || node instanceof AST_DefClass) { exported_definition = node; } else if (node instanceof AST_SimpleStatement) { exported_value = node.body; diff --git a/test/compress/export.js b/test/compress/export.js index aad0238d..783fa80a 100644 --- a/test/compress/export.js +++ b/test/compress/export.js @@ -262,3 +262,185 @@ trailing_comma: { } expect_exact: "export const a = 1;" } + +export_default_anonymous_function: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + mangle = { + toplevel: true, + } + input: { + export default function () { + foo(); + } + } + expect_exact: "export default function(){foo()};" +} + +export_default_arrow: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + mangle = { + toplevel: true, + } + input: { + export default () => foo(); + } + expect_exact: "export default()=>foo();" +} + +export_default_anonymous_generator: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + mangle = { + toplevel: true, + } + input: { + export default function * () { + yield foo(); + } + } + expect_exact: "export default function*(){yield foo()};" +} + +export_default_anonymous_async_function: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + mangle = { + toplevel: true, + } + input: { + export default async function() { + return await foo(); + } + } + expect_exact: "export default async function(){return await foo()};" +} + +export_default_async_arrow_function: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + mangle = { + toplevel: true, + } + input: { + export default async () => await foo(); + } + expect_exact: "export default async()=>await foo();" +} + +export_default_named_generator: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + mangle = { + toplevel: true, + } + input: { + export default function * gen() { + yield foo(); + } + } + expect_exact: "export default function*gen(){yield foo()};" +} + +export_default_named_async_function: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + mangle = { + toplevel: true, + } + input: { + export default async function bar() { + return await foo(); + } + } + expect_exact: "export default async function bar(){return await foo()};" +} + +export_default_anonymous_class: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + mangle = { + toplevel: true, + } + input: { + export default class { + constructor() { + foo(); + } + }; + } + expect_exact: "export default class{constructor(){foo()}};" +} + +export_default_anonymous_function_not_call: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + mangle = { + toplevel: true, + } + input: { + export default function(){}(foo); + } + // FIXME: should be `export default function(){};foo;` + expect_exact: "export default function(){}(foo);" +} + +export_default_anonymous_generator_not_call: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + mangle = { + toplevel: true, + } + input: { + export default function*(){}(foo); + } + // agrees with `acorn` and `babylon 7` + expect_exact: "export default function*(){};foo;" +} + +export_default_anonymous_async_function_not_call: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + mangle = { + toplevel: true, + } + input: { + export default async function(){}(foo); + } + // agrees with `acorn` and `babylon 7` + expect_exact: "export default async function(){};foo;" +}