|
7 | 7 | */
|
8 | 8 |
|
9 | 9 | import { FSWatcher } from 'chokidar';
|
10 |
| -import { normalize } from 'node:path'; |
| 10 | +import { extname, normalize } from 'node:path'; |
11 | 11 |
|
12 | 12 | export class ChangedFiles {
|
13 | 13 | readonly added = new Set<string>();
|
@@ -98,55 +98,24 @@ export function createWatcher(options?: {
|
98 | 98 | * ... (Nothing)
|
99 | 99 | * ```
|
100 | 100 | */
|
101 |
| - watcher.on(watcher.options.useFsEvents ? 'all' : 'raw', (event, path, metadata) => { |
102 |
| - switch (event) { |
103 |
| - case 'add': |
104 |
| - case 'change': |
105 |
| - // When using Visual Studio the rename event is fired before a change event when the contents of the file changed |
106 |
| - // or instead of `unlink` when the file has been renamed. |
107 |
| - case 'unlink': |
108 |
| - case 'rename': |
109 |
| - // When polling is enabled `watchedPath` can be undefined. |
110 |
| - // `path` is always normalized unlike `watchedPath`. |
111 |
| - const changedPath = metadata?.watchedPath ? normalize(metadata.watchedPath) : path; |
112 |
| - currentEvents ??= new Map(); |
113 |
| - currentEvents.set(changedPath, event); |
114 |
| - break; |
115 |
| - default: |
| 101 | + watcher |
| 102 | + .on('raw', (event, path, { watchedPath }) => { |
| 103 | + if (watchedPath && !extname(watchedPath)) { |
| 104 | + // Ignore directories, file changes in directories will be fired seperatly. |
116 | 105 | return;
|
117 |
| - } |
118 |
| - |
119 |
| - // Wait 250ms from next change to better capture groups of file save operations. |
120 |
| - if (!nextWaitTimeout) { |
121 |
| - nextWaitTimeout = setTimeout(() => { |
122 |
| - nextWaitTimeout = undefined; |
123 |
| - const next = nextQueue.shift(); |
124 |
| - if (next && currentEvents) { |
125 |
| - const events = currentEvents; |
126 |
| - currentEvents = undefined; |
127 |
| - |
128 |
| - const currentChanges = new ChangedFiles(); |
129 |
| - for (const [path, event] of events) { |
130 |
| - switch (event) { |
131 |
| - case 'add': |
132 |
| - currentChanges.added.add(path); |
133 |
| - break; |
134 |
| - case 'change': |
135 |
| - currentChanges.modified.add(path); |
136 |
| - break; |
137 |
| - case 'unlink': |
138 |
| - case 'rename': |
139 |
| - currentChanges.removed.add(path); |
140 |
| - break; |
141 |
| - } |
142 |
| - } |
| 106 | + } |
143 | 107 |
|
144 |
| - next(currentChanges); |
145 |
| - } |
146 |
| - }, 250); |
147 |
| - nextWaitTimeout?.unref(); |
148 |
| - } |
149 |
| - }); |
| 108 | + switch (event) { |
| 109 | + case 'rename': |
| 110 | + case 'change': |
| 111 | + // When polling is enabled `watchedPath` can be undefined. |
| 112 | + // `path` is always normalized unlike `watchedPath`. |
| 113 | + const changedPath = watchedPath ? normalize(watchedPath) : path; |
| 114 | + handleFileChange(event, changedPath); |
| 115 | + break; |
| 116 | + } |
| 117 | + }) |
| 118 | + .on('all', handleFileChange); |
150 | 119 |
|
151 | 120 | return {
|
152 | 121 | [Symbol.asyncIterator]() {
|
@@ -188,4 +157,51 @@ export function createWatcher(options?: {
|
188 | 157 | }
|
189 | 158 | },
|
190 | 159 | };
|
| 160 | + |
| 161 | + function handleFileChange(event: string, path: string): void { |
| 162 | + switch (event) { |
| 163 | + case 'add': |
| 164 | + case 'change': |
| 165 | + // When using Visual Studio the rename event is fired before a change event when the contents of the file changed |
| 166 | + // or instead of `unlink` when the file has been renamed. |
| 167 | + case 'unlink': |
| 168 | + case 'rename': |
| 169 | + currentEvents ??= new Map(); |
| 170 | + currentEvents.set(path, event); |
| 171 | + break; |
| 172 | + default: |
| 173 | + return; |
| 174 | + } |
| 175 | + |
| 176 | + // Wait 250ms from next change to better capture groups of file save operations. |
| 177 | + if (!nextWaitTimeout) { |
| 178 | + nextWaitTimeout = setTimeout(() => { |
| 179 | + nextWaitTimeout = undefined; |
| 180 | + const next = nextQueue.shift(); |
| 181 | + if (next && currentEvents) { |
| 182 | + const events = currentEvents; |
| 183 | + currentEvents = undefined; |
| 184 | + |
| 185 | + const currentChanges = new ChangedFiles(); |
| 186 | + for (const [path, event] of events) { |
| 187 | + switch (event) { |
| 188 | + case 'add': |
| 189 | + currentChanges.added.add(path); |
| 190 | + break; |
| 191 | + case 'change': |
| 192 | + currentChanges.modified.add(path); |
| 193 | + break; |
| 194 | + case 'unlink': |
| 195 | + case 'rename': |
| 196 | + currentChanges.removed.add(path); |
| 197 | + break; |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + next(currentChanges); |
| 202 | + } |
| 203 | + }, 250); |
| 204 | + nextWaitTimeout?.unref(); |
| 205 | + } |
| 206 | + } |
191 | 207 | }
|
0 commit comments