CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes45downloads
index.js799 linesDownload Raw Back to esm
1/*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */2import { stat as statcb } from 'fs';3import { stat, readdir } from 'fs/promises';4import { EventEmitter } from 'events';5import * as sysPath from 'path';6import { readdirp } from 'readdirp';7import { NodeFsHandler, EVENTS as EV, isWindows, isIBMi, EMPTY_FN, STR_CLOSE, STR_END, } from './handler.js';8const SLASH = '/';9const SLASH_SLASH = '//';10const ONE_DOT = '.';11const TWO_DOTS = '..';12const STRING_TYPE = 'string';13const BACK_SLASH_RE = /\\/g;14const DOUBLE_SLASH_RE = /\/\//;15const DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;16const REPLACER_RE = /^\.[/\\]/;17function arrify(item) {18    return Array.isArray(item) ? item : [item];19}20const isMatcherObject = (matcher) => typeof matcher === 'object' && matcher !== null && !(matcher instanceof RegExp);21function createPattern(matcher) {22    if (typeof matcher === 'function')23        return matcher;24    if (typeof matcher === 'string')25        return (string) => matcher === string;26    if (matcher instanceof RegExp)27        return (string) => matcher.test(string);28    if (typeof matcher === 'object' && matcher !== null) {29        return (string) => {30            if (matcher.path === string)31                return true;32            if (matcher.recursive) {33                const relative = sysPath.relative(matcher.path, string);34                if (!relative) {35                    return false;36                }37                return !relative.startsWith('..') && !sysPath.isAbsolute(relative);38            }39            return false;40        };41    }42    return () => false;43}44function normalizePath(path) {45    if (typeof path !== 'string')46        throw new Error('string expected');47    path = sysPath.normalize(path);48    path = path.replace(/\\/g, '/');49    let prepend = false;50    if (path.startsWith('//'))51        prepend = true;52    const DOUBLE_SLASH_RE = /\/\//;53    while (path.match(DOUBLE_SLASH_RE))54        path = path.replace(DOUBLE_SLASH_RE, '/');55    if (prepend)56        path = '/' + path;57    return path;58}59function matchPatterns(patterns, testString, stats) {60    const path = normalizePath(testString);61    for (let index = 0; index < patterns.length; index++) {62        const pattern = patterns[index];63        if (pattern(path, stats)) {64            return true;65        }66    }67    return false;68}69function anymatch(matchers, testString) {70    if (matchers == null) {71        throw new TypeError('anymatch: specify first argument');72    }73    // Early cache for matchers.74    const matchersArray = arrify(matchers);75    const patterns = matchersArray.map((matcher) => createPattern(matcher));76    if (testString == null) {77        return (testString, stats) => {78            return matchPatterns(patterns, testString, stats);79        };80    }81    return matchPatterns(patterns, testString);82}83const unifyPaths = (paths_) => {84    const paths = arrify(paths_).flat();85    if (!paths.every((p) => typeof p === STRING_TYPE)) {86        throw new TypeError(`Non-string provided as watch path: ${paths}`);87    }88    return paths.map(normalizePathToUnix);89};90// If SLASH_SLASH occurs at the beginning of path, it is not replaced91//     because "//StoragePC/DrivePool/Movies" is a valid network path92const toUnix = (string) => {93    let str = string.replace(BACK_SLASH_RE, SLASH);94    let prepend = false;95    if (str.startsWith(SLASH_SLASH)) {96        prepend = true;97    }98    while (str.match(DOUBLE_SLASH_RE)) {99        str = str.replace(DOUBLE_SLASH_RE, SLASH);100    }101    if (prepend) {102        str = SLASH + str;103    }104    return str;105};106// Our version of upath.normalize107// TODO: this is not equal to path-normalize module - investigate why108const normalizePathToUnix = (path) => toUnix(sysPath.normalize(toUnix(path)));109// TODO: refactor110const normalizeIgnored = (cwd = '') => (path) => {111    if (typeof path === 'string') {112        return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path));113    }114    else {115        return path;116    }117};118const getAbsolutePath = (path, cwd) => {119    if (sysPath.isAbsolute(path)) {120        return path;121    }122    return sysPath.join(cwd, path);123};124const EMPTY_SET = Object.freeze(new Set());125/**126 * Directory entry.127 */128class DirEntry {129    constructor(dir, removeWatcher) {130        this.path = dir;131        this._removeWatcher = removeWatcher;132        this.items = new Set();133    }134    add(item) {135        const { items } = this;136        if (!items)137            return;138        if (item !== ONE_DOT && item !== TWO_DOTS)139            items.add(item);140    }141    async remove(item) {142        const { items } = this;143        if (!items)144            return;145        items.delete(item);146        if (items.size > 0)147            return;148        const dir = this.path;149        try {150            await readdir(dir);151        }152        catch (err) {153            if (this._removeWatcher) {154                this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir));155            }156        }157    }158    has(item) {159        const { items } = this;160        if (!items)161            return;162        return items.has(item);163    }164    getChildren() {165        const { items } = this;166        if (!items)167            return [];168        return [...items.values()];169    }170    dispose() {171        this.items.clear();172        this.path = '';173        this._removeWatcher = EMPTY_FN;174        this.items = EMPTY_SET;175        Object.freeze(this);176    }177}178const STAT_METHOD_F = 'stat';179const STAT_METHOD_L = 'lstat';180export class WatchHelper {181    constructor(path, follow, fsw) {182        this.fsw = fsw;183        const watchPath = path;184        this.path = path = path.replace(REPLACER_RE, '');185        this.watchPath = watchPath;186        this.fullWatchPath = sysPath.resolve(watchPath);187        this.dirParts = [];188        this.dirParts.forEach((parts) => {189            if (parts.length > 1)190                parts.pop();191        });192        this.followSymlinks = follow;193        this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;194    }195    entryPath(entry) {196        return sysPath.join(this.watchPath, sysPath.relative(this.watchPath, entry.fullPath));197    }198    filterPath(entry) {199        const { stats } = entry;200        if (stats && stats.isSymbolicLink())201            return this.filterDir(entry);202        const resolvedPath = this.entryPath(entry);203        // TODO: what if stats is undefined? remove !204        return this.fsw._isntIgnored(resolvedPath, stats) && this.fsw._hasReadPermissions(stats);205    }206    filterDir(entry) {207        return this.fsw._isntIgnored(this.entryPath(entry), entry.stats);208    }209}210/**211 * Watches files & directories for changes. Emitted events:212 * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`213 *214 *     new FSWatcher()215 *       .add(directories)216 *       .on('add', path => log('File', path, 'was added'))217 */218export class FSWatcher extends EventEmitter {219    // Not indenting methods for history sake; for now.220    constructor(_opts = {}) {221        super();222        this.closed = false;223        this._closers = new Map();224        this._ignoredPaths = new Set();225        this._throttled = new Map();226        this._streams = new Set();227        this._symlinkPaths = new Map();228        this._watched = new Map();229        this._pendingWrites = new Map();230        this._pendingUnlinks = new Map();231        this._readyCount = 0;232        this._readyEmitted = false;233        const awf = _opts.awaitWriteFinish;234        const DEF_AWF = { stabilityThreshold: 2000, pollInterval: 100 };235        const opts = {236            // Defaults237            persistent: true,238            ignoreInitial: false,239            ignorePermissionErrors: false,240            interval: 100,241            binaryInterval: 300,242            followSymlinks: true,243            usePolling: false,244            // useAsync: false,245            atomic: true, // NOTE: overwritten later (depends on usePolling)246            ..._opts,247            // Change format248            ignored: _opts.ignored ? arrify(_opts.ignored) : arrify([]),249            awaitWriteFinish: awf === true ? DEF_AWF : typeof awf === 'object' ? { ...DEF_AWF, ...awf } : false,250        };251        // Always default to polling on IBM i because fs.watch() is not available on IBM i.252        if (isIBMi)253            opts.usePolling = true;254        // Editor atomic write normalization enabled by default with fs.watch255        if (opts.atomic === undefined)256            opts.atomic = !opts.usePolling;257        // opts.atomic = typeof _opts.atomic === 'number' ? _opts.atomic : 100;258        // Global override. Useful for developers, who need to force polling for all259        // instances of chokidar, regardless of usage / dependency depth260        const envPoll = process.env.CHOKIDAR_USEPOLLING;261        if (envPoll !== undefined) {262            const envLower = envPoll.toLowerCase();263            if (envLower === 'false' || envLower === '0')264                opts.usePolling = false;265            else if (envLower === 'true' || envLower === '1')266                opts.usePolling = true;267            else268                opts.usePolling = !!envLower;269        }270        const envInterval = process.env.CHOKIDAR_INTERVAL;271        if (envInterval)272            opts.interval = Number.parseInt(envInterval, 10);273        // This is done to emit ready only once, but each 'add' will increase that?274        let readyCalls = 0;275        this._emitReady = () => {276            readyCalls++;277            if (readyCalls >= this._readyCount) {278                this._emitReady = EMPTY_FN;279                this._readyEmitted = true;280                // use process.nextTick to allow time for listener to be bound281                process.nextTick(() => this.emit(EV.READY));282            }283        };284        this._emitRaw = (...args) => this.emit(EV.RAW, ...args);285        this._boundRemove = this._remove.bind(this);286        this.options = opts;287        this._nodeFsHandler = new NodeFsHandler(this);288        // You’re frozen when your heart’s not open.289        Object.freeze(opts);290    }291    _addIgnoredPath(matcher) {292        if (isMatcherObject(matcher)) {293            // return early if we already have a deeply equal matcher object294            for (const ignored of this._ignoredPaths) {295                if (isMatcherObject(ignored) &&296                    ignored.path === matcher.path &&297                    ignored.recursive === matcher.recursive) {298                    return;299                }300            }301        }302        this._ignoredPaths.add(matcher);303    }304    _removeIgnoredPath(matcher) {305        this._ignoredPaths.delete(matcher);306        // now find any matcher objects with the matcher as path307        if (typeof matcher === 'string') {308            for (const ignored of this._ignoredPaths) {309                // TODO (43081j): make this more efficient.310                // probably just make a `this._ignoredDirectories` or some311                // such thing.312                if (isMatcherObject(ignored) && ignored.path === matcher) {313                    this._ignoredPaths.delete(ignored);314                }315            }316        }317    }318    // Public methods319    /**320     * Adds paths to be watched on an existing FSWatcher instance.321     * @param paths_ file or file list. Other arguments are unused322     */323    add(paths_, _origAdd, _internal) {324        const { cwd } = this.options;325        this.closed = false;326        this._closePromise = undefined;327        let paths = unifyPaths(paths_);328        if (cwd) {329            paths = paths.map((path) => {330                const absPath = getAbsolutePath(path, cwd);331                // Check `path` instead of `absPath` because the cwd portion can't be a glob332                return absPath;333            });334        }335        paths.forEach((path) => {336            this._removeIgnoredPath(path);337        });338        this._userIgnored = undefined;339        if (!this._readyCount)340            this._readyCount = 0;341        this._readyCount += paths.length;342        Promise.all(paths.map(async (path) => {343            const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, undefined, 0, _origAdd);344            if (res)345                this._emitReady();346            return res;347        })).then((results) => {348            if (this.closed)349                return;350            results.forEach((item) => {351                if (item)352                    this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item));353            });354        });355        return this;356    }357    /**358     * Close watchers or start ignoring events from specified paths.359     */360    unwatch(paths_) {361        if (this.closed)362            return this;363        const paths = unifyPaths(paths_);364        const { cwd } = this.options;365        paths.forEach((path) => {366            // convert to absolute path unless relative path already matches367            if (!sysPath.isAbsolute(path) && !this._closers.has(path)) {368                if (cwd)369                    path = sysPath.join(cwd, path);370                path = sysPath.resolve(path);371            }372            this._closePath(path);373            this._addIgnoredPath(path);374            if (this._watched.has(path)) {375                this._addIgnoredPath({376                    path,377                    recursive: true,378                });379            }380            // reset the cached userIgnored anymatch fn381            // to make ignoredPaths changes effective382            this._userIgnored = undefined;383        });384        return this;385    }386    /**387     * Close watchers and remove all listeners from watched paths.388     */389    close() {390        if (this._closePromise) {391            return this._closePromise;392        }393        this.closed = true;394        // Memory management.395        this.removeAllListeners();396        const closers = [];397        this._closers.forEach((closerList) => closerList.forEach((closer) => {398            const promise = closer();399            if (promise instanceof Promise)400                closers.push(promise);401        }));402        this._streams.forEach((stream) => stream.destroy());403        this._userIgnored = undefined;404        this._readyCount = 0;405        this._readyEmitted = false;406        this._watched.forEach((dirent) => dirent.dispose());407        this._closers.clear();408        this._watched.clear();409        this._streams.clear();410        this._symlinkPaths.clear();411        this._throttled.clear();412        this._closePromise = closers.length413            ? Promise.all(closers).then(() => undefined)414            : Promise.resolve();415        return this._closePromise;416    }417    /**418     * Expose list of watched paths419     * @returns for chaining420     */421    getWatched() {422        const watchList = {};423        this._watched.forEach((entry, dir) => {424            const key = this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir;425            const index = key || ONE_DOT;426            watchList[index] = entry.getChildren().sort();427        });428        return watchList;429    }430    emitWithAll(event, args) {431        this.emit(event, ...args);432        if (event !== EV.ERROR)433            this.emit(EV.ALL, event, ...args);434    }435    // Common helpers436    // --------------437    /**438     * Normalize and emit events.439     * Calling _emit DOES NOT MEAN emit() would be called!440     * @param event Type of event441     * @param path File or directory path442     * @param stats arguments to be passed with event443     * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag444     */445    async _emit(event, path, stats) {446        if (this.closed)447            return;448        const opts = this.options;449        if (isWindows)450            path = sysPath.normalize(path);451        if (opts.cwd)452            path = sysPath.relative(opts.cwd, path);453        const args = [path];454        if (stats != null)455            args.push(stats);456        const awf = opts.awaitWriteFinish;457        let pw;458        if (awf && (pw = this._pendingWrites.get(path))) {459            pw.lastChange = new Date();460            return this;461        }462        if (opts.atomic) {463            if (event === EV.UNLINK) {464                this._pendingUnlinks.set(path, [event, ...args]);465                setTimeout(() => {466                    this._pendingUnlinks.forEach((entry, path) => {467                        this.emit(...entry);468                        this.emit(EV.ALL, ...entry);469                        this._pendingUnlinks.delete(path);470                    });471                }, typeof opts.atomic === 'number' ? opts.atomic : 100);472                return this;473            }474            if (event === EV.ADD && this._pendingUnlinks.has(path)) {475                event = EV.CHANGE;476                this._pendingUnlinks.delete(path);477            }478        }479        if (awf && (event === EV.ADD || event === EV.CHANGE) && this._readyEmitted) {480            const awfEmit = (err, stats) => {481                if (err) {482                    event = EV.ERROR;483                    args[0] = err;484                    this.emitWithAll(event, args);485                }486                else if (stats) {487                    // if stats doesn't exist the file must have been deleted488                    if (args.length > 1) {489                        args[1] = stats;490                    }491                    else {492                        args.push(stats);493                    }494                    this.emitWithAll(event, args);495                }496            };497            this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit);498            return this;499        }500        if (event === EV.CHANGE) {501            const isThrottled = !this._throttle(EV.CHANGE, path, 50);502            if (isThrottled)503                return this;504        }505        if (opts.alwaysStat &&506            stats === undefined &&507            (event === EV.ADD || event === EV.ADD_DIR || event === EV.CHANGE)) {508            const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path;509            let stats;510            try {511                stats = await stat(fullPath);512            }513            catch (err) {514                // do nothing515            }516            // Suppress event when fs_stat fails, to avoid sending undefined 'stat'517            if (!stats || this.closed)518                return;519            args.push(stats);520        }521        this.emitWithAll(event, args);522        return this;523    }524    /**525     * Common handler for errors526     * @returns The error if defined, otherwise the value of the FSWatcher instance's `closed` flag527     */528    _handleError(error) {529        const code = error && error.code;530        if (error &&531            code !== 'ENOENT' &&532            code !== 'ENOTDIR' &&533            (!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES'))) {534            this.emit(EV.ERROR, error);535        }536        return error || this.closed;537    }538    /**539     * Helper utility for throttling540     * @param actionType type being throttled541     * @param path being acted upon542     * @param timeout duration of time to suppress duplicate actions543     * @returns tracking object or false if action should be suppressed544     */545    _throttle(actionType, path, timeout) {546        if (!this._throttled.has(actionType)) {547            this._throttled.set(actionType, new Map());548        }549        const action = this._throttled.get(actionType);550        if (!action)551            throw new Error('invalid throttle');552        const actionPath = action.get(path);553        if (actionPath) {554            actionPath.count++;555            return false;556        }557        // eslint-disable-next-line prefer-const558        let timeoutObject;559        const clear = () => {560            const item = action.get(path);561            const count = item ? item.count : 0;562            action.delete(path);563            clearTimeout(timeoutObject);564            if (item)565                clearTimeout(item.timeoutObject);566            return count;567        };568        timeoutObject = setTimeout(clear, timeout);569        const thr = { timeoutObject, clear, count: 0 };570        action.set(path, thr);571        return thr;572    }573    _incrReadyCount() {574        return this._readyCount++;575    }576    /**577     * Awaits write operation to finish.578     * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.579     * @param path being acted upon580     * @param threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished581     * @param event582     * @param awfEmit Callback to be called when ready for event to be emitted.583     */584    _awaitWriteFinish(path, threshold, event, awfEmit) {585        const awf = this.options.awaitWriteFinish;586        if (typeof awf !== 'object')587            return;588        const pollInterval = awf.pollInterval;589        let timeoutHandler;590        let fullPath = path;591        if (this.options.cwd && !sysPath.isAbsolute(path)) {592            fullPath = sysPath.join(this.options.cwd, path);593        }594        const now = new Date();595        const writes = this._pendingWrites;596        function awaitWriteFinishFn(prevStat) {597            statcb(fullPath, (err, curStat) => {598                if (err || !writes.has(path)) {599                    if (err && err.code !== 'ENOENT')600                        awfEmit(err);601                    return;602                }603                const now = Number(new Date());604                if (prevStat && curStat.size !== prevStat.size) {605                    writes.get(path).lastChange = now;606                }607                const pw = writes.get(path);608                const df = now - pw.lastChange;609                if (df >= threshold) {610                    writes.delete(path);611                    awfEmit(undefined, curStat);612                }613                else {614                    timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);615                }616            });617        }618        if (!writes.has(path)) {619            writes.set(path, {620                lastChange: now,621                cancelWait: () => {622                    writes.delete(path);623                    clearTimeout(timeoutHandler);624                    return event;625                },626            });627            timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);628        }629    }630    /**631     * Determines whether user has asked to ignore this path.632     */633    _isIgnored(path, stats) {634        if (this.options.atomic && DOT_RE.test(path))635            return true;636        if (!this._userIgnored) {637            const { cwd } = this.options;638            const ign = this.options.ignored;639            const ignored = (ign || []).map(normalizeIgnored(cwd));640            const ignoredPaths = [...this._ignoredPaths];641            const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];642            this._userIgnored = anymatch(list, undefined);643        }644        return this._userIgnored(path, stats);645    }646    _isntIgnored(path, stat) {647        return !this._isIgnored(path, stat);648    }649    /**650     * Provides a set of common helpers and properties relating to symlink handling.651     * @param path file or directory pattern being watched652     */653    _getWatchHelpers(path) {654        return new WatchHelper(path, this.options.followSymlinks, this);655    }656    // Directory helpers657    // -----------------658    /**659     * Provides directory tracking objects660     * @param directory path of the directory661     */662    _getWatchedDir(directory) {663        const dir = sysPath.resolve(directory);664        if (!this._watched.has(dir))665            this._watched.set(dir, new DirEntry(dir, this._boundRemove));666        return this._watched.get(dir);667    }668    // File helpers669    // ------------670    /**671     * Check for read permissions: https://stackoverflow.com/a/11781404/1358405672     */673    _hasReadPermissions(stats) {674        if (this.options.ignorePermissionErrors)675            return true;676        return Boolean(Number(stats.mode) & 0o400);677    }678    /**679     * Handles emitting unlink events for680     * files and directories, and via recursion, for681     * files and directories within directories that are unlinked682     * @param directory within which the following item is located683     * @param item      base path of item/directory684     */685    _remove(directory, item, isDirectory) {686        // if what is being deleted is a directory, get that directory's paths687        // for recursive deleting and cleaning of watched object688        // if it is not a directory, nestedDirectoryChildren will be empty array689        const path = sysPath.join(directory, item);690        const fullPath = sysPath.resolve(path);691        isDirectory =692            isDirectory != null ? isDirectory : this._watched.has(path) || this._watched.has(fullPath);693        // prevent duplicate handling in case of arriving here nearly simultaneously694        // via multiple paths (such as _handleFile and _handleDir)695        if (!this._throttle('remove', path, 100))696            return;697        // if the only watched file is removed, watch for its return698        if (!isDirectory && this._watched.size === 1) {699            this.add(directory, item, true);700        }701        // This will create a new entry in the watched object in either case702        // so we got to do the directory check beforehand703        const wp = this._getWatchedDir(path);704        const nestedDirectoryChildren = wp.getChildren();705        // Recursively remove children directories / files.706        nestedDirectoryChildren.forEach((nested) => this._remove(path, nested));707        // Check if item was on the watched list and remove it708        const parent = this._getWatchedDir(directory);709        const wasTracked = parent.has(item);710        parent.remove(item);711        // Fixes issue #1042 -> Relative paths were detected and added as symlinks712        // (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612),713        // but never removed from the map in case the path was deleted.714        // This leads to an incorrect state if the path was recreated:715        // https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553716        if (this._symlinkPaths.has(fullPath)) {717            this._symlinkPaths.delete(fullPath);718        }719        // If we wait for this file to be fully written, cancel the wait.720        let relPath = path;721        if (this.options.cwd)722            relPath = sysPath.relative(this.options.cwd, path);723        if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {724            const event = this._pendingWrites.get(relPath).cancelWait();725            if (event === EV.ADD)726                return;727        }728        // The Entry will either be a directory that just got removed729        // or a bogus entry to a file, in either case we have to remove it730        this._watched.delete(path);731        this._watched.delete(fullPath);732        const eventName = isDirectory ? EV.UNLINK_DIR : EV.UNLINK;733        if (wasTracked && !this._isIgnored(path))734            this._emit(eventName, path);735        // Avoid conflicts if we later create another file with the same name736        this._closePath(path);737    }738    /**739     * Closes all watchers for a path740     */741    _closePath(path) {742        this._closeFile(path);743        const dir = sysPath.dirname(path);744        this._getWatchedDir(dir).remove(sysPath.basename(path));745    }746    /**747     * Closes only file-specific watchers748     */749    _closeFile(path) {750        const closers = this._closers.get(path);751        if (!closers)752            return;753        closers.forEach((closer) => closer());754        this._closers.delete(path);755    }756    _addPathCloser(path, closer) {757        if (!closer)758            return;759        let list = this._closers.get(path);760        if (!list) {761            list = [];762            this._closers.set(path, list);763        }764        list.push(closer);765    }766    _readdirp(root, opts) {767        if (this.closed)768            return;769        const options = { type: EV.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 };770        let stream = readdirp(root, options);771        this._streams.add(stream);772        stream.once(STR_CLOSE, () => {773            stream = undefined;774        });775        stream.once(STR_END, () => {776            if (stream) {777                this._streams.delete(stream);778                stream = undefined;779            }780        });781        return stream;782    }783}784/**785 * Instantiates watcher with paths to be tracked.786 * @param paths file / directory paths787 * @param options opts, such as `atomic`, `awaitWriteFinish`, `ignored`, and others788 * @returns an instance of FSWatcher for chaining.789 * @example790 * const watcher = watch('.').on('all', (event, path) => { console.log(event, path); });791 * watch('.', { atomic: true, awaitWriteFinish: true, ignored: (f, stats) => stats?.isFile() && !f.endsWith('.js') })792 */793export function watch(paths, options = {}) {794    const watcher = new FSWatcher(options);795    watcher.add(paths);796    return watcher;797}798export default { watch, FSWatcher };799 
basant307/AI_Governance_Project · CoolFace