Skip to content

Commit cdfd92b

Browse files
author
Andy
authored
Don't add import completion from a re-export in "./index" (microsoft#23623)
* Don't add import completion from a re-export in "./index" * Simpler heuristic
1 parent 4a379d6 commit cdfd92b

File tree

2 files changed

+35
-3
lines changed

2 files changed

+35
-3
lines changed

src/services/codefixes/importFixes.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,21 @@ namespace ts.codefix {
9898
symbolToken: Node | undefined,
9999
preferences: UserPreferences,
100100
): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } {
101-
const exportInfos = getAllReExportingModules(exportedSymbol, symbolName, checker, allSourceFiles);
101+
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, checker, allSourceFiles);
102102
Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol));
103103
// We sort the best codefixes first, so taking `first` is best for completions.
104104
const moduleSpecifier = first(getNewImportInfos(program, sourceFile, exportInfos, compilerOptions, getCanonicalFileName, host, preferences)).moduleSpecifier;
105105
const ctx: ImportCodeFixContext = { host, program, checker, compilerOptions, sourceFile, formatContext, symbolName, getCanonicalFileName, symbolToken, preferences };
106106
return { moduleSpecifier, codeAction: first(getCodeActionsForImport(exportInfos, ctx)) };
107107
}
108-
function getAllReExportingModules(exportedSymbol: Symbol, symbolName: string, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
108+
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
109109
const result: SymbolExportInfo[] = [];
110-
forEachExternalModule(checker, allSourceFiles, moduleSymbol => {
110+
forEachExternalModule(checker, allSourceFiles, (moduleSymbol, moduleFile) => {
111+
// Don't import from a re-export when looking "up" like to `./index` or `../index`.
112+
if (moduleFile && moduleSymbol !== exportingModuleSymbol && startsWith(sourceFile.fileName, getDirectoryPath(moduleFile.fileName))) {
113+
return;
114+
}
115+
111116
for (const exported of checker.getExportsOfModule(moduleSymbol)) {
112117
if (exported.escapedName === InternalSymbolName.Default || exported.name === symbolName && skipAlias(exported, checker) === exportedSymbol) {
113118
const isDefaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol) === exported;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @Filename: /src/a.ts
4+
////export const x = 0;
5+
6+
// @Filename: /src/index.ts
7+
////export { x } from "./a";
8+
9+
// @Filename: /0.ts
10+
////x/*0*/
11+
12+
// @Filename: /src/1.ts
13+
////x/*1*/
14+
15+
// @Filename: /src/inner/2.ts
16+
////x/*2*/
17+
18+
for (const [marker, sourceDisplay] of [["0", "./src"], ["1", "./a"], ["2", "../a"]]) {
19+
goTo.marker(marker);
20+
verify.completionListContains({ name: "x", source: "/src/a" }, "const x: 0", "", "const", /*spanIndex*/ undefined, /*hasAction*/ true, { includeCompletionsForModuleExports: true, sourceDisplay });
21+
verify.applyCodeActionFromCompletion(marker, {
22+
name: "x",
23+
source: "/src/a",
24+
description: `Import 'x' from module "${sourceDisplay}"`,
25+
newFileContent: `import { x } from "${sourceDisplay}";\n\nx`,
26+
});
27+
}

0 commit comments

Comments
 (0)