@@ -28,6 +28,7 @@ namespace ts {
28
28
interface ResolutionWithFailedLookupLocations {
29
29
readonly failedLookupLocations : ReadonlyArray < string > ;
30
30
isInvalidated ?: boolean ;
31
+ refCount ?: number ;
31
32
}
32
33
33
34
interface ResolutionWithResolvedFileName {
@@ -42,6 +43,7 @@ namespace ts {
42
43
43
44
export interface ResolutionCacheHost extends ModuleResolutionHost {
44
45
toPath ( fileName : string ) : Path ;
46
+ getCanonicalFileName : GetCanonicalFileName ;
45
47
getCompilationSettings ( ) : CompilerOptions ;
46
48
watchDirectoryOfFailedLookupLocation ( directory : string , cb : DirectoryWatcherCallback , flags : WatchDirectoryFlags ) : FileWatcher ;
47
49
onInvalidatedResolution ( ) : void ;
@@ -78,18 +80,25 @@ namespace ts {
78
80
let filesWithInvalidatedResolutions : Map < true > | undefined ;
79
81
let allFilesHaveInvalidatedResolution = false ;
80
82
83
+ const getCurrentDirectory = memoize ( ( ) => resolutionHost . getCurrentDirectory ( ) ) ;
84
+ const cachedDirectoryStructureHost = resolutionHost . getCachedDirectoryStructureHost ( ) ;
85
+
81
86
// The resolvedModuleNames and resolvedTypeReferenceDirectives are the cache of resolutions per file.
82
87
// The key in the map is source file's path.
83
88
// The values are Map of resolutions with key being name lookedup.
84
89
const resolvedModuleNames = createMap < Map < ResolvedModuleWithFailedLookupLocations > > ( ) ;
85
90
const perDirectoryResolvedModuleNames = createMap < Map < ResolvedModuleWithFailedLookupLocations > > ( ) ;
91
+ const nonRelaticeModuleNameCache = createMap < PerModuleNameCache > ( ) ;
92
+ const moduleResolutionCache = createModuleResolutionCacheWithMaps (
93
+ perDirectoryResolvedModuleNames ,
94
+ nonRelaticeModuleNameCache ,
95
+ getCurrentDirectory ( ) ,
96
+ resolutionHost . getCanonicalFileName
97
+ ) ;
86
98
87
99
const resolvedTypeReferenceDirectives = createMap < Map < ResolvedTypeReferenceDirectiveWithFailedLookupLocations > > ( ) ;
88
100
const perDirectoryResolvedTypeReferenceDirectives = createMap < Map < ResolvedTypeReferenceDirectiveWithFailedLookupLocations > > ( ) ;
89
101
90
- const getCurrentDirectory = memoize ( ( ) => resolutionHost . getCurrentDirectory ( ) ) ;
91
- const cachedDirectoryStructureHost = resolutionHost . getCachedDirectoryStructureHost ( ) ;
92
-
93
102
/**
94
103
* These are the extensions that failed lookup files will have by default,
95
104
* any other extension of failed lookup will be store that path in custom failed lookup path
@@ -173,6 +182,7 @@ namespace ts {
173
182
174
183
function clearPerDirectoryResolutions ( ) {
175
184
perDirectoryResolvedModuleNames . clear ( ) ;
185
+ nonRelaticeModuleNameCache . clear ( ) ;
176
186
perDirectoryResolvedTypeReferenceDirectives . clear ( ) ;
177
187
}
178
188
@@ -189,7 +199,7 @@ namespace ts {
189
199
}
190
200
191
201
function resolveModuleName ( moduleName : string , containingFile : string , compilerOptions : CompilerOptions , host : ModuleResolutionHost ) : ResolvedModuleWithFailedLookupLocations {
192
- const primaryResult = ts . resolveModuleName ( moduleName , containingFile , compilerOptions , host ) ;
202
+ const primaryResult = ts . resolveModuleName ( moduleName , containingFile , compilerOptions , host , moduleResolutionCache ) ;
193
203
// return result immediately only if global cache support is not enabled or if it is .ts, .tsx or .d.ts
194
204
if ( ! resolutionHost . getGlobalCache ) {
195
205
return primaryResult ;
@@ -248,17 +258,11 @@ namespace ts {
248
258
perDirectoryResolution . set ( name , resolution ) ;
249
259
}
250
260
resolutionsInFile . set ( name , resolution ) ;
251
- if ( resolution . failedLookupLocations ) {
252
- if ( existingResolution && existingResolution . failedLookupLocations ) {
253
- watchAndStopWatchDiffFailedLookupLocations ( resolution , existingResolution ) ;
254
- }
255
- else {
256
- watchFailedLookupLocationOfResolution ( resolution , 0 ) ;
257
- }
258
- }
259
- else if ( existingResolution ) {
261
+ watchFailedLookupLocationOfResolution ( resolution ) ;
262
+ if ( existingResolution ) {
260
263
stopWatchFailedLookupLocationOfResolution ( existingResolution ) ;
261
264
}
265
+
262
266
if ( logChanges && filesWithChangedSetOfUnresolvedImports && ! resolutionIsEqualTo ( existingResolution , resolution ) ) {
263
267
filesWithChangedSetOfUnresolvedImports . push ( path ) ;
264
268
// reset log changes to avoid recording the same file multiple times
@@ -390,80 +394,98 @@ namespace ts {
390
394
return fileExtensionIsOneOf ( path , failedLookupDefaultExtensions ) ;
391
395
}
392
396
393
- function watchAndStopWatchDiffFailedLookupLocations ( resolution : ResolutionWithFailedLookupLocations , existingResolution : ResolutionWithFailedLookupLocations ) {
394
- const failedLookupLocations = resolution . failedLookupLocations ;
395
- const existingFailedLookupLocations = existingResolution . failedLookupLocations ;
396
- for ( let index = 0 ; index < failedLookupLocations . length ; index ++ ) {
397
- if ( index === existingFailedLookupLocations . length ) {
398
- // Additional failed lookup locations, watch from this index
399
- watchFailedLookupLocationOfResolution ( resolution , index ) ;
400
- return ;
401
- }
402
- else if ( failedLookupLocations [ index ] !== existingFailedLookupLocations [ index ] ) {
403
- // Different failed lookup locations,
404
- // Watch new resolution failed lookup locations from this index and
405
- // stop watching existing resolutions from this index
406
- watchFailedLookupLocationOfResolution ( resolution , index ) ;
407
- stopWatchFailedLookupLocationOfResolutionFrom ( existingResolution , index ) ;
408
- return ;
409
- }
397
+ function watchFailedLookupLocationOfResolution ( resolution : ResolutionWithFailedLookupLocations ) {
398
+ // No need to set the resolution refCount
399
+ if ( ! resolution . failedLookupLocations || ! resolution . failedLookupLocations . length ) {
400
+ return ;
410
401
}
411
402
412
- // All new failed lookup locations are already watched (and are same),
413
- // Stop watching failed lookup locations of existing resolution after failed lookup locations length
414
- stopWatchFailedLookupLocationOfResolutionFrom ( existingResolution , failedLookupLocations . length ) ;
415
- }
403
+ if ( resolution . refCount !== undefined ) {
404
+ resolution . refCount ++ ;
405
+ return ;
406
+ }
416
407
417
- function watchFailedLookupLocationOfResolution ( { failedLookupLocations } : ResolutionWithFailedLookupLocations , startIndex : number ) {
418
- for ( let i = startIndex ; i < failedLookupLocations . length ; i ++ ) {
419
- const failedLookupLocation = failedLookupLocations [ i ] ;
408
+ resolution . refCount = 1 ;
409
+ const { failedLookupLocations } = resolution ;
410
+ let setAtRoot = false ;
411
+ for ( const failedLookupLocation of failedLookupLocations ) {
420
412
const failedLookupLocationPath = resolutionHost . toPath ( failedLookupLocation ) ;
421
- // If the failed lookup location path is not one of the supported extensions,
422
- // store it in the custom path
423
- if ( ! isPathWithDefaultFailedLookupExtension ( failedLookupLocationPath ) ) {
424
- const refCount = customFailedLookupPaths . get ( failedLookupLocationPath ) || 0 ;
425
- customFailedLookupPaths . set ( failedLookupLocationPath , refCount + 1 ) ;
426
- }
427
413
const { dir, dirPath, ignore } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
428
414
if ( ! ignore ) {
429
- const dirWatcher = directoryWatchesOfFailedLookups . get ( dirPath ) ;
430
- if ( dirWatcher ) {
431
- dirWatcher . refCount ++ ;
415
+ // If the failed lookup location path is not one of the supported extensions,
416
+ // store it in the custom path
417
+ if ( ! isPathWithDefaultFailedLookupExtension ( failedLookupLocationPath ) ) {
418
+ const refCount = customFailedLookupPaths . get ( failedLookupLocationPath ) || 0 ;
419
+ customFailedLookupPaths . set ( failedLookupLocationPath , refCount + 1 ) ;
420
+ }
421
+ if ( dirPath === rootPath ) {
422
+ setAtRoot = true ;
432
423
}
433
424
else {
434
- directoryWatchesOfFailedLookups . set ( dirPath , { watcher : createDirectoryWatcher ( dir , dirPath ) , refCount : 1 } ) ;
425
+ setDirectoryWatcher ( dir , dirPath ) ;
435
426
}
436
427
}
437
428
}
429
+
430
+ if ( setAtRoot ) {
431
+ setDirectoryWatcher ( rootDir , rootPath ) ;
432
+ }
438
433
}
439
434
440
- function stopWatchFailedLookupLocationOfResolution ( resolution : ResolutionWithFailedLookupLocations ) {
441
- if ( resolution . failedLookupLocations ) {
442
- stopWatchFailedLookupLocationOfResolutionFrom ( resolution , 0 ) ;
435
+ function setDirectoryWatcher ( dir : string , dirPath : Path ) {
436
+ const dirWatcher = directoryWatchesOfFailedLookups . get ( dirPath ) ;
437
+ if ( dirWatcher ) {
438
+ dirWatcher . refCount ++ ;
439
+ }
440
+ else {
441
+ directoryWatchesOfFailedLookups . set ( dirPath , { watcher : createDirectoryWatcher ( dir , dirPath ) , refCount : 1 } ) ;
443
442
}
444
443
}
445
444
446
- function stopWatchFailedLookupLocationOfResolutionFrom ( { failedLookupLocations } : ResolutionWithFailedLookupLocations , startIndex : number ) {
447
- for ( let i = startIndex ; i < failedLookupLocations . length ; i ++ ) {
448
- const failedLookupLocation = failedLookupLocations [ i ] ;
445
+ function stopWatchFailedLookupLocationOfResolution ( resolution : ResolutionWithFailedLookupLocations ) {
446
+ if ( ! resolution . failedLookupLocations || ! resolution . failedLookupLocations . length ) {
447
+ return ;
448
+ }
449
+
450
+ resolution . refCount ! -- ;
451
+ if ( resolution . refCount ) {
452
+ return ;
453
+ }
454
+
455
+ const { failedLookupLocations } = resolution ;
456
+ let removeAtRoot = false ;
457
+ for ( const failedLookupLocation of failedLookupLocations ) {
449
458
const failedLookupLocationPath = resolutionHost . toPath ( failedLookupLocation ) ;
450
- const refCount = customFailedLookupPaths . get ( failedLookupLocationPath ) ;
451
- if ( refCount ) {
452
- if ( refCount === 1 ) {
453
- customFailedLookupPaths . delete ( failedLookupLocationPath ) ;
459
+ const { dirPath, ignore } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
460
+ if ( ! ignore ) {
461
+ const refCount = customFailedLookupPaths . get ( failedLookupLocationPath ) ;
462
+ if ( refCount ) {
463
+ if ( refCount === 1 ) {
464
+ customFailedLookupPaths . delete ( failedLookupLocationPath ) ;
465
+ }
466
+ else {
467
+ Debug . assert ( refCount > 1 ) ;
468
+ customFailedLookupPaths . set ( failedLookupLocationPath , refCount - 1 ) ;
469
+ }
470
+ }
471
+
472
+ if ( dirPath === rootPath ) {
473
+ removeAtRoot = true ;
454
474
}
455
475
else {
456
- Debug . assert ( refCount > 1 ) ;
457
- customFailedLookupPaths . set ( failedLookupLocationPath , refCount - 1 ) ;
476
+ removeDirectoryWatcher ( dirPath ) ;
458
477
}
459
478
}
460
- const { dirPath, ignore } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
461
- if ( ! ignore ) {
462
- const dirWatcher = directoryWatchesOfFailedLookups . get ( dirPath ) ;
463
- // Do not close the watcher yet since it might be needed by other failed lookup locations.
464
- dirWatcher . refCount -- ;
465
- }
466
479
}
480
+ if ( removeAtRoot ) {
481
+ removeDirectoryWatcher ( rootPath ) ;
482
+ }
483
+ }
484
+
485
+ function removeDirectoryWatcher ( dirPath : string ) {
486
+ const dirWatcher = directoryWatchesOfFailedLookups . get ( dirPath ) ;
487
+ // Do not close the watcher yet since it might be needed by other failed lookup locations.
488
+ dirWatcher . refCount -- ;
467
489
}
468
490
469
491
function createDirectoryWatcher ( directory : string , dirPath : Path ) {
0 commit comments