diff --git a/packages/core/schematics/utils/typescript/imports.ts b/packages/core/schematics/utils/typescript/imports.ts index 75fd966821f..a10c9cfd61f 100644 --- a/packages/core/schematics/utils/typescript/imports.ts +++ b/packages/core/schematics/utils/typescript/imports.ts @@ -67,28 +67,40 @@ export function getImportSpecifier( moduleName: string | RegExp, specifierName: string, ): ts.ImportSpecifier | null { - return getImportSpecifiers(sourceFile, moduleName, [specifierName])[0] ?? null; + return getImportSpecifiers(sourceFile, moduleName, specifierName)[0] ?? null; } export function getImportSpecifiers( sourceFile: ts.SourceFile, moduleName: string | RegExp, - specifierNames: string[], + specifierOrSpecifiers: string | string[], ): ts.ImportSpecifier[] { const matches: ts.ImportSpecifier[] = []; for (const node of sourceFile.statements) { - if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) { - const isMatch = - typeof moduleName === 'string' - ? node.moduleSpecifier.text === moduleName - : moduleName.test(node.moduleSpecifier.text); - const namedBindings = node.importClause?.namedBindings; - if (isMatch && namedBindings && ts.isNamedImports(namedBindings)) { - for (const specifierName of specifierNames) { - const match = findImportSpecifier(namedBindings.elements, specifierName); - if (match) { - matches.push(match); - } + if (!ts.isImportDeclaration(node) || !ts.isStringLiteral(node.moduleSpecifier)) { + continue; + } + + const namedBindings = node.importClause?.namedBindings; + const isMatch = + typeof moduleName === 'string' + ? node.moduleSpecifier.text === moduleName + : moduleName.test(node.moduleSpecifier.text); + + if (!isMatch || !namedBindings || !ts.isNamedImports(namedBindings)) { + continue; + } + + if (typeof specifierOrSpecifiers === 'string') { + const match = findImportSpecifier(namedBindings.elements, specifierOrSpecifiers); + if (match) { + matches.push(match); + } + } else { + for (const specifierName of specifierOrSpecifiers) { + const match = findImportSpecifier(namedBindings.elements, specifierName); + if (match) { + matches.push(match); } } } diff --git a/packages/core/schematics/utils/typescript/symbol.ts b/packages/core/schematics/utils/typescript/symbol.ts index 82228e92697..c497f6c972a 100644 --- a/packages/core/schematics/utils/typescript/symbol.ts +++ b/packages/core/schematics/utils/typescript/symbol.ts @@ -27,6 +27,13 @@ export function isReferenceToImport( node: ts.Node, importSpecifier: ts.ImportSpecifier, ): boolean { + // If this function is called on an identifier (should be most cases), we can quickly rule out + // non-matches by comparing the identifier's string and the local name of the import specifier + // which saves us some calls to the type checker. + if (ts.isIdentifier(node) && node.text !== importSpecifier.name.text) { + return false; + } + const nodeSymbol = typeChecker.getTypeAtLocation(node).getSymbol(); const importSymbol = typeChecker.getTypeAtLocation(importSpecifier).getSymbol(); return (