fix corner cases with export default (#4673)

This commit is contained in:
Alex Lam S.L
2021-02-21 05:01:56 +00:00
committed by GitHub
parent bfe3a8b516
commit b726e364c1
5 changed files with 96 additions and 40 deletions

View File

@@ -1060,7 +1060,7 @@ var AST_ExportDeclaration = DEFNODE("ExportDeclaration", "body", {
var AST_ExportDefault = DEFNODE("ExportDefault", "body", {
$documentation: "An `export default` statement",
$propdoc: {
body: "[AST_Node] an expression node (should not be instanceof AST_Statement)",
body: "[AST_Node] the default export",
},
walk: function(visitor) {
var node = this;
@@ -1069,7 +1069,11 @@ var AST_ExportDefault = DEFNODE("ExportDefault", "body", {
});
},
_validate: function() {
must_be_expression(this, "body");
if (this.body instanceof AST_Lambda && this.body.name) {
if (!(this.body instanceof AST_LambdaDefinition)) throw new Error("body must be AST_LambdaDefinition");
} else {
must_be_expression(this, "body");
}
},
}, AST_Statement);

View File

@@ -5537,6 +5537,27 @@ merge(Compressor.prototype, {
}
}
function to_func_expr(defun, drop_name) {
var ctor;
switch (defun.CTOR) {
case AST_AsyncDefun:
ctor = AST_AsyncFunction;
break;
case AST_AsyncGeneratorDefun:
ctor = AST_AsyncGeneratorFunction;
break;
case AST_Defun:
ctor = AST_Function;
break;
case AST_GeneratorDefun:
ctor = AST_GeneratorFunction;
break;
}
var fn = make_node(ctor, defun, defun);
fn.name = drop_name ? null : make_node(AST_SymbolLambda, defun.name, defun.name);
return fn;
}
AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
if (!compressor.option("unused")) return;
var self = this;
@@ -5632,7 +5653,7 @@ merge(Compressor.prototype, {
in_use.push(def);
}
initializations.add(def.id, node);
return true; // don't go in nested scopes
if (!(tw.parent() instanceof AST_ExportDefault)) return true;
}
if (node instanceof AST_Definitions) {
node.definitions.forEach(function(defn) {
@@ -5828,6 +5849,7 @@ merge(Compressor.prototype, {
if (!(def.id in in_use_ids)) {
log(node.name, "Dropping unused function {name}");
def.eliminated++;
if (parent instanceof AST_ExportDefault) return to_func_expr(node, true);
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
}
}
@@ -9973,25 +9995,7 @@ merge(Compressor.prototype, {
def.single_use = false;
fixed._squeezed = true;
fixed.single_use = true;
if (fixed instanceof AST_LambdaDefinition) {
var ctor;
switch (fixed.CTOR) {
case AST_AsyncDefun:
ctor = AST_AsyncFunction;
break;
case AST_AsyncGeneratorDefun:
ctor = AST_AsyncGeneratorFunction;
break;
case AST_Defun:
ctor = AST_Function;
break;
case AST_GeneratorDefun:
ctor = AST_GeneratorFunction;
break;
}
fixed = make_node(ctor, fixed, fixed);
fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
}
if (fixed instanceof AST_LambdaDefinition) fixed = to_func_expr(fixed);
if (fixed instanceof AST_Lambda) {
var scope = self.scope.resolve();
fixed.enclosed.forEach(function(def) {

View File

@@ -663,14 +663,11 @@ function OutputStream(options) {
// the first token to appear in a statement.
function needs_parens_function(output) {
if (!output.has_parens() && first_in_statement(output)) return true;
if (output.option("webkit")) {
var p = output.parent();
if (p instanceof AST_PropAccess && p.expression === this) return true;
}
if (output.option("wrap_iife")) {
var p = output.parent();
if (p instanceof AST_Call && p.expression === this) return true;
}
var p = output.parent();
// export default (function() {})()
if (p && p.TYPE == "Call" && output.parent(1) instanceof AST_ExportDefault) return true;
if (output.option("webkit") && p instanceof AST_PropAccess && p.expression === this) return true;
if (output.option("wrap_iife") && p instanceof AST_Call && p.expression === this) return true;
}
PARENS(AST_AsyncFunction, needs_parens_function);
PARENS(AST_AsyncGeneratorFunction, needs_parens_function);
@@ -1018,7 +1015,7 @@ function OutputStream(options) {
output.print("default");
output.space();
this.body.print(output);
output.semicolon();
if (!(this.body instanceof AST_Lambda) || is_arrow(this.body)) output.semicolon();
});
DEFPRINT(AST_ExportForeign, function(output) {
var self = this;

View File

@@ -1351,13 +1351,46 @@ function parse($TEXT, options) {
}
if (is("keyword", "default")) {
next();
var body = expression();
semicolon();
var start = S.token;
var body = export_default_decl();
if (body) {
body.start = start;
body.end = prev();
} else {
body = expression();
semicolon();
}
return new AST_ExportDefault({ body: body });
}
return new AST_ExportDeclaration({ body: export_decl() });
}
function maybe_named(def, exp) {
var node = function_(exp);
if (node.name) {
node = new def(node);
node.name = new AST_SymbolDefun(node.name);
}
return node;
}
function export_default_decl() {
switch (S.token.value) {
case "async":
if (!is_token(peek(), "keyword", "function")) return;
next();
next();
if (!is("operator", "*")) return maybe_named(AST_AsyncDefun, AST_AsyncFunction);
next();
return maybe_named(AST_AsyncGeneratorDefun, AST_AsyncGeneratorFunction);
case "function":
next();
if (!is("operator", "*")) return maybe_named(AST_Defun, AST_Function);
next();
return maybe_named(AST_GeneratorDefun, AST_GeneratorFunction);
}
}
var export_decl = embed_tokens(function() {
switch (S.token.value) {
case "async":