Support deferred import evaluation and source phase import syntax (#15487)

This commit is contained in:
SUZUKI Sosuke authored and GitHub committed 2023-10-09 08:52:48 +09:00
1 parent 7e67e43061
commit 4b432496df
26 files changed
+615 -20

No files matched your search

+3
View File
@@ -26,6 +26,7 @@ const parseOptions = {
allowUndeclaredExports: true, allowUndeclaredExports: true,
errorRecovery: true, errorRecovery: true,
createParenthesizedExpressions: true, createParenthesizedExpressions: true,
createImportExpressions: true,
plugins: [ plugins: [
// When adding a plugin, please add a test in `tests/format/js/babel-plugins`, // When adding a plugin, please add a test in `tests/format/js/babel-plugins`,
// To remove plugins, remove it here and run `yarn test tests/format/js/babel-plugins` to verify // To remove plugins, remove it here and run `yarn test tests/format/js/babel-plugins` to verify
@@ -45,6 +46,8 @@ const parseOptions = {
"importReflection", "importReflection",
"explicitResourceManagement", "explicitResourceManagement",
["importAttributes", { deprecatedAssertSyntax: true }], ["importAttributes", { deprecatedAssertSyntax: true }],
"sourcePhaseImports",
"deferredImportEvaluation",
["optionalChainingAssign", { version: "2023-07" }], ["optionalChainingAssign", { version: "2023-07" }],
], ],
tokens: true, tokens: true,
+8 -1
View File
@@ -68,7 +68,7 @@ function printCallExpression(path, options, print) {
const contents = [ const contents = [
isNew ? "new " : "", isNew ? "new " : "",
isDynamicImport ? "import" : print("callee"), isDynamicImport ? printDynamicImportCallee(node) : print("callee"),
optional, optional,
printFunctionTypeParameters(path, options, print), printFunctionTypeParameters(path, options, print),
printCallArguments(path, options, print), printCallArguments(path, options, print),
@@ -83,6 +83,13 @@ function printCallExpression(path, options, print) {
return contents; return contents;
} }
function printDynamicImportCallee(node) {
if (!node.phase) {
return "import";
}
return `import.${node.phase}`;
}
function isCommonsJsOrAmdCall(node, parentNode) { function isCommonsJsOrAmdCall(node, parentNode) {
if (node.callee.type !== "Identifier") { if (node.callee.type !== "Identifier") {
return false; return false;
+1
View File
@@ -34,6 +34,7 @@ function printImportDeclaration(path, options, print) {
return [ return [
"import", "import",
node.module ? " module" : "", node.module ? " module" : "",
node.phase ? ` ${node.phase}` : "",
printImportKind(node), printImportKind(node),
printModuleSpecifiers(path, options, print), printModuleSpecifiers(path, options, print),
printModuleSource(path, options, print), printModuleSource(path, options, print),
+18 -1
View File
@@ -1050,9 +1050,15 @@ function getCallArguments(node) {
if (node.type === "ImportExpression") { if (node.type === "ImportExpression") {
args = [node.source]; args = [node.source];
// import attributes
if (node.attributes) { if (node.attributes) {
args.push(node.attributes); args.push(node.attributes);
} }
// deprecated import assertions
if (node.options) {
args.push(node.options);
}
} }
callArgumentsCache.set(node, args); callArgumentsCache.set(node, args);
@@ -1064,9 +1070,15 @@ function iterateCallArgumentsPath(path, iteratee) {
if (node.type === "ImportExpression") { if (node.type === "ImportExpression") {
path.call((sourcePath) => iteratee(sourcePath, 0), "source"); path.call((sourcePath) => iteratee(sourcePath, 0), "source");
// import attributes
if (node.attributes) { if (node.attributes) {
path.call((sourcePath) => iteratee(sourcePath, 1), "attributes"); path.call((sourcePath) => iteratee(sourcePath, 1), "attributes");
} }
// deprecated import assertions
if (node.options) {
path.call((sourcePath) => iteratee(sourcePath, 1), "options");
}
} else { } else {
path.each(iteratee, "arguments"); path.each(iteratee, "arguments");
} }
@@ -1074,12 +1086,17 @@ function iterateCallArgumentsPath(path, iteratee) {
function getCallArgumentSelector(node, index) { function getCallArgumentSelector(node, index) {
if (node.type === "ImportExpression") { if (node.type === "ImportExpression") {
if (index === 0 || index === (node.attributes ? -2 : -1)) { if (index === 0 || index === (node.attributes || node.options ? -2 : -1)) {
return "source"; return "source";
} }
// import attributes
if (node.attributes && (index === 1 || index === -1)) { if (node.attributes && (index === 1 || index === -1)) {
return "attributes"; return "attributes";
} }
// deprecated import assertions
if (node.options && (index === 1 || index === -1)) {
return "options";
}
throw new RangeError("Invalid argument index"); throw new RangeError("Invalid argument index");
} }
if (index < 0) { if (index < 0) {
@@ -651,6 +651,41 @@ function enumerable(value) {
================================================================================ ================================================================================
`; `;
exports[`deferred-import-evaluation.js [acorn] format 1`] = `
"Unexpected token (1:14)
> 1 | import defer * as ns from "x";
| ^
2 |"
`;
exports[`deferred-import-evaluation.js [espree] format 1`] = `
"Unexpected token * (1:14)
> 1 | import defer * as ns from "x";
| ^
2 |"
`;
exports[`deferred-import-evaluation.js [meriyah] format 1`] = `
"Import source must be string (1:14)
> 1 | import defer * as ns from "x";
| ^
2 |"
`;
exports[`deferred-import-evaluation.js format 1`] = `
====================================options=====================================
parsers: ["babel", "babel-ts", "babel-flow"]
printWidth: 80
| printWidth
=====================================input======================================
import defer * as ns from "x";
=====================================output=====================================
import defer * as ns from "x";
================================================================================
`;
exports[`destructuring-private.js [acorn] format 1`] = ` exports[`destructuring-private.js [acorn] format 1`] = `
"Unexpected token (5:13) "Unexpected token (5:13)
3 | constructor() { 3 | constructor() {
@@ -2496,6 +2531,46 @@ const re = /^(?i:[a-z])[a-z]$/;
================================================================================ ================================================================================
`; `;
exports[`source-phase-imports.js [acorn] format 1`] = `
"Unexpected token (1:15)
> 1 | import source fooSource from "foo";
| ^
2 | import.source("x");
3 |"
`;
exports[`source-phase-imports.js [espree] format 1`] = `
"Unexpected token fooSource (1:15)
> 1 | import source fooSource from "foo";
| ^
2 | import.source("x");
3 |"
`;
exports[`source-phase-imports.js [meriyah] format 1`] = `
"Import source must be string (1:23)
> 1 | import source fooSource from "foo";
| ^
2 | import.source("x");
3 |"
`;
exports[`source-phase-imports.js format 1`] = `
====================================options=====================================
parsers: ["babel", "babel-ts", "babel-flow"]
printWidth: 80
| printWidth
=====================================input======================================
import source fooSource from "foo";
import.source("x");
=====================================output=====================================
import source fooSource from "foo";
import.source("x");
================================================================================
`;
exports[`throw-expressions.js [acorn] format 1`] = ` exports[`throw-expressions.js [acorn] format 1`] = `
"Unexpected token (3:23) "Unexpected token (3:23)
1 | // https://babeljs.io/docs/en/babel-plugin-proposal-throw-expressions 1 | // https://babeljs.io/docs/en/babel-plugin-proposal-throw-expressions
@@ -0,0 +1 @@
import defer * as ns from "x";
@@ -31,6 +31,8 @@ run_spec(import.meta, ["babel", "babel-ts", "babel-flow"], {
"import-reflection.js", "import-reflection.js",
"explicit-resource-management.js", "explicit-resource-management.js",
"regexp-modifiers.js", "regexp-modifiers.js",
"source-phase-imports.js",
"deferred-import-evaluation.js",
"optional-chaining-assignment.js", "optional-chaining-assignment.js",
], ],
espree: [ espree: [
@@ -61,6 +63,8 @@ run_spec(import.meta, ["babel", "babel-ts", "babel-flow"], {
"import-reflection.js", "import-reflection.js",
"explicit-resource-management.js", "explicit-resource-management.js",
"regexp-modifiers.js", "regexp-modifiers.js",
"source-phase-imports.js",
"deferred-import-evaluation.js",
"optional-chaining-assignment.js", "optional-chaining-assignment.js",
], ],
meriyah: [ meriyah: [
@@ -93,6 +97,8 @@ run_spec(import.meta, ["babel", "babel-ts", "babel-flow"], {
"import-reflection.js", "import-reflection.js",
"explicit-resource-management.js", "explicit-resource-management.js",
"regexp-modifiers.js", "regexp-modifiers.js",
"source-phase-imports.js",
"deferred-import-evaluation.js",
"optional-chaining-assignment.js", "optional-chaining-assignment.js",
], ],
babel: ["flow.js", "typescript.js"], babel: ["flow.js", "typescript.js"],
@@ -0,0 +1,2 @@
import source fooSource from "foo";
import.source("x");
@@ -0,0 +1,141 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`import-defer.js [acorn] format 1`] = `
"Unexpected token (1:14)
> 1 | import defer * as ns from "x";
| ^
2 |"
`;
exports[`import-defer.js [espree] format 1`] = `
"Unexpected token * (1:14)
> 1 | import defer * as ns from "x";
| ^
2 |"
`;
exports[`import-defer.js [meriyah] format 1`] = `
"Import source must be string (1:14)
> 1 | import defer * as ns from "x";
| ^
2 |"
`;
exports[`import-defer.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
import defer * as ns from "x";
=====================================output=====================================
import defer * as ns from "x";
================================================================================
`;
exports[`import-defer-attributes-declaration.js [acorn] format 1`] = `
"Unexpected token (1:14)
> 1 | import defer * as ns from "x" with { attr: "val" };
| ^
2 |"
`;
exports[`import-defer-attributes-declaration.js [espree] format 1`] = `
"Unexpected token * (1:14)
> 1 | import defer * as ns from "x" with { attr: "val" };
| ^
2 |"
`;
exports[`import-defer-attributes-declaration.js [meriyah] format 1`] = `
"Import source must be string (1:14)
> 1 | import defer * as ns from "x" with { attr: "val" };
| ^
2 |"
`;
exports[`import-defer-attributes-declaration.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
import defer * as ns from "x" with { attr: "val" };
=====================================output=====================================
import defer * as ns from "x" with { attr: "val" };
================================================================================
`;
exports[`no-default.js [__babel_estree] format 1`] = `
"Only \`import defer * as x from "./module"\` is valid. (1:14)
> 1 | import defer x from "x";
| ^
2 |"
`;
exports[`no-default.js [acorn] format 1`] = `
"Unexpected token (1:14)
> 1 | import defer x from "x";
| ^
2 |"
`;
exports[`no-default.js [babel] format 1`] = `
"Only \`import defer * as x from "./module"\` is valid. (1:14)
> 1 | import defer x from "x";
| ^
2 |"
`;
exports[`no-default.js [espree] format 1`] = `
"Unexpected token x (1:14)
> 1 | import defer x from "x";
| ^
2 |"
`;
exports[`no-default.js [meriyah] format 1`] = `
"Import source must be string (1:14)
> 1 | import defer x from "x";
| ^
2 |"
`;
exports[`no-named.js [__babel_estree] format 1`] = `
"Only \`import defer * as x from "./module"\` is valid. (1:16)
> 1 | import defer { x } from "x";
| ^
2 |"
`;
exports[`no-named.js [acorn] format 1`] = `
"Unexpected token (1:14)
> 1 | import defer { x } from "x";
| ^
2 |"
`;
exports[`no-named.js [babel] format 1`] = `
"Only \`import defer * as x from "./module"\` is valid. (1:16)
> 1 | import defer { x } from "x";
| ^
2 |"
`;
exports[`no-named.js [espree] format 1`] = `
"Unexpected token { (1:14)
> 1 | import defer { x } from "x";
| ^
2 |"
`;
exports[`no-named.js [meriyah] format 1`] = `
"Import source must be string (1:14)
> 1 | import defer { x } from "x";
| ^
2 |"
`;
@@ -0,0 +1 @@
import defer * as ns from "x" with { attr: "val" };
@@ -0,0 +1 @@
import defer * as ns from "x";
@@ -0,0 +1,15 @@
const importDeferTests = [
"import-defer.js",
"import-defer-attributes-declaration.js",
];
const invalidSyntaxTests = ["no-default.js", "no-named.js"];
run_spec(import.meta, ["babel"], {
errors: {
acorn: [...importDeferTests, ...invalidSyntaxTests],
espree: [...importDeferTests, ...invalidSyntaxTests],
meriyah: [...importDeferTests, ...invalidSyntaxTests],
babel: invalidSyntaxTests,
__babel_estree: invalidSyntaxTests,
},
});
@@ -0,0 +1 @@
import defer x from "x";
@@ -0,0 +1 @@
import defer { x } from "x";
@@ -0,0 +1,295 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`default-binding.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
import source from "x";
=====================================output=====================================
import source from "x";
================================================================================
`;
exports[`import-source.js [acorn] format 1`] = `
"Unexpected token (1:15)
> 1 | import source x from "x";
| ^
2 |"
`;
exports[`import-source.js [espree] format 1`] = `
"Unexpected token x (1:15)
> 1 | import source x from "x";
| ^
2 |"
`;
exports[`import-source.js [meriyah] format 1`] = `
"Import source must be string (1:15)
> 1 | import source x from "x";
| ^
2 |"
`;
exports[`import-source.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
import source x from "x";
=====================================output=====================================
import source x from "x";
================================================================================
`;
exports[`import-source-attributes-declaration.js [acorn] format 1`] = `
"Unexpected token (1:15)
> 1 | import source s from "x" with { attr: "val" };
| ^
2 |"
`;
exports[`import-source-attributes-declaration.js [espree] format 1`] = `
"Unexpected token s (1:15)
> 1 | import source s from "x" with { attr: "val" };
| ^
2 |"
`;
exports[`import-source-attributes-declaration.js [meriyah] format 1`] = `
"Import source must be string (1:15)
> 1 | import source s from "x" with { attr: "val" };
| ^
2 |"
`;
exports[`import-source-attributes-declaration.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
import source s from "x" with { attr: "val" };
=====================================output=====================================
import source s from "x" with { attr: "val" };
================================================================================
`;
exports[`import-source-attributes-expression.js [acorn] format 1`] = `
"The only valid meta property for import is 'import.meta' (1:8)
> 1 | import.source("x", { with: { attr: "val" } });
| ^
2 |"
`;
exports[`import-source-attributes-expression.js [espree] format 1`] = `
"The only valid meta property for import is 'import.meta' (1:8)
> 1 | import.source("x", { with: { attr: "val" } });
| ^
2 |"
`;
exports[`import-source-attributes-expression.js [meriyah] format 1`] = `
"Unexpected token: 'identifier' (1:13)
> 1 | import.source("x", { with: { attr: "val" } });
| ^
2 |"
`;
exports[`import-source-attributes-expression.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
import.source("x", { with: { attr: "val" } });
=====================================output=====================================
import.source("x", { with: { attr: "val" } });
================================================================================
`;
exports[`import-source-binding-from.js [acorn] format 1`] = `
"Unexpected token (1:20)
> 1 | import source from from "x";
| ^
2 |"
`;
exports[`import-source-binding-from.js [espree] format 1`] = `
"Unexpected token from (1:20)
> 1 | import source from from "x";
| ^
2 |"
`;
exports[`import-source-binding-from.js [meriyah] format 1`] = `
"Import source must be string (1:23)
> 1 | import source from from "x";
| ^
2 |"
`;
exports[`import-source-binding-from.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
import source from from "x";
=====================================output=====================================
import source from from "x";
================================================================================
`;
exports[`import-source-binding-source.js [acorn] format 1`] = `
"Unexpected token (1:15)
> 1 | import source source from "x";
| ^
2 |"
`;
exports[`import-source-binding-source.js [espree] format 1`] = `
"Unexpected token source (1:15)
> 1 | import source source from "x";
| ^
2 |"
`;
exports[`import-source-binding-source.js [meriyah] format 1`] = `
"Import source must be string (1:20)
> 1 | import source source from "x";
| ^
2 |"
`;
exports[`import-source-binding-source.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
import source source from "x";
=====================================output=====================================
import source source from "x";
================================================================================
`;
exports[`import-source-dynamic-import.js [acorn] format 1`] = `
"The only valid meta property for import is 'import.meta' (1:8)
> 1 | import.source("foo");
| ^
2 |"
`;
exports[`import-source-dynamic-import.js [espree] format 1`] = `
"The only valid meta property for import is 'import.meta' (1:8)
> 1 | import.source("foo");
| ^
2 |"
`;
exports[`import-source-dynamic-import.js [meriyah] format 1`] = `
"Unexpected token: 'identifier' (1:13)
> 1 | import.source("foo");
| ^
2 |"
`;
exports[`import-source-dynamic-import.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
import.source("foo");
=====================================output=====================================
import.source("foo");
================================================================================
`;
exports[`no-named.js [__babel_estree] format 1`] = `
"Only \`import source x from "./module"\` is valid. (1:17)
> 1 | import source { x } from "x";
| ^
2 |"
`;
exports[`no-named.js [acorn] format 1`] = `
"Unexpected token (1:15)
> 1 | import source { x } from "x";
| ^
2 |"
`;
exports[`no-named.js [babel] format 1`] = `
"Only \`import source x from "./module"\` is valid. (1:17)
> 1 | import source { x } from "x";
| ^
2 |"
`;
exports[`no-named.js [espree] format 1`] = `
"Unexpected token { (1:15)
> 1 | import source { x } from "x";
| ^
2 |"
`;
exports[`no-named.js [meriyah] format 1`] = `
"Import source must be string (1:15)
> 1 | import source { x } from "x";
| ^
2 |"
`;
exports[`no-namespace.js [__babel_estree] format 1`] = `
"Only \`import source x from "./module"\` is valid. (1:15)
> 1 | import source * as x from "x";
| ^
2 |"
`;
exports[`no-namespace.js [acorn] format 1`] = `
"Unexpected token (1:15)
> 1 | import source * as x from "x";
| ^
2 |"
`;
exports[`no-namespace.js [babel] format 1`] = `
"Only \`import source x from "./module"\` is valid. (1:15)
> 1 | import source * as x from "x";
| ^
2 |"
`;
exports[`no-namespace.js [espree] format 1`] = `
"Unexpected token * (1:15)
> 1 | import source * as x from "x";
| ^
2 |"
`;
exports[`no-namespace.js [meriyah] format 1`] = `
"Import source must be string (1:15)
> 1 | import source * as x from "x";
| ^
2 |"
`;
@@ -0,0 +1 @@
import source from "x";
@@ -0,0 +1 @@
import source s from "x" with { attr: "val" };
@@ -0,0 +1 @@
import.source("x", { with: { attr: "val" } });
@@ -0,0 +1 @@
import source from from "x";
@@ -0,0 +1 @@
import source source from "x";
@@ -0,0 +1 @@
import.source("foo");
@@ -0,0 +1 @@
import source x from "x";
@@ -0,0 +1,19 @@
const importSourceTests = [
"import-source-attributes-declaration.js",
"import-source-attributes-expression.js",
"import-source-binding-from.js",
"import-source-binding-source.js",
"import-source-dynamic-import.js",
"import-source.js",
];
const invalidSyntaxTests = ["no-namespace.js", "no-named.js"];
run_spec(import.meta, ["babel"], {
errors: {
acorn: [...importSourceTests, ...invalidSyntaxTests],
espree: [...importSourceTests, ...invalidSyntaxTests],
meriyah: [...importSourceTests, ...invalidSyntaxTests],
babel: invalidSyntaxTests,
__babel_estree: invalidSyntaxTests,
},
});
@@ -0,0 +1 @@
import source { x } from "x";
@@ -0,0 +1 @@
import source * as x from "x";
@@ -1,21 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`snippet: #0 [babel] format 1`] = ` exports[`snippet: #0 [babel] format 1`] = `
"\`import()\` requires exactly one or two arguments. (1:1) "Unexpected token (1:8)
> 1 | import(); > 1 | import();
| ^" | ^"
`; `;
exports[`snippet: #0 [babel-flow] format 1`] = ` exports[`snippet: #0 [babel-flow] format 1`] = `
"\`import()\` requires exactly one or two arguments. (1:1) "Unexpected token (1:8)
> 1 | import(); > 1 | import();
| ^" | ^"
`; `;
exports[`snippet: #0 [babel-ts] format 1`] = ` exports[`snippet: #0 [babel-ts] format 1`] = `
"\`import()\` requires exactly one or two arguments. (1:1) "Unexpected token (1:8)
> 1 | import(); > 1 | import();
| ^" | ^"
`; `;
exports[`snippet: #0 [flow] format 1`] = ` exports[`snippet: #0 [flow] format 1`] = `
@@ -37,21 +37,21 @@ exports[`snippet: #0 [typescript] format 1`] = `
`; `;
exports[`snippet: #1 [babel] format 1`] = ` exports[`snippet: #1 [babel] format 1`] = `
"\`import()\` requires exactly one or two arguments. (1:1) "Unexpected token (1:21)
> 1 | import(/* comment */); > 1 | import(/* comment */);
| ^" | ^"
`; `;
exports[`snippet: #1 [babel-flow] format 1`] = ` exports[`snippet: #1 [babel-flow] format 1`] = `
"\`import()\` requires exactly one or two arguments. (1:1) "Unexpected token (1:21)
> 1 | import(/* comment */); > 1 | import(/* comment */);
| ^" | ^"
`; `;
exports[`snippet: #1 [babel-ts] format 1`] = ` exports[`snippet: #1 [babel-ts] format 1`] = `
"\`import()\` requires exactly one or two arguments. (1:1) "Unexpected token (1:21)
> 1 | import(/* comment */); > 1 | import(/* comment */);
| ^" | ^"
`; `;
exports[`snippet: #1 [flow] format 1`] = ` exports[`snippet: #1 [flow] format 1`] = `
@@ -109,21 +109,21 @@ exports[`snippet: #2 [typescript] format 1`] = `
`; `;
exports[`snippet: #3 [babel] format 1`] = ` exports[`snippet: #3 [babel] format 1`] = `
"Cannot use new with import(...). (1:5) "Unexpected token (1:12)
> 1 | new import(); > 1 | new import();
| ^" | ^"
`; `;
exports[`snippet: #3 [babel-flow] format 1`] = ` exports[`snippet: #3 [babel-flow] format 1`] = `
"Cannot use new with import(...). (1:5) "Unexpected token (1:12)
> 1 | new import(); > 1 | new import();
| ^" | ^"
`; `;
exports[`snippet: #3 [babel-ts] format 1`] = ` exports[`snippet: #3 [babel-ts] format 1`] = `
"Cannot use new with import(...). (1:5) "Unexpected token (1:12)
> 1 | new import(); > 1 | new import();
| ^" | ^"
`; `;
exports[`snippet: #3 [flow] format 1`] = ` exports[`snippet: #3 [flow] format 1`] = `