@@ -30,13 +30,6 @@ namespace ts {
30
30
isInvalidated ?: boolean ;
31
31
}
32
32
33
- interface DirectoryWatchesOfFailedLookup {
34
- /** watcher for the directory of failed lookup */
35
- watcher : FileWatcher ;
36
- /** map with key being the failed lookup location path and value being the actual location */
37
- mapLocations : Map < number > ;
38
- }
39
-
40
33
export interface ResolutionCacheHost extends ModuleResolutionHost {
41
34
toPath ( fileName : string ) : Path ;
42
35
getCompilationSettings ( ) : CompilerOptions ;
@@ -61,11 +54,10 @@ namespace ts {
61
54
const perDirectoryResolvedModuleNames = createMap < Map < ResolvedModuleWithFailedLookupLocations > > ( ) ;
62
55
const resolvedTypeReferenceDirectives = createMap < Map < ResolvedTypeReferenceDirectiveWithFailedLookupLocations > > ( ) ;
63
56
const perDirectoryResolvedTypeReferenceDirectives = createMap < Map < ResolvedTypeReferenceDirectiveWithFailedLookupLocations > > ( ) ;
64
-
65
57
const getCurrentDirectory = memoize ( ( ) => resolutionHost . getCurrentDirectory ( ) ) ;
66
58
67
- const directoryWatchesOfFailedLookups = createMap < DirectoryWatchesOfFailedLookup > ( ) ;
68
- const failedLookupLocationToDirPath = createMap < Path > ( ) ;
59
+ const directoryWatchesOfFailedLookups = createMap < FileWatcher > ( ) ;
60
+ let hasChangesInFailedLookupLocations = false ;
69
61
let rootDir : string ;
70
62
let rootPath : Path ;
71
63
@@ -101,9 +93,8 @@ namespace ts {
101
93
}
102
94
103
95
function clear ( ) {
104
- // Close all the watches for failed lookup locations, irrespective of refcounts for them since this is to clear the cache
105
- clearMap ( directoryWatchesOfFailedLookups , closeFileWatcherOf ) ;
106
- failedLookupLocationToDirPath . clear ( ) ;
96
+ clearMap ( directoryWatchesOfFailedLookups , closeFileWatcher ) ;
97
+ hasChangesInFailedLookupLocations = false ;
107
98
closeTypeRootsWatch ( ) ;
108
99
resolvedModuleNames . clear ( ) ;
109
100
resolvedTypeReferenceDirectives . clear ( ) ;
@@ -131,6 +122,18 @@ namespace ts {
131
122
}
132
123
133
124
function finishCachingPerDirectoryResolution ( ) {
125
+ if ( hasChangesInFailedLookupLocations ) {
126
+ const seenDirectories = createMap < true > ( ) ;
127
+ watchFailedLookupLocationForCache ( perDirectoryResolvedModuleNames , seenDirectories ) ;
128
+ watchFailedLookupLocationForCache ( perDirectoryResolvedTypeReferenceDirectives , seenDirectories ) ;
129
+ directoryWatchesOfFailedLookups . forEach ( ( watcher , path ) => {
130
+ if ( ! seenDirectories . has ( path ) ) {
131
+ watcher . close ( ) ;
132
+ }
133
+ } ) ;
134
+ hasChangesInFailedLookupLocations = false ;
135
+ }
136
+
134
137
perDirectoryResolvedModuleNames . clear ( ) ;
135
138
perDirectoryResolvedTypeReferenceDirectives . clear ( ) ;
136
139
}
@@ -202,8 +205,9 @@ namespace ts {
202
205
else {
203
206
resolution = loader ( name , containingFile , compilerOptions , resolutionHost ) ;
204
207
perDirectoryResolution . set ( name , resolution ) ;
208
+ hasChangesInFailedLookupLocations = hasChangesInFailedLookupLocations ||
209
+ resolution . failedLookupLocations !== ( existingResolution && existingResolution . failedLookupLocations ) ;
205
210
}
206
- updateFailedLookupLocationWatches ( resolution . failedLookupLocations , existingResolution && existingResolution . failedLookupLocations ) ;
207
211
}
208
212
newResolutions . set ( name , resolution ) ;
209
213
if ( logChanges && filesWithChangedSetOfUnresolvedImports && ! resolutionIsEqualTo ( existingResolution , resolution ) ) {
@@ -218,11 +222,6 @@ namespace ts {
218
222
resolvedModules . push ( getResult ( resolution ) ) ;
219
223
}
220
224
221
- // Close all the file watchers for the names that arent required any more
222
- if ( currentResolutionsInFile ) {
223
- clearMap ( currentResolutionsInFile , resolution => withFailedLookupLocations ( resolution . failedLookupLocations , closeFailedLookupLocationWatcher ) ) ;
224
- }
225
-
226
225
// replace old results with a new one
227
226
cache . set ( path , newResolutions ) ;
228
227
return resolvedModules ;
@@ -262,6 +261,7 @@ namespace ts {
262
261
}
263
262
264
263
function resolveTypeReferenceDirectives ( typeDirectiveNames : string [ ] , containingFile : string ) : ResolvedTypeReferenceDirective [ ] {
264
+ resolutionHost . writeLog ( `resolveTypeReferenceDirectives[${ resolvedTypeReferenceDirectives . size } "]: " + ${ containingFile } ` ) ;
265
265
return resolveNamesWithLocalCache (
266
266
typeDirectiveNames , containingFile ,
267
267
resolvedTypeReferenceDirectives , perDirectoryResolvedTypeReferenceDirectives ,
@@ -271,6 +271,7 @@ namespace ts {
271
271
}
272
272
273
273
function resolveModuleNames ( moduleNames : string [ ] , containingFile : string , logChanges : boolean ) : ResolvedModuleFull [ ] {
274
+ resolutionHost . writeLog ( `resolveModuleNames[${ resolvedModuleNames . size } "]: " + ${ containingFile } ` ) ;
274
275
return resolveNamesWithLocalCache (
275
276
moduleNames , containingFile ,
276
277
resolvedModuleNames , perDirectoryResolvedModuleNames ,
@@ -279,35 +280,19 @@ namespace ts {
279
280
) ;
280
281
}
281
282
282
- function watchFailedLookupLocation ( failedLookupLocation : string , failedLookupLocationPath : Path ) {
283
- const failedLocationDirPath = getDirectoryPath ( failedLookupLocationPath ) ;
284
- const cachedDirPath = failedLookupLocationToDirPath . get ( failedLocationDirPath ) ;
285
- if ( cachedDirPath ) {
286
- watchFailedLookupLocationInDirectory ( cachedDirPath , failedLookupLocationPath , /*dir*/ undefined ) ;
287
- return ;
288
- }
283
+ function isNodeModulesDirectory ( dirPath : Path ) {
284
+ return endsWith ( dirPath , "/node_modules" ) ;
285
+ }
289
286
287
+ type DirectoryOfFailedLookupWatch = { dir : string ; dirPath : Path ; } ;
288
+ function getDirectoryToWatchFailedLookupLocation ( failedLookupLocation : string , failedLookupLocationPath : Path ) : DirectoryOfFailedLookupWatch {
290
289
if ( isInDirectoryPath ( rootPath , failedLookupLocationPath ) ) {
291
- // Watch in directory of rootPath
292
- failedLookupLocationToDirPath . set ( failedLocationDirPath , rootPath ) ;
293
- watchFailedLookupLocationInDirectory ( rootPath , failedLookupLocationPath , rootDir ) ;
294
- return ;
290
+ return { dir : rootDir , dirPath : rootPath } ;
295
291
}
296
292
297
- const { dir, dirPath } = getDirectoryToWatchWhenNotInRootPath (
298
- getDirectoryPath ( getNormalizedAbsolutePath ( failedLookupLocation , getCurrentDirectory ( ) ) ) ,
299
- getDirectoryPath ( failedLookupLocationPath )
300
- ) ;
301
- failedLookupLocationToDirPath . set ( failedLocationDirPath , dirPath ) ;
302
- watchFailedLookupLocationInDirectory ( dirPath , failedLookupLocationPath , dir ) ;
303
- }
304
-
305
- function isNodeModulesDirectory ( dirPath : Path ) {
306
- const nodemodules = "/node_modules" ;
307
- return endsWith ( dirPath , nodemodules ) ;
308
- }
293
+ let dir = getDirectoryPath ( getNormalizedAbsolutePath ( failedLookupLocation , getCurrentDirectory ( ) ) ) ;
294
+ let dirPath = getDirectoryPath ( failedLookupLocationPath ) ;
309
295
310
- function getDirectoryToWatchWhenNotInRootPath ( dir : string , dirPath : Path ) : { dir : string , dirPath : Path } {
311
296
// If the directory is node_modules use it to watch
312
297
if ( isNodeModulesDirectory ( dirPath ) ) {
313
298
return { dir, dirPath } ;
@@ -337,21 +322,22 @@ namespace ts {
337
322
return { dir, dirPath } ;
338
323
}
339
324
340
- function watchFailedLookupLocationInDirectory ( dirPath : Path , failedLookupLocationPath : Path , dir : string | undefined ) {
341
- const watches = directoryWatchesOfFailedLookups . get ( dirPath ) ;
342
- if ( watches ) {
343
- const existingCount = watches . mapLocations . get ( failedLookupLocationPath ) || 0 ;
344
- watches . mapLocations . set ( failedLookupLocationPath , existingCount + 1 ) ;
345
- }
346
- else {
347
- Debug . assert ( dir !== undefined ) ;
348
- const mapLocations = createMap < number > ( ) ;
349
- mapLocations . set ( failedLookupLocationPath , 1 ) ;
350
- directoryWatchesOfFailedLookups . set ( dirPath , {
351
- watcher : createDirectoryWatcher ( dir , dirPath ) ,
352
- mapLocations
353
- } ) ;
354
- }
325
+ function watchFailedLookupLocationForCache < T extends NameResolutionWithFailedLookupLocations > (
326
+ cache : Map < Map < T > > , seenDirectories : Map < true >
327
+ ) {
328
+ cache . forEach ( value => value && value . forEach (
329
+ resolution => forEach ( resolution && resolution . failedLookupLocations ,
330
+ failedLookupLocation => {
331
+ const { dir, dirPath } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , resolutionHost . toPath ( failedLookupLocation ) ) ;
332
+ if ( ! seenDirectories . has ( dirPath ) ) {
333
+ if ( ! directoryWatchesOfFailedLookups . has ( dirPath ) ) {
334
+ directoryWatchesOfFailedLookups . set ( dirPath , createDirectoryWatcher ( dir , dirPath ) ) ;
335
+ }
336
+ seenDirectories . set ( dirPath , true ) ;
337
+ }
338
+ }
339
+ )
340
+ ) ) ;
355
341
}
356
342
357
343
function createDirectoryWatcher ( directory : string , dirPath : Path ) {
@@ -365,62 +351,18 @@ namespace ts {
365
351
// If the files are added to project root or node_modules directory, always run through the invalidation process
366
352
// Otherwise run through invalidation only if adding to the immediate directory
367
353
if ( dirPath === rootPath || isNodeModulesDirectory ( dirPath ) || getDirectoryPath ( fileOrFolderPath ) === dirPath ) {
368
- // If the location results in update to failed lookup, schedule program update
369
- if ( dirPath === fileOrFolderPath ) {
370
- if ( onAddOrRemoveDirectoryOfFailedLookup ( dirPath ) ) {
371
- resolutionHost . onInvalidatedResolution ( ) ;
372
- }
373
- }
374
- else if ( onFileAddOrRemoveInDirectoryOfFailedLookup ( dirPath , fileOrFolderPath ) ) {
354
+ const isChangedFailedLookupLocation : ( location : string ) => boolean = dirPath === fileOrFolderPath ?
355
+ // If the file watched directory is created/deleted invalidate any resolution has failed lookup in this directory
356
+ location => isInDirectoryPath ( dirPath , resolutionHost . toPath ( location ) ) :
357
+ // Otherwise only the resolutions referencing the file or folder added
358
+ location => resolutionHost . toPath ( location ) === fileOrFolderPath ;
359
+ if ( invalidateResolutionOfFailedLookupLocation ( isChangedFailedLookupLocation ) ) {
375
360
resolutionHost . onInvalidatedResolution ( ) ;
376
361
}
377
362
}
378
363
} , WatchDirectoryFlags . Recursive ) ;
379
364
}
380
365
381
- function closeFailedLookupLocationWatcher ( _failedLookupLocation : string , failedLookupLocationPath : Path ) {
382
- const failedLookupDirectory = getDirectoryPath ( failedLookupLocationPath ) ;
383
- const dirPath = failedLookupLocationToDirPath . get ( failedLookupDirectory ) ;
384
- const watches = directoryWatchesOfFailedLookups . get ( dirPath ) ;
385
- const refCount = watches . mapLocations . get ( failedLookupLocationPath ) ;
386
- if ( refCount === 1 ) {
387
- // If this was last failed lookup location being tracked by the dir watcher,
388
- // remove the failed lookup location path to dir Path entry
389
- watches . mapLocations . delete ( failedLookupLocationPath ) ;
390
-
391
- // If there are no more files that need this watcher alive, close the watcher
392
- if ( watches . mapLocations . size === 0 ) {
393
- watches . watcher . close ( ) ;
394
- directoryWatchesOfFailedLookups . delete ( dirPath ) ;
395
- failedLookupLocationToDirPath . delete ( failedLookupDirectory ) ;
396
- }
397
- }
398
- else {
399
- watches . mapLocations . set ( failedLookupLocationPath , refCount - 1 ) ;
400
- }
401
- }
402
-
403
- type FailedLookupLocationAction = ( failedLookupLocation : string , failedLookupLocationPath : Path ) => void ;
404
- function withFailedLookupLocations ( failedLookupLocations : ReadonlyArray < string > | undefined , fn : FailedLookupLocationAction , startIndex ?: number ) {
405
- if ( failedLookupLocations ) {
406
- for ( let i = startIndex || 0 ; i < failedLookupLocations . length ; i ++ ) {
407
- fn ( failedLookupLocations [ i ] , resolutionHost . toPath ( failedLookupLocations [ i ] ) ) ;
408
- }
409
- }
410
- }
411
-
412
- function updateFailedLookupLocationWatches ( failedLookupLocations : ReadonlyArray < string > | undefined , existingFailedLookupLocations : ReadonlyArray < string > | undefined ) {
413
- const index = existingFailedLookupLocations && failedLookupLocations ?
414
- findDiffIndex ( failedLookupLocations , existingFailedLookupLocations ) :
415
- 0 ;
416
-
417
- // Watch all the failed lookup locations
418
- withFailedLookupLocations ( failedLookupLocations , watchFailedLookupLocation , index ) ;
419
-
420
- // Close existing watches for the failed locations
421
- withFailedLookupLocations ( existingFailedLookupLocations , closeFailedLookupLocationWatcher , index ) ;
422
- }
423
-
424
366
function invalidateResolutionCacheOfDeletedFile < T extends NameResolutionWithFailedLookupLocations , R > (
425
367
deletedFilePath : Path ,
426
368
cache : Map < Map < T > > ,
@@ -429,9 +371,8 @@ namespace ts {
429
371
cache . forEach ( ( value , path ) => {
430
372
if ( path === deletedFilePath ) {
431
373
cache . delete ( path ) ;
432
- value . forEach ( resolution => {
433
- withFailedLookupLocations ( resolution . failedLookupLocations , closeFailedLookupLocationWatcher ) ;
434
- } ) ;
374
+ hasChangesInFailedLookupLocations = hasChangesInFailedLookupLocations ||
375
+ value && forEachEntry ( value , resolution => ! ! resolution . failedLookupLocations ) ;
435
376
}
436
377
else if ( value ) {
437
378
value . forEach ( resolution => {
@@ -449,7 +390,12 @@ namespace ts {
449
390
} ) ;
450
391
}
451
392
452
- function invalidateResolutionCacheOfChangedFailedLookupLocation < T extends NameResolutionWithFailedLookupLocations > (
393
+ function invalidateResolutionOfFile ( filePath : Path ) {
394
+ invalidateResolutionCacheOfDeletedFile ( filePath , resolvedModuleNames , m => m . resolvedModule , r => r . resolvedFileName ) ;
395
+ invalidateResolutionCacheOfDeletedFile ( filePath , resolvedTypeReferenceDirectives , m => m . resolvedTypeReferenceDirective , r => r . resolvedFileName ) ;
396
+ }
397
+
398
+ function invalidateResolutionCacheOfFailedLookupLocation < T extends NameResolutionWithFailedLookupLocations > (
453
399
cache : Map < Map < T > > ,
454
400
isChangedFailedLookupLocation : ( location : string ) => boolean
455
401
) {
@@ -466,29 +412,11 @@ namespace ts {
466
412
} ) ;
467
413
}
468
414
469
- function invalidateResolutionOfFile ( filePath : Path ) {
470
- invalidateResolutionCacheOfDeletedFile ( filePath , resolvedModuleNames , m => m . resolvedModule , r => r . resolvedFileName ) ;
471
- invalidateResolutionCacheOfDeletedFile ( filePath , resolvedTypeReferenceDirectives , m => m . resolvedTypeReferenceDirective , r => r . resolvedFileName ) ;
472
- }
473
-
474
- function onFileAddOrRemoveInDirectoryOfFailedLookup ( dirPath : Path , fileOrFolder : Path ) {
475
- const watches = directoryWatchesOfFailedLookups . get ( dirPath ) ;
476
- if ( watches . mapLocations . has ( fileOrFolder ) ) {
477
- const invalidatedFiles = filesWithInvalidatedResolutions && filesWithInvalidatedResolutions . size ;
478
- const isFileOrFolder : ( location : string ) => boolean = location => resolutionHost . toPath ( location ) === fileOrFolder ;
479
- invalidateResolutionCacheOfChangedFailedLookupLocation ( resolvedModuleNames , isFileOrFolder ) ;
480
- invalidateResolutionCacheOfChangedFailedLookupLocation ( resolvedTypeReferenceDirectives , isFileOrFolder ) ;
481
- return filesWithInvalidatedResolutions && filesWithInvalidatedResolutions . size !== invalidatedFiles ;
482
- }
483
- return false ;
484
- }
485
-
486
- function onAddOrRemoveDirectoryOfFailedLookup ( dirPath : Path ) {
487
- const invalidatedFiles = filesWithInvalidatedResolutions && filesWithInvalidatedResolutions . size ;
488
- const isInDirPath : ( location : string ) => boolean = location => isInDirectoryPath ( dirPath , resolutionHost . toPath ( location ) ) ;
489
- invalidateResolutionCacheOfChangedFailedLookupLocation ( resolvedModuleNames , isInDirPath ) ;
490
- invalidateResolutionCacheOfChangedFailedLookupLocation ( resolvedTypeReferenceDirectives , isInDirPath ) ;
491
- filesWithInvalidatedResolutions && filesWithInvalidatedResolutions . size !== invalidatedFiles ;
415
+ function invalidateResolutionOfFailedLookupLocation ( isChangedFailedLookupLocation : ( location : string ) => boolean ) {
416
+ const invalidatedFilesCount = filesWithInvalidatedResolutions && filesWithInvalidatedResolutions . size ;
417
+ invalidateResolutionCacheOfFailedLookupLocation ( resolvedModuleNames , isChangedFailedLookupLocation ) ;
418
+ invalidateResolutionCacheOfFailedLookupLocation ( resolvedTypeReferenceDirectives , isChangedFailedLookupLocation ) ;
419
+ return filesWithInvalidatedResolutions && filesWithInvalidatedResolutions . size !== invalidatedFilesCount ;
492
420
}
493
421
494
422
function closeTypeRootsWatch ( ) {
0 commit comments