@@ -18,11 +18,10 @@ namespace ts.codefix {
18
18
errorCodes,
19
19
getCodeActions ( context ) {
20
20
const { errorCode, preferences, sourceFile, span, program } = context ;
21
- const info = getFixesInfo ( context , errorCode , span . start , /*useAutoImportProvider*/ true ) ;
21
+ const info = getFixInfos ( context , errorCode , span . start , /*useAutoImportProvider*/ true ) ;
22
22
if ( ! info ) return undefined ;
23
- const { fixes, symbolName, errorIdentifierText } = info ;
24
23
const quotePreference = getQuotePreference ( sourceFile , preferences ) ;
25
- return fixes . map ( fix => codeActionForFix (
24
+ return info . map ( ( { fix, symbolName , errorIdentifierText } ) => codeActionForFix (
26
25
context ,
27
26
sourceFile ,
28
27
symbolName ,
@@ -74,9 +73,9 @@ namespace ts.codefix {
74
73
return { addImportFromDiagnostic, addImportFromExportedSymbol, writeFixes, hasFixes } ;
75
74
76
75
function addImportFromDiagnostic ( diagnostic : DiagnosticWithLocation , context : CodeFixContextBase ) {
77
- const info = getFixesInfo ( context , diagnostic . code , diagnostic . start , useAutoImportProvider ) ;
78
- if ( ! info || ! info . fixes . length ) return ;
79
- addImport ( info ) ;
76
+ const info = getFixInfos ( context , diagnostic . code , diagnostic . start , useAutoImportProvider ) ;
77
+ if ( ! info || ! info . length ) return ;
78
+ addImport ( first ( info ) ) ;
80
79
}
81
80
82
81
function addImportFromExportedSymbol ( exportedSymbol : Symbol , isValidTypeOnlyUseSite ?: boolean ) {
@@ -88,13 +87,12 @@ namespace ts.codefix {
88
87
const useRequire = shouldUseRequire ( sourceFile , program ) ;
89
88
const fix = getImportFixForSymbol ( sourceFile , exportInfo , moduleSymbol , program , /*useNamespaceInfo*/ undefined , ! ! isValidTypeOnlyUseSite , useRequire , host , preferences ) ;
90
89
if ( fix ) {
91
- addImport ( { fixes : [ fix ] , symbolName, errorIdentifierText : undefined } ) ;
90
+ addImport ( { fix, symbolName, errorIdentifierText : undefined } ) ;
92
91
}
93
92
}
94
93
95
- function addImport ( info : FixesInfo ) {
96
- const { fixes, symbolName } = info ;
97
- const fix = first ( fixes ) ;
94
+ function addImport ( info : FixInfo ) {
95
+ const { fix, symbolName } = info ;
98
96
switch ( fix . kind ) {
99
97
case ImportFixKind . UseNamespace :
100
98
addToNamespace . push ( fix ) ;
@@ -369,7 +367,7 @@ namespace ts.codefix {
369
367
370
368
export function getPromoteTypeOnlyCompletionAction ( sourceFile : SourceFile , symbolToken : Identifier , program : Program , host : LanguageServiceHost , formatContext : formatting . FormatContext , preferences : UserPreferences ) {
371
369
const compilerOptions = program . getCompilerOptions ( ) ;
372
- const symbolName = getSymbolName ( sourceFile , program . getTypeChecker ( ) , symbolToken , compilerOptions ) ;
370
+ const symbolName = single ( getSymbolNamesToImport ( sourceFile , program . getTypeChecker ( ) , symbolToken , compilerOptions ) ) ;
373
371
const fix = getTypeOnlyPromotionFix ( sourceFile , symbolToken , symbolName , program ) ;
374
372
const includeSymbolNameInDescription = symbolName !== symbolToken . text ;
375
373
return fix && codeFixActionToCodeAction ( codeActionForFix ( { host, formatContext, preferences } , sourceFile , symbolName , fix , includeSymbolNameInDescription , QuotePreference . Double , compilerOptions ) ) ;
@@ -741,8 +739,13 @@ namespace ts.codefix {
741
739
}
742
740
}
743
741
744
- interface FixesInfo { readonly fixes : readonly ImportFix [ ] , readonly symbolName : string , readonly errorIdentifierText : string | undefined }
745
- function getFixesInfo ( context : CodeFixContextBase , errorCode : number , pos : number , useAutoImportProvider : boolean ) : FixesInfo | undefined {
742
+ interface FixInfo {
743
+ readonly fix : ImportFix ;
744
+ readonly symbolName : string ;
745
+ readonly errorIdentifierText : string | undefined ;
746
+ readonly isJsxNamespaceFix ?: boolean ;
747
+ }
748
+ function getFixInfos ( context : CodeFixContextBase , errorCode : number , pos : number , useAutoImportProvider : boolean ) : readonly FixInfo [ ] | undefined {
746
749
const symbolToken = getTokenAtPosition ( context . sourceFile , pos ) ;
747
750
let info ;
748
751
if ( errorCode === Diagnostics . _0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead . code ) {
@@ -752,21 +755,24 @@ namespace ts.codefix {
752
755
return undefined ;
753
756
}
754
757
else if ( errorCode === Diagnostics . _0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type . code ) {
755
- const symbolName = getSymbolName ( context . sourceFile , context . program . getTypeChecker ( ) , symbolToken , context . program . getCompilerOptions ( ) ) ;
758
+ const symbolName = single ( getSymbolNamesToImport ( context . sourceFile , context . program . getTypeChecker ( ) , symbolToken , context . program . getCompilerOptions ( ) ) ) ;
756
759
const fix = getTypeOnlyPromotionFix ( context . sourceFile , symbolToken , symbolName , context . program ) ;
757
- return fix && { fixes : [ fix ] , symbolName, errorIdentifierText : symbolToken . text } ;
760
+ return fix && [ { fix, symbolName, errorIdentifierText : symbolToken . text } ] ;
758
761
}
759
762
else {
760
763
info = getFixesInfoForNonUMDImport ( context , symbolToken , useAutoImportProvider ) ;
761
764
}
762
765
763
766
const packageJsonImportFilter = createPackageJsonImportFilter ( context . sourceFile , context . preferences , context . host ) ;
764
- return info && { ... info , fixes : sortFixes ( info . fixes , context . sourceFile , context . program , packageJsonImportFilter , context . host ) } ;
767
+ return info && sortFixInfo ( info , context . sourceFile , context . program , packageJsonImportFilter , context . host ) ;
765
768
}
766
769
767
- function sortFixes ( fixes : readonly ImportFixWithModuleSpecifier [ ] , sourceFile : SourceFile , program : Program , packageJsonImportFilter : PackageJsonImportFilter , host : LanguageServiceHost ) : readonly ImportFixWithModuleSpecifier [ ] {
770
+ function sortFixInfo ( fixes : readonly ( FixInfo & { fix : ImportFixWithModuleSpecifier } ) [ ] , sourceFile : SourceFile , program : Program , packageJsonImportFilter : PackageJsonImportFilter , host : LanguageServiceHost ) : readonly ( FixInfo & { fix : ImportFixWithModuleSpecifier } ) [ ] {
768
771
const _toPath = ( fileName : string ) => toPath ( fileName , host . getCurrentDirectory ( ) , hostGetCanonicalFileName ( host ) ) ;
769
- return sort ( fixes , ( a , b ) => compareValues ( a . kind , b . kind ) || compareModuleSpecifiers ( a , b , sourceFile , program , packageJsonImportFilter . allowsImportingSpecifier , _toPath ) ) ;
772
+ return sort ( fixes , ( a , b ) =>
773
+ compareBooleans ( ! ! a . isJsxNamespaceFix , ! ! b . isJsxNamespaceFix ) ||
774
+ compareValues ( a . fix . kind , b . fix . kind ) ||
775
+ compareModuleSpecifiers ( a . fix , b . fix , sourceFile , program , packageJsonImportFilter . allowsImportingSpecifier , _toPath ) ) ;
770
776
}
771
777
772
778
function getBestFix ( fixes : readonly ImportFixWithModuleSpecifier [ ] , sourceFile : SourceFile , program : Program , packageJsonImportFilter : PackageJsonImportFilter , host : LanguageServiceHost ) : ImportFixWithModuleSpecifier | undefined {
@@ -836,7 +842,7 @@ namespace ts.codefix {
836
842
return Comparison . EqualTo ;
837
843
}
838
844
839
- function getFixesInfoForUMDImport ( { sourceFile, program, host, preferences } : CodeFixContextBase , token : Node ) : FixesInfo & { fixes : readonly ImportFixWithModuleSpecifier [ ] } | undefined {
845
+ function getFixesInfoForUMDImport ( { sourceFile, program, host, preferences } : CodeFixContextBase , token : Node ) : ( FixInfo & { fix : ImportFixWithModuleSpecifier } ) [ ] | undefined {
840
846
const checker = program . getTypeChecker ( ) ;
841
847
const umdSymbol = getUmdSymbol ( token , checker ) ;
842
848
if ( ! umdSymbol ) return undefined ;
@@ -846,7 +852,7 @@ namespace ts.codefix {
846
852
const useRequire = shouldUseRequire ( sourceFile , program ) ;
847
853
const position = isIdentifier ( token ) ? token . getStart ( sourceFile ) : undefined ;
848
854
const fixes = getImportFixes ( exportInfo , position ? { position, symbolName } : undefined , /*isValidTypeOnlyUseSite*/ false , useRequire , program , sourceFile , host , preferences ) . fixes ;
849
- return { fixes , symbolName, errorIdentifierText : tryCast ( token , isIdentifier ) ?. text } ;
855
+ return fixes . map ( fix => ( { fix , symbolName, errorIdentifierText : tryCast ( token , isIdentifier ) ?. text } ) ) ;
850
856
}
851
857
function getUmdSymbol ( token : Node , checker : TypeChecker ) : Symbol | undefined {
852
858
// try the identifier to see if it is the umd symbol
@@ -906,20 +912,21 @@ namespace ts.codefix {
906
912
}
907
913
}
908
914
909
- function getFixesInfoForNonUMDImport ( { sourceFile, program, cancellationToken, host, preferences } : CodeFixContextBase , symbolToken : Identifier , useAutoImportProvider : boolean ) : FixesInfo & { fixes : readonly ImportFixWithModuleSpecifier [ ] } | undefined {
915
+ function getFixesInfoForNonUMDImport ( { sourceFile, program, cancellationToken, host, preferences } : CodeFixContextBase , symbolToken : Identifier , useAutoImportProvider : boolean ) : readonly ( FixInfo & { fix : ImportFixWithModuleSpecifier } ) [ ] | undefined {
910
916
const checker = program . getTypeChecker ( ) ;
911
917
const compilerOptions = program . getCompilerOptions ( ) ;
912
- const symbolName = getSymbolName ( sourceFile , checker , symbolToken , compilerOptions ) ;
913
- // "default" is a keyword and not a legal identifier for the import, but appears as an identifier.
914
- if ( symbolName === InternalSymbolName . Default ) {
915
- return undefined ;
916
- }
917
- const isValidTypeOnlyUseSite = isValidTypeOnlyAliasUseSite ( symbolToken ) ;
918
- const useRequire = shouldUseRequire ( sourceFile , program ) ;
919
- const exportInfo = getExportInfos ( symbolName , isJSXTagName ( symbolToken ) , getMeaningFromLocation ( symbolToken ) , cancellationToken , sourceFile , program , useAutoImportProvider , host , preferences ) ;
920
- const fixes = arrayFrom ( flatMapIterator ( exportInfo . entries ( ) , ( [ _ , exportInfos ] ) =>
921
- getImportFixes ( exportInfos , { symbolName, position : symbolToken . getStart ( sourceFile ) } , isValidTypeOnlyUseSite , useRequire , program , sourceFile , host , preferences ) . fixes ) ) ;
922
- return { fixes, symbolName, errorIdentifierText : symbolToken . text } ;
918
+ return flatMap ( getSymbolNamesToImport ( sourceFile , checker , symbolToken , compilerOptions ) , symbolName => {
919
+ // "default" is a keyword and not a legal identifier for the import, but appears as an identifier.
920
+ if ( symbolName === InternalSymbolName . Default ) {
921
+ return undefined ;
922
+ }
923
+ const isValidTypeOnlyUseSite = isValidTypeOnlyAliasUseSite ( symbolToken ) ;
924
+ const useRequire = shouldUseRequire ( sourceFile , program ) ;
925
+ const exportInfo = getExportInfos ( symbolName , isJSXTagName ( symbolToken ) , getMeaningFromLocation ( symbolToken ) , cancellationToken , sourceFile , program , useAutoImportProvider , host , preferences ) ;
926
+ const fixes = arrayFrom ( flatMapIterator ( exportInfo . entries ( ) , ( [ _ , exportInfos ] ) =>
927
+ getImportFixes ( exportInfos , { symbolName, position : symbolToken . getStart ( sourceFile ) } , isValidTypeOnlyUseSite , useRequire , program , sourceFile , host , preferences ) . fixes ) ) ;
928
+ return fixes . map ( fix => ( { fix, symbolName, errorIdentifierText : symbolToken . text , isJsxNamespaceFix : symbolName !== symbolToken . text } ) ) ;
929
+ } ) ;
923
930
}
924
931
925
932
function getTypeOnlyPromotionFix ( sourceFile : SourceFile , symbolToken : Identifier , symbolName : string , program : Program ) : FixPromoteTypeOnlyImport | undefined {
@@ -933,15 +940,16 @@ namespace ts.codefix {
933
940
return { kind : ImportFixKind . PromoteTypeOnly , typeOnlyAliasDeclaration } ;
934
941
}
935
942
936
- function getSymbolName ( sourceFile : SourceFile , checker : TypeChecker , symbolToken : Identifier , compilerOptions : CompilerOptions ) : string {
943
+ function getSymbolNamesToImport ( sourceFile : SourceFile , checker : TypeChecker , symbolToken : Identifier , compilerOptions : CompilerOptions ) : string [ ] {
937
944
const parent = symbolToken . parent ;
938
945
if ( ( isJsxOpeningLikeElement ( parent ) || isJsxClosingElement ( parent ) ) && parent . tagName === symbolToken && jsxModeNeedsExplicitImport ( compilerOptions . jsx ) ) {
939
946
const jsxNamespace = checker . getJsxNamespace ( sourceFile ) ;
940
947
if ( needsJsxNamespaceFix ( jsxNamespace , symbolToken , checker ) ) {
941
- return jsxNamespace ;
948
+ const needsComponentNameFix = ! isIntrinsicJsxName ( symbolToken . text ) && ! checker . resolveName ( symbolToken . text , symbolToken , SymbolFlags . Value , /*excludeGlobals*/ false ) ;
949
+ return needsComponentNameFix ? [ symbolToken . text , jsxNamespace ] : [ jsxNamespace ] ;
942
950
}
943
951
}
944
- return symbolToken . text ;
952
+ return [ symbolToken . text ] ;
945
953
}
946
954
947
955
function needsJsxNamespaceFix ( jsxNamespace : string , symbolToken : Identifier , checker : TypeChecker ) {
0 commit comments