@@ -74,23 +74,23 @@ namespace ts.Completions {
74
74
75
75
interface SymbolOriginInfo {
76
76
kind : SymbolOriginInfoKind ;
77
- symbolName ?: string ;
78
- moduleSymbol ?: Symbol ;
79
77
isDefaultExport ?: boolean ;
80
78
isFromPackageJson ?: boolean ;
81
- exportName ?: string ;
82
79
fileName ?: string ;
83
- moduleSpecifier ?: string ;
84
80
}
85
81
86
82
interface SymbolOriginInfoExport extends SymbolOriginInfo {
87
83
symbolName : string ;
88
84
moduleSymbol : Symbol ;
89
85
isDefaultExport : boolean ;
90
86
exportName : string ;
87
+ exportMapKey : string ;
91
88
}
92
89
93
- interface SymbolOriginInfoResolvedExport extends SymbolOriginInfoExport {
90
+ interface SymbolOriginInfoResolvedExport extends SymbolOriginInfo {
91
+ symbolName : string ;
92
+ moduleSymbol : Symbol ;
93
+ exportName : string ;
94
94
moduleSpecifier : string ;
95
95
}
96
96
@@ -294,6 +294,10 @@ namespace ts.Completions {
294
294
}
295
295
}
296
296
297
+ function completionEntryDataIsResolved ( data : CompletionEntryDataAutoImport | undefined ) : data is CompletionEntryDataResolved {
298
+ return ! ! data ?. moduleSpecifier ;
299
+ }
300
+
297
301
function continuePreviousIncompleteResponse (
298
302
cache : IncompleteCompletionsCache ,
299
303
file : SourceFile ,
@@ -308,9 +312,6 @@ namespace ts.Completions {
308
312
309
313
const lowerCaseTokenText = location . text . toLowerCase ( ) ;
310
314
const exportMap = getExportInfoMap ( file , host , program , cancellationToken ) ;
311
- const checker = program . getTypeChecker ( ) ;
312
- const autoImportProvider = host . getPackageJsonAutoImportProvider ?.( ) ;
313
- const autoImportProviderChecker = autoImportProvider ?. getTypeChecker ( ) ;
314
315
const newEntries = resolvingModuleSpecifiers (
315
316
"continuePreviousIncompleteResponse" ,
316
317
host ,
@@ -320,7 +321,7 @@ namespace ts.Completions {
320
321
/*isForImportStatementCompletion*/ false ,
321
322
context => {
322
323
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 ) ) {
324
325
// Not an auto import or already resolved; keep as is
325
326
return entry ;
326
327
}
@@ -329,13 +330,8 @@ namespace ts.Completions {
329
330
return undefined ;
330
331
}
331
332
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 ) ;
339
335
340
336
const result = info && context . tryResolve ( info , ! isExternalModuleNameRelative ( stripQuotes ( origin . moduleSymbol . name ) ) ) ;
341
337
if ( ! result ) return entry ;
@@ -760,14 +756,56 @@ namespace ts.Completions {
760
756
return text . replace ( / \$ / gm, "\\$" ) ;
761
757
}
762
758
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 = {
765
773
exportName : origin . exportName ,
774
+ exportMapKey : origin . exportMapKey ,
766
775
fileName : origin . fileName ,
767
776
ambientModuleName : origin . fileName ? undefined : stripQuotes ( origin . moduleSymbol . name ) ,
768
777
isPackageJsonImport : origin . isFromPackageJson ? true : undefined ,
769
- moduleSpecifier : originIsResolvedExport ( origin ) ? origin . moduleSpecifier : undefined ,
770
778
} ;
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 ;
771
809
}
772
810
773
811
function getInsertTextAndReplacementSpanForImportCompletion ( name : string , importCompletionNode : Node , contextToken : Node | undefined , origin : SymbolOriginInfoResolvedExport , useSemicolons : boolean , options : CompilerOptions , preferences : UserPreferences ) {
@@ -1762,19 +1800,35 @@ namespace ts.Completions {
1762
1800
const index = symbols . length ;
1763
1801
symbols . push ( firstAccessibleSymbol ) ;
1764
1802
const moduleSymbol = firstAccessibleSymbol . parent ;
1765
- if ( ! moduleSymbol || ! isExternalModuleSymbol ( moduleSymbol ) ) {
1803
+ if ( ! moduleSymbol ||
1804
+ ! isExternalModuleSymbol ( moduleSymbol ) ||
1805
+ typeChecker . tryGetMemberInModuleExportsAndProperties ( firstAccessibleSymbol . name , moduleSymbol ) !== firstAccessibleSymbol
1806
+ ) {
1766
1807
symbolToOriginInfoMap [ index ] = { kind : getNullableSymbolOriginInfoKind ( SymbolOriginInfoKind . SymbolMemberNoExport ) } ;
1767
1808
}
1768
1809
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 ,
1771
1815
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
+ }
1778
1832
}
1779
1833
}
1780
1834
else if ( preferences . includeCompletionsWithInsertText ) {
@@ -2034,7 +2088,7 @@ namespace ts.Completions {
2034
2088
preferences ,
2035
2089
! ! importCompletionNode ,
2036
2090
context => {
2037
- exportInfo . forEach ( sourceFile . path , ( info , symbolName , isFromAmbientModule ) => {
2091
+ exportInfo . forEach ( sourceFile . path , ( info , symbolName , isFromAmbientModule , exportMapKey ) => {
2038
2092
if ( ! isIdentifierText ( symbolName , getEmitScriptTarget ( host . getCompilationSettings ( ) ) ) ) return ;
2039
2093
if ( ! detailsEntryId && isStringANonContextualKeyword ( symbolName ) ) return ;
2040
2094
// `targetFlags` should be the same for each `info`
@@ -2056,6 +2110,7 @@ namespace ts.Completions {
2056
2110
kind : moduleSpecifier ? SymbolOriginInfoKind . ResolvedExport : SymbolOriginInfoKind . Export ,
2057
2111
moduleSpecifier,
2058
2112
symbolName,
2113
+ exportMapKey,
2059
2114
exportName : exportInfo . exportKind === ExportKind . ExportEquals ? InternalSymbolName . ExportEquals : exportInfo . symbol . name ,
2060
2115
fileName : exportInfo . moduleFileName ,
2061
2116
isDefaultExport,
@@ -2974,7 +3029,7 @@ namespace ts.Completions {
2974
3029
return { contextToken : previousToken as Node , previousToken : previousToken as Node } ;
2975
3030
}
2976
3031
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 {
2978
3033
const containingProgram = data . isPackageJsonImport ? host . getPackageJsonAutoImportProvider ! ( ) ! : program ;
2979
3034
const checker = containingProgram . getTypeChecker ( ) ;
2980
3035
const moduleSymbol =
@@ -2989,18 +3044,7 @@ namespace ts.Completions {
2989
3044
if ( ! symbol ) return undefined ;
2990
3045
const isDefaultExport = data . exportName === InternalSymbolName . Default ;
2991
3046
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 ) } ;
3004
3048
}
3005
3049
3006
3050
interface CompletionEntryDisplayNameForSymbol {
0 commit comments