Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON modules should be imported with default #14668

Merged
merged 8 commits into from Jun 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,4 +1,4 @@
import foo1 from "foo.json" assert { type: "json" };
export { foo2 } from "foo.json" assert { type: "json" };
export { default as foo2 } from "foo.json" assert { type: "json" };
export * from "foo.json" assert { type: "json" };
export * as foo3 from "foo.json" assert { type: "json" };
@@ -1,4 +1,4 @@
import foo1 from "foo.json" assert { type: "json" };
export { foo2 } from "foo.json" assert { type: "json" };
export { default as foo2 } from "foo.json" assert { type: "json" };
export * from "foo.json" assert { type: "json" };
export * as foo3 from "foo.json" assert { type: "json" };
3 changes: 3 additions & 0 deletions packages/babel-parser/src/parse-error/standard-errors.js
Expand Up @@ -129,6 +129,9 @@ export default (_: typeof toParseErrorCredentials) => ({
),
ImportCallNotNewExpression: _("Cannot use new with import(...)."),
ImportCallSpreadArgument: _("`...` is not allowed in `import()`."),
ImportJSONBindingNotDefault: _(
"A JSON module can only be imported with `default`.",
),
IncompatibleRegExpUVFlags: _(
"The 'u' and 'v' regular expression flags cannot be enabled at the same time.",
),
Expand Down
52 changes: 52 additions & 0 deletions packages/babel-parser/src/parser/statement.js
Expand Up @@ -2182,6 +2182,7 @@ export default class StatementParser extends ExpressionParser {
const assertions = this.maybeParseImportAssertions();
if (assertions) {
node.assertions = assertions;
this.checkJSONModuleImport(node);
}
} else if (expect) {
this.unexpected();
Expand Down Expand Up @@ -2399,6 +2400,56 @@ export default class StatementParser extends ExpressionParser {
return this.parseIdentifier(true);
}

isJSONModuleImport(
node:
| N.ExportAllDeclaration
| N.ExportNamedDeclaration
| N.ImportDeclaration,
): boolean {
if (node.assertions != null) {
return node.assertions.some(({ key, value }) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently import assertions only allow type: "json", so isJSONModuleImport always return true. If more import assertions are supported, then we should differentiate each assertions/attributes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add a test where node.assertions is not null but it does not return true: import { foo } from "bar" asserts {};

return (
value.value === "json" &&
(key.type === "Identifier"
? key.name === "type"
: key.value === "type")
);
});
}
return false;
}

checkJSONModuleImport(
node:
| N.ExportAllDeclaration
| N.ExportNamedDeclaration
| N.ImportDeclaration,
) {
if (this.isJSONModuleImport(node) && node.type !== "ExportAllDeclaration") {
const { specifiers } = node;
if (node.specifiers != null) {
const nonDefaultNamedSpecifier = specifiers.find(specifier => {
let imported;
if (specifier.type === "ExportSpecifier") {
imported = specifier.local;
} else if (specifier.type === "ImportSpecifier") {
imported = specifier.imported;
}
if (imported !== undefined) {
return imported.type === "Identifier"
? imported.name !== "default"
: imported.value !== "default";
}
});
if (nonDefaultNamedSpecifier !== undefined) {
this.raise(Errors.ImportJSONBindingNotDefault, {
at: nonDefaultNamedSpecifier.loc.start,
});
}
}
}
}

// Parses import declaration.
// https://tc39.es/ecma262/#prod-ImportDeclaration

Expand Down Expand Up @@ -2437,6 +2488,7 @@ export default class StatementParser extends ExpressionParser {
node.attributes = attributes;
}
}
this.checkJSONModuleImport(node);

this.semicolon();
return this.finishNode(node, "ImportDeclaration");
Expand Down
@@ -0,0 +1 @@
export { default as foo } from "foo.json" assert { type: "json", type: "html" };
@@ -0,0 +1,84 @@
{
"type": "File",
"start":0,"end":80,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":80,"index":80}},
"errors": [
"SyntaxError: Duplicate key \"type\" is not allowed in module attributes. (1:65)"
],
"program": {
"type": "Program",
"start":0,"end":80,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":80,"index":80}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExportNamedDeclaration",
"start":0,"end":80,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":80,"index":80}},
"specifiers": [
{
"type": "ExportSpecifier",
"start":9,"end":23,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":23,"index":23}},
"local": {
"type": "Identifier",
"start":9,"end":16,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":16,"index":16},"identifierName":"default"},
"name": "default"
},
"exported": {
"type": "Identifier",
"start":20,"end":23,"loc":{"start":{"line":1,"column":20,"index":20},"end":{"line":1,"column":23,"index":23},"identifierName":"foo"},
"name": "foo"
}
}
],
"source": {
"type": "StringLiteral",
"start":31,"end":41,"loc":{"start":{"line":1,"column":31,"index":31},"end":{"line":1,"column":41,"index":41}},
"extra": {
"rawValue": "foo.json",
"raw": "\"foo.json\""
},
"value": "foo.json"
},
"declaration": null,
"assertions": [
{
"type": "ImportAttribute",
"start":51,"end":63,"loc":{"start":{"line":1,"column":51,"index":51},"end":{"line":1,"column":63,"index":63}},
"key": {
"type": "Identifier",
"start":51,"end":55,"loc":{"start":{"line":1,"column":51,"index":51},"end":{"line":1,"column":55,"index":55},"identifierName":"type"},
"name": "type"
},
"value": {
"type": "StringLiteral",
"start":57,"end":63,"loc":{"start":{"line":1,"column":57,"index":57},"end":{"line":1,"column":63,"index":63}},
"extra": {
"rawValue": "json",
"raw": "\"json\""
},
"value": "json"
}
},
{
"type": "ImportAttribute",
"start":65,"end":77,"loc":{"start":{"line":1,"column":65,"index":65},"end":{"line":1,"column":77,"index":77}},
"key": {
"type": "Identifier",
"start":65,"end":69,"loc":{"start":{"line":1,"column":65,"index":65},"end":{"line":1,"column":69,"index":69},"identifierName":"type"},
"name": "type"
},
"value": {
"type": "StringLiteral",
"start":71,"end":77,"loc":{"start":{"line":1,"column":71,"index":71},"end":{"line":1,"column":77,"index":77}},
"extra": {
"rawValue": "html",
"raw": "\"html\""
},
"value": "html"
}
}
]
}
],
"directives": []
}
}
@@ -1,2 +1,2 @@
import foo from "foo" assert { type: "json", }
export { foo } from "foo" assert { type: "json", }
export { default as foo } from "foo" assert { type: "json", }
@@ -1,9 +1,9 @@
{
"type": "File",
"start":0,"end":97,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":50,"index":97}},
"start":0,"end":108,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":61,"index":108}},
"program": {
"type": "Program",
"start":0,"end":97,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":50,"index":97}},
"start":0,"end":108,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":61,"index":108}},
"sourceType": "module",
"interpreter": null,
"body": [
Expand Down Expand Up @@ -53,26 +53,26 @@
},
{
"type": "ExportNamedDeclaration",
"start":47,"end":97,"loc":{"start":{"line":2,"column":0,"index":47},"end":{"line":2,"column":50,"index":97}},
"start":47,"end":108,"loc":{"start":{"line":2,"column":0,"index":47},"end":{"line":2,"column":61,"index":108}},
"specifiers": [
{
"type": "ExportSpecifier",
"start":56,"end":59,"loc":{"start":{"line":2,"column":9,"index":56},"end":{"line":2,"column":12,"index":59}},
"start":56,"end":70,"loc":{"start":{"line":2,"column":9,"index":56},"end":{"line":2,"column":23,"index":70}},
"local": {
"type": "Identifier",
"start":56,"end":59,"loc":{"start":{"line":2,"column":9,"index":56},"end":{"line":2,"column":12,"index":59},"identifierName":"foo"},
"name": "foo"
"start":56,"end":63,"loc":{"start":{"line":2,"column":9,"index":56},"end":{"line":2,"column":16,"index":63},"identifierName":"default"},
"name": "default"
},
"exported": {
"type": "Identifier",
"start":56,"end":59,"loc":{"start":{"line":2,"column":9,"index":56},"end":{"line":2,"column":12,"index":59},"identifierName":"foo"},
"start":67,"end":70,"loc":{"start":{"line":2,"column":20,"index":67},"end":{"line":2,"column":23,"index":70},"identifierName":"foo"},
"name": "foo"
}
}
],
"source": {
"type": "StringLiteral",
"start":67,"end":72,"loc":{"start":{"line":2,"column":20,"index":67},"end":{"line":2,"column":25,"index":72}},
"start":78,"end":83,"loc":{"start":{"line":2,"column":31,"index":78},"end":{"line":2,"column":36,"index":83}},
"extra": {
"rawValue": "foo",
"raw": "\"foo\""
Expand All @@ -83,15 +83,15 @@
"assertions": [
{
"type": "ImportAttribute",
"start":82,"end":94,"loc":{"start":{"line":2,"column":35,"index":82},"end":{"line":2,"column":47,"index":94}},
"start":93,"end":105,"loc":{"start":{"line":2,"column":46,"index":93},"end":{"line":2,"column":58,"index":105}},
"key": {
"type": "Identifier",
"start":82,"end":86,"loc":{"start":{"line":2,"column":35,"index":82},"end":{"line":2,"column":39,"index":86},"identifierName":"type"},
"start":93,"end":97,"loc":{"start":{"line":2,"column":46,"index":93},"end":{"line":2,"column":50,"index":97},"identifierName":"type"},
"name": "type"
},
"value": {
"type": "StringLiteral",
"start":88,"end":94,"loc":{"start":{"line":2,"column":41,"index":88},"end":{"line":2,"column":47,"index":94}},
"start":99,"end":105,"loc":{"start":{"line":2,"column":52,"index":99},"end":{"line":2,"column":58,"index":105}},
"extra": {
"rawValue": "json",
"raw": "\"json\""
Expand Down
@@ -0,0 +1,4 @@
import foo, { bar } from "foo" assert {};
import * as ns from "foo" assert {};
export { quux } from "foo" assert {};
export * as ns2 from "foo" assert {};
@@ -0,0 +1,133 @@
{
"type": "File",
"start":0,"end":154,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":37,"index":154}},
"program": {
"type": "Program",
"start":0,"end":154,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":37,"index":154}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start":0,"end":41,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":41,"index":41}},
"specifiers": [
{
"type": "ImportDefaultSpecifier",
"start":7,"end":10,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":10,"index":10}},
"local": {
"type": "Identifier",
"start":7,"end":10,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":10,"index":10},"identifierName":"foo"},
"name": "foo"
}
},
{
"type": "ImportSpecifier",
"start":14,"end":17,"loc":{"start":{"line":1,"column":14,"index":14},"end":{"line":1,"column":17,"index":17}},
"imported": {
"type": "Identifier",
"start":14,"end":17,"loc":{"start":{"line":1,"column":14,"index":14},"end":{"line":1,"column":17,"index":17},"identifierName":"bar"},
"name": "bar"
},
"local": {
"type": "Identifier",
"start":14,"end":17,"loc":{"start":{"line":1,"column":14,"index":14},"end":{"line":1,"column":17,"index":17},"identifierName":"bar"},
"name": "bar"
}
}
],
"source": {
"type": "StringLiteral",
"start":25,"end":30,"loc":{"start":{"line":1,"column":25,"index":25},"end":{"line":1,"column":30,"index":30}},
"extra": {
"rawValue": "foo",
"raw": "\"foo\""
},
"value": "foo"
},
"assertions": []
},
{
"type": "ImportDeclaration",
"start":42,"end":78,"loc":{"start":{"line":2,"column":0,"index":42},"end":{"line":2,"column":36,"index":78}},
"specifiers": [
{
"type": "ImportNamespaceSpecifier",
"start":49,"end":56,"loc":{"start":{"line":2,"column":7,"index":49},"end":{"line":2,"column":14,"index":56}},
"local": {
"type": "Identifier",
"start":54,"end":56,"loc":{"start":{"line":2,"column":12,"index":54},"end":{"line":2,"column":14,"index":56},"identifierName":"ns"},
"name": "ns"
}
}
],
"source": {
"type": "StringLiteral",
"start":62,"end":67,"loc":{"start":{"line":2,"column":20,"index":62},"end":{"line":2,"column":25,"index":67}},
"extra": {
"rawValue": "foo",
"raw": "\"foo\""
},
"value": "foo"
},
"assertions": []
},
{
"type": "ExportNamedDeclaration",
"start":79,"end":116,"loc":{"start":{"line":3,"column":0,"index":79},"end":{"line":3,"column":37,"index":116}},
"specifiers": [
{
"type": "ExportSpecifier",
"start":88,"end":92,"loc":{"start":{"line":3,"column":9,"index":88},"end":{"line":3,"column":13,"index":92}},
"local": {
"type": "Identifier",
"start":88,"end":92,"loc":{"start":{"line":3,"column":9,"index":88},"end":{"line":3,"column":13,"index":92},"identifierName":"quux"},
"name": "quux"
},
"exported": {
"type": "Identifier",
"start":88,"end":92,"loc":{"start":{"line":3,"column":9,"index":88},"end":{"line":3,"column":13,"index":92},"identifierName":"quux"},
"name": "quux"
}
}
],
"source": {
"type": "StringLiteral",
"start":100,"end":105,"loc":{"start":{"line":3,"column":21,"index":100},"end":{"line":3,"column":26,"index":105}},
"extra": {
"rawValue": "foo",
"raw": "\"foo\""
},
"value": "foo"
},
"declaration": null,
"assertions": []
},
{
"type": "ExportNamedDeclaration",
"start":117,"end":154,"loc":{"start":{"line":4,"column":0,"index":117},"end":{"line":4,"column":37,"index":154}},
"specifiers": [
{
"type": "ExportNamespaceSpecifier",
"start":124,"end":132,"loc":{"start":{"line":4,"column":7,"index":124},"end":{"line":4,"column":15,"index":132}},
"exported": {
"type": "Identifier",
"start":129,"end":132,"loc":{"start":{"line":4,"column":12,"index":129},"end":{"line":4,"column":15,"index":132},"identifierName":"ns2"},
"name": "ns2"
}
}
],
"source": {
"type": "StringLiteral",
"start":138,"end":143,"loc":{"start":{"line":4,"column":21,"index":138},"end":{"line":4,"column":26,"index":143}},
"extra": {
"rawValue": "foo",
"raw": "\"foo\""
},
"value": "foo"
},
"assertions": []
}
],
"directives": []
}
}
@@ -1,2 +1,2 @@
export { x } from "foo" assert
export { default as x } from "foo" assert
{ type: "json" }