@@ -475,7 +475,7 @@ namespace ts {
475475
476476 const cache = createMap < HostDirectoryWatcher > ( ) ;
477477 const callbackCache = createMultiMap < { dirName : string ; callback : DirectoryWatcherCallback ; } > ( ) ;
478- const cacheToUpdateChildWatches = createMap < { dirName : string ; options : WatchOptions | undefined ; } > ( ) ;
478+ const cacheToUpdateChildWatches = createMap < { dirName : string ; options : WatchOptions | undefined ; fileNames : string [ ] ; } > ( ) ;
479479 let timerToUpdateChildWatches : any ;
480480
481481 const filePathComparer = getStringComparer ( ! host . useCaseSensitiveFileNames ) ;
@@ -538,9 +538,12 @@ namespace ts {
538538 } ;
539539 }
540540
541- function invokeCallbacks ( dirPath : Path , fileNameOrInvokeMap : string | Map < true > ) {
541+ type InvokeMap = Map < string [ ] | true > ;
542+ function invokeCallbacks ( dirPath : Path , fileName : string ) : void ;
543+ function invokeCallbacks ( dirPath : Path , invokeMap : InvokeMap , fileNames : string [ ] | undefined ) : void ;
544+ function invokeCallbacks ( dirPath : Path , fileNameOrInvokeMap : string | InvokeMap , fileNames ?: string [ ] ) {
542545 let fileName : string | undefined ;
543- let invokeMap : Map < true > | undefined ;
546+ let invokeMap : InvokeMap | undefined ;
544547 if ( isString ( fileNameOrInvokeMap ) ) {
545548 fileName = fileNameOrInvokeMap ;
546549 }
@@ -549,10 +552,21 @@ namespace ts {
549552 }
550553 // Call the actual callback
551554 callbackCache . forEach ( ( callbacks , rootDirName ) => {
552- if ( invokeMap && invokeMap . has ( rootDirName ) ) return ;
555+ if ( invokeMap && invokeMap . get ( rootDirName ) === true ) return ;
553556 if ( rootDirName === dirPath || ( startsWith ( dirPath , rootDirName ) && dirPath [ rootDirName . length ] === directorySeparator ) ) {
554557 if ( invokeMap ) {
555- invokeMap . set ( rootDirName , true ) ;
558+ if ( fileNames ) {
559+ const existing = invokeMap . get ( rootDirName ) ;
560+ if ( existing ) {
561+ ( existing as string [ ] ) . push ( ...fileNames ) ;
562+ }
563+ else {
564+ invokeMap . set ( rootDirName , fileNames . slice ( ) ) ;
565+ }
566+ }
567+ else {
568+ invokeMap . set ( rootDirName , true ) ;
569+ }
556570 }
557571 else {
558572 callbacks . forEach ( ( { callback } ) => callback ( fileName ! ) ) ;
@@ -566,7 +580,7 @@ namespace ts {
566580 const parentWatcher = cache . get ( dirPath ) ;
567581 if ( parentWatcher && host . directoryExists ( dirName ) ) {
568582 // Schedule the update and postpone invoke for callbacks
569- scheduleUpdateChildWatches ( dirName , dirPath , options ) ;
583+ scheduleUpdateChildWatches ( dirName , dirPath , fileName , options ) ;
570584 return ;
571585 }
572586
@@ -575,9 +589,13 @@ namespace ts {
575589 removeChildWatches ( parentWatcher ) ;
576590 }
577591
578- function scheduleUpdateChildWatches ( dirName : string , dirPath : Path , options : WatchOptions | undefined ) {
579- if ( ! cacheToUpdateChildWatches . has ( dirPath ) ) {
580- cacheToUpdateChildWatches . set ( dirPath , { dirName, options } ) ;
592+ function scheduleUpdateChildWatches ( dirName : string , dirPath : Path , fileName : string , options : WatchOptions | undefined ) {
593+ const existing = cacheToUpdateChildWatches . get ( dirPath ) ;
594+ if ( existing ) {
595+ existing . fileNames . push ( fileName ) ;
596+ }
597+ else {
598+ cacheToUpdateChildWatches . set ( dirPath , { dirName, options, fileNames : [ fileName ] } ) ;
581599 }
582600 if ( timerToUpdateChildWatches ) {
583601 host . clearTimeout ( timerToUpdateChildWatches ) ;
@@ -590,22 +608,30 @@ namespace ts {
590608 timerToUpdateChildWatches = undefined ;
591609 sysLog ( `sysLog:: onTimerToUpdateChildWatches:: ${ cacheToUpdateChildWatches . size } ` ) ;
592610 const start = timestamp ( ) ;
593- const invokeMap = createMap < true > ( ) ;
611+ const invokeMap = createMap < string [ ] > ( ) ;
594612
595613 while ( ! timerToUpdateChildWatches && cacheToUpdateChildWatches . size ) {
596- const { value : [ dirPath , { dirName, options } ] , done } = cacheToUpdateChildWatches . entries ( ) . next ( ) ;
614+ const { value : [ dirPath , { dirName, options, fileNames } ] , done } = cacheToUpdateChildWatches . entries ( ) . next ( ) ;
597615 Debug . assert ( ! done ) ;
598616 cacheToUpdateChildWatches . delete ( dirPath ) ;
599617 // Because the child refresh is fresh, we would need to invalidate whole root directory being watched
600618 // to ensure that all the changes are reflected at this time
601- invokeCallbacks ( dirPath as Path , invokeMap ) ;
602- updateChildWatches ( dirName , dirPath as Path , options ) ;
619+ const hasChanges = updateChildWatches ( dirName , dirPath as Path , options ) ;
620+ invokeCallbacks ( dirPath as Path , invokeMap , hasChanges ? undefined : fileNames ) ;
603621 }
604622
605623 sysLog ( `sysLog:: invokingWatchers:: ${ timestamp ( ) - start } ms:: ${ cacheToUpdateChildWatches . size } ` ) ;
606624 callbackCache . forEach ( ( callbacks , rootDirName ) => {
607- if ( invokeMap . has ( rootDirName ) ) {
608- callbacks . forEach ( ( { callback, dirName } ) => callback ( dirName ) ) ;
625+ const existing = invokeMap . get ( rootDirName ) ;
626+ if ( existing ) {
627+ callbacks . forEach ( ( { callback, dirName } ) => {
628+ if ( isArray ( existing ) ) {
629+ existing . forEach ( callback ) ;
630+ }
631+ else {
632+ callback ( dirName ) ;
633+ }
634+ } ) ;
609635 }
610636 } ) ;
611637
@@ -623,34 +649,26 @@ namespace ts {
623649 }
624650 }
625651
626- function updateChildWatches ( dirName : string , dirPath : Path , options : WatchOptions | undefined ) {
652+ function updateChildWatches ( parentDir : string , parentDirPath : Path , options : WatchOptions | undefined ) {
627653 // Iterate through existing children and update the watches if needed
628- const parentWatcher = cache . get ( dirPath ) ;
629- if ( parentWatcher ) {
630- parentWatcher . childWatches = watchChildDirectories ( dirName , parentWatcher . childWatches , options ) ;
631- }
632- }
633-
634- /**
635- * Watch the directories in the parentDir
636- */
637- function watchChildDirectories ( parentDir : string , existingChildWatches : ChildWatches , options : WatchOptions | undefined ) : ChildWatches {
654+ const parentWatcher = cache . get ( parentDirPath ) ;
655+ if ( ! parentWatcher ) return false ;
638656 let newChildWatches : ChildDirectoryWatcher [ ] | undefined ;
639- enumerateInsertsAndDeletes < string , ChildDirectoryWatcher > (
657+ const hasChanges = enumerateInsertsAndDeletes < string , ChildDirectoryWatcher > (
640658 host . directoryExists ( parentDir ) ? mapDefined ( host . getAccessibleSortedChildDirectories ( parentDir ) , child => {
641659 const childFullName = getNormalizedAbsolutePath ( child , parentDir ) ;
642660 // Filter our the symbolic link directories since those arent included in recursive watch
643661 // which is same behaviour when recursive: true is passed to fs.watch
644662 return ! isIgnoredPath ( childFullName ) && filePathComparer ( childFullName , normalizePath ( host . realpath ( childFullName ) ) ) === Comparison . EqualTo ? childFullName : undefined ;
645663 } ) : emptyArray ,
646- existingChildWatches ,
664+ parentWatcher . childWatches ,
647665 ( child , childWatcher ) => filePathComparer ( child , childWatcher . dirName ) ,
648666 createAndAddChildDirectoryWatcher ,
649667 closeFileWatcher ,
650668 addChildDirectoryWatcher
651669 ) ;
652-
653- return newChildWatches || emptyArray ;
670+ parentWatcher . childWatches = newChildWatches || emptyArray ;
671+ return hasChanges ;
654672
655673 /**
656674 * Create new childDirectoryWatcher and add it to the new ChildDirectoryWatcher list
0 commit comments