@@ -24,7 +24,7 @@ namespace ts {
2424 interface WatchedFile {
2525 fileName : string ;
2626 callback : ( fileName : string , removed ?: boolean ) => void ;
27- mtime : Date ;
27+ mtime ? : Date ;
2828 }
2929
3030 export interface FileWatcher {
@@ -218,7 +218,7 @@ namespace ts {
218218
219219 // average async stat takes about 30 microseconds
220220 // set chunk size to do 30 files in < 1 millisecond
221- function createWatchedFileSet ( interval = 2500 , chunkSize = 30 ) {
221+ function createPollingWatchedFileSet ( interval = 2500 , chunkSize = 30 ) {
222222 let watchedFiles : WatchedFile [ ] = [ ] ;
223223 let nextFileToCheck = 0 ;
224224 let watchTimer : any ;
@@ -293,6 +293,50 @@ namespace ts {
293293 removeFile : removeFile
294294 } ;
295295 }
296+
297+ function createWatchedFileSet ( ) {
298+ let watchedDirectories : { [ path : string ] : FileWatcher } = { } ;
299+ let watchedFiles : { [ fileName : string ] : ( fileName : string , removed ?: boolean ) => void ; } = { } ;
300+
301+ function addFile ( fileName : string , callback : ( fileName : string , removed ?: boolean ) => void ) : WatchedFile {
302+ const file : WatchedFile = { fileName, callback } ;
303+ let watchedPaths = Object . keys ( watchedDirectories ) ;
304+ // Try to find parent paths that are already watched. If found, don't add directory watchers
305+ let watchedParentPaths = watchedPaths . filter ( path => fileName . indexOf ( path ) === 0 ) ;
306+ // If adding new watchers, try to find children paths that are already watched. If found, close them.
307+ if ( watchedParentPaths . length === 0 ) {
308+ let pathToWatch = ts . getDirectoryPath ( fileName ) ;
309+ for ( let watchedPath in watchedDirectories ) {
310+ if ( watchedPath . indexOf ( pathToWatch ) === 0 ) {
311+ watchedDirectories [ watchedPath ] . close ( ) ;
312+ delete watchedDirectories [ watchedPath ] ;
313+ }
314+ }
315+ watchedDirectories [ pathToWatch ] = _fs . watch (
316+ pathToWatch ,
317+ ( eventName : string , relativeFileName : string ) => fileEventHandler ( eventName , ts . normalizePath ( ts . combinePaths ( pathToWatch , relativeFileName ) ) )
318+ ) ;
319+ }
320+ watchedFiles [ fileName ] = callback ;
321+ return { fileName, callback }
322+ }
323+
324+ function removeFile ( file : WatchedFile ) {
325+ delete watchedFiles [ file . fileName ] ;
326+ }
327+
328+ function fileEventHandler ( eventName : string , fileName : string ) {
329+ if ( watchedFiles [ fileName ] ) {
330+ let callback = watchedFiles [ fileName ] ;
331+ callback ( fileName ) ;
332+ }
333+ }
334+
335+ return {
336+ addFile : addFile ,
337+ removeFile : removeFile
338+ }
339+ }
296340
297341 // REVIEW: for now this implementation uses polling.
298342 // The advantage of polling is that it works reliably
@@ -307,6 +351,7 @@ namespace ts {
307351 // changes for large reference sets? If so, do we want
308352 // to increase the chunk size or decrease the interval
309353 // time dynamically to match the large reference set?
354+ const pollingWatchedFileSet = createPollingWatchedFileSet ( ) ;
310355 const watchedFileSet = createWatchedFileSet ( ) ;
311356
312357 function isNode4OrLater ( ) : Boolean {
@@ -411,14 +456,10 @@ namespace ts {
411456 // and is more efficient than `fs.watchFile` (ref: https://github.com/nodejs/node/pull/2649
412457 // and https://github.com/Microsoft/TypeScript/issues/4643), therefore
413458 // if the current node.js version is newer than 4, use `fs.watch` instead.
414- if ( isNode4OrLater ( ) ) {
415- // Note: in node the callback of fs.watch is given only the relative file name as a parameter
416- return _fs . watch ( fileName , ( eventName : string , relativeFileName : string ) => callback ( fileName ) ) ;
417- }
418-
419- const watchedFile = watchedFileSet . addFile ( fileName , callback ) ;
459+ let fileSet = isNode4OrLater ( ) ? watchedFileSet : pollingWatchedFileSet ;
460+ const watchedFile = fileSet . addFile ( fileName , callback ) ;
420461 return {
421- close : ( ) => watchedFileSet . removeFile ( watchedFile )
462+ close : ( ) => fileSet . removeFile ( watchedFile )
422463 } ;
423464 } ,
424465 watchDirectory : ( path , callback , recursive ) => {
0 commit comments