@@ -14,7 +14,7 @@ namespace ts {
1414 resolveTypeReferenceDirectives ( typeDirectiveNames : string [ ] , containingFile : string ) : ResolvedTypeReferenceDirective [ ] ;
1515
1616 invalidateResolutionOfFile ( filePath : Path ) : void ;
17- invalidateResolutionOfChangedFailedLookupLocation ( failedLookupLocationPath : Path ) : void ;
17+ onFileAddOrRemoveInDirectoryOfFailedLookup ( fileOrFolder : Path ) : boolean ;
1818
1919 createHasInvalidatedResolution ( ) : HasInvalidatedResolution ;
2020
@@ -26,15 +26,17 @@ namespace ts {
2626 isInvalidated ?: boolean ;
2727 }
2828
29- interface FailedLookupLocationsWatcher {
29+ interface DirectoryWatchesOfFailedLookup {
30+ /** watcher for the directory of failed lookup */
3031 watcher : FileWatcher ;
31- refCount : number ;
32+ /** map with key being the failed lookup location path and value being the actual location */
33+ mapLocations : MultiMap < string > ;
3234 }
3335
3436 export function createResolutionCache (
3537 toPath : ( fileName : string ) => Path ,
3638 getCompilerOptions : ( ) => CompilerOptions ,
37- watchForFailedLookupLocation : ( failedLookupLocation : string , failedLookupLocationPath : Path ) => FileWatcher ,
39+ watchDirectoryOfFailedLookupLocation : ( directory : string ) => FileWatcher ,
3840 log : ( s : string ) => void ,
3941 projectName ?: string ,
4042 getGlobalCache ?: ( ) => string | undefined ) : ResolutionCache {
@@ -49,7 +51,7 @@ namespace ts {
4951 const resolvedModuleNames = createMap < Map < ResolvedModuleWithFailedLookupLocations > > ( ) ;
5052 const resolvedTypeReferenceDirectives = createMap < Map < ResolvedTypeReferenceDirectiveWithFailedLookupLocations > > ( ) ;
5153
52- const failedLookupLocationsWatches = createMap < FailedLookupLocationsWatcher > ( ) ;
54+ const directoryWatchesOfFailedLookups = createMap < DirectoryWatchesOfFailedLookup > ( ) ;
5355
5456 return {
5557 setModuleResolutionHost,
@@ -58,7 +60,7 @@ namespace ts {
5860 resolveModuleNames,
5961 resolveTypeReferenceDirectives,
6062 invalidateResolutionOfFile,
61- invalidateResolutionOfChangedFailedLookupLocation ,
63+ onFileAddOrRemoveInDirectoryOfFailedLookup ,
6264 createHasInvalidatedResolution,
6365 clear
6466 } ;
@@ -69,7 +71,7 @@ namespace ts {
6971
7072 function clear ( ) {
7173 // Close all the watches for failed lookup locations, irrespective of refcounts for them since this is to clear the cache
72- clearMap ( failedLookupLocationsWatches , closeFileWatcherOf ) ;
74+ clearMap ( directoryWatchesOfFailedLookups , closeFileWatcherOf ) ;
7375 resolvedModuleNames . clear ( ) ;
7476 resolvedTypeReferenceDirectives . clear ( ) ;
7577 }
@@ -203,43 +205,51 @@ namespace ts {
203205 }
204206
205207 function watchFailedLookupLocation ( failedLookupLocation : string , failedLookupLocationPath : Path ) {
206- const failedLookupLocationWatcher = failedLookupLocationsWatches . get ( failedLookupLocationPath ) ;
207- if ( failedLookupLocationWatcher ) {
208- failedLookupLocationWatcher . refCount ++ ;
209- log ( `Watcher: FailedLookupLocations: Status: Using existing watcher: Location: ${ failedLookupLocation } ` ) ;
208+ const dirPath = getDirectoryPath ( failedLookupLocationPath ) ;
209+ const watches = directoryWatchesOfFailedLookups . get ( dirPath ) ;
210+ if ( watches ) {
211+ watches . mapLocations . add ( failedLookupLocationPath , failedLookupLocation ) ;
210212 }
211213 else {
212- const watcher = watchForFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
213- failedLookupLocationsWatches . set ( failedLookupLocationPath , { watcher, refCount : 1 } ) ;
214+ const mapLocations = createMultiMap < string > ( ) ;
215+ mapLocations . add ( failedLookupLocationPath , failedLookupLocation ) ;
216+ directoryWatchesOfFailedLookups . set ( dirPath , {
217+ watcher : watchDirectoryOfFailedLookupLocation ( getDirectoryPath ( failedLookupLocation ) ) ,
218+ mapLocations
219+ } ) ;
214220 }
215221 }
216222
217223 function closeFailedLookupLocationWatcher ( failedLookupLocation : string , failedLookupLocationPath : Path ) {
218- const failedLookupLocationWatcher = failedLookupLocationsWatches . get ( failedLookupLocationPath ) ;
219- Debug . assert ( ! ! failedLookupLocationWatcher ) ;
220- failedLookupLocationWatcher . refCount -- ;
221- if ( failedLookupLocationWatcher . refCount ) {
222- log ( `Watcher: FailedLookupLocations: Status: Removing existing watcher: Location: ${ failedLookupLocation } ` ) ;
223- }
224- else {
225- failedLookupLocationWatcher . watcher . close ( ) ;
226- failedLookupLocationsWatches . delete ( failedLookupLocationPath ) ;
224+ const dirPath = getDirectoryPath ( failedLookupLocationPath ) ;
225+ const watches = directoryWatchesOfFailedLookups . get ( dirPath ) ;
226+ watches . mapLocations . remove ( failedLookupLocationPath , failedLookupLocation ) ;
227+ if ( watches . mapLocations . size === 0 ) {
228+ watches . watcher . close ( ) ;
229+ directoryWatchesOfFailedLookups . delete ( dirPath ) ;
227230 }
228231 }
229232
230233 type FailedLookupLocationAction = ( failedLookupLocation : string , failedLookupLocationPath : Path ) => void ;
231- function withFailedLookupLocations ( failedLookupLocations : ReadonlyArray < string > | undefined , fn : FailedLookupLocationAction ) {
232- forEach ( failedLookupLocations , failedLookupLocation => {
233- fn ( failedLookupLocation , toPath ( failedLookupLocation ) ) ;
234- } ) ;
234+ function withFailedLookupLocations ( failedLookupLocations : ReadonlyArray < string > | undefined , fn : FailedLookupLocationAction , startIndex ?: number ) {
235+ if ( failedLookupLocations ) {
236+ for ( let i = startIndex || 0 ; i < failedLookupLocations . length ; i ++ ) {
237+ fn ( failedLookupLocations [ i ] , toPath ( failedLookupLocations [ i ] ) ) ;
238+ }
239+ }
235240 }
236241
237242 function updateFailedLookupLocationWatches ( failedLookupLocations : ReadonlyArray < string > | undefined , existingFailedLookupLocations : ReadonlyArray < string > | undefined ) {
243+ log ( `Resolution cache: Updating...` ) ;
244+ const index = existingFailedLookupLocations && failedLookupLocations ?
245+ findDiffIndex ( failedLookupLocations , existingFailedLookupLocations ) :
246+ 0 ;
247+
238248 // Watch all the failed lookup locations
239- withFailedLookupLocations ( failedLookupLocations , watchFailedLookupLocation ) ;
249+ withFailedLookupLocations ( failedLookupLocations , watchFailedLookupLocation , index ) ;
240250
241251 // Close existing watches for the failed locations
242- withFailedLookupLocations ( existingFailedLookupLocations , closeFailedLookupLocationWatcher ) ;
252+ withFailedLookupLocations ( existingFailedLookupLocations , closeFailedLookupLocationWatcher , index ) ;
243253 }
244254
245255 function invalidateResolutionCacheOfDeletedFile < T extends NameResolutionWithFailedLookupLocations , R > (
@@ -291,9 +301,15 @@ namespace ts {
291301 invalidateResolutionCacheOfDeletedFile ( filePath , resolvedTypeReferenceDirectives , m => m . resolvedTypeReferenceDirective , r => r . resolvedFileName ) ;
292302 }
293303
294- function invalidateResolutionOfChangedFailedLookupLocation ( failedLookupLocationPath : Path ) {
295- invalidateResolutionCacheOfChangedFailedLookupLocation ( failedLookupLocationPath , resolvedModuleNames ) ;
296- invalidateResolutionCacheOfChangedFailedLookupLocation ( failedLookupLocationPath , resolvedTypeReferenceDirectives ) ;
304+ function onFileAddOrRemoveInDirectoryOfFailedLookup ( fileOrFolder : Path ) {
305+ const dirPath = getDirectoryPath ( fileOrFolder ) ;
306+ const watches = directoryWatchesOfFailedLookups . get ( dirPath ) ;
307+ const isFailedLookupFile = watches . mapLocations . has ( fileOrFolder ) ;
308+ if ( isFailedLookupFile ) {
309+ invalidateResolutionCacheOfChangedFailedLookupLocation ( fileOrFolder , resolvedModuleNames ) ;
310+ invalidateResolutionCacheOfChangedFailedLookupLocation ( fileOrFolder , resolvedTypeReferenceDirectives ) ;
311+ }
312+ return isFailedLookupFile ;
297313 }
298314 }
299315}
0 commit comments