@@ -25,6 +25,9 @@ const { setTimeout, clearTimeout } = require('timers');
2525const supportsRecursiveWatching = process . platform === 'win32' ||
2626 process . platform === 'darwin' ;
2727
28+ const supportsDirectoryWatching = supportsRecursiveWatching ||
29+ process . platform === 'linux' ;
30+
2831const isParentPath = ( parentCandidate , childCandidate ) => {
2932 const parent = resolve ( parentCandidate ) ;
3033 const child = resolve ( childCandidate ) ;
@@ -114,15 +117,15 @@ class FilesWatcher extends EventEmitter {
114117 if ( this . #isPathWatched( path ) ) {
115118 return ;
116119 }
117- const { allowMissing = false } = options ;
120+ // `watchEntries` tells that `path` is a directory whose entries are
121+ // reported by name, as opposed to a single watched file.
122+ const { allowMissing = false , watchEntries = recursive } = options ;
118123
119124 const watcher = watch ( path , { recursive, signal : this . #signal, throwIfNoEntry : ! allowMissing } ) ;
120125 watcher . on ( 'change' , ( eventType , fileName ) => {
121126 // `fileName` can be `null` if it cannot be determined. See
122127 // https://github.com/nodejs/node/pull/49891#issuecomment-1744673430.
123- // `path` is the watched directory (see `filterFile`), so resolve the
124- // changed entry against it to get the absolute path of the trigger.
125- this . #onChange( resolve ( path , fileName ?? '' ) , eventType ) ;
128+ this . #onChange( watchEntries ? resolve ( path , fileName ?? '' ) : path , eventType ) ;
126129 } ) ;
127130 this . #watchers. set ( path , { handle : watcher , recursive } ) ;
128131 if ( recursive ) {
@@ -134,14 +137,16 @@ class FilesWatcher extends EventEmitter {
134137 if ( ! file ) return ;
135138 if ( supportsRecursiveWatching ) {
136139 this . watchPath ( dirname ( file ) , true , options ) ;
137- } else {
140+ } else if ( supportsDirectoryWatching ) {
138141 // Watch the parent directory non-recursively rather than the file
139142 // itself. A watch bound to the file's inode stops receiving events once
140143 // the file is replaced via unlink+create or rename (atomic saves, Docker
141144 // Compose watch, ...), so only the first replacement would be detected.
142145 // Watching the directory keeps working across replacements, and unrelated
143146 // siblings are discarded by the `filter` mode check in `#onChange`.
144- this . watchPath ( dirname ( file ) , false , options ) ;
147+ this . watchPath ( dirname ( file ) , false , { __proto__ : null , ...options , watchEntries : true } ) ;
148+ } else {
149+ this . watchPath ( file , false , options ) ;
145150 }
146151 this . #filteredFiles. add ( file ) ;
147152 if ( owner ) {
0 commit comments