e', (eventType, fileName) => {
      // `fileName` can be `null` if it cannot be determined. See
      // https://github.com/nodejs/node/pull/49891#issuecomment-1744673430.
      this.#onChange(recursive ? resolve(path, fileName ?? '') : path, eventType);
    });
    this.#watchers.set(path, { handle: watcher, recursive });
    if (recursive) {
      this.#removeWatchedChildren(path);
    }
  }

  filterFile(file, owner) {
    if (!file) return;
    if (supportsRecursiveWatching) {
      this.watchPath(dirname(file));
    } else {
      // Having multiple FSWatcher's seems to be slower
      // than a single recursive FSWatcher
      this.watchPath(file, false);
    }
    this.#filteredFiles.add(file);
    if (owner) {
      const owners = this.#dependencyOwners.get(file) ?? new SafeSet();
      const dependencies = this.#ownerDependencies.get(file) ?? new SafeSet();
      owners.add(owner);
      dependencies.add(file);
      this.#dependencyOwners.set(file, owners);
      this.#ownerDependencies.set(owner, dependencies);
    }
  }


  #setupIPC(child) {
    const handlers = {
      __proto__: null,
      parentToChild: (message) => child.send(message),
      childToParent: (message) => process.send(message),
    };
    this.#ipcHandlers.set(child, handlers);
    process.on('message', handlers.parentToChild);
    child.on('message', handlers.childToParent);
  }

  destroyIPC(child) {
    const handlers = this.#ipcHandlers.get(child);
    if (this.#passthroughIPC && handlers !== undefined) {
      process.off('message', handlers.parentToChild);
      child.off('message', handlers.childToParent);
    }
  }

  watchChildProcessModules(child, key = null) {
    if (this.#passthroughIPC) {
      this.#setupIPC(child);
    }

    child.on('message', (message) => {
      try {
        if (ArrayIsArray(message['watch:require'])) {
          ArrayPrototypeForEach(message['watch:require'], (file) => this.filterFile(file, key));
        }
        if (ArrayIsArray(message['watch:import'])) {
          ArrayPrototypeForEach(message['watch:import'], (file) => this.filterFile(fileURLToPath(file), key));
        }
      } catch {
        // Failed watching file. ignore
      }
    });
  }
  unfilterFilesOwnedBy(owners) {
    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);
        }
      });
      this.#filteredFiles.delete(owner);
      this.#dependencyOwners.delete(owner);
      this.#ownerDependencies.delete(owner);
    });
  }
  clearFileFilters() {
    this.#filteredFiles.clear();
  }
  clear() {
    this.#watchers.forEach(this.#unwatch);
    this.#watchers.clear();
    this.#filteredFiles.clear();
    this.#dependencyOwners.clear();
    this.#ownerDependencies.clear();
  }
}

module.exports = { FilesWatcher };
