diff --git a/src/services/exportInfoMap.ts b/src/services/exportInfoMap.ts index 78c20881cae3d..44aa456b5a85e 100644 --- a/src/services/exportInfoMap.ts +++ b/src/services/exportInfoMap.ts @@ -327,7 +327,9 @@ namespace ts { const seenExports = new Map(); const checker = program.getTypeChecker(); const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); - if (defaultInfo && !checker.isUndefinedSymbol(defaultInfo.symbol)) { + // Note: I think we shouldn't actually see resolved module symbols here, but weird merges + // can cause it to happen: see 'completionsImport_mergedReExport.ts' + if (defaultInfo && !checker.isUndefinedSymbol(defaultInfo.symbol) && !isExternalModuleSymbol(defaultInfo.symbol)) { cache.add( importingFile.path, defaultInfo.symbol, @@ -339,7 +341,7 @@ namespace ts { checker); } for (const exported of checker.getExportsAndPropertiesOfModule(moduleSymbol)) { - if (exported !== defaultInfo?.symbol && addToSeen(seenExports, exported)) { + if (exported !== defaultInfo?.symbol && !isKnownSymbol(exported) && !isExternalModuleSymbol(exported) && addToSeen(seenExports, exported)) { cache.add( importingFile.path, exported, diff --git a/tests/cases/fourslash/server/completionsImport_computedSymbolName.ts b/tests/cases/fourslash/server/completionsImport_computedSymbolName.ts new file mode 100644 index 0000000000000..92ac904c46b1c --- /dev/null +++ b/tests/cases/fourslash/server/completionsImport_computedSymbolName.ts @@ -0,0 +1,48 @@ +/// + +// @Filename: /tsconfig.json +//// { "compilerOptions": { "module": "commonjs" } } + +// @Filename: /node_modules/@types/ts-node/index.d.ts +//// export {}; +//// declare const REGISTER_INSTANCE: unique symbol; +//// declare global { +//// namespace NodeJS { +//// interface Process { +//// [REGISTER_INSTANCE]?: Service; +//// } +//// } +//// } + +// @Filename: /node_modules/@types/node/index.d.ts +//// declare module "process" { +//// global { +//// var process: NodeJS.Process; +//// namespace NodeJS { +//// interface Process { +//// argv: string[]; +//// } +//// } +//// } +//// export = process; +//// } + +// @Filename: /index.ts +//// I/**/ + +verify.completions({ + marker: "", + preferences: { + includeCompletionsForModuleExports: true, + }, +}); + +edit.insert("N"); + +// Should not crash +verify.completions({ + marker: "", + preferences: { + includeCompletionsForModuleExports: true, + }, +}); diff --git a/tests/cases/fourslash/server/completionsImport_mergedReExport.ts b/tests/cases/fourslash/server/completionsImport_mergedReExport.ts new file mode 100644 index 0000000000000..5ca30b36f0a23 --- /dev/null +++ b/tests/cases/fourslash/server/completionsImport_mergedReExport.ts @@ -0,0 +1,55 @@ +/// + +// @Filename: /tsconfig.json +//// { "compilerOptions": { "module": "commonjs" } } + +// @Filename: /package.json +//// { "dependencies": { "@jest/types": "*", "ts-jest": "*" } } + +// @Filename: /node_modules/@jest/types/index.d.ts +//// import type * as Config from "./Config"; +//// export type { Config }; + +// @Filename: /node_modules/@jest/types/Config.d.ts +//// export interface ConfigGlobals { +//// [K: string]: unknown; +//// } + +// @Filename: /node_modules/ts-jest/index.d.ts +//// export {}; +//// declare module "@jest/types" { +//// namespace Config { +//// interface ConfigGlobals { +//// 'ts-jest': any; +//// } +//// } +//// } + +// @Filename: /index.ts +//// C/**/ + +verify.completions({ + marker: "", + preferences: { + includeCompletionsForModuleExports: true, + }, +}); + +edit.insert("o"); + +// Should not crash +verify.completions({ + marker: "", + preferences: { + includeCompletionsForModuleExports: true, + }, +}); + +// Because of the way `Config` is merged, we are actually not including it +// in completions here, though it would be better if we could. The `exports` +// of "@jest/types/index" would contain an alias symbol named `Config` without +// the merge from ts-jest, but with the merge, the `exports` contains the merge +// of `namespace Config` and the "@jest/types/Config" module symbol. This is +// unexpected (to me) and difficult to work with, and might be wrong? My +// expectation would have been to preserve the export alias symbol, but let it +// *resolve* to the merge of the SourceFile and the namespace declaration.