Properly parse export default from when exportDefaultFrom is not enabled (#11676)
Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
This commit is contained in:
parent
3874470841
commit
71d3527ef5
@ -42,6 +42,8 @@ export const ErrorMessages = Object.freeze({
|
|||||||
DuplicateRegExpFlags: "Duplicate regular expression flag",
|
DuplicateRegExpFlags: "Duplicate regular expression flag",
|
||||||
ElementAfterRest: "Rest element must be last element",
|
ElementAfterRest: "Rest element must be last element",
|
||||||
EscapedCharNotAnIdentifier: "Invalid Unicode escape",
|
EscapedCharNotAnIdentifier: "Invalid Unicode escape",
|
||||||
|
ExportDefaultFromAsIdentifier:
|
||||||
|
"'from' is not allowed as an identifier after 'export default'",
|
||||||
ForInOfLoopInitializer:
|
ForInOfLoopInitializer:
|
||||||
"%0 loop variable declaration may not have an initializer",
|
"%0 loop variable declaration may not have an initializer",
|
||||||
GeneratorInSingleStatementContext:
|
GeneratorInSingleStatementContext:
|
||||||
|
|||||||
@ -1857,10 +1857,24 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const next = this.nextTokenStart();
|
const next = this.nextTokenStart();
|
||||||
return (
|
const hasFrom = this.isUnparsedContextual(next, "from");
|
||||||
|
if (
|
||||||
this.input.charCodeAt(next) === charCodes.comma ||
|
this.input.charCodeAt(next) === charCodes.comma ||
|
||||||
this.isUnparsedContextual(next, "from")
|
(this.match(tt.name) && hasFrom)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// lookahead again when `export default from` is seen
|
||||||
|
if (this.match(tt._default) && hasFrom) {
|
||||||
|
const nextAfterFrom = this.input.charCodeAt(
|
||||||
|
this.nextTokenStartSince(next + 4),
|
||||||
);
|
);
|
||||||
|
return (
|
||||||
|
nextAfterFrom === charCodes.quotationMark ||
|
||||||
|
nextAfterFrom === charCodes.apostrophe
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseExportFrom(node: N.ExportNamedDeclaration, expect?: boolean): void {
|
parseExportFrom(node: N.ExportNamedDeclaration, expect?: boolean): void {
|
||||||
@ -1911,6 +1925,18 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
if (isDefault) {
|
if (isDefault) {
|
||||||
// Default exports
|
// Default exports
|
||||||
this.checkDuplicateExports(node, "default");
|
this.checkDuplicateExports(node, "default");
|
||||||
|
if (this.hasPlugin("exportDefaultFrom")) {
|
||||||
|
const declaration = ((node: any): N.ExportDefaultDeclaration)
|
||||||
|
.declaration;
|
||||||
|
if (
|
||||||
|
declaration.type === "Identifier" &&
|
||||||
|
declaration.name === "from" &&
|
||||||
|
declaration.end - declaration.start === 4 && // does not contain escape
|
||||||
|
!declaration.extra?.parenthesized
|
||||||
|
) {
|
||||||
|
this.raise(declaration.start, Errors.ExportDefaultFromAsIdentifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (node.specifiers && node.specifiers.length) {
|
} else if (node.specifiers && node.specifiers.length) {
|
||||||
// Named exports
|
// Named exports
|
||||||
for (const specifier of node.specifiers) {
|
for (const specifier of node.specifiers) {
|
||||||
|
|||||||
@ -251,6 +251,23 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
return super.parseExport(node);
|
return super.parseExport(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isExportDefaultSpecifier(): boolean {
|
||||||
|
if (this.match(tt._default)) {
|
||||||
|
const next = this.nextTokenStart();
|
||||||
|
if (this.isUnparsedContextual(next, "from")) {
|
||||||
|
if (
|
||||||
|
this.input.startsWith(
|
||||||
|
tt.placeholder.label,
|
||||||
|
this.nextTokenStartSince(next + 4),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.isExportDefaultSpecifier();
|
||||||
|
}
|
||||||
|
|
||||||
maybeParseExportDefaultSpecifier(node: N.Node): boolean {
|
maybeParseExportDefaultSpecifier(node: N.Node): boolean {
|
||||||
if (node.specifiers && node.specifiers.length > 0) {
|
if (node.specifiers && node.specifiers.length > 0) {
|
||||||
// "export %%NAME%%" has already been parsed by #parseExport.
|
// "export %%NAME%%" has already been parsed by #parseExport.
|
||||||
|
|||||||
@ -190,11 +190,14 @@ export default class Tokenizer extends ParserErrors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nextTokenStart(): number {
|
nextTokenStart(): number {
|
||||||
const thisTokEnd = this.state.pos;
|
return this.nextTokenStartSince(this.state.pos);
|
||||||
skipWhiteSpace.lastIndex = thisTokEnd;
|
}
|
||||||
|
|
||||||
|
nextTokenStartSince(pos: number): number {
|
||||||
|
skipWhiteSpace.lastIndex = pos;
|
||||||
const skip = skipWhiteSpace.exec(this.input);
|
const skip = skipWhiteSpace.exec(this.input);
|
||||||
// $FlowIgnore: The skipWhiteSpace ensures to match any string
|
// $FlowIgnore: The skipWhiteSpace ensures to match any string
|
||||||
return thisTokEnd + skip[0].length;
|
return pos + skip[0].length;
|
||||||
}
|
}
|
||||||
|
|
||||||
lookaheadCharCode(): number {
|
lookaheadCharCode(): number {
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
export default from (bar);
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}},
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}},
|
||||||
|
"sourceType": "module",
|
||||||
|
"interpreter": null,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExportDefaultDeclaration",
|
||||||
|
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}},
|
||||||
|
"declaration": {
|
||||||
|
"type": "CallExpression",
|
||||||
|
"start":15,"end":25,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":25}},
|
||||||
|
"callee": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":15,"end":19,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":19},"identifierName":"from"},
|
||||||
|
"name": "from"
|
||||||
|
},
|
||||||
|
"arguments": [
|
||||||
|
{
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":21,"end":24,"loc":{"start":{"line":1,"column":21},"end":{"line":1,"column":24},"identifierName":"bar"},
|
||||||
|
"name": "bar"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export default from ?? 42;
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}},
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}},
|
||||||
|
"sourceType": "module",
|
||||||
|
"interpreter": null,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExportDefaultDeclaration",
|
||||||
|
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}},
|
||||||
|
"declaration": {
|
||||||
|
"type": "LogicalExpression",
|
||||||
|
"start":15,"end":25,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":25}},
|
||||||
|
"left": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":15,"end":19,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":19},"identifierName":"from"},
|
||||||
|
"name": "from"
|
||||||
|
},
|
||||||
|
"operator": "??",
|
||||||
|
"right": {
|
||||||
|
"type": "NumericLiteral",
|
||||||
|
"start":23,"end":25,"loc":{"start":{"line":1,"column":23},"end":{"line":1,"column":25}},
|
||||||
|
"extra": {
|
||||||
|
"rawValue": 42,
|
||||||
|
"raw": "42"
|
||||||
|
},
|
||||||
|
"value": 42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export default from;
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start":0,"end":20,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":20}},
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start":0,"end":20,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":20}},
|
||||||
|
"sourceType": "module",
|
||||||
|
"interpreter": null,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExportDefaultDeclaration",
|
||||||
|
"start":0,"end":20,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":20}},
|
||||||
|
"declaration": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":15,"end":19,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":19},"identifierName":"from"},
|
||||||
|
"name": "from"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export default from
|
||||||
|
"bar";
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"sourceType": "module",
|
||||||
|
"plugins": ["exportDefaultFrom"]
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":6}},
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":6}},
|
||||||
|
"sourceType": "module",
|
||||||
|
"interpreter": null,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExportNamedDeclaration",
|
||||||
|
"start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":6}},
|
||||||
|
"specifiers": [
|
||||||
|
{
|
||||||
|
"type": "ExportDefaultSpecifier",
|
||||||
|
"start":7,"end":14,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":14}},
|
||||||
|
"exported": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":7,"end":14,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":14},"identifierName":"default"},
|
||||||
|
"name": "default"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": {
|
||||||
|
"type": "StringLiteral",
|
||||||
|
"start":20,"end":25,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":5}},
|
||||||
|
"extra": {
|
||||||
|
"rawValue": "bar",
|
||||||
|
"raw": "\"bar\""
|
||||||
|
},
|
||||||
|
"value": "bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export default \u{66}rom;
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["exportDefaultFrom"],
|
||||||
|
"sourceType": "module"
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":25}},
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":25}},
|
||||||
|
"sourceType": "module",
|
||||||
|
"interpreter": null,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExportDefaultDeclaration",
|
||||||
|
"start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":25}},
|
||||||
|
"declaration": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":15,"end":24,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":24},"identifierName":"from"},
|
||||||
|
"name": "from"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export default (from);
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["exportDefaultFrom"],
|
||||||
|
"sourceType": "module"
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}},
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}},
|
||||||
|
"sourceType": "module",
|
||||||
|
"interpreter": null,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExportDefaultDeclaration",
|
||||||
|
"start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}},
|
||||||
|
"declaration": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":16,"end":20,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":20},"identifierName":"from"},
|
||||||
|
"name": "from",
|
||||||
|
"extra": {
|
||||||
|
"parenthesized": true,
|
||||||
|
"parenStart": 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export default from;
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["exportDefaultFrom"],
|
||||||
|
"sourceType": "module"
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start":0,"end":20,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":20}},
|
||||||
|
"errors": [
|
||||||
|
"SyntaxError: 'from' is not allowed as an identifier after 'export default' (1:15)"
|
||||||
|
],
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start":0,"end":20,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":20}},
|
||||||
|
"sourceType": "module",
|
||||||
|
"interpreter": null,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExportDefaultDeclaration",
|
||||||
|
"start":0,"end":20,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":20}},
|
||||||
|
"declaration": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":15,"end":19,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":19},"identifierName":"from"},
|
||||||
|
"name": "from"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user