@@ -501,8 +501,7 @@ namespace ts {
501
501
for ( const name of names ) {
502
502
let result : T ;
503
503
const mode = getModeForFileReference ( name , containingFileMode ) ;
504
- // We lower-case all type references because npm automatically lowercases all packages. See GH#9824.
505
- const strName = isString ( name ) ? name : name . fileName . toLowerCase ( ) ;
504
+ const strName = getResolutionName ( name ) ;
506
505
const cacheKey = mode !== undefined ? `${ mode } |${ strName } ` : strName ;
507
506
if ( cache . has ( cacheKey ) ) {
508
507
result = cache . get ( cacheKey ) ! ;
@@ -1138,9 +1137,16 @@ namespace ts {
1138
1137
loadWithModeAwareCache ( moduleNames , containingFile , containingFileName , redirectedReference , resolutionInfo , loader ) ;
1139
1138
}
1140
1139
1141
- let actualResolveTypeReferenceDirectiveNamesWorker : ( typeDirectiveNames : string [ ] | readonly FileReference [ ] , containingFile : string , redirectedReference ?: ResolvedProjectReference , containingFileMode ?: SourceFile [ "impliedNodeFormat" ] | undefined ) => ( ResolvedTypeReferenceDirective | undefined ) [ ] ;
1140
+ let actualResolveTypeReferenceDirectiveNamesWorker : (
1141
+ typeDirectiveNames : string [ ] | readonly FileReference [ ] ,
1142
+ containingFile : string ,
1143
+ redirectedReference : ResolvedProjectReference | undefined ,
1144
+ containingFileMode : SourceFile [ "impliedNodeFormat" ] | undefined ,
1145
+ resolutionInfo : TypeReferenceDirectiveResolutionInfo | undefined ,
1146
+ ) => ( ResolvedTypeReferenceDirective | undefined ) [ ] ;
1142
1147
if ( host . resolveTypeReferenceDirectives ) {
1143
- actualResolveTypeReferenceDirectiveNamesWorker = ( typeDirectiveNames , containingFile , redirectedReference , containingFileMode ) => host . resolveTypeReferenceDirectives ! ( Debug . checkEachDefined ( typeDirectiveNames ) , containingFile , redirectedReference , options , containingFileMode ) ;
1148
+ actualResolveTypeReferenceDirectiveNamesWorker = ( typeDirectiveNames , containingFile , redirectedReference , containingFileMode , resolutionInfo ) =>
1149
+ host . resolveTypeReferenceDirectives ! ( Debug . checkEachDefined ( typeDirectiveNames ) , containingFile , redirectedReference , options , containingFileMode , resolutionInfo ) ;
1144
1150
}
1145
1151
else {
1146
1152
typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache ( currentDirectory , getCanonicalFileName , /*options*/ undefined , moduleResolutionCache ?. getPackageJsonInfoCache ( ) ) ;
@@ -1254,7 +1260,7 @@ namespace ts {
1254
1260
// This containingFilename needs to match with the one used in managed-side
1255
1261
const containingDirectory = options . configFilePath ? getDirectoryPath ( options . configFilePath ) : host . getCurrentDirectory ( ) ;
1256
1262
const containingFilename = combinePaths ( containingDirectory , inferredTypesContainingFile ) ;
1257
- const resolutions = resolveTypeReferenceDirectiveNamesWorker ( typeReferences , containingFilename ) ;
1263
+ const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState ( typeReferences , containingFilename ) ;
1258
1264
for ( let i = 0 ; i < typeReferences . length ; i ++ ) {
1259
1265
// under node16/nodenext module resolution, load `types`/ata include names as cjs resolution results by passing an `undefined` mode
1260
1266
processTypeReferenceDirective ( typeReferences [ i ] , /*mode*/ undefined , resolutions [ i ] , { kind : FileIncludeKind . AutomaticTypeDirectiveFile , typeReference : typeReferences [ i ] , packageId : resolutions [ i ] ?. packageId } ) ;
@@ -1452,14 +1458,14 @@ namespace ts {
1452
1458
return result ;
1453
1459
}
1454
1460
1455
- function resolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames : string [ ] | readonly FileReference [ ] , containingFile : string | SourceFile ) : readonly ( ResolvedTypeReferenceDirective | undefined ) [ ] {
1461
+ function resolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames : string [ ] | readonly FileReference [ ] , containingFile : string | SourceFile , resolutionInfo : TypeReferenceDirectiveResolutionInfo | undefined ) : readonly ( ResolvedTypeReferenceDirective | undefined ) [ ] {
1456
1462
if ( ! typeDirectiveNames . length ) return [ ] ;
1457
1463
const containingFileName = ! isString ( containingFile ) ? getNormalizedAbsolutePath ( containingFile . originalFileName , currentDirectory ) : containingFile ;
1458
1464
const redirectedReference = ! isString ( containingFile ) ? getRedirectReferenceForResolution ( containingFile ) : undefined ;
1459
1465
const containingFileMode = ! isString ( containingFile ) ? containingFile . impliedNodeFormat : undefined ;
1460
1466
tracing ?. push ( tracing . Phase . Program , "resolveTypeReferenceDirectiveNamesWorker" , { containingFileName } ) ;
1461
1467
performance . mark ( "beforeResolveTypeReference" ) ;
1462
- const result = actualResolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames , containingFileName , redirectedReference , containingFileMode ) ;
1468
+ const result = actualResolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames , containingFileName , redirectedReference , containingFileMode , resolutionInfo ) ;
1463
1469
performance . mark ( "afterResolveTypeReference" ) ;
1464
1470
performance . measure ( "ResolveTypeReference" , "beforeResolveTypeReference" , "afterResolveTypeReference" ) ;
1465
1471
tracing ?. pop ( ) ;
@@ -1695,6 +1701,96 @@ namespace ts {
1695
1701
}
1696
1702
}
1697
1703
1704
+ function resolveTypeReferenceDirectiveNamesReusingOldState ( typeDirectiveNames : readonly FileReference [ ] , containingFile : SourceFile ) : readonly ( ResolvedTypeReferenceDirective | undefined ) [ ] ;
1705
+ function resolveTypeReferenceDirectiveNamesReusingOldState ( typeDirectiveNames : string [ ] , containingFile : string ) : readonly ( ResolvedTypeReferenceDirective | undefined ) [ ] ;
1706
+ function resolveTypeReferenceDirectiveNamesReusingOldState ( typeDirectiveNames : string [ ] | readonly FileReference [ ] , containingFile : string | SourceFile ) : readonly ( ResolvedTypeReferenceDirective | undefined ) [ ] {
1707
+ if ( structureIsReused === StructureIsReused . Not ) {
1708
+ // If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules,
1709
+ // the best we can do is fallback to the default logic.
1710
+ return resolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames , containingFile , /*resolutionInfo*/ undefined ) ;
1711
+ }
1712
+
1713
+ const oldSourceFile = ! isString ( containingFile ) ? oldProgram && oldProgram . getSourceFile ( containingFile . fileName ) : undefined ;
1714
+ if ( ! isString ( containingFile ) ) {
1715
+ if ( oldSourceFile !== containingFile && containingFile . resolvedTypeReferenceDirectiveNames ) {
1716
+ // `file` was created for the new program.
1717
+ //
1718
+ // We only set `file.resolvedTypeReferenceDirectiveNames` via work from the current function,
1719
+ // so it is defined iff we already called the current function on `file`.
1720
+ // That call happened no later than the creation of the `file` object,
1721
+ // which per above occurred during the current program creation.
1722
+ // Since we assume the filesystem does not change during program creation,
1723
+ // it is safe to reuse resolutions from the earlier call.
1724
+ const result : ( ResolvedTypeReferenceDirective | undefined ) [ ] = [ ] ;
1725
+ for ( const typeDirectiveName of typeDirectiveNames as readonly FileReference [ ] ) {
1726
+ // We lower-case all type references because npm automatically lowercases all packages. See GH#9824.
1727
+ const resolvedTypeReferenceDirective = containingFile . resolvedTypeReferenceDirectiveNames . get ( getResolutionName ( typeDirectiveName ) , typeDirectiveName . resolutionMode || containingFile . impliedNodeFormat ) ;
1728
+ result . push ( resolvedTypeReferenceDirective ) ;
1729
+ }
1730
+ return result ;
1731
+ }
1732
+ }
1733
+
1734
+ /** An ordered list of module names for which we cannot recover the resolution. */
1735
+ let unknownTypeReferenceDirectiveNames : string [ ] | FileReference [ ] | undefined ;
1736
+ let result : ( ResolvedTypeReferenceDirective | undefined ) [ ] | undefined ;
1737
+ let reusedNames : ( string | FileReference ) [ ] | undefined ;
1738
+ const containingSourceFile = ! isString ( containingFile ) ? containingFile : undefined ;
1739
+ const canReuseResolutions = ! isString ( containingFile ) ?
1740
+ containingFile === oldSourceFile && ! hasInvalidatedResolutions ( oldSourceFile . path ) :
1741
+ ! hasInvalidatedResolutions ( toPath ( containingFile ) ) ;
1742
+ for ( let i = 0 ; i < typeDirectiveNames . length ; i ++ ) {
1743
+ const entry = typeDirectiveNames [ i ] ;
1744
+ if ( canReuseResolutions ) {
1745
+ const typeDirectiveName = getResolutionName ( entry ) ;
1746
+ const mode = getModeForFileReference ( entry , containingSourceFile ?. impliedNodeFormat ) ;
1747
+ const oldResolvedTypeReferenceDirective = getResolvedTypeReferenceDirective ( oldSourceFile , typeDirectiveName , mode ) ;
1748
+ if ( oldResolvedTypeReferenceDirective ) {
1749
+ if ( isTraceEnabled ( options , host ) ) {
1750
+ trace ( host ,
1751
+ oldResolvedTypeReferenceDirective . packageId ?
1752
+ Diagnostics . Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 :
1753
+ Diagnostics . Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2 ,
1754
+ typeDirectiveName ,
1755
+ ! isString ( containingFile ) ? getNormalizedAbsolutePath ( containingFile . originalFileName , currentDirectory ) : containingFile ,
1756
+ oldResolvedTypeReferenceDirective . resolvedFileName ,
1757
+ oldResolvedTypeReferenceDirective . packageId && packageIdToString ( oldResolvedTypeReferenceDirective . packageId )
1758
+ ) ;
1759
+ }
1760
+ ( result ??= new Array ( typeDirectiveNames . length ) ) [ i ] = oldResolvedTypeReferenceDirective ;
1761
+ ( reusedNames ??= [ ] ) . push ( entry ) ;
1762
+ continue ;
1763
+ }
1764
+ }
1765
+ // Resolution failed in the old program, or resolved to an ambient module for which we can't reuse the result.
1766
+ ( unknownTypeReferenceDirectiveNames ??= [ ] ) . push ( entry as FileReference & string ) ;
1767
+ }
1768
+
1769
+ if ( ! unknownTypeReferenceDirectiveNames ) return result || emptyArray ;
1770
+ const resolutions = resolveTypeReferenceDirectiveNamesWorker (
1771
+ unknownTypeReferenceDirectiveNames ,
1772
+ containingFile ,
1773
+ { names : unknownTypeReferenceDirectiveNames , reusedNames }
1774
+ ) ;
1775
+
1776
+ // Combine results of resolutions
1777
+ if ( ! result ) {
1778
+ // There were no unresolved resolutions.
1779
+ Debug . assert ( resolutions . length === typeDirectiveNames . length ) ;
1780
+ return resolutions ;
1781
+ }
1782
+
1783
+ let j = 0 ;
1784
+ for ( let i = 0 ; i < result . length ; i ++ ) {
1785
+ if ( ! result [ i ] ) {
1786
+ result [ i ] = resolutions [ j ] ;
1787
+ j ++ ;
1788
+ }
1789
+ }
1790
+ Debug . assert ( j === resolutions . length ) ;
1791
+ return result ;
1792
+ }
1793
+
1698
1794
function canReuseProjectReferences ( ) : boolean {
1699
1795
return ! forEachProjectReference (
1700
1796
oldProgram ! . getProjectReferences ( ) ,
@@ -1898,7 +1994,7 @@ namespace ts {
1898
1994
newSourceFile . resolvedModules = oldSourceFile . resolvedModules ;
1899
1995
}
1900
1996
const typesReferenceDirectives = newSourceFile . typeReferenceDirectives ;
1901
- const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesWorker ( typesReferenceDirectives , newSourceFile ) ;
1997
+ const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesReusingOldState ( typesReferenceDirectives , newSourceFile ) ;
1902
1998
// ensure that types resolutions are still correct
1903
1999
const typeReferenceResolutionsChanged = hasChangesInResolutions ( typesReferenceDirectives , newSourceFile , typeReferenceResolutions , oldSourceFile . resolvedTypeReferenceDirectiveNames , typeDirectiveIsEqualTo ) ;
1904
2000
if ( typeReferenceResolutionsChanged ) {
@@ -3165,13 +3261,13 @@ namespace ts {
3165
3261
return ;
3166
3262
}
3167
3263
3168
- const resolutions = resolveTypeReferenceDirectiveNamesWorker ( typeDirectives , file ) ;
3264
+ const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState ( typeDirectives , file ) ;
3169
3265
for ( let index = 0 ; index < typeDirectives . length ; index ++ ) {
3170
3266
const ref = file . typeReferenceDirectives [ index ] ;
3171
3267
const resolvedTypeReferenceDirective = resolutions [ index ] ;
3172
3268
// store resolved type directive on the file
3173
3269
const fileName = toFileNameLowerCase ( ref . fileName ) ;
3174
- setResolvedTypeReferenceDirective ( file , fileName , resolvedTypeReferenceDirective ) ;
3270
+ setResolvedTypeReferenceDirective ( file , fileName , resolvedTypeReferenceDirective , getModeForFileReference ( ref , file . impliedNodeFormat ) ) ;
3175
3271
const mode = ref . resolutionMode || file . impliedNodeFormat ;
3176
3272
if ( mode && getEmitModuleResolutionKind ( options ) !== ModuleResolutionKind . Node16 && getEmitModuleResolutionKind ( options ) !== ModuleResolutionKind . NodeNext ) {
3177
3273
programDiagnostics . add ( createDiagnosticForRange ( file , ref , Diagnostics . resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext ) ) ;
0 commit comments