@@ -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 ,
@@ -1049,6 +1052,12 @@ export function loadWithModeAwareCache<Entry, SourceFile, ResolutionCache, Resol
1049
1052
return resolutions ;
1050
1053
}
1051
1054
1055
+ function getLibFileName ( libReference : FileReference ) {
1056
+ const libName = toFileNameLowerCase ( libReference . fileName ) ;
1057
+ const libFileName = libMap . get ( libName ) ;
1058
+ return { libName, libFileName } ;
1059
+ }
1060
+
1052
1061
/** @internal */
1053
1062
export function forEachResolvedProjectReference < T > (
1054
1063
resolvedProjectReferences : readonly ( ResolvedProjectReference | undefined ) [ ] | undefined ,
@@ -1176,6 +1185,7 @@ export function isProgramUptoDate(
1176
1185
getSourceVersion : ( path : Path , fileName : string ) => string | undefined ,
1177
1186
fileExists : ( fileName : string ) => boolean ,
1178
1187
hasInvalidatedResolutions : HasInvalidatedResolutions ,
1188
+ hasInvalidatedLibResolutions : HasInvalidatedLibResolutions ,
1179
1189
hasChangedAutomaticTypeDirectiveNames : HasChangedAutomaticTypeDirectiveNames | undefined ,
1180
1190
getParsedCommandLine : ( fileName : string ) => ParsedCommandLine | undefined ,
1181
1191
projectReferences : readonly ProjectReference [ ] | undefined
@@ -1201,6 +1211,8 @@ export function isProgramUptoDate(
1201
1211
// If the compilation settings do no match, then the program is not up-to-date
1202
1212
if ( ! compareDataObjects ( currentOptions , newOptions ) ) return false ;
1203
1213
1214
+ if ( some ( newOptions . lib , hasInvalidatedLibResolutions ) ) return false ;
1215
+
1204
1216
// If everything matches but the text of config file is changed,
1205
1217
// error locations can change for program options, so update the program
1206
1218
if ( currentOptions . configFile && newOptions . configFile ) return currentOptions . configFile . text === newOptions . configFile . text ;
@@ -1209,7 +1221,11 @@ export function isProgramUptoDate(
1209
1221
1210
1222
function sourceFileNotUptoDate ( sourceFile : SourceFile ) {
1211
1223
return ! sourceFileVersionUptoDate ( sourceFile ) ||
1212
- hasInvalidatedResolutions ( sourceFile . path ) ;
1224
+ hasInvalidatedResolutions ( sourceFile . path ) ||
1225
+ some ( sourceFile . libReferenceDirectives , libRef => {
1226
+ const { libFileName } = getLibFileName ( libRef ) ;
1227
+ return ! ! libFileName && hasInvalidatedLibResolutions ( libFileName ) ;
1228
+ } ) ;
1213
1229
}
1214
1230
1215
1231
function sourceFileVersionUptoDate ( sourceFile : SourceFile ) {
@@ -1469,7 +1485,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1469
1485
let automaticTypeDirectiveNames : string [ ] | undefined ;
1470
1486
let automaticTypeDirectiveResolutions : ModeAwareCache < ResolvedTypeReferenceDirectiveWithFailedLookupLocations > ;
1471
1487
1472
- let resolvedLibReferences : Map < string , string > | undefined ;
1488
+ let resolvedLibReferences : Map < string , LibResolution > | undefined ;
1489
+ let resolvedLibProcessing : Map < string , LibResolution > | undefined ;
1473
1490
1474
1491
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
1475
1492
// This works as imported modules are discovered recursively in a depth first manner, specifically:
@@ -1594,6 +1611,17 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1594
1611
) ;
1595
1612
}
1596
1613
1614
+ const hasInvalidatedLibResolutions = host . hasInvalidatedLibResolutions || returnFalse ;
1615
+ let actualResolveLibrary : ( libraryName : string , resolveFrom : string , options : CompilerOptions , libFileName : string ) => ResolvedModuleWithFailedLookupLocations ;
1616
+ if ( host . resolveLibrary ) {
1617
+ actualResolveLibrary = host . resolveLibrary . bind ( host ) ;
1618
+ }
1619
+ else {
1620
+ const libraryResolutionCache = createModuleResolutionCache ( currentDirectory , getCanonicalFileName , options , moduleResolutionCache ?. getPackageJsonInfoCache ( ) ) ;
1621
+ actualResolveLibrary = ( libraryName , resolveFrom , options ) =>
1622
+ resolveLibrary ( libraryName , resolveFrom , options , host , libraryResolutionCache ) ;
1623
+ }
1624
+
1597
1625
// Map from a stringified PackageId to the source file with that id.
1598
1626
// Only one source file may have a given packageId. Others become redirects (see createRedirectSourceFile).
1599
1627
// `packageIdToSourceFile` is only used while building the program, while `sourceFileToPackageName` and `isSourceFileTargetOfRedirect` are kept around.
@@ -1774,6 +1802,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
1774
1802
1775
1803
// unconditionally set oldProgram to undefined to prevent it from being captured in closure
1776
1804
oldProgram = undefined ;
1805
+ resolvedLibProcessing = undefined ;
1777
1806
1778
1807
const program : Program = {
1779
1808
getRootFileNames : ( ) => rootNames ,
@@ -2434,6 +2463,15 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
2434
2463
else {
2435
2464
newSourceFile . resolvedTypeReferenceDirectiveNames = oldSourceFile . resolvedTypeReferenceDirectiveNames ;
2436
2465
}
2466
+ // Do this resolution if necessary to determine reconstruction of program
2467
+ if ( structureIsReused !== StructureIsReused . Completely &&
2468
+ some ( newSourceFile . libReferenceDirectives , libReference => {
2469
+ const { libFileName } = getLibFileName ( libReference ) ;
2470
+ return ! ! libFileName &&
2471
+ pathForLibFileWorker ( libFileName ) . actual !== oldProgram ?. resolvedLibReferences ?. get ( libFileName ) ?. actual ;
2472
+ } ) ) {
2473
+ structureIsReused = StructureIsReused . SafeModules ;
2474
+ }
2437
2475
}
2438
2476
2439
2477
if ( structureIsReused !== StructureIsReused . Completely ) {
@@ -2444,6 +2482,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
2444
2482
return StructureIsReused . SafeModules ;
2445
2483
}
2446
2484
2485
+ if ( some ( options . lib , libFileName => pathForLibFileWorker ( libFileName ) . actual !== oldProgram ?. resolvedLibReferences ?. get ( libFileName ) ?. actual ) ) {
2486
+ return StructureIsReused . SafeModules ;
2487
+ }
2488
+
2447
2489
if ( host . hasChangedAutomaticTypeDirectiveNames ) {
2448
2490
if ( host . hasChangedAutomaticTypeDirectiveNames ( ) ) return StructureIsReused . SafeModules ;
2449
2491
}
@@ -2600,7 +2642,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
2600
2642
return equalityComparer ( file . fileName , getDefaultLibraryFileName ( ) ) ;
2601
2643
}
2602
2644
else {
2603
- return some ( options . lib , libFileName => equalityComparer ( file . fileName , resolvedLibReferences ! . get ( libFileName ) ! ) ) ;
2645
+ return some ( options . lib , libFileName => equalityComparer ( file . fileName , resolvedLibReferences ! . get ( libFileName ) ! . actual ) ) ;
2604
2646
}
2605
2647
}
2606
2648
@@ -3314,10 +3356,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
3314
3356
}
3315
3357
3316
3358
function getLibFileFromReference ( ref : FileReference ) {
3317
- const libName = toFileNameLowerCase ( ref . fileName ) ;
3318
- const libFileName = libMap . get ( libName ) ;
3359
+ const { libFileName } = getLibFileName ( ref ) ;
3319
3360
if ( libFileName ) {
3320
- return getSourceFile ( resolvedLibReferences ? .get ( libFileName ) ! ) ;
3361
+ return getSourceFile ( resolvedLibReferences ! . get ( libFileName ) ! . actual ) ;
3321
3362
}
3322
3363
}
3323
3364
@@ -3815,7 +3856,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
3815
3856
3816
3857
function pathForLibFile ( libFileName : string ) : string {
3817
3858
const existing = resolvedLibReferences ?. get ( libFileName ) ;
3818
- if ( existing ) return existing ;
3859
+ if ( existing ) return existing . actual ;
3860
+ const result = pathForLibFileWorker ( libFileName ) ;
3861
+ ( resolvedLibReferences ??= new Map ( ) ) . set ( libFileName , result ) ;
3862
+ return result . actual ;
3863
+ }
3864
+
3865
+ function getLibraryNameAndResolveFrom ( libFileName : string ) {
3819
3866
// Support resolving to lib.dom.d.ts -> @typescript/lib-dom, and
3820
3867
// lib.dom.iterable.d.ts -> @typescript/lib-dom/iterable
3821
3868
// lib.es2015.symbol.wellknown.d.ts -> @typescript/lib-es2015/symbol-wellknown
@@ -3827,18 +3874,51 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
3827
3874
i ++ ;
3828
3875
}
3829
3876
const resolveFrom = combinePaths ( currentDirectory , `__lib_node_modules_lookup_${ libFileName } __.ts` ) ;
3830
- const localOverrideModuleResult = resolveModuleName ( "@typescript/lib-" + path , resolveFrom , { moduleResolution : ModuleResolutionKind . Node10 , traceResolution : options . traceResolution } , host , moduleResolutionCache ) ;
3831
- const result = localOverrideModuleResult ?. resolvedModule ?
3832
- localOverrideModuleResult . resolvedModule . resolvedFileName :
3833
- combinePaths ( defaultLibraryPath , libFileName ) ;
3834
- ( resolvedLibReferences ??= new Map ( ) ) . set ( libFileName , result ) ;
3877
+ const libraryName = "@typescript/lib-" + path ;
3878
+ return { resolveFrom, libraryName } ;
3879
+ }
3880
+
3881
+ function pathForLibFileWorker ( libFileName : string ) : LibResolution {
3882
+ const existing = resolvedLibProcessing ?. get ( libFileName ) ;
3883
+ if ( existing ) return existing ;
3884
+
3885
+ if ( structureIsReused !== StructureIsReused . Not && oldProgram && ! hasInvalidatedLibResolutions ( libFileName ) ) {
3886
+ const oldResolution = oldProgram . resolvedLibReferences ?. get ( libFileName ) ;
3887
+ if ( oldResolution ) {
3888
+ if ( oldResolution . resolution && isTraceEnabled ( options , host ) ) {
3889
+ const { libraryName, resolveFrom } = getLibraryNameAndResolveFrom ( libFileName ) ;
3890
+ trace ( host ,
3891
+ oldResolution . resolution . resolvedModule ?
3892
+ oldResolution . resolution . resolvedModule . packageId ?
3893
+ Diagnostics . Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 :
3894
+ Diagnostics . Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2 :
3895
+ Diagnostics . Reusing_resolution_of_module_0_from_1_of_old_program_it_was_not_resolved ,
3896
+ libraryName ,
3897
+ getNormalizedAbsolutePath ( resolveFrom , currentDirectory ) ,
3898
+ oldResolution . resolution . resolvedModule ?. resolvedFileName ,
3899
+ oldResolution . resolution . resolvedModule ?. packageId && packageIdToString ( oldResolution . resolution . resolvedModule . packageId )
3900
+ ) ;
3901
+ }
3902
+ ( resolvedLibProcessing ??= new Map ( ) ) . set ( libFileName , oldResolution ) ;
3903
+ return oldResolution ;
3904
+ }
3905
+ }
3906
+
3907
+ const { libraryName, resolveFrom } = getLibraryNameAndResolveFrom ( libFileName ) ;
3908
+ const resolution = actualResolveLibrary ( libraryName , resolveFrom , options , libFileName ) ;
3909
+ const result : LibResolution = {
3910
+ resolution,
3911
+ actual : resolution . resolvedModule ?
3912
+ resolution . resolvedModule . resolvedFileName :
3913
+ combinePaths ( defaultLibraryPath , libFileName )
3914
+ } ;
3915
+ ( resolvedLibProcessing ??= new Map ( ) ) . set ( libFileName , result ) ;
3835
3916
return result ;
3836
3917
}
3837
3918
3838
3919
function processLibReferenceDirectives ( file : SourceFile ) {
3839
3920
forEach ( file . libReferenceDirectives , ( libReference , index ) => {
3840
- const libName = toFileNameLowerCase ( libReference . fileName ) ;
3841
- const libFileName = libMap . get ( libName ) ;
3921
+ const { libName, libFileName } = getLibFileName ( libReference ) ;
3842
3922
if ( libFileName ) {
3843
3923
// we ignore any 'no-default-lib' reference set on this file.
3844
3924
processRootFile ( pathForLibFile ( libFileName ) , /*isDefaultLib*/ true , /*ignoreNoDefaultLib*/ true , { kind : FileIncludeKind . LibReferenceDirective , file : file . path , index, } ) ;
0 commit comments