@@ -58,7 +58,7 @@ import {
58
58
targetOptionDeclaration , toFileNameLowerCase , tokenToString , trace , tracing , trimStringEnd , TsConfigSourceFile ,
59
59
TypeChecker , typeDirectiveIsEqualTo , TypeReferenceDirectiveResolutionCache , UnparsedSource , VariableDeclaration ,
60
60
VariableStatement , walkUpParenthesizedExpressions , WriteFileCallback , WriteFileCallbackData ,
61
- writeFileEnsuringDirectories , zipToModeAwareCache ,
61
+ writeFileEnsuringDirectories , zipToModeAwareCache , TypeReferenceDirectiveResolutionInfo , getResolvedTypeReferenceDirective ,
62
62
} from "./_namespaces/ts" ;
63
63
import * as performance from "./_namespaces/ts.performance" ;
64
64
@@ -564,8 +564,7 @@ export function loadWithTypeDirectiveCache<T>(names: string[] | readonly FileRef
564
564
for ( const name of names ) {
565
565
let result : T ;
566
566
const mode = getModeForFileReference ( name , containingFileMode ) ;
567
- // We lower-case all type references because npm automatically lowercases all packages. See GH#9824.
568
- const strName = isString ( name ) ? name : name . fileName . toLowerCase ( ) ;
567
+ const strName = getResolutionName ( name ) ;
569
568
const cacheKey = mode !== undefined ? `${ mode } |${ strName } ` : strName ;
570
569
if ( cache . has ( cacheKey ) ) {
571
570
result = cache . get ( cacheKey ) ! ;
@@ -1202,9 +1201,16 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1202
1201
loadWithModeAwareCache ( moduleNames , containingFile , containingFileName , redirectedReference , resolutionInfo , loader ) ;
1203
1202
}
1204
1203
1205
- let actualResolveTypeReferenceDirectiveNamesWorker : ( typeDirectiveNames : string [ ] | readonly FileReference [ ] , containingFile : string , redirectedReference ?: ResolvedProjectReference , containingFileMode ?: SourceFile [ "impliedNodeFormat" ] | undefined ) => ( ResolvedTypeReferenceDirective | undefined ) [ ] ;
1204
+ let actualResolveTypeReferenceDirectiveNamesWorker : (
1205
+ typeDirectiveNames : string [ ] | readonly FileReference [ ] ,
1206
+ containingFile : string ,
1207
+ redirectedReference : ResolvedProjectReference | undefined ,
1208
+ containingFileMode : SourceFile [ "impliedNodeFormat" ] | undefined ,
1209
+ resolutionInfo : TypeReferenceDirectiveResolutionInfo | undefined ,
1210
+ ) => ( ResolvedTypeReferenceDirective | undefined ) [ ] ;
1206
1211
if ( host . resolveTypeReferenceDirectives ) {
1207
- actualResolveTypeReferenceDirectiveNamesWorker = ( typeDirectiveNames , containingFile , redirectedReference , containingFileMode ) => host . resolveTypeReferenceDirectives ! ( Debug . checkEachDefined ( typeDirectiveNames ) , containingFile , redirectedReference , options , containingFileMode ) ;
1212
+ actualResolveTypeReferenceDirectiveNamesWorker = ( typeDirectiveNames , containingFile , redirectedReference , containingFileMode , resolutionInfo ) =>
1213
+ host . resolveTypeReferenceDirectives ! ( Debug . checkEachDefined ( typeDirectiveNames ) , containingFile , redirectedReference , options , containingFileMode , resolutionInfo ) ;
1208
1214
}
1209
1215
else {
1210
1216
typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache ( currentDirectory , getCanonicalFileName , /*options*/ undefined , moduleResolutionCache ?. getPackageJsonInfoCache ( ) ) ;
@@ -1318,7 +1324,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1318
1324
// This containingFilename needs to match with the one used in managed-side
1319
1325
const containingDirectory = options . configFilePath ? getDirectoryPath ( options . configFilePath ) : host . getCurrentDirectory ( ) ;
1320
1326
const containingFilename = combinePaths ( containingDirectory , inferredTypesContainingFile ) ;
1321
- const resolutions = resolveTypeReferenceDirectiveNamesWorker ( typeReferences , containingFilename ) ;
1327
+ const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState ( typeReferences , containingFilename ) ;
1322
1328
for ( let i = 0 ; i < typeReferences . length ; i ++ ) {
1323
1329
// under node16/nodenext module resolution, load `types`/ata include names as cjs resolution results by passing an `undefined` mode
1324
1330
processTypeReferenceDirective ( typeReferences [ i ] , /*mode*/ undefined , resolutions [ i ] , { kind : FileIncludeKind . AutomaticTypeDirectiveFile , typeReference : typeReferences [ i ] , packageId : resolutions [ i ] ?. packageId } ) ;
@@ -1516,14 +1522,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1516
1522
return result ;
1517
1523
}
1518
1524
1519
- function resolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames : string [ ] | readonly FileReference [ ] , containingFile : string | SourceFile ) : readonly ( ResolvedTypeReferenceDirective | undefined ) [ ] {
1525
+ function resolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames : string [ ] | readonly FileReference [ ] , containingFile : string | SourceFile , resolutionInfo : TypeReferenceDirectiveResolutionInfo | undefined ) : readonly ( ResolvedTypeReferenceDirective | undefined ) [ ] {
1520
1526
if ( ! typeDirectiveNames . length ) return [ ] ;
1521
1527
const containingFileName = ! isString ( containingFile ) ? getNormalizedAbsolutePath ( containingFile . originalFileName , currentDirectory ) : containingFile ;
1522
1528
const redirectedReference = ! isString ( containingFile ) ? getRedirectReferenceForResolution ( containingFile ) : undefined ;
1523
1529
const containingFileMode = ! isString ( containingFile ) ? containingFile . impliedNodeFormat : undefined ;
1524
1530
tracing ?. push ( tracing . Phase . Program , "resolveTypeReferenceDirectiveNamesWorker" , { containingFileName } ) ;
1525
1531
performance . mark ( "beforeResolveTypeReference" ) ;
1526
- const result = actualResolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames , containingFileName , redirectedReference , containingFileMode ) ;
1532
+ const result = actualResolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames , containingFileName , redirectedReference , containingFileMode , resolutionInfo ) ;
1527
1533
performance . mark ( "afterResolveTypeReference" ) ;
1528
1534
performance . measure ( "ResolveTypeReference" , "beforeResolveTypeReference" , "afterResolveTypeReference" ) ;
1529
1535
tracing ?. pop ( ) ;
@@ -1759,6 +1765,96 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1759
1765
}
1760
1766
}
1761
1767
1768
+ function resolveTypeReferenceDirectiveNamesReusingOldState ( typeDirectiveNames : readonly FileReference [ ] , containingFile : SourceFile ) : readonly ( ResolvedTypeReferenceDirective | undefined ) [ ] ;
1769
+ function resolveTypeReferenceDirectiveNamesReusingOldState ( typeDirectiveNames : string [ ] , containingFile : string ) : readonly ( ResolvedTypeReferenceDirective | undefined ) [ ] ;
1770
+ function resolveTypeReferenceDirectiveNamesReusingOldState ( typeDirectiveNames : string [ ] | readonly FileReference [ ] , containingFile : string | SourceFile ) : readonly ( ResolvedTypeReferenceDirective | undefined ) [ ] {
1771
+ if ( structureIsReused === StructureIsReused . Not ) {
1772
+ // If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules,
1773
+ // the best we can do is fallback to the default logic.
1774
+ return resolveTypeReferenceDirectiveNamesWorker ( typeDirectiveNames , containingFile , /*resolutionInfo*/ undefined ) ;
1775
+ }
1776
+
1777
+ const oldSourceFile = ! isString ( containingFile ) ? oldProgram && oldProgram . getSourceFile ( containingFile . fileName ) : undefined ;
1778
+ if ( ! isString ( containingFile ) ) {
1779
+ if ( oldSourceFile !== containingFile && containingFile . resolvedTypeReferenceDirectiveNames ) {
1780
+ // `file` was created for the new program.
1781
+ //
1782
+ // We only set `file.resolvedTypeReferenceDirectiveNames` via work from the current function,
1783
+ // so it is defined iff we already called the current function on `file`.
1784
+ // That call happened no later than the creation of the `file` object,
1785
+ // which per above occurred during the current program creation.
1786
+ // Since we assume the filesystem does not change during program creation,
1787
+ // it is safe to reuse resolutions from the earlier call.
1788
+ const result : ( ResolvedTypeReferenceDirective | undefined ) [ ] = [ ] ;
1789
+ for ( const typeDirectiveName of typeDirectiveNames as readonly FileReference [ ] ) {
1790
+ // We lower-case all type references because npm automatically lowercases all packages. See GH#9824.
1791
+ const resolvedTypeReferenceDirective = containingFile . resolvedTypeReferenceDirectiveNames . get ( getResolutionName ( typeDirectiveName ) , typeDirectiveName . resolutionMode || containingFile . impliedNodeFormat ) ;
1792
+ result . push ( resolvedTypeReferenceDirective ) ;
1793
+ }
1794
+ return result ;
1795
+ }
1796
+ }
1797
+
1798
+ /** An ordered list of module names for which we cannot recover the resolution. */
1799
+ let unknownTypeReferenceDirectiveNames : string [ ] | FileReference [ ] | undefined ;
1800
+ let result : ( ResolvedTypeReferenceDirective | undefined ) [ ] | undefined ;
1801
+ let reusedNames : ( string | FileReference ) [ ] | undefined ;
1802
+ const containingSourceFile = ! isString ( containingFile ) ? containingFile : undefined ;
1803
+ const canReuseResolutions = ! isString ( containingFile ) ?
1804
+ containingFile === oldSourceFile && ! hasInvalidatedResolutions ( oldSourceFile . path ) :
1805
+ ! hasInvalidatedResolutions ( toPath ( containingFile ) ) ;
1806
+ for ( let i = 0 ; i < typeDirectiveNames . length ; i ++ ) {
1807
+ const entry = typeDirectiveNames [ i ] ;
1808
+ if ( canReuseResolutions ) {
1809
+ const typeDirectiveName = getResolutionName ( entry ) ;
1810
+ const mode = getModeForFileReference ( entry , containingSourceFile ?. impliedNodeFormat ) ;
1811
+ const oldResolvedTypeReferenceDirective = getResolvedTypeReferenceDirective ( oldSourceFile , typeDirectiveName , mode ) ;
1812
+ if ( oldResolvedTypeReferenceDirective ) {
1813
+ if ( isTraceEnabled ( options , host ) ) {
1814
+ trace ( host ,
1815
+ oldResolvedTypeReferenceDirective . packageId ?
1816
+ Diagnostics . Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 :
1817
+ Diagnostics . Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2 ,
1818
+ typeDirectiveName ,
1819
+ ! isString ( containingFile ) ? getNormalizedAbsolutePath ( containingFile . originalFileName , currentDirectory ) : containingFile ,
1820
+ oldResolvedTypeReferenceDirective . resolvedFileName ,
1821
+ oldResolvedTypeReferenceDirective . packageId && packageIdToString ( oldResolvedTypeReferenceDirective . packageId )
1822
+ ) ;
1823
+ }
1824
+ ( result ??= new Array ( typeDirectiveNames . length ) ) [ i ] = oldResolvedTypeReferenceDirective ;
1825
+ ( reusedNames ??= [ ] ) . push ( entry ) ;
1826
+ continue ;
1827
+ }
1828
+ }
1829
+ // Resolution failed in the old program, or resolved to an ambient module for which we can't reuse the result.
1830
+ ( unknownTypeReferenceDirectiveNames ??= [ ] ) . push ( entry as FileReference & string ) ;
1831
+ }
1832
+
1833
+ if ( ! unknownTypeReferenceDirectiveNames ) return result || emptyArray ;
1834
+ const resolutions = resolveTypeReferenceDirectiveNamesWorker (
1835
+ unknownTypeReferenceDirectiveNames ,
1836
+ containingFile ,
1837
+ { names : unknownTypeReferenceDirectiveNames , reusedNames }
1838
+ ) ;
1839
+
1840
+ // Combine results of resolutions
1841
+ if ( ! result ) {
1842
+ // There were no unresolved resolutions.
1843
+ Debug . assert ( resolutions . length === typeDirectiveNames . length ) ;
1844
+ return resolutions ;
1845
+ }
1846
+
1847
+ let j = 0 ;
1848
+ for ( let i = 0 ; i < result . length ; i ++ ) {
1849
+ if ( ! result [ i ] ) {
1850
+ result [ i ] = resolutions [ j ] ;
1851
+ j ++ ;
1852
+ }
1853
+ }
1854
+ Debug . assert ( j === resolutions . length ) ;
1855
+ return result ;
1856
+ }
1857
+
1762
1858
function canReuseProjectReferences ( ) : boolean {
1763
1859
return ! forEachProjectReference (
1764
1860
oldProgram ! . getProjectReferences ( ) ,
@@ -1962,7 +2058,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1962
2058
newSourceFile . resolvedModules = oldSourceFile . resolvedModules ;
1963
2059
}
1964
2060
const typesReferenceDirectives = newSourceFile . typeReferenceDirectives ;
1965
- const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesWorker ( typesReferenceDirectives , newSourceFile ) ;
2061
+ const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesReusingOldState ( typesReferenceDirectives , newSourceFile ) ;
1966
2062
// ensure that types resolutions are still correct
1967
2063
const typeReferenceResolutionsChanged = hasChangesInResolutions ( typesReferenceDirectives , newSourceFile , typeReferenceResolutions , oldSourceFile . resolvedTypeReferenceDirectiveNames , typeDirectiveIsEqualTo ) ;
1968
2064
if ( typeReferenceResolutionsChanged ) {
@@ -3229,13 +3325,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
3229
3325
return ;
3230
3326
}
3231
3327
3232
- const resolutions = resolveTypeReferenceDirectiveNamesWorker ( typeDirectives , file ) ;
3328
+ const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState ( typeDirectives , file ) ;
3233
3329
for ( let index = 0 ; index < typeDirectives . length ; index ++ ) {
3234
3330
const ref = file . typeReferenceDirectives [ index ] ;
3235
3331
const resolvedTypeReferenceDirective = resolutions [ index ] ;
3236
3332
// store resolved type directive on the file
3237
3333
const fileName = toFileNameLowerCase ( ref . fileName ) ;
3238
- setResolvedTypeReferenceDirective ( file , fileName , resolvedTypeReferenceDirective ) ;
3334
+ setResolvedTypeReferenceDirective ( file , fileName , resolvedTypeReferenceDirective , getModeForFileReference ( ref , file . impliedNodeFormat ) ) ;
3239
3335
const mode = ref . resolutionMode || file . impliedNodeFormat ;
3240
3336
if ( mode && getEmitModuleResolutionKind ( options ) !== ModuleResolutionKind . Node16 && getEmitModuleResolutionKind ( options ) !== ModuleResolutionKind . NodeNext ) {
3241
3337
programDiagnostics . add ( createDiagnosticForRange ( file , ref , Diagnostics . resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext ) ) ;
0 commit comments