1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3    if (k2 === undefined) k2 = k;
4    var desc = Object.getOwnPropertyDescriptor(m, k);
5    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6      desc = { enumerable: true, get: function() { return m[k]; } };
7    }
8    Object.defineProperty(o, k2, desc);
9}) : (function(o, m, k, k2) {
10    if (k2 === undefined) k2 = k;
11    o[k2] = m[k];
12}));
13var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14    Object.defineProperty(o, "default", { enumerable: true, value: v });
15}) : function(o, v) {
16    o["default"] = v;
17});
18var __importStar = (this && this.__importStar) || function (mod) {
19    if (mod && mod.__esModule) return mod;
20    var result = {};
21    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22    __setModuleDefault(result, mod);
23    return result;
24};
25Object.defineProperty(exports, "__esModule", { value: true });
26exports.PathScurry = exports.Path = exports.PathScurryDarwin = exports.PathScurryPosix = exports.PathScurryWin32 = exports.PathScurryBase = exports.PathPosix = exports.PathWin32 = exports.PathBase = exports.ChildrenCache = exports.ResolveCache = void 0;
27const lru_cache_1 = require("lru-cache");
28const path_1 = require("path");
29const url_1 = require("url");
30const actualFS = __importStar(require("fs"));
31const fs_1 = require("fs");
32const realpathSync = fs_1.realpathSync.native;
33// TODO: test perf of fs/promises realpath vs realpathCB,
34// since the promises one uses realpath.native
35const promises_1 = require("fs/promises");
36const minipass_1 = require("minipass");
37const defaultFS = {
38    lstatSync: fs_1.lstatSync,
39    readdir: fs_1.readdir,
40    readdirSync: fs_1.readdirSync,
41    readlinkSync: fs_1.readlinkSync,
42    realpathSync,
43    promises: {
44        lstat: promises_1.lstat,
45        readdir: promises_1.readdir,
46        readlink: promises_1.readlink,
47        realpath: promises_1.realpath,
48    },
49};
50// if they just gave us require('fs') then use our default
51const fsFromOption = (fsOption) => !fsOption || fsOption === defaultFS || fsOption === actualFS
52    ? defaultFS
53    : {
54        ...defaultFS,
55        ...fsOption,
56        promises: {
57            ...defaultFS.promises,
58            ...(fsOption.promises || {}),
59        },
60    };
61// turn something like //?/c:/ into c:\
62const uncDriveRegexp = /^\\\\\?\\([a-z]:)\\?$/i;
63const uncToDrive = (rootPath) => rootPath.replace(/\//g, '\\').replace(uncDriveRegexp, '$1\\');
64// windows paths are separated by either / or \
65const eitherSep = /[\\\/]/;
66const UNKNOWN = 0; // may not even exist, for all we know
67const IFIFO = 0b0001;
68const IFCHR = 0b0010;
69const IFDIR = 0b0100;
70const IFBLK = 0b0110;
71const IFREG = 0b1000;
72const IFLNK = 0b1010;
73const IFSOCK = 0b1100;
74const IFMT = 0b1111;
75// mask to unset low 4 bits
76const IFMT_UNKNOWN = ~IFMT;
77// set after successfully calling readdir() and getting entries.
78const READDIR_CALLED = 16;
79// set after a successful lstat()
80const LSTAT_CALLED = 32;
81// set if an entry (or one of its parents) is definitely not a dir
82const ENOTDIR = 64;
83// set if an entry (or one of its parents) does not exist
84// (can also be set on lstat errors like EACCES or ENAMETOOLONG)
85const ENOENT = 128;
86// cannot have child entries -- also verify &IFMT is either IFDIR or IFLNK
87// set if we fail to readlink
88const ENOREADLINK = 256;
89// set if we know realpath() will fail
90const ENOREALPATH = 512;
91const ENOCHILD = ENOTDIR | ENOENT | ENOREALPATH;
92const TYPEMASK = 1023;
93const entToType = (s) => s.isFile()
94    ? IFREG
95    : s.isDirectory()
96        ? IFDIR
97        : s.isSymbolicLink()
98            ? IFLNK
99            : s.isCharacterDevice()
100                ? IFCHR
101                : s.isBlockDevice()
102                    ? IFBLK
103                    : s.isSocket()
104                        ? IFSOCK
105                        : s.isFIFO()
106                            ? IFIFO
107                            : UNKNOWN;
108// normalize unicode path names
109const normalizeCache = new Map();
110const normalize = (s) => {
111    const c = normalizeCache.get(s);
112    if (c)
113        return c;
114    const n = s.normalize('NFKD');
115    normalizeCache.set(s, n);
116    return n;
117};
118const normalizeNocaseCache = new Map();
119const normalizeNocase = (s) => {
120    const c = normalizeNocaseCache.get(s);
121    if (c)
122        return c;
123    const n = normalize(s.toLowerCase());
124    normalizeNocaseCache.set(s, n);
125    return n;
126};
127/**
128 * An LRUCache for storing resolved path strings or Path objects.
129 * @internal
130 */
131class ResolveCache extends lru_cache_1.LRUCache {
132    constructor() {
133        super({ max: 256 });
134    }
135}
136exports.ResolveCache = ResolveCache;
137// In order to prevent blowing out the js heap by allocating hundreds of
138// thousands of Path entries when walking extremely large trees, the "children"
139// in this tree are represented by storing an array of Path entries in an
140// LRUCache, indexed by the parent.  At any time, Path.children() may return an
141// empty array, indicating that it doesn't know about any of its children, and
142// thus has to rebuild that cache.  This is fine, it just means that we don't
143// benefit as much from having the cached entries, but huge directory walks
144// don't blow out the stack, and smaller ones are still as fast as possible.
145//
146//It does impose some complexity when building up the readdir data, because we
147//need to pass a reference to the children array that we started with.
148/**
149 * an LRUCache for storing child entries.
150 * @internal
151 */
152class ChildrenCache extends lru_cache_1.LRUCache {
153    constructor(maxSize = 16 * 1024) {
154        super({
155            maxSize,
156            // parent + children
157            sizeCalculation: a => a.length + 1,
158        });
159    }
160}
161exports.ChildrenCache = ChildrenCache;
162const setAsCwd = Symbol('PathScurry setAsCwd');
163/**
164 * Path objects are sort of like a super-powered
165 * {@link https://nodejs.org/docs/latest/api/fs.html#class-fsdirent fs.Dirent}
166 *
167 * Each one represents a single filesystem entry on disk, which may or may not
168 * exist. It includes methods for reading various types of information via
169 * lstat, readlink, and readdir, and caches all information to the greatest
170 * degree possible.
171 *
172 * Note that fs operations that would normally throw will instead return an
173 * "empty" value. This is in order to prevent excessive overhead from error
174 * stack traces.
175 */
176class PathBase {
177    /**
178     * the basename of this path
179     *
180     * **Important**: *always* test the path name against any test string
181     * usingthe {@link isNamed} method, and not by directly comparing this
182     * string. Otherwise, unicode path strings that the system sees as identical
183     * will not be properly treated as the same path, leading to incorrect
184     * behavior and possible security issues.
185     */
186    name;
187    /**
188     * the Path entry corresponding to the path root.
189     *
190     * @internal
191     */
192    root;
193    /**
194     * All roots found within the current PathScurry family
195     *
196     * @internal
197     */
198    roots;
199    /**
200     * a reference to the parent path, or undefined in the case of root entries
201     *
202     * @internal
203     */
204    parent;
205    /**
206     * boolean indicating whether paths are compared case-insensitively
207     * @internal
208     */
209    nocase;
210    // potential default fs override
211    #fs;
212    // Stats fields
213    #dev;
214    get dev() {
215        return this.#dev;
216    }
217    #mode;
218    get mode() {
219        return this.#mode;
220    }
221    #nlink;
222    get nlink() {
223        return this.#nlink;
224    }
225    #uid;
226    get uid() {
227        return this.#uid;
228    }
229    #gid;
230    get gid() {
231        return this.#gid;
232    }
233    #rdev;
234    get rdev() {
235        return this.#rdev;
236    }
237    #blksize;
238    get blksize() {
239        return this.#blksize;
240    }
241    #ino;
242    get ino() {
243        return this.#ino;
244    }
245    #size;
246    get size() {
247        return this.#size;
248    }
249    #blocks;
250    get blocks() {
251        return this.#blocks;
252    }
253    #atimeMs;
254    get atimeMs() {
255        return this.#atimeMs;
256    }
257    #mtimeMs;
258    get mtimeMs() {
259        return this.#mtimeMs;
260    }
261    #ctimeMs;
262    get ctimeMs() {
263        return this.#ctimeMs;
264    }
265    #birthtimeMs;
266    get birthtimeMs() {
267        return this.#birthtimeMs;
268    }
269    #atime;
270    get atime() {
271        return this.#atime;
272    }
273    #mtime;
274    get mtime() {
275        return this.#mtime;
276    }
277    #ctime;
278    get ctime() {
279        return this.#ctime;
280    }
281    #birthtime;
282    get birthtime() {
283        return this.#birthtime;
284    }
285    #matchName;
286    #depth;
287    #fullpath;
288    #fullpathPosix;
289    #relative;
290    #relativePosix;
291    #type;
292    #children;
293    #linkTarget;
294    #realpath;
295    /**
296     * This property is for compatibility with the Dirent class as of
297     * Node v20, where Dirent['path'] refers to the path of the directory
298     * that was passed to readdir.  So, somewhat counterintuitively, this
299     * property refers to the *parent* path, not the path object itself.
300     * For root entries, it's the path to the entry itself.
301     */
302    get path() {
303        return (this.parent || this).fullpath();
304    }
305    /**
306     * Do not create new Path objects directly.  They should always be accessed
307     * via the PathScurry class or other methods on the Path class.
308     *
309     * @internal
310     */
311    constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
312        this.name = name;
313        this.#matchName = nocase ? normalizeNocase(name) : normalize(name);
314        this.#type = type & TYPEMASK;
315        this.nocase = nocase;
316        this.roots = roots;
317        this.root = root || this;
318        this.#children = children;
319        this.#fullpath = opts.fullpath;
320        this.#relative = opts.relative;
321        this.#relativePosix = opts.relativePosix;
322        this.parent = opts.parent;
323        if (this.parent) {
324            this.#fs = this.parent.#fs;
325        }
326        else {
327            this.#fs = fsFromOption(opts.fs);
328        }
329    }
330    /**
331     * Returns the depth of the Path object from its root.
332     *
333     * For example, a path at `/foo/bar` would have a depth of 2.
334     */
335    depth() {
336        if (this.#depth !== undefined)
337            return this.#depth;
338        if (!this.parent)
339            return (this.#depth = 0);
340        return (this.#depth = this.parent.depth() + 1);
341    }
342    /**
343     * @internal
344     */
345    childrenCache() {
346        return this.#children;
347    }
348    /**
349     * Get the Path object referenced by the string path, resolved from this Path
350     */
351    resolve(path) {
352        if (!path) {
353            return this;
354        }
355        const rootPath = this.getRootString(path);
356        const dir = path.substring(rootPath.length);
357        const dirParts = dir.split(this.splitSep);
358        const result = rootPath
359            ? this.getRoot(rootPath).#resolveParts(dirParts)
360            : this.#resolveParts(dirParts);
361        return result;
362    }
363    #resolveParts(dirParts) {
364        let p = this;
365        for (const part of dirParts) {
366            p = p.child(part);
367        }
368        return p;
369    }
370    /**
371     * Returns the cached children Path objects, if still available.  If they
372     * have fallen out of the cache, then returns an empty array, and resets the
373     * READDIR_CALLED bit, so that future calls to readdir() will require an fs
374     * lookup.
375     *
376     * @internal
377     */
378    children() {
379        const cached = this.#children.get(this);
380        if (cached) {
381            return cached;
382        }
383        const children = Object.assign([], { provisional: 0 });
384        this.#children.set(this, children);
385        this.#type &= ~READDIR_CALLED;
386        return children;
387    }
388    /**
389     * Resolves a path portion and returns or creates the child Path.
390     *
391     * Returns `this` if pathPart is `''` or `'.'`, or `parent` if pathPart is
392     * `'..'`.
393     *
394     * This should not be called directly.  If `pathPart` contains any path
395     * separators, it will lead to unsafe undefined behavior.
396     *
397     * Use `Path.resolve()` instead.
398     *
399     * @internal
400     */
401    child(pathPart, opts) {
402        if (pathPart === '' || pathPart === '.') {
403            return this;
404        }
405        if (pathPart === '..') {
406            return this.parent || this;
407        }
408        // find the child
409        const children = this.children();
410        const name = this.nocase
411            ? normalizeNocase(pathPart)
412            : normalize(pathPart);
413        for (const p of children) {
414            if (p.#matchName === name) {
415                return p;
416            }
417        }
418        // didn't find it, create provisional child, since it might not
419        // actually exist.  If we know the parent isn't a dir, then
420        // in fact it CAN'T exist.
421        const s = this.parent ? this.sep : '';
422        const fullpath = this.#fullpath
423            ? this.#fullpath + s + pathPart
424            : undefined;
425        const pchild = this.newChild(pathPart, UNKNOWN, {
426            ...opts,
427            parent: this,
428            fullpath,
429        });
430        if (!this.canReaddir()) {
431            pchild.#type |= ENOENT;
432        }
433        // don't have to update provisional, because if we have real children,
434        // then provisional is set to children.length, otherwise a lower number
435        children.push(pchild);
436        return pchild;
437    }
438    /**
439     * The relative path from the cwd. If it does not share an ancestor with
440     * the cwd, then this ends up being equivalent to the fullpath()
441     */
442    relative() {
443        if (this.#relative !== undefined) {
444            return this.#relative;
445        }
446        const name = this.name;
447        const p = this.parent;
448        if (!p) {
449            return (this.#relative = this.name);
450        }
451        const pv = p.relative();
452        return pv + (!pv || !p.parent ? '' : this.sep) + name;
453    }
454    /**
455     * The relative path from the cwd, using / as the path separator.
456     * If it does not share an ancestor with
457     * the cwd, then this ends up being equivalent to the fullpathPosix()
458     * On posix systems, this is identical to relative().
459     */
460    relativePosix() {
461        if (this.sep === '/')
462            return this.relative();
463        if (this.#relativePosix !== undefined)
464            return this.#relativePosix;
465        const name = this.name;
466        const p = this.parent;
467        if (!p) {
468            return (this.#relativePosix = this.fullpathPosix());
469        }
470        const pv = p.relativePosix();
471        return pv + (!pv || !p.parent ? '' : '/') + name;
472    }
473    /**
474     * The fully resolved path string for this Path entry
475     */
476    fullpath() {
477        if (this.#fullpath !== undefined) {
478            return this.#fullpath;
479        }
480        const name = this.name;
481        const p = this.parent;
482        if (!p) {
483            return (this.#fullpath = this.name);
484        }
485        const pv = p.fullpath();
486        const fp = pv + (!p.parent ? '' : this.sep) + name;
487        return (this.#fullpath = fp);
488    }
489    /**
490     * On platforms other than windows, this is identical to fullpath.
491     *
492     * On windows, this is overridden to return the forward-slash form of the
493     * full UNC path.
494     */
495    fullpathPosix() {
496        if (this.#fullpathPosix !== undefined)
497            return this.#fullpathPosix;
498        if (this.sep === '/')
499            return (this.#fullpathPosix = this.fullpath());
500        if (!this.parent) {
501            const p = this.fullpath().replace(/\\/g, '/');
502            if (/^[a-z]:\//i.test(p)) {
503                return (this.#fullpathPosix = `//?/${p}`);
504            }
505            else {
506                return (this.#fullpathPosix = p);
507            }
508        }
509        const p = this.parent;
510        const pfpp = p.fullpathPosix();
511        const fpp = pfpp + (!pfpp || !p.parent ? '' : '/') + this.name;
512        return (this.#fullpathPosix = fpp);
513    }
514    /**
515     * Is the Path of an unknown type?
516     *
517     * Note that we might know *something* about it if there has been a previous
518     * filesystem operation, for example that it does not exist, or is not a
519     * link, or whether it has child entries.
520     */
521    isUnknown() {
522        return (this.#type & IFMT) === UNKNOWN;
523    }
524    isType(type) {
525        return this[`is${type}`]();
526    }
527    getType() {
528        return this.isUnknown()
529            ? 'Unknown'
530            : this.isDirectory()
531                ? 'Directory'
532                : this.isFile()
533                    ? 'File'
534                    : this.isSymbolicLink()
535                        ? 'SymbolicLink'
536                        : this.isFIFO()
537                            ? 'FIFO'
538                            : this.isCharacterDevice()
539                                ? 'CharacterDevice'
540                                : this.isBlockDevice()
541                                    ? 'BlockDevice'
542                                    : /* c8 ignore start */ this.isSocket()
543                                        ? 'Socket'
544                                        : 'Unknown';
545        /* c8 ignore stop */
546    }
547    /**
548     * Is the Path a regular file?
549     */
550    isFile() {
551        return (this.#type & IFMT) === IFREG;
552    }
553    /**
554     * Is the Path a directory?
555     */
556    isDirectory() {
557        return (this.#type & IFMT) === IFDIR;
558    }
559    /**
560     * Is the path a character device?
561     */
562    isCharacterDevice() {
563        return (this.#type & IFMT) === IFCHR;
564    }
565    /**
566     * Is the path a block device?
567     */
568    isBlockDevice() {
569        return (this.#type & IFMT) === IFBLK;
570    }
571    /**
572     * Is the path a FIFO pipe?
573     */
574    isFIFO() {
575        return (this.#type & IFMT) === IFIFO;
576    }
577    /**
578     * Is the path a socket?
579     */
580    isSocket() {
581        return (this.#type & IFMT) === IFSOCK;
582    }
583    /**
584     * Is the path a symbolic link?
585     */
586    isSymbolicLink() {
587        return (this.#type & IFLNK) === IFLNK;
588    }
589    /**
590     * Return the entry if it has been subject of a successful lstat, or
591     * undefined otherwise.
592     *
593     * Does not read the filesystem, so an undefined result *could* simply
594     * mean that we haven't called lstat on it.
595     */
596    lstatCached() {
597        return this.#type & LSTAT_CALLED ? this : undefined;
598    }
599    /**
600     * Return the cached link target if the entry has been the subject of a
601     * successful readlink, or undefined otherwise.
602     *
603     * Does not read the filesystem, so an undefined result *could* just mean we
604     * don't have any cached data. Only use it if you are very sure that a
605     * readlink() has been called at some point.
606     */
607    readlinkCached() {
608        return this.#linkTarget;
609    }
610    /**
611     * Returns the cached realpath target if the entry has been the subject
612     * of a successful realpath, or undefined otherwise.
613     *
614     * Does not read the filesystem, so an undefined result *could* just mean we
615     * don't have any cached data. Only use it if you are very sure that a
616     * realpath() has been called at some point.
617     */
618    realpathCached() {
619        return this.#realpath;
620    }
621    /**
622     * Returns the cached child Path entries array if the entry has been the
623     * subject of a successful readdir(), or [] otherwise.
624     *
625     * Does not read the filesystem, so an empty array *could* just mean we
626     * don't have any cached data. Only use it if you are very sure that a
627     * readdir() has been called recently enough to still be valid.
628     */
629    readdirCached() {
630        const children = this.children();
631        return children.slice(0, children.provisional);
632    }
633    /**
634     * Return true if it's worth trying to readlink.  Ie, we don't (yet) have
635     * any indication that readlink will definitely fail.
636     *
637     * Returns false if the path is known to not be a symlink, if a previous
638     * readlink failed, or if the entry does not exist.
639     */
640    canReadlink() {
641        if (this.#linkTarget)
642            return true;
643        if (!this.parent)
644            return false;
645        // cases where it cannot possibly succeed
646        const ifmt = this.#type & IFMT;
647        return !((ifmt !== UNKNOWN && ifmt !== IFLNK) ||
648            this.#type & ENOREADLINK ||
649            this.#type & ENOENT);
650    }
651    /**
652     * Return true if readdir has previously been successfully called on this
653     * path, indicating that cachedReaddir() is likely valid.
654     */
655    calledReaddir() {
656        return !!(this.#type & READDIR_CALLED);
657    }
658    /**
659     * Returns true if the path is known to not exist. That is, a previous lstat
660     * or readdir failed to verify its existence when that would have been
661     * expected, or a parent entry was marked either enoent or enotdir.
662     */
663    isENOENT() {
664        return !!(this.#type & ENOENT);
665    }
666    /**
667     * Return true if the path is a match for the given path name.  This handles
668     * case sensitivity and unicode normalization.
669     *
670     * Note: even on case-sensitive systems, it is **not** safe to test the
671     * equality of the `.name` property to determine whether a given pathname
672     * matches, due to unicode normalization mismatches.
673     *
674     * Always use this method instead of testing the `path.name` property
675     * directly.
676     */
677    isNamed(n) {
678        return !this.nocase
679            ? this.#matchName === normalize(n)
680            : this.#matchName === normalizeNocase(n);
681    }
682    /**
683     * Return the Path object corresponding to the target of a symbolic link.
684     *
685     * If the Path is not a symbolic link, or if the readlink call fails for any
686     * reason, `undefined` is returned.
687     *
688     * Result is cached, and thus may be outdated if the filesystem is mutated.
689     */
690    async readlink() {
691        const target = this.#linkTarget;
692        if (target) {
693            return target;
694        }
695        if (!this.canReadlink()) {
696            return undefined;
697        }
698        /* c8 ignore start */
699        // already covered by the canReadlink test, here for ts grumples
700        if (!this.parent) {
701            return undefined;
702        }
703        /* c8 ignore stop */
704        try {
705            const read = await this.#fs.promises.readlink(this.fullpath());
706            const linkTarget = this.parent.resolve(read);
707            if (linkTarget) {
708                return (this.#linkTarget = linkTarget);
709            }
710        }
711        catch (er) {
712            this.#readlinkFail(er.code);
713            return undefined;
714        }
715    }
716    /**
717     * Synchronous {@link PathBase.readlink}
718     */
719    readlinkSync() {
720        const target = this.#linkTarget;
721        if (target) {
722            return target;
723        }
724        if (!this.canReadlink()) {
725            return undefined;
726        }
727        /* c8 ignore start */
728        // already covered by the canReadlink test, here for ts grumples
729        if (!this.parent) {
730            return undefined;
731        }
732        /* c8 ignore stop */
733        try {
734            const read = this.#fs.readlinkSync(this.fullpath());
735            const linkTarget = this.parent.resolve(read);
736            if (linkTarget) {
737                return (this.#linkTarget = linkTarget);
738            }
739        }
740        catch (er) {
741            this.#readlinkFail(er.code);
742            return undefined;
743        }
744    }
745    #readdirSuccess(children) {
746        // succeeded, mark readdir called bit
747        this.#type |= READDIR_CALLED;
748        // mark all remaining provisional children as ENOENT
749        for (let p = children.provisional; p < children.length; p++) {
750            children[p].#markENOENT();
751        }
752    }
753    #markENOENT() {
754        // mark as UNKNOWN and ENOENT
755        if (this.#type & ENOENT)
756            return;
757        this.#type = (this.#type | ENOENT) & IFMT_UNKNOWN;
758        this.#markChildrenENOENT();
759    }
760    #markChildrenENOENT() {
761        // all children are provisional and do not exist
762        const children = this.children();
763        children.provisional = 0;
764        for (const p of children) {
765            p.#markENOENT();
766        }
767    }
768    #markENOREALPATH() {
769        this.#type |= ENOREALPATH;
770        this.#markENOTDIR();
771    }
772    // save the information when we know the entry is not a dir
773    #markENOTDIR() {
774        // entry is not a directory, so any children can't exist.
775        // this *should* be impossible, since any children created
776        // after it's been marked ENOTDIR should be marked ENOENT,
777        // so it won't even get to this point.
778        /* c8 ignore start */
779        if (this.#type & ENOTDIR)
780            return;
781        /* c8 ignore stop */
782        let t = this.#type;
783        // this could happen if we stat a dir, then delete it,
784        // then try to read it or one of its children.
785        if ((t & IFMT) === IFDIR)
786            t &= IFMT_UNKNOWN;
787        this.#type = t | ENOTDIR;
788        this.#markChildrenENOENT();
789    }
790    #readdirFail(code = '') {
791        // markENOTDIR and markENOENT also set provisional=0
792        if (code === 'ENOTDIR' || code === 'EPERM') {
793            this.#markENOTDIR();
794        }
795        else if (code === 'ENOENT') {
796            this.#markENOENT();
797        }
798        else {
799            this.children().provisional = 0;
800        }
801    }
802    #lstatFail(code = '') {
803        // Windows just raises ENOENT in this case, disable for win CI
804        /* c8 ignore start */
805        if (code === 'ENOTDIR') {
806            // already know it has a parent by this point
807            const p = this.parent;
808            p.#markENOTDIR();
809        }
810        else if (code === 'ENOENT') {
811            /* c8 ignore stop */
812            this.#markENOENT();
813        }
814    }
815    #readlinkFail(code = '') {
816        let ter = this.#type;
817        ter |= ENOREADLINK;
818        if (code === 'ENOENT')
819            ter |= ENOENT;
820        // windows gets a weird error when you try to readlink a file
821        if (code === 'EINVAL' || code === 'UNKNOWN') {
822            // exists, but not a symlink, we don't know WHAT it is, so remove
823            // all IFMT bits.
824            ter &= IFMT_UNKNOWN;
825        }
826        this.#type = ter;
827        // windows just gets ENOENT in this case.  We do cover the case,
828        // just disabled because it's impossible on Windows CI
829        /* c8 ignore start */
830        if (code === 'ENOTDIR' && this.parent) {
831            this.parent.#markENOTDIR();
832        }
833        /* c8 ignore stop */
834    }
835    #readdirAddChild(e, c) {
836        return (this.#readdirMaybePromoteChild(e, c) ||
837            this.#readdirAddNewChild(e, c));
838    }
839    #readdirAddNewChild(e, c) {
840        // alloc new entry at head, so it's never provisional
841        const type = entToType(e);
842        const child = this.newChild(e.name, type, { parent: this });
843        const ifmt = child.#type & IFMT;
844        if (ifmt !== IFDIR && ifmt !== IFLNK && ifmt !== UNKNOWN) {
845            child.#type |= ENOTDIR;
846        }
847        c.unshift(child);
848        c.provisional++;
849        return child;
850    }
851    #readdirMaybePromoteChild(e, c) {
852        for (let p = c.provisional; p < c.length; p++) {
853            const pchild = c[p];
854            const name = this.nocase
855                ? normalizeNocase(e.name)
856                : normalize(e.name);
857            if (name !== pchild.#matchName) {
858                continue;
859            }
860            return this.#readdirPromoteChild(e, pchild, p, c);
861        }
862    }
863    #readdirPromoteChild(e, p, index, c) {
864        const v = p.name;
865        // retain any other flags, but set ifmt from dirent
866        p.#type = (p.#type & IFMT_UNKNOWN) | entToType(e);
867        // case sensitivity fixing when we learn the true name.
868        if (v !== e.name)
869            p.name = e.name;
870        // just advance provisional index (potentially off the list),
871        // otherwise we have to splice/pop it out and re-insert at head
872        if (index !== c.provisional) {
873            if (index === c.length - 1)
874                c.pop();
875            else
876                c.splice(index, 1);
877            c.unshift(p);
878        }
879        c.provisional++;
880        return p;
881    }
882    /**
883     * Call lstat() on this Path, and update all known information that can be
884     * determined.
885     *
886     * Note that unlike `fs.lstat()`, the returned value does not contain some
887     * information, such as `mode`, `dev`, `nlink`, and `ino`.  If that
888     * information is required, you will need to call `fs.lstat` yourself.
889     *
890     * If the Path refers to a nonexistent file, or if the lstat call fails for
891     * any reason, `undefined` is returned.  Otherwise the updated Path object is
892     * returned.
893     *
894     * Results are cached, and thus may be out of date if the filesystem is
895     * mutated.
896     */
897    async lstat() {
898        if ((this.#type & ENOENT) === 0) {
899            try {
900                this.#applyStat(await this.#fs.promises.lstat(this.fullpath()));
901                return this;
902            }
903            catch (er) {
904                this.#lstatFail(er.code);
905            }
906        }
907    }
908    /**
909     * synchronous {@link PathBase.lstat}
910     */
911    lstatSync() {
912        if ((this.#type & ENOENT) === 0) {
913            try {
914                this.#applyStat(this.#fs.lstatSync(this.fullpath()));
915                return this;
916            }
917            catch (er) {
918                this.#lstatFail(er.code);
919            }
920        }
921    }
922    #applyStat(st) {
923        const { atime, atimeMs, birthtime, birthtimeMs, blksize, blocks, ctime, ctimeMs, dev, gid, ino, mode, mtime, mtimeMs, nlink, rdev, size, uid, } = st;
924        this.#atime = atime;
925        this.#atimeMs = atimeMs;
926        this.#birthtime = birthtime;
927        this.#birthtimeMs = birthtimeMs;
928        this.#blksize = blksize;
929        this.#blocks = blocks;
930        this.#ctime = ctime;
931        this.#ctimeMs = ctimeMs;
932        this.#dev = dev;
933        this.#gid = gid;
934        this.#ino = ino;
935        this.#mode = mode;
936        this.#mtime = mtime;
937        this.#mtimeMs = mtimeMs;
938        this.#nlink = nlink;
939        this.#rdev = rdev;
940        this.#size = size;
941        this.#uid = uid;
942        const ifmt = entToType(st);
943        // retain any other flags, but set the ifmt
944        this.#type = (this.#type & IFMT_UNKNOWN) | ifmt | LSTAT_CALLED;
945        if (ifmt !== UNKNOWN && ifmt !== IFDIR && ifmt !== IFLNK) {
946            this.#type |= ENOTDIR;
947        }
948    }
949    #onReaddirCB = [];
950    #readdirCBInFlight = false;
951    #callOnReaddirCB(children) {
952        this.#readdirCBInFlight = false;
953        const cbs = this.#onReaddirCB.slice();
954        this.#onReaddirCB.length = 0;
955        cbs.forEach(cb => cb(null, children));
956    }
957    /**
958     * Standard node-style callback interface to get list of directory entries.
959     *
960     * If the Path cannot or does not contain any children, then an empty array
961     * is returned.
962     *
963     * Results are cached, and thus may be out of date if the filesystem is
964     * mutated.
965     *
966     * @param cb The callback called with (er, entries).  Note that the `er`
967     * param is somewhat extraneous, as all readdir() errors are handled and
968     * simply result in an empty set of entries being returned.
969     * @param allowZalgo Boolean indicating that immediately known results should
970     * *not* be deferred with `queueMicrotask`. Defaults to `false`. Release
971     * zalgo at your peril, the dark pony lord is devious and unforgiving.
972     */
973    readdirCB(cb, allowZalgo = false) {
974        if (!this.canReaddir()) {
975            if (allowZalgo)
976                cb(null, []);
977            else
978                queueMicrotask(() => cb(null, []));
979            return;
980        }
981        const children = this.children();
982        if (this.calledReaddir()) {
983            const c = children.slice(0, children.provisional);
984            if (allowZalgo)
985                cb(null, c);
986            else
987                queueMicrotask(() => cb(null, c));
988            return;
989        }
990        // don't have to worry about zalgo at this point.
991        this.#onReaddirCB.push(cb);
992        if (this.#readdirCBInFlight) {
993            return;
994        }
995        this.#readdirCBInFlight = true;
996        // else read the directory, fill up children
997        // de-provisionalize any provisional children.
998        const fullpath = this.fullpath();
999        this.#fs.readdir(fullpath, { withFileTypes: true }, (er, entries) => {
1000            if (er) {
1001                this.#readdirFail(er.code);
1002                children.provisional = 0;
1003            }
1004            else {
1005                // if we didn't get an error, we always get entries.
1006                //@ts-ignore
1007                for (const e of entries) {
1008                    this.#readdirAddChild(e, children);
1009                }
1010                this.#readdirSuccess(children);
1011            }
1012            this.#callOnReaddirCB(children.slice(0, children.provisional));
1013            return;
1014        });
1015    }
1016    #asyncReaddirInFlight;
1017    /**
1018     * Return an array of known child entries.
1019     *
1020     * If the Path cannot or does not contain any children, then an empty array
1021     * is returned.
1022     *
1023     * Results are cached, and thus may be out of date if the filesystem is
1024     * mutated.
1025     */
1026    async readdir() {
1027        if (!this.canReaddir()) {
1028            return [];
1029        }
1030        const children = this.children();
1031        if (this.calledReaddir()) {
1032            return children.slice(0, children.provisional);
1033        }
1034        // else read the directory, fill up children
1035        // de-provisionalize any provisional children.
1036        const fullpath = this.fullpath();
1037        if (this.#asyncReaddirInFlight) {
1038            await this.#asyncReaddirInFlight;
1039        }
1040        else {
1041            /* c8 ignore start */
1042            let resolve = () => { };
1043            /* c8 ignore stop */
1044            this.#asyncReaddirInFlight = new Promise(res => (resolve = res));
1045            try {
1046                for (const e of await this.#fs.promises.readdir(fullpath, {
1047                    withFileTypes: true,
1048                })) {
1049                    this.#readdirAddChild(e, children);
1050                }
1051                this.#readdirSuccess(children);
1052            }
1053            catch (er) {
1054                this.#readdirFail(er.code);
1055                children.provisional = 0;
1056            }
1057            this.#asyncReaddirInFlight = undefined;
1058            resolve();
1059        }
1060        return children.slice(0, children.provisional);
1061    }
1062    /**
1063     * synchronous {@link PathBase.readdir}
1064     */
1065    readdirSync() {
1066        if (!this.canReaddir()) {
1067            return [];
1068        }
1069        const children = this.children();
1070        if (this.calledReaddir()) {
1071            return children.slice(0, children.provisional);
1072        }
1073        // else read the directory, fill up children
1074        // de-provisionalize any provisional children.
1075        const fullpath = this.fullpath();
1076        try {
1077            for (const e of this.#fs.readdirSync(fullpath, {
1078                withFileTypes: true,
1079            })) {
1080                this.#readdirAddChild(e, children);
1081            }
1082            this.#readdirSuccess(children);
1083        }
1084        catch (er) {
1085            this.#readdirFail(er.code);
1086            children.provisional = 0;
1087        }
1088        return children.slice(0, children.provisional);
1089    }
1090    canReaddir() {
1091        if (this.#type & ENOCHILD)
1092            return false;
1093        const ifmt = IFMT & this.#type;
1094        // we always set ENOTDIR when setting IFMT, so should be impossible
1095        /* c8 ignore start */
1096        if (!(ifmt === UNKNOWN || ifmt === IFDIR || ifmt === IFLNK)) {
1097            return false;
1098        }
1099        /* c8 ignore stop */
1100        return true;
1101    }
1102    shouldWalk(dirs, walkFilter) {
1103        return ((this.#type & IFDIR) === IFDIR &&
1104            !(this.#type & ENOCHILD) &&
1105            !dirs.has(this) &&
1106            (!walkFilter || walkFilter(this)));
1107    }
1108    /**
1109     * Return the Path object corresponding to path as resolved
1110     * by realpath(3).
1111     *
1112     * If the realpath call fails for any reason, `undefined` is returned.
1113     *
1114     * Result is cached, and thus may be outdated if the filesystem is mutated.
1115     * On success, returns a Path object.
1116     */
1117    async realpath() {
1118        if (this.#realpath)
1119            return this.#realpath;
1120        if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type)
1121            return undefined;
1122        try {
1123            const rp = await this.#fs.promises.realpath(this.fullpath());
1124            return (this.#realpath = this.resolve(rp));
1125        }
1126        catch (_) {
1127            this.#markENOREALPATH();
1128        }
1129    }
1130    /**
1131     * Synchronous {@link realpath}
1132     */
1133    realpathSync() {
1134        if (this.#realpath)
1135            return this.#realpath;
1136        if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type)
1137            return undefined;
1138        try {
1139            const rp = this.#fs.realpathSync(this.fullpath());
1140            return (this.#realpath = this.resolve(rp));
1141        }
1142        catch (_) {
1143            this.#markENOREALPATH();
1144        }
1145    }
1146    /**
1147     * Internal method to mark this Path object as the scurry cwd,
1148     * called by {@link PathScurry#chdir}
1149     *
1150     * @internal
1151     */
1152    [setAsCwd](oldCwd) {
1153        if (oldCwd === this)
1154            return;
1155        const changed = new Set([]);
1156        let rp = [];
1157        let p = this;
1158        while (p && p.parent) {
1159            changed.add(p);
1160            p.#relative = rp.join(this.sep);
1161            p.#relativePosix = rp.join('/');
1162            p = p.parent;
1163            rp.push('..');
1164        }
1165        // now un-memoize parents of old cwd
1166        p = oldCwd;
1167        while (p && p.parent && !changed.has(p)) {
1168            p.#relative = undefined;
1169            p.#relativePosix = undefined;
1170            p = p.parent;
1171        }
1172    }
1173}
1174exports.PathBase = PathBase;
1175/**
1176 * Path class used on win32 systems
1177 *
1178 * Uses `'\\'` as the path separator for returned paths, either `'\\'` or `'/'`
1179 * as the path separator for parsing paths.
1180 */
1181class PathWin32 extends PathBase {
1182    /**
1183     * Separator for generating path strings.
1184     */
1185    sep = '\\';
1186    /**
1187     * Separator for parsing path strings.
1188     */
1189    splitSep = eitherSep;
1190    /**
1191     * Do not create new Path objects directly.  They should always be accessed
1192     * via the PathScurry class or other methods on the Path class.
1193     *
1194     * @internal
1195     */
1196    constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
1197        super(name, type, root, roots, nocase, children, opts);
1198    }
1199    /**
1200     * @internal
1201     */
1202    newChild(name, type = UNKNOWN, opts = {}) {
1203        return new PathWin32(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
1204    }
1205    /**
1206     * @internal
1207     */
1208    getRootString(path) {
1209        return path_1.win32.parse(path).root;
1210    }
1211    /**
1212     * @internal
1213     */
1214    getRoot(rootPath) {
1215        rootPath = uncToDrive(rootPath.toUpperCase());
1216        if (rootPath === this.root.name) {
1217            return this.root;
1218        }
1219        // ok, not that one, check if it matches another we know about
1220        for (const [compare, root] of Object.entries(this.roots)) {
1221            if (this.sameRoot(rootPath, compare)) {
1222                return (this.roots[rootPath] = root);
1223            }
1224        }
1225        // otherwise, have to create a new one.
1226        return (this.roots[rootPath] = new PathScurryWin32(rootPath, this).root);
1227    }
1228    /**
1229     * @internal
1230     */
1231    sameRoot(rootPath, compare = this.root.name) {
1232        // windows can (rarely) have case-sensitive filesystem, but
1233        // UNC and drive letters are always case-insensitive, and canonically
1234        // represented uppercase.
1235        rootPath = rootPath
1236            .toUpperCase()
1237            .replace(/\//g, '\\')
1238            .replace(uncDriveRegexp, '$1\\');
1239        return rootPath === compare;
1240    }
1241}
1242exports.PathWin32 = PathWin32;
1243/**
1244 * Path class used on all posix systems.
1245 *
1246 * Uses `'/'` as the path separator.
1247 */
1248class PathPosix extends PathBase {
1249    /**
1250     * separator for parsing path strings
1251     */
1252    splitSep = '/';
1253    /**
1254     * separator for generating path strings
1255     */
1256    sep = '/';
1257    /**
1258     * Do not create new Path objects directly.  They should always be accessed
1259     * via the PathScurry class or other methods on the Path class.
1260     *
1261     * @internal
1262     */
1263    constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
1264        super(name, type, root, roots, nocase, children, opts);
1265    }
1266    /**
1267     * @internal
1268     */
1269    getRootString(path) {
1270        return path.startsWith('/') ? '/' : '';
1271    }
1272    /**
1273     * @internal
1274     */
1275    getRoot(_rootPath) {
1276        return this.root;
1277    }
1278    /**
1279     * @internal
1280     */
1281    newChild(name, type = UNKNOWN, opts = {}) {
1282        return new PathPosix(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
1283    }
1284}
1285exports.PathPosix = PathPosix;
1286/**
1287 * The base class for all PathScurry classes, providing the interface for path
1288 * resolution and filesystem operations.
1289 *
1290 * Typically, you should *not* instantiate this class directly, but rather one
1291 * of the platform-specific classes, or the exported {@link PathScurry} which
1292 * defaults to the current platform.
1293 */
1294class PathScurryBase {
1295    /**
1296     * The root Path entry for the current working directory of this Scurry
1297     */
1298    root;
1299    /**
1300     * The string path for the root of this Scurry's current working directory
1301     */
1302    rootPath;
1303    /**
1304     * A collection of all roots encountered, referenced by rootPath
1305     */
1306    roots;
1307    /**
1308     * The Path entry corresponding to this PathScurry's current working directory.
1309     */
1310    cwd;
1311    #resolveCache;
1312    #resolvePosixCache;
1313    #children;
1314    /**
1315     * Perform path comparisons case-insensitively.
1316     *
1317     * Defaults true on Darwin and Windows systems, false elsewhere.
1318     */
1319    nocase;
1320    #fs;
1321    /**
1322     * This class should not be instantiated directly.
1323     *
1324     * Use PathScurryWin32, PathScurryDarwin, PathScurryPosix, or PathScurry
1325     *
1326     * @internal
1327     */
1328    constructor(cwd = process.cwd(), pathImpl, sep, { nocase, childrenCacheSize = 16 * 1024, fs = defaultFS, } = {}) {
1329        this.#fs = fsFromOption(fs);
1330        if (cwd instanceof URL || cwd.startsWith('file://')) {
1331            cwd = (0, url_1.fileURLToPath)(cwd);
1332        }
1333        // resolve and split root, and then add to the store.
1334        // this is the only time we call path.resolve()
1335        const cwdPath = pathImpl.resolve(cwd);
1336        this.roots = Object.create(null);
1337        this.rootPath = this.parseRootPath(cwdPath);
1338        this.#resolveCache = new ResolveCache();
1339        this.#resolvePosixCache = new ResolveCache();
1340        this.#children = new ChildrenCache(childrenCacheSize);
1341        const split = cwdPath.substring(this.rootPath.length).split(sep);
1342        // resolve('/') leaves '', splits to [''], we don't want that.
1343        if (split.length === 1 && !split[0]) {
1344            split.pop();
1345        }
1346        /* c8 ignore start */
1347        if (nocase === undefined) {
1348            throw new TypeError('must provide nocase setting to PathScurryBase ctor');
1349        }
1350        /* c8 ignore stop */
1351        this.nocase = nocase;
1352        this.root = this.newRoot(this.#fs);
1353        this.roots[this.rootPath] = this.root;
1354        let prev = this.root;
1355        let len = split.length - 1;
1356        const joinSep = pathImpl.sep;
1357        let abs = this.rootPath;
1358        let sawFirst = false;
1359        for (const part of split) {
1360            const l = len--;
1361            prev = prev.child(part, {
1362                relative: new Array(l).fill('..').join(joinSep),
1363                relativePosix: new Array(l).fill('..').join('/'),
1364                fullpath: (abs += (sawFirst ? '' : joinSep) + part),
1365            });
1366            sawFirst = true;
1367        }
1368        this.cwd = prev;
1369    }
1370    /**
1371     * Get the depth of a provided path, string, or the cwd
1372     */
1373    depth(path = this.cwd) {
1374        if (typeof path === 'string') {
1375            path = this.cwd.resolve(path);
1376        }
1377        return path.depth();
1378    }
1379    /**
1380     * Return the cache of child entries.  Exposed so subclasses can create
1381     * child Path objects in a platform-specific way.
1382     *
1383     * @internal
1384     */
1385    childrenCache() {
1386        return this.#children;
1387    }
1388    /**
1389     * Resolve one or more path strings to a resolved string
1390     *
1391     * Same interface as require('path').resolve.
1392     *
1393     * Much faster than path.resolve() when called multiple times for the same
1394     * path, because the resolved Path objects are cached.  Much slower
1395     * otherwise.
1396     */
1397    resolve(...paths) {
1398        // first figure out the minimum number of paths we have to test
1399        // we always start at cwd, but any absolutes will bump the start
1400        let r = '';
1401        for (let i = paths.length - 1; i >= 0; i--) {
1402            const p = paths[i];
1403            if (!p || p === '.')
1404                continue;
1405            r = r ? `${p}/${r}` : p;
1406            if (this.isAbsolute(p)) {
1407                break;
1408            }
1409        }
1410        const cached = this.#resolveCache.get(r);
1411        if (cached !== undefined) {
1412            return cached;
1413        }
1414        const result = this.cwd.resolve(r).fullpath();
1415        this.#resolveCache.set(r, result);
1416        return result;
1417    }
1418    /**
1419     * Resolve one or more path strings to a resolved string, returning
1420     * the posix path.  Identical to .resolve() on posix systems, but on
1421     * windows will return a forward-slash separated UNC path.
1422     *
1423     * Same interface as require('path').resolve.
1424     *
1425     * Much faster than path.resolve() when called multiple times for the same
1426     * path, because the resolved Path objects are cached.  Much slower
1427     * otherwise.
1428     */
1429    resolvePosix(...paths) {
1430        // first figure out the minimum number of paths we have to test
1431        // we always start at cwd, but any absolutes will bump the start
1432        let r = '';
1433        for (let i = paths.length - 1; i >= 0; i--) {
1434            const p = paths[i];
1435            if (!p || p === '.')
1436                continue;
1437            r = r ? `${p}/${r}` : p;
1438            if (this.isAbsolute(p)) {
1439                break;
1440            }
1441        }
1442        const cached = this.#resolvePosixCache.get(r);
1443        if (cached !== undefined) {
1444            return cached;
1445        }
1446        const result = this.cwd.resolve(r).fullpathPosix();
1447        this.#resolvePosixCache.set(r, result);
1448        return result;
1449    }
1450    /**
1451     * find the relative path from the cwd to the supplied path string or entry
1452     */
1453    relative(entry = this.cwd) {
1454        if (typeof entry === 'string') {
1455            entry = this.cwd.resolve(entry);
1456        }
1457        return entry.relative();
1458    }
1459    /**
1460     * find the relative path from the cwd to the supplied path string or
1461     * entry, using / as the path delimiter, even on Windows.
1462     */
1463    relativePosix(entry = this.cwd) {
1464        if (typeof entry === 'string') {
1465            entry = this.cwd.resolve(entry);
1466        }
1467        return entry.relativePosix();
1468    }
1469    /**
1470     * Return the basename for the provided string or Path object
1471     */
1472    basename(entry = this.cwd) {
1473        if (typeof entry === 'string') {
1474            entry = this.cwd.resolve(entry);
1475        }
1476        return entry.name;
1477    }
1478    /**
1479     * Return the dirname for the provided string or Path object
1480     */
1481    dirname(entry = this.cwd) {
1482        if (typeof entry === 'string') {
1483            entry = this.cwd.resolve(entry);
1484        }
1485        return (entry.parent || entry).fullpath();
1486    }
1487    async readdir(entry = this.cwd, opts = {
1488        withFileTypes: true,
1489    }) {
1490        if (typeof entry === 'string') {
1491            entry = this.cwd.resolve(entry);
1492        }
1493        else if (!(entry instanceof PathBase)) {
1494            opts = entry;
1495            entry = this.cwd;
1496        }
1497        const { withFileTypes } = opts;
1498        if (!entry.canReaddir()) {
1499            return [];
1500        }
1501        else {
1502            const p = await entry.readdir();
1503            return withFileTypes ? p : p.map(e => e.name);
1504        }
1505    }
1506    readdirSync(entry = this.cwd, opts = {
1507        withFileTypes: true,
1508    }) {
1509        if (typeof entry === 'string') {
1510            entry = this.cwd.resolve(entry);
1511        }
1512        else if (!(entry instanceof PathBase)) {
1513            opts = entry;
1514            entry = this.cwd;
1515        }
1516        const { withFileTypes = true } = opts;
1517        if (!entry.canReaddir()) {
1518            return [];
1519        }
1520        else if (withFileTypes) {
1521            return entry.readdirSync();
1522        }
1523        else {
1524            return entry.readdirSync().map(e => e.name);
1525        }
1526    }
1527    /**
1528     * Call lstat() on the string or Path object, and update all known
1529     * information that can be determined.
1530     *
1531     * Note that unlike `fs.lstat()`, the returned value does not contain some
1532     * information, such as `mode`, `dev`, `nlink`, and `ino`.  If that
1533     * information is required, you will need to call `fs.lstat` yourself.
1534     *
1535     * If the Path refers to a nonexistent file, or if the lstat call fails for
1536     * any reason, `undefined` is returned.  Otherwise the updated Path object is
1537     * returned.
1538     *
1539     * Results are cached, and thus may be out of date if the filesystem is
1540     * mutated.
1541     */
1542    async lstat(entry = this.cwd) {
1543        if (typeof entry === 'string') {
1544            entry = this.cwd.resolve(entry);
1545        }
1546        return entry.lstat();
1547    }
1548    /**
1549     * synchronous {@link PathScurryBase.lstat}
1550     */
1551    lstatSync(entry = this.cwd) {
1552        if (typeof entry === 'string') {
1553            entry = this.cwd.resolve(entry);
1554        }
1555        return entry.lstatSync();
1556    }
1557    async readlink(entry = this.cwd, { withFileTypes } = {
1558        withFileTypes: false,
1559    }) {
1560        if (typeof entry === 'string') {
1561            entry = this.cwd.resolve(entry);
1562        }
1563        else if (!(entry instanceof PathBase)) {
1564            withFileTypes = entry.withFileTypes;
1565            entry = this.cwd;
1566        }
1567        const e = await entry.readlink();
1568        return withFileTypes ? e : e?.fullpath();
1569    }
1570    readlinkSync(entry = this.cwd, { withFileTypes } = {
1571        withFileTypes: false,
1572    }) {
1573        if (typeof entry === 'string') {
1574            entry = this.cwd.resolve(entry);
1575        }
1576        else if (!(entry instanceof PathBase)) {
1577            withFileTypes = entry.withFileTypes;
1578            entry = this.cwd;
1579        }
1580        const e = entry.readlinkSync();
1581        return withFileTypes ? e : e?.fullpath();
1582    }
1583    async realpath(entry = this.cwd, { withFileTypes } = {
1584        withFileTypes: false,
1585    }) {
1586        if (typeof entry === 'string') {
1587            entry = this.cwd.resolve(entry);
1588        }
1589        else if (!(entry instanceof PathBase)) {
1590            withFileTypes = entry.withFileTypes;
1591            entry = this.cwd;
1592        }
1593        const e = await entry.realpath();
1594        return withFileTypes ? e : e?.fullpath();
1595    }
1596    realpathSync(entry = this.cwd, { withFileTypes } = {
1597        withFileTypes: false,
1598    }) {
1599        if (typeof entry === 'string') {
1600            entry = this.cwd.resolve(entry);
1601        }
1602        else if (!(entry instanceof PathBase)) {
1603            withFileTypes = entry.withFileTypes;
1604            entry = this.cwd;
1605        }
1606        const e = entry.realpathSync();
1607        return withFileTypes ? e : e?.fullpath();
1608    }
1609    async walk(entry = this.cwd, opts = {}) {
1610        if (typeof entry === 'string') {
1611            entry = this.cwd.resolve(entry);
1612        }
1613        else if (!(entry instanceof PathBase)) {
1614            opts = entry;
1615            entry = this.cwd;
1616        }
1617        const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
1618        const results = [];
1619        if (!filter || filter(entry)) {
1620            results.push(withFileTypes ? entry : entry.fullpath());
1621        }
1622        const dirs = new Set();
1623        const walk = (dir, cb) => {
1624            dirs.add(dir);
1625            dir.readdirCB((er, entries) => {
1626                /* c8 ignore start */
1627                if (er) {
1628                    return cb(er);
1629                }
1630                /* c8 ignore stop */
1631                let len = entries.length;
1632                if (!len)
1633                    return cb();
1634                const next = () => {
1635                    if (--len === 0) {
1636                        cb();
1637                    }
1638                };
1639                for (const e of entries) {
1640                    if (!filter || filter(e)) {
1641                        results.push(withFileTypes ? e : e.fullpath());
1642                    }
1643                    if (follow && e.isSymbolicLink()) {
1644                        e.realpath()
1645                            .then(r => (r?.isUnknown() ? r.lstat() : r))
1646                            .then(r => r?.shouldWalk(dirs, walkFilter) ? walk(r, next) : next());
1647                    }
1648                    else {
1649                        if (e.shouldWalk(dirs, walkFilter)) {
1650                            walk(e, next);
1651                        }
1652                        else {
1653                            next();
1654                        }
1655                    }
1656                }
1657            }, true); // zalgooooooo
1658        };
1659        const start = entry;
1660        return new Promise((res, rej) => {
1661            walk(start, er => {
1662                /* c8 ignore start */
1663                if (er)
1664                    return rej(er);
1665                /* c8 ignore stop */
1666                res(results);
1667            });
1668        });
1669    }
1670    walkSync(entry = this.cwd, opts = {}) {
1671        if (typeof entry === 'string') {
1672            entry = this.cwd.resolve(entry);
1673        }
1674        else if (!(entry instanceof PathBase)) {
1675            opts = entry;
1676            entry = this.cwd;
1677        }
1678        const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
1679        const results = [];
1680        if (!filter || filter(entry)) {
1681            results.push(withFileTypes ? entry : entry.fullpath());
1682        }
1683        const dirs = new Set([entry]);
1684        for (const dir of dirs) {
1685            const entries = dir.readdirSync();
1686            for (const e of entries) {
1687                if (!filter || filter(e)) {
1688                    results.push(withFileTypes ? e : e.fullpath());
1689                }
1690                let r = e;
1691                if (e.isSymbolicLink()) {
1692                    if (!(follow && (r = e.realpathSync())))
1693                        continue;
1694                    if (r.isUnknown())
1695                        r.lstatSync();
1696                }
1697                if (r.shouldWalk(dirs, walkFilter)) {
1698                    dirs.add(r);
1699                }
1700            }
1701        }
1702        return results;
1703    }
1704    /**
1705     * Support for `for await`
1706     *
1707     * Alias for {@link PathScurryBase.iterate}
1708     *
1709     * Note: As of Node 19, this is very slow, compared to other methods of
1710     * walking.  Consider using {@link PathScurryBase.stream} if memory overhead
1711     * and backpressure are concerns, or {@link PathScurryBase.walk} if not.
1712     */
1713    [Symbol.asyncIterator]() {
1714        return this.iterate();
1715    }
1716    iterate(entry = this.cwd, options = {}) {
1717        // iterating async over the stream is significantly more performant,
1718        // especially in the warm-cache scenario, because it buffers up directory
1719        // entries in the background instead of waiting for a yield for each one.
1720        if (typeof entry === 'string') {
1721            entry = this.cwd.resolve(entry);
1722        }
1723        else if (!(entry instanceof PathBase)) {
1724            options = entry;
1725            entry = this.cwd;
1726        }
1727        return this.stream(entry, options)[Symbol.asyncIterator]();
1728    }
1729    /**
1730     * Iterating over a PathScurry performs a synchronous walk.
1731     *
1732     * Alias for {@link PathScurryBase.iterateSync}
1733     */
1734    [Symbol.iterator]() {
1735        return this.iterateSync();
1736    }
1737    *iterateSync(entry = this.cwd, opts = {}) {
1738        if (typeof entry === 'string') {
1739            entry = this.cwd.resolve(entry);
1740        }
1741        else if (!(entry instanceof PathBase)) {
1742            opts = entry;
1743            entry = this.cwd;
1744        }
1745        const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
1746        if (!filter || filter(entry)) {
1747            yield withFileTypes ? entry : entry.fullpath();
1748        }
1749        const dirs = new Set([entry]);
1750        for (const dir of dirs) {
1751            const entries = dir.readdirSync();
1752            for (const e of entries) {
1753                if (!filter || filter(e)) {
1754                    yield withFileTypes ? e : e.fullpath();
1755                }
1756                let r = e;
1757                if (e.isSymbolicLink()) {
1758                    if (!(follow && (r = e.realpathSync())))
1759                        continue;
1760                    if (r.isUnknown())
1761                        r.lstatSync();
1762                }
1763                if (r.shouldWalk(dirs, walkFilter)) {
1764                    dirs.add(r);
1765                }
1766            }
1767        }
1768    }
1769    stream(entry = this.cwd, opts = {}) {
1770        if (typeof entry === 'string') {
1771            entry = this.cwd.resolve(entry);
1772        }
1773        else if (!(entry instanceof PathBase)) {
1774            opts = entry;
1775            entry = this.cwd;
1776        }
1777        const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
1778        const results = new minipass_1.Minipass({ objectMode: true });
1779        if (!filter || filter(entry)) {
1780            results.write(withFileTypes ? entry : entry.fullpath());
1781        }
1782        const dirs = new Set();
1783        const queue = [entry];
1784        let processing = 0;
1785        const process = () => {
1786            let paused = false;
1787            while (!paused) {
1788                const dir = queue.shift();
1789                if (!dir) {
1790                    if (processing === 0)
1791                        results.end();
1792                    return;
1793                }
1794                processing++;
1795                dirs.add(dir);
1796                const onReaddir = (er, entries, didRealpaths = false) => {
1797                    /* c8 ignore start */
1798                    if (er)
1799                        return results.emit('error', er);
1800                    /* c8 ignore stop */
1801                    if (follow && !didRealpaths) {
1802                        const promises = [];
1803                        for (const e of entries) {
1804                            if (e.isSymbolicLink()) {
1805                                promises.push(e
1806                                    .realpath()
1807                                    .then((r) => r?.isUnknown() ? r.lstat() : r));
1808                            }
1809                        }
1810                        if (promises.length) {
1811                            Promise.all(promises).then(() => onReaddir(null, entries, true));
1812                            return;
1813                        }
1814                    }
1815                    for (const e of entries) {
1816                        if (e && (!filter || filter(e))) {
1817                            if (!results.write(withFileTypes ? e : e.fullpath())) {
1818                                paused = true;
1819                            }
1820                        }
1821                    }
1822                    processing--;
1823                    for (const e of entries) {
1824                        const r = e.realpathCached() || e;
1825                        if (r.shouldWalk(dirs, walkFilter)) {
1826                            queue.push(r);
1827                        }
1828                    }
1829                    if (paused && !results.flowing) {
1830                        results.once('drain', process);
1831                    }
1832                    else if (!sync) {
1833                        process();
1834                    }
1835                };
1836                // zalgo containment
1837                let sync = true;
1838                dir.readdirCB(onReaddir, true);
1839                sync = false;
1840            }
1841        };
1842        process();
1843        return results;
1844    }
1845    streamSync(entry = this.cwd, opts = {}) {
1846        if (typeof entry === 'string') {
1847            entry = this.cwd.resolve(entry);
1848        }
1849        else if (!(entry instanceof PathBase)) {
1850            opts = entry;
1851            entry = this.cwd;
1852        }
1853        const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
1854        const results = new minipass_1.Minipass({ objectMode: true });
1855        const dirs = new Set();
1856        if (!filter || filter(entry)) {
1857            results.write(withFileTypes ? entry : entry.fullpath());
1858        }
1859        const queue = [entry];
1860        let processing = 0;
1861        const process = () => {
1862            let paused = false;
1863            while (!paused) {
1864                const dir = queue.shift();
1865                if (!dir) {
1866                    if (processing === 0)
1867                        results.end();
1868                    return;
1869                }
1870                processing++;
1871                dirs.add(dir);
1872                const entries = dir.readdirSync();
1873                for (const e of entries) {
1874                    if (!filter || filter(e)) {
1875                        if (!results.write(withFileTypes ? e : e.fullpath())) {
1876                            paused = true;
1877                        }
1878                    }
1879                }
1880                processing--;
1881                for (const e of entries) {
1882                    let r = e;
1883                    if (e.isSymbolicLink()) {
1884                        if (!(follow && (r = e.realpathSync())))
1885                            continue;
1886                        if (r.isUnknown())
1887                            r.lstatSync();
1888                    }
1889                    if (r.shouldWalk(dirs, walkFilter)) {
1890                        queue.push(r);
1891                    }
1892                }
1893            }
1894            if (paused && !results.flowing)
1895                results.once('drain', process);
1896        };
1897        process();
1898        return results;
1899    }
1900    chdir(path = this.cwd) {
1901        const oldCwd = this.cwd;
1902        this.cwd = typeof path === 'string' ? this.cwd.resolve(path) : path;
1903        this.cwd[setAsCwd](oldCwd);
1904    }
1905}
1906exports.PathScurryBase = PathScurryBase;
1907/**
1908 * Windows implementation of {@link PathScurryBase}
1909 *
1910 * Defaults to case insensitve, uses `'\\'` to generate path strings.  Uses
1911 * {@link PathWin32} for Path objects.
1912 */
1913class PathScurryWin32 extends PathScurryBase {
1914    /**
1915     * separator for generating path strings
1916     */
1917    sep = '\\';
1918    constructor(cwd = process.cwd(), opts = {}) {
1919        const { nocase = true } = opts;
1920        super(cwd, path_1.win32, '\\', { ...opts, nocase });
1921        this.nocase = nocase;
1922        for (let p = this.cwd; p; p = p.parent) {
1923            p.nocase = this.nocase;
1924        }
1925    }
1926    /**
1927     * @internal
1928     */
1929    parseRootPath(dir) {
1930        // if the path starts with a single separator, it's not a UNC, and we'll
1931        // just get separator as the root, and driveFromUNC will return \
1932        // In that case, mount \ on the root from the cwd.
1933        return path_1.win32.parse(dir).root.toUpperCase();
1934    }
1935    /**
1936     * @internal
1937     */
1938    newRoot(fs) {
1939        return new PathWin32(this.rootPath, IFDIR, undefined, this.roots, this.nocase, this.childrenCache(), { fs });
1940    }
1941    /**
1942     * Return true if the provided path string is an absolute path
1943     */
1944    isAbsolute(p) {
1945        return (p.startsWith('/') || p.startsWith('\\') || /^[a-z]:(\/|\\)/i.test(p));
1946    }
1947}
1948exports.PathScurryWin32 = PathScurryWin32;
1949/**
1950 * {@link PathScurryBase} implementation for all posix systems other than Darwin.
1951 *
1952 * Defaults to case-sensitive matching, uses `'/'` to generate path strings.
1953 *
1954 * Uses {@link PathPosix} for Path objects.
1955 */
1956class PathScurryPosix extends PathScurryBase {
1957    /**
1958     * separator for generating path strings
1959     */
1960    sep = '/';
1961    constructor(cwd = process.cwd(), opts = {}) {
1962        const { nocase = false } = opts;
1963        super(cwd, path_1.posix, '/', { ...opts, nocase });
1964        this.nocase = nocase;
1965    }
1966    /**
1967     * @internal
1968     */
1969    parseRootPath(_dir) {
1970        return '/';
1971    }
1972    /**
1973     * @internal
1974     */
1975    newRoot(fs) {
1976        return new PathPosix(this.rootPath, IFDIR, undefined, this.roots, this.nocase, this.childrenCache(), { fs });
1977    }
1978    /**
1979     * Return true if the provided path string is an absolute path
1980     */
1981    isAbsolute(p) {
1982        return p.startsWith('/');
1983    }
1984}
1985exports.PathScurryPosix = PathScurryPosix;
1986/**
1987 * {@link PathScurryBase} implementation for Darwin (macOS) systems.
1988 *
1989 * Defaults to case-insensitive matching, uses `'/'` for generating path
1990 * strings.
1991 *
1992 * Uses {@link PathPosix} for Path objects.
1993 */
1994class PathScurryDarwin extends PathScurryPosix {
1995    constructor(cwd = process.cwd(), opts = {}) {
1996        const { nocase = true } = opts;
1997        super(cwd, { ...opts, nocase });
1998    }
1999}
2000exports.PathScurryDarwin = PathScurryDarwin;
2001/**
2002 * Default {@link PathBase} implementation for the current platform.
2003 *
2004 * {@link PathWin32} on Windows systems, {@link PathPosix} on all others.
2005 */
2006exports.Path = process.platform === 'win32' ? PathWin32 : PathPosix;
2007/**
2008 * Default {@link PathScurryBase} implementation for the current platform.
2009 *
2010 * {@link PathScurryWin32} on Windows systems, {@link PathScurryDarwin} on
2011 * Darwin (macOS) systems, {@link PathScurryPosix} on all others.
2012 */
2013exports.PathScurry = process.platform === 'win32'
2014    ? PathScurryWin32
2015    : process.platform === 'darwin'
2016        ? PathScurryDarwin
2017        : PathScurryPosix;
2018//# sourceMappingURL=index.js.map