From 578043a5f77f1f9bf2b6d629b8f2a93ad36ca2b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Tue, 18 May 2021 15:08:13 -0400 Subject: [PATCH 1/8] refactor: simplify parseLiteral interface --- packages/babel-parser/src/parser/expression.js | 18 +++++++++--------- packages/babel-parser/src/plugins/estree.js | 9 ++------- .../babel-parser/src/plugins/flow/index.js | 11 +++++------ 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 43616202ee5f..c2cf0792ec03 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -1398,21 +1398,21 @@ export default class ExpressionParser extends LValParser { return this.parseMetaProperty(node, id, "meta"); } - parseLiteral( + parseLiteralAtNode( value: any, type: /*T["kind"]*/ string, - startPos?: number, - startLoc?: Position, + node: any, ): T { - startPos = startPos || this.state.start; - startLoc = startLoc || this.state.startLoc; - - const node = this.startNodeAt(startPos, startLoc); this.addExtra(node, "rawValue", value); - this.addExtra(node, "raw", this.input.slice(startPos, this.state.end)); + this.addExtra(node, "raw", this.input.slice(node.start, this.state.end)); node.value = value; this.next(); - return this.finishNode(node, type); + return this.finishNode(node, type); + } + + parseLiteral(value: any, type: /*T["kind"]*/ string): T { + const node = this.startNode(); + return this.parseLiteralAtNode(value, type, node); } // https://tc39.es/ecma262/#prod-CoverParenthesizedExpressionAndArrowParameterList diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index 9a592c18b6df..3e7563a71fdc 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -230,13 +230,8 @@ export default (superClass: Class): Class => return node.name; } - parseLiteral( - value: any, - type: /*T["kind"]*/ string, - startPos?: number, - startLoc?: Position, - ): T { - const node = super.parseLiteral(value, type, startPos, startLoc); + parseLiteral(value: any, type: /*T["kind"]*/ string): T { + const node = super.parseLiteral(value, type); node.raw = node.extra.raw; delete node.extra; diff --git a/packages/babel-parser/src/plugins/flow/index.js b/packages/babel-parser/src/plugins/flow/index.js index 36eb19a7368b..0a235919b7ee 100644 --- a/packages/babel-parser/src/plugins/flow/index.js +++ b/packages/babel-parser/src/plugins/flow/index.js @@ -1549,22 +1549,21 @@ export default (superClass: Class): Class => case tt.plusMin: if (this.state.value === "-") { + const node = this.startNode(); this.next(); if (this.match(tt.num)) { - return this.parseLiteral( + return this.parseLiteralAtNode( -this.state.value, "NumberLiteralTypeAnnotation", - node.start, - node.loc.start, + node, ); } if (this.match(tt.bigint)) { - return this.parseLiteral( + return this.parseLiteralAtNode( -this.state.value, "BigIntLiteralTypeAnnotation", - node.start, - node.loc.start, + node, ); } From 8674f1142661f8a922188c971446ab8c3080f214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Tue, 18 May 2021 16:28:51 -0400 Subject: [PATCH 2/8] refactor: extract specific methods on parsing literals --- .../babel-parser/src/parser/expression.js | 68 +++++++++++++------ packages/babel-parser/src/parser/statement.js | 14 ++-- packages/babel-parser/src/plugins/estree.js | 53 ++++++--------- .../babel-parser/src/plugins/flow/index.js | 6 +- 4 files changed, 75 insertions(+), 66 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index c2cf0792ec03..4713114e9ce2 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -1068,33 +1068,28 @@ export default class ExpressionParser extends LValParser { } case tt.regexp: { - const value = this.state.value; - node = this.parseLiteral(value.value, "RegExpLiteral"); - node.pattern = value.pattern; - node.flags = value.flags; - return node; + return this.parseRegExpLiteral(this.state.value); } case tt.num: - return this.parseLiteral(this.state.value, "NumericLiteral"); + return this.parseNumericLiteral(this.state.value); case tt.bigint: - return this.parseLiteral(this.state.value, "BigIntLiteral"); + return this.parseBigIntLiteral(this.state.value); case tt.decimal: - return this.parseLiteral(this.state.value, "DecimalLiteral"); + return this.parseDecimalLiteral(this.state.value); case tt.string: - return this.parseLiteral(this.state.value, "StringLiteral"); + return this.parseStringLiteral(this.state.value); case tt._null: - node = this.startNode(); - this.next(); - return this.finishNode(node, "NullLiteral"); + return this.parseNullLiteral(); case tt._true: + return this.parseBooleanLiteral(true); case tt._false: - return this.parseBooleanLiteral(); + return this.parseBooleanLiteral(false); case tt.parenL: return this.parseParenAndDistinguishExpression(canBeArrow); @@ -1290,13 +1285,6 @@ export default class ExpressionParser extends LValParser { return this.finishNode(node, "Super"); } - parseBooleanLiteral(): N.BooleanLiteral { - const node = this.startNode(); - node.value = this.match(tt._true); - this.next(); - return this.finishNode(node, "BooleanLiteral"); - } - parseMaybePrivateName( isPrivateNameAllowed: boolean, ): N.PrivateName | N.Identifier { @@ -1415,6 +1403,46 @@ export default class ExpressionParser extends LValParser { return this.parseLiteralAtNode(value, type, node); } + parseStringLiteral(value: any): any { + return this.parseLiteral(value, "StringLiteral"); + } + + parseNumericLiteral(value: any): any { + return this.parseLiteral(value, "NumericLiteral"); + } + + parseBigIntLiteral(value: any): any { + return this.parseLiteral(value, "BigIntLiteral"); + } + + parseDecimalLiteral(value: any): any { + return this.parseLiteral(value, "DecimalLiteral"); + } + + parseRegExpLiteral(value: { + value: any, + pattern: string, + flags: string, + }): N.RegExpLiteral { + const node = this.parseLiteral(value.value, "RegExpLiteral"); + node.pattern = value.pattern; + node.flags = value.flags; + return node; + } + + parseBooleanLiteral(value: boolean): N.BooleanLiteral { + const node = this.startNode(); + node.value = value; + this.next(); + return this.finishNode(node, "BooleanLiteral"); + } + + parseNullLiteral(): N.NullLiteral { + const node = this.startNode(); + this.next(); + return this.finishNode(node, "NullLiteral"); + } + // https://tc39.es/ecma262/#prod-CoverParenthesizedExpressionAndArrowParameterList parseParenAndDistinguishExpression(canBeArrow: boolean): N.Expression { const startPos = this.state.start; diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index 7aefb14a4f49..d10ce33d7e19 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -2157,10 +2157,7 @@ export default class StatementParser extends ExpressionParser { // https://tc39.es/ecma262/#prod-ModuleExportName parseModuleExportName(): N.StringLiteral | N.Identifier { if (this.match(tt.string)) { - const result = this.parseLiteral( - this.state.value, - "StringLiteral", - ); + const result = this.parseStringLiteral(this.state.value); const surrogate = result.value.match(loneSurrogate); if (surrogate) { this.raise( @@ -2259,7 +2256,7 @@ export default class StatementParser extends ExpressionParser { // parse AssertionKey : IdentifierName, StringLiteral const keyName = this.state.value; if (this.match(tt.string)) { - node.key = this.parseLiteral(keyName, "StringLiteral"); + node.key = this.parseStringLiteral(keyName); } else { node.key = this.parseIdentifier(true); } @@ -2291,10 +2288,7 @@ export default class StatementParser extends ExpressionParser { Errors.ModuleAttributeInvalidValue, ); } - node.value = this.parseLiteral( - this.state.value, - "StringLiteral", - ); + node.value = this.parseStringLiteral(this.state.value); this.finishNode(node, "ImportAttribute"); attrs.push(node); } while (this.eat(tt.comma)); @@ -2345,7 +2339,7 @@ export default class StatementParser extends ExpressionParser { Errors.ModuleAttributeInvalidValue, ); } - node.value = this.parseLiteral(this.state.value, "StringLiteral"); + node.value = this.parseStringLiteral(this.state.value); this.finishNode(node, "ImportAttribute"); attrs.push(node); } while (this.eat(tt.comma)); diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index 3e7563a71fdc..e3d288e2455c 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -1,6 +1,6 @@ // @flow -import { types as tt, TokenType } from "../tokenizer/types"; +import { TokenType } from "../tokenizer/types"; import type Parser from "../parser"; import type { ExpressionErrors } from "../parser/util"; import * as N from "../types"; @@ -9,7 +9,7 @@ import { Errors } from "../parser/error"; export default (superClass: Class): Class => class extends superClass { - estreeParseRegExpLiteral({ pattern, flags }: N.RegExpLiteral): N.Node { + parseRegExpLiteral({ pattern, flags }): N.Node { let regex = null; try { regex = new RegExp(pattern, flags); @@ -23,7 +23,7 @@ export default (superClass: Class): Class => return node; } - estreeParseBigIntLiteral(value: any): N.Node { + parseBigIntLiteral(value: any): N.Node { // https://github.com/estree/estree/blob/master/es2020.md#bigintliteral let bigInt; try { @@ -38,7 +38,7 @@ export default (superClass: Class): Class => return node; } - estreeParseDecimalLiteral(value: any): N.Node { + parseDecimalLiteral(value: any): N.Node { // https://github.com/estree/estree/blob/master/experimental/decimal.md // todo: use BigDecimal when node supports it. const decimal = null; @@ -52,6 +52,22 @@ export default (superClass: Class): Class => return this.parseLiteral(value, "Literal"); } + parseStringLiteral(value: any): N.Node { + return this.estreeParseLiteral(value); + } + + parseNumericLiteral(value: any): any { + return this.estreeParseLiteral(value); + } + + parseNullLiteral(): N.Node { + return this.estreeParseLiteral(null); + } + + parseBooleanLiteral(value: boolean): N.BooleanLiteral { + return this.estreeParseLiteral(value); + } + directiveToStmt(directive: N.Directive): N.ExpressionStatement { const directiveLiteral = directive.value; @@ -165,35 +181,6 @@ export default (superClass: Class): Class => classBody.body.push(method); } - parseExprAtom(refExpressionErrors?: ?ExpressionErrors): N.Expression { - switch (this.state.type) { - case tt.num: - case tt.string: - return this.estreeParseLiteral(this.state.value); - - case tt.regexp: - return this.estreeParseRegExpLiteral(this.state.value); - - case tt.bigint: - return this.estreeParseBigIntLiteral(this.state.value); - - case tt.decimal: - return this.estreeParseDecimalLiteral(this.state.value); - - case tt._null: - return this.estreeParseLiteral(null); - - case tt._true: - return this.estreeParseLiteral(true); - - case tt._false: - return this.estreeParseLiteral(false); - - default: - return super.parseExprAtom(refExpressionErrors); - } - } - parseMaybePrivateName(...args: [boolean]): any { const node = super.parseMaybePrivateName(...args); if ( diff --git a/packages/babel-parser/src/plugins/flow/index.js b/packages/babel-parser/src/plugins/flow/index.js index 0a235919b7ee..660800f0f898 100644 --- a/packages/babel-parser/src/plugins/flow/index.js +++ b/packages/babel-parser/src/plugins/flow/index.js @@ -3387,14 +3387,14 @@ export default (superClass: Class): Class => const endOfInit = () => this.match(tt.comma) || this.match(tt.braceR); switch (this.state.type) { case tt.num: { - const literal = this.parseLiteral(this.state.value, "NumericLiteral"); + const literal = this.parseNumericLiteral(this.state.value); if (endOfInit()) { return { type: "number", pos: literal.start, value: literal }; } return { type: "invalid", pos: startPos }; } case tt.string: { - const literal = this.parseLiteral(this.state.value, "StringLiteral"); + const literal = this.parseStringLiteral(this.state.value); if (endOfInit()) { return { type: "string", pos: literal.start, value: literal }; } @@ -3402,7 +3402,7 @@ export default (superClass: Class): Class => } case tt._true: case tt._false: { - const literal = this.parseBooleanLiteral(); + const literal = this.parseBooleanLiteral(this.match(tt._true)); if (endOfInit()) { return { type: "boolean", From 9c3d4fdfc43f38549f48152be5241e0a2d67a31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Tue, 18 May 2021 16:31:05 -0400 Subject: [PATCH 3/8] fix: avoid StringLiteral type comparison --- packages/babel-parser/src/parser/statement.js | 5 +++-- packages/babel-parser/src/plugins/flow/index.js | 8 +++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index d10ce33d7e19..f3c9772c3023 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -2041,7 +2041,7 @@ export default class StatementParser extends ExpressionParser { // $FlowIgnore if (!isFrom && specifier.local) { const { local } = specifier; - if (local.type === "StringLiteral") { + if (local.type !== "Identifier") { this.raise( specifier.start, Errors.ExportBindingIsString, @@ -2418,12 +2418,13 @@ export default class StatementParser extends ExpressionParser { // https://tc39.es/ecma262/#prod-ImportSpecifier parseImportSpecifier(node: N.ImportDeclaration): void { const specifier = this.startNode(); + const importedIsString = this.match(tt.string); specifier.imported = this.parseModuleExportName(); if (this.eatContextual("as")) { specifier.local = this.parseIdentifier(); } else { const { imported } = specifier; - if (imported.type === "StringLiteral") { + if (importedIsString) { throw this.raise( specifier.start, Errors.ImportBindingIsString, diff --git a/packages/babel-parser/src/plugins/flow/index.js b/packages/babel-parser/src/plugins/flow/index.js index 660800f0f898..305c1825170f 100644 --- a/packages/babel-parser/src/plugins/flow/index.js +++ b/packages/babel-parser/src/plugins/flow/index.js @@ -2668,7 +2668,7 @@ export default (superClass: Class): Class => // parse import-type/typeof shorthand parseImportSpecifier(node: N.ImportDeclaration): void { const specifier = this.startNode(); - const firstIdentLoc = this.state.start; + const fistIdentIsString = this.match(tt.string); const firstIdent = this.parseModuleExportName(); let specifierTypeKind = null; @@ -2712,13 +2712,15 @@ export default (superClass: Class): Class => specifier.local = specifier.imported.__clone(); } } else { - if (firstIdent.type === "StringLiteral") { + if (fistIdentIsString) { + /*:: invariant(firstIdent instanceof N.StringLiteral) */ throw this.raise( specifier.start, Errors.ImportBindingIsString, firstIdent.value, ); } + /*:: invariant(firstIdent instanceof N.Node) */ isBinding = true; specifier.imported = firstIdent; specifier.importKind = null; @@ -2730,7 +2732,7 @@ export default (superClass: Class): Class => if (nodeIsTypeImport && specifierIsTypeImport) { this.raise( - firstIdentLoc, + specifier.start, FlowErrors.ImportTypeShorthandOnlyInPureImport, ); } From c934cadf61f5cb6cacefba95276d874140a5b7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Tue, 18 May 2021 16:37:09 -0400 Subject: [PATCH 4/8] add test cases --- .../valid-syntax-with-attributes/input.js | 1 + .../valid-syntax-with-attributes/options.json | 3 + .../valid-syntax-with-attributes/output.json | 54 +++++++++++ .../estree/module-string-names/mixed/input.js | 2 + .../module-string-names/mixed/options.json | 3 + .../module-string-names/mixed/output.json | 96 +++++++++++++++++++ 6 files changed, 159 insertions(+) create mode 100644 packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/input.js create mode 100644 packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/options.json create mode 100644 packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/output.json create mode 100644 packages/babel-parser/test/fixtures/estree/module-string-names/mixed/input.js create mode 100644 packages/babel-parser/test/fixtures/estree/module-string-names/mixed/options.json create mode 100644 packages/babel-parser/test/fixtures/estree/module-string-names/mixed/output.json diff --git a/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/input.js b/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/input.js new file mode 100644 index 000000000000..7b43091236b9 --- /dev/null +++ b/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/input.js @@ -0,0 +1 @@ +import foo from "foo.json" assert { type: "json" }; diff --git a/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/options.json b/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/options.json new file mode 100644 index 000000000000..478bc014191c --- /dev/null +++ b/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["flow", "jsx", "estree", "importAssertions"] +} diff --git a/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/output.json b/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/output.json new file mode 100644 index 000000000000..13e1bafa7935 --- /dev/null +++ b/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/output.json @@ -0,0 +1,54 @@ +{ + "type": "File", + "start":0,"end":51,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":51}}, + "errors": [ + "SyntaxError: 'import' and 'export' may appear only with 'sourceType: \"module\"' (1:0)" + ], + "program": { + "type": "Program", + "start":0,"end":51,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":51}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ImportDeclaration", + "start":0,"end":51,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":51}}, + "specifiers": [ + { + "type": "ImportDefaultSpecifier", + "start":7,"end":10,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":10}}, + "local": { + "type": "Identifier", + "start":7,"end":10,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":10},"identifierName":"foo"}, + "name": "foo" + } + } + ], + "importKind": "value", + "source": { + "type": "Literal", + "start":16,"end":26,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":26}}, + "value": "foo.json", + "raw": "\"foo.json\"" + }, + "assertions": [ + { + "type": "ImportAttribute", + "start":36,"end":48,"loc":{"start":{"line":1,"column":36},"end":{"line":1,"column":48}}, + "key": { + "type": "Identifier", + "start":36,"end":40,"loc":{"start":{"line":1,"column":36},"end":{"line":1,"column":40},"identifierName":"type"}, + "name": "type" + }, + "value": { + "type": "Literal", + "start":42,"end":48,"loc":{"start":{"line":1,"column":42},"end":{"line":1,"column":48}}, + "value": "json", + "raw": "\"json\"" + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/estree/module-string-names/mixed/input.js b/packages/babel-parser/test/fixtures/estree/module-string-names/mixed/input.js new file mode 100644 index 000000000000..a6cfd5e177b6 --- /dev/null +++ b/packages/babel-parser/test/fixtures/estree/module-string-names/mixed/input.js @@ -0,0 +1,2 @@ +import { "foo" as bar, "default" as qux } from "module-a"; +export * as "foo", { default as "quux" } from "module-b"; diff --git a/packages/babel-parser/test/fixtures/estree/module-string-names/mixed/options.json b/packages/babel-parser/test/fixtures/estree/module-string-names/mixed/options.json new file mode 100644 index 000000000000..2104ca43283f --- /dev/null +++ b/packages/babel-parser/test/fixtures/estree/module-string-names/mixed/options.json @@ -0,0 +1,3 @@ +{ + "sourceType": "module" +} diff --git a/packages/babel-parser/test/fixtures/estree/module-string-names/mixed/output.json b/packages/babel-parser/test/fixtures/estree/module-string-names/mixed/output.json new file mode 100644 index 000000000000..1005de8ecc72 --- /dev/null +++ b/packages/babel-parser/test/fixtures/estree/module-string-names/mixed/output.json @@ -0,0 +1,96 @@ +{ + "type": "File", + "start":0,"end":116,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":57}}, + "program": { + "type": "Program", + "start":0,"end":116,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":57}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ImportDeclaration", + "start":0,"end":58,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":58}}, + "specifiers": [ + { + "type": "ImportSpecifier", + "start":9,"end":21,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":21}}, + "imported": { + "type": "Literal", + "start":9,"end":14,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":14}}, + "value": "foo", + "raw": "\"foo\"" + }, + "importKind": null, + "local": { + "type": "Identifier", + "start":18,"end":21,"loc":{"start":{"line":1,"column":18},"end":{"line":1,"column":21},"identifierName":"bar"}, + "name": "bar" + } + }, + { + "type": "ImportSpecifier", + "start":23,"end":39,"loc":{"start":{"line":1,"column":23},"end":{"line":1,"column":39}}, + "imported": { + "type": "Literal", + "start":23,"end":32,"loc":{"start":{"line":1,"column":23},"end":{"line":1,"column":32}}, + "value": "default", + "raw": "\"default\"" + }, + "importKind": null, + "local": { + "type": "Identifier", + "start":36,"end":39,"loc":{"start":{"line":1,"column":36},"end":{"line":1,"column":39},"identifierName":"qux"}, + "name": "qux" + } + } + ], + "importKind": "value", + "source": { + "type": "Literal", + "start":47,"end":57,"loc":{"start":{"line":1,"column":47},"end":{"line":1,"column":57}}, + "value": "module-a", + "raw": "\"module-a\"" + } + }, + { + "type": "ExportNamedDeclaration", + "start":59,"end":116,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":57}}, + "specifiers": [ + { + "type": "ExportNamespaceSpecifier", + "start":66,"end":76,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":17}}, + "exported": { + "type": "Literal", + "start":71,"end":76,"loc":{"start":{"line":2,"column":12},"end":{"line":2,"column":17}}, + "value": "foo", + "raw": "\"foo\"" + } + }, + { + "type": "ExportSpecifier", + "start":80,"end":97,"loc":{"start":{"line":2,"column":21},"end":{"line":2,"column":38}}, + "local": { + "type": "Identifier", + "start":80,"end":87,"loc":{"start":{"line":2,"column":21},"end":{"line":2,"column":28},"identifierName":"default"}, + "name": "default" + }, + "exported": { + "type": "Literal", + "start":91,"end":97,"loc":{"start":{"line":2,"column":32},"end":{"line":2,"column":38}}, + "value": "quux", + "raw": "\"quux\"" + } + } + ], + "source": { + "type": "Literal", + "start":105,"end":115,"loc":{"start":{"line":2,"column":46},"end":{"line":2,"column":56}}, + "value": "module-b", + "raw": "\"module-b\"" + }, + "declaration": null, + "exportKind": "value" + } + ] + } +} \ No newline at end of file From 959076891311885b5a58735e2e3f2df90a5bcefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Tue, 18 May 2021 17:00:32 -0400 Subject: [PATCH 5/8] fix: remove redundant node --- packages/babel-parser/src/plugins/flow/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/babel-parser/src/plugins/flow/index.js b/packages/babel-parser/src/plugins/flow/index.js index 305c1825170f..d890aefd1765 100644 --- a/packages/babel-parser/src/plugins/flow/index.js +++ b/packages/babel-parser/src/plugins/flow/index.js @@ -1549,7 +1549,6 @@ export default (superClass: Class): Class => case tt.plusMin: if (this.state.value === "-") { - const node = this.startNode(); this.next(); if (this.match(tt.num)) { return this.parseLiteralAtNode( From ace673c3c19d540ca8ab145b5ca9bb3383693df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Wed, 19 May 2021 07:45:24 -0400 Subject: [PATCH 6/8] Update packages/babel-parser/src/plugins/flow/index.js Co-authored-by: Federico Ciardi --- packages/babel-parser/src/plugins/flow/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/babel-parser/src/plugins/flow/index.js b/packages/babel-parser/src/plugins/flow/index.js index d890aefd1765..ce58e21b80bb 100644 --- a/packages/babel-parser/src/plugins/flow/index.js +++ b/packages/babel-parser/src/plugins/flow/index.js @@ -2667,7 +2667,7 @@ export default (superClass: Class): Class => // parse import-type/typeof shorthand parseImportSpecifier(node: N.ImportDeclaration): void { const specifier = this.startNode(); - const fistIdentIsString = this.match(tt.string); + const firstIdentIsString = this.match(tt.string); const firstIdent = this.parseModuleExportName(); let specifierTypeKind = null; @@ -2711,7 +2711,7 @@ export default (superClass: Class): Class => specifier.local = specifier.imported.__clone(); } } else { - if (fistIdentIsString) { + if (firstIdentIsString) { /*:: invariant(firstIdent instanceof N.StringLiteral) */ throw this.raise( specifier.start, From 72147214bcec6b86e58e5ef4158640229098d3b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Wed, 19 May 2021 09:14:42 -0400 Subject: [PATCH 7/8] update test fixtures --- .../valid-syntax-with-attributes/options.json | 3 ++- .../valid-syntax-with-attributes/output.json | 5 +---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/options.json b/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/options.json index 478bc014191c..bc028a2d77d0 100644 --- a/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/options.json +++ b/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/options.json @@ -1,3 +1,4 @@ { - "plugins": ["flow", "jsx", "estree", "importAssertions"] + "plugins": ["flow", "jsx", "estree", "importAssertions"], + "sourceType": "module" } diff --git a/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/output.json b/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/output.json index 13e1bafa7935..e08a9f151de8 100644 --- a/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/output.json +++ b/packages/babel-parser/test/fixtures/estree/import-assertions/valid-syntax-with-attributes/output.json @@ -1,13 +1,10 @@ { "type": "File", "start":0,"end":51,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":51}}, - "errors": [ - "SyntaxError: 'import' and 'export' may appear only with 'sourceType: \"module\"' (1:0)" - ], "program": { "type": "Program", "start":0,"end":51,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":51}}, - "sourceType": "script", + "sourceType": "module", "interpreter": null, "body": [ { From 4205780a0c8adbd2a494793a6332b5853475dceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Wed, 19 May 2021 14:58:28 -0400 Subject: [PATCH 8/8] fix: refine parseLiteral typings --- .../babel-parser/src/parser/expression.js | 41 +++++++++-------- packages/babel-parser/src/plugins/estree.js | 12 ++--- .../babel-parser/src/plugins/flow/index.js | 11 +++-- packages/babel-parser/src/types.js | 45 ++++++++++++++++++- 4 files changed, 77 insertions(+), 32 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 4713114e9ce2..eb2ddaa9e14e 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -1386,9 +1386,9 @@ export default class ExpressionParser extends LValParser { return this.parseMetaProperty(node, id, "meta"); } - parseLiteralAtNode( + parseLiteralAtNode( value: any, - type: /*T["kind"]*/ string, + type: $ElementType, node: any, ): T { this.addExtra(node, "rawValue", value); @@ -1398,49 +1398,48 @@ export default class ExpressionParser extends LValParser { return this.finishNode(node, type); } - parseLiteral(value: any, type: /*T["kind"]*/ string): T { + parseLiteral(value: any, type: $ElementType): T { const node = this.startNode(); return this.parseLiteralAtNode(value, type, node); } - parseStringLiteral(value: any): any { - return this.parseLiteral(value, "StringLiteral"); + parseStringLiteral(value: any) { + return this.parseLiteral(value, "StringLiteral"); } - parseNumericLiteral(value: any): any { - return this.parseLiteral(value, "NumericLiteral"); + parseNumericLiteral(value: any) { + return this.parseLiteral(value, "NumericLiteral"); } - parseBigIntLiteral(value: any): any { - return this.parseLiteral(value, "BigIntLiteral"); + parseBigIntLiteral(value: any) { + return this.parseLiteral(value, "BigIntLiteral"); } - parseDecimalLiteral(value: any): any { - return this.parseLiteral(value, "DecimalLiteral"); + parseDecimalLiteral(value: any) { + return this.parseLiteral(value, "DecimalLiteral"); } - parseRegExpLiteral(value: { - value: any, - pattern: string, - flags: string, - }): N.RegExpLiteral { - const node = this.parseLiteral(value.value, "RegExpLiteral"); + parseRegExpLiteral(value: { value: any, pattern: string, flags: string }) { + const node = this.parseLiteral( + value.value, + "RegExpLiteral", + ); node.pattern = value.pattern; node.flags = value.flags; return node; } - parseBooleanLiteral(value: boolean): N.BooleanLiteral { + parseBooleanLiteral(value: boolean) { const node = this.startNode(); node.value = value; this.next(); - return this.finishNode(node, "BooleanLiteral"); + return this.finishNode(node, "BooleanLiteral"); } - parseNullLiteral(): N.NullLiteral { + parseNullLiteral() { const node = this.startNode(); this.next(); - return this.finishNode(node, "NullLiteral"); + return this.finishNode(node, "NullLiteral"); } // https://tc39.es/ecma262/#prod-CoverParenthesizedExpressionAndArrowParameterList diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index e3d288e2455c..8d566a1ddd3a 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -17,7 +17,7 @@ export default (superClass: Class): Class => // In environments that don't support these flags value will // be null as the regex can't be represented natively. } - const node = this.estreeParseLiteral(regex); + const node = this.estreeParseLiteral(regex); node.regex = { pattern, flags }; return node; @@ -32,7 +32,7 @@ export default (superClass: Class): Class => } catch { bigInt = null; } - const node = this.estreeParseLiteral(bigInt); + const node = this.estreeParseLiteral(bigInt); node.bigint = String(node.value || value); return node; @@ -48,8 +48,8 @@ export default (superClass: Class): Class => return node; } - estreeParseLiteral(value: any): N.Node { - return this.parseLiteral(value, "Literal"); + estreeParseLiteral(value: any) { + return this.parseLiteral(value, "Literal"); } parseStringLiteral(value: any): N.Node { @@ -217,8 +217,8 @@ export default (superClass: Class): Class => return node.name; } - parseLiteral(value: any, type: /*T["kind"]*/ string): T { - const node = super.parseLiteral(value, type); + parseLiteral(value: any, type: $ElementType): T { + const node = super.parseLiteral(value, type); node.raw = node.extra.raw; delete node.extra; diff --git a/packages/babel-parser/src/plugins/flow/index.js b/packages/babel-parser/src/plugins/flow/index.js index ce58e21b80bb..d9c3c33b94db 100644 --- a/packages/babel-parser/src/plugins/flow/index.js +++ b/packages/babel-parser/src/plugins/flow/index.js @@ -1536,7 +1536,7 @@ export default (superClass: Class): Class => return this.finishNode(node, "FunctionTypeAnnotation"); case tt.string: - return this.parseLiteral( + return this.parseLiteral( this.state.value, "StringLiteralTypeAnnotation", ); @@ -1545,13 +1545,16 @@ export default (superClass: Class): Class => case tt._false: node.value = this.match(tt._true); this.next(); - return this.finishNode(node, "BooleanLiteralTypeAnnotation"); + return this.finishNode( + node, + "BooleanLiteralTypeAnnotation", + ); case tt.plusMin: if (this.state.value === "-") { this.next(); if (this.match(tt.num)) { - return this.parseLiteralAtNode( + return this.parseLiteralAtNode( -this.state.value, "NumberLiteralTypeAnnotation", node, @@ -1559,7 +1562,7 @@ export default (superClass: Class): Class => } if (this.match(tt.bigint)) { - return this.parseLiteralAtNode( + return this.parseLiteralAtNode( -this.state.value, "BigIntLiteralTypeAnnotation", node, diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index c3af5a3fd226..4fd8649ed00a 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -98,7 +98,8 @@ export type Literal = | StringLiteral | BooleanLiteral | NumericLiteral - | BigIntLiteral; + | BigIntLiteral + | DecimalLiteral; export type RegExpLiteral = NodeBase & { type: "RegExpLiteral", @@ -130,6 +131,11 @@ export type BigIntLiteral = NodeBase & { value: number, }; +export type DecimalLiteral = NodeBase & { + type: "DecimalLiteral", + value: number, +}; + export type ParserOutput = { comments: $ReadOnlyArray, errors: Array, @@ -1066,7 +1072,44 @@ export type FlowOptionalIndexedAccessType = Node & { optional: boolean, }; +export type StringLiteralTypeAnnotation = NodeBase & { + type: "StringLiteralTypeAnnotation", + value: string, +}; + +export type BooleanLiteralTypeAnnotation = NodeBase & { + type: "BooleanLiteralTypeAnnotation", + value: boolean, +}; +export type NumberLiteralTypeAnnotation = NodeBase & { + type: "NumberLiteralTypeAnnotation", + value: number, +}; + +export type BigIntLiteralTypeAnnotation = NodeBase & { + type: "BigIntLiteralTypeAnnotation", + //todo(flow): use bigint when Flow supports BigInt + value: number, +}; + // ESTree +export type EstreeLiteral = NodeBase & { + type: "Literal", + value: any, +}; + +type EstreeRegExpLiteralRegex = { + pattern: string, + flags: string, +}; +export type EstreeRegExpLiteral = EstreeLiteral & { + regex: EstreeRegExpLiteralRegex, +}; + +export type EstreeBigIntLiteral = EstreeLiteral & { + value: number | null, + bigint: string, +}; export type EstreeProperty = NodeBase & { type: "Property",