@@ -379,6 +379,9 @@ namespace ts {
379379 /*@internal */
380380 export const ignoredPaths = [ "/node_modules/." , "/.git" , "/.#" ] ;
381381
382+ /*@internal */
383+ export let sysLog : ( s : string ) => void = noop ;
384+
382385 /*@internal */
383386 export interface RecursiveDirectoryWatcherHost {
384387 watchDirectory : HostWatchDirectory ;
@@ -730,6 +733,7 @@ namespace ts {
730733
731734 const nodeVersion = getNodeMajorVersion ( ) ;
732735 const isNode4OrLater = nodeVersion ! >= 4 ;
736+ const isLinuxOrMacOs = process . platform === "linux" || process . platform === "darwin" ;
733737
734738 const platform : string = _os . platform ( ) ;
735739 const useCaseSensitiveFileNames = isFileSystemCaseSensitive ( ) ;
@@ -1029,6 +1033,12 @@ namespace ts {
10291033
10301034 function fsWatch ( fileOrDirectory : string , entryKind : FileSystemEntryKind . File | FileSystemEntryKind . Directory , callback : FsWatchCallback , recursive : boolean , fallbackPollingWatchFile : HostWatchFile , pollingInterval ?: number ) : FileWatcher {
10311035 let options : any ;
1036+ let lastDirectoryPartWithDirectorySeparator : string | undefined ;
1037+ let lastDirectoryPart : string | undefined ;
1038+ if ( isLinuxOrMacOs ) {
1039+ lastDirectoryPartWithDirectorySeparator = fileOrDirectory . substr ( fileOrDirectory . lastIndexOf ( directorySeparator ) ) ;
1040+ lastDirectoryPart = lastDirectoryPartWithDirectorySeparator . slice ( directorySeparator . length ) ;
1041+ }
10321042 /** Watcher for the file system entry depending on whether it is missing or present */
10331043 let watcher = ! fileSystemEntryExists ( fileOrDirectory , entryKind ) ?
10341044 watchMissingFileSystemEntry ( ) :
@@ -1046,6 +1056,7 @@ namespace ts {
10461056 * @param createWatcher
10471057 */
10481058 function invokeCallbackAndUpdateWatcher ( createWatcher : ( ) => FileWatcher ) {
1059+ sysLog ( `sysLog:: ${ fileOrDirectory } :: Changing watcher to ${ createWatcher === watchPresentFileSystemEntry ? "Present" : "Missing" } FileSystemEntryWatcher` ) ;
10491060 // Call the callback for current directory
10501061 callback ( "rename" , "" ) ;
10511062
@@ -1072,11 +1083,12 @@ namespace ts {
10721083 }
10731084 }
10741085 try {
1075-
10761086 const presentWatcher = _fs . watch (
10771087 fileOrDirectory ,
10781088 options ,
1079- callback
1089+ isLinuxOrMacOs ?
1090+ callbackChangingToMissingFileSystemEntry :
1091+ callback
10801092 ) ;
10811093 // Watch the missing file or directory or error
10821094 presentWatcher . on ( "error" , ( ) => invokeCallbackAndUpdateWatcher ( watchMissingFileSystemEntry ) ) ;
@@ -1090,11 +1102,24 @@ namespace ts {
10901102 }
10911103 }
10921104
1105+ function callbackChangingToMissingFileSystemEntry ( event : "rename" | "change" , relativeName : string | undefined ) {
1106+ // because relativeName is not guaranteed to be correct we need to check on each rename with few combinations
1107+ // Eg on ubuntu while watching app/node_modules the relativeName is "node_modules" which is neither relative nor full path
1108+ return event === "rename" &&
1109+ ( ! relativeName ||
1110+ relativeName === lastDirectoryPart ||
1111+ relativeName . lastIndexOf ( lastDirectoryPartWithDirectorySeparator ! ) === relativeName . length - lastDirectoryPartWithDirectorySeparator ! . length ) &&
1112+ ! fileSystemEntryExists ( fileOrDirectory , entryKind ) ?
1113+ invokeCallbackAndUpdateWatcher ( watchMissingFileSystemEntry ) :
1114+ callback ( event , relativeName ) ;
1115+ }
1116+
10931117 /**
10941118 * Watch the file or directory using fs.watchFile since fs.watch threw exception
10951119 * Eg. on linux the number of watches are limited and one could easily exhaust watches and the exception ENOSPC is thrown when creating watcher at that point
10961120 */
10971121 function watchPresentFileSystemEntryWithFsWatchFile ( ) : FileWatcher {
1122+ sysLog ( `sysLog:: ${ fileOrDirectory } :: Changing to fsWatchFile` ) ;
10981123 return fallbackPollingWatchFile ( fileOrDirectory , createFileWatcherCallback ( callback ) , pollingInterval ) ;
10991124 }
11001125
0 commit comments