UNPKG

@rstest/core

Version:
1,426 lines (1,425 loc) 48.4 kB
/*! For license information please see 0~7583.js.LICENSE.txt */ import 'module'; /*#__PURE__*/ import.meta.url; import { __webpack_require__ } from "./rslib-runtime.js"; import { lstat, open as promises_open, readdir, realpath as promises_realpath, stat as promises_stat } from "fs/promises"; import "./1157.js"; import "./2672.js"; import { Readable } from "./0~1981.js"; import { EventEmitter } from "./9131.js"; const promises_ = __webpack_require__("node:fs/promises"); const external_node_path_ = __webpack_require__("node:path"); 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 = 'win32' === process.platform; const emptyFn = (_entryInfo)=>true; const normalizeFilter = (filter)=>{ if (void 0 === filter) return emptyFn; if ('function' == typeof filter) return filter; if ('string' == typeof filter) { 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; }; class ReaddirpStream extends Readable { constructor(options = {}){ super({ objectMode: true, autoDestroy: true, highWaterMark: options.highWaterMark }); const opts = { ...defaultOptions, ...options }; const { root, type } = opts; this._fileFilter = normalizeFilter(opts.fileFilter); this._directoryFilter = normalizeFilter(opts.directoryFilter); const statMethod = opts.lstat ? promises_.lstat : promises_.stat; if (wantBigintFsStats) this._stat = (path)=>statMethod(path, { bigint: true }); else this._stat = statMethod; this._maxDepth = opts.depth ?? defaultOptions.depth; this._wantsDir = type ? DIR_TYPES.has(type) : false; this._wantsFile = type ? FILE_TYPES.has(type) : false; this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE; this._root = (0, external_node_path_.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, depth } = par; const slice = fil.splice(0, batch).map((dirent)=>this._formatEntry(dirent, path)); 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 ('directory' === entryType && 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 (('file' === entryType || 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, depth) { let files; try { files = await (0, promises_.readdir)(path, this._rdOptions); } catch (error) { this._onError(error); } return { files, depth, path }; } async _formatEntry(dirent, path) { let entry; const basename = this._isDirent ? dirent.name : dirent; try { const fullPath = (0, external_node_path_.resolve)((0, external_node_path_.join)(path, basename)); entry = { path: (0, external_node_path_.relative)(this._root, fullPath), fullPath, basename }; 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 (0, promises_.realpath)(full); const entryRealPathStats = await (0, promises_.lstat)(entryRealPath); if (entryRealPathStats.isFile()) return 'file'; if (entryRealPathStats.isDirectory()) { const len = entryRealPath.length; if (full.startsWith(entryRealPath) && full.substr(len, 1) === external_node_path_.sep) { const recursiveError = 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(); } } function readdirp(root, options = {}) { let type = options.entryType || options.type; if ('both' === type) type = EntryTypes.FILE_DIR_TYPE; if (type) options.type = type; if (root) { if ('string' != typeof root) throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)'); else if (type && !ALL_TYPES.includes(type)) throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`); } else throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)'); options.root = root; return new ReaddirpStream(options); } const external_node_fs_ = __webpack_require__("fs"); const external_node_os_ = __webpack_require__("node:os"); const STR_DATA = 'data'; const STR_END = 'end'; const STR_CLOSE = 'close'; const EMPTY_FN = ()=>{}; const pl = process.platform; const isWindows = 'win32' === pl; const isMacos = 'darwin' === pl; const isLinux = 'linux' === pl; const isFreeBSD = 'freebsd' === pl; const isIBMi = 'OS400' === (0, external_node_os_.type)(); 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: lstat, stat: promises_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(external_node_path_.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 ? 0 === val.size : !val; const FsWatchInstances = new Map(); function createFsWatchInstance(path, options, listener, errHandler, emitRaw) { const handleEvent = (rawEvent, evPath)=>{ listener(path); emitRaw(rawEvent, evPath, { watchedPath: path }); if (evPath && path !== evPath) fsWatchBroadcast(external_node_path_.resolve(path, evPath), KEY_LISTENERS, external_node_path_.join(path, evPath)); }; try { return (0, external_node_fs_.watch)(path, { persistent: options.persistent }, handleEvent); } catch (error) { errHandler(error); return; } } const fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3)=>{ const cont = FsWatchInstances.get(fullPath); if (!cont) return; foreach(cont[listenerType], (listener)=>{ listener(val1, val2, val3); }); }; const setFsWatchListener = (path, fullPath, options, handlers)=>{ const { listener, errHandler, rawEmitter } = handlers; let cont = FsWatchInstances.get(fullPath); let watcher; if (!options.persistent) { watcher = createFsWatchInstance(path, 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, 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 && 'EPERM' === error.code) try { const fd = await promises_open(path, 'r'); await fd.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 = new Map(); const setFsWatchFileListener = (path, 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)) { (0, external_node_fs_.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: (0, external_node_fs_.watchFile)(fullPath, options, (curr, prev)=>{ foreach(cont.rawEmitters, (rawEmitter)=>{ rawEmitter(EV.CHANGE, fullPath, { curr, prev }); }); const currmtime = curr.mtimeMs; if (curr.size !== prev.size || currmtime > prev.mtimeMs || 0 === currmtime) foreach(cont.listeners, (listener)=>listener(path, curr)); }) }; FsWatchFileInstances.set(fullPath, cont); } return ()=>{ delFromSet(cont, KEY_LISTENERS, listener); delFromSet(cont, KEY_RAW, rawEmitter); if (isEmptySet(cont.listeners)) { FsWatchFileInstances.delete(fullPath); (0, external_node_fs_.unwatchFile)(fullPath); cont.options = cont.watcher = void 0; Object.freeze(cont); } }; }; class NodeFsHandler { constructor(fsW){ this.fsw = fsW; this._boundHandleError = (error)=>fsW._handleError(error); } _watchWithNodeFs(path, listener) { const opts = this.fsw.options; const directory = external_node_path_.dirname(path); const basename = external_node_path_.basename(path); const parent = this.fsw._getWatchedDir(directory); parent.add(basename); const absolutePath = external_node_path_.resolve(path); const options = { persistent: opts.persistent }; if (!listener) listener = EMPTY_FN; let closer; if (opts.usePolling) { const enableBin = opts.interval !== opts.binaryInterval; options.interval = enableBin && isBinaryPath(basename) ? opts.binaryInterval : opts.interval; closer = setFsWatchFileListener(path, absolutePath, options, { listener, rawEmitter: this.fsw._emitRaw }); } else closer = setFsWatchListener(path, absolutePath, options, { listener, errHandler: this._boundHandleError, rawEmitter: this.fsw._emitRaw }); return closer; } _handleFile(file, stats, initialAdd) { if (this.fsw.closed) return; const dirname = external_node_path_.dirname(file); const basename = external_node_path_.basename(file); const parent = this.fsw._getWatchedDir(dirname); let prevStats = stats; if (parent.has(basename)) return; const listener = async (path, newStats)=>{ if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5)) return; if (newStats && 0 !== newStats.mtimeMs) { if (parent.has(basename)) { const at = newStats.atimeMs; const mt = newStats.mtimeMs; if (!at || at <= mt || mt !== prevStats.mtimeMs) this.fsw._emit(EV.CHANGE, file, newStats); prevStats = newStats; } } else try { const newStats = await promises_stat(file); if (this.fsw.closed) return; const at = newStats.atimeMs; const mt = newStats.mtimeMs; if (!at || at <= mt || mt !== prevStats.mtimeMs) this.fsw._emit(EV.CHANGE, file, newStats); if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats.ino) { this.fsw._closeFile(path); prevStats = newStats; const closer = this._watchWithNodeFs(file, listener); if (closer) this.fsw._addPathCloser(path, closer); } else prevStats = newStats; } catch (error) { this.fsw._remove(dirname, basename); } }; 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; } async _handleSymlink(entry, directory, path, 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 promises_realpath(path); } 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, entry.stats); } } else { dir.add(item); this.fsw._symlinkPaths.set(full, linkPath); this.fsw._emit(EV.ADD, path, 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 = external_node_path_.join(directory, ''); throttler = this.fsw._throttle('readdir', directory, 1000); if (!throttler) return; const previous = this.fsw._getWatchedDir(wh.path); const current = 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 = external_node_path_.join(directory, item); current.add(item); if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path, item)) return; if (this.fsw.closed) { stream = void 0; return; } if (item === target || !target && !previous.has(item)) { this.fsw._incrReadyCount(); path = external_node_path_.join(dir, external_node_path_.relative(dir, path)); this._addToNodeFs(path, initialAdd, wh, depth + 1); } }).on(EV.ERROR, this._boundHandleError); return new Promise((resolve, reject)=>{ if (!stream) return reject(); stream.once(STR_END, ()=>{ if (this.fsw.closed) { stream = void 0; return; } const wasThrottled = throttler ? throttler.clear() : false; resolve(void 0); previous.getChildren().filter((item)=>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); }); }); } async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) { const parentDir = this.fsw._getWatchedDir(external_node_path_.dirname(dir)); const tracked = parentDir.has(external_node_path_.basename(dir)); if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) this.fsw._emit(EV.ADD_DIR, dir, stats); parentDir.add(external_node_path_.basename(dir)); this.fsw._getWatchedDir(dir); let throttler; let closer; const oDepth = this.fsw.options.depth; if ((null == oDepth || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath)) { if (!target) { await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler); if (this.fsw.closed) return; } closer = this._watchWithNodeFs(dir, (dirPath, stats)=>{ if (stats && 0 === stats.mtimeMs) return; this._handleRead(dirPath, false, wh, target, dir, depth, throttler); }); } return closer; } async _addToNodeFs(path, initialAdd, priorWh, depth, target) { const ready = this.fsw._emitReady; if (this.fsw._isIgnored(path) || this.fsw.closed) { ready(); return false; } const wh = this.fsw._getWatchHelpers(path); 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 = external_node_path_.resolve(path); const targetPath = follow ? await promises_realpath(path) : path; 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 && void 0 !== targetPath) this.fsw._symlinkPaths.set(absPath, targetPath); } else if (stats.isSymbolicLink()) { const targetPath = follow ? await promises_realpath(path) : path; if (this.fsw.closed) return; const parent = external_node_path_.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, wh, targetPath); if (this.fsw.closed) return; if (void 0 !== targetPath) this.fsw._symlinkPaths.set(external_node_path_.resolve(path), targetPath); } else closer = this._handleFile(wh.watchPath, stats, initialAdd); ready(); if (closer) this.fsw._addPathCloser(path, closer); return false; } catch (error) { if (this.fsw._handleError(error)) { ready(); return path; } } } } /*! 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 esm_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)=>'object' == typeof matcher && null !== matcher && !(matcher instanceof RegExp); function createPattern(matcher) { if ('function' == typeof matcher) return matcher; if ('string' == typeof matcher) return (string)=>matcher === string; if (matcher instanceof RegExp) return (string)=>matcher.test(string); if ('object' == typeof matcher && null !== matcher) return (string)=>{ if (matcher.path === string) return true; if (matcher.recursive) { const relative = external_node_path_.relative(matcher.path, string); if (!relative) return false; return !relative.startsWith('..') && !external_node_path_.isAbsolute(relative); } return false; }; return ()=>false; } function normalizePath(path) { if ('string' != typeof path) throw new Error('string expected'); path = external_node_path_.normalize(path); path = path.replace(/\\/g, '/'); let prepend = false; if (path.startsWith('//')) prepend = true; const DOUBLE_SLASH_RE = /\/\//; while(path.match(DOUBLE_SLASH_RE))path = path.replace(DOUBLE_SLASH_RE, '/'); if (prepend) path = '/' + path; return path; } function matchPatterns(patterns, testString, stats) { const path = normalizePath(testString); for(let index = 0; index < patterns.length; index++){ const pattern = patterns[index]; if (pattern(path, stats)) return true; } return false; } function anymatch(matchers, testString) { if (null == matchers) throw new TypeError('anymatch: specify first argument'); const matchersArray = arrify(matchers); const patterns = matchersArray.map((matcher)=>createPattern(matcher)); if (null == testString) return (testString, stats)=>matchPatterns(patterns, testString, 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(esm_DOUBLE_SLASH_RE))str = str.replace(esm_DOUBLE_SLASH_RE, SLASH); if (prepend) str = SLASH + str; return str; }; const normalizePathToUnix = (path)=>toUnix(external_node_path_.normalize(toUnix(path))); const normalizeIgnored = (cwd = '')=>(path)=>{ if ('string' == typeof path) return normalizePathToUnix(external_node_path_.isAbsolute(path) ? path : external_node_path_.join(cwd, path)); return path; }; const getAbsolutePath = (path, cwd)=>{ if (external_node_path_.isAbsolute(path)) return path; return external_node_path_.join(cwd, path); }; const EMPTY_SET = Object.freeze(new Set()); class DirEntry { constructor(dir, removeWatcher){ this.path = dir; this._removeWatcher = removeWatcher; this.items = 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(external_node_path_.dirname(dir), external_node_path_.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'; class WatchHelper { constructor(path, follow, fsw){ this.fsw = fsw; const watchPath = path; this.path = path = path.replace(REPLACER_RE, ''); this.watchPath = watchPath; this.fullWatchPath = external_node_path_.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 external_node_path_.join(this.watchPath, external_node_path_.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); } } class FSWatcher extends EventEmitter { constructor(_opts = {}){ super(); this.closed = false; this._closers = new Map(); this._ignoredPaths = new Set(); this._throttled = new Map(); this._streams = new Set(); this._symlinkPaths = new Map(); this._watched = new Map(); this._pendingWrites = new Map(); this._pendingUnlinks = new Map(); this._readyCount = 0; this._readyEmitted = false; const awf = _opts.awaitWriteFinish; const DEF_AWF = { stabilityThreshold: 2000, 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: true === awf ? DEF_AWF : 'object' == typeof awf ? { ...DEF_AWF, ...awf } : false }; if (isIBMi) opts.usePolling = true; if (void 0 === opts.atomic) opts.atomic = !opts.usePolling; const envPoll = process.env.CHOKIDAR_USEPOLLING; if (void 0 !== envPoll) { const envLower = envPoll.toLowerCase(); if ('false' === envLower || '0' === envLower) opts.usePolling = false; else if ('true' === envLower || '1' === envLower) 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 ('string' == typeof matcher) { for (const ignored of this._ignoredPaths)if (isMatcherObject(ignored) && ignored.path === matcher) this._ignoredPaths.delete(ignored); } } 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)=>{ const absPath = getAbsolutePath(path, cwd); return absPath; }); paths.forEach((path)=>{ this._removeIgnoredPath(path); }); this._userIgnored = void 0; if (!this._readyCount) this._readyCount = 0; this._readyCount += paths.length; Promise.all(paths.map(async (path)=>{ const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, void 0, 0, _origAdd); if (res) this._emitReady(); return res; })).then((results)=>{ if (this.closed) return; results.forEach((item)=>{ if (item) this.add(external_node_path_.dirname(item), external_node_path_.basename(_origAdd || item)); }); }); return this; } unwatch(paths_) { if (this.closed) return this; const paths = unifyPaths(paths_); const { cwd } = this.options; paths.forEach((path)=>{ if (!external_node_path_.isAbsolute(path) && !this._closers.has(path)) { if (cwd) path = external_node_path_.join(cwd, path); path = external_node_path_.resolve(path); } this._closePath(path); this._addIgnoredPath(path); if (this._watched.has(path)) this._addIgnoredPath({ path, recursive: true }); this._userIgnored = void 0; }); return this; } 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; } getWatched() { const watchList = {}; this._watched.forEach((entry, dir)=>{ const key = this.options.cwd ? external_node_path_.relative(this.options.cwd, dir) : dir; const index = key || 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); } async _emit(event, path, stats) { if (this.closed) return; const opts = this.options; if (isWindows) path = external_node_path_.normalize(path); if (opts.cwd) path = external_node_path_.relative(opts.cwd, path); const args = [ path ]; if (null != stats) args.push(stats); const awf = opts.awaitWriteFinish; let pw; if (awf && (pw = this._pendingWrites.get(path))) { pw.lastChange = new Date(); return this; } if (opts.atomic) { if (event === EVENTS.UNLINK) { this._pendingUnlinks.set(path, [ event, ...args ]); setTimeout(()=>{ this._pendingUnlinks.forEach((entry, path)=>{ this.emit(...entry); this.emit(EVENTS.ALL, ...entry); this._pendingUnlinks.delete(path); }); }, 'number' == typeof opts.atomic ? opts.atomic : 100); return this; } if (event === EVENTS.ADD && this._pendingUnlinks.has(path)) { event = EVENTS.CHANGE; this._pendingUnlinks.delete(path); } } if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) { const awfEmit = (err, stats)=>{ if (err) { event = EVENTS.ERROR; args[0] = err; this.emitWithAll(event, args); } else if (stats) { if (args.length > 1) args[1] = stats; else args.push(stats); this.emitWithAll(event, args); } }; this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit); return this; } if (event === EVENTS.CHANGE) { const isThrottled = !this._throttle(EVENTS.CHANGE, path, 50); if (isThrottled) return this; } if (opts.alwaysStat && void 0 === stats && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) { const fullPath = opts.cwd ? external_node_path_.join(opts.cwd, path) : path; let stats; try { stats = await promises_stat(fullPath); } catch (err) {} if (!stats || this.closed) return; args.push(stats); } this.emitWithAll(event, args); return this; } _handleError(error) { const code = error && error.code; if (error && 'ENOENT' !== code && 'ENOTDIR' !== code && (!this.options.ignorePermissionErrors || 'EPERM' !== code && 'EACCES' !== code)) this.emit(EVENTS.ERROR, error); return error || this.closed; } _throttle(actionType, path, timeout) { if (!this._throttled.has(actionType)) this._throttled.set(actionType, new Map()); const action = this._throttled.get(actionType); if (!action) throw new Error('invalid throttle'); const actionPath = action.get(path); if (actionPath) { actionPath.count++; return false; } let timeoutObject; const clear = ()=>{ const item = action.get(path); const count = item ? item.count : 0; action.delete(path); clearTimeout(timeoutObject); if (item) clearTimeout(item.timeoutObject); return count; }; timeoutObject = setTimeout(clear, timeout); const thr = { timeoutObject, clear, count: 0 }; action.set(path, thr); return thr; } _incrReadyCount() { return this._readyCount++; } _awaitWriteFinish(path, threshold, event, awfEmit) { const awf = this.options.awaitWriteFinish; if ('object' != typeof awf) return; const pollInterval = awf.pollInterval; let timeoutHandler; let fullPath = path; if (this.options.cwd && !external_node_path_.isAbsolute(path)) fullPath = external_node_path_.join(this.options.cwd, path); const now = new Date(); const writes = this._pendingWrites; function awaitWriteFinishFn(prevStat) { (0, external_node_fs_.stat)(fullPath, (err, curStat)=>{ if (err || !writes.has(path)) { if (err && 'ENOENT' !== err.code) awfEmit(err); return; } const now = Number(new Date()); if (prevStat && curStat.size !== prevStat.size) writes.get(path).lastChange = now; const pw = writes.get(path); const df = now - pw.lastChange; if (df >= threshold) { writes.delete(path); awfEmit(void 0, curStat); } else timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat); }); } if (!writes.has(path)) { writes.set(path, { lastChange: now, cancelWait: ()=>{ writes.delete(path); clearTimeout(timeoutHandler); return event; } }); timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval); } } _isIgnored(path, stats) { if (this.options.atomic && DOT_RE.test(path)) return true; if (!this._userIgnored) { const { cwd } = this.options; const ign = this.options.ignored; const ignored = (ign || []).map(normalizeIgnored(cwd)); const ignoredPaths = [ ...this._ignoredPaths ]; const list = [ ...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored ]; this._userIgnored = anymatch(list, void 0); } return this._userIgnored(path, stats); } _isntIgnored(path, stat) { return !this._isIgnored(path, stat); } _getWatchHelpers(path) { return new WatchHelper(path, this.options.followSymlinks, this); } _getWatchedDir(directory) { const dir = external_node_path_.resolve(directory); if (!this._watched.has(dir)) this._watched.set(dir, new DirEntry(dir, this._boundRemove)); return this._watched.get(dir); } _hasReadPermissions(stats) { if (this.options.ignorePermissionErrors) return true; return Boolean(256 & Number(stats.mode)); } _remove(directory, item, isDirectory) { const path = external_node_path_.join(directory, item); const fullPath = external_node_path_.resolve(path); isDirectory = null != isDirectory ? isDirectory : this._watched.has(path) || this._watched.has(fullPath); if (!this._throttle('remove', path, 100)) return; if (!isDirectory && 1 === this._watched.size) this.add(directory, item, true); const wp = this._getWatchedDir(path); const nestedDirectoryChildren = wp.getChildren(); nestedDirectoryChildren.forEach((nested)=>this._remove(path, 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; if (this.options.cwd) relPath = external_node_path_.relative(this.options.cwd, path); if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) { const event = this._pendingWrites.get(relPath).cancelWait(); if (event === EVENTS.ADD) return; } this._watched.delete(path); this._watched.delete(fullPath); const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK; if (wasTracked && !this._isIgnored(path)) this._emit(eventName, path); this._closePath(path); } _closePath(path) { this._closeFile(path); const dir = external_node_path_.dirname(path); this._getWatchedDir(dir).remove(external_node_path_.basename(path)); } _closeFile(path) { const closers = this._closers.get(path); if (!closers) return; closers.forEach((closer)=>closer()); this._closers.delete(path); } _addPathCloser(path, closer) { if (!closer) return; let list = this._closers.get(path); if (!list) { list = []; this._closers.set(path, list); } list.push(closer); } _readdirp(root, opts) { if (this.closed) return; const options = { type: EVENTS.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 }; let stream = readdirp(root, options); 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; } } function watch(paths, options = {}) { const watcher = new FSWatcher(options); watcher.add(paths); return watcher; } export { watch };