WXL
4 天以前 3bd962a6d7f61239c020e2dbbeb7341e5b842dd1
node_modules/watchpack/lib/watchEventSource.js
@@ -4,22 +4,28 @@
*/
"use strict";
const { EventEmitter } = require("events");
const fs = require("fs");
const path = require("path");
const { EventEmitter } = require("events");
const reducePlan = require("./reducePlan");
/** @typedef {import("fs").FSWatcher} FSWatcher */
/** @typedef {import("./index").EventType} EventType */
const IS_OSX = require("os").platform() === "darwin";
const IS_WIN = require("os").platform() === "win32";
const SUPPORTS_RECURSIVE_WATCHING = IS_OSX || IS_WIN;
// Use 20 for OSX to make `FSWatcher.close` faster
// https://github.com/nodejs/node/issues/29949
const watcherLimit =
   // @ts-expect-error avoid additional checks
   +process.env.WATCHPACK_WATCHER_LIMIT || (IS_OSX ? 20 : 10000);
const recursiveWatcherLogging = !!process.env
   .WATCHPACK_RECURSIVE_WATCHER_LOGGING;
const recursiveWatcherLogging = Boolean(
   process.env.WATCHPACK_RECURSIVE_WATCHER_LOGGING,
);
let isBatch = false;
let watcherCount = 0;
@@ -36,12 +42,24 @@
/** @type {Map<Watcher, RecursiveWatcher | DirectWatcher>} */
const underlyingWatcher = new Map();
/**
 * @param {string} filePath file path
 * @returns {NodeJS.ErrnoException} new error with file path in the message
 */
function createEPERMError(filePath) {
   const error = new Error(`Operation not permitted: ${filePath}`);
   const error =
      /** @type {NodeJS.ErrnoException} */
      (new Error(`Operation not permitted: ${filePath}`));
   error.code = "EPERM";
   return error;
}
/**
 * @param {FSWatcher} watcher watcher
 * @param {string} filePath a file path
 * @param {(type: "rename" | "change", filename: string) => void} handleChangeEvent function to handle change
 * @returns {(type: "rename" | "change", filename: string) => void} handler of change event
 */
function createHandleChangeEvent(watcher, filePath, handleChangeEvent) {
   return (type, filename) => {
      // TODO: After Node.js v22, fs.watch(dir) and deleting a dir will trigger the rename change event.
@@ -64,9 +82,13 @@
}
class DirectWatcher {
   /**
    * @param {string} filePath file path
    */
   constructor(filePath) {
      this.filePath = filePath;
      this.watchers = new Set();
      /** @type {FSWatcher | undefined} */
      this.watcher = undefined;
      try {
         const watcher = fs.watch(filePath);
@@ -79,10 +101,10 @@
               for (const w of this.watchers) {
                  w.emit("change", type, filename);
               }
            }
            },
         );
         watcher.on("change", handleChangeEvent);
         watcher.on("error", error => {
         watcher.on("error", (error) => {
            for (const w of this.watchers) {
               w.emit("error", error);
            }
@@ -97,11 +119,17 @@
      watcherCount++;
   }
   /**
    * @param {Watcher} watcher a watcher
    */
   add(watcher) {
      underlyingWatcher.set(watcher, this);
      this.watchers.add(watcher);
   }
   /**
    * @param {Watcher} watcher a watcher
    */
   remove(watcher) {
      this.watchers.delete(watcher);
      if (this.watchers.size === 0) {
@@ -116,31 +144,36 @@
   }
}
/** @typedef {Set<Watcher>} WatcherSet */
class RecursiveWatcher {
   /**
    * @param {string} rootPath a root path
    */
   constructor(rootPath) {
      this.rootPath = rootPath;
      /** @type {Map<Watcher, string>} */
      this.mapWatcherToPath = new Map();
      /** @type {Map<string, Set<Watcher>>} */
      /** @type {Map<string, WatcherSet>} */
      this.mapPathToWatchers = new Map();
      this.watcher = undefined;
      try {
         const watcher = fs.watch(rootPath, {
            recursive: true
            recursive: true,
         });
         this.watcher = watcher;
         watcher.on("change", (type, filename) => {
            if (!filename) {
               if (recursiveWatcherLogging) {
                  process.stderr.write(
                     `[watchpack] dispatch ${type} event in recursive watcher (${this.rootPath}) to all watchers\n`
                     `[watchpack] dispatch ${type} event in recursive watcher (${this.rootPath}) to all watchers\n`,
                  );
               }
               for (const w of this.mapWatcherToPath.keys()) {
                  w.emit("change", type);
                  w.emit("change", /** @type {EventType} */ (type));
               }
            } else {
               const dir = path.dirname(filename);
               const dir = path.dirname(/** @type {string} */ (filename));
               const watchers = this.mapPathToWatchers.get(dir);
               if (recursiveWatcherLogging) {
                  process.stderr.write(
@@ -148,16 +181,20 @@
                        this.rootPath
                     }) for '${filename}' to ${
                        watchers ? watchers.size : 0
                     } watchers\n`
                     } watchers\n`,
                  );
               }
               if (watchers === undefined) return;
               for (const w of watchers) {
                  w.emit("change", type, path.basename(filename));
                  w.emit(
                     "change",
                     /** @type {EventType} */ (type),
                     path.basename(/** @type {string} */ (filename)),
                  );
               }
            }
         });
         watcher.on("error", error => {
         watcher.on("error", (error) => {
            for (const w of this.mapWatcherToPath.keys()) {
               w.emit("error", error);
            }
@@ -172,11 +209,15 @@
      watcherCount++;
      if (recursiveWatcherLogging) {
         process.stderr.write(
            `[watchpack] created recursive watcher at ${rootPath}\n`
            `[watchpack] created recursive watcher at ${rootPath}\n`,
         );
      }
   }
   /**
    * @param {string} filePath a file path
    * @param {Watcher} watcher a watcher
    */
   add(filePath, watcher) {
      underlyingWatcher.set(watcher, this);
      const subpath = filePath.slice(this.rootPath.length + 1) || ".";
@@ -191,11 +232,14 @@
      }
   }
   /**
    * @param {Watcher} watcher a watcher
    */
   remove(watcher) {
      const subpath = this.mapWatcherToPath.get(watcher);
      if (!subpath) return;
      this.mapWatcherToPath.delete(watcher);
      const set = this.mapPathToWatchers.get(subpath);
      const set = /** @type {WatcherSet} */ (this.mapPathToWatchers.get(subpath));
      set.delete(watcher);
      if (set.size === 0) {
         this.mapPathToWatchers.delete(subpath);
@@ -206,7 +250,7 @@
         if (this.watcher) this.watcher.close();
         if (recursiveWatcherLogging) {
            process.stderr.write(
               `[watchpack] closed recursive watcher at ${this.rootPath}\n`
               `[watchpack] closed recursive watcher at ${this.rootPath}\n`,
            );
         }
      }
@@ -217,19 +261,37 @@
   }
}
/**
 * @typedef {object} WatcherEvents
 * @property {(eventType: EventType, filename?: string) => void} change change event
 * @property {(err: unknown) => void} error error event
 */
/**
 * @extends {EventEmitter<{ [K in keyof WatcherEvents]: Parameters<WatcherEvents[K]> }>}
 */
class Watcher extends EventEmitter {
   constructor() {
      super();
   }
   close() {
      if (pendingWatchers.has(this)) {
         pendingWatchers.delete(this);
         return;
      }
      const watcher = underlyingWatcher.get(this);
      watcher.remove(this);
      /** @type {RecursiveWatcher | DirectWatcher} */
      (watcher).remove(this);
      underlyingWatcher.delete(this);
   }
}
const createDirectWatcher = filePath => {
/**
 * @param {string} filePath a file path
 * @returns {DirectWatcher} a directory watcher
 */
const createDirectWatcher = (filePath) => {
   const existing = directWatchers.get(filePath);
   if (existing !== undefined) return existing;
   const w = new DirectWatcher(filePath);
@@ -237,7 +299,11 @@
   return w;
};
const createRecursiveWatcher = rootPath => {
/**
 * @param {string} rootPath a root path
 * @returns {RecursiveWatcher} a recursive watcher
 */
const createRecursiveWatcher = (rootPath) => {
   const existing = recursiveWatchers.get(rootPath);
   if (existing !== undefined) return existing;
   const w = new RecursiveWatcher(rootPath);
@@ -248,6 +314,10 @@
const execute = () => {
   /** @type {Map<string, Watcher[] | Watcher>} */
   const map = new Map();
   /**
    * @param {Watcher} watcher a watcher
    * @param {string} filePath a file path
    */
   const addWatcher = (watcher, filePath) => {
      const entry = map.get(filePath);
      if (entry === undefined) {
@@ -328,7 +398,30 @@
   }
};
exports.watch = filePath => {
module.exports.Watcher = Watcher;
/**
 * @param {() => void} fn a function
 */
module.exports.batch = (fn) => {
   isBatch = true;
   try {
      fn();
   } finally {
      isBatch = false;
      execute();
   }
};
module.exports.createHandleChangeEvent = createHandleChangeEvent;
module.exports.getNumberOfWatchers = () => watcherCount;
/**
 * @param {string} filePath a file path
 * @returns {Watcher} watcher
 */
module.exports.watch = (filePath) => {
   const watcher = new Watcher();
   // Find an existing watcher
   const directWatcher = directWatchers.get(filePath);
@@ -353,19 +446,4 @@
   return watcher;
};
exports.batch = fn => {
   isBatch = true;
   try {
      fn();
   } finally {
      isBatch = false;
      execute();
   }
};
exports.getNumberOfWatchers = () => {
   return watcherCount;
};
exports.createHandleChangeEvent = createHandleChangeEvent;
exports.watcherLimit = watcherLimit;
module.exports.watcherLimit = watcherLimit;