@babel/plugin-transform-typescript
Version:
Transform TypeScript into ES.next
1,037 lines (1,030 loc) • 35.9 kB
JavaScript
import { declare } from '@babel/helper-plugin-utils';
import syntaxTypeScript from '@babel/plugin-syntax-typescript';
import { injectInitialization } from '@babel/helper-create-class-features-plugin';
import { template, types } from '@babel/core';
import assert from 'node:assert';
import annotateAsPure from '@babel/helper-annotate-as-pure';
import { skipTransparentExprWrapperNodes } from '@babel/helper-skip-transparent-expression-wrappers';
const ENUMS = new WeakMap();
const buildEnumWrapper = template.expression(`
(function (ID) {
ASSIGNMENTS;
return ID;
})(INIT)
`);
function transpileEnum(path, t) {
const {
node,
parentPath
} = path;
if (node.declare) {
path.remove();
return;
}
const name = node.id.name;
const {
fill,
data,
isPure
} = enumFill(path, t, node.id);
switch (parentPath.type) {
case "BlockStatement":
case "ExportNamedDeclaration":
case "Program":
{
const isGlobal = t.isProgram(path.parent);
const isSeen = seen(parentPath);
let init = t.objectExpression([]);
if (isSeen || isGlobal) {
init = t.logicalExpression("||", t.cloneNode(fill.ID), init);
}
const enumIIFE = buildEnumWrapper({
...fill,
INIT: init
});
if (isPure) annotateAsPure(enumIIFE);
if (isSeen) {
const toReplace = parentPath.isExportDeclaration() ? parentPath : path;
toReplace.replaceWith(t.expressionStatement(t.assignmentExpression("=", t.cloneNode(node.id), enumIIFE)));
} else {
path.scope.registerDeclaration(path.replaceWith(t.variableDeclaration(isGlobal ? "var" : "let", [t.variableDeclarator(node.id, enumIIFE)]))[0]);
}
ENUMS.set(path.scope.getBindingIdentifier(name), data);
break;
}
default:
throw new Error(`Unexpected enum parent '${path.parent.type}`);
}
function seen(parentPath) {
if (parentPath.isExportDeclaration()) {
return seen(parentPath.parentPath);
}
if (parentPath.getData(name)) {
return true;
} else {
parentPath.setData(name, true);
return false;
}
}
}
const buildStringAssignment = template.statement(`
ENUM["NAME"] = VALUE;
`);
const buildNumericAssignment = template.statement(`
ENUM[ENUM["NAME"] = VALUE] = "NAME";
`);
const buildEnumMember = (isString, options) => (isString ? buildStringAssignment : buildNumericAssignment)(options);
function enumFill(path, t, id) {
const {
enumValues,
data,
isPure
} = translateEnumValues(path, t);
const enumMembers = path.get("body").get("members");
const assignments = [];
for (let i = 0; i < enumMembers.length; i++) {
const [memberName, memberValue] = enumValues[i];
assignments.push(t.inheritsComments(buildEnumMember(isSyntacticallyString(memberValue), {
ENUM: t.cloneNode(id),
NAME: memberName,
VALUE: memberValue
}), enumMembers[i].node));
}
return {
fill: {
ID: t.cloneNode(id),
ASSIGNMENTS: assignments
},
data,
isPure
};
}
function isSyntacticallyString(expr) {
expr = skipTransparentExprWrapperNodes(expr);
switch (expr.type) {
case "BinaryExpression":
{
const left = expr.left;
const right = expr.right;
return expr.operator === "+" && (isSyntacticallyString(left) || isSyntacticallyString(right));
}
case "TemplateLiteral":
case "StringLiteral":
return true;
}
return false;
}
function ReferencedIdentifier(expr, state) {
const {
seen,
path,
t
} = state;
const name = expr.node.name;
if (seen.has(name)) {
if (expr.scope.hasBinding(name, {
upToScope: path.scope
})) {
return;
}
expr.replaceWith(t.memberExpression(t.cloneNode(path.node.id), t.cloneNode(expr.node)));
expr.skip();
}
}
const enumSelfReferenceVisitor = {
ReferencedIdentifier
};
function translateEnumValues(path, t) {
const bindingIdentifier = path.scope.getBindingIdentifier(path.node.id.name);
const seen = ENUMS.get(bindingIdentifier) ?? new Map();
let constValue = -1;
let lastName;
let isPure = true;
const enumMembers = path.get("body").get("members");
const enumValues = enumMembers.map(memberPath => {
const member = memberPath.node;
const name = t.isIdentifier(member.id) ? member.id.name : member.id.value;
const initializerPath = memberPath.get("initializer");
const initializer = member.initializer;
let value;
if (initializer) {
constValue = computeConstantValue(initializerPath, seen);
if (constValue !== undefined) {
seen.set(name, constValue);
assert(typeof constValue === "number" || typeof constValue === "string");
if (constValue === Infinity || Number.isNaN(constValue)) {
value = t.identifier(String(constValue));
} else if (constValue === -Infinity) {
value = t.unaryExpression("-", t.identifier("Infinity"));
} else {
value = t.valueToNode(constValue);
}
} else {
isPure &&= initializerPath.isPure();
if (initializerPath.isReferencedIdentifier()) {
ReferencedIdentifier(initializerPath, {
t,
seen,
path
});
} else {
initializerPath.traverse(enumSelfReferenceVisitor, {
t,
seen,
path
});
}
value = initializerPath.node;
seen.set(name, undefined);
}
} else if (typeof constValue === "number") {
constValue += 1;
value = t.numericLiteral(constValue);
seen.set(name, constValue);
} else if (typeof constValue === "string") {
throw path.buildCodeFrameError("Enum member must have initializer.");
} else {
const lastRef = t.memberExpression(t.cloneNode(path.node.id), t.stringLiteral(lastName), true);
value = t.binaryExpression("+", t.numericLiteral(1), lastRef);
seen.set(name, undefined);
}
lastName = name;
return [name, value];
});
return {
isPure,
data: seen,
enumValues
};
}
function computeConstantValue(path, prevMembers, seen = new Set()) {
return evaluate(path);
function evaluate(path) {
const expr = path.node;
switch (expr.type) {
case "MemberExpression":
return evaluateRef(path, prevMembers, seen);
case "StringLiteral":
return expr.value;
case "UnaryExpression":
return evalUnaryExpression(path);
case "BinaryExpression":
return evalBinaryExpression(path);
case "NumericLiteral":
return expr.value;
case "ParenthesizedExpression":
return evaluate(path.get("expression"));
case "Identifier":
return evaluateRef(path, prevMembers, seen);
case "TemplateLiteral":
{
if (expr.quasis.length === 1) {
return expr.quasis[0].value.cooked ?? undefined;
}
const paths = path.get("expressions");
const quasis = expr.quasis;
let str = "";
for (let i = 0; i < quasis.length; i++) {
str += quasis[i].value.cooked;
if (i + 1 < quasis.length) {
const value = evaluateRef(paths[i], prevMembers, seen);
if (value === undefined) return undefined;
str += value;
}
}
return str;
}
default:
return undefined;
}
}
function evaluateRef(path, prevMembers, seen) {
if (path.isMemberExpression()) {
const expr = path.node;
const obj = expr.object;
const prop = expr.property;
if (!types.isIdentifier(obj) || (expr.computed ? !types.isStringLiteral(prop) : !types.isIdentifier(prop))) {
return;
}
const bindingIdentifier = path.scope.getBindingIdentifier(obj.name);
const data = ENUMS.get(bindingIdentifier);
if (!data) return;
return data.get(prop.computed ? prop.value : prop.name);
} else if (path.isIdentifier()) {
const name = path.node.name;
if (["Infinity", "NaN"].includes(name)) {
return Number(name);
}
let value = prevMembers?.get(name);
if (value !== undefined) {
return value;
}
if (prevMembers?.has(name)) {
return undefined;
}
if (seen.has(path.node)) return;
seen.add(path.node);
value = computeConstantValue(path.resolve(), prevMembers, seen);
return value;
}
}
function evalUnaryExpression(path) {
const value = evaluate(path.get("argument"));
if (value === undefined) {
return undefined;
}
switch (path.node.operator) {
case "+":
return value;
case "-":
return -value;
case "~":
return ~value;
default:
return undefined;
}
}
function evalBinaryExpression(path) {
const left = evaluate(path.get("left"));
if (left === undefined) {
return undefined;
}
const right = evaluate(path.get("right"));
if (right === undefined) {
return undefined;
}
switch (path.node.operator) {
case "|":
return left | right;
case "&":
return left & right;
case ">>":
return left >> right;
case ">>>":
return left >>> right;
case "<<":
return left << right;
case "^":
return left ^ right;
case "*":
return left * right;
case "/":
return left / right;
case "+":
return left + right;
case "-":
return left - right;
case "%":
return left % right;
case "**":
return left ** right;
default:
return undefined;
}
}
}
const EXPORTED_CONST_ENUMS_IN_NAMESPACE = new WeakSet();
function transpileConstEnum(path, t) {
const {
name
} = path.node.id;
const parentIsExport = path.parentPath.isExportNamedDeclaration();
let isExported = parentIsExport;
if (!isExported && t.isProgram(path.parent)) {
isExported = path.parent.body.some(stmt => t.isExportNamedDeclaration(stmt) && stmt.exportKind !== "type" && !stmt.source && stmt.specifiers.some(spec => t.isExportSpecifier(spec) && spec.exportKind !== "type" && spec.local.name === name));
}
const {
enumValues: entries
} = translateEnumValues(path, t);
if (isExported || EXPORTED_CONST_ENUMS_IN_NAMESPACE.has(path.node)) {
const obj = t.objectExpression(entries.map(([name, value]) => t.objectProperty(t.isValidIdentifier(name) ? t.identifier(name) : t.stringLiteral(name), value)));
if (path.scope.hasOwnBinding(name)) {
(parentIsExport ? path.parentPath : path).replaceWith(t.expressionStatement(t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("assign")), [path.node.id, obj])));
} else {
path.replaceWith(t.variableDeclaration("const", [t.variableDeclarator(path.node.id, obj)]));
path.scope.registerDeclaration(path);
}
return;
}
const entriesMap = new Map(entries);
path.scope.path.traverse({
Scope(path) {
if (path.scope.hasOwnBinding(name)) path.skip();
},
MemberExpression(path) {
if (!t.isIdentifier(path.node.object, {
name
})) return;
let key;
if (path.node.computed) {
if (t.isStringLiteral(path.node.property)) {
key = path.node.property.value;
} else {
return;
}
} else if (t.isIdentifier(path.node.property)) {
key = path.node.property.name;
} else {
return;
}
if (!entriesMap.has(key)) return;
path.replaceWith(t.cloneNode(entriesMap.get(key)));
}
});
path.remove();
}
const GLOBAL_TYPES = new WeakMap();
function isGlobalType({
scope
}, name) {
if (scope.hasBinding(name)) return false;
if (GLOBAL_TYPES.get(scope).has(name)) return true;
console.warn(`The exported identifier "${name}" is not declared in Babel's scope tracker\n` + `as a JavaScript value binding, and "@babel/plugin-transform-typescript"\n` + `never encountered it as a TypeScript type declaration.\n` + `It will be treated as a JavaScript value.\n\n` + `This problem is likely caused by another plugin injecting\n` + `"${name}" without registering it in the scope tracker. If you are the author\n` + ` of that plugin, please use "scope.registerDeclaration(declarationPath)".`);
return false;
}
function registerGlobalType(programScope, name) {
GLOBAL_TYPES.get(programScope).add(name);
}
function getFirstIdentifier(node) {
if (types.isIdentifier(node)) {
return node;
}
return getFirstIdentifier(node.left);
}
function transpileNamespace(path, allowNamespaces) {
if (path.node.declare || path.node.id.type === "StringLiteral") {
path.remove();
return;
}
if (!allowNamespaces) {
throw path.get("id").buildCodeFrameError("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 = getFirstIdentifier(path.node.id).name;
const value = handleNested(path, path.node);
if (value === null) {
const program = path.findParent(p => p.isProgram());
registerGlobalType(program.scope, name);
path.remove();
} else if (path.scope.hasOwnBinding(name)) {
path.replaceWith(value);
} else {
path.scope.registerDeclaration(path.replaceWithMultiple([getDeclaration(name), value])[0]);
}
}
function getDeclaration(name) {
return types.variableDeclaration("let", [types.variableDeclarator(types.identifier(name))]);
}
function getMemberExpression(name, itemName) {
return types.memberExpression(types.identifier(name), types.identifier(itemName));
}
function handleVariableDeclaration(node, name, hub) {
if (node.kind !== "const") {
throw hub.file.buildCodeFrameError(node, "Namespaces exporting non-const are not supported by Babel." + " Change to const or see:" + " https://babeljs.io/docs/en/babel-plugin-transform-typescript");
}
const {
declarations
} = node;
if (declarations.every(declarator => types.isIdentifier(declarator.id))) {
for (const declarator of declarations) {
declarator.init = types.assignmentExpression("=", getMemberExpression(name, declarator.id.name), declarator.init);
}
return [node];
}
const bindingIdentifiers = types.getBindingIdentifiers(node);
const assignments = [];
for (const idName in bindingIdentifiers) {
assignments.push(types.assignmentExpression("=", getMemberExpression(name, idName), types.cloneNode(bindingIdentifiers[idName])));
}
return [node, types.expressionStatement(types.sequenceExpression(assignments))];
}
function buildNestedAmbientModuleError(path, node) {
return path.hub.buildError(node, "Ambient modules cannot be nested in other modules or namespaces.", Error);
}
function handleNested(path, node, parentExport) {
const names = new Set();
const realName = types.isIdentifier(node.id) ? node.id : getFirstIdentifier(node.id);
const name = path.scope.generateUid(realName.name);
const body = node.body;
let id = node.id;
let namespaceTopLevel;
if (types.isTSQualifiedName(id)) {
namespaceTopLevel = body.body;
while (types.isTSQualifiedName(id)) {
namespaceTopLevel = [types.exportNamedDeclaration(types.tsModuleDeclaration(types.cloneNode(id.right), types.tsModuleBlock(namespaceTopLevel)))];
id = id.left;
}
} else {
namespaceTopLevel = body.body;
}
let isEmpty = true;
for (let i = 0; i < namespaceTopLevel.length; i++) {
const subNode = namespaceTopLevel[i];
switch (subNode.type) {
case "TSModuleDeclaration":
{
if (!types.isIdentifier(subNode.id)) {
throw buildNestedAmbientModuleError(path, subNode);
}
const transformed = handleNested(path, subNode);
if (transformed !== null) {
isEmpty = false;
const moduleName = subNode.id.name;
if (names.has(moduleName)) {
namespaceTopLevel[i] = transformed;
} else {
names.add(moduleName);
namespaceTopLevel.splice(i++, 1, getDeclaration(moduleName), transformed);
}
}
continue;
}
case "TSEnumDeclaration":
case "FunctionDeclaration":
case "ClassDeclaration":
isEmpty = false;
names.add(subNode.id.name);
continue;
case "VariableDeclaration":
{
isEmpty = false;
for (const name in types.getBindingIdentifiers(subNode)) {
names.add(name);
}
continue;
}
default:
isEmpty &&= types.isTypeScript(subNode);
continue;
case "ExportNamedDeclaration":
}
if ("declare" in subNode.declaration && subNode.declaration.declare) {
continue;
}
switch (subNode.declaration.type) {
case "TSEnumDeclaration":
EXPORTED_CONST_ENUMS_IN_NAMESPACE.add(subNode.declaration);
case "FunctionDeclaration":
case "ClassDeclaration":
{
isEmpty = false;
const itemName = subNode.declaration.id.name;
names.add(itemName);
namespaceTopLevel.splice(i++, 1, subNode.declaration, types.expressionStatement(types.assignmentExpression("=", getMemberExpression(name, itemName), types.identifier(itemName))));
break;
}
case "VariableDeclaration":
{
isEmpty = false;
const nodes = handleVariableDeclaration(subNode.declaration, name, path.hub);
namespaceTopLevel.splice(i, nodes.length, ...nodes);
i += nodes.length - 1;
break;
}
case "TSModuleDeclaration":
{
if (!types.isIdentifier(subNode.declaration.id)) {
throw buildNestedAmbientModuleError(path, subNode.declaration);
}
const transformed = handleNested(path, subNode.declaration, types.identifier(name));
if (transformed !== null) {
isEmpty = false;
const moduleName = subNode.declaration.id.name;
if (names.has(moduleName)) {
namespaceTopLevel[i] = transformed;
} else {
names.add(moduleName);
namespaceTopLevel.splice(i++, 1, getDeclaration(moduleName), transformed);
}
} else {
namespaceTopLevel.splice(i, 1);
i--;
}
}
}
}
if (isEmpty) return null;
let fallthroughValue = types.objectExpression([]);
if (parentExport) {
const memberExpr = types.memberExpression(parentExport, realName);
fallthroughValue = template.expression.ast`
${types.cloneNode(memberExpr)} ||
(${types.cloneNode(memberExpr)} = ${fallthroughValue})
`;
}
return template.statement.ast`
(function (${types.identifier(name)}) {
${namespaceTopLevel}
})(${realName} || (${types.cloneNode(realName)} = ${fallthroughValue}));
`;
}
function isInType(path) {
switch (path.parent.type) {
case "TSTypeReference":
case "TSClassImplements":
case "TSInterfaceHeritage":
case "TSTypeQuery":
return true;
case "TSQualifiedName":
return (path.parentPath.findParent(path => path.type !== "TSQualifiedName").type !== "TSImportEqualsDeclaration"
);
case "ExportSpecifier":
return (path.parent.exportKind === "type" || path.parentPath.parent.exportKind === "type"
);
default:
return false;
}
}
const NEEDS_EXPLICIT_ESM = new WeakMap();
const PARSED_PARAMS = new WeakSet();
function safeRemove(path) {
const ids = path.getBindingIdentifiers();
for (const name of Object.keys(ids)) {
const binding = path.scope.getBinding(name);
if (binding?.identifier === ids[name]) {
binding.scope.removeBinding(name);
}
}
path.opts.noScope = true;
path.remove();
path.opts.noScope = false;
}
function assertCjsTransformEnabled(path, pass, wrong, suggestion, extra = "") {
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.`);
}
}
const index = declare((api, opts) => {
const {
types: t,
template,
traverse
} = api;
api.assertVersion("^7.0.0-0 || ^8.0.0");
const JSX_PRAGMA_REGEX = /\*?\s*@jsx((?:Frag)?)\s+(\S+)/;
const {
allowNamespaces = true,
jsxPragma = "React.createElement",
jsxPragmaFrag = "React.Fragment",
onlyRemoveTypeImports = false,
optimizeConstEnums = false
} = opts;
const classMemberVisitors = {
field(path) {
const {
node
} = path;
if (node.declare) {
if (node.value) {
throw path.buildCodeFrameError(`Fields with the 'declare' modifier cannot be initialized here, but only in the constructor`);
}
if (!node.decorators) {
path.remove();
}
} else if (node.definite) {
if (node.value) {
throw path.buildCodeFrameError(`Definitely assigned fields cannot be initialized here, but only in the constructor`);
}
} else if (node.abstract) {
path.remove();
}
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.typeAnnotation) node.typeAnnotation = null;
if (node.definite) node.definite = null;
if (node.declare) node.declare = null;
if (node.override) node.override = null;
},
method({
node
}) {
if (node.accessibility) node.accessibility = null;
if (node.abstract) node.abstract = null;
if (node.optional) node.optional = null;
if (node.override) node.override = null;
},
constructor(path, classPath) {
if (path.node.accessibility) path.node.accessibility = null;
const assigns = [];
const {
scope
} = path;
for (const paramPath of path.get("params")) {
if (paramPath.isTSParameterProperty()) {
const param = paramPath.node;
const parameter = param.parameter;
if (PARSED_PARAMS.has(parameter)) continue;
PARSED_PARAMS.add(parameter);
let id;
if (t.isIdentifier(parameter)) {
id = parameter;
} else if (t.isAssignmentPattern(parameter) && t.isIdentifier(parameter.left)) {
id = parameter.left;
} else {
throw paramPath.buildCodeFrameError("Parameter properties can not be destructuring patterns.");
}
assigns.push(template.statement.ast`
this.${t.cloneNode(id)} = ${t.cloneNode(id)}
`);
paramPath.replaceWith(param.parameter);
scope.registerBinding("param", paramPath);
}
}
injectInitialization(classPath, path, assigns);
}
};
return {
name: "transform-typescript",
inherits: syntaxTypeScript,
visitor: traverse.explode({
Pattern: visitPattern,
Identifier: visitPattern,
RestElement: visitPattern,
Program: {
enter(path, state) {
const {
file
} = state;
let fileJsxPragma = null;
let fileJsxPragmaFrag = null;
const programScope = path.scope;
if (!GLOBAL_TYPES.has(programScope)) {
GLOBAL_TYPES.set(programScope, new Set());
}
if (file.ast.comments) {
for (const comment of file.ast.comments) {
const jsxMatches = JSX_PRAGMA_REGEX.exec(comment.value);
if (jsxMatches) {
if (jsxMatches[1]) {
fileJsxPragmaFrag = jsxMatches[2];
} else {
fileJsxPragma = jsxMatches[2];
}
}
}
}
let pragmaImportName = fileJsxPragma || jsxPragma;
if (pragmaImportName) {
[pragmaImportName] = pragmaImportName.split(".");
}
let pragmaFragImportName = fileJsxPragmaFrag || jsxPragmaFrag;
if (pragmaFragImportName) {
[pragmaFragImportName] = pragmaFragImportName.split(".");
}
for (let stmt of path.get("body")) {
if (stmt.isImportDeclaration()) {
if (!NEEDS_EXPLICIT_ESM.has(state.file.ast.program)) {
NEEDS_EXPLICIT_ESM.set(state.file.ast.program, true);
}
if (stmt.node.importKind === "type") {
for (const specifier of stmt.node.specifiers) {
registerGlobalType(programScope, specifier.local.name);
}
stmt.remove();
continue;
}
const importsToRemove = new Set();
const specifiersLength = stmt.node.specifiers.length;
const isAllSpecifiersElided = () => specifiersLength > 0 && specifiersLength === importsToRemove.size;
for (const specifier of stmt.node.specifiers) {
if (specifier.type === "ImportSpecifier" && specifier.importKind === "type") {
registerGlobalType(programScope, specifier.local.name);
const binding = stmt.scope.getBinding(specifier.local.name);
if (binding) {
importsToRemove.add(binding.path);
}
}
}
if (onlyRemoveTypeImports) {
NEEDS_EXPLICIT_ESM.set(path.node, false);
} else {
if (stmt.node.specifiers.length === 0) {
NEEDS_EXPLICIT_ESM.set(path.node, false);
continue;
}
for (const specifier of stmt.node.specifiers) {
const binding = stmt.scope.getBinding(specifier.local.name);
if (binding && !importsToRemove.has(binding.path)) {
if (isImportTypeOnly({
binding,
programPath: path,
pragmaImportName,
pragmaFragImportName
})) {
importsToRemove.add(binding.path);
} else {
NEEDS_EXPLICIT_ESM.set(path.node, false);
}
}
}
}
if (isAllSpecifiersElided() && !onlyRemoveTypeImports) {
stmt.remove();
} else {
for (const importPath of importsToRemove) {
importPath.remove();
}
}
continue;
}
if (!onlyRemoveTypeImports && stmt.isTSImportEqualsDeclaration()) {
const {
id
} = stmt.node;
const binding = stmt.scope.getBinding(id.name);
if (binding && isImportTypeOnly({
binding,
programPath: path,
pragmaImportName,
pragmaFragImportName
})) {
stmt.remove();
continue;
}
}
if (stmt.isExportDeclaration()) {
stmt = stmt.get("declaration");
}
if (stmt.isVariableDeclaration({
declare: true
})) {
for (const name of Object.keys(stmt.getBindingIdentifiers())) {
registerGlobalType(programScope, name);
}
} else if (stmt.isTSTypeAliasDeclaration() || stmt.isTSDeclareFunction() && stmt.get("id").isIdentifier() || stmt.isTSInterfaceDeclaration() || stmt.isClassDeclaration({
declare: true
}) || stmt.isTSEnumDeclaration({
declare: true
}) || stmt.isTSModuleDeclaration({
declare: true
}) && stmt.get("id").isIdentifier()) {
registerGlobalType(programScope, stmt.node.id.name);
}
}
},
exit(path) {
if (path.node.sourceType === "module" && NEEDS_EXPLICIT_ESM.get(path.node)) {
path.pushContainer("body", t.exportNamedDeclaration());
}
}
},
ExportNamedDeclaration(path, state) {
if (!NEEDS_EXPLICIT_ESM.has(state.file.ast.program)) {
NEEDS_EXPLICIT_ESM.set(state.file.ast.program, true);
}
if (path.node.exportKind === "type") {
path.remove();
return;
}
if (t.isTSImportEqualsDeclaration(path.node.declaration)) {
return;
}
if (path.node.source && path.node.specifiers.length > 0 && path.node.specifiers.every(specifier => specifier.type === "ExportSpecifier" && specifier.exportKind === "type")) {
path.remove();
return;
}
if (!path.node.source && path.node.specifiers.length > 0 && path.node.specifiers.every(specifier => t.isExportSpecifier(specifier) && isGlobalType(path, specifier.local.name))) {
path.remove();
return;
}
if (t.isTSModuleDeclaration(path.node.declaration)) {
const namespace = path.node.declaration;
if (!t.isStringLiteral(namespace.id)) {
const id = getFirstIdentifier(namespace.id);
if (path.scope.hasOwnBinding(id.name)) {
path.replaceWith(namespace);
} else {
const [newExport] = path.replaceWithMultiple([t.exportNamedDeclaration(t.variableDeclaration("let", [t.variableDeclarator(t.cloneNode(id))])), namespace]);
path.scope.registerDeclaration(newExport);
}
}
}
NEEDS_EXPLICIT_ESM.set(state.file.ast.program, false);
},
ExportAllDeclaration(path) {
if (path.node.exportKind === "type") path.remove();
},
ExportSpecifier(path) {
const parent = path.parent;
if (!parent.source && isGlobalType(path, path.node.local.name) || path.node.exportKind === "type") {
path.remove();
}
},
ExportDefaultDeclaration(path, state) {
if (!NEEDS_EXPLICIT_ESM.has(state.file.ast.program)) {
NEEDS_EXPLICIT_ESM.set(state.file.ast.program, true);
}
if (t.isIdentifier(path.node.declaration) && isGlobalType(path, path.node.declaration.name)) {
path.remove();
return;
}
NEEDS_EXPLICIT_ESM.set(state.file.ast.program, false);
},
TSDeclareFunction(path) {
safeRemove(path);
},
TSDeclareMethod(path) {
safeRemove(path);
},
VariableDeclaration(path) {
if (path.node.declare) {
safeRemove(path);
}
},
VariableDeclarator({
node
}) {
if (node.definite) node.definite = null;
},
TSIndexSignature(path) {
path.remove();
},
ClassDeclaration(path) {
const {
node
} = path;
if (node.declare) {
safeRemove(path);
}
},
Class(path) {
const {
node
} = path;
if (node.typeParameters) node.typeParameters = null;
if (node.superTypeArguments) node.superTypeArguments = null;
if (node.implements) node.implements = null;
if (node.abstract) node.abstract = null;
path.get("body.body").forEach(child => {
if (child.isClassMethod() || child.isClassPrivateMethod()) {
if (child.node.kind === "constructor") {
classMemberVisitors.constructor(child, path);
} else {
classMemberVisitors.method(child);
}
} else if (child.isClassProperty() || child.isClassPrivateProperty() || child.isClassAccessorProperty()) {
classMemberVisitors.field(child);
}
});
},
Function(path) {
const {
node
} = path;
if (node.typeParameters) node.typeParameters = null;
if (node.returnType) node.returnType = null;
const params = node.params;
if (params.length > 0 && t.isIdentifier(params[0], {
name: "this"
})) {
params.shift();
}
},
TSModuleDeclaration(path) {
transpileNamespace(path, allowNamespaces);
},
TSInterfaceDeclaration(path) {
path.remove();
},
TSTypeAliasDeclaration(path) {
path.remove();
},
TSEnumDeclaration(path) {
if (optimizeConstEnums && path.node.const) {
transpileConstEnum(path, t);
} else {
transpileEnum(path, t);
}
},
TSImportEqualsDeclaration(path, pass) {
const {
id,
moduleReference
} = path.node;
let init;
let varKind;
if (t.isTSExternalModuleReference(moduleReference)) {
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 {
init = entityNameToExpr(moduleReference);
varKind = "var";
}
const newNode = t.variableDeclaration(varKind, [t.variableDeclarator(id, init)]);
path.replaceWith(newNode);
path.scope.registerDeclaration(path);
},
TSExportAssignment(path, pass) {
assertCjsTransformEnabled(path, pass, `export = <value>;`, `export default <value>;`);
path.replaceWith(template.statement.ast`module.exports = ${path.node.expression}`);
},
TSTypeAssertion(path) {
path.replaceWith(path.node.expression);
},
["TSAsExpression|TSSatisfiesExpression"](path) {
let {
node
} = path;
do {
node = node.expression;
} while (t.isTSAsExpression(node) || t.isTSSatisfiesExpression(node));
path.replaceWith(node);
},
["TSNonNullExpression|TSInstantiationExpression"](path) {
path.replaceWith(path.node.expression);
},
CallExpression(path) {
path.node.typeArguments = null;
},
OptionalCallExpression(path) {
path.node.typeArguments = null;
},
NewExpression(path) {
path.node.typeArguments = null;
},
JSXOpeningElement(path) {
path.node.typeArguments = null;
},
TaggedTemplateExpression(path) {
path.node.typeArguments = null;
}
})
};
function entityNameToExpr(node) {
if (t.isTSQualifiedName(node)) {
return t.memberExpression(entityNameToExpr(node.left), node.right);
}
return node;
}
function visitPattern({
node
}) {
if (node.typeAnnotation) node.typeAnnotation = null;
if (t.isIdentifier(node) && node.optional) node.optional = null;
}
function isImportTypeOnly({
binding,
programPath,
pragmaImportName,
pragmaFragImportName
}) {
for (const path of binding.referencePaths) {
if (!isInType(path)) {
return false;
}
}
if (binding.identifier.name !== pragmaImportName && binding.identifier.name !== pragmaFragImportName) {
return true;
}
const sourceFileHasJsx = t.traverseFast(programPath.node, node => {
if (t.isJSXElement(node) || t.isJSXFragment(node)) {
return t.traverseFast.stop;
}
});
return !sourceFileHasJsx;
}
});
export { index as default };
//# sourceMappingURL=index.js.map