Implement TypeScript namespace support (#9785)
* Add module tests for typescript namespace transform Fixes #8244, fixes #10038
This commit is contained in:
parent
8bf9714d69
commit
0a98814329
@ -4,6 +4,7 @@ import { types as t, template } from "@babel/core";
|
|||||||
import { injectInitialization } from "@babel/helper-create-class-features-plugin";
|
import { injectInitialization } from "@babel/helper-create-class-features-plugin";
|
||||||
|
|
||||||
import transpileEnum from "./enum";
|
import transpileEnum from "./enum";
|
||||||
|
import transpileNamespace from "./namespace";
|
||||||
|
|
||||||
function isInType(path) {
|
function isInType(path) {
|
||||||
switch (path.parent.type) {
|
switch (path.parent.type) {
|
||||||
@ -19,333 +20,335 @@ function isInType(path) {
|
|||||||
|
|
||||||
const PARSED_PARAMS = new WeakSet();
|
const PARSED_PARAMS = new WeakSet();
|
||||||
|
|
||||||
export default declare((api, { jsxPragma = "React" }) => {
|
export default declare(
|
||||||
api.assertVersion(7);
|
(api, { jsxPragma = "React", allowNamespaces = false }) => {
|
||||||
|
api.assertVersion(7);
|
||||||
|
|
||||||
const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/;
|
const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "transform-typescript",
|
name: "transform-typescript",
|
||||||
inherits: syntaxTypeScript,
|
inherits: syntaxTypeScript,
|
||||||
|
|
||||||
visitor: {
|
visitor: {
|
||||||
//"Pattern" alias doesn't include Identifier or RestElement.
|
//"Pattern" alias doesn't include Identifier or RestElement.
|
||||||
Pattern: visitPattern,
|
Pattern: visitPattern,
|
||||||
Identifier: visitPattern,
|
Identifier: visitPattern,
|
||||||
RestElement: visitPattern,
|
RestElement: visitPattern,
|
||||||
|
|
||||||
Program(path, state) {
|
Program(path, state) {
|
||||||
const { file } = state;
|
const { file } = state;
|
||||||
let fileJsxPragma = null;
|
let fileJsxPragma = null;
|
||||||
|
|
||||||
if (file.ast.comments) {
|
if (file.ast.comments) {
|
||||||
for (const comment of (file.ast.comments: Array<Object>)) {
|
for (const comment of (file.ast.comments: Array<Object>)) {
|
||||||
const jsxMatches = JSX_ANNOTATION_REGEX.exec(comment.value);
|
const jsxMatches = JSX_ANNOTATION_REGEX.exec(comment.value);
|
||||||
if (jsxMatches) {
|
if (jsxMatches) {
|
||||||
fileJsxPragma = jsxMatches[1];
|
fileJsxPragma = jsxMatches[1];
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove type imports
|
|
||||||
for (const stmt of path.get("body")) {
|
|
||||||
if (t.isImportDeclaration(stmt)) {
|
|
||||||
// Note: this will allow both `import { } from "m"` and `import "m";`.
|
|
||||||
// In TypeScript, the former would be elided.
|
|
||||||
if (stmt.node.specifiers.length === 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let allElided = true;
|
|
||||||
const importsToRemove: Path<Node>[] = [];
|
|
||||||
|
|
||||||
for (const specifier of stmt.node.specifiers) {
|
|
||||||
const binding = stmt.scope.getBinding(specifier.local.name);
|
|
||||||
|
|
||||||
// The binding may not exist if the import node was explicitly
|
|
||||||
// injected by another plugin. Currently core does not do a good job
|
|
||||||
// of keeping scope bindings synchronized with the AST. For now we
|
|
||||||
// just bail if there is no binding, since chances are good that if
|
|
||||||
// the import statement was injected then it wasn't a typescript type
|
|
||||||
// import anyway.
|
|
||||||
if (
|
|
||||||
binding &&
|
|
||||||
isImportTypeOnly({
|
|
||||||
binding,
|
|
||||||
programPath: path,
|
|
||||||
jsxPragma: fileJsxPragma || jsxPragma,
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
importsToRemove.push(binding.path);
|
|
||||||
} else {
|
|
||||||
allElided = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allElided) {
|
|
||||||
stmt.remove();
|
|
||||||
} else {
|
|
||||||
for (const importPath of importsToRemove) {
|
|
||||||
importPath.remove();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ExportNamedDeclaration(path) {
|
// remove type imports
|
||||||
// remove export declaration if it's exporting only types
|
for (const stmt of path.get("body")) {
|
||||||
if (
|
if (t.isImportDeclaration(stmt)) {
|
||||||
path.node.specifiers.length > 0 &&
|
// Note: this will allow both `import { } from "m"` and `import "m";`.
|
||||||
!path.node.specifiers.find(exportSpecifier =>
|
// In TypeScript, the former would be elided.
|
||||||
path.scope.hasOwnBinding(exportSpecifier.local.name),
|
if (stmt.node.specifiers.length === 0) {
|
||||||
)
|
continue;
|
||||||
) {
|
|
||||||
path.remove();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ExportSpecifier(path) {
|
|
||||||
// remove type exports
|
|
||||||
if (!path.scope.hasOwnBinding(path.node.local.name)) {
|
|
||||||
path.remove();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ExportDefaultDeclaration(path) {
|
|
||||||
// remove whole declaration if it's exporting a TS type
|
|
||||||
if (
|
|
||||||
t.isIdentifier(path.node.declaration) &&
|
|
||||||
!path.scope.hasOwnBinding(path.node.declaration.name)
|
|
||||||
) {
|
|
||||||
path.remove();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
TSDeclareFunction(path) {
|
|
||||||
path.remove();
|
|
||||||
},
|
|
||||||
|
|
||||||
TSDeclareMethod(path) {
|
|
||||||
path.remove();
|
|
||||||
},
|
|
||||||
|
|
||||||
VariableDeclaration(path) {
|
|
||||||
if (path.node.declare) path.remove();
|
|
||||||
},
|
|
||||||
|
|
||||||
VariableDeclarator({ node }) {
|
|
||||||
if (node.definite) node.definite = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
ClassMethod(path) {
|
|
||||||
const { node } = path;
|
|
||||||
|
|
||||||
if (node.accessibility) node.accessibility = null;
|
|
||||||
if (node.abstract) node.abstract = null;
|
|
||||||
if (node.optional) node.optional = null;
|
|
||||||
|
|
||||||
// Rest handled by Function visitor
|
|
||||||
},
|
|
||||||
|
|
||||||
ClassProperty(path) {
|
|
||||||
const { node } = path;
|
|
||||||
|
|
||||||
if (node.accessibility) node.accessibility = null;
|
|
||||||
if (node.abstract) node.abstract = null;
|
|
||||||
if (node.readonly) node.readonly = null;
|
|
||||||
if (node.optional) node.optional = null;
|
|
||||||
if (node.definite) node.definite = null;
|
|
||||||
if (node.typeAnnotation) node.typeAnnotation = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
TSIndexSignature(path) {
|
|
||||||
path.remove();
|
|
||||||
},
|
|
||||||
|
|
||||||
ClassDeclaration(path) {
|
|
||||||
const { node } = path;
|
|
||||||
if (node.declare) {
|
|
||||||
path.remove();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
Class(path) {
|
|
||||||
const { node } = path;
|
|
||||||
|
|
||||||
if (node.typeParameters) node.typeParameters = null;
|
|
||||||
if (node.superTypeParameters) node.superTypeParameters = null;
|
|
||||||
if (node.implements) node.implements = null;
|
|
||||||
if (node.abstract) node.abstract = null;
|
|
||||||
|
|
||||||
// Similar to the logic in `transform-flow-strip-types`, we need to
|
|
||||||
// handle `TSParameterProperty` and `ClassProperty` here because the
|
|
||||||
// class transform would transform the class, causing more specific
|
|
||||||
// visitors to not run.
|
|
||||||
path.get("body.body").forEach(child => {
|
|
||||||
const childNode = child.node;
|
|
||||||
|
|
||||||
if (t.isClassMethod(childNode, { kind: "constructor" })) {
|
|
||||||
// Collects parameter properties so that we can add an assignment
|
|
||||||
// for each of them in the constructor body
|
|
||||||
//
|
|
||||||
// We use a WeakSet to ensure an assignment for a parameter
|
|
||||||
// property is only added once. This is necessary for cases like
|
|
||||||
// using `transform-classes`, which causes this visitor to run
|
|
||||||
// twice.
|
|
||||||
const parameterProperties = [];
|
|
||||||
for (const param of childNode.params) {
|
|
||||||
if (
|
|
||||||
param.type === "TSParameterProperty" &&
|
|
||||||
!PARSED_PARAMS.has(param.parameter)
|
|
||||||
) {
|
|
||||||
PARSED_PARAMS.add(param.parameter);
|
|
||||||
parameterProperties.push(param.parameter);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (parameterProperties.length) {
|
let allElided = true;
|
||||||
const assigns = parameterProperties.map(p => {
|
const importsToRemove: Path<Node>[] = [];
|
||||||
let id;
|
|
||||||
if (t.isIdentifier(p)) {
|
for (const specifier of stmt.node.specifiers) {
|
||||||
id = p;
|
const binding = stmt.scope.getBinding(specifier.local.name);
|
||||||
} else if (t.isAssignmentPattern(p) && t.isIdentifier(p.left)) {
|
|
||||||
id = p.left;
|
// The binding may not exist if the import node was explicitly
|
||||||
|
// injected by another plugin. Currently core does not do a good job
|
||||||
|
// of keeping scope bindings synchronized with the AST. For now we
|
||||||
|
// just bail if there is no binding, since chances are good that if
|
||||||
|
// the import statement was injected then it wasn't a typescript type
|
||||||
|
// import anyway.
|
||||||
|
if (
|
||||||
|
binding &&
|
||||||
|
isImportTypeOnly({
|
||||||
|
binding,
|
||||||
|
programPath: path,
|
||||||
|
jsxPragma: fileJsxPragma || jsxPragma,
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
importsToRemove.push(binding.path);
|
||||||
} else {
|
} else {
|
||||||
throw path.buildCodeFrameError(
|
allElided = false;
|
||||||
"Parameter properties can not be destructuring patterns.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return template.statement.ast`this.${id} = ${id}`;
|
if (allElided) {
|
||||||
});
|
stmt.remove();
|
||||||
|
} else {
|
||||||
injectInitialization(path, child, assigns);
|
for (const importPath of importsToRemove) {
|
||||||
}
|
importPath.remove();
|
||||||
} else if (child.isClassProperty()) {
|
}
|
||||||
childNode.typeAnnotation = null;
|
}
|
||||||
|
|
||||||
if (!childNode.value && !childNode.decorators) {
|
|
||||||
child.remove();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
|
||||||
|
ExportNamedDeclaration(path) {
|
||||||
|
// remove export declaration if it's exporting only types
|
||||||
|
if (
|
||||||
|
path.node.specifiers.length > 0 &&
|
||||||
|
!path.node.specifiers.find(exportSpecifier =>
|
||||||
|
path.scope.hasOwnBinding(exportSpecifier.local.name),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
path.remove();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ExportSpecifier(path) {
|
||||||
|
// remove type exports
|
||||||
|
if (!path.scope.hasOwnBinding(path.node.local.name)) {
|
||||||
|
path.remove();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ExportDefaultDeclaration(path) {
|
||||||
|
// remove whole declaration if it's exporting a TS type
|
||||||
|
if (
|
||||||
|
t.isIdentifier(path.node.declaration) &&
|
||||||
|
!path.scope.hasOwnBinding(path.node.declaration.name)
|
||||||
|
) {
|
||||||
|
path.remove();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
TSDeclareFunction(path) {
|
||||||
|
path.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
TSDeclareMethod(path) {
|
||||||
|
path.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
VariableDeclaration(path) {
|
||||||
|
if (path.node.declare) path.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
VariableDeclarator({ node }) {
|
||||||
|
if (node.definite) node.definite = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
ClassMethod(path) {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
if (node.accessibility) node.accessibility = null;
|
||||||
|
if (node.abstract) node.abstract = null;
|
||||||
|
if (node.optional) node.optional = null;
|
||||||
|
|
||||||
|
// Rest handled by Function visitor
|
||||||
|
},
|
||||||
|
|
||||||
|
ClassProperty(path) {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
if (node.accessibility) node.accessibility = null;
|
||||||
|
if (node.abstract) node.abstract = null;
|
||||||
|
if (node.readonly) node.readonly = null;
|
||||||
|
if (node.optional) node.optional = null;
|
||||||
|
if (node.definite) node.definite = null;
|
||||||
|
if (node.typeAnnotation) node.typeAnnotation = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
TSIndexSignature(path) {
|
||||||
|
path.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
ClassDeclaration(path) {
|
||||||
|
const { node } = path;
|
||||||
|
if (node.declare) {
|
||||||
|
path.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Class(path) {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
if (node.typeParameters) node.typeParameters = null;
|
||||||
|
if (node.superTypeParameters) node.superTypeParameters = null;
|
||||||
|
if (node.implements) node.implements = null;
|
||||||
|
if (node.abstract) node.abstract = null;
|
||||||
|
|
||||||
|
// Similar to the logic in `transform-flow-strip-types`, we need to
|
||||||
|
// handle `TSParameterProperty` and `ClassProperty` here because the
|
||||||
|
// class transform would transform the class, causing more specific
|
||||||
|
// visitors to not run.
|
||||||
|
path.get("body.body").forEach(child => {
|
||||||
|
const childNode = child.node;
|
||||||
|
|
||||||
|
if (t.isClassMethod(childNode, { kind: "constructor" })) {
|
||||||
|
// Collects parameter properties so that we can add an assignment
|
||||||
|
// for each of them in the constructor body
|
||||||
|
//
|
||||||
|
// We use a WeakSet to ensure an assignment for a parameter
|
||||||
|
// property is only added once. This is necessary for cases like
|
||||||
|
// using `transform-classes`, which causes this visitor to run
|
||||||
|
// twice.
|
||||||
|
const parameterProperties = [];
|
||||||
|
for (const param of childNode.params) {
|
||||||
|
if (
|
||||||
|
param.type === "TSParameterProperty" &&
|
||||||
|
!PARSED_PARAMS.has(param.parameter)
|
||||||
|
) {
|
||||||
|
PARSED_PARAMS.add(param.parameter);
|
||||||
|
parameterProperties.push(param.parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameterProperties.length) {
|
||||||
|
const assigns = parameterProperties.map(p => {
|
||||||
|
let id;
|
||||||
|
if (t.isIdentifier(p)) {
|
||||||
|
id = p;
|
||||||
|
} else if (
|
||||||
|
t.isAssignmentPattern(p) &&
|
||||||
|
t.isIdentifier(p.left)
|
||||||
|
) {
|
||||||
|
id = p.left;
|
||||||
|
} else {
|
||||||
|
throw path.buildCodeFrameError(
|
||||||
|
"Parameter properties can not be destructuring patterns.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return template.statement.ast`this.${id} = ${id}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
injectInitialization(path, child, assigns);
|
||||||
|
}
|
||||||
|
} else if (child.isClassProperty()) {
|
||||||
|
childNode.typeAnnotation = null;
|
||||||
|
|
||||||
|
if (!childNode.value && !childNode.decorators) {
|
||||||
|
child.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
Function({ node }) {
|
||||||
|
if (node.typeParameters) node.typeParameters = null;
|
||||||
|
if (node.returnType) node.returnType = null;
|
||||||
|
|
||||||
|
const p0 = node.params[0];
|
||||||
|
if (p0 && t.isIdentifier(p0) && p0.name === "this") {
|
||||||
|
node.params.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We replace `TSParameterProperty` here so that transforms that
|
||||||
|
// rely on a `Function` visitor to deal with arguments, like
|
||||||
|
// `transform-parameters`, work properly.
|
||||||
|
node.params = node.params.map(p => {
|
||||||
|
return p.type === "TSParameterProperty" ? p.parameter : p;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
TSModuleDeclaration(path) {
|
||||||
|
transpileNamespace(path, t, allowNamespaces);
|
||||||
|
},
|
||||||
|
|
||||||
|
TSInterfaceDeclaration(path) {
|
||||||
|
path.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
TSTypeAliasDeclaration(path) {
|
||||||
|
path.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
TSEnumDeclaration(path) {
|
||||||
|
transpileEnum(path, t);
|
||||||
|
},
|
||||||
|
|
||||||
|
TSImportEqualsDeclaration(path) {
|
||||||
|
throw path.buildCodeFrameError(
|
||||||
|
"`import =` is not supported by @babel/plugin-transform-typescript\n" +
|
||||||
|
"Please consider using " +
|
||||||
|
"`import <moduleName> from '<moduleName>';` alongside " +
|
||||||
|
"Typescript's --allowSyntheticDefaultImports option.",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
TSExportAssignment(path) {
|
||||||
|
throw path.buildCodeFrameError(
|
||||||
|
"`export =` is not supported by @babel/plugin-transform-typescript\n" +
|
||||||
|
"Please consider using `export <value>;`.",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
TSTypeAssertion(path) {
|
||||||
|
path.replaceWith(path.node.expression);
|
||||||
|
},
|
||||||
|
|
||||||
|
TSAsExpression(path) {
|
||||||
|
let { node } = path;
|
||||||
|
do {
|
||||||
|
node = node.expression;
|
||||||
|
} while (t.isTSAsExpression(node));
|
||||||
|
path.replaceWith(node);
|
||||||
|
},
|
||||||
|
|
||||||
|
TSNonNullExpression(path) {
|
||||||
|
path.replaceWith(path.node.expression);
|
||||||
|
},
|
||||||
|
|
||||||
|
CallExpression(path) {
|
||||||
|
path.node.typeParameters = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
NewExpression(path) {
|
||||||
|
path.node.typeParameters = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
JSXOpeningElement(path) {
|
||||||
|
path.node.typeParameters = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
TaggedTemplateExpression(path) {
|
||||||
|
path.node.typeParameters = null;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
|
||||||
Function({ node }) {
|
function visitPattern({ node }) {
|
||||||
if (node.typeParameters) node.typeParameters = null;
|
if (node.typeAnnotation) node.typeAnnotation = null;
|
||||||
if (node.returnType) node.returnType = null;
|
if (t.isIdentifier(node) && node.optional) node.optional = null;
|
||||||
|
// 'access' and 'readonly' are only for parameter properties, so constructor visitor will handle them.
|
||||||
|
}
|
||||||
|
|
||||||
const p0 = node.params[0];
|
function isImportTypeOnly({ binding, programPath, jsxPragma }) {
|
||||||
if (p0 && t.isIdentifier(p0) && p0.name === "this") {
|
for (const path of binding.referencePaths) {
|
||||||
node.params.shift();
|
if (!isInType(path)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We replace `TSParameterProperty` here so that transforms that
|
|
||||||
// rely on a `Function` visitor to deal with arguments, like
|
|
||||||
// `transform-parameters`, work properly.
|
|
||||||
node.params = node.params.map(p => {
|
|
||||||
return p.type === "TSParameterProperty" ? p.parameter : p;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
TSModuleDeclaration(path) {
|
|
||||||
if (!path.node.declare && path.node.id.type !== "StringLiteral") {
|
|
||||||
throw path.buildCodeFrameError("Namespaces are not supported.");
|
|
||||||
}
|
|
||||||
path.remove();
|
|
||||||
},
|
|
||||||
|
|
||||||
TSInterfaceDeclaration(path) {
|
|
||||||
path.remove();
|
|
||||||
},
|
|
||||||
|
|
||||||
TSTypeAliasDeclaration(path) {
|
|
||||||
path.remove();
|
|
||||||
},
|
|
||||||
|
|
||||||
TSEnumDeclaration(path) {
|
|
||||||
transpileEnum(path, t);
|
|
||||||
},
|
|
||||||
|
|
||||||
TSImportEqualsDeclaration(path) {
|
|
||||||
throw path.buildCodeFrameError(
|
|
||||||
"`import =` is not supported by @babel/plugin-transform-typescript\n" +
|
|
||||||
"Please consider using " +
|
|
||||||
"`import <moduleName> from '<moduleName>';` alongside " +
|
|
||||||
"Typescript's --allowSyntheticDefaultImports option.",
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
TSExportAssignment(path) {
|
|
||||||
throw path.buildCodeFrameError(
|
|
||||||
"`export =` is not supported by @babel/plugin-transform-typescript\n" +
|
|
||||||
"Please consider using `export <value>;`.",
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
TSTypeAssertion(path) {
|
|
||||||
path.replaceWith(path.node.expression);
|
|
||||||
},
|
|
||||||
|
|
||||||
TSAsExpression(path) {
|
|
||||||
let { node } = path;
|
|
||||||
do {
|
|
||||||
node = node.expression;
|
|
||||||
} while (t.isTSAsExpression(node));
|
|
||||||
path.replaceWith(node);
|
|
||||||
},
|
|
||||||
|
|
||||||
TSNonNullExpression(path) {
|
|
||||||
path.replaceWith(path.node.expression);
|
|
||||||
},
|
|
||||||
|
|
||||||
CallExpression(path) {
|
|
||||||
path.node.typeParameters = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
NewExpression(path) {
|
|
||||||
path.node.typeParameters = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
JSXOpeningElement(path) {
|
|
||||||
path.node.typeParameters = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
TaggedTemplateExpression(path) {
|
|
||||||
path.node.typeParameters = null;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function visitPattern({ node }) {
|
|
||||||
if (node.typeAnnotation) node.typeAnnotation = null;
|
|
||||||
if (t.isIdentifier(node) && node.optional) node.optional = null;
|
|
||||||
// 'access' and 'readonly' are only for parameter properties, so constructor visitor will handle them.
|
|
||||||
}
|
|
||||||
|
|
||||||
function isImportTypeOnly({ binding, programPath, jsxPragma }) {
|
|
||||||
for (const path of binding.referencePaths) {
|
|
||||||
if (!isInType(path)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (binding.identifier.name !== jsxPragma) {
|
if (binding.identifier.name !== jsxPragma) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "React" or the JSX pragma is referenced as a value if there are any JSX elements in the code.
|
// "React" or the JSX pragma is referenced as a value if there are any JSX elements in the code.
|
||||||
let sourceFileHasJsx = false;
|
let sourceFileHasJsx = false;
|
||||||
programPath.traverse({
|
programPath.traverse({
|
||||||
JSXElement() {
|
JSXElement() {
|
||||||
sourceFileHasJsx = true;
|
sourceFileHasJsx = true;
|
||||||
},
|
},
|
||||||
JSXFragment() {
|
JSXFragment() {
|
||||||
sourceFileHasJsx = true;
|
sourceFileHasJsx = true;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return !sourceFileHasJsx;
|
return !sourceFileHasJsx;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|||||||
171
packages/babel-plugin-transform-typescript/src/namespace.js
Normal file
171
packages/babel-plugin-transform-typescript/src/namespace.js
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
import { template } from "@babel/core";
|
||||||
|
|
||||||
|
export default function transpileNamespace(path, t, allowNamespaces) {
|
||||||
|
if (path.node.declare || path.node.id.type === "StringLiteral") {
|
||||||
|
path.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allowNamespaces) {
|
||||||
|
throw path.hub.file.buildCodeFrameError(
|
||||||
|
path.node.id,
|
||||||
|
"Namespace not marked type-only declare." +
|
||||||
|
" Non-declarative namespaces are only supported experimentally in Babel." +
|
||||||
|
" To enable and review caveats see:" +
|
||||||
|
" https://babeljs.io/docs/en/babel-plugin-transform-typescript",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = path.node.id.name;
|
||||||
|
const value = handleNested(path, t, t.cloneDeep(path.node));
|
||||||
|
const bound = path.scope.hasOwnBinding(name);
|
||||||
|
if (path.parent.type === "ExportNamedDeclaration") {
|
||||||
|
if (!bound) {
|
||||||
|
path.parentPath.insertAfter(value);
|
||||||
|
path.replaceWith(getDeclaration(t, name));
|
||||||
|
path.scope.registerDeclaration(path.parentPath);
|
||||||
|
} else {
|
||||||
|
path.parentPath.replaceWith(value);
|
||||||
|
}
|
||||||
|
} else if (bound) {
|
||||||
|
path.replaceWith(value);
|
||||||
|
} else {
|
||||||
|
path.scope.registerDeclaration(
|
||||||
|
path.replaceWithMultiple([getDeclaration(t, name), value])[0],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDeclaration(t, name) {
|
||||||
|
return t.variableDeclaration("let", [
|
||||||
|
t.variableDeclarator(t.identifier(name)),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMemberExpression(t, name, itemName) {
|
||||||
|
return t.memberExpression(t.identifier(name), t.identifier(itemName));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleNested(path, t, node, parentExport) {
|
||||||
|
const names = new Set();
|
||||||
|
const realName = node.id;
|
||||||
|
const name = path.scope.generateUid(realName.name);
|
||||||
|
const namespaceTopLevel = node.body.body;
|
||||||
|
for (let i = 0; i < namespaceTopLevel.length; i++) {
|
||||||
|
const subNode = namespaceTopLevel[i];
|
||||||
|
|
||||||
|
// The first switch is mainly to detect name usage. Only export
|
||||||
|
// declarations require further transformation.
|
||||||
|
switch (subNode.type) {
|
||||||
|
case "TSModuleDeclaration": {
|
||||||
|
const transformed = handleNested(path, t, subNode);
|
||||||
|
const moduleName = subNode.id.name;
|
||||||
|
if (names.has(moduleName)) {
|
||||||
|
namespaceTopLevel[i] = transformed;
|
||||||
|
} else {
|
||||||
|
names.add(moduleName);
|
||||||
|
namespaceTopLevel.splice(
|
||||||
|
i++,
|
||||||
|
1,
|
||||||
|
getDeclaration(t, moduleName),
|
||||||
|
transformed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case "TSEnumDeclaration":
|
||||||
|
case "FunctionDeclaration":
|
||||||
|
case "ClassDeclaration":
|
||||||
|
names.add(subNode.id.name);
|
||||||
|
continue;
|
||||||
|
case "VariableDeclaration":
|
||||||
|
for (const variable of subNode.declarations) {
|
||||||
|
names.add(variable.id.name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
// Neither named declaration nor export, continue to next item.
|
||||||
|
continue;
|
||||||
|
case "ExportNamedDeclaration":
|
||||||
|
// Export declarations get parsed using the next switch.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform the export declarations that occur inside of a namespace.
|
||||||
|
switch (subNode.declaration.type) {
|
||||||
|
case "TSEnumDeclaration":
|
||||||
|
case "FunctionDeclaration":
|
||||||
|
case "ClassDeclaration": {
|
||||||
|
const itemName = subNode.declaration.id.name;
|
||||||
|
names.add(itemName);
|
||||||
|
namespaceTopLevel.splice(
|
||||||
|
i++,
|
||||||
|
1,
|
||||||
|
subNode.declaration,
|
||||||
|
t.expressionStatement(
|
||||||
|
t.assignmentExpression(
|
||||||
|
"=",
|
||||||
|
getMemberExpression(t, name, itemName),
|
||||||
|
t.identifier(itemName),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "VariableDeclaration":
|
||||||
|
if (subNode.declaration.kind !== "const") {
|
||||||
|
throw path.hub.file.buildCodeFrameError(
|
||||||
|
subNode.declaration,
|
||||||
|
"Namespaces exporting non-const are not supported by Babel." +
|
||||||
|
" Change to const or see:" +
|
||||||
|
" https://babeljs.io/docs/en/babel-plugin-transform-typescript",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (const variable of subNode.declaration.declarations) {
|
||||||
|
variable.init = t.assignmentExpression(
|
||||||
|
"=",
|
||||||
|
getMemberExpression(t, name, variable.id.name),
|
||||||
|
variable.init,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
namespaceTopLevel[i] = subNode.declaration;
|
||||||
|
break;
|
||||||
|
case "TSModuleDeclaration": {
|
||||||
|
const transformed = handleNested(
|
||||||
|
path,
|
||||||
|
t,
|
||||||
|
subNode.declaration,
|
||||||
|
t.identifier(name),
|
||||||
|
);
|
||||||
|
const moduleName = subNode.declaration.id.name;
|
||||||
|
if (names.has(moduleName)) {
|
||||||
|
namespaceTopLevel[i] = transformed;
|
||||||
|
} else {
|
||||||
|
names.add(moduleName);
|
||||||
|
namespaceTopLevel.splice(
|
||||||
|
i++,
|
||||||
|
1,
|
||||||
|
getDeclaration(t, moduleName),
|
||||||
|
transformed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// {}
|
||||||
|
let fallthroughValue = t.objectExpression([]);
|
||||||
|
|
||||||
|
if (parentExport) {
|
||||||
|
fallthroughValue = template.expression.ast`
|
||||||
|
${parentExport}.${realName} || (
|
||||||
|
${parentExport}.${realName} = ${fallthroughValue}
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return template.statement.ast`
|
||||||
|
(function (${t.identifier(name)}) {
|
||||||
|
${namespaceTopLevel}
|
||||||
|
})(${realName} || (${realName} = ${fallthroughValue}));
|
||||||
|
`;
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
; // Otherwise-empty file
|
||||||
|
export declare namespace P {
|
||||||
|
export namespace C {}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
; // Otherwise-empty file
|
||||||
35
packages/babel-plugin-transform-typescript/test/fixtures/namespace/canonical/input.mjs
vendored
Normal file
35
packages/babel-plugin-transform-typescript/test/fixtures/namespace/canonical/input.mjs
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
namespace Validation {
|
||||||
|
export interface StringValidator {
|
||||||
|
isAcceptable(s: string): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lettersRegexp = /^[A-Za-z]+$/;
|
||||||
|
const numberRegexp = /^[0-9]+$/;
|
||||||
|
|
||||||
|
export class LettersOnlyValidator implements StringValidator {
|
||||||
|
constructor() {
|
||||||
|
console.log("1");
|
||||||
|
}
|
||||||
|
isAcceptable(s: string) {
|
||||||
|
return lettersRegexp.test(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ZipCodeValidator implements StringValidator {
|
||||||
|
isAcceptable(s: string) {
|
||||||
|
return s.length === 5 && numberRegexp.test(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let strings = ["Hello", "98052", "101"];
|
||||||
|
|
||||||
|
let validators: { [s: string]: Validation.StringValidator; } = {};
|
||||||
|
validators["ZIP code"] = new Validation.ZipCodeValidator();
|
||||||
|
validators["Letters only"] = new Validation.LettersOnlyValidator();
|
||||||
|
|
||||||
|
for (let s of strings) {
|
||||||
|
for (let name in validators) {
|
||||||
|
console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
packages/babel-plugin-transform-typescript/test/fixtures/namespace/canonical/output.mjs
vendored
Normal file
39
packages/babel-plugin-transform-typescript/test/fixtures/namespace/canonical/output.mjs
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
let Validation;
|
||||||
|
|
||||||
|
(function (_Validation) {
|
||||||
|
const lettersRegexp = /^[A-Za-z]+$/;
|
||||||
|
const numberRegexp = /^[0-9]+$/;
|
||||||
|
|
||||||
|
class LettersOnlyValidator {
|
||||||
|
constructor() {
|
||||||
|
console.log("1");
|
||||||
|
}
|
||||||
|
|
||||||
|
isAcceptable(s) {
|
||||||
|
return lettersRegexp.test(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_Validation.LettersOnlyValidator = LettersOnlyValidator;
|
||||||
|
|
||||||
|
class ZipCodeValidator {
|
||||||
|
isAcceptable(s) {
|
||||||
|
return s.length === 5 && numberRegexp.test(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_Validation.ZipCodeValidator = ZipCodeValidator;
|
||||||
|
})(Validation || (Validation = {}));
|
||||||
|
|
||||||
|
let strings = ["Hello", "98052", "101"];
|
||||||
|
let validators = {};
|
||||||
|
validators["ZIP code"] = new Validation.ZipCodeValidator();
|
||||||
|
validators["Letters only"] = new Validation.LettersOnlyValidator();
|
||||||
|
|
||||||
|
for (let s of strings) {
|
||||||
|
for (let name in validators) {
|
||||||
|
console.log(`"${s}" - ${validators[name].isAcceptable(s) ? "matches" : "does not match"} ${name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
4
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-class/input.mjs
vendored
Normal file
4
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-class/input.mjs
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
class A { }
|
||||||
|
namespace A {
|
||||||
|
export const B = 1;
|
||||||
|
}
|
||||||
5
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-class/output.mjs
vendored
Normal file
5
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-class/output.mjs
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class A {}
|
||||||
|
|
||||||
|
(function (_A) {
|
||||||
|
const B = _A.B = 1;
|
||||||
|
})(A || (A = {}));
|
||||||
6
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/input.mjs
vendored
Normal file
6
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/input.mjs
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
enum A {
|
||||||
|
C = 2,
|
||||||
|
}
|
||||||
|
namespace A {
|
||||||
|
export const B = 1;
|
||||||
|
}
|
||||||
9
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/output.mjs
vendored
Normal file
9
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/output.mjs
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
var A;
|
||||||
|
|
||||||
|
(function (A) {
|
||||||
|
A[A["C"] = 2] = "C";
|
||||||
|
})(A || (A = {}));
|
||||||
|
|
||||||
|
(function (_A) {
|
||||||
|
const B = _A.B = 1;
|
||||||
|
})(A || (A = {}));
|
||||||
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-export/input.mjs
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-export/input.mjs
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export class N {}
|
||||||
|
export namespace N {}
|
||||||
|
export default N;
|
||||||
5
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-export/output.mjs
vendored
Normal file
5
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-export/output.mjs
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export class N {}
|
||||||
|
|
||||||
|
(function (_N) {})(N || (N = {}));
|
||||||
|
|
||||||
|
export default N;
|
||||||
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-import/input.mjs
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-import/input.mjs
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import N from 'n';
|
||||||
|
|
||||||
|
namespace N {}
|
||||||
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-import/output.mjs
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-import/output.mjs
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import N from 'n';
|
||||||
|
|
||||||
|
(function (_N) {})(N || (N = {}));
|
||||||
36
packages/babel-plugin-transform-typescript/test/fixtures/namespace/contentious-names/input.mjs
vendored
Normal file
36
packages/babel-plugin-transform-typescript/test/fixtures/namespace/contentious-names/input.mjs
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
namespace N {
|
||||||
|
namespace N {}
|
||||||
|
namespace constructor {}
|
||||||
|
namespace length {}
|
||||||
|
namespace concat {}
|
||||||
|
namespace copyWithin {}
|
||||||
|
namespace fill {}
|
||||||
|
namespace find {}
|
||||||
|
namespace findIndex {}
|
||||||
|
namespace lastIndexOf {}
|
||||||
|
namespace pop {}
|
||||||
|
namespace push {}
|
||||||
|
namespace reverse {}
|
||||||
|
namespace shift {}
|
||||||
|
namespace unshift {}
|
||||||
|
namespace slice {}
|
||||||
|
namespace sort {}
|
||||||
|
namespace splice {}
|
||||||
|
namespace includes {}
|
||||||
|
namespace indexOf {}
|
||||||
|
namespace join {}
|
||||||
|
namespace keys {}
|
||||||
|
namespace entries {}
|
||||||
|
namespace values {}
|
||||||
|
namespace forEach {}
|
||||||
|
namespace filter {}
|
||||||
|
namespace map {}
|
||||||
|
namespace every {}
|
||||||
|
namespace some {}
|
||||||
|
namespace reduce {}
|
||||||
|
namespace reduceRight {}
|
||||||
|
namespace toLocaleString {}
|
||||||
|
namespace toString {}
|
||||||
|
namespace flat {}
|
||||||
|
namespace flatMap {}
|
||||||
|
}
|
||||||
139
packages/babel-plugin-transform-typescript/test/fixtures/namespace/contentious-names/output.mjs
vendored
Normal file
139
packages/babel-plugin-transform-typescript/test/fixtures/namespace/contentious-names/output.mjs
vendored
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
let N;
|
||||||
|
|
||||||
|
(function (_N) {
|
||||||
|
let N;
|
||||||
|
|
||||||
|
(function (_N2) {})(N || (N = {}));
|
||||||
|
|
||||||
|
let constructor;
|
||||||
|
|
||||||
|
(function (_constructor) {})(constructor || (constructor = {}));
|
||||||
|
|
||||||
|
let length;
|
||||||
|
|
||||||
|
(function (_length) {})(length || (length = {}));
|
||||||
|
|
||||||
|
let concat;
|
||||||
|
|
||||||
|
(function (_concat) {})(concat || (concat = {}));
|
||||||
|
|
||||||
|
let copyWithin;
|
||||||
|
|
||||||
|
(function (_copyWithin) {})(copyWithin || (copyWithin = {}));
|
||||||
|
|
||||||
|
let fill;
|
||||||
|
|
||||||
|
(function (_fill) {})(fill || (fill = {}));
|
||||||
|
|
||||||
|
let find;
|
||||||
|
|
||||||
|
(function (_find) {})(find || (find = {}));
|
||||||
|
|
||||||
|
let findIndex;
|
||||||
|
|
||||||
|
(function (_findIndex) {})(findIndex || (findIndex = {}));
|
||||||
|
|
||||||
|
let lastIndexOf;
|
||||||
|
|
||||||
|
(function (_lastIndexOf) {})(lastIndexOf || (lastIndexOf = {}));
|
||||||
|
|
||||||
|
let pop;
|
||||||
|
|
||||||
|
(function (_pop) {})(pop || (pop = {}));
|
||||||
|
|
||||||
|
let push;
|
||||||
|
|
||||||
|
(function (_push) {})(push || (push = {}));
|
||||||
|
|
||||||
|
let reverse;
|
||||||
|
|
||||||
|
(function (_reverse) {})(reverse || (reverse = {}));
|
||||||
|
|
||||||
|
let shift;
|
||||||
|
|
||||||
|
(function (_shift) {})(shift || (shift = {}));
|
||||||
|
|
||||||
|
let unshift;
|
||||||
|
|
||||||
|
(function (_unshift) {})(unshift || (unshift = {}));
|
||||||
|
|
||||||
|
let slice;
|
||||||
|
|
||||||
|
(function (_slice) {})(slice || (slice = {}));
|
||||||
|
|
||||||
|
let sort;
|
||||||
|
|
||||||
|
(function (_sort) {})(sort || (sort = {}));
|
||||||
|
|
||||||
|
let splice;
|
||||||
|
|
||||||
|
(function (_splice) {})(splice || (splice = {}));
|
||||||
|
|
||||||
|
let includes;
|
||||||
|
|
||||||
|
(function (_includes) {})(includes || (includes = {}));
|
||||||
|
|
||||||
|
let indexOf;
|
||||||
|
|
||||||
|
(function (_indexOf) {})(indexOf || (indexOf = {}));
|
||||||
|
|
||||||
|
let join;
|
||||||
|
|
||||||
|
(function (_join) {})(join || (join = {}));
|
||||||
|
|
||||||
|
let keys;
|
||||||
|
|
||||||
|
(function (_keys) {})(keys || (keys = {}));
|
||||||
|
|
||||||
|
let entries;
|
||||||
|
|
||||||
|
(function (_entries) {})(entries || (entries = {}));
|
||||||
|
|
||||||
|
let values;
|
||||||
|
|
||||||
|
(function (_values) {})(values || (values = {}));
|
||||||
|
|
||||||
|
let forEach;
|
||||||
|
|
||||||
|
(function (_forEach) {})(forEach || (forEach = {}));
|
||||||
|
|
||||||
|
let filter;
|
||||||
|
|
||||||
|
(function (_filter) {})(filter || (filter = {}));
|
||||||
|
|
||||||
|
let map;
|
||||||
|
|
||||||
|
(function (_map) {})(map || (map = {}));
|
||||||
|
|
||||||
|
let every;
|
||||||
|
|
||||||
|
(function (_every) {})(every || (every = {}));
|
||||||
|
|
||||||
|
let some;
|
||||||
|
|
||||||
|
(function (_some) {})(some || (some = {}));
|
||||||
|
|
||||||
|
let reduce;
|
||||||
|
|
||||||
|
(function (_reduce) {})(reduce || (reduce = {}));
|
||||||
|
|
||||||
|
let reduceRight;
|
||||||
|
|
||||||
|
(function (_reduceRight) {})(reduceRight || (reduceRight = {}));
|
||||||
|
|
||||||
|
let toLocaleString;
|
||||||
|
|
||||||
|
(function (_toLocaleString) {})(toLocaleString || (toLocaleString = {}));
|
||||||
|
|
||||||
|
let toString;
|
||||||
|
|
||||||
|
(function (_toString) {})(toString || (toString = {}));
|
||||||
|
|
||||||
|
let flat;
|
||||||
|
|
||||||
|
(function (_flat) {})(flat || (flat = {}));
|
||||||
|
|
||||||
|
let flatMap;
|
||||||
|
|
||||||
|
(function (_flatMap) {})(flatMap || (flatMap = {}));
|
||||||
|
})(N || (N = {}));
|
||||||
1
packages/babel-plugin-transform-typescript/test/fixtures/namespace/export/input.mjs
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/namespace/export/input.mjs
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
export namespace N {}
|
||||||
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/export/output.mjs
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/export/output.mjs
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export let N;
|
||||||
|
|
||||||
|
(function (_N) {})(N || (N = {}));
|
||||||
@ -1 +0,0 @@
|
|||||||
namespace N {}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"throws": "Namespaces are not supported."
|
|
||||||
}
|
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
export module src {
|
||||||
|
export namespace ns1 {
|
||||||
|
export class foo {
|
||||||
|
F1: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export namespace ns2 {
|
||||||
|
export class foo {
|
||||||
|
F1: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
export let src;
|
||||||
|
|
||||||
|
(function (_src) {
|
||||||
|
let ns1;
|
||||||
|
|
||||||
|
(function (_ns) {
|
||||||
|
class foo {}
|
||||||
|
|
||||||
|
_ns.foo = foo;
|
||||||
|
})(ns1 || (ns1 = _src.ns1 || (_src.ns1 = {})));
|
||||||
|
|
||||||
|
let ns2;
|
||||||
|
|
||||||
|
(function (_ns2) {
|
||||||
|
class foo {}
|
||||||
|
|
||||||
|
_ns2.foo = foo;
|
||||||
|
})(ns2 || (ns2 = _src.ns2 || (_src.ns2 = {})));
|
||||||
|
})(src || (src = {}));
|
||||||
12
packages/babel-plugin-transform-typescript/test/fixtures/namespace/module-nested/input.mjs
vendored
Normal file
12
packages/babel-plugin-transform-typescript/test/fixtures/namespace/module-nested/input.mjs
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module src {
|
||||||
|
export namespace ns1 {
|
||||||
|
export class foo {
|
||||||
|
F1: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export namespace ns2 {
|
||||||
|
export class foo {
|
||||||
|
F1: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
packages/babel-plugin-transform-typescript/test/fixtures/namespace/module-nested/output.mjs
vendored
Normal file
19
packages/babel-plugin-transform-typescript/test/fixtures/namespace/module-nested/output.mjs
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
let src;
|
||||||
|
|
||||||
|
(function (_src) {
|
||||||
|
let ns1;
|
||||||
|
|
||||||
|
(function (_ns) {
|
||||||
|
class foo {}
|
||||||
|
|
||||||
|
_ns.foo = foo;
|
||||||
|
})(ns1 || (ns1 = _src.ns1 || (_src.ns1 = {})));
|
||||||
|
|
||||||
|
let ns2;
|
||||||
|
|
||||||
|
(function (_ns2) {
|
||||||
|
class foo {}
|
||||||
|
|
||||||
|
_ns2.foo = foo;
|
||||||
|
})(ns2 || (ns2 = _src.ns2 || (_src.ns2 = {})));
|
||||||
|
})(src || (src = {}));
|
||||||
2
packages/babel-plugin-transform-typescript/test/fixtures/namespace/multiple/input.mjs
vendored
Normal file
2
packages/babel-plugin-transform-typescript/test/fixtures/namespace/multiple/input.mjs
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
namespace N {}
|
||||||
|
namespace N {}
|
||||||
5
packages/babel-plugin-transform-typescript/test/fixtures/namespace/multiple/output.mjs
vendored
Normal file
5
packages/babel-plugin-transform-typescript/test/fixtures/namespace/multiple/output.mjs
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
let N;
|
||||||
|
|
||||||
|
(function (_N) {})(N || (N = {}));
|
||||||
|
|
||||||
|
(function (_N2) {})(N || (N = {}));
|
||||||
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/mutable-fail/input.mjs
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/mutable-fail/input.mjs
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace N {
|
||||||
|
export let V;
|
||||||
|
}
|
||||||
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/mutable-fail/options.json
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/mutable-fail/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"throws": "Namespaces exporting non-const are not supported by Babel. Change to const or see: https://babeljs.io/docs/en/babel-plugin-transform-typescript"
|
||||||
|
}
|
||||||
1
packages/babel-plugin-transform-typescript/test/fixtures/namespace/namespace-flag/input.mjs
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/namespace/namespace-flag/input.mjs
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
namespace N {}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"throws": "Namespace not marked type-only declare. Non-declarative namespaces are only supported experimentally in Babel. To enable and review caveats see: https://babeljs.io/docs/en/babel-plugin-transform-typescript",
|
||||||
|
"plugins": [["transform-typescript", { "allowNamespaces": false }]]
|
||||||
|
}
|
||||||
26
packages/babel-plugin-transform-typescript/test/fixtures/namespace/nested/input.mjs
vendored
Normal file
26
packages/babel-plugin-transform-typescript/test/fixtures/namespace/nested/input.mjs
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
class A { }
|
||||||
|
namespace A {
|
||||||
|
export namespace C {
|
||||||
|
export class G {}
|
||||||
|
export const E = 7;
|
||||||
|
}
|
||||||
|
function M() {}
|
||||||
|
namespace M {
|
||||||
|
export const N = C.E;
|
||||||
|
}
|
||||||
|
export function D() {}
|
||||||
|
export namespace D {
|
||||||
|
const C = 5;
|
||||||
|
export enum H {
|
||||||
|
I = 11,
|
||||||
|
J = 13,
|
||||||
|
K = 17,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class F {}
|
||||||
|
namespace F {}
|
||||||
|
namespace G {}
|
||||||
|
enum L {
|
||||||
|
M = 19,
|
||||||
|
}
|
||||||
|
}
|
||||||
49
packages/babel-plugin-transform-typescript/test/fixtures/namespace/nested/output.mjs
vendored
Normal file
49
packages/babel-plugin-transform-typescript/test/fixtures/namespace/nested/output.mjs
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
class A {}
|
||||||
|
|
||||||
|
(function (_A) {
|
||||||
|
let C;
|
||||||
|
|
||||||
|
(function (_C) {
|
||||||
|
class G {}
|
||||||
|
|
||||||
|
_C.G = G;
|
||||||
|
const E = _C.E = 7;
|
||||||
|
})(C || (C = _A.C || (_A.C = {})));
|
||||||
|
|
||||||
|
function M() {}
|
||||||
|
|
||||||
|
(function (_M) {
|
||||||
|
const N = _M.N = C.E;
|
||||||
|
})(M || (M = {}));
|
||||||
|
|
||||||
|
function D() {}
|
||||||
|
|
||||||
|
_A.D = D;
|
||||||
|
|
||||||
|
(function (_D) {
|
||||||
|
const C = 5;
|
||||||
|
let H;
|
||||||
|
|
||||||
|
(function (H) {
|
||||||
|
H[H["I"] = 11] = "I";
|
||||||
|
H[H["J"] = 13] = "J";
|
||||||
|
H[H["K"] = 17] = "K";
|
||||||
|
})(H || (H = {}));
|
||||||
|
|
||||||
|
_D.H = H;
|
||||||
|
})(D || (D = _A.D || (_A.D = {})));
|
||||||
|
|
||||||
|
class F {}
|
||||||
|
|
||||||
|
(function (_F) {})(F || (F = {}));
|
||||||
|
|
||||||
|
let G;
|
||||||
|
|
||||||
|
(function (_G) {})(G || (G = {}));
|
||||||
|
|
||||||
|
let L;
|
||||||
|
|
||||||
|
(function (L) {
|
||||||
|
L[L["M"] = 19] = "M";
|
||||||
|
})(L || (L = {}));
|
||||||
|
})(A || (A = {}));
|
||||||
12
packages/babel-plugin-transform-typescript/test/fixtures/namespace/same-name/input.mjs
vendored
Normal file
12
packages/babel-plugin-transform-typescript/test/fixtures/namespace/same-name/input.mjs
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace N {
|
||||||
|
namespace _N7 {}
|
||||||
|
export namespace N {
|
||||||
|
export function _N3() {}
|
||||||
|
}
|
||||||
|
export namespace N {
|
||||||
|
export class _N5 {}
|
||||||
|
}
|
||||||
|
export namespace N {
|
||||||
|
export enum _N {}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
packages/babel-plugin-transform-typescript/test/fixtures/namespace/same-name/output.mjs
vendored
Normal file
29
packages/babel-plugin-transform-typescript/test/fixtures/namespace/same-name/output.mjs
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
let N;
|
||||||
|
|
||||||
|
(function (_N2) {
|
||||||
|
let _N7;
|
||||||
|
|
||||||
|
(function (_N4) {})(_N7 || (_N7 = {}));
|
||||||
|
|
||||||
|
let N;
|
||||||
|
|
||||||
|
(function (_N6) {
|
||||||
|
function _N3() {}
|
||||||
|
|
||||||
|
_N6._N3 = _N3;
|
||||||
|
})(N || (N = _N2.N || (_N2.N = {})));
|
||||||
|
|
||||||
|
(function (_N8) {
|
||||||
|
class _N5 {}
|
||||||
|
|
||||||
|
_N8._N5 = _N5;
|
||||||
|
})(N || (N = _N2.N || (_N2.N = {})));
|
||||||
|
|
||||||
|
(function (_N9) {
|
||||||
|
let _N;
|
||||||
|
|
||||||
|
(function (_N) {})(_N || (_N = {}));
|
||||||
|
|
||||||
|
_N9._N = _N;
|
||||||
|
})(N || (N = _N2.N || (_N2.N = {})));
|
||||||
|
})(N || (N = {}));
|
||||||
1
packages/babel-plugin-transform-typescript/test/fixtures/namespace/undeclared/input.mjs
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/namespace/undeclared/input.mjs
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
namespace N {}
|
||||||
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/undeclared/output.mjs
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/namespace/undeclared/output.mjs
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
let N;
|
||||||
|
|
||||||
|
(function (_N) {})(N || (N = {}));
|
||||||
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"plugins": ["transform-typescript"]
|
"plugins": [["transform-typescript", { "allowNamespaces": true }]]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -399,6 +399,7 @@ defineType("TSModuleDeclaration", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
defineType("TSModuleBlock", {
|
defineType("TSModuleBlock", {
|
||||||
|
aliases: ["Scopable", "Block", "BlockParent"],
|
||||||
visitor: ["body"],
|
visitor: ["body"],
|
||||||
fields: {
|
fields: {
|
||||||
body: validateArrayOfType("Statement"),
|
body: validateArrayOfType("Statement"),
|
||||||
|
|||||||
@ -3350,6 +3350,7 @@ export function isScopable(node: ?Object, opts?: Object): boolean {
|
|||||||
"ForOfStatement" === nodeType ||
|
"ForOfStatement" === nodeType ||
|
||||||
"ClassMethod" === nodeType ||
|
"ClassMethod" === nodeType ||
|
||||||
"ClassPrivateMethod" === nodeType ||
|
"ClassPrivateMethod" === nodeType ||
|
||||||
|
"TSModuleBlock" === nodeType ||
|
||||||
(nodeType === "Placeholder" && "BlockStatement" === node.expectedNode)
|
(nodeType === "Placeholder" && "BlockStatement" === node.expectedNode)
|
||||||
) {
|
) {
|
||||||
if (typeof opts === "undefined") {
|
if (typeof opts === "undefined") {
|
||||||
@ -3382,6 +3383,7 @@ export function isBlockParent(node: ?Object, opts?: Object): boolean {
|
|||||||
"ForOfStatement" === nodeType ||
|
"ForOfStatement" === nodeType ||
|
||||||
"ClassMethod" === nodeType ||
|
"ClassMethod" === nodeType ||
|
||||||
"ClassPrivateMethod" === nodeType ||
|
"ClassPrivateMethod" === nodeType ||
|
||||||
|
"TSModuleBlock" === nodeType ||
|
||||||
(nodeType === "Placeholder" && "BlockStatement" === node.expectedNode)
|
(nodeType === "Placeholder" && "BlockStatement" === node.expectedNode)
|
||||||
) {
|
) {
|
||||||
if (typeof opts === "undefined") {
|
if (typeof opts === "undefined") {
|
||||||
@ -3401,6 +3403,7 @@ export function isBlock(node: ?Object, opts?: Object): boolean {
|
|||||||
nodeType === "Block" ||
|
nodeType === "Block" ||
|
||||||
"BlockStatement" === nodeType ||
|
"BlockStatement" === nodeType ||
|
||||||
"Program" === nodeType ||
|
"Program" === nodeType ||
|
||||||
|
"TSModuleBlock" === nodeType ||
|
||||||
(nodeType === "Placeholder" && "BlockStatement" === node.expectedNode)
|
(nodeType === "Placeholder" && "BlockStatement" === node.expectedNode)
|
||||||
) {
|
) {
|
||||||
if (typeof opts === "undefined") {
|
if (typeof opts === "undefined") {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user