From 9bce51f651aad297ef9eb6df832bfdaf1de05d84 Mon Sep 17 00:00:00 2001
From: WXL <wl_5969728@163.com>
Date: 星期三, 22 四月 2026 14:27:54 +0800
Subject: [PATCH] 青岛推送
---
node_modules/watchpack/lib/DirectoryWatcher.js | 454 +++++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 314 insertions(+), 140 deletions(-)
diff --git a/node_modules/watchpack/lib/DirectoryWatcher.js b/node_modules/watchpack/lib/DirectoryWatcher.js
index 9a5eeb9..a529e67 100644
--- a/node_modules/watchpack/lib/DirectoryWatcher.js
+++ b/node_modules/watchpack/lib/DirectoryWatcher.js
@@ -4,12 +4,23 @@
*/
"use strict";
-const EventEmitter = require("events").EventEmitter;
-const fs = require("graceful-fs");
+const { EventEmitter } = require("events");
const path = require("path");
+const fs = require("graceful-fs");
const watchEventSource = require("./watchEventSource");
+/** @typedef {import("./index").IgnoredFunction} IgnoredFunction */
+/** @typedef {import("./index").EventType} EventType */
+/** @typedef {import("./index").TimeInfoEntries} TimeInfoEntries */
+/** @typedef {import("./index").Entry} Entry */
+/** @typedef {import("./index").ExistenceOnlyTimeEntry} ExistenceOnlyTimeEntry */
+/** @typedef {import("./index").OnlySafeTimeEntry} OnlySafeTimeEntry */
+/** @typedef {import("./index").EventMap} EventMap */
+/** @typedef {import("./getWatcherManager").WatcherManager} WatcherManager */
+/** @typedef {import("./watchEventSource").Watcher} EventSourceWatcher */
+
+/** @type {ExistenceOnlyTimeEntry} */
const EXISTANCE_ONLY_TIME_ENTRY = Object.freeze({});
let FS_ACCURACY = 2000;
@@ -17,45 +28,130 @@
const IS_OSX = require("os").platform() === "darwin";
const IS_WIN = require("os").platform() === "win32";
-const WATCHPACK_POLLING = process.env.WATCHPACK_POLLING;
+const { WATCHPACK_POLLING } = process.env;
const FORCE_POLLING =
+ // @ts-expect-error avoid additional checks
`${+WATCHPACK_POLLING}` === WATCHPACK_POLLING
? +WATCHPACK_POLLING
- : !!WATCHPACK_POLLING && WATCHPACK_POLLING !== "false";
+ : Boolean(WATCHPACK_POLLING) && WATCHPACK_POLLING !== "false";
+/**
+ * @param {string} str string
+ * @returns {string} lower cased string
+ */
function withoutCase(str) {
return str.toLowerCase();
}
+/**
+ * @param {number} times times
+ * @param {() => void} callback callback
+ * @returns {() => void} result
+ */
function needCalls(times, callback) {
- return function() {
+ return function needCallsCallback() {
if (--times === 0) {
return callback();
}
};
}
+/**
+ * @param {Entry} entry entry
+ */
+function fixupEntryAccuracy(entry) {
+ if (entry.accuracy > FS_ACCURACY) {
+ entry.safeTime = entry.safeTime - entry.accuracy + FS_ACCURACY;
+ entry.accuracy = FS_ACCURACY;
+ }
+}
+
+/**
+ * @param {number=} mtime mtime
+ */
+function ensureFsAccuracy(mtime) {
+ if (!mtime) return;
+ if (FS_ACCURACY > 1 && mtime % 1 !== 0) FS_ACCURACY = 1;
+ else if (FS_ACCURACY > 10 && mtime % 10 !== 0) FS_ACCURACY = 10;
+ else if (FS_ACCURACY > 100 && mtime % 100 !== 0) FS_ACCURACY = 100;
+ else if (FS_ACCURACY > 1000 && mtime % 1000 !== 0) FS_ACCURACY = 1000;
+}
+
+/**
+ * @typedef {object} FileWatcherEvents
+ * @property {(type: EventType) => void} initial-missing initial missing event
+ * @property {(mtime: number, type: EventType, initial: boolean) => void} change change event
+ * @property {(type: EventType) => void} remove remove event
+ * @property {() => void} closed closed event
+ */
+
+/**
+ * @typedef {object} DirectoryWatcherEvents
+ * @property {(type: EventType) => void} initial-missing initial missing event
+ * @property {((file: string, mtime: number, type: EventType, initial: boolean) => void)} change change event
+ * @property {(type: EventType) => void} remove remove event
+ * @property {() => void} closed closed event
+ */
+
+/**
+ * @template {EventMap} T
+ * @extends {EventEmitter<{ [K in keyof T]: Parameters<T[K]> }>}
+ */
class Watcher extends EventEmitter {
- constructor(directoryWatcher, filePath, startTime) {
+ /**
+ * @param {DirectoryWatcher} directoryWatcher a directory watcher
+ * @param {string} target a target to watch
+ * @param {number=} startTime start time
+ */
+ constructor(directoryWatcher, target, startTime) {
super();
this.directoryWatcher = directoryWatcher;
- this.path = filePath;
+ this.path = target;
this.startTime = startTime && +startTime;
}
+ /**
+ * @param {number} mtime mtime
+ * @param {boolean} initial true when initial, otherwise false
+ * @returns {boolean} true of start time less than mtile, otherwise false
+ */
checkStartTime(mtime, initial) {
- const startTime = this.startTime;
+ const { startTime } = this;
if (typeof startTime !== "number") return !initial;
return startTime <= mtime;
}
close() {
+ // @ts-expect-error bad typing in EventEmitter
this.emit("closed");
}
}
+/** @typedef {Set<string>} InitialScanRemoved */
+
+/**
+ * @typedef {object} WatchpackEvents
+ * @property {(target: string, mtime: string, type: EventType, initial: boolean) => void} change change event
+ * @property {() => void} closed closed event
+ */
+
+/**
+ * @typedef {object} DirectoryWatcherOptions
+ * @property {boolean=} followSymlinks true when need to resolve symlinks and watch symlink and real file, otherwise false
+ * @property {IgnoredFunction=} ignored ignore some files from watching (glob pattern or regexp)
+ * @property {number | boolean=} poll true when need to enable polling mode for watching, otherwise false
+ */
+
+/**
+ * @extends {EventEmitter<{ [K in keyof WatchpackEvents]: Parameters<WatchpackEvents[K]> }>}
+ */
class DirectoryWatcher extends EventEmitter {
- constructor(watcherManager, directoryPath, options) {
+ /**
+ * @param {WatcherManager} watcherManager a watcher manager
+ * @param {string} directoryPath directory path
+ * @param {DirectoryWatcherOptions=} options options
+ */
+ constructor(watcherManager, directoryPath, options = {}) {
super();
if (FORCE_POLLING) {
options.poll = FORCE_POLLING;
@@ -65,28 +161,35 @@
this.path = directoryPath;
// safeTime is the point in time after which reading is safe to be unchanged
// timestamp is a value that should be compared with another timestamp (mtime)
- /** @type {Map<string, { safeTime: number, timestamp: number }} */
+ /** @type {Map<string, Entry>} */
this.files = new Map();
/** @type {Map<string, number>} */
this.filesWithoutCase = new Map();
+ /** @type {Map<string, Watcher<DirectoryWatcherEvents> | boolean>} */
this.directories = new Map();
this.lastWatchEvent = 0;
this.initialScan = true;
this.ignored = options.ignored || (() => false);
this.nestedWatching = false;
+ /** @type {number | false} */
this.polledWatching =
typeof options.poll === "number"
? options.poll
: options.poll
- ? 5007
- : false;
+ ? 5007
+ : false;
+ /** @type {undefined | NodeJS.Timeout} */
this.timeout = undefined;
+ /** @type {null | InitialScanRemoved} */
this.initialScanRemoved = new Set();
+ /** @type {undefined | number} */
this.initialScanFinished = undefined;
- /** @type {Map<string, Set<Watcher>>} */
+ /** @type {Map<string, Set<Watcher<DirectoryWatcherEvents> | Watcher<FileWatcherEvents>>>} */
this.watchers = new Map();
+ /** @type {Watcher<FileWatcherEvents> | null} */
this.parentWatcher = null;
this.refs = 0;
+ /** @type {Map<string, boolean>} */
this._activeEvents = new Map();
this.closed = false;
this.scanning = false;
@@ -100,19 +203,22 @@
createWatcher() {
try {
if (this.polledWatching) {
- this.watcher = {
+ /** @type {EventSourceWatcher} */
+ (this.watcher) = /** @type {EventSourceWatcher} */ ({
close: () => {
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = undefined;
}
- }
- };
+ },
+ });
} else {
if (IS_OSX) {
this.watchInParentDirectory();
}
- this.watcher = watchEventSource.watch(this.path);
+ this.watcher =
+ /** @type {EventSourceWatcher} */
+ (watchEventSource.watch(this.path));
this.watcher.on("change", this.onWatchEvent.bind(this));
this.watcher.on("error", this.onWatcherError.bind(this));
}
@@ -121,6 +227,11 @@
}
}
+ /**
+ * @template {(watcher: Watcher<EventMap>) => void} T
+ * @param {string} path path
+ * @param {T} fn function
+ */
forEachWatcher(path, fn) {
const watchers = this.watchers.get(withoutCase(path));
if (watchers !== undefined) {
@@ -130,20 +241,28 @@
}
}
+ /**
+ * @param {string} itemPath an item path
+ * @param {boolean} initial true when initial, otherwise false
+ * @param {EventType} type even type
+ */
setMissing(itemPath, initial, type) {
if (this.initialScan) {
- this.initialScanRemoved.add(itemPath);
+ /** @type {InitialScanRemoved} */
+ (this.initialScanRemoved).add(itemPath);
}
const oldDirectory = this.directories.get(itemPath);
if (oldDirectory) {
- if (this.nestedWatching) oldDirectory.close();
+ if (this.nestedWatching) {
+ /** @type {Watcher<DirectoryWatcherEvents>} */
+ (oldDirectory).close();
+ }
this.directories.delete(itemPath);
-
- this.forEachWatcher(itemPath, w => w.emit("remove", type));
+ this.forEachWatcher(itemPath, (w) => w.emit("remove", type));
if (!initial) {
- this.forEachWatcher(this.path, w =>
- w.emit("change", itemPath, null, type, initial)
+ this.forEachWatcher(this.path, (w) =>
+ w.emit("change", itemPath, null, type, initial),
);
}
}
@@ -152,30 +271,38 @@
if (oldFile) {
this.files.delete(itemPath);
const key = withoutCase(itemPath);
- const count = this.filesWithoutCase.get(key) - 1;
+ const count = /** @type {number} */ (this.filesWithoutCase.get(key)) - 1;
if (count <= 0) {
this.filesWithoutCase.delete(key);
- this.forEachWatcher(itemPath, w => w.emit("remove", type));
+ this.forEachWatcher(itemPath, (w) => w.emit("remove", type));
} else {
this.filesWithoutCase.set(key, count);
}
if (!initial) {
- this.forEachWatcher(this.path, w =>
- w.emit("change", itemPath, null, type, initial)
+ this.forEachWatcher(this.path, (w) =>
+ w.emit("change", itemPath, null, type, initial),
);
}
}
}
- setFileTime(filePath, mtime, initial, ignoreWhenEqual, type) {
+ /**
+ * @param {string} target a target to set file time
+ * @param {number} mtime mtime
+ * @param {boolean} initial true when initial, otherwise false
+ * @param {boolean} ignoreWhenEqual true to ignore when equal, otherwise false
+ * @param {EventType} type type
+ */
+ setFileTime(target, mtime, initial, ignoreWhenEqual, type) {
const now = Date.now();
- if (this.ignored(filePath)) return;
+ if (this.ignored(target)) return;
- const old = this.files.get(filePath);
+ const old = this.files.get(target);
- let safeTime, accuracy;
+ let safeTime;
+ let accuracy;
if (initial) {
safeTime = Math.min(now, mtime) + FS_ACCURACY;
accuracy = FS_ACCURACY;
@@ -194,14 +321,14 @@
if (ignoreWhenEqual && old && old.timestamp === mtime) return;
- this.files.set(filePath, {
+ this.files.set(target, {
safeTime,
accuracy,
- timestamp: mtime
+ timestamp: mtime,
});
if (!old) {
- const key = withoutCase(filePath);
+ const key = withoutCase(target);
const count = this.filesWithoutCase.get(key);
this.filesWithoutCase.set(key, (count || 0) + 1);
if (count !== undefined) {
@@ -213,27 +340,33 @@
this.doScan(false);
}
- this.forEachWatcher(filePath, w => {
+ this.forEachWatcher(target, (w) => {
if (!initial || w.checkStartTime(safeTime, initial)) {
w.emit("change", mtime, type);
}
});
} else if (!initial) {
- this.forEachWatcher(filePath, w => w.emit("change", mtime, type));
+ this.forEachWatcher(target, (w) => w.emit("change", mtime, type));
}
- this.forEachWatcher(this.path, w => {
+ this.forEachWatcher(this.path, (w) => {
if (!initial || w.checkStartTime(safeTime, initial)) {
- w.emit("change", filePath, safeTime, type, initial);
+ w.emit("change", target, safeTime, type, initial);
}
});
}
+ /**
+ * @param {string} directoryPath directory path
+ * @param {number} birthtime birthtime
+ * @param {boolean} initial true when initial, otherwise false
+ * @param {EventType} type even type
+ */
setDirectory(directoryPath, birthtime, initial, type) {
if (this.ignored(directoryPath)) return;
if (directoryPath === this.path) {
if (!initial) {
- this.forEachWatcher(this.path, w =>
- w.emit("change", directoryPath, birthtime, type, initial)
+ this.forEachWatcher(this.path, (w) =>
+ w.emit("change", directoryPath, birthtime, type, initial),
);
}
} else {
@@ -247,19 +380,14 @@
this.directories.set(directoryPath, true);
}
- let safeTime;
- if (initial) {
- safeTime = Math.min(now, birthtime) + FS_ACCURACY;
- } else {
- safeTime = now;
- }
+ const safeTime = initial ? Math.min(now, birthtime) + FS_ACCURACY : now;
- this.forEachWatcher(directoryPath, w => {
+ this.forEachWatcher(directoryPath, (w) => {
if (!initial || w.checkStartTime(safeTime, false)) {
w.emit("change", birthtime, type);
}
});
- this.forEachWatcher(this.path, w => {
+ this.forEachWatcher(this.path, (w) => {
if (!initial || w.checkStartTime(safeTime, initial)) {
w.emit("change", directoryPath, safeTime, type, initial);
}
@@ -268,43 +396,57 @@
}
}
+ /**
+ * @param {string} directoryPath directory path
+ */
createNestedWatcher(directoryPath) {
const watcher = this.watcherManager.watchDirectory(directoryPath, 1);
- watcher.on("change", (filePath, mtime, type, initial) => {
- this.forEachWatcher(this.path, w => {
+ watcher.on("change", (target, mtime, type, initial) => {
+ this.forEachWatcher(this.path, (w) => {
if (!initial || w.checkStartTime(mtime, initial)) {
- w.emit("change", filePath, mtime, type, initial);
+ w.emit("change", target, mtime, type, initial);
}
});
});
this.directories.set(directoryPath, watcher);
}
+ /**
+ * @param {boolean} flag true when nested, otherwise false
+ */
setNestedWatching(flag) {
- if (this.nestedWatching !== !!flag) {
- this.nestedWatching = !!flag;
+ if (this.nestedWatching !== Boolean(flag)) {
+ this.nestedWatching = Boolean(flag);
if (this.nestedWatching) {
for (const directory of this.directories.keys()) {
this.createNestedWatcher(directory);
}
} else {
for (const [directory, watcher] of this.directories) {
- watcher.close();
+ /** @type {Watcher<DirectoryWatcherEvents>} */
+ (watcher).close();
this.directories.set(directory, true);
}
}
}
}
- watch(filePath, startTime) {
- const key = withoutCase(filePath);
+ /**
+ * @param {string} target a target to watch
+ * @param {number=} startTime start time
+ * @returns {Watcher<DirectoryWatcherEvents> | Watcher<FileWatcherEvents>} watcher
+ */
+ watch(target, startTime) {
+ const key = withoutCase(target);
let watchers = this.watchers.get(key);
if (watchers === undefined) {
watchers = new Set();
this.watchers.set(key, watchers);
}
this.refs++;
- const watcher = new Watcher(this, filePath, startTime);
+ const watcher =
+ /** @type {Watcher<DirectoryWatcherEvents> | Watcher<FileWatcherEvents>} */
+ (new Watcher(this, target, startTime));
watcher.on("closed", () => {
if (--this.refs <= 0) {
this.close();
@@ -313,12 +455,12 @@
watchers.delete(watcher);
if (watchers.size === 0) {
this.watchers.delete(key);
- if (this.path === filePath) this.setNestedWatching(false);
+ if (this.path === target) this.setNestedWatching(false);
}
});
watchers.add(watcher);
let safeTime;
- if (filePath === this.path) {
+ if (target === this.path) {
this.setNestedWatching(true);
safeTime = this.lastWatchEvent;
for (const entry of this.files.values()) {
@@ -326,7 +468,7 @@
safeTime = Math.max(safeTime, entry.safeTime);
}
} else {
- const entry = this.files.get(filePath);
+ const entry = this.files.get(target);
if (entry) {
fixupEntryAccuracy(entry);
safeTime = entry.safeTime;
@@ -335,38 +477,47 @@
}
}
if (safeTime) {
- if (safeTime >= startTime) {
+ if (startTime && safeTime >= startTime) {
process.nextTick(() => {
if (this.closed) return;
- if (filePath === this.path) {
- watcher.emit(
+ if (target === this.path) {
+ /** @type {Watcher<DirectoryWatcherEvents>} */
+ (watcher).emit(
"change",
- filePath,
+ target,
safeTime,
"watch (outdated on attach)",
- true
+ true,
);
} else {
- watcher.emit(
+ /** @type {Watcher<FileWatcherEvents>} */
+ (watcher).emit(
"change",
safeTime,
"watch (outdated on attach)",
- true
+ true,
);
}
});
}
} else if (this.initialScan) {
- if (this.initialScanRemoved.has(filePath)) {
+ if (
+ /** @type {InitialScanRemoved} */
+ (this.initialScanRemoved).has(target)
+ ) {
process.nextTick(() => {
if (this.closed) return;
watcher.emit("remove");
});
}
} else if (
- filePath !== this.path &&
- !this.directories.has(filePath) &&
- watcher.checkStartTime(this.initialScanFinished, false)
+ target !== this.path &&
+ !this.directories.has(target) &&
+ watcher.checkStartTime(
+ /** @type {number} */
+ (this.initialScanFinished),
+ false,
+ )
) {
process.nextTick(() => {
if (this.closed) return;
@@ -376,6 +527,10 @@
return watcher;
}
+ /**
+ * @param {EventType} eventType event type
+ * @param {string=} filename filename
+ */
onWatchEvent(eventType, filename) {
if (this.closed) return;
if (!filename) {
@@ -387,15 +542,15 @@
return;
}
- const filePath = path.join(this.path, filename);
- if (this.ignored(filePath)) return;
+ const target = path.join(this.path, filename);
+ if (this.ignored(target)) return;
if (this._activeEvents.get(filename) === undefined) {
this._activeEvents.set(filename, false);
const checkStats = () => {
if (this.closed) return;
this._activeEvents.set(filename, false);
- fs.lstat(filePath, (err, stats) => {
+ fs.lstat(target, (err, stats) => {
if (this.closed) return;
if (this._activeEvents.get(filename) === true) {
process.nextTick(checkStats);
@@ -411,35 +566,28 @@
err.code !== "EBUSY"
) {
this.onStatsError(err);
- } else {
- if (filename === path.basename(this.path)) {
- // This may indicate that the directory itself was removed
- if (!fs.existsSync(this.path)) {
- this.onDirectoryRemoved("stat failed");
- }
- }
+ } else if (
+ filename === path.basename(this.path) && // This may indicate that the directory itself was removed
+ !fs.existsSync(this.path)
+ ) {
+ this.onDirectoryRemoved("stat failed");
}
}
this.lastWatchEvent = Date.now();
if (!stats) {
- this.setMissing(filePath, false, eventType);
+ this.setMissing(target, false, eventType);
} else if (stats.isDirectory()) {
- this.setDirectory(
- filePath,
- +stats.birthtime || 1,
- false,
- eventType
- );
+ this.setDirectory(target, +stats.birthtime || 1, false, eventType);
} else if (stats.isFile() || stats.isSymbolicLink()) {
if (stats.mtime) {
- ensureFsAccuracy(stats.mtime);
+ ensureFsAccuracy(+stats.mtime);
}
this.setFileTime(
- filePath,
+ target,
+stats.mtime || +stats.ctime || 1,
false,
false,
- eventType
+ eventType,
);
}
});
@@ -450,25 +598,42 @@
}
}
+ /**
+ * @param {unknown=} err error
+ */
onWatcherError(err) {
if (this.closed) return;
if (err) {
- if (err.code !== "EPERM" && err.code !== "ENOENT") {
- console.error("Watchpack Error (watcher): " + err);
+ if (
+ /** @type {NodeJS.ErrnoException} */
+ (err).code !== "EPERM" &&
+ /** @type {NodeJS.ErrnoException} */
+ (err).code !== "ENOENT"
+ ) {
+ // eslint-disable-next-line no-console
+ console.error(`Watchpack Error (watcher): ${err}`);
}
this.onDirectoryRemoved("watch error");
}
}
+ /**
+ * @param {Error | NodeJS.ErrnoException=} err error
+ */
onStatsError(err) {
if (err) {
- console.error("Watchpack Error (stats): " + err);
+ // eslint-disable-next-line no-console
+ console.error(`Watchpack Error (stats): ${err}`);
}
}
+ /**
+ * @param {Error | NodeJS.ErrnoException=} err error
+ */
onScanError(err) {
if (err) {
- console.error("Watchpack Error (initial scan): " + err);
+ // eslint-disable-next-line no-console
+ console.error(`Watchpack Error (initial scan): ${err}`);
}
this.onScanFinished();
}
@@ -482,18 +647,21 @@
}
}
+ /**
+ * @param {string} reason a reason
+ */
onDirectoryRemoved(reason) {
if (this.watcher) {
this.watcher.close();
this.watcher = null;
}
this.watchInParentDirectory();
- const type = `directory-removed (${reason})`;
+ const type = /** @type {EventType} */ (`directory-removed (${reason})`);
for (const directory of this.directories.keys()) {
- this.setMissing(directory, null, type);
+ this.setMissing(directory, false, type);
}
for (const file of this.files.keys()) {
- this.setMissing(file, null, type);
+ this.setMissing(file, false, type);
}
}
@@ -505,7 +673,8 @@
if (path.dirname(parentDir) === parentDir) return;
this.parentWatcher = this.watcherManager.watchFile(this.path, 1);
- this.parentWatcher.on("change", (mtime, type) => {
+ /** @type {Watcher<FileWatcherEvents>} */
+ (this.parentWatcher).on("change", (mtime, type) => {
if (this.closed) return;
// On non-osx platforms we don't need this watcher to detect
@@ -520,17 +689,21 @@
this.doScan(false);
// directory was created so we emit an event
- this.forEachWatcher(this.path, w =>
- w.emit("change", this.path, mtime, type, false)
+ this.forEachWatcher(this.path, (w) =>
+ w.emit("change", this.path, mtime, type, false),
);
}
});
- this.parentWatcher.on("remove", () => {
+ /** @type {Watcher<FileWatcherEvents>} */
+ (this.parentWatcher).on("remove", () => {
this.onDirectoryRemoved("parent directory removed");
});
}
}
+ /**
+ * @param {boolean} initial true when initial, otherwise false
+ */
doScan(initial) {
if (this.scanning) {
if (this.scanAgain) {
@@ -564,7 +737,7 @@
if (watcher.checkStartTime(this.initialScanFinished, false)) {
watcher.emit(
"initial-missing",
- "scan (parent directory missing in initial scan)"
+ "scan (parent directory missing in initial scan)",
);
}
}
@@ -579,7 +752,7 @@
return;
}
const itemPaths = new Set(
- items.map(item => path.join(this.path, item.normalize("NFC")))
+ items.map((item) => path.join(this.path, item.normalize("NFC"))),
);
for (const file of this.files.keys()) {
if (!itemPaths.has(file)) {
@@ -613,7 +786,7 @@
if (watcher.checkStartTime(this.initialScanFinished, false)) {
watcher.emit(
"initial-missing",
- "scan (missing in initial scan)"
+ "scan (missing in initial scan)",
);
}
}
@@ -639,7 +812,7 @@
// TODO https://github.com/libuv/libuv/pull/4566
(err2.code === "EINVAL" && IS_WIN)
) {
- this.setMissing(itemPath, initial, "scan (" + err2.code + ")");
+ this.setMissing(itemPath, initial, `scan (${err2.code})`);
} else {
this.onScanError(err2);
}
@@ -648,23 +821,25 @@
}
if (stats.isFile() || stats.isSymbolicLink()) {
if (stats.mtime) {
- ensureFsAccuracy(stats.mtime);
+ ensureFsAccuracy(+stats.mtime);
}
this.setFileTime(
itemPath,
+stats.mtime || +stats.ctime || 1,
initial,
true,
- "scan (file)"
+ "scan (file)",
);
- } else if (stats.isDirectory()) {
- if (!initial || !this.directories.has(itemPath))
- this.setDirectory(
- itemPath,
- +stats.birthtime || 1,
- initial,
- "scan (dir)"
- );
+ } else if (
+ stats.isDirectory() &&
+ (!initial || !this.directories.has(itemPath))
+ ) {
+ this.setDirectory(
+ itemPath,
+ +stats.birthtime || 1,
+ initial,
+ "scan (dir)",
+ );
}
itemFinished();
});
@@ -674,6 +849,9 @@
});
}
+ /**
+ * @returns {Record<string, number>} times
+ */
getTimes() {
const obj = Object.create(null);
let safeTime = this.lastWatchEvent;
@@ -684,7 +862,9 @@
}
if (this.nestedWatching) {
for (const w of this.directories.values()) {
- const times = w.directoryWatcher.getTimes();
+ const times =
+ /** @type {Watcher<DirectoryWatcherEvents>} */
+ (w).directoryWatcher.getTimes();
for (const file of Object.keys(times)) {
const time = times[file];
safeTime = Math.max(safeTime, time);
@@ -696,7 +876,7 @@
if (!this.initialScan) {
for (const watchers of this.watchers.values()) {
for (const watcher of watchers) {
- const path = watcher.path;
+ const { path } = watcher;
if (!Object.prototype.hasOwnProperty.call(obj, path)) {
obj[path] = null;
}
@@ -706,6 +886,11 @@
return obj;
}
+ /**
+ * @param {TimeInfoEntries} fileTimestamps file timestamps
+ * @param {TimeInfoEntries} directoryTimestamps directory timestamps
+ * @returns {number} safe time
+ */
collectTimeInfoEntries(fileTimestamps, directoryTimestamps) {
let safeTime = this.lastWatchEvent;
for (const [file, entry] of this.files) {
@@ -717,23 +902,25 @@
for (const w of this.directories.values()) {
safeTime = Math.max(
safeTime,
- w.directoryWatcher.collectTimeInfoEntries(
+ /** @type {Watcher<DirectoryWatcherEvents>} */
+ (w).directoryWatcher.collectTimeInfoEntries(
fileTimestamps,
- directoryTimestamps
- )
+ directoryTimestamps,
+ ),
);
}
fileTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
directoryTimestamps.set(this.path, {
- safeTime
+ safeTime,
});
} else {
for (const dir of this.directories.keys()) {
// No additional info about this directory
// but maybe another DirectoryWatcher has info
fileTimestamps.set(dir, EXISTANCE_ONLY_TIME_ENTRY);
- if (!directoryTimestamps.has(dir))
+ if (!directoryTimestamps.has(dir)) {
directoryTimestamps.set(dir, EXISTANCE_ONLY_TIME_ENTRY);
+ }
}
fileTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
directoryTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
@@ -741,7 +928,7 @@
if (!this.initialScan) {
for (const watchers of this.watchers.values()) {
for (const watcher of watchers) {
- const path = watcher.path;
+ const { path } = watcher;
if (!fileTimestamps.has(path)) {
fileTimestamps.set(path, null);
}
@@ -760,7 +947,8 @@
}
if (this.nestedWatching) {
for (const w of this.directories.values()) {
- w.close();
+ /** @type {Watcher<DirectoryWatcherEvents>} */
+ (w).close();
}
this.directories.clear();
}
@@ -774,18 +962,4 @@
module.exports = DirectoryWatcher;
module.exports.EXISTANCE_ONLY_TIME_ENTRY = EXISTANCE_ONLY_TIME_ENTRY;
-
-function fixupEntryAccuracy(entry) {
- if (entry.accuracy > FS_ACCURACY) {
- entry.safeTime = entry.safeTime - entry.accuracy + FS_ACCURACY;
- entry.accuracy = FS_ACCURACY;
- }
-}
-
-function ensureFsAccuracy(mtime) {
- if (!mtime) return;
- if (FS_ACCURACY > 1 && mtime % 1 !== 0) FS_ACCURACY = 1;
- else if (FS_ACCURACY > 10 && mtime % 10 !== 0) FS_ACCURACY = 10;
- else if (FS_ACCURACY > 100 && mtime % 100 !== 0) FS_ACCURACY = 100;
- else if (FS_ACCURACY > 1000 && mtime % 1000 !== 0) FS_ACCURACY = 1000;
-}
+module.exports.Watcher = Watcher;
--
Gitblit v1.9.3