mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(language-service): Allow auto-imports to suggest multiple possible imports. (#47787)
This change allows the language service to suggest imports for *all* directives returned from the compiler, and for *all* import specifiers for each directive. The first change has immediate effect, since there could already be multiple directives with the same selector. The second change is future-proofing; the compiler currently only returns a single best specifier, but will return more in the future. PR Close #47787
This commit is contained in:
committed by
Pawel Kozlowski
parent
d436a19555
commit
5f0b53c735
@@ -39,6 +39,8 @@ export const missingImportMeta: CodeActionMeta = {
|
||||
function getCodeActions(
|
||||
{templateInfo, start, compiler, formatOptions, preferences, errorCode, tsLs}:
|
||||
CodeActionContext) {
|
||||
let codeActions: ts.CodeFixAction[] = [];
|
||||
|
||||
const checker = compiler.getTemplateTypeChecker();
|
||||
const tsChecker = compiler.programDriver.getProgram().getTypeChecker();
|
||||
|
||||
@@ -64,46 +66,45 @@ function getCodeActions(
|
||||
}
|
||||
const importOn = owningNgModule ?? templateInfo.component;
|
||||
|
||||
// Find all possible importable directives with a matching selector, and take one of them.
|
||||
// In the future, we could handle multiple matches as additional quick fixes.
|
||||
// Find all possible importable directives with a matching selector.
|
||||
const allPossibleDirectives = checker.getPotentialTemplateDirectives(templateInfo.component);
|
||||
const matchingDirectives =
|
||||
getDirectiveMatchesForElementTag(missingElement, allPossibleDirectives);
|
||||
if (matchingDirectives.size === 0) {
|
||||
return [];
|
||||
}
|
||||
const bestMatch: PotentialDirective = matchingDirectives.values().next().value;
|
||||
const bestMatchSymbol = bestMatch.tsSymbol.valueDeclaration;
|
||||
const matches = matchingDirectives.values();
|
||||
|
||||
// Get possible trait imports corresponding to the recommended directive. Only use the
|
||||
// compiler's best import; in the future, we could suggest multiple imports if they exist.
|
||||
const potentialImports = checker.getPotentialImportsFor(bestMatch, importOn);
|
||||
if (potentialImports.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const potentialImport = potentialImports[0];
|
||||
// Generate suggestions for each possible match.
|
||||
for (let currMatch of matches) {
|
||||
const currMatchSymbol = currMatch.tsSymbol.valueDeclaration;
|
||||
|
||||
// Update the imports on the TypeScript file and Angular decorator.
|
||||
let [fileImportChanges, importName] = updateImportsForTypescriptFile(
|
||||
tsChecker, importOn.getSourceFile(), potentialImport, bestMatchSymbol.getSourceFile());
|
||||
let traitImportChanges = updateImportsForAngularTrait(checker, importOn, importName);
|
||||
// Get possible trait imports corresponding to the recommended directive.
|
||||
const potentialImports = checker.getPotentialImportsFor(currMatch, importOn);
|
||||
|
||||
// All quick fixes should always update the trait import; however, the TypeScript import might
|
||||
// already be present.
|
||||
if (traitImportChanges.length === 0) {
|
||||
return [];
|
||||
// For each possible import specifier, create a suggestion.
|
||||
for (let potentialImport of potentialImports) {
|
||||
// Update the imports on the TypeScript file and Angular decorator.
|
||||
let [fileImportChanges, importName] = updateImportsForTypescriptFile(
|
||||
tsChecker, importOn.getSourceFile(), potentialImport, currMatchSymbol.getSourceFile());
|
||||
let traitImportChanges = updateImportsForAngularTrait(checker, importOn, importName);
|
||||
|
||||
// All quick fixes should always update the trait import; however, the TypeScript import might
|
||||
// already be present.
|
||||
if (traitImportChanges.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create a code action for this import.
|
||||
codeActions.push({
|
||||
fixName: FixIdForCodeFixesAll.FIX_MISSING_IMPORT,
|
||||
description: `Import ${importName} from '${potentialImport.moduleSpecifier}' on ${
|
||||
importOn.name!.text}`,
|
||||
changes: [{
|
||||
fileName: importOn.getSourceFile().fileName,
|
||||
textChanges: [...fileImportChanges, ...traitImportChanges],
|
||||
}]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Create the code action to insert the new imports.
|
||||
const codeActions: ts.CodeFixAction[] = [{
|
||||
fixName: FixIdForCodeFixesAll.FIX_MISSING_IMPORT,
|
||||
description:
|
||||
`Import ${importName} from '${potentialImport.moduleSpecifier}' on ${importOn.name!.text}`,
|
||||
changes: [{
|
||||
fileName: importOn.getSourceFile().fileName,
|
||||
textChanges: [...fileImportChanges, ...traitImportChanges],
|
||||
}],
|
||||
}];
|
||||
return codeActions;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user