@@ -501,8 +501,7 @@ namespace ts {
501501 for ( const name of names ) {
502502 let result : T ;
503503 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 ) ;
506505 const cacheKey = mode !== undefined ? `${ mode } |${ strName } ` : strName ;
507506 if ( cache . has ( cacheKey ) ) {
508507 result = cache . get ( cacheKey ) ! ;
@@ -1138,9 +1137,16 @@ namespace ts {
11381137 loadWithModeAwareCache ( moduleNames , containingFile , containingFileName , redirectedReference , resolutionInfo , loader ) ;
11391138 }
11401139
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 ) [ ] ;
11421147 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 ) ;
11441150 }
11451151 else {
11461152 typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache ( currentDirectory , getCanonicalFileName , /*options*/ undefined , moduleResolutionCache ?. getPackageJsonInfoCache ( ) ) ;
@@ -1254,7 +1260,7 @@ namespace ts {
12541260 // This containingFilename needs to match with the one used in managed-side
12551261 const containingDirectory = options . configFilePath ? getDirectoryPath ( options . configFilePath ) : host . getCurrentDirectory ( ) ;
12561262 const containingFilename = combinePaths ( containingDirectory , inferredTypesContainingFile ) ;
1257- const resolutions = resolveTypeReferenceDirectiveNamesWorker ( typeReferences , containingFilename ) ;
1263+ const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState ( typeReferences , containingFilename ) ;
12581264 for ( let i = 0 ; i < typeReferences . length ; i ++ ) {
12591265 // under node16/nodenext module resolution, load `types`/ata include names as cjs resolution results by passing an `undefined` mode
12601266 processTypeReferenceDirective ( typeReferences [ i ] , /*mode*/ undefined , resolutions [ i ] , { kind : FileIncludeKind . AutomaticTypeDirectiveFile , typeReference : typeReferences [ i ] , packageId : resolutions [ i ] ?. packageId } ) ;
@@ -1452,14 +1458,14 @@ namespace ts {
14521458 return result ;
14531459 }
14541460
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 ) [ ] {
14561462 if ( ! typeDirectiveNames . length ) return [ ] ;
14571463 const containingFileName = ! isString ( containingFile ) ? getNormalizedAbsolutePath ( containingFile . originalFileName , currentDirectory ) : containingFile ;
14581464 const redirectedReference = ! isString ( containingFile ) ? getRedirectReferenceForResolution ( containingFile ) : undefined ;
14591465 const containingFileMode = ! isString ( containingFile ) ? containingFile . impliedNodeFormat : undefined ;
14601466 tracing ?. push ( tracing . Phase . Program , "resolveTypeReferenceDirectiveNamesWorker" , { containingFileName } ) ;
14611467 performance . mark ( "beforeResolveTypeReference" ) ;
1462- const result = actualResolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames , containingFileName , redirectedReference , containingFileMode ) ;
1468+ const result = actualResolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames , containingFileName , redirectedReference , containingFileMode , resolutionInfo ) ;
14631469 performance . mark ( "afterResolveTypeReference" ) ;
14641470 performance . measure ( "ResolveTypeReference" , "beforeResolveTypeReference" , "afterResolveTypeReference" ) ;
14651471 tracing ?. pop ( ) ;
@@ -1695,6 +1701,96 @@ namespace ts {
16951701 }
16961702 }
16971703
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+
16981794 function canReuseProjectReferences ( ) : boolean {
16991795 return ! forEachProjectReference (
17001796 oldProgram ! . getProjectReferences ( ) ,
@@ -1898,7 +1994,7 @@ namespace ts {
18981994 newSourceFile . resolvedModules = oldSourceFile . resolvedModules ;
18991995 }
19001996 const typesReferenceDirectives = newSourceFile . typeReferenceDirectives ;
1901- const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesWorker ( typesReferenceDirectives , newSourceFile ) ;
1997+ const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesReusingOldState ( typesReferenceDirectives , newSourceFile ) ;
19021998 // ensure that types resolutions are still correct
19031999 const typeReferenceResolutionsChanged = hasChangesInResolutions ( typesReferenceDirectives , newSourceFile , typeReferenceResolutions , oldSourceFile . resolvedTypeReferenceDirectiveNames , typeDirectiveIsEqualTo ) ;
19042000 if ( typeReferenceResolutionsChanged ) {
@@ -3165,13 +3261,13 @@ namespace ts {
31653261 return ;
31663262 }
31673263
3168- const resolutions = resolveTypeReferenceDirectiveNamesWorker ( typeDirectives , file ) ;
3264+ const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState ( typeDirectives , file ) ;
31693265 for ( let index = 0 ; index < typeDirectives . length ; index ++ ) {
31703266 const ref = file . typeReferenceDirectives [ index ] ;
31713267 const resolvedTypeReferenceDirective = resolutions [ index ] ;
31723268 // store resolved type directive on the file
31733269 const fileName = toFileNameLowerCase ( ref . fileName ) ;
3174- setResolvedTypeReferenceDirective ( file , fileName , resolvedTypeReferenceDirective ) ;
3270+ setResolvedTypeReferenceDirective ( file , fileName , resolvedTypeReferenceDirective , getModeForFileReference ( ref , file . impliedNodeFormat ) ) ;
31753271 const mode = ref . resolutionMode || file . impliedNodeFormat ;
31763272 if ( mode && getEmitModuleResolutionKind ( options ) !== ModuleResolutionKind . Node16 && getEmitModuleResolutionKind ( options ) !== ModuleResolutionKind . NodeNext ) {
31773273 programDiagnostics . add ( createDiagnosticForRange ( file , ref , Diagnostics . resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext ) ) ;
0 commit comments