UNPKG

chaite

Version:

core for chatgpt-plugin and karin-plugin-chatgpt

1,561 lines (1,557 loc) 45.1 kB
import { join, relative, resolve, sep } from "node:path"; import { lstat, open, readdir, realpath, stat } from "fs/promises"; import * as sysPath from "path"; import { EventEmitter } from "events"; import { stat as stat$1, unwatchFile, watch, watchFile } from "fs"; import { type } from "os"; import { lstat as lstat$1, readdir as readdir$1, realpath as realpath$1, stat as stat$2 } from "node:fs/promises"; import { Readable } from "node:stream"; //#region node_modules/.pnpm/readdirp@4.1.2/node_modules/readdirp/esm/index.js const EntryTypes = { FILE_TYPE: "files", DIR_TYPE: "directories", FILE_DIR_TYPE: "files_directories", EVERYTHING_TYPE: "all" }; const defaultOptions = { root: ".", fileFilter: (_entryInfo) => true, directoryFilter: (_entryInfo) => true, type: EntryTypes.FILE_TYPE, lstat: false, depth: 2147483648, alwaysStat: false, highWaterMark: 4096 }; Object.freeze(defaultOptions); const RECURSIVE_ERROR_CODE = "READDIRP_RECURSIVE_ERROR"; const NORMAL_FLOW_ERRORS = new Set([ "ENOENT", "EPERM", "EACCES", "ELOOP", RECURSIVE_ERROR_CODE ]); const ALL_TYPES = [ EntryTypes.DIR_TYPE, EntryTypes.EVERYTHING_TYPE, EntryTypes.FILE_DIR_TYPE, EntryTypes.FILE_TYPE ]; const DIR_TYPES = new Set([ EntryTypes.DIR_TYPE, EntryTypes.EVERYTHING_TYPE, EntryTypes.FILE_DIR_TYPE ]); const FILE_TYPES = new Set([ EntryTypes.EVERYTHING_TYPE, EntryTypes.FILE_DIR_TYPE, EntryTypes.FILE_TYPE ]); const isNormalFlowError = (error) => NORMAL_FLOW_ERRORS.has(error.code); const wantBigintFsStats = process.platform === "win32"; const emptyFn = (_entryInfo) => true; const normalizeFilter = (filter) => { if (filter === void 0) return emptyFn; if (typeof filter === "function") return filter; if (typeof filter === "string") { const fl = filter.trim(); return (entry) => entry.basename === fl; } if (Array.isArray(filter)) { const trItems = filter.map((item) => item.trim()); return (entry) => trItems.some((f) => entry.basename === f); } return emptyFn; }; /** Readable readdir stream, emitting new files as they're being listed. */ var ReaddirpStream = class extends Readable { constructor(options = {}) { super({ objectMode: true, autoDestroy: true, highWaterMark: options.highWaterMark }); const opts = { ...defaultOptions, ...options }; const { root, type: type$1 } = opts; this._fileFilter = normalizeFilter(opts.fileFilter); this._directoryFilter = normalizeFilter(opts.directoryFilter); const statMethod = opts.lstat ? lstat$1 : stat$2; if (wantBigintFsStats) this._stat = (path$2) => statMethod(path$2, { bigint: true }); else this._stat = statMethod; this._maxDepth = opts.depth ?? defaultOptions.depth; this._wantsDir = type$1 ? DIR_TYPES.has(type$1) : false; this._wantsFile = type$1 ? FILE_TYPES.has(type$1) : false; this._wantsEverything = type$1 === EntryTypes.EVERYTHING_TYPE; this._root = resolve(root); this._isDirent = !opts.alwaysStat; this._statsProp = this._isDirent ? "dirent" : "stats"; this._rdOptions = { encoding: "utf8", withFileTypes: this._isDirent }; this.parents = [this._exploreDir(root, 1)]; this.reading = false; this.parent = void 0; } async _read(batch) { if (this.reading) return; this.reading = true; try { while (!this.destroyed && batch > 0) { const par = this.parent; const fil = par && par.files; if (fil && fil.length > 0) { const { path: path$2, depth } = par; const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path$2)); const awaited = await Promise.all(slice); for (const entry of awaited) { if (!entry) continue; if (this.destroyed) return; const entryType = await this._getEntryType(entry); if (entryType === "directory" && this._directoryFilter(entry)) { if (depth <= this._maxDepth) this.parents.push(this._exploreDir(entry.fullPath, depth + 1)); if (this._wantsDir) { this.push(entry); batch--; } } else if ((entryType === "file" || this._includeAsFile(entry)) && this._fileFilter(entry)) { if (this._wantsFile) { this.push(entry); batch--; } } } } else { const parent = this.parents.pop(); if (!parent) { this.push(null); break; } this.parent = await parent; if (this.destroyed) return; } } } catch (error) { this.destroy(error); } finally { this.reading = false; } } async _exploreDir(path$2, depth) { let files; try { files = await readdir$1(path$2, this._rdOptions); } catch (error) { this._onError(error); } return { files, depth, path: path$2 }; } async _formatEntry(dirent, path$2) { let entry; const basename$1 = this._isDirent ? dirent.name : dirent; try { const fullPath = resolve(join(path$2, basename$1)); entry = { path: relative(this._root, fullPath), fullPath, basename: basename$1 }; entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath); } catch (err) { this._onError(err); return; } return entry; } _onError(err) { if (isNormalFlowError(err) && !this.destroyed) this.emit("warn", err); else this.destroy(err); } async _getEntryType(entry) { if (!entry && this._statsProp in entry) return ""; const stats = entry[this._statsProp]; if (stats.isFile()) return "file"; if (stats.isDirectory()) return "directory"; if (stats && stats.isSymbolicLink()) { const full = entry.fullPath; try { const entryRealPath = await realpath$1(full); const entryRealPathStats = await lstat$1(entryRealPath); if (entryRealPathStats.isFile()) return "file"; if (entryRealPathStats.isDirectory()) { const len = entryRealPath.length; if (full.startsWith(entryRealPath) && full.substr(len, 1) === sep) { const recursiveError = /* @__PURE__ */ new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`); recursiveError.code = RECURSIVE_ERROR_CODE; return this._onError(recursiveError); } return "directory"; } } catch (error) { this._onError(error); return ""; } } } _includeAsFile(entry) { const stats = entry && entry[this._statsProp]; return stats && this._wantsEverything && !stats.isDirectory(); } }; /** * Streaming version: Reads all files and directories in given root recursively. * Consumes ~constant small amount of RAM. * @param root Root directory * @param options Options to specify root (start directory), filters and recursion depth */ function readdirp(root, options = {}) { let type$1 = options.entryType || options.type; if (type$1 === "both") type$1 = EntryTypes.FILE_DIR_TYPE; if (type$1) options.type = type$1; if (!root) throw new Error("readdirp: root argument is required. Usage: readdirp(root, options)"); else if (typeof root !== "string") throw new TypeError("readdirp: root argument must be a string. Usage: readdirp(root, options)"); else if (type$1 && !ALL_TYPES.includes(type$1)) throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(", ")}`); options.root = root; return new ReaddirpStream(options); } //#endregion //#region node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/handler.js const STR_DATA = "data"; const STR_END = "end"; const STR_CLOSE = "close"; const EMPTY_FN = () => {}; const pl = process.platform; const isWindows = pl === "win32"; const isMacos = pl === "darwin"; const isLinux = pl === "linux"; const isFreeBSD = pl === "freebsd"; const isIBMi = type() === "OS400"; const EVENTS = { ALL: "all", READY: "ready", ADD: "add", CHANGE: "change", ADD_DIR: "addDir", UNLINK: "unlink", UNLINK_DIR: "unlinkDir", RAW: "raw", ERROR: "error" }; const EV = EVENTS; const THROTTLE_MODE_WATCH = "watch"; const statMethods = { lstat, stat }; const KEY_LISTENERS = "listeners"; const KEY_ERR = "errHandlers"; const KEY_RAW = "rawEmitters"; const HANDLER_KEYS = [ KEY_LISTENERS, KEY_ERR, KEY_RAW ]; const binaryExtensions = new Set([ "3dm", "3ds", "3g2", "3gp", "7z", "a", "aac", "adp", "afdesign", "afphoto", "afpub", "ai", "aif", "aiff", "alz", "ape", "apk", "appimage", "ar", "arj", "asf", "au", "avi", "bak", "baml", "bh", "bin", "bk", "bmp", "btif", "bz2", "bzip2", "cab", "caf", "cgm", "class", "cmx", "cpio", "cr2", "cur", "dat", "dcm", "deb", "dex", "djvu", "dll", "dmg", "dng", "doc", "docm", "docx", "dot", "dotm", "dra", "DS_Store", "dsk", "dts", "dtshd", "dvb", "dwg", "dxf", "ecelp4800", "ecelp7470", "ecelp9600", "egg", "eol", "eot", "epub", "exe", "f4v", "fbs", "fh", "fla", "flac", "flatpak", "fli", "flv", "fpx", "fst", "fvt", "g3", "gh", "gif", "graffle", "gz", "gzip", "h261", "h263", "h264", "icns", "ico", "ief", "img", "ipa", "iso", "jar", "jpeg", "jpg", "jpgv", "jpm", "jxr", "key", "ktx", "lha", "lib", "lvp", "lz", "lzh", "lzma", "lzo", "m3u", "m4a", "m4v", "mar", "mdi", "mht", "mid", "midi", "mj2", "mka", "mkv", "mmr", "mng", "mobi", "mov", "movie", "mp3", "mp4", "mp4a", "mpeg", "mpg", "mpga", "mxu", "nef", "npx", "numbers", "nupkg", "o", "odp", "ods", "odt", "oga", "ogg", "ogv", "otf", "ott", "pages", "pbm", "pcx", "pdb", "pdf", "pea", "pgm", "pic", "png", "pnm", "pot", "potm", "potx", "ppa", "ppam", "ppm", "pps", "ppsm", "ppsx", "ppt", "pptm", "pptx", "psd", "pya", "pyc", "pyo", "pyv", "qt", "rar", "ras", "raw", "resources", "rgb", "rip", "rlc", "rmf", "rmvb", "rpm", "rtf", "rz", "s3m", "s7z", "scpt", "sgi", "shar", "snap", "sil", "sketch", "slk", "smv", "snk", "so", "stl", "suo", "sub", "swf", "tar", "tbz", "tbz2", "tga", "tgz", "thmx", "tif", "tiff", "tlz", "ttc", "ttf", "txz", "udf", "uvh", "uvi", "uvm", "uvp", "uvs", "uvu", "viv", "vob", "war", "wav", "wax", "wbmp", "wdp", "weba", "webm", "webp", "whl", "wim", "wm", "wma", "wmv", "wmx", "woff", "woff2", "wrm", "wvx", "xbm", "xif", "xla", "xlam", "xls", "xlsb", "xlsm", "xlsx", "xlt", "xltm", "xltx", "xm", "xmind", "xpi", "xpm", "xwd", "xz", "z", "zip", "zipx" ]); const isBinaryPath = (filePath) => binaryExtensions.has(sysPath.extname(filePath).slice(1).toLowerCase()); const foreach = (val, fn) => { if (val instanceof Set) val.forEach(fn); else fn(val); }; const addAndConvert = (main, prop, item) => { let container = main[prop]; if (!(container instanceof Set)) main[prop] = container = new Set([container]); container.add(item); }; const clearItem = (cont) => (key) => { const set = cont[key]; if (set instanceof Set) set.clear(); else delete cont[key]; }; const delFromSet = (main, prop, item) => { const container = main[prop]; if (container instanceof Set) container.delete(item); else if (container === item) delete main[prop]; }; const isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val; const FsWatchInstances = /* @__PURE__ */ new Map(); /** * Instantiates the fs_watch interface * @param path to be watched * @param options to be passed to fs_watch * @param listener main event handler * @param errHandler emits info about errors * @param emitRaw emits raw event data * @returns {NativeFsWatcher} */ function createFsWatchInstance(path$2, options, listener, errHandler, emitRaw) { const handleEvent = (rawEvent, evPath) => { listener(path$2); emitRaw(rawEvent, evPath, { watchedPath: path$2 }); if (evPath && path$2 !== evPath) fsWatchBroadcast(sysPath.resolve(path$2, evPath), KEY_LISTENERS, sysPath.join(path$2, evPath)); }; try { return watch(path$2, { persistent: options.persistent }, handleEvent); } catch (error) { errHandler(error); return; } } /** * Helper for passing fs_watch event data to a collection of listeners * @param fullPath absolute path bound to fs_watch instance */ const fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => { const cont = FsWatchInstances.get(fullPath); if (!cont) return; foreach(cont[listenerType], (listener) => { listener(val1, val2, val3); }); }; /** * Instantiates the fs_watch interface or binds listeners * to an existing one covering the same file system entry * @param path * @param fullPath absolute path * @param options to be passed to fs_watch * @param handlers container for event listener functions */ const setFsWatchListener = (path$2, fullPath, options, handlers) => { const { listener, errHandler, rawEmitter } = handlers; let cont = FsWatchInstances.get(fullPath); let watcher; if (!options.persistent) { watcher = createFsWatchInstance(path$2, options, listener, errHandler, rawEmitter); if (!watcher) return; return watcher.close.bind(watcher); } if (cont) { addAndConvert(cont, KEY_LISTENERS, listener); addAndConvert(cont, KEY_ERR, errHandler); addAndConvert(cont, KEY_RAW, rawEmitter); } else { watcher = createFsWatchInstance(path$2, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, fsWatchBroadcast.bind(null, fullPath, KEY_RAW)); if (!watcher) return; watcher.on(EV.ERROR, async (error) => { const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR); if (cont) cont.watcherUnusable = true; if (isWindows && error.code === "EPERM") try { await (await open(path$2, "r")).close(); broadcastErr(error); } catch (err) {} else broadcastErr(error); }); cont = { listeners: listener, errHandlers: errHandler, rawEmitters: rawEmitter, watcher }; FsWatchInstances.set(fullPath, cont); } return () => { delFromSet(cont, KEY_LISTENERS, listener); delFromSet(cont, KEY_ERR, errHandler); delFromSet(cont, KEY_RAW, rawEmitter); if (isEmptySet(cont.listeners)) { cont.watcher.close(); FsWatchInstances.delete(fullPath); HANDLER_KEYS.forEach(clearItem(cont)); cont.watcher = void 0; Object.freeze(cont); } }; }; const FsWatchFileInstances = /* @__PURE__ */ new Map(); /** * Instantiates the fs_watchFile interface or binds listeners * to an existing one covering the same file system entry * @param path to be watched * @param fullPath absolute path * @param options options to be passed to fs_watchFile * @param handlers container for event listener functions * @returns closer */ const setFsWatchFileListener = (path$2, fullPath, options, handlers) => { const { listener, rawEmitter } = handlers; let cont = FsWatchFileInstances.get(fullPath); const copts = cont && cont.options; if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) { unwatchFile(fullPath); cont = void 0; } if (cont) { addAndConvert(cont, KEY_LISTENERS, listener); addAndConvert(cont, KEY_RAW, rawEmitter); } else { cont = { listeners: listener, rawEmitters: rawEmitter, options, watcher: watchFile(fullPath, options, (curr, prev) => { foreach(cont.rawEmitters, (rawEmitter$1) => { rawEmitter$1(EV.CHANGE, fullPath, { curr, prev }); }); const currmtime = curr.mtimeMs; if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) foreach(cont.listeners, (listener$1) => listener$1(path$2, curr)); }) }; FsWatchFileInstances.set(fullPath, cont); } return () => { delFromSet(cont, KEY_LISTENERS, listener); delFromSet(cont, KEY_RAW, rawEmitter); if (isEmptySet(cont.listeners)) { FsWatchFileInstances.delete(fullPath); unwatchFile(fullPath); cont.options = cont.watcher = void 0; Object.freeze(cont); } }; }; /** * @mixin */ var NodeFsHandler = class { constructor(fsW) { this.fsw = fsW; this._boundHandleError = (error) => fsW._handleError(error); } /** * Watch file for changes with fs_watchFile or fs_watch. * @param path to file or dir * @param listener on fs change * @returns closer for the watcher instance */ _watchWithNodeFs(path$2, listener) { const opts = this.fsw.options; const directory = sysPath.dirname(path$2); const basename$1 = sysPath.basename(path$2); this.fsw._getWatchedDir(directory).add(basename$1); const absolutePath = sysPath.resolve(path$2); const options = { persistent: opts.persistent }; if (!listener) listener = EMPTY_FN; let closer; if (opts.usePolling) { options.interval = opts.interval !== opts.binaryInterval && isBinaryPath(basename$1) ? opts.binaryInterval : opts.interval; closer = setFsWatchFileListener(path$2, absolutePath, options, { listener, rawEmitter: this.fsw._emitRaw }); } else closer = setFsWatchListener(path$2, absolutePath, options, { listener, errHandler: this._boundHandleError, rawEmitter: this.fsw._emitRaw }); return closer; } /** * Watch a file and emit add event if warranted. * @returns closer for the watcher instance */ _handleFile(file, stats, initialAdd) { if (this.fsw.closed) return; const dirname = sysPath.dirname(file); const basename$1 = sysPath.basename(file); const parent = this.fsw._getWatchedDir(dirname); let prevStats = stats; if (parent.has(basename$1)) return; const listener = async (path$2, newStats) => { if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5)) return; if (!newStats || newStats.mtimeMs === 0) try { const newStats$1 = await stat(file); if (this.fsw.closed) return; const at = newStats$1.atimeMs; const mt = newStats$1.mtimeMs; if (!at || at <= mt || mt !== prevStats.mtimeMs) this.fsw._emit(EV.CHANGE, file, newStats$1); if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats$1.ino) { this.fsw._closeFile(path$2); prevStats = newStats$1; const closer$1 = this._watchWithNodeFs(file, listener); if (closer$1) this.fsw._addPathCloser(path$2, closer$1); } else prevStats = newStats$1; } catch (error) { this.fsw._remove(dirname, basename$1); } else if (parent.has(basename$1)) { const at = newStats.atimeMs; const mt = newStats.mtimeMs; if (!at || at <= mt || mt !== prevStats.mtimeMs) this.fsw._emit(EV.CHANGE, file, newStats); prevStats = newStats; } }; const closer = this._watchWithNodeFs(file, listener); if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) { if (!this.fsw._throttle(EV.ADD, file, 0)) return; this.fsw._emit(EV.ADD, file, stats); } return closer; } /** * Handle symlinks encountered while reading a dir. * @param entry returned by readdirp * @param directory path of dir being read * @param path of this item * @param item basename of this item * @returns true if no more processing is needed for this entry. */ async _handleSymlink(entry, directory, path$2, item) { if (this.fsw.closed) return; const full = entry.fullPath; const dir = this.fsw._getWatchedDir(directory); if (!this.fsw.options.followSymlinks) { this.fsw._incrReadyCount(); let linkPath; try { linkPath = await realpath(path$2); } catch (e) { this.fsw._emitReady(); return true; } if (this.fsw.closed) return; if (dir.has(item)) { if (this.fsw._symlinkPaths.get(full) !== linkPath) { this.fsw._symlinkPaths.set(full, linkPath); this.fsw._emit(EV.CHANGE, path$2, entry.stats); } } else { dir.add(item); this.fsw._symlinkPaths.set(full, linkPath); this.fsw._emit(EV.ADD, path$2, entry.stats); } this.fsw._emitReady(); return true; } if (this.fsw._symlinkPaths.has(full)) return true; this.fsw._symlinkPaths.set(full, true); } _handleRead(directory, initialAdd, wh, target, dir, depth, throttler) { directory = sysPath.join(directory, ""); throttler = this.fsw._throttle("readdir", directory, 1e3); if (!throttler) return; const previous = this.fsw._getWatchedDir(wh.path); const current = /* @__PURE__ */ new Set(); let stream = this.fsw._readdirp(directory, { fileFilter: (entry) => wh.filterPath(entry), directoryFilter: (entry) => wh.filterDir(entry) }); if (!stream) return; stream.on(STR_DATA, async (entry) => { if (this.fsw.closed) { stream = void 0; return; } const item = entry.path; let path$2 = sysPath.join(directory, item); current.add(item); if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path$2, item)) return; if (this.fsw.closed) { stream = void 0; return; } if (item === target || !target && !previous.has(item)) { this.fsw._incrReadyCount(); path$2 = sysPath.join(dir, sysPath.relative(dir, path$2)); this._addToNodeFs(path$2, initialAdd, wh, depth + 1); } }).on(EV.ERROR, this._boundHandleError); return new Promise((resolve$1, reject) => { if (!stream) return reject(); stream.once(STR_END, () => { if (this.fsw.closed) { stream = void 0; return; } const wasThrottled = throttler ? throttler.clear() : false; resolve$1(void 0); previous.getChildren().filter((item) => { return item !== directory && !current.has(item); }).forEach((item) => { this.fsw._remove(directory, item); }); stream = void 0; if (wasThrottled) this._handleRead(directory, false, wh, target, dir, depth, throttler); }); }); } /** * Read directory to add / remove files from `@watched` list and re-read it on change. * @param dir fs path * @param stats * @param initialAdd * @param depth relative to user-supplied path * @param target child path targeted for watch * @param wh Common watch helpers for this path * @param realpath * @returns closer for the watcher instance. */ async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath$2) { const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir)); const tracked = parentDir.has(sysPath.basename(dir)); if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) this.fsw._emit(EV.ADD_DIR, dir, stats); parentDir.add(sysPath.basename(dir)); this.fsw._getWatchedDir(dir); let throttler; let closer; const oDepth = this.fsw.options.depth; if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath$2)) { if (!target) { await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler); if (this.fsw.closed) return; } closer = this._watchWithNodeFs(dir, (dirPath, stats$1) => { if (stats$1 && stats$1.mtimeMs === 0) return; this._handleRead(dirPath, false, wh, target, dir, depth, throttler); }); } return closer; } /** * Handle added file, directory, or glob pattern. * Delegates call to _handleFile / _handleDir after checks. * @param path to file or ir * @param initialAdd was the file added at watch instantiation? * @param priorWh depth relative to user-supplied path * @param depth Child path actually targeted for watch * @param target Child path actually targeted for watch */ async _addToNodeFs(path$2, initialAdd, priorWh, depth, target) { const ready = this.fsw._emitReady; if (this.fsw._isIgnored(path$2) || this.fsw.closed) { ready(); return false; } const wh = this.fsw._getWatchHelpers(path$2); if (priorWh) { wh.filterPath = (entry) => priorWh.filterPath(entry); wh.filterDir = (entry) => priorWh.filterDir(entry); } try { const stats = await statMethods[wh.statMethod](wh.watchPath); if (this.fsw.closed) return; if (this.fsw._isIgnored(wh.watchPath, stats)) { ready(); return false; } const follow = this.fsw.options.followSymlinks; let closer; if (stats.isDirectory()) { const absPath = sysPath.resolve(path$2); const targetPath = follow ? await realpath(path$2) : path$2; if (this.fsw.closed) return; closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath); if (this.fsw.closed) return; if (absPath !== targetPath && targetPath !== void 0) this.fsw._symlinkPaths.set(absPath, targetPath); } else if (stats.isSymbolicLink()) { const targetPath = follow ? await realpath(path$2) : path$2; if (this.fsw.closed) return; const parent = sysPath.dirname(wh.watchPath); this.fsw._getWatchedDir(parent).add(wh.watchPath); this.fsw._emit(EV.ADD, wh.watchPath, stats); closer = await this._handleDir(parent, stats, initialAdd, depth, path$2, wh, targetPath); if (this.fsw.closed) return; if (targetPath !== void 0) this.fsw._symlinkPaths.set(sysPath.resolve(path$2), targetPath); } else closer = this._handleFile(wh.watchPath, stats, initialAdd); ready(); if (closer) this.fsw._addPathCloser(path$2, closer); return false; } catch (error) { if (this.fsw._handleError(error)) { ready(); return path$2; } } } }; //#endregion //#region node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js /*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */ const SLASH = "/"; const SLASH_SLASH = "//"; const ONE_DOT = "."; const TWO_DOTS = ".."; const STRING_TYPE = "string"; const BACK_SLASH_RE = /\\/g; const DOUBLE_SLASH_RE = /\/\//; const DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/; const REPLACER_RE = /^\.[/\\]/; function arrify(item) { return Array.isArray(item) ? item : [item]; } const isMatcherObject = (matcher) => typeof matcher === "object" && matcher !== null && !(matcher instanceof RegExp); function createPattern(matcher) { if (typeof matcher === "function") return matcher; if (typeof matcher === "string") return (string) => matcher === string; if (matcher instanceof RegExp) return (string) => matcher.test(string); if (typeof matcher === "object" && matcher !== null) return (string) => { if (matcher.path === string) return true; if (matcher.recursive) { const relative$1 = sysPath.relative(matcher.path, string); if (!relative$1) return false; return !relative$1.startsWith("..") && !sysPath.isAbsolute(relative$1); } return false; }; return () => false; } function normalizePath(path$2) { if (typeof path$2 !== "string") throw new Error("string expected"); path$2 = sysPath.normalize(path$2); path$2 = path$2.replace(/\\/g, "/"); let prepend = false; if (path$2.startsWith("//")) prepend = true; const DOUBLE_SLASH_RE$1 = /\/\//; while (path$2.match(DOUBLE_SLASH_RE$1)) path$2 = path$2.replace(DOUBLE_SLASH_RE$1, "/"); if (prepend) path$2 = "/" + path$2; return path$2; } function matchPatterns(patterns, testString, stats) { const path$2 = normalizePath(testString); for (let index = 0; index < patterns.length; index++) { const pattern = patterns[index]; if (pattern(path$2, stats)) return true; } return false; } function anymatch(matchers, testString) { if (matchers == null) throw new TypeError("anymatch: specify first argument"); const patterns = arrify(matchers).map((matcher) => createPattern(matcher)); if (testString == null) return (testString$1, stats) => { return matchPatterns(patterns, testString$1, stats); }; return matchPatterns(patterns, testString); } const unifyPaths = (paths_) => { const paths = arrify(paths_).flat(); if (!paths.every((p) => typeof p === STRING_TYPE)) throw new TypeError(`Non-string provided as watch path: ${paths}`); return paths.map(normalizePathToUnix); }; const toUnix = (string) => { let str = string.replace(BACK_SLASH_RE, SLASH); let prepend = false; if (str.startsWith(SLASH_SLASH)) prepend = true; while (str.match(DOUBLE_SLASH_RE)) str = str.replace(DOUBLE_SLASH_RE, SLASH); if (prepend) str = SLASH + str; return str; }; const normalizePathToUnix = (path$2) => toUnix(sysPath.normalize(toUnix(path$2))); const normalizeIgnored = (cwd = "") => (path$2) => { if (typeof path$2 === "string") return normalizePathToUnix(sysPath.isAbsolute(path$2) ? path$2 : sysPath.join(cwd, path$2)); else return path$2; }; const getAbsolutePath = (path$2, cwd) => { if (sysPath.isAbsolute(path$2)) return path$2; return sysPath.join(cwd, path$2); }; const EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set()); /** * Directory entry. */ var DirEntry = class { constructor(dir, removeWatcher) { this.path = dir; this._removeWatcher = removeWatcher; this.items = /* @__PURE__ */ new Set(); } add(item) { const { items } = this; if (!items) return; if (item !== ONE_DOT && item !== TWO_DOTS) items.add(item); } async remove(item) { const { items } = this; if (!items) return; items.delete(item); if (items.size > 0) return; const dir = this.path; try { await readdir(dir); } catch (err) { if (this._removeWatcher) this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir)); } } has(item) { const { items } = this; if (!items) return; return items.has(item); } getChildren() { const { items } = this; if (!items) return []; return [...items.values()]; } dispose() { this.items.clear(); this.path = ""; this._removeWatcher = EMPTY_FN; this.items = EMPTY_SET; Object.freeze(this); } }; const STAT_METHOD_F = "stat"; const STAT_METHOD_L = "lstat"; var WatchHelper = class { constructor(path$2, follow, fsw) { this.fsw = fsw; const watchPath = path$2; this.path = path$2 = path$2.replace(REPLACER_RE, ""); this.watchPath = watchPath; this.fullWatchPath = sysPath.resolve(watchPath); this.dirParts = []; this.dirParts.forEach((parts) => { if (parts.length > 1) parts.pop(); }); this.followSymlinks = follow; this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L; } entryPath(entry) { return sysPath.join(this.watchPath, sysPath.relative(this.watchPath, entry.fullPath)); } filterPath(entry) { const { stats } = entry; if (stats && stats.isSymbolicLink()) return this.filterDir(entry); const resolvedPath = this.entryPath(entry); return this.fsw._isntIgnored(resolvedPath, stats) && this.fsw._hasReadPermissions(stats); } filterDir(entry) { return this.fsw._isntIgnored(this.entryPath(entry), entry.stats); } }; /** * Watches files & directories for changes. Emitted events: * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error` * * new FSWatcher() * .add(directories) * .on('add', path => log('File', path, 'was added')) */ var FSWatcher = class extends EventEmitter { constructor(_opts = {}) { super(); this.closed = false; this._closers = /* @__PURE__ */ new Map(); this._ignoredPaths = /* @__PURE__ */ new Set(); this._throttled = /* @__PURE__ */ new Map(); this._streams = /* @__PURE__ */ new Set(); this._symlinkPaths = /* @__PURE__ */ new Map(); this._watched = /* @__PURE__ */ new Map(); this._pendingWrites = /* @__PURE__ */ new Map(); this._pendingUnlinks = /* @__PURE__ */ new Map(); this._readyCount = 0; this._readyEmitted = false; const awf = _opts.awaitWriteFinish; const DEF_AWF = { stabilityThreshold: 2e3, pollInterval: 100 }; const opts = { persistent: true, ignoreInitial: false, ignorePermissionErrors: false, interval: 100, binaryInterval: 300, followSymlinks: true, usePolling: false, atomic: true, ..._opts, ignored: _opts.ignored ? arrify(_opts.ignored) : arrify([]), awaitWriteFinish: awf === true ? DEF_AWF : typeof awf === "object" ? { ...DEF_AWF, ...awf } : false }; if (isIBMi) opts.usePolling = true; if (opts.atomic === void 0) opts.atomic = !opts.usePolling; const envPoll = process.env.CHOKIDAR_USEPOLLING; if (envPoll !== void 0) { const envLower = envPoll.toLowerCase(); if (envLower === "false" || envLower === "0") opts.usePolling = false; else if (envLower === "true" || envLower === "1") opts.usePolling = true; else opts.usePolling = !!envLower; } const envInterval = process.env.CHOKIDAR_INTERVAL; if (envInterval) opts.interval = Number.parseInt(envInterval, 10); let readyCalls = 0; this._emitReady = () => { readyCalls++; if (readyCalls >= this._readyCount) { this._emitReady = EMPTY_FN; this._readyEmitted = true; process.nextTick(() => this.emit(EVENTS.READY)); } }; this._emitRaw = (...args) => this.emit(EVENTS.RAW, ...args); this._boundRemove = this._remove.bind(this); this.options = opts; this._nodeFsHandler = new NodeFsHandler(this); Object.freeze(opts); } _addIgnoredPath(matcher) { if (isMatcherObject(matcher)) { for (const ignored of this._ignoredPaths) if (isMatcherObject(ignored) && ignored.path === matcher.path && ignored.recursive === matcher.recursive) return; } this._ignoredPaths.add(matcher); } _removeIgnoredPath(matcher) { this._ignoredPaths.delete(matcher); if (typeof matcher === "string") { for (const ignored of this._ignoredPaths) if (isMatcherObject(ignored) && ignored.path === matcher) this._ignoredPaths.delete(ignored); } } /** * Adds paths to be watched on an existing FSWatcher instance. * @param paths_ file or file list. Other arguments are unused */ add(paths_, _origAdd, _internal) { const { cwd } = this.options; this.closed = false; this._closePromise = void 0; let paths = unifyPaths(paths_); if (cwd) paths = paths.map((path$2) => { return getAbsolutePath(path$2, cwd); }); paths.forEach((path$2) => { this._removeIgnoredPath(path$2); }); this._userIgnored = void 0; if (!this._readyCount) this._readyCount = 0; this._readyCount += paths.length; Promise.all(paths.map(async (path$2) => { const res = await this._nodeFsHandler._addToNodeFs(path$2, !_internal, void 0, 0, _origAdd); if (res) this._emitReady(); return res; })).then((results) => { if (this.closed) return; results.forEach((item) => { if (item) this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item)); }); }); return this; } /** * Close watchers or start ignoring events from specified paths. */ unwatch(paths_) { if (this.closed) return this; const paths = unifyPaths(paths_); const { cwd } = this.options; paths.forEach((path$2) => { if (!sysPath.isAbsolute(path$2) && !this._closers.has(path$2)) { if (cwd) path$2 = sysPath.join(cwd, path$2); path$2 = sysPath.resolve(path$2); } this._closePath(path$2); this._addIgnoredPath(path$2); if (this._watched.has(path$2)) this._addIgnoredPath({ path: path$2, recursive: true }); this._userIgnored = void 0; }); return this; } /** * Close watchers and remove all listeners from watched paths. */ close() { if (this._closePromise) return this._closePromise; this.closed = true; this.removeAllListeners(); const closers = []; this._closers.forEach((closerList) => closerList.forEach((closer) => { const promise = closer(); if (promise instanceof Promise) closers.push(promise); })); this._streams.forEach((stream) => stream.destroy()); this._userIgnored = void 0; this._readyCount = 0; this._readyEmitted = false; this._watched.forEach((dirent) => dirent.dispose()); this._closers.clear(); this._watched.clear(); this._streams.clear(); this._symlinkPaths.clear(); this._throttled.clear(); this._closePromise = closers.length ? Promise.all(closers).then(() => void 0) : Promise.resolve(); return this._closePromise; } /** * Expose list of watched paths * @returns for chaining */ getWatched() { const watchList = {}; this._watched.forEach((entry, dir) => { const index = (this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir) || ONE_DOT; watchList[index] = entry.getChildren().sort(); }); return watchList; } emitWithAll(event, args) { this.emit(event, ...args); if (event !== EVENTS.ERROR) this.emit(EVENTS.ALL, event, ...args); } /** * Normalize and emit events. * Calling _emit DOES NOT MEAN emit() would be called! * @param event Type of event * @param path File or directory path * @param stats arguments to be passed with event * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag */ async _emit(event, path$2, stats) { if (this.closed) return; const opts = this.options; if (isWindows) path$2 = sysPath.normalize(path$2); if (opts.cwd) path$2 = sysPath.relative(opts.cwd, path$2); const args = [path$2]; if (stats != null) args.push(stats); const awf = opts.awaitWriteFinish; let pw; if (awf && (pw = this._pendingWrites.get(path$2))) { pw.lastChange = /* @__PURE__ */ new Date(); return this; } if (opts.atomic) { if (event === EVENTS.UNLINK) { this._pendingUnlinks.set(path$2, [event, ...args]); setTimeout(() => { this._pendingUnlinks.forEach((entry, path$3) => { this.emit(...entry); this.emit(EVENTS.ALL, ...entry); this._pendingUnlinks.delete(path$3); }); }, typeof opts.atomic === "number" ? opts.atomic : 100); return this; } if (event === EVENTS.ADD && this._pendingUnlinks.has(path$2)) { event = EVENTS.CHANGE; this._pendingUnlinks.delete(path$2); } } if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) { const awfEmit = (err, stats$1) => { if (err) { event = EVENTS.ERROR; args[0] = err; this.emitWithAll(event, args); } else if (stats$1) { if (args.length > 1) args[1] = stats$1; else args.push(stats$1); this.emitWithAll(event, args); } }; this._awaitWriteFinish(path$2, awf.stabilityThreshold, event, awfEmit); return this; } if (event === EVENTS.CHANGE) { if (!this._throttle(EVENTS.CHANGE, path$2, 50)) return this; } if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) { const fullPath = opts.cwd ? sysPath.join(opts.cwd, path$2) : path$2; let stats$1; try { stats$1 = await stat(fullPath); } catch (err) {} if (!stats$1 || this.closed) return; args.push(stats$1); } this.emitWithAll(event, args); return this; } /** * Common handler for errors * @returns The error if defined, otherwise the value of the FSWatcher instance's `closed` flag */ _handleError(error) { const code = error && error.code; if (error && code !== "ENOENT" && code !== "ENOTDIR" && (!this.options.ignorePermissionErrors || code !== "EPERM" && code !== "EACCES")) this.emit(EVENTS.ERROR, error); return error || this.closed; } /** * Helper utility for throttling * @param actionType type being throttled * @param path being acted upon * @param timeout duration of time to suppress duplicate actions * @returns tracking object or false if action should be suppressed */ _throttle(actionType, path$2, timeout) { if (!this._throttled.has(actionType)) this._throttled.set(actionType, /* @__PURE__ */ new Map()); const action = this._throttled.get(actionType); if (!action) throw new Error("invalid throttle"); const actionPath = action.get(path$2); if (actionPath) { actionPath.count++; return false; } let timeoutObject; const clear = () => { const item = action.get(path$2); const count = item ? item.count : 0; action.delete(path$2); clearTimeout(timeoutObject); if (item) clearTimeout(item.timeoutObject); return count; }; timeoutObject = setTimeout(clear, timeout); const thr = { timeoutObject, clear, count: 0 }; action.set(path$2, thr); return thr; } _incrReadyCount() { return this._readyCount++; } /** * Awaits write operation to finish. * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback. * @param path being acted upon * @param threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished * @param event * @param awfEmit Callback to be called when ready for event to be emitted. */ _awaitWriteFinish(path$2, threshold, event, awfEmit) { const awf = this.options.awaitWriteFinish; if (typeof awf !== "object") return; const pollInterval = awf.pollInterval; let timeoutHandler; let fullPath = path$2; if (this.options.cwd && !sysPath.isAbsolute(path$2)) fullPath = sysPath.join(this.options.cwd, path$2); const now = /* @__PURE__ */ new Date(); const writes = this._pendingWrites; function awaitWriteFinishFn(prevStat) { stat$1(fullPath, (err, curStat) => { if (err || !writes.has(path$2)) { if (err && err.code !== "ENOENT") awfEmit(err); return; } const now$1 = Number(/* @__PURE__ */ new Date()); if (prevStat && curStat.size !== prevStat.size) writes.get(path$2).lastChange = now$1; if (now$1 - writes.get(path$2).lastChange >= threshold) { writes.delete(path$2); awfEmit(void 0, curStat); } else timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat); }); } if (!writes.has(path$2)) { writes.set(path$2, { lastChange: now, cancelWait: () => { writes.delete(path$2); clearTimeout(timeoutHandler); return event; } }); timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval); } } /** * Determines whether user has asked to ignore this path. */ _isIgnored(path$2, stats) { if (this.options.atomic && DOT_RE.test(path$2)) return true; if (!this._userIgnored) { const { cwd } = this.options; const ignored = (this.options.ignored || []).map(normalizeIgnored(cwd)); this._userIgnored = anymatch([...[...this._ignoredPaths].map(normalizeIgnored(cwd)), ...ignored], void 0); } return this._userIgnored(path$2, stats); } _isntIgnored(path$2, stat$3) { return !this._isIgnored(path$2, stat$3); } /** * Provides a set of common helpers and properties relating to symlink handling. * @param path file or directory pattern being watched */ _getWatchHelpers(path$2) { return new WatchHelper(path$2, this.options.followSymlinks, this); } /** * Provides directory tracking objects * @param directory path of the directory */ _getWatchedDir(directory) { const dir = sysPath.resolve(directory); if (!this._watched.has(dir)) this._watched.set(dir, new DirEntry(dir, this._boundRemove)); return this._watched.get(dir); } /** * Check for read permissions: https://stackoverflow.com/a/11781404/1358405 */ _hasReadPermissions(stats) { if (this.options.ignorePermissionErrors) return true; return Boolean(Number(stats.mode) & 256); } /** * Handles emitting unlink events for * files and directories, and via recursion, for * files and directories within directories that are unlinked * @param directory within which the following item is located * @param item base path of item/directory */ _remove(directory, item, isDirectory) { const path$2 = sysPath.join(directory, item); const fullPath = sysPath.resolve(path$2); isDirectory = isDirectory != null ? isDirectory : this._watched.has(path$2) || this._watched.has(fullPath); if (!this._throttle("remove", path$2, 100)) return; if (!isDirectory && this._watched.size === 1) this.add(directory, item, true); this._getWatchedDir(path$2).getChildren().forEach((nested) => this._remove(path$2, nested)); const parent = this._getWatchedDir(directory); const wasTracked = parent.has(item); parent.remove(item); if (this._symlinkPaths.has(fullPath)) this._symlinkPaths.delete(fullPath); let relPath = path$2; if (this.options.cwd) relPath = sysPath.relative(this.options.cwd, path$2); if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) { if (this._pendingWrites.get(relPath).cancelWait() === EVENTS.ADD) return; } this._watched.delete(path$2); this._watched.delete(fullPath); const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK; if (wasTracked && !this._isIgnored(path$2)) this._emit(eventName, path$2); this._closePath(path$2); } /** * Closes all watchers for a path */ _closePath(path$2) { this._closeFile(path$2); const dir = sysPath.dirname(path$2); this._getWatchedDir(dir).remove(sysPath.basename(path$2)); } /** * Closes only file-specific watchers */ _closeFile(path$2) { const closers = this._closers.get(path$2); if (!closers) return; closers.forEach((closer) => closer()); this._closers.delete(path$2); } _addPathCloser(path$2, closer) { if (!closer) return; let list = this._closers.get(path$2); if (!list) { list = []; this._closers.set(path$2, list); } list.push(closer); } _readdirp(root, opts) { if (this.closed) return; let stream = readdirp(root, { type: EVENTS.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 }); this._streams.add(stream); stream.once(STR_CLOSE, () => { stream = void 0; }); stream.once(STR_END, () => { if (stream) { this._streams.delete(stream); stream = void 0; } }); return stream; } }; /** * Instantiates watcher with paths to be tracked. * @param paths file / directory paths * @param options opts, such as `atomic`, `awaitWriteFinish`, `ignored`, and others * @returns an instance of FSWatcher for chaining. * @example * const watcher = watch('.').on('all', (event, path) => { console.log(event, path); }); * watch('.', { atomic: true, awaitWriteFinish: true, ignored: (f, stats) => stats?.isFile() && !f.endsWith('.js') }) */ function watch$1(paths, options = {}) { const watcher = new FSWatcher(options); watcher.add(paths); return watcher; } var esm_default = { watch: watch$1, FSWatcher }; //#endregion export { esm_default as t };