fix corner cases with export default (#4673)
This commit is contained in:
@@ -1060,7 +1060,7 @@ var AST_ExportDeclaration = DEFNODE("ExportDeclaration", "body", {
|
|||||||
var AST_ExportDefault = DEFNODE("ExportDefault", "body", {
|
var AST_ExportDefault = DEFNODE("ExportDefault", "body", {
|
||||||
$documentation: "An `export default` statement",
|
$documentation: "An `export default` statement",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
body: "[AST_Node] an expression node (should not be instanceof AST_Statement)",
|
body: "[AST_Node] the default export",
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
@@ -1069,7 +1069,11 @@ var AST_ExportDefault = DEFNODE("ExportDefault", "body", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_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);
|
}, AST_Statement);
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
||||||
if (!compressor.option("unused")) return;
|
if (!compressor.option("unused")) return;
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -5632,7 +5653,7 @@ merge(Compressor.prototype, {
|
|||||||
in_use.push(def);
|
in_use.push(def);
|
||||||
}
|
}
|
||||||
initializations.add(def.id, node);
|
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) {
|
if (node instanceof AST_Definitions) {
|
||||||
node.definitions.forEach(function(defn) {
|
node.definitions.forEach(function(defn) {
|
||||||
@@ -5828,6 +5849,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!(def.id in in_use_ids)) {
|
if (!(def.id in in_use_ids)) {
|
||||||
log(node.name, "Dropping unused function {name}");
|
log(node.name, "Dropping unused function {name}");
|
||||||
def.eliminated++;
|
def.eliminated++;
|
||||||
|
if (parent instanceof AST_ExportDefault) return to_func_expr(node, true);
|
||||||
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9973,25 +9995,7 @@ merge(Compressor.prototype, {
|
|||||||
def.single_use = false;
|
def.single_use = false;
|
||||||
fixed._squeezed = true;
|
fixed._squeezed = true;
|
||||||
fixed.single_use = true;
|
fixed.single_use = true;
|
||||||
if (fixed instanceof AST_LambdaDefinition) {
|
if (fixed instanceof AST_LambdaDefinition) fixed = to_func_expr(fixed);
|
||||||
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_Lambda) {
|
if (fixed instanceof AST_Lambda) {
|
||||||
var scope = self.scope.resolve();
|
var scope = self.scope.resolve();
|
||||||
fixed.enclosed.forEach(function(def) {
|
fixed.enclosed.forEach(function(def) {
|
||||||
|
|||||||
@@ -663,14 +663,11 @@ function OutputStream(options) {
|
|||||||
// the first token to appear in a statement.
|
// the first token to appear in a statement.
|
||||||
function needs_parens_function(output) {
|
function needs_parens_function(output) {
|
||||||
if (!output.has_parens() && first_in_statement(output)) return true;
|
if (!output.has_parens() && first_in_statement(output)) return true;
|
||||||
if (output.option("webkit")) {
|
var p = output.parent();
|
||||||
var p = output.parent();
|
// export default (function() {})()
|
||||||
if (p instanceof AST_PropAccess && p.expression === this) return true;
|
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")) {
|
if (output.option("wrap_iife") && p instanceof AST_Call && p.expression === this) return true;
|
||||||
var p = output.parent();
|
|
||||||
if (p instanceof AST_Call && p.expression === this) return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PARENS(AST_AsyncFunction, needs_parens_function);
|
PARENS(AST_AsyncFunction, needs_parens_function);
|
||||||
PARENS(AST_AsyncGeneratorFunction, needs_parens_function);
|
PARENS(AST_AsyncGeneratorFunction, needs_parens_function);
|
||||||
@@ -1018,7 +1015,7 @@ function OutputStream(options) {
|
|||||||
output.print("default");
|
output.print("default");
|
||||||
output.space();
|
output.space();
|
||||||
this.body.print(output);
|
this.body.print(output);
|
||||||
output.semicolon();
|
if (!(this.body instanceof AST_Lambda) || is_arrow(this.body)) output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_ExportForeign, function(output) {
|
DEFPRINT(AST_ExportForeign, function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|||||||
37
lib/parse.js
37
lib/parse.js
@@ -1351,13 +1351,46 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
if (is("keyword", "default")) {
|
if (is("keyword", "default")) {
|
||||||
next();
|
next();
|
||||||
var body = expression();
|
var start = S.token;
|
||||||
semicolon();
|
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_ExportDefault({ body: body });
|
||||||
}
|
}
|
||||||
return new AST_ExportDeclaration({ body: export_decl() });
|
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() {
|
var export_decl = embed_tokens(function() {
|
||||||
switch (S.token.value) {
|
switch (S.token.value) {
|
||||||
case "async":
|
case "async":
|
||||||
|
|||||||
@@ -32,7 +32,25 @@ defaults: {
|
|||||||
export default function*(a, b) {};
|
export default function*(a, b) {};
|
||||||
export default async function f({ c }, ...[ d ]) {};
|
export default async function f({ c }, ...[ d ]) {};
|
||||||
}
|
}
|
||||||
expect_exact: "export default 42;export default(x,y)=>x*x;export default function*(a,b){};export default async function f({c:c},...[d]){};"
|
expect_exact: "export default 42;export default(x,y)=>x*x;export default function*(a,b){}export default async function f({c:c},...[d]){}"
|
||||||
|
}
|
||||||
|
|
||||||
|
defaults_parenthesis_1: {
|
||||||
|
input: {
|
||||||
|
export default function() {
|
||||||
|
console.log("FAIL");
|
||||||
|
}(console.log("PASS"));
|
||||||
|
}
|
||||||
|
expect_exact: 'export default function(){console.log("FAIL")}console.log("PASS");'
|
||||||
|
}
|
||||||
|
|
||||||
|
defaults_parenthesis_2: {
|
||||||
|
input: {
|
||||||
|
export default (async function() {
|
||||||
|
console.log("PASS");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_exact: 'export default(async function(){console.log("PASS")})();'
|
||||||
}
|
}
|
||||||
|
|
||||||
foreign: {
|
foreign: {
|
||||||
@@ -108,8 +126,8 @@ mangle: {
|
|||||||
t(o, f);
|
t(o, f);
|
||||||
}
|
}
|
||||||
export default t;
|
export default t;
|
||||||
export default async function t(o, ...{ [c]: e}) {
|
export default async function e(t, ...{ [c]: o}) {
|
||||||
(await o)(t, e);
|
(await t)(e, o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,8 +155,8 @@ mangle_rename: {
|
|||||||
t(o, f);
|
t(o, f);
|
||||||
}
|
}
|
||||||
export default t;
|
export default t;
|
||||||
export default async function t(o, ...{ [c]: e}) {
|
export default async function e(t, ...{ [c]: o}) {
|
||||||
(await o)(t, e);
|
(await t)(e, o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,8 +189,8 @@ hoist_exports: {
|
|||||||
t(a, c);
|
t(a, c);
|
||||||
}
|
}
|
||||||
export default 42;
|
export default 42;
|
||||||
export default async function t(a, ...{ [o]: f }) {
|
export default async function e(t, ...{ [o]: a }) {
|
||||||
(await a)(t, f);
|
(await t)(e, a);
|
||||||
};
|
};
|
||||||
export { f as bbb, o as ccc, c as fff };
|
export { f as bbb, o as ccc, c as fff };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user