Skip to content

Commit 280798a

Browse files
watch: track all dependencies of an owner
filterFile() reads #ownerDependencies with the dependency path, but writes the set back keyed by the owner, so each call starts a fresh set and overwrites the previous one. An owner keeps only the last dependency registered for it. unfilterFilesOwnedBy() walks that set to release an owner's dependencies, so every other one stays in #filteredFiles and #dependencyOwners. Under `node --test --watch` a restart re-reports the modules the test still loads, which hides it for those, but a dependency it stopped requiring is never reported again and keeps re-running the test. Read #ownerDependencies with the key it is written with, and collapse the repeated #dependencyOwners lookup in the loop, which now runs once per dependency rather than once per owner. Signed-off-by: Christian Aurich Zanettini Martins <christian.aurichzm@gmail.com> PR-URL: #66139 Refs: #45214 Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
1 parent 3c463ba commit 280798a

2 files changed

Lines changed: 27 additions & 4 deletions

File tree

‎lib/internal/watch_mode/files_watcher.js‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class FilesWatcher extends EventEmitter {
154154
this.#filteredFiles.add(file);
155155
if (owner) {
156156
const owners = this.#dependencyOwners.get(file) ?? new SafeSet();
157-
const dependencies = this.#ownerDependencies.get(file) ?? new SafeSet();
157+
const dependencies = this.#ownerDependencies.get(owner) ?? new SafeSet();
158158
owners.add(owner);
159159
dependencies.add(file);
160160
this.#dependencyOwners.set(file, owners);
@@ -204,9 +204,12 @@ class FilesWatcher extends EventEmitter {
204204
owners.forEach((owner) => {
205205
this.#ownerDependencies.get(owner)?.forEach((dependency) => {
206206
this.#filteredFiles.delete(dependency);
207-
this.#dependencyOwners.get(dependency)?.delete(owner);
208-
if (this.#dependencyOwners.get(dependency)?.size === 0) {
209-
this.#dependencyOwners.delete(dependency);
207+
const dependencyOwners = this.#dependencyOwners.get(dependency);
208+
if (dependencyOwners !== undefined) {
209+
dependencyOwners.delete(owner);
210+
if (dependencyOwners.size === 0) {
211+
this.#dependencyOwners.delete(dependency);
212+
}
210213
}
211214
});
212215
this.#filteredFiles.delete(owner);

‎test/parallel/test-watch-mode-files_watcher.mjs‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,26 @@ describe('watch mode file watcher', () => {
175175
assert.strictEqual(changesCount, 1);
176176
});
177177

178+
it('should unfilter every dependency of an unfiltered owner', async () => {
179+
const owner = tmpdir.resolve('owner.js');
180+
const dependency1 = tmpdir.resolve('owner-dependency-1.js');
181+
const dependency2 = tmpdir.resolve('owner-dependency-2.js');
182+
for (const file of [owner, dependency1, dependency2]) {
183+
writeFileSync(file, 'written');
184+
}
185+
186+
watcher.filterFile(owner);
187+
watcher.filterFile(dependency1, owner);
188+
watcher.filterFile(dependency2, owner);
189+
watcher.unfilterFilesOwnedBy([owner]);
190+
191+
watcher.on('changed', common.mustNotCall());
192+
writeFileSync(dependency1, '1');
193+
writeFileSync(dependency2, '2');
194+
// Wait for this long to make sure changes are not triggered
195+
await setTimeout(1000);
196+
});
197+
178198
it('should watch all files in watched path when in "all" mode',
179199
{ skip: !supportsRecursiveWatching }, async () => {
180200
watcher = new FilesWatcher({ debounce: 100, mode: 'all' });

0 commit comments

Comments
 (0)