@@ -74,23 +74,23 @@ namespace ts.Completions {
7474
7575 interface SymbolOriginInfo {
7676 kind : SymbolOriginInfoKind ;
77- symbolName ?: string ;
78- moduleSymbol ?: Symbol ;
7977 isDefaultExport ?: boolean ;
8078 isFromPackageJson ?: boolean ;
81- exportName ?: string ;
8279 fileName ?: string ;
83- moduleSpecifier ?: string ;
8480 }
8581
8682 interface SymbolOriginInfoExport extends SymbolOriginInfo {
8783 symbolName : string ;
8884 moduleSymbol : Symbol ;
8985 isDefaultExport : boolean ;
9086 exportName : string ;
87+ exportMapKey : string ;
9188 }
9289
93- interface SymbolOriginInfoResolvedExport extends SymbolOriginInfoExport {
90+ interface SymbolOriginInfoResolvedExport extends SymbolOriginInfo {
91+ symbolName : string ;
92+ moduleSymbol : Symbol ;
93+ exportName : string ;
9494 moduleSpecifier : string ;
9595 }
9696
@@ -294,6 +294,10 @@ namespace ts.Completions {
294294 }
295295 }
296296
297+ function completionEntryDataIsResolved ( data : CompletionEntryDataAutoImport | undefined ) : data is CompletionEntryDataResolved {
298+ return ! ! data ?. moduleSpecifier ;
299+ }
300+
297301 function continuePreviousIncompleteResponse (
298302 cache : IncompleteCompletionsCache ,
299303 file : SourceFile ,
@@ -308,9 +312,6 @@ namespace ts.Completions {
308312
309313 const lowerCaseTokenText = location . text . toLowerCase ( ) ;
310314 const exportMap = getExportInfoMap ( file , host , program , cancellationToken ) ;
311- const checker = program . getTypeChecker ( ) ;
312- const autoImportProvider = host . getPackageJsonAutoImportProvider ?.( ) ;
313- const autoImportProviderChecker = autoImportProvider ?. getTypeChecker ( ) ;
314315 const newEntries = resolvingModuleSpecifiers (
315316 "continuePreviousIncompleteResponse" ,
316317 host ,
@@ -320,7 +321,7 @@ namespace ts.Completions {
320321 /*isForImportStatementCompletion*/ false ,
321322 context => {
322323 const entries = mapDefined ( previousResponse . entries , entry => {
323- if ( ! entry . hasAction || ! entry . source || ! entry . data || entry . data . moduleSpecifier ) {
324+ if ( ! entry . hasAction || ! entry . source || ! entry . data || completionEntryDataIsResolved ( entry . data ) ) {
324325 // Not an auto import or already resolved; keep as is
325326 return entry ;
326327 }
@@ -329,13 +330,8 @@ namespace ts.Completions {
329330 return undefined ;
330331 }
331332
332- const { symbol, origin } = Debug . checkDefined ( getAutoImportSymbolFromCompletionEntryData ( entry . name , entry . data , program , host ) ) ;
333- const info = exportMap . get (
334- file . path ,
335- entry . name ,
336- symbol ,
337- origin . moduleSymbol . name ,
338- origin . isFromPackageJson ? autoImportProviderChecker ! : checker ) ;
333+ const { origin } = Debug . checkDefined ( getAutoImportSymbolFromCompletionEntryData ( entry . name , entry . data , program , host ) ) ;
334+ const info = exportMap . get ( file . path , entry . data . exportMapKey ) ;
339335
340336 const result = info && context . tryResolve ( info , ! isExternalModuleNameRelative ( stripQuotes ( origin . moduleSymbol . name ) ) ) ;
341337 if ( ! result ) return entry ;
@@ -760,14 +756,56 @@ namespace ts.Completions {
760756 return text . replace ( / \$ / gm, "\\$" ) ;
761757 }
762758
763- function originToCompletionEntryData ( origin : SymbolOriginInfoExport ) : CompletionEntryData | undefined {
764- return {
759+ function originToCompletionEntryData ( origin : SymbolOriginInfoExport | SymbolOriginInfoResolvedExport ) : CompletionEntryData | undefined {
760+ const ambientModuleName = origin . fileName ? undefined : stripQuotes ( origin . moduleSymbol . name ) ;
761+ const isPackageJsonImport = origin . isFromPackageJson ? true : undefined ;
762+ if ( originIsResolvedExport ( origin ) ) {
763+ const resolvedData : CompletionEntryDataResolved = {
764+ exportName : origin . exportName ,
765+ moduleSpecifier : origin . moduleSpecifier ,
766+ ambientModuleName,
767+ fileName : origin . fileName ,
768+ isPackageJsonImport,
769+ } ;
770+ return resolvedData ;
771+ }
772+ const unresolvedData : CompletionEntryDataUnresolved = {
765773 exportName : origin . exportName ,
774+ exportMapKey : origin . exportMapKey ,
766775 fileName : origin . fileName ,
767776 ambientModuleName : origin . fileName ? undefined : stripQuotes ( origin . moduleSymbol . name ) ,
768777 isPackageJsonImport : origin . isFromPackageJson ? true : undefined ,
769- moduleSpecifier : originIsResolvedExport ( origin ) ? origin . moduleSpecifier : undefined ,
770778 } ;
779+ return unresolvedData ;
780+ }
781+
782+ function completionEntryDataToSymbolOriginInfo ( data : CompletionEntryData , completionName : string , moduleSymbol : Symbol ) : SymbolOriginInfoExport | SymbolOriginInfoResolvedExport {
783+ const isDefaultExport = data . exportName === InternalSymbolName . Default ;
784+ const isFromPackageJson = ! ! data . isPackageJsonImport ;
785+ if ( completionEntryDataIsResolved ( data ) ) {
786+ const resolvedOrigin : SymbolOriginInfoResolvedExport = {
787+ kind : SymbolOriginInfoKind . ResolvedExport ,
788+ exportName : data . exportName ,
789+ moduleSpecifier : data . moduleSpecifier ,
790+ symbolName : completionName ,
791+ fileName : data . fileName ,
792+ moduleSymbol,
793+ isDefaultExport,
794+ isFromPackageJson,
795+ } ;
796+ return resolvedOrigin ;
797+ }
798+ const unresolvedOrigin : SymbolOriginInfoExport = {
799+ kind : SymbolOriginInfoKind . Export ,
800+ exportName : data . exportName ,
801+ exportMapKey : data . exportMapKey ,
802+ symbolName : completionName ,
803+ fileName : data . fileName ,
804+ moduleSymbol,
805+ isDefaultExport,
806+ isFromPackageJson,
807+ } ;
808+ return unresolvedOrigin ;
771809 }
772810
773811 function getInsertTextAndReplacementSpanForImportCompletion ( name : string , importCompletionNode : Node , contextToken : Node | undefined , origin : SymbolOriginInfoResolvedExport , useSemicolons : boolean , options : CompilerOptions , preferences : UserPreferences ) {
@@ -1762,19 +1800,35 @@ namespace ts.Completions {
17621800 const index = symbols . length ;
17631801 symbols . push ( firstAccessibleSymbol ) ;
17641802 const moduleSymbol = firstAccessibleSymbol . parent ;
1765- if ( ! moduleSymbol || ! isExternalModuleSymbol ( moduleSymbol ) ) {
1803+ if ( ! moduleSymbol ||
1804+ ! isExternalModuleSymbol ( moduleSymbol ) ||
1805+ typeChecker . tryGetMemberInModuleExportsAndProperties ( firstAccessibleSymbol . name , moduleSymbol ) !== firstAccessibleSymbol
1806+ ) {
17661807 symbolToOriginInfoMap [ index ] = { kind : getNullableSymbolOriginInfoKind ( SymbolOriginInfoKind . SymbolMemberNoExport ) } ;
17671808 }
17681809 else {
1769- const origin : SymbolOriginInfoExport = {
1770- kind : getNullableSymbolOriginInfoKind ( SymbolOriginInfoKind . SymbolMemberExport ) ,
1810+ const fileName = isExternalModuleNameRelative ( stripQuotes ( moduleSymbol . name ) ) ? getSourceFileOfModule ( moduleSymbol ) ?. fileName : undefined ;
1811+ const { moduleSpecifier } = codefix . getModuleSpecifierForBestExportInfo ( [ {
1812+ exportKind : ExportKind . Named ,
1813+ moduleFileName : fileName ,
1814+ isFromPackageJson : false ,
17711815 moduleSymbol,
1772- isDefaultExport : false ,
1773- symbolName : firstAccessibleSymbol . name ,
1774- exportName : firstAccessibleSymbol . name ,
1775- fileName : isExternalModuleNameRelative ( stripQuotes ( moduleSymbol . name ) ) ? cast ( moduleSymbol . valueDeclaration , isSourceFile ) . fileName : undefined ,
1776- } ;
1777- symbolToOriginInfoMap [ index ] = origin ;
1816+ symbol : firstAccessibleSymbol ,
1817+ targetFlags : skipAlias ( firstAccessibleSymbol , typeChecker ) . flags ,
1818+ } ] , sourceFile , program , host , preferences ) || { } ;
1819+
1820+ if ( moduleSpecifier ) {
1821+ const origin : SymbolOriginInfoResolvedExport = {
1822+ kind : getNullableSymbolOriginInfoKind ( SymbolOriginInfoKind . SymbolMemberExport ) ,
1823+ moduleSymbol,
1824+ isDefaultExport : false ,
1825+ symbolName : firstAccessibleSymbol . name ,
1826+ exportName : firstAccessibleSymbol . name ,
1827+ fileName,
1828+ moduleSpecifier,
1829+ } ;
1830+ symbolToOriginInfoMap [ index ] = origin ;
1831+ }
17781832 }
17791833 }
17801834 else if ( preferences . includeCompletionsWithInsertText ) {
@@ -2034,7 +2088,7 @@ namespace ts.Completions {
20342088 preferences ,
20352089 ! ! importCompletionNode ,
20362090 context => {
2037- exportInfo . forEach ( sourceFile . path , ( info , symbolName , isFromAmbientModule ) => {
2091+ exportInfo . forEach ( sourceFile . path , ( info , symbolName , isFromAmbientModule , exportMapKey ) => {
20382092 if ( ! isIdentifierText ( symbolName , getEmitScriptTarget ( host . getCompilationSettings ( ) ) ) ) return ;
20392093 if ( ! detailsEntryId && isStringANonContextualKeyword ( symbolName ) ) return ;
20402094 // `targetFlags` should be the same for each `info`
@@ -2056,6 +2110,7 @@ namespace ts.Completions {
20562110 kind : moduleSpecifier ? SymbolOriginInfoKind . ResolvedExport : SymbolOriginInfoKind . Export ,
20572111 moduleSpecifier,
20582112 symbolName,
2113+ exportMapKey,
20592114 exportName : exportInfo . exportKind === ExportKind . ExportEquals ? InternalSymbolName . ExportEquals : exportInfo . symbol . name ,
20602115 fileName : exportInfo . moduleFileName ,
20612116 isDefaultExport,
@@ -2974,7 +3029,7 @@ namespace ts.Completions {
29743029 return { contextToken : previousToken as Node , previousToken : previousToken as Node } ;
29753030 }
29763031
2977- function getAutoImportSymbolFromCompletionEntryData ( name : string , data : CompletionEntryData , program : Program , host : LanguageServiceHost ) : { symbol : Symbol , origin : SymbolOriginInfoExport } | undefined {
3032+ function getAutoImportSymbolFromCompletionEntryData ( name : string , data : CompletionEntryData , program : Program , host : LanguageServiceHost ) : { symbol : Symbol , origin : SymbolOriginInfoExport | SymbolOriginInfoResolvedExport } | undefined {
29783033 const containingProgram = data . isPackageJsonImport ? host . getPackageJsonAutoImportProvider ! ( ) ! : program ;
29793034 const checker = containingProgram . getTypeChecker ( ) ;
29803035 const moduleSymbol =
@@ -2989,18 +3044,7 @@ namespace ts.Completions {
29893044 if ( ! symbol ) return undefined ;
29903045 const isDefaultExport = data . exportName === InternalSymbolName . Default ;
29913046 symbol = isDefaultExport && getLocalSymbolForExportDefault ( symbol ) || symbol ;
2992- return {
2993- symbol,
2994- origin : {
2995- kind : data . moduleSpecifier ? SymbolOriginInfoKind . ResolvedExport : SymbolOriginInfoKind . Export ,
2996- moduleSymbol,
2997- symbolName : name ,
2998- isDefaultExport,
2999- exportName : data . exportName ,
3000- fileName : data . fileName ,
3001- isFromPackageJson : ! ! data . isPackageJsonImport ,
3002- }
3003- } ;
3047+ return { symbol, origin : completionEntryDataToSymbolOriginInfo ( data , name , moduleSymbol ) } ;
30043048 }
30053049
30063050 interface CompletionEntryDisplayNameForSymbol {
0 commit comments