@@ -43,7 +43,7 @@ namespace ts.server.typingsInstaller {
4343 private readonly packageNameToTypingLocation : Map < JsTyping . CachedTyping > = createMap < JsTyping . CachedTyping > ( ) ;
4444 private readonly missingTypingsSet : Map < true > = createMap < true > ( ) ;
4545 private readonly knownCachesSet : Map < true > = createMap < true > ( ) ;
46- private readonly projectWatchers : Map < FileWatcher [ ] > = createMap < FileWatcher [ ] > ( ) ;
46+ private readonly projectWatchers = createMap < Map < FileWatcher > > ( ) ;
4747 private safeList : JsTyping . SafeList | undefined ;
4848 readonly pendingRunRequests : PendingRequest [ ] = [ ] ;
4949
@@ -80,10 +80,7 @@ namespace ts.server.typingsInstaller {
8080 }
8181 return ;
8282 }
83- for ( const w of watchers ) {
84- w . close ( ) ;
85- }
86-
83+ clearMap ( watchers , closeFileWatcher ) ;
8784 this . projectWatchers . delete ( projectName ) ;
8885
8986 if ( this . log . isEnabled ( ) ) {
@@ -345,27 +342,49 @@ namespace ts.server.typingsInstaller {
345342
346343 private watchFiles ( projectName : string , files : string [ ] ) {
347344 if ( ! files . length ) {
345+ // shut down existing watchers
346+ this . closeWatchers ( projectName ) ;
348347 return ;
349348 }
350- // shut down existing watchers
351- this . closeWatchers ( projectName ) ;
349+
350+ let watchers = this . projectWatchers . get ( projectName ) ;
351+ if ( ! watchers ) {
352+ watchers = createMap ( ) ;
353+ this . projectWatchers . set ( projectName , watchers ) ;
354+ }
352355
353356 // handler should be invoked once for the entire set of files since it will trigger full rediscovery of typings
354357 let isInvoked = false ;
355- const watchers : FileWatcher [ ] = [ ] ;
356- for ( const file of files ) {
357- const w = this . installTypingHost . watchFile ( file , f => {
358- if ( this . log . isEnabled ( ) ) {
359- this . log . writeLine ( `Got FS notification for ${ f } , handler is already invoked '${ isInvoked } '` ) ;
360- }
361- if ( ! isInvoked ) {
362- this . sendResponse ( { projectName, kind : ActionInvalidate } ) ;
363- isInvoked = true ;
364- }
365- } , /*pollingInterval*/ 2000 ) ;
366- watchers . push ( w ) ;
367- }
368- this . projectWatchers . set ( projectName , watchers ) ;
358+ const isLoggingEnabled = this . log . isEnabled ( ) ;
359+ mutateMap (
360+ watchers ,
361+ arrayToSet ( files ) ,
362+ {
363+ // Watch the missing files
364+ createNewValue : file => {
365+ if ( isLoggingEnabled ) {
366+ this . log . writeLine ( `FileWatcher:: Added:: WatchInfo: ${ file } ` ) ;
367+ }
368+ const watcher = this . installTypingHost . watchFile ( file , ( f , eventKind ) => {
369+ if ( isLoggingEnabled ) {
370+ this . log . writeLine ( `FileWatcher:: Triggered with ${ f } eventKind: ${ FileWatcherEventKind [ eventKind ] } :: WatchInfo: ${ file } :: handler is already invoked '${ isInvoked } '` ) ;
371+ }
372+ if ( ! isInvoked ) {
373+ this . sendResponse ( { projectName, kind : ActionInvalidate } ) ;
374+ isInvoked = true ;
375+ }
376+ } , /*pollingInterval*/ 2000 ) ;
377+ return isLoggingEnabled ? {
378+ close : ( ) => {
379+ this . log . writeLine ( `FileWatcher:: Closed:: WatchInfo: ${ file } ` ) ;
380+ }
381+ } : watcher ;
382+ } ,
383+ // Files that are no longer missing (e.g. because they are no longer required)
384+ // should no longer be watched.
385+ onDeleteValue : closeFileWatcher
386+ }
387+ ) ;
369388 }
370389
371390 private createSetTypings ( request : DiscoverTypings , typings : string [ ] ) : SetTypings {
0 commit comments