in src/transforms/deprecated-remover.ts [673:762]
private visitor<T extends ts.Node>(node: T): ts.VisitResult<T> {
if (this.isDeprecated(node)) {
// Removing deprecated members by substituting "nothing" to them
return [];
}
if (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) {
for (const transformation of this.transformations) {
// 👇 as any because the assignment below confuses type checker
if (transformation.targets(node as any)) {
const { node: transformedNode, syntheticImport } = transformation.apply(node);
node = transformedNode as any;
if (syntheticImport) {
this.syntheticImports.push(syntheticImport);
}
}
}
}
// Remove named imports of `@deprecated` members from the source...
if (
ts.isImportDeclaration(node) &&
node.importClause &&
node.importClause.namedBindings &&
ts.isNamedImports(node.importClause.namedBindings)
) {
const filteredElements = node.importClause.namedBindings.elements.filter((element) => {
// This symbol is local (it's declaration points back to the named import)
const symbol = this.typeChecker.getSymbolAtLocation(element.name);
const exportedSymbol =
// This "resolves" the imported type, so we can get to it's declaration(s)
symbol && this.typeChecker.getDeclaredTypeOfSymbol(symbol)?.symbol;
return !exportedSymbol?.declarations?.some((decl) => this.isDeprecated(decl));
});
if (filteredElements.length !== node.importClause.namedBindings.elements.length) {
return this.context.factory.updateImportDeclaration(
node,
node.modifiers,
node.importClause.name != null || filteredElements.length > 0
? this.context.factory.updateImportClause(
node.importClause,
node.importClause.isTypeOnly,
node.importClause.name,
this.context.factory.updateNamedImports(node.importClause.namedBindings, filteredElements),
)
: undefined,
node.moduleSpecifier,
node.assertClause,
) as any;
}
return node;
}
// Replace "export ... from ..." places that no longer export anything
// with an "import from ...", so side effects are preserved.
if (ts.isExportDeclaration(node) && node.moduleSpecifier) {
const symbol = this.typeChecker.getSymbolAtLocation(node.moduleSpecifier);
const moduleExports =
symbol &&
this.typeChecker
.getExportsOfModule(symbol)
?.filter((sym) => !sym.declarations?.some((decl) => this.isDeprecated(decl)));
if ((node.exportClause == null || ts.isNamespaceExport(node.exportClause)) && moduleExports?.length === 0) {
return this.context.factory.createImportDeclaration(
undefined /* modifiers */,
undefined /* importClause */,
node.moduleSpecifier,
) as any;
}
if (node.exportClause != null && moduleExports) {
const namedExports = node.exportClause as ts.NamedExports;
const exportedNames = new Set(moduleExports.map((sym) => sym.name));
const filteredElements = namedExports.elements?.filter((elt) => exportedNames.has(elt.name.text));
if (filteredElements?.length !== namedExports.elements?.length) {
return this.context.factory.updateExportDeclaration(
node,
node.modifiers,
node.isTypeOnly,
this.context.factory.updateNamedExports(namedExports, filteredElements),
node.moduleSpecifier,
node.assertClause,
) as any;
}
}
}
return DeprecationRemovalTransformer.IGNORE_CHILDREN.has(node.kind) ? node : this.visitEachChild(node);
}