mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-12 20:25:48 -06:00
Fix auto import completion inserting wrong module specifier (#41955)
* Don’t look for reëxports when import source was an ambient module * Add additional assertion for clarity
This commit is contained in:
parent
e84a95f707
commit
487be36919
@ -2798,7 +2798,12 @@ namespace FourSlash {
|
||||
|
||||
const details = this.getCompletionEntryDetails(options.name, options.source, options.preferences);
|
||||
if (!details) {
|
||||
return this.raiseError(`No completions were found for the given name, source, and preferences.`);
|
||||
const completions = this.getCompletionListAtCaret(options.preferences)?.entries;
|
||||
const matchingName = completions?.filter(e => e.name === options.name);
|
||||
const detailMessage = matchingName?.length
|
||||
? `\n Found ${matchingName.length} with name '${options.name}' from source(s) ${matchingName.map(e => `'${e.source}'`).join(", ")}.`
|
||||
: "";
|
||||
return this.raiseError(`No completions were found for the given name, source, and preferences.` + detailMessage);
|
||||
}
|
||||
const codeActions = details.codeActions;
|
||||
if (codeActions?.length !== 1) {
|
||||
|
||||
@ -210,7 +210,9 @@ namespace ts.codefix {
|
||||
preferences: UserPreferences,
|
||||
): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const exportInfos = getAllReExportingModules(sourceFile, exportedSymbol, moduleSymbol, symbolName, host, program, /*useAutoImportProvider*/ true);
|
||||
const exportInfos = pathIsBareSpecifier(stripQuotes(moduleSymbol.name))
|
||||
? [getSymbolExportInfoForSymbol(exportedSymbol, moduleSymbol, sourceFile, program, host)]
|
||||
: getAllReExportingModules(sourceFile, exportedSymbol, moduleSymbol, symbolName, host, program, /*useAutoImportProvider*/ true);
|
||||
const useRequire = shouldUseRequire(sourceFile, program);
|
||||
const preferTypeOnlyImport = compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error && !isSourceFileJS(sourceFile) && isValidTypeOnlyAliasUseSite(getTokenAtPosition(sourceFile, position));
|
||||
const moduleSpecifier = first(getNewImportInfos(program, sourceFile, position, preferTypeOnlyImport, useRequire, exportInfos, host, preferences)).moduleSpecifier;
|
||||
@ -228,6 +230,27 @@ namespace ts.codefix {
|
||||
return { description, changes, commands };
|
||||
}
|
||||
|
||||
function getSymbolExportInfoForSymbol(symbol: Symbol, moduleSymbol: Symbol, importingFile: SourceFile, program: Program, host: LanguageServiceHost): SymbolExportInfo {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const mainProgramInfo = getInfoWithChecker(program.getTypeChecker());
|
||||
if (mainProgramInfo) {
|
||||
return mainProgramInfo;
|
||||
}
|
||||
const autoImportProvider = host.getPackageJsonAutoImportProvider?.()?.getTypeChecker();
|
||||
return Debug.checkDefined(autoImportProvider && getInfoWithChecker(autoImportProvider), `Could not find symbol in specified module for code actions`);
|
||||
|
||||
function getInfoWithChecker(checker: TypeChecker): SymbolExportInfo | undefined {
|
||||
const defaultInfo = getDefaultLikeExportInfo(importingFile, moduleSymbol, checker, compilerOptions);
|
||||
if (defaultInfo && skipAlias(defaultInfo.symbol, checker) === symbol) {
|
||||
return { moduleSymbol, importKind: defaultInfo.kind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(symbol, checker) };
|
||||
}
|
||||
const named = checker.tryGetMemberInModuleExportsAndProperties(symbol.name, moduleSymbol);
|
||||
if (named && skipAlias(named, checker) === symbol) {
|
||||
return { moduleSymbol, importKind: ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(symbol, checker) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getAllReExportingModules(importingFile: SourceFile, exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, host: LanguageServiceHost, program: Program, useAutoImportProvider: boolean): readonly SymbolExportInfo[] {
|
||||
const result: SymbolExportInfo[] = [];
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
|
||||
57
tests/cases/fourslash/completionsImport_ambient.ts
Normal file
57
tests/cases/fourslash/completionsImport_ambient.ts
Normal file
@ -0,0 +1,57 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: commonjs
|
||||
|
||||
// @Filename: a.d.ts
|
||||
//// declare namespace foo { class Bar {} }
|
||||
//// declare module 'path1' {
|
||||
//// import Bar = foo.Bar;
|
||||
//// export default Bar;
|
||||
//// }
|
||||
//// declare module 'path2longer' {
|
||||
//// import Bar = foo.Bar;
|
||||
//// export {Bar};
|
||||
//// }
|
||||
////
|
||||
|
||||
// @Filename: b.ts
|
||||
//// Ba/**/
|
||||
|
||||
verify.completions({
|
||||
marker: "",
|
||||
exact: [
|
||||
completion.globalThisEntry,
|
||||
...completion.globalsVars,
|
||||
{
|
||||
name: "foo",
|
||||
sortText: completion.SortText.GlobalsOrKeywords
|
||||
},
|
||||
completion.undefinedVarEntry,
|
||||
{
|
||||
name: "Bar",
|
||||
source: "path1",
|
||||
hasAction: true,
|
||||
sortText: completion.SortText.AutoImportSuggestions
|
||||
},
|
||||
{
|
||||
name: "Bar",
|
||||
source: "path2longer",
|
||||
hasAction: true,
|
||||
sortText: completion.SortText.AutoImportSuggestions
|
||||
},
|
||||
...completion.statementKeywordsWithTypes
|
||||
],
|
||||
preferences: {
|
||||
includeCompletionsForModuleExports: true
|
||||
}
|
||||
});
|
||||
|
||||
verify.applyCodeActionFromCompletion("", {
|
||||
name: "Bar",
|
||||
source: "path2longer",
|
||||
description: `Import 'Bar' from module "path2longer"`,
|
||||
newFileContent: `import { Bar } from "path2longer";\n\nBa`,
|
||||
preferences: {
|
||||
includeCompletionsForModuleExports: true
|
||||
}
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user