From 958551fd890605515c82cff9ac4b1bacc99027fb Mon Sep 17 00:00:00 2001 From: Logan Smyth Date: Fri, 9 Mar 2018 14:35:55 -0800 Subject: [PATCH 1/2] Refactor unambiguous to track state during parsing. --- packages/babylon/src/index.js | 18 +++--------------- packages/babylon/src/parser/base.js | 1 + packages/babylon/src/parser/statement.js | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/babylon/src/index.js b/packages/babylon/src/index.js index 7071a312b3..a90f0af0f6 100755 --- a/packages/babylon/src/index.js +++ b/packages/babylon/src/index.js @@ -22,11 +22,12 @@ export function parse(input: string, options?: Options): File { options = Object.assign({}, options); try { options.sourceType = "module"; - const ast = getParser(options, input).parse(); + const parser = getParser(options, input); + const ast = parser.parse(); // Rather than try to parse as a script first, we opt to parse as a module and convert back // to a script where possible to avoid having to do a full re-parse of the input content. - if (!hasModuleSyntax(ast)) ast.program.sourceType = "script"; + if (!parser.sawUnambiguousESM) ast.program.sourceType = "script"; return ast; } catch (moduleError) { try { @@ -111,16 +112,3 @@ function getParserClass( } return cls; } - -function hasModuleSyntax(ast) { - return ast.program.body.some( - child => - (child.type === "ImportDeclaration" && - (!child.importKind || child.importKind === "value")) || - (child.type === "ExportNamedDeclaration" && - (!child.exportKind || child.exportKind === "value")) || - (child.type === "ExportAllDeclaration" && - (!child.exportKind || child.exportKind === "value")) || - child.type === "ExportDefaultDeclaration", - ); -} diff --git a/packages/babylon/src/parser/base.js b/packages/babylon/src/parser/base.js index 972d60c800..6e7ab90d65 100644 --- a/packages/babylon/src/parser/base.js +++ b/packages/babylon/src/parser/base.js @@ -11,6 +11,7 @@ export default class BaseParser { inModule: boolean; plugins: { [key: string]: boolean }; filename: ?string; + sawUnambiguousESM: boolean = false; // Initialized by Tokenizer state: State; diff --git a/packages/babylon/src/parser/statement.js b/packages/babylon/src/parser/statement.js index a014806c51..f86f7af9b9 100644 --- a/packages/babylon/src/parser/statement.js +++ b/packages/babylon/src/parser/statement.js @@ -146,8 +146,25 @@ export default class StatementParser extends ExpressionParser { let result; if (starttype == tt._import) { result = this.parseImport(node); + + if ( + result.type === "ImportDeclaration" && + (!result.importKind || result.importKind === "value") + ) { + this.sawUnambiguousESM = true; + } } else { result = this.parseExport(node); + + if ( + (result.type === "ExportNamedDeclaration" && + (!result.exportKind || result.exportKind === "value")) || + (result.type === "ExportAllDeclaration" && + (!result.exportKind || result.exportKind === "value")) || + result.type === "ExportDefaultDeclaration" + ) { + this.sawUnambiguousESM = true; + } } this.assertModuleNodeAllowed(node); From 3c8e9acd4a77e99e4442e2b6833782276e49cb1c Mon Sep 17 00:00:00 2001 From: Logan Smyth Date: Fri, 9 Mar 2018 14:44:06 -0800 Subject: [PATCH 2/2] Make the unambiguous grammar select module when import.meta is used. --- packages/babylon/src/parser/expression.js | 2 + .../import-meta/input.js | 1 + .../import-meta/options.json | 4 + .../import-meta/output.json | 165 ++++++++++++++++++ 4 files changed, 172 insertions(+) create mode 100644 packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/input.js create mode 100644 packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/options.json create mode 100644 packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/output.json diff --git a/packages/babylon/src/parser/expression.js b/packages/babylon/src/parser/expression.js index 04c4bc8db7..d17cdf01e4 100644 --- a/packages/babylon/src/parser/expression.js +++ b/packages/babylon/src/parser/expression.js @@ -957,6 +957,8 @@ export default class ExpressionParser extends LValParser { { code: "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED" }, ); } + this.sawUnambiguousESM = true; + return this.parseMetaProperty(node, id, "meta"); } diff --git a/packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/input.js b/packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/input.js new file mode 100644 index 0000000000..e7313a090f --- /dev/null +++ b/packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/input.js @@ -0,0 +1 @@ +console.log(import.meta); diff --git a/packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/options.json b/packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/options.json new file mode 100644 index 0000000000..6fdc0a23b6 --- /dev/null +++ b/packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "unambiguous", + "plugins": ["importMeta"] +} diff --git a/packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/output.json b/packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/output.json new file mode 100644 index 0000000000..1fe4795f64 --- /dev/null +++ b/packages/babylon/test/fixtures/core/sourcetype-unambiguous/import-meta/output.json @@ -0,0 +1,165 @@ +{ + "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", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 25, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 25 + } + }, + "expression": { + "type": "CallExpression", + "start": 0, + "end": 24, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 24 + } + }, + "callee": { + "type": "MemberExpression", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "object": { + "type": "Identifier", + "start": 0, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "console" + }, + "name": "console" + }, + "property": { + "type": "Identifier", + "start": 8, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 1, + "column": 11 + }, + "identifierName": "log" + }, + "name": "log" + }, + "computed": false + }, + "arguments": [ + { + "type": "MetaProperty", + "start": 12, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "meta": { + "type": "Identifier", + "start": 12, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 18 + }, + "identifierName": "import" + }, + "name": "import" + }, + "property": { + "type": "Identifier", + "start": 19, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 19 + }, + "end": { + "line": 1, + "column": 23 + }, + "identifierName": "meta" + }, + "name": "meta" + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file