Skip to content

Commit

Permalink
[ts] Support import ... = and export = in scripts (#15497)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed May 24, 2023
1 parent 696784a commit 560b8ac
Show file tree
Hide file tree
Showing 30 changed files with 302 additions and 24 deletions.
2 changes: 2 additions & 0 deletions packages/babel-parser/src/plugins/typescript/index.ts
Expand Up @@ -2015,6 +2015,7 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
// For compatibility to estree we cannot call parseLiteral directly here
node.expression = super.parseExprAtom() as N.StringLiteral;
this.expect(tt.parenR);
this.sawUnambiguousESM = true;
return this.finishNode(node, "TSExternalModuleReference");
}

Expand Down Expand Up @@ -2813,6 +2814,7 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
const assign = node as Undone<N.TsExportAssignment>;
assign.expression = super.parseExpression();
this.semicolon();
this.sawUnambiguousESM = true;
return this.finishNode(assign, "TSExportAssignment");
} else if (this.eatContextual(tt._as)) {
// `export as namespace A;`
Expand Down
@@ -0,0 +1 @@
export = f;
@@ -0,0 +1,3 @@
{
"sourceType": "script"
}
@@ -0,0 +1,25 @@
{
"type": "File",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":11,"index":11}},
"errors": [
"SyntaxError: 'import' and 'export' may appear only with 'sourceType: \"module\"' (1:0)"
],
"program": {
"type": "Program",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":11,"index":11}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "TSExportAssignment",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":11,"index":11}},
"expression": {
"type": "Identifier",
"start":9,"end":10,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":10,"index":10},"identifierName":"f"},
"name": "f"
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
export = f;
@@ -0,0 +1,3 @@
{
"sourceType": "unambiguous"
}
@@ -0,0 +1,22 @@
{
"type": "File",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":11,"index":11}},
"program": {
"type": "Program",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":11,"index":11}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "TSExportAssignment",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":11,"index":11}},
"expression": {
"type": "Identifier",
"start":9,"end":10,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":10,"index":10},"identifierName":"f"},
"name": "f"
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
import A = B.C;
@@ -0,0 +1,3 @@
{
"sourceType": "script"
}
@@ -0,0 +1,41 @@
{
"type": "File",
"start":0,"end":15,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":15,"index":15}},
"errors": [
"SyntaxError: 'import' and 'export' may appear only with 'sourceType: \"module\"' (1:0)"
],
"program": {
"type": "Program",
"start":0,"end":15,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":15,"index":15}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "TSImportEqualsDeclaration",
"start":0,"end":15,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":15,"index":15}},
"importKind": "value",
"isExport": false,
"id": {
"type": "Identifier",
"start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8},"identifierName":"A"},
"name": "A"
},
"moduleReference": {
"type": "TSQualifiedName",
"start":11,"end":14,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":14,"index":14}},
"left": {
"type": "Identifier",
"start":11,"end":12,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":12,"index":12},"identifierName":"B"},
"name": "B"
},
"right": {
"type": "Identifier",
"start":13,"end":14,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":14,"index":14},"identifierName":"C"},
"name": "C"
}
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
import A = B.C;
@@ -0,0 +1,3 @@
{
"sourceType": "unambiguous"
}
@@ -0,0 +1,38 @@
{
"type": "File",
"start":0,"end":15,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":15,"index":15}},
"program": {
"type": "Program",
"start":0,"end":15,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":15,"index":15}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "TSImportEqualsDeclaration",
"start":0,"end":15,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":15,"index":15}},
"importKind": "value",
"isExport": false,
"id": {
"type": "Identifier",
"start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8},"identifierName":"A"},
"name": "A"
},
"moduleReference": {
"type": "TSQualifiedName",
"start":11,"end":14,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":14,"index":14}},
"left": {
"type": "Identifier",
"start":11,"end":12,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":12,"index":12},"identifierName":"B"},
"name": "B"
},
"right": {
"type": "Identifier",
"start":13,"end":14,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":14,"index":14},"identifierName":"C"},
"name": "C"
}
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
import a = require("a");
@@ -0,0 +1,3 @@
{
"sourceType": "script"
}
@@ -0,0 +1,40 @@
{
"type": "File",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":24,"index":24}},
"errors": [
"SyntaxError: 'import' and 'export' may appear only with 'sourceType: \"module\"' (1:0)"
],
"program": {
"type": "Program",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":24,"index":24}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "TSImportEqualsDeclaration",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":24,"index":24}},
"importKind": "value",
"isExport": false,
"id": {
"type": "Identifier",
"start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8},"identifierName":"a"},
"name": "a"
},
"moduleReference": {
"type": "TSExternalModuleReference",
"start":11,"end":23,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":23,"index":23}},
"expression": {
"type": "StringLiteral",
"start":19,"end":22,"loc":{"start":{"line":1,"column":19,"index":19},"end":{"line":1,"column":22,"index":22}},
"extra": {
"rawValue": "a",
"raw": "\"a\""
},
"value": "a"
}
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
import a = require("a");
@@ -0,0 +1,3 @@
{
"sourceType": "unambiguous"
}
@@ -0,0 +1,37 @@
{
"type": "File",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":24,"index":24}},
"program": {
"type": "Program",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":24,"index":24}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "TSImportEqualsDeclaration",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":24,"index":24}},
"importKind": "value",
"isExport": false,
"id": {
"type": "Identifier",
"start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8},"identifierName":"a"},
"name": "a"
},
"moduleReference": {
"type": "TSExternalModuleReference",
"start":11,"end":23,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":23,"index":23}},
"expression": {
"type": "StringLiteral",
"start":19,"end":22,"loc":{"start":{"line":1,"column":19,"index":19},"end":{"line":1,"column":22,"index":22}},
"extra": {
"rawValue": "a",
"raw": "\"a\""
},
"value": "a"
}
}
}
],
"directives": []
}
}
70 changes: 50 additions & 20 deletions packages/babel-plugin-transform-typescript/src/index.ts
@@ -1,6 +1,6 @@
import { declare } from "@babel/helper-plugin-utils";
import syntaxTypeScript from "@babel/plugin-syntax-typescript";
import type { types as t } from "@babel/core";
import type { PluginPass, types as t } from "@babel/core";
import { injectInitialization } from "@babel/helper-create-class-features-plugin";
import type { Binding, NodePath, Scope } from "@babel/traverse";
import type { Options as SyntaxOptions } from "@babel/plugin-syntax-typescript";
Expand Down Expand Up @@ -78,6 +78,22 @@ function safeRemove(path: NodePath) {
path.opts.noScope = false;
}

function assertCjsTransformEnabled(
path: NodePath,
pass: PluginPass,
wrong: string,
suggestion: string,
extra: string = "",
): void {
if (pass.file.get("@babel/plugin-transform-modules-*") !== "commonjs") {
throw path.buildCodeFrameError(
`\`${wrong}\` is only supported when compiling modules to CommonJS.\n` +
`Please consider using \`${suggestion}\`${extra}, or add ` +
`@babel/plugin-transform-modules-commonjs to your Babel config.`,
);
}
}

export interface Options extends SyntaxOptions {
/** @default true */
allowNamespaces?: boolean;
Expand Down Expand Up @@ -574,34 +590,48 @@ export default declare((api, opts: Options) => {
}
},

TSImportEqualsDeclaration(path: NodePath<t.TSImportEqualsDeclaration>) {
if (t.isTSExternalModuleReference(path.node.moduleReference)) {
TSImportEqualsDeclaration(
path: NodePath<t.TSImportEqualsDeclaration>,
pass,
) {
const { id, moduleReference } = path.node;

let init: t.Expression;
let varKind: "var" | "const";
if (t.isTSExternalModuleReference(moduleReference)) {
// import alias = require('foo');
throw path.buildCodeFrameError(
`\`import ${path.node.id.name} = require('${path.node.moduleReference.expression.value}')\` ` +
"is not supported by @babel/plugin-transform-typescript\n" +
"Please consider using " +
`\`import ${path.node.id.name} from '${path.node.moduleReference.expression.value}';\` alongside ` +
"Typescript's --allowSyntheticDefaultImports option.",
assertCjsTransformEnabled(
path,
pass,
`import ${id.name} = require(...);`,
`import ${id.name} from '...';`,
" alongside Typescript's --allowSyntheticDefaultImports option",
);
init = t.callExpression(t.identifier("require"), [
moduleReference.expression,
]);
varKind = "const";
} else {
// import alias = Namespace;
init = entityNameToExpr(moduleReference);
varKind = "var";
}

// import alias = Namespace;
path.replaceWith(
t.variableDeclaration("var", [
t.variableDeclarator(
path.node.id,
entityNameToExpr(path.node.moduleReference),
),
]),
t.variableDeclaration(varKind, [t.variableDeclarator(id, init)]),
);
path.scope.registerDeclaration(path);
},

TSExportAssignment(path) {
throw path.buildCodeFrameError(
"`export =` is not supported by @babel/plugin-transform-typescript\n" +
"Please consider using `export <value>;`.",
TSExportAssignment(path, pass) {
assertCjsTransformEnabled(
path,
pass,
`export = <value>;`,
`export default <value>;`,
);
path.replaceWith(
template.statement.ast`module.exports = ${path.node.expression}`,
);
},

Expand Down
@@ -0,0 +1 @@
export = 0;
@@ -0,0 +1,4 @@
{
"plugins": ["transform-typescript", "transform-modules-commonjs"],
"sourceType": "module"
}
@@ -0,0 +1,3 @@
"use strict";

module.exports = 0;
@@ -1,3 +1,3 @@
{
"throws": "`export =` is not supported by @babel/plugin-transform-typescript\nPlease consider using `export <value>;`."
"throws": "`export = <value>;` is only supported when compiling modules to CommonJS.\nPlease consider using `export default <value>;`, or add @babel/plugin-transform-modules-commonjs to your Babel config."
}
@@ -0,0 +1,4 @@
{
"plugins": ["transform-typescript", "transform-modules-commonjs"],
"sourceType": "module"
}
@@ -0,0 +1,4 @@
"use strict";

const lib = require("lib");
lib();
@@ -0,0 +1,2 @@
import lib = require("lib");
lib();
@@ -0,0 +1,4 @@
{
"sourceType": "module",
"throws": "`import lib = require(...);` is only supported when compiling modules to CommonJS.\nPlease consider using `import lib from '...';` alongside Typescript's --allowSyntheticDefaultImports option, or add @babel/plugin-transform-modules-commonjs to your Babel config."
}

0 comments on commit 560b8ac

Please sign in to comment.