Commit 280798a30d4 for nodejs

commit 280798a30d4c51494dcbc7f2f14bdabbf460509a
Author: Christian Aurich Zanettini Martins <christian.aurichzm@gmail.com>
Date:   Fri Nov 6 07:35:50 2026 -0300

    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: https://github.com/nodejs/node/pull/66139
    Refs: https://github.com/nodejs/node/pull/45214
    Reviewed-By: Moshe Atlow <moshe@atlow.co.il>

diff --git a/lib/internal/watch_mode/files_watcher.js b/lib/internal/watch_mode/files_watcher.js
index 8b5faeaf0e9..bd8a86aac84 100644
--- a/lib/internal/watch_mode/files_watcher.js
+++ b/lib/internal/watch_mode/files_watcher.js
@@ -154,7 +154,7 @@ class FilesWatcher extends EventEmitter {
     this.#filteredFiles.add(file);
     if (owner) {
       const owners = this.#dependencyOwners.get(file) ?? new SafeSet();
-      const dependencies = this.#ownerDependencies.get(file) ?? new SafeSet();
+      const dependencies = this.#ownerDependencies.get(owner) ?? new SafeSet();
       owners.add(owner);
       dependencies.add(file);
       this.#dependencyOwners.set(file, owners);
@@ -204,9 +204,12 @@ class FilesWatcher extends EventEmitter {
     owners.forEach((owner) => {
       this.#ownerDependencies.get(owner)?.forEach((dependency) => {
         this.#filteredFiles.delete(dependency);
-        this.#dependencyOwners.get(dependency)?.delete(owner);
-        if (this.#dependencyOwners.get(dependency)?.size === 0) {
-          this.#dependencyOwners.delete(dependency);
+        const dependencyOwners = this.#dependencyOwners.get(dependency);
+        if (dependencyOwners !== undefined) {
+          dependencyOwners.delete(owner);
+          if (dependencyOwners.size === 0) {
+            this.#dependencyOwners.delete(dependency);
+          }
         }
       });
       this.#filteredFiles.delete(owner);
diff --git a/test/parallel/test-watch-mode-files_watcher.mjs b/test/parallel/test-watch-mode-files_watcher.mjs
index 10e078286e0..71b9cb2ae0f 100644
--- a/test/parallel/test-watch-mode-files_watcher.mjs
+++ b/test/parallel/test-watch-mode-files_watcher.mjs
@@ -175,6 +175,26 @@ describe('watch mode file watcher', () => {
     assert.strictEqual(changesCount, 1);
   });

+  it('should unfilter every dependency of an unfiltered owner', async () => {
+    const owner = tmpdir.resolve('owner.js');
+    const dependency1 = tmpdir.resolve('owner-dependency-1.js');
+    const dependency2 = tmpdir.resolve('owner-dependency-2.js');
+    for (const file of [owner, dependency1, dependency2]) {
+      writeFileSync(file, 'written');
+    }
+
+    watcher.filterFile(owner);
+    watcher.filterFile(dependency1, owner);
+    watcher.filterFile(dependency2, owner);
+    watcher.unfilterFilesOwnedBy([owner]);
+
+    watcher.on('changed', common.mustNotCall());
+    writeFileSync(dependency1, '1');
+    writeFileSync(dependency2, '2');
+    // Wait for this long to make sure changes are not triggered
+    await setTimeout(1000);
+  });
+
   it('should watch all files in watched path when in "all" mode',
      { skip: !supportsRecursiveWatching }, async () => {
        watcher = new FilesWatcher({ debounce: 100, mode: 'all' });