@@ -156,6 +156,7 @@ import {
156
156
HasChangedAutomaticTypeDirectiveNames ,
157
157
hasChangesInResolutions ,
158
158
hasExtension ,
159
+ HasInvalidatedLibResolutions ,
159
160
HasInvalidatedResolutions ,
160
161
hasJSDocNodes ,
161
162
hasJSFileExtension ,
@@ -211,6 +212,7 @@ import {
211
212
JsxEmit ,
212
213
length ,
213
214
libMap ,
215
+ LibResolution ,
214
216
libs ,
215
217
mapDefined ,
216
218
mapDefinedIterator ,
@@ -276,6 +278,7 @@ import {
276
278
ResolvedModuleWithFailedLookupLocations ,
277
279
ResolvedProjectReference ,
278
280
ResolvedTypeReferenceDirectiveWithFailedLookupLocations ,
281
+ resolveLibrary ,
279
282
resolveModuleName ,
280
283
resolveTypeReferenceDirective ,
281
284
returnFalse ,
@@ -1097,6 +1100,32 @@ function forEachProjectReference<T>(
1097
1100
/** @internal */
1098
1101
export const inferredTypesContainingFile = "__inferred type names__.ts" ;
1099
1102
1103
+ /** @internal */
1104
+ export function getInferredLibraryNameResolveFrom ( options : CompilerOptions , currentDirectory : string , libFileName : string ) {
1105
+ const containingDirectory = options . configFilePath ? getDirectoryPath ( options . configFilePath ) : currentDirectory ;
1106
+ return combinePaths ( containingDirectory , `__lib_node_modules_lookup_${ libFileName } __.ts` ) ;
1107
+ }
1108
+
1109
+ function getLibraryNameFromLibFileName ( libFileName : string ) {
1110
+ // Support resolving to lib.dom.d.ts -> @typescript/lib-dom, and
1111
+ // lib.dom.iterable.d.ts -> @typescript/lib-dom/iterable
1112
+ // lib.es2015.symbol.wellknown.d.ts -> @typescript/lib-es2015/symbol-wellknown
1113
+ const components = libFileName . split ( "." ) ;
1114
+ let path = components [ 1 ] ;
1115
+ let i = 2 ;
1116
+ while ( components [ i ] && components [ i ] !== "d" ) {
1117
+ path += ( i === 2 ? "/" : "-" ) + components [ i ] ;
1118
+ i ++ ;
1119
+ }
1120
+ return "@typescript/lib-" + path ;
1121
+ }
1122
+
1123
+ function getLibFileNameFromLibReference ( libReference : FileReference ) {
1124
+ const libName = toFileNameLowerCase ( libReference . fileName ) ;
1125
+ const libFileName = libMap . get ( libName ) ;
1126
+ return { libName, libFileName } ;
1127
+ }
1128
+
1100
1129
interface DiagnosticCache < T extends Diagnostic > {
1101
1130
perFile ?: Map < Path , readonly T [ ] > ;
1102
1131
allDiagnostics ?: readonly T [ ] ;
@@ -1176,6 +1205,7 @@ export function isProgramUptoDate(
1176
1205
getSourceVersion : ( path : Path , fileName : string ) => string | undefined ,
1177
1206
fileExists : ( fileName : string ) => boolean ,
1178
1207
hasInvalidatedResolutions : HasInvalidatedResolutions ,
1208
+ hasInvalidatedLibResolutions : HasInvalidatedLibResolutions ,
1179
1209
hasChangedAutomaticTypeDirectiveNames : HasChangedAutomaticTypeDirectiveNames | undefined ,
1180
1210
getParsedCommandLine : ( fileName : string ) => ParsedCommandLine | undefined ,
1181
1211
projectReferences : readonly ProjectReference [ ] | undefined
@@ -1201,6 +1231,9 @@ export function isProgramUptoDate(
1201
1231
// If the compilation settings do no match, then the program is not up-to-date
1202
1232
if ( ! compareDataObjects ( currentOptions , newOptions ) ) return false ;
1203
1233
1234
+ // If library resolution is invalidated, then the program is not up-to-date
1235
+ if ( program . resolvedLibReferences && forEachEntry ( program . resolvedLibReferences , ( _value , libFileName ) => hasInvalidatedLibResolutions ( libFileName ) ) ) return false ;
1236
+
1204
1237
// If everything matches but the text of config file is changed,
1205
1238
// error locations can change for program options, so update the program
1206
1239
if ( currentOptions . configFile && newOptions . configFile ) return currentOptions . configFile . text === newOptions . configFile . text ;
@@ -1469,6 +1502,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1469
1502
let automaticTypeDirectiveNames : string [ ] | undefined ;
1470
1503
let automaticTypeDirectiveResolutions : ModeAwareCache < ResolvedTypeReferenceDirectiveWithFailedLookupLocations > ;
1471
1504
1505
+ let resolvedLibReferences : Map < string , LibResolution > | undefined ;
1506
+ let resolvedLibProcessing : Map < string , LibResolution > | undefined ;
1507
+
1472
1508
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
1473
1509
// This works as imported modules are discovered recursively in a depth first manner, specifically:
1474
1510
// - For each root file, findSourceFile is called.
@@ -1592,6 +1628,17 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1592
1628
) ;
1593
1629
}
1594
1630
1631
+ const hasInvalidatedLibResolutions = host . hasInvalidatedLibResolutions || returnFalse ;
1632
+ let actualResolveLibrary : ( libraryName : string , resolveFrom : string , options : CompilerOptions , libFileName : string ) => ResolvedModuleWithFailedLookupLocations ;
1633
+ if ( host . resolveLibrary ) {
1634
+ actualResolveLibrary = host . resolveLibrary . bind ( host ) ;
1635
+ }
1636
+ else {
1637
+ const libraryResolutionCache = createModuleResolutionCache ( currentDirectory , getCanonicalFileName , options , moduleResolutionCache ?. getPackageJsonInfoCache ( ) ) ;
1638
+ actualResolveLibrary = ( libraryName , resolveFrom , options ) =>
1639
+ resolveLibrary ( libraryName , resolveFrom , options , host , libraryResolutionCache ) ;
1640
+ }
1641
+
1595
1642
// Map from a stringified PackageId to the source file with that id.
1596
1643
// Only one source file may have a given packageId. Others become redirects (see createRedirectSourceFile).
1597
1644
// `packageIdToSourceFile` is only used while building the program, while `sourceFileToPackageName` and `isSourceFileTargetOfRedirect` are kept around.
@@ -1772,6 +1819,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1772
1819
1773
1820
// unconditionally set oldProgram to undefined to prevent it from being captured in closure
1774
1821
oldProgram = undefined ;
1822
+ resolvedLibProcessing = undefined ;
1775
1823
1776
1824
const program : Program = {
1777
1825
getRootFileNames : ( ) => rootNames ,
@@ -1813,6 +1861,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1813
1861
sourceFileToPackageName,
1814
1862
redirectTargetsMap,
1815
1863
usesUriStyleNodeCoreModules,
1864
+ resolvedLibReferences,
1816
1865
isEmittedFile,
1817
1866
getConfigFileParsingDiagnostics,
1818
1867
getProjectReferences,
@@ -2441,6 +2490,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
2441
2490
return StructureIsReused . SafeModules ;
2442
2491
}
2443
2492
2493
+ if ( oldProgram . resolvedLibReferences &&
2494
+ forEachEntry ( oldProgram . resolvedLibReferences , ( resolution , libFileName ) => pathForLibFileWorker ( libFileName ) . actual !== resolution . actual ) ) {
2495
+ return StructureIsReused . SafeModules ;
2496
+ }
2497
+
2444
2498
if ( host . hasChangedAutomaticTypeDirectiveNames ) {
2445
2499
if ( host . hasChangedAutomaticTypeDirectiveNames ( ) ) return StructureIsReused . SafeModules ;
2446
2500
}
@@ -2481,6 +2535,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
2481
2535
sourceFileToPackageName = oldProgram . sourceFileToPackageName ;
2482
2536
redirectTargetsMap = oldProgram . redirectTargetsMap ;
2483
2537
usesUriStyleNodeCoreModules = oldProgram . usesUriStyleNodeCoreModules ;
2538
+ resolvedLibReferences = oldProgram . resolvedLibReferences ;
2484
2539
2485
2540
return StructureIsReused . Completely ;
2486
2541
}
@@ -2596,7 +2651,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
2596
2651
return equalityComparer ( file . fileName , getDefaultLibraryFileName ( ) ) ;
2597
2652
}
2598
2653
else {
2599
- return some ( options . lib , libFileName => equalityComparer ( file . fileName , pathForLibFile ( libFileName ) ) ) ;
2654
+ return some ( options . lib , libFileName => equalityComparer ( file . fileName , resolvedLibReferences ! . get ( libFileName ) ! . actual ) ) ;
2600
2655
}
2601
2656
}
2602
2657
@@ -3310,11 +3365,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
3310
3365
}
3311
3366
3312
3367
function getLibFileFromReference ( ref : FileReference ) {
3313
- const libName = toFileNameLowerCase ( ref . fileName ) ;
3314
- const libFileName = libMap . get ( libName ) ;
3315
- if ( libFileName ) {
3316
- return getSourceFile ( pathForLibFile ( libFileName ) ) ;
3317
- }
3368
+ const { libFileName } = getLibFileNameFromLibReference ( ref ) ;
3369
+ const actualFileName = libFileName && resolvedLibReferences ?. get ( libFileName ) ?. actual ;
3370
+ return actualFileName !== undefined ? getSourceFile ( actualFileName ) : undefined ;
3318
3371
}
3319
3372
3320
3373
/** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
@@ -3810,29 +3863,61 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
3810
3863
}
3811
3864
3812
3865
function pathForLibFile ( libFileName : string ) : string {
3813
- // Support resolving to lib.dom.d.ts -> @typescript/lib-dom, and
3814
- // lib.dom.iterable.d.ts -> @typescript/lib-dom/iterable
3815
- // lib.es2015.symbol.wellknown.d.ts -> @typescript/lib-es2015/symbol-wellknown
3816
- const components = libFileName . split ( "." ) ;
3817
- let path = components [ 1 ] ;
3818
- let i = 2 ;
3819
- while ( components [ i ] && components [ i ] !== "d" ) {
3820
- path += ( i === 2 ? "/" : "-" ) + components [ i ] ;
3821
- i ++ ;
3822
- }
3823
- const containingDirectory = options . configFilePath ? getDirectoryPath ( options . configFilePath ) : currentDirectory ;
3824
- const resolveFrom = combinePaths ( containingDirectory , `__lib_node_modules_lookup_${ libFileName } __.ts` ) ;
3825
- const localOverrideModuleResult = resolveModuleName ( "@typescript/lib-" + path , resolveFrom , { moduleResolution : ModuleResolutionKind . Node10 , traceResolution : options . traceResolution } , host , moduleResolutionCache ) ;
3826
- if ( localOverrideModuleResult ?. resolvedModule ) {
3827
- return localOverrideModuleResult . resolvedModule . resolvedFileName ;
3866
+ const existing = resolvedLibReferences ?. get ( libFileName ) ;
3867
+ if ( existing ) return existing . actual ;
3868
+ const result = pathForLibFileWorker ( libFileName ) ;
3869
+ ( resolvedLibReferences ??= new Map ( ) ) . set ( libFileName , result ) ;
3870
+ return result . actual ;
3871
+ }
3872
+
3873
+ function pathForLibFileWorker ( libFileName : string ) : LibResolution {
3874
+ const existing = resolvedLibProcessing ?. get ( libFileName ) ;
3875
+ if ( existing ) return existing ;
3876
+
3877
+ if ( structureIsReused !== StructureIsReused . Not && oldProgram && ! hasInvalidatedLibResolutions ( libFileName ) ) {
3878
+ const oldResolution = oldProgram . resolvedLibReferences ?. get ( libFileName ) ;
3879
+ if ( oldResolution ) {
3880
+ if ( oldResolution . resolution && isTraceEnabled ( options , host ) ) {
3881
+ const libraryName = getLibraryNameFromLibFileName ( libFileName ) ;
3882
+ const resolveFrom = getInferredLibraryNameResolveFrom ( options , currentDirectory , libFileName ) ;
3883
+ trace ( host ,
3884
+ oldResolution . resolution . resolvedModule ?
3885
+ oldResolution . resolution . resolvedModule . packageId ?
3886
+ Diagnostics . Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 :
3887
+ Diagnostics . Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2 :
3888
+ Diagnostics . Reusing_resolution_of_module_0_from_1_of_old_program_it_was_not_resolved ,
3889
+ libraryName ,
3890
+ getNormalizedAbsolutePath ( resolveFrom , currentDirectory ) ,
3891
+ oldResolution . resolution . resolvedModule ?. resolvedFileName ,
3892
+ oldResolution . resolution . resolvedModule ?. packageId && packageIdToString ( oldResolution . resolution . resolvedModule . packageId )
3893
+ ) ;
3894
+ }
3895
+ ( resolvedLibProcessing ??= new Map ( ) ) . set ( libFileName , oldResolution ) ;
3896
+ return oldResolution ;
3897
+ }
3828
3898
}
3829
- return combinePaths ( defaultLibraryPath , libFileName ) ;
3899
+
3900
+ const libraryName = getLibraryNameFromLibFileName ( libFileName ) ;
3901
+ const resolveFrom = getInferredLibraryNameResolveFrom ( options , currentDirectory , libFileName ) ;
3902
+ tracing ?. push ( tracing . Phase . Program , "resolveLibrary" , { resolveFrom } ) ;
3903
+ performance . mark ( "beforeResolveLibrary" ) ;
3904
+ const resolution = actualResolveLibrary ( libraryName , resolveFrom , options , libFileName ) ;
3905
+ performance . mark ( "afterResolveLibrary" ) ;
3906
+ performance . measure ( "ResolveLibrary" , "beforeResolveLibrary" , "afterResolveLibrary" ) ;
3907
+ tracing ?. pop ( ) ;
3908
+ const result : LibResolution = {
3909
+ resolution,
3910
+ actual : resolution . resolvedModule ?
3911
+ resolution . resolvedModule . resolvedFileName :
3912
+ combinePaths ( defaultLibraryPath , libFileName )
3913
+ } ;
3914
+ ( resolvedLibProcessing ??= new Map ( ) ) . set ( libFileName , result ) ;
3915
+ return result ;
3830
3916
}
3831
3917
3832
3918
function processLibReferenceDirectives ( file : SourceFile ) {
3833
3919
forEach ( file . libReferenceDirectives , ( libReference , index ) => {
3834
- const libName = toFileNameLowerCase ( libReference . fileName ) ;
3835
- const libFileName = libMap . get ( libName ) ;
3920
+ const { libName, libFileName } = getLibFileNameFromLibReference ( libReference ) ;
3836
3921
if ( libFileName ) {
3837
3922
// we ignore any 'no-default-lib' reference set on this file.
3838
3923
processRootFile ( pathForLibFile ( libFileName ) , /*isDefaultLib*/ true , /*ignoreNoDefaultLib*/ true , { kind : FileIncludeKind . LibReferenceDirective , file : file . path , index, } ) ;
0 commit comments