mirror of
https://github.com/hanzoai/fsevents.git
synced 2026-09-24 16:59:25 +00:00
When you scan a really large folder for file event changes, the client or kernel might not be able to keep up with all the initial 'add' events sent by fsevents. This happens for me with our humongous vite project that has thousands of files that are sent to firefox. At some point today, chokidar receives undefined as file type when it's actually a rescan request, and fsevents / chokidar attempts to unlink the directory instead of rescanning it, making vite crash after a while instead of finishing processing fsevents. This might be a fix in the correct direction, but the maintainers here are probably better at evaluating it. With this patch locally, vite no longer stops working for large projects on initial load.
84 lines
2.4 KiB
JavaScript
84 lines
2.4 KiB
JavaScript
/*
|
|
** © 2020 by Philipp Dunkel, Ben Noordhuis, Elan Shankar, Paul Miller
|
|
** Licensed under MIT License.
|
|
*/
|
|
|
|
/* jshint node:true */
|
|
"use strict";
|
|
|
|
if (process.platform !== "darwin") {
|
|
throw new Error(`Module 'fsevents' is not compatible with platform '${process.platform}'`);
|
|
}
|
|
|
|
const Native = require("./fsevents.node");
|
|
const events = Native.constants;
|
|
|
|
function watch(path, since, handler) {
|
|
if (typeof path !== "string") {
|
|
throw new TypeError(`fsevents argument 1 must be a string and not a ${typeof path}`);
|
|
}
|
|
if ("function" === typeof since && "undefined" === typeof handler) {
|
|
handler = since;
|
|
since = Native.flags.SinceNow;
|
|
}
|
|
if (typeof since !== "number") {
|
|
throw new TypeError(`fsevents argument 2 must be a number and not a ${typeof since}`);
|
|
}
|
|
if (typeof handler !== "function") {
|
|
throw new TypeError(`fsevents argument 3 must be a function and not a ${typeof handler}`);
|
|
}
|
|
|
|
let instance = Native.start(Native.global, path, since, handler);
|
|
if (!instance) throw new Error(`could not watch: ${path}`);
|
|
return () => {
|
|
const result = instance ? Promise.resolve(instance).then(Native.stop) : Promise.resolve(undefined);
|
|
instance = undefined;
|
|
return result;
|
|
};
|
|
}
|
|
|
|
function getInfo(path, flags) {
|
|
return {
|
|
path,
|
|
flags,
|
|
event: getEventType(flags),
|
|
type: getFileType(flags),
|
|
changes: getFileChanges(flags),
|
|
};
|
|
}
|
|
|
|
function getFileType(flags) {
|
|
if (events.ItemIsFile & flags) return "file";
|
|
if (events.ItemIsDir & flags) return "directory";
|
|
if (events.MustScanSubDirs & flags) return "directory";
|
|
if (events.ItemIsSymlink & flags) return "symlink";
|
|
}
|
|
function anyIsTrue(obj) {
|
|
for (let key in obj) {
|
|
if (obj[key]) return true;
|
|
}
|
|
return false;
|
|
}
|
|
function getEventType(flags) {
|
|
if (events.ItemRemoved & flags) return "deleted";
|
|
if (events.ItemRenamed & flags) return "moved";
|
|
if (events.ItemCreated & flags) return "created";
|
|
if (events.ItemModified & flags) return "modified";
|
|
if (events.RootChanged & flags) return "root-changed";
|
|
if (events.ItemCloned & flags) return "cloned";
|
|
if (anyIsTrue(flags)) return "modified";
|
|
return "unknown";
|
|
}
|
|
function getFileChanges(flags) {
|
|
return {
|
|
inode: !!(events.ItemInodeMetaMod & flags),
|
|
finder: !!(events.ItemFinderInfoMod & flags),
|
|
access: !!(events.ItemChangeOwner & flags),
|
|
xattrs: !!(events.ItemXattrMod & flags),
|
|
};
|
|
}
|
|
|
|
exports.watch = watch;
|
|
exports.getInfo = getInfo;
|
|
exports.constants = events;
|