vlt
Version:
The vlt CLI
1,793 lines (1,789 loc) • 80.5 kB
JavaScript
var global = globalThis;
import {Buffer} from "node:buffer";
import {setTimeout,clearTimeout,setImmediate,clearImmediate,setInterval,clearInterval} from "node:timers";
import {createRequire as _vlt_createRequire} from "node:module";
var require = _vlt_createRequire(import.meta.filename);
import {
LRUCache
} from "./chunk-3HSZY4YW.js";
import {
GLOBSTAR,
Minimatch,
Minipass,
escape,
unescape
} from "./chunk-6YRWYWZQ.js";
// ../../node_modules/.pnpm/path-scurry@2.0.0/node_modules/path-scurry/dist/esm/index.js
import { posix, win32 } from "node:path";
import { fileURLToPath } from "node:url";
import { lstatSync, readdir as readdirCB, readdirSync, readlinkSync, realpathSync as rps } from "node:fs";
import * as actualFS from "node:fs";
import { lstat, readdir, readlink, realpath } from "node:fs/promises";
var realpathSync = rps.native;
var defaultFS = {
lstatSync,
readdir: readdirCB,
readdirSync,
readlinkSync,
realpathSync,
promises: {
lstat,
readdir,
readlink,
realpath
}
};
var fsFromOption = (fsOption) => !fsOption || fsOption === defaultFS || fsOption === actualFS ? defaultFS : {
...defaultFS,
...fsOption,
promises: {
...defaultFS.promises,
...fsOption.promises || {}
}
};
var uncDriveRegexp = /^\\\\\?\\([a-z]:)\\?$/i;
var uncToDrive = (rootPath) => rootPath.replace(/\//g, "\\").replace(uncDriveRegexp, "$1\\");
var eitherSep = /[\\\/]/;
var UNKNOWN = 0;
var IFIFO = 1;
var IFCHR = 2;
var IFDIR = 4;
var IFBLK = 6;
var IFREG = 8;
var IFLNK = 10;
var IFSOCK = 12;
var IFMT = 15;
var IFMT_UNKNOWN = ~IFMT;
var READDIR_CALLED = 16;
var LSTAT_CALLED = 32;
var ENOTDIR = 64;
var ENOENT = 128;
var ENOREADLINK = 256;
var ENOREALPATH = 512;
var ENOCHILD = ENOTDIR | ENOENT | ENOREALPATH;
var TYPEMASK = 1023;
var entToType = (s) => s.isFile() ? IFREG : s.isDirectory() ? IFDIR : s.isSymbolicLink() ? IFLNK : s.isCharacterDevice() ? IFCHR : s.isBlockDevice() ? IFBLK : s.isSocket() ? IFSOCK : s.isFIFO() ? IFIFO : UNKNOWN;
var normalizeCache = /* @__PURE__ */ new Map();
var normalize = (s) => {
const c = normalizeCache.get(s);
if (c)
return c;
const n = s.normalize("NFKD");
normalizeCache.set(s, n);
return n;
};
var normalizeNocaseCache = /* @__PURE__ */ new Map();
var normalizeNocase = (s) => {
const c = normalizeNocaseCache.get(s);
if (c)
return c;
const n = normalize(s.toLowerCase());
normalizeNocaseCache.set(s, n);
return n;
};
var ResolveCache = class extends LRUCache {
constructor() {
super({ max: 256 });
}
};
var ChildrenCache = class extends LRUCache {
constructor(maxSize = 16 * 1024) {
super({
maxSize,
// parent + children
sizeCalculation: (a) => a.length + 1
});
}
};
var setAsCwd = Symbol("PathScurry setAsCwd");
var PathBase = class {
/**
* the basename of this path
*
* **Important**: *always* test the path name against any test string
* usingthe {@link isNamed} method, and not by directly comparing this
* string. Otherwise, unicode path strings that the system sees as identical
* will not be properly treated as the same path, leading to incorrect
* behavior and possible security issues.
*/
name;
/**
* the Path entry corresponding to the path root.
*
* @internal
*/
root;
/**
* All roots found within the current PathScurry family
*
* @internal
*/
roots;
/**
* a reference to the parent path, or undefined in the case of root entries
*
* @internal
*/
parent;
/**
* boolean indicating whether paths are compared case-insensitively
* @internal
*/
nocase;
/**
* boolean indicating that this path is the current working directory
* of the PathScurry collection that contains it.
*/
isCWD = false;
// potential default fs override
#fs;
// Stats fields
#dev;
get dev() {
return this.#dev;
}
#mode;
get mode() {
return this.#mode;
}
#nlink;
get nlink() {
return this.#nlink;
}
#uid;
get uid() {
return this.#uid;
}
#gid;
get gid() {
return this.#gid;
}
#rdev;
get rdev() {
return this.#rdev;
}
#blksize;
get blksize() {
return this.#blksize;
}
#ino;
get ino() {
return this.#ino;
}
#size;
get size() {
return this.#size;
}
#blocks;
get blocks() {
return this.#blocks;
}
#atimeMs;
get atimeMs() {
return this.#atimeMs;
}
#mtimeMs;
get mtimeMs() {
return this.#mtimeMs;
}
#ctimeMs;
get ctimeMs() {
return this.#ctimeMs;
}
#birthtimeMs;
get birthtimeMs() {
return this.#birthtimeMs;
}
#atime;
get atime() {
return this.#atime;
}
#mtime;
get mtime() {
return this.#mtime;
}
#ctime;
get ctime() {
return this.#ctime;
}
#birthtime;
get birthtime() {
return this.#birthtime;
}
#matchName;
#depth;
#fullpath;
#fullpathPosix;
#relative;
#relativePosix;
#type;
#children;
#linkTarget;
#realpath;
/**
* This property is for compatibility with the Dirent class as of
* Node v20, where Dirent['parentPath'] refers to the path of the
* directory that was passed to readdir. For root entries, it's the path
* to the entry itself.
*/
get parentPath() {
return (this.parent || this).fullpath();
}
/**
* Deprecated alias for Dirent['parentPath'] Somewhat counterintuitively,
* this property refers to the *parent* path, not the path object itself.
*
* @deprecated
*/
get path() {
return this.parentPath;
}
/**
* Do not create new Path objects directly. They should always be accessed
* via the PathScurry class or other methods on the Path class.
*
* @internal
*/
constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
this.name = name;
this.#matchName = nocase ? normalizeNocase(name) : normalize(name);
this.#type = type & TYPEMASK;
this.nocase = nocase;
this.roots = roots;
this.root = root || this;
this.#children = children;
this.#fullpath = opts.fullpath;
this.#relative = opts.relative;
this.#relativePosix = opts.relativePosix;
this.parent = opts.parent;
if (this.parent) {
this.#fs = this.parent.#fs;
} else {
this.#fs = fsFromOption(opts.fs);
}
}
/**
* Returns the depth of the Path object from its root.
*
* For example, a path at `/foo/bar` would have a depth of 2.
*/
depth() {
if (this.#depth !== void 0)
return this.#depth;
if (!this.parent)
return this.#depth = 0;
return this.#depth = this.parent.depth() + 1;
}
/**
* @internal
*/
childrenCache() {
return this.#children;
}
/**
* Get the Path object referenced by the string path, resolved from this Path
*/
resolve(path) {
if (!path) {
return this;
}
const rootPath = this.getRootString(path);
const dir = path.substring(rootPath.length);
const dirParts = dir.split(this.splitSep);
const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
return result;
}
#resolveParts(dirParts) {
let p = this;
for (const part of dirParts) {
p = p.child(part);
}
return p;
}
/**
* Returns the cached children Path objects, if still available. If they
* have fallen out of the cache, then returns an empty array, and resets the
* READDIR_CALLED bit, so that future calls to readdir() will require an fs
* lookup.
*
* @internal
*/
children() {
const cached = this.#children.get(this);
if (cached) {
return cached;
}
const children = Object.assign([], { provisional: 0 });
this.#children.set(this, children);
this.#type &= ~READDIR_CALLED;
return children;
}
/**
* Resolves a path portion and returns or creates the child Path.
*
* Returns `this` if pathPart is `''` or `'.'`, or `parent` if pathPart is
* `'..'`.
*
* This should not be called directly. If `pathPart` contains any path
* separators, it will lead to unsafe undefined behavior.
*
* Use `Path.resolve()` instead.
*
* @internal
*/
child(pathPart, opts) {
if (pathPart === "" || pathPart === ".") {
return this;
}
if (pathPart === "..") {
return this.parent || this;
}
const children = this.children();
const name = this.nocase ? normalizeNocase(pathPart) : normalize(pathPart);
for (const p of children) {
if (p.#matchName === name) {
return p;
}
}
const s = this.parent ? this.sep : "";
const fullpath = this.#fullpath ? this.#fullpath + s + pathPart : void 0;
const pchild = this.newChild(pathPart, UNKNOWN, {
...opts,
parent: this,
fullpath
});
if (!this.canReaddir()) {
pchild.#type |= ENOENT;
}
children.push(pchild);
return pchild;
}
/**
* The relative path from the cwd. If it does not share an ancestor with
* the cwd, then this ends up being equivalent to the fullpath()
*/
relative() {
if (this.isCWD)
return "";
if (this.#relative !== void 0) {
return this.#relative;
}
const name = this.name;
const p = this.parent;
if (!p) {
return this.#relative = this.name;
}
const pv = p.relative();
return pv + (!pv || !p.parent ? "" : this.sep) + name;
}
/**
* The relative path from the cwd, using / as the path separator.
* If it does not share an ancestor with
* the cwd, then this ends up being equivalent to the fullpathPosix()
* On posix systems, this is identical to relative().
*/
relativePosix() {
if (this.sep === "/")
return this.relative();
if (this.isCWD)
return "";
if (this.#relativePosix !== void 0)
return this.#relativePosix;
const name = this.name;
const p = this.parent;
if (!p) {
return this.#relativePosix = this.fullpathPosix();
}
const pv = p.relativePosix();
return pv + (!pv || !p.parent ? "" : "/") + name;
}
/**
* The fully resolved path string for this Path entry
*/
fullpath() {
if (this.#fullpath !== void 0) {
return this.#fullpath;
}
const name = this.name;
const p = this.parent;
if (!p) {
return this.#fullpath = this.name;
}
const pv = p.fullpath();
const fp = pv + (!p.parent ? "" : this.sep) + name;
return this.#fullpath = fp;
}
/**
* On platforms other than windows, this is identical to fullpath.
*
* On windows, this is overridden to return the forward-slash form of the
* full UNC path.
*/
fullpathPosix() {
if (this.#fullpathPosix !== void 0)
return this.#fullpathPosix;
if (this.sep === "/")
return this.#fullpathPosix = this.fullpath();
if (!this.parent) {
const p2 = this.fullpath().replace(/\\/g, "/");
if (/^[a-z]:\//i.test(p2)) {
return this.#fullpathPosix = `//?/${p2}`;
} else {
return this.#fullpathPosix = p2;
}
}
const p = this.parent;
const pfpp = p.fullpathPosix();
const fpp = pfpp + (!pfpp || !p.parent ? "" : "/") + this.name;
return this.#fullpathPosix = fpp;
}
/**
* Is the Path of an unknown type?
*
* Note that we might know *something* about it if there has been a previous
* filesystem operation, for example that it does not exist, or is not a
* link, or whether it has child entries.
*/
isUnknown() {
return (this.#type & IFMT) === UNKNOWN;
}
isType(type) {
return this[`is${type}`]();
}
getType() {
return this.isUnknown() ? "Unknown" : this.isDirectory() ? "Directory" : this.isFile() ? "File" : this.isSymbolicLink() ? "SymbolicLink" : this.isFIFO() ? "FIFO" : this.isCharacterDevice() ? "CharacterDevice" : this.isBlockDevice() ? "BlockDevice" : (
/* c8 ignore start */
this.isSocket() ? "Socket" : "Unknown"
);
}
/**
* Is the Path a regular file?
*/
isFile() {
return (this.#type & IFMT) === IFREG;
}
/**
* Is the Path a directory?
*/
isDirectory() {
return (this.#type & IFMT) === IFDIR;
}
/**
* Is the path a character device?
*/
isCharacterDevice() {
return (this.#type & IFMT) === IFCHR;
}
/**
* Is the path a block device?
*/
isBlockDevice() {
return (this.#type & IFMT) === IFBLK;
}
/**
* Is the path a FIFO pipe?
*/
isFIFO() {
return (this.#type & IFMT) === IFIFO;
}
/**
* Is the path a socket?
*/
isSocket() {
return (this.#type & IFMT) === IFSOCK;
}
/**
* Is the path a symbolic link?
*/
isSymbolicLink() {
return (this.#type & IFLNK) === IFLNK;
}
/**
* Return the entry if it has been subject of a successful lstat, or
* undefined otherwise.
*
* Does not read the filesystem, so an undefined result *could* simply
* mean that we haven't called lstat on it.
*/
lstatCached() {
return this.#type & LSTAT_CALLED ? this : void 0;
}
/**
* Return the cached link target if the entry has been the subject of a
* successful readlink, or undefined otherwise.
*
* Does not read the filesystem, so an undefined result *could* just mean we
* don't have any cached data. Only use it if you are very sure that a
* readlink() has been called at some point.
*/
readlinkCached() {
return this.#linkTarget;
}
/**
* Returns the cached realpath target if the entry has been the subject
* of a successful realpath, or undefined otherwise.
*
* Does not read the filesystem, so an undefined result *could* just mean we
* don't have any cached data. Only use it if you are very sure that a
* realpath() has been called at some point.
*/
realpathCached() {
return this.#realpath;
}
/**
* Returns the cached child Path entries array if the entry has been the
* subject of a successful readdir(), or [] otherwise.
*
* Does not read the filesystem, so an empty array *could* just mean we
* don't have any cached data. Only use it if you are very sure that a
* readdir() has been called recently enough to still be valid.
*/
readdirCached() {
const children = this.children();
return children.slice(0, children.provisional);
}
/**
* Return true if it's worth trying to readlink. Ie, we don't (yet) have
* any indication that readlink will definitely fail.
*
* Returns false if the path is known to not be a symlink, if a previous
* readlink failed, or if the entry does not exist.
*/
canReadlink() {
if (this.#linkTarget)
return true;
if (!this.parent)
return false;
const ifmt = this.#type & IFMT;
return !(ifmt !== UNKNOWN && ifmt !== IFLNK || this.#type & ENOREADLINK || this.#type & ENOENT);
}
/**
* Return true if readdir has previously been successfully called on this
* path, indicating that cachedReaddir() is likely valid.
*/
calledReaddir() {
return !!(this.#type & READDIR_CALLED);
}
/**
* Returns true if the path is known to not exist. That is, a previous lstat
* or readdir failed to verify its existence when that would have been
* expected, or a parent entry was marked either enoent or enotdir.
*/
isENOENT() {
return !!(this.#type & ENOENT);
}
/**
* Return true if the path is a match for the given path name. This handles
* case sensitivity and unicode normalization.
*
* Note: even on case-sensitive systems, it is **not** safe to test the
* equality of the `.name` property to determine whether a given pathname
* matches, due to unicode normalization mismatches.
*
* Always use this method instead of testing the `path.name` property
* directly.
*/
isNamed(n) {
return !this.nocase ? this.#matchName === normalize(n) : this.#matchName === normalizeNocase(n);
}
/**
* Return the Path object corresponding to the target of a symbolic link.
*
* If the Path is not a symbolic link, or if the readlink call fails for any
* reason, `undefined` is returned.
*
* Result is cached, and thus may be outdated if the filesystem is mutated.
*/
async readlink() {
const target = this.#linkTarget;
if (target) {
return target;
}
if (!this.canReadlink()) {
return void 0;
}
if (!this.parent) {
return void 0;
}
try {
const read = await this.#fs.promises.readlink(this.fullpath());
const linkTarget = (await this.parent.realpath())?.resolve(read);
if (linkTarget) {
return this.#linkTarget = linkTarget;
}
} catch (er) {
this.#readlinkFail(er.code);
return void 0;
}
}
/**
* Synchronous {@link PathBase.readlink}
*/
readlinkSync() {
const target = this.#linkTarget;
if (target) {
return target;
}
if (!this.canReadlink()) {
return void 0;
}
if (!this.parent) {
return void 0;
}
try {
const read = this.#fs.readlinkSync(this.fullpath());
const linkTarget = this.parent.realpathSync()?.resolve(read);
if (linkTarget) {
return this.#linkTarget = linkTarget;
}
} catch (er) {
this.#readlinkFail(er.code);
return void 0;
}
}
#readdirSuccess(children) {
this.#type |= READDIR_CALLED;
for (let p = children.provisional; p < children.length; p++) {
const c = children[p];
if (c)
c.#markENOENT();
}
}
#markENOENT() {
if (this.#type & ENOENT)
return;
this.#type = (this.#type | ENOENT) & IFMT_UNKNOWN;
this.#markChildrenENOENT();
}
#markChildrenENOENT() {
const children = this.children();
children.provisional = 0;
for (const p of children) {
p.#markENOENT();
}
}
#markENOREALPATH() {
this.#type |= ENOREALPATH;
this.#markENOTDIR();
}
// save the information when we know the entry is not a dir
#markENOTDIR() {
if (this.#type & ENOTDIR)
return;
let t = this.#type;
if ((t & IFMT) === IFDIR)
t &= IFMT_UNKNOWN;
this.#type = t | ENOTDIR;
this.#markChildrenENOENT();
}
#readdirFail(code = "") {
if (code === "ENOTDIR" || code === "EPERM") {
this.#markENOTDIR();
} else if (code === "ENOENT") {
this.#markENOENT();
} else {
this.children().provisional = 0;
}
}
#lstatFail(code = "") {
if (code === "ENOTDIR") {
const p = this.parent;
p.#markENOTDIR();
} else if (code === "ENOENT") {
this.#markENOENT();
}
}
#readlinkFail(code = "") {
let ter = this.#type;
ter |= ENOREADLINK;
if (code === "ENOENT")
ter |= ENOENT;
if (code === "EINVAL" || code === "UNKNOWN") {
ter &= IFMT_UNKNOWN;
}
this.#type = ter;
if (code === "ENOTDIR" && this.parent) {
this.parent.#markENOTDIR();
}
}
#readdirAddChild(e, c) {
return this.#readdirMaybePromoteChild(e, c) || this.#readdirAddNewChild(e, c);
}
#readdirAddNewChild(e, c) {
const type = entToType(e);
const child = this.newChild(e.name, type, { parent: this });
const ifmt = child.#type & IFMT;
if (ifmt !== IFDIR && ifmt !== IFLNK && ifmt !== UNKNOWN) {
child.#type |= ENOTDIR;
}
c.unshift(child);
c.provisional++;
return child;
}
#readdirMaybePromoteChild(e, c) {
for (let p = c.provisional; p < c.length; p++) {
const pchild = c[p];
const name = this.nocase ? normalizeNocase(e.name) : normalize(e.name);
if (name !== pchild.#matchName) {
continue;
}
return this.#readdirPromoteChild(e, pchild, p, c);
}
}
#readdirPromoteChild(e, p, index, c) {
const v = p.name;
p.#type = p.#type & IFMT_UNKNOWN | entToType(e);
if (v !== e.name)
p.name = e.name;
if (index !== c.provisional) {
if (index === c.length - 1)
c.pop();
else
c.splice(index, 1);
c.unshift(p);
}
c.provisional++;
return p;
}
/**
* Call lstat() on this Path, and update all known information that can be
* determined.
*
* Note that unlike `fs.lstat()`, the returned value does not contain some
* information, such as `mode`, `dev`, `nlink`, and `ino`. If that
* information is required, you will need to call `fs.lstat` yourself.
*
* If the Path refers to a nonexistent file, or if the lstat call fails for
* any reason, `undefined` is returned. Otherwise the updated Path object is
* returned.
*
* Results are cached, and thus may be out of date if the filesystem is
* mutated.
*/
async lstat() {
if ((this.#type & ENOENT) === 0) {
try {
this.#applyStat(await this.#fs.promises.lstat(this.fullpath()));
return this;
} catch (er) {
this.#lstatFail(er.code);
}
}
}
/**
* synchronous {@link PathBase.lstat}
*/
lstatSync() {
if ((this.#type & ENOENT) === 0) {
try {
this.#applyStat(this.#fs.lstatSync(this.fullpath()));
return this;
} catch (er) {
this.#lstatFail(er.code);
}
}
}
#applyStat(st) {
const { atime, atimeMs, birthtime, birthtimeMs, blksize, blocks, ctime, ctimeMs, dev, gid, ino, mode, mtime, mtimeMs, nlink, rdev, size, uid } = st;
this.#atime = atime;
this.#atimeMs = atimeMs;
this.#birthtime = birthtime;
this.#birthtimeMs = birthtimeMs;
this.#blksize = blksize;
this.#blocks = blocks;
this.#ctime = ctime;
this.#ctimeMs = ctimeMs;
this.#dev = dev;
this.#gid = gid;
this.#ino = ino;
this.#mode = mode;
this.#mtime = mtime;
this.#mtimeMs = mtimeMs;
this.#nlink = nlink;
this.#rdev = rdev;
this.#size = size;
this.#uid = uid;
const ifmt = entToType(st);
this.#type = this.#type & IFMT_UNKNOWN | ifmt | LSTAT_CALLED;
if (ifmt !== UNKNOWN && ifmt !== IFDIR && ifmt !== IFLNK) {
this.#type |= ENOTDIR;
}
}
#onReaddirCB = [];
#readdirCBInFlight = false;
#callOnReaddirCB(children) {
this.#readdirCBInFlight = false;
const cbs = this.#onReaddirCB.slice();
this.#onReaddirCB.length = 0;
cbs.forEach((cb) => cb(null, children));
}
/**
* Standard node-style callback interface to get list of directory entries.
*
* If the Path cannot or does not contain any children, then an empty array
* is returned.
*
* Results are cached, and thus may be out of date if the filesystem is
* mutated.
*
* @param cb The callback called with (er, entries). Note that the `er`
* param is somewhat extraneous, as all readdir() errors are handled and
* simply result in an empty set of entries being returned.
* @param allowZalgo Boolean indicating that immediately known results should
* *not* be deferred with `queueMicrotask`. Defaults to `false`. Release
* zalgo at your peril, the dark pony lord is devious and unforgiving.
*/
readdirCB(cb, allowZalgo = false) {
if (!this.canReaddir()) {
if (allowZalgo)
cb(null, []);
else
queueMicrotask(() => cb(null, []));
return;
}
const children = this.children();
if (this.calledReaddir()) {
const c = children.slice(0, children.provisional);
if (allowZalgo)
cb(null, c);
else
queueMicrotask(() => cb(null, c));
return;
}
this.#onReaddirCB.push(cb);
if (this.#readdirCBInFlight) {
return;
}
this.#readdirCBInFlight = true;
const fullpath = this.fullpath();
this.#fs.readdir(fullpath, { withFileTypes: true }, (er, entries) => {
if (er) {
this.#readdirFail(er.code);
children.provisional = 0;
} else {
for (const e of entries) {
this.#readdirAddChild(e, children);
}
this.#readdirSuccess(children);
}
this.#callOnReaddirCB(children.slice(0, children.provisional));
return;
});
}
#asyncReaddirInFlight;
/**
* Return an array of known child entries.
*
* If the Path cannot or does not contain any children, then an empty array
* is returned.
*
* Results are cached, and thus may be out of date if the filesystem is
* mutated.
*/
async readdir() {
if (!this.canReaddir()) {
return [];
}
const children = this.children();
if (this.calledReaddir()) {
return children.slice(0, children.provisional);
}
const fullpath = this.fullpath();
if (this.#asyncReaddirInFlight) {
await this.#asyncReaddirInFlight;
} else {
let resolve = () => {
};
this.#asyncReaddirInFlight = new Promise((res) => resolve = res);
try {
for (const e of await this.#fs.promises.readdir(fullpath, {
withFileTypes: true
})) {
this.#readdirAddChild(e, children);
}
this.#readdirSuccess(children);
} catch (er) {
this.#readdirFail(er.code);
children.provisional = 0;
}
this.#asyncReaddirInFlight = void 0;
resolve();
}
return children.slice(0, children.provisional);
}
/**
* synchronous {@link PathBase.readdir}
*/
readdirSync() {
if (!this.canReaddir()) {
return [];
}
const children = this.children();
if (this.calledReaddir()) {
return children.slice(0, children.provisional);
}
const fullpath = this.fullpath();
try {
for (const e of this.#fs.readdirSync(fullpath, {
withFileTypes: true
})) {
this.#readdirAddChild(e, children);
}
this.#readdirSuccess(children);
} catch (er) {
this.#readdirFail(er.code);
children.provisional = 0;
}
return children.slice(0, children.provisional);
}
canReaddir() {
if (this.#type & ENOCHILD)
return false;
const ifmt = IFMT & this.#type;
if (!(ifmt === UNKNOWN || ifmt === IFDIR || ifmt === IFLNK)) {
return false;
}
return true;
}
shouldWalk(dirs, walkFilter) {
return (this.#type & IFDIR) === IFDIR && !(this.#type & ENOCHILD) && !dirs.has(this) && (!walkFilter || walkFilter(this));
}
/**
* Return the Path object corresponding to path as resolved
* by realpath(3).
*
* If the realpath call fails for any reason, `undefined` is returned.
*
* Result is cached, and thus may be outdated if the filesystem is mutated.
* On success, returns a Path object.
*/
async realpath() {
if (this.#realpath)
return this.#realpath;
if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type)
return void 0;
try {
const rp = await this.#fs.promises.realpath(this.fullpath());
return this.#realpath = this.resolve(rp);
} catch (_) {
this.#markENOREALPATH();
}
}
/**
* Synchronous {@link realpath}
*/
realpathSync() {
if (this.#realpath)
return this.#realpath;
if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type)
return void 0;
try {
const rp = this.#fs.realpathSync(this.fullpath());
return this.#realpath = this.resolve(rp);
} catch (_) {
this.#markENOREALPATH();
}
}
/**
* Internal method to mark this Path object as the scurry cwd,
* called by {@link PathScurry#chdir}
*
* @internal
*/
[setAsCwd](oldCwd) {
if (oldCwd === this)
return;
oldCwd.isCWD = false;
this.isCWD = true;
const changed = /* @__PURE__ */ new Set([]);
let rp = [];
let p = this;
while (p && p.parent) {
changed.add(p);
p.#relative = rp.join(this.sep);
p.#relativePosix = rp.join("/");
p = p.parent;
rp.push("..");
}
p = oldCwd;
while (p && p.parent && !changed.has(p)) {
p.#relative = void 0;
p.#relativePosix = void 0;
p = p.parent;
}
}
};
var PathWin32 = class _PathWin32 extends PathBase {
/**
* Separator for generating path strings.
*/
sep = "\\";
/**
* Separator for parsing path strings.
*/
splitSep = eitherSep;
/**
* Do not create new Path objects directly. They should always be accessed
* via the PathScurry class or other methods on the Path class.
*
* @internal
*/
constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
super(name, type, root, roots, nocase, children, opts);
}
/**
* @internal
*/
newChild(name, type = UNKNOWN, opts = {}) {
return new _PathWin32(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
}
/**
* @internal
*/
getRootString(path) {
return win32.parse(path).root;
}
/**
* @internal
*/
getRoot(rootPath) {
rootPath = uncToDrive(rootPath.toUpperCase());
if (rootPath === this.root.name) {
return this.root;
}
for (const [compare, root] of Object.entries(this.roots)) {
if (this.sameRoot(rootPath, compare)) {
return this.roots[rootPath] = root;
}
}
return this.roots[rootPath] = new PathScurryWin32(rootPath, this).root;
}
/**
* @internal
*/
sameRoot(rootPath, compare = this.root.name) {
rootPath = rootPath.toUpperCase().replace(/\//g, "\\").replace(uncDriveRegexp, "$1\\");
return rootPath === compare;
}
};
var PathPosix = class _PathPosix extends PathBase {
/**
* separator for parsing path strings
*/
splitSep = "/";
/**
* separator for generating path strings
*/
sep = "/";
/**
* Do not create new Path objects directly. They should always be accessed
* via the PathScurry class or other methods on the Path class.
*
* @internal
*/
constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
super(name, type, root, roots, nocase, children, opts);
}
/**
* @internal
*/
getRootString(path) {
return path.startsWith("/") ? "/" : "";
}
/**
* @internal
*/
getRoot(_rootPath) {
return this.root;
}
/**
* @internal
*/
newChild(name, type = UNKNOWN, opts = {}) {
return new _PathPosix(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
}
};
var PathScurryBase = class {
/**
* The root Path entry for the current working directory of this Scurry
*/
root;
/**
* The string path for the root of this Scurry's current working directory
*/
rootPath;
/**
* A collection of all roots encountered, referenced by rootPath
*/
roots;
/**
* The Path entry corresponding to this PathScurry's current working directory.
*/
cwd;
#resolveCache;
#resolvePosixCache;
#children;
/**
* Perform path comparisons case-insensitively.
*
* Defaults true on Darwin and Windows systems, false elsewhere.
*/
nocase;
#fs;
/**
* This class should not be instantiated directly.
*
* Use PathScurryWin32, PathScurryDarwin, PathScurryPosix, or PathScurry
*
* @internal
*/
constructor(cwd = process.cwd(), pathImpl, sep, { nocase, childrenCacheSize = 16 * 1024, fs = defaultFS } = {}) {
this.#fs = fsFromOption(fs);
if (cwd instanceof URL || cwd.startsWith("file://")) {
cwd = fileURLToPath(cwd);
}
const cwdPath = pathImpl.resolve(cwd);
this.roots = /* @__PURE__ */ Object.create(null);
this.rootPath = this.parseRootPath(cwdPath);
this.#resolveCache = new ResolveCache();
this.#resolvePosixCache = new ResolveCache();
this.#children = new ChildrenCache(childrenCacheSize);
const split = cwdPath.substring(this.rootPath.length).split(sep);
if (split.length === 1 && !split[0]) {
split.pop();
}
if (nocase === void 0) {
throw new TypeError("must provide nocase setting to PathScurryBase ctor");
}
this.nocase = nocase;
this.root = this.newRoot(this.#fs);
this.roots[this.rootPath] = this.root;
let prev = this.root;
let len = split.length - 1;
const joinSep = pathImpl.sep;
let abs = this.rootPath;
let sawFirst = false;
for (const part of split) {
const l = len--;
prev = prev.child(part, {
relative: new Array(l).fill("..").join(joinSep),
relativePosix: new Array(l).fill("..").join("/"),
fullpath: abs += (sawFirst ? "" : joinSep) + part
});
sawFirst = true;
}
this.cwd = prev;
}
/**
* Get the depth of a provided path, string, or the cwd
*/
depth(path = this.cwd) {
if (typeof path === "string") {
path = this.cwd.resolve(path);
}
return path.depth();
}
/**
* Return the cache of child entries. Exposed so subclasses can create
* child Path objects in a platform-specific way.
*
* @internal
*/
childrenCache() {
return this.#children;
}
/**
* Resolve one or more path strings to a resolved string
*
* Same interface as require('path').resolve.
*
* Much faster than path.resolve() when called multiple times for the same
* path, because the resolved Path objects are cached. Much slower
* otherwise.
*/
resolve(...paths) {
let r = "";
for (let i = paths.length - 1; i >= 0; i--) {
const p = paths[i];
if (!p || p === ".")
continue;
r = r ? `${p}/${r}` : p;
if (this.isAbsolute(p)) {
break;
}
}
const cached = this.#resolveCache.get(r);
if (cached !== void 0) {
return cached;
}
const result = this.cwd.resolve(r).fullpath();
this.#resolveCache.set(r, result);
return result;
}
/**
* Resolve one or more path strings to a resolved string, returning
* the posix path. Identical to .resolve() on posix systems, but on
* windows will return a forward-slash separated UNC path.
*
* Same interface as require('path').resolve.
*
* Much faster than path.resolve() when called multiple times for the same
* path, because the resolved Path objects are cached. Much slower
* otherwise.
*/
resolvePosix(...paths) {
let r = "";
for (let i = paths.length - 1; i >= 0; i--) {
const p = paths[i];
if (!p || p === ".")
continue;
r = r ? `${p}/${r}` : p;
if (this.isAbsolute(p)) {
break;
}
}
const cached = this.#resolvePosixCache.get(r);
if (cached !== void 0) {
return cached;
}
const result = this.cwd.resolve(r).fullpathPosix();
this.#resolvePosixCache.set(r, result);
return result;
}
/**
* find the relative path from the cwd to the supplied path string or entry
*/
relative(entry = this.cwd) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
}
return entry.relative();
}
/**
* find the relative path from the cwd to the supplied path string or
* entry, using / as the path delimiter, even on Windows.
*/
relativePosix(entry = this.cwd) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
}
return entry.relativePosix();
}
/**
* Return the basename for the provided string or Path object
*/
basename(entry = this.cwd) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
}
return entry.name;
}
/**
* Return the dirname for the provided string or Path object
*/
dirname(entry = this.cwd) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
}
return (entry.parent || entry).fullpath();
}
async readdir(entry = this.cwd, opts = {
withFileTypes: true
}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
opts = entry;
entry = this.cwd;
}
const { withFileTypes } = opts;
if (!entry.canReaddir()) {
return [];
} else {
const p = await entry.readdir();
return withFileTypes ? p : p.map((e) => e.name);
}
}
readdirSync(entry = this.cwd, opts = {
withFileTypes: true
}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
opts = entry;
entry = this.cwd;
}
const { withFileTypes = true } = opts;
if (!entry.canReaddir()) {
return [];
} else if (withFileTypes) {
return entry.readdirSync();
} else {
return entry.readdirSync().map((e) => e.name);
}
}
/**
* Call lstat() on the string or Path object, and update all known
* information that can be determined.
*
* Note that unlike `fs.lstat()`, the returned value does not contain some
* information, such as `mode`, `dev`, `nlink`, and `ino`. If that
* information is required, you will need to call `fs.lstat` yourself.
*
* If the Path refers to a nonexistent file, or if the lstat call fails for
* any reason, `undefined` is returned. Otherwise the updated Path object is
* returned.
*
* Results are cached, and thus may be out of date if the filesystem is
* mutated.
*/
async lstat(entry = this.cwd) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
}
return entry.lstat();
}
/**
* synchronous {@link PathScurryBase.lstat}
*/
lstatSync(entry = this.cwd) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
}
return entry.lstatSync();
}
async readlink(entry = this.cwd, { withFileTypes } = {
withFileTypes: false
}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
withFileTypes = entry.withFileTypes;
entry = this.cwd;
}
const e = await entry.readlink();
return withFileTypes ? e : e?.fullpath();
}
readlinkSync(entry = this.cwd, { withFileTypes } = {
withFileTypes: false
}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
withFileTypes = entry.withFileTypes;
entry = this.cwd;
}
const e = entry.readlinkSync();
return withFileTypes ? e : e?.fullpath();
}
async realpath(entry = this.cwd, { withFileTypes } = {
withFileTypes: false
}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
withFileTypes = entry.withFileTypes;
entry = this.cwd;
}
const e = await entry.realpath();
return withFileTypes ? e : e?.fullpath();
}
realpathSync(entry = this.cwd, { withFileTypes } = {
withFileTypes: false
}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
withFileTypes = entry.withFileTypes;
entry = this.cwd;
}
const e = entry.realpathSync();
return withFileTypes ? e : e?.fullpath();
}
async walk(entry = this.cwd, opts = {}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
opts = entry;
entry = this.cwd;
}
const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
const results = [];
if (!filter || filter(entry)) {
results.push(withFileTypes ? entry : entry.fullpath());
}
const dirs = /* @__PURE__ */ new Set();
const walk = (dir, cb) => {
dirs.add(dir);
dir.readdirCB((er, entries) => {
if (er) {
return cb(er);
}
let len = entries.length;
if (!len)
return cb();
const next = () => {
if (--len === 0) {
cb();
}
};
for (const e of entries) {
if (!filter || filter(e)) {
results.push(withFileTypes ? e : e.fullpath());
}
if (follow && e.isSymbolicLink()) {
e.realpath().then((r) => r?.isUnknown() ? r.lstat() : r).then((r) => r?.shouldWalk(dirs, walkFilter) ? walk(r, next) : next());
} else {
if (e.shouldWalk(dirs, walkFilter)) {
walk(e, next);
} else {
next();
}
}
}
}, true);
};
const start = entry;
return new Promise((res, rej) => {
walk(start, (er) => {
if (er)
return rej(er);
res(results);
});
});
}
walkSync(entry = this.cwd, opts = {}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
opts = entry;
entry = this.cwd;
}
const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
const results = [];
if (!filter || filter(entry)) {
results.push(withFileTypes ? entry : entry.fullpath());
}
const dirs = /* @__PURE__ */ new Set([entry]);
for (const dir of dirs) {
const entries = dir.readdirSync();
for (const e of entries) {
if (!filter || filter(e)) {
results.push(withFileTypes ? e : e.fullpath());
}
let r = e;
if (e.isSymbolicLink()) {
if (!(follow && (r = e.realpathSync())))
continue;
if (r.isUnknown())
r.lstatSync();
}
if (r.shouldWalk(dirs, walkFilter)) {
dirs.add(r);
}
}
}
return results;
}
/**
* Support for `for await`
*
* Alias for {@link PathScurryBase.iterate}
*
* Note: As of Node 19, this is very slow, compared to other methods of
* walking. Consider using {@link PathScurryBase.stream} if memory overhead
* and backpressure are concerns, or {@link PathScurryBase.walk} if not.
*/
[Symbol.asyncIterator]() {
return this.iterate();
}
iterate(entry = this.cwd, options = {}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
options = entry;
entry = this.cwd;
}
return this.stream(entry, options)[Symbol.asyncIterator]();
}
/**
* Iterating over a PathScurry performs a synchronous walk.
*
* Alias for {@link PathScurryBase.iterateSync}
*/
[Symbol.iterator]() {
return this.iterateSync();
}
*iterateSync(entry = this.cwd, opts = {}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
opts = entry;
entry = this.cwd;
}
const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
if (!filter || filter(entry)) {
yield withFileTypes ? entry : entry.fullpath();
}
const dirs = /* @__PURE__ */ new Set([entry]);
for (const dir of dirs) {
const entries = dir.readdirSync();
for (const e of entries) {
if (!filter || filter(e)) {
yield withFileTypes ? e : e.fullpath();
}
let r = e;
if (e.isSymbolicLink()) {
if (!(follow && (r = e.realpathSync())))
continue;
if (r.isUnknown())
r.lstatSync();
}
if (r.shouldWalk(dirs, walkFilter)) {
dirs.add(r);
}
}
}
}
stream(entry = this.cwd, opts = {}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
opts = entry;
entry = this.cwd;
}
const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
const results = new Minipass({ objectMode: true });
if (!filter || filter(entry)) {
results.write(withFileTypes ? entry : entry.fullpath());
}
const dirs = /* @__PURE__ */ new Set();
const queue = [entry];
let processing = 0;
const process2 = () => {
let paused = false;
while (!paused) {
const dir = queue.shift();
if (!dir) {
if (processing === 0)
results.end();
return;
}
processing++;
dirs.add(dir);
const onReaddir = (er, entries, didRealpaths = false) => {
if (er)
return results.emit("error", er);
if (follow && !didRealpaths) {
const promises = [];
for (const e of entries) {
if (e.isSymbolicLink()) {
promises.push(e.realpath().then((r) => r?.isUnknown() ? r.lstat() : r));
}
}
if (promises.length) {
Promise.all(promises).then(() => onReaddir(null, entries, true));
return;
}
}
for (const e of entries) {
if (e && (!filter || filter(e))) {
if (!results.write(withFileTypes ? e : e.fullpath())) {
paused = true;
}
}
}
processing--;
for (const e of entries) {
const r = e.realpathCached() || e;
if (r.shouldWalk(dirs, walkFilter)) {
queue.push(r);
}
}
if (paused && !results.flowing) {
results.once("drain", process2);
} else if (!sync2) {
process2();
}
};
let sync2 = true;
dir.readdirCB(onReaddir, true);
sync2 = false;
}
};
process2();
return results;
}
streamSync(entry = this.cwd, opts = {}) {
if (typeof entry === "string") {
entry = this.cwd.resolve(entry);
} else if (!(entry instanceof PathBase)) {
opts = entry;
entry = this.cwd;
}
const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
const results = new Minipass({ objectMode: true });
const dirs = /* @__PURE__ */ new Set();
if (!filter || filter(entry)) {
results.write(withFileTypes ? entry : entry.fullpath());
}
const queue = [entry];
let processing = 0;
const process2 = () => {
let paused = false;
while (!paused) {
const dir = queue.shift();
if (!dir) {
if (processing === 0)
results.end();
return;
}
processing++;
dirs.add(dir);
const entries = dir.readdirSync();
for (const e of entries) {
if (!filter || filter(e)) {
if (!results.write(withFileTypes ? e : e.fullpath())) {
paused = true;
}
}
}
processing--;
for (const e of entries) {
let r = e;
if (e.isSymbolicLink()) {
if (!(follow && (r = e.realpathSync())))
continue;
if (r.isUnknown())
r.lstatSync();
}
if (r.shouldWalk(dirs, walkFilter)) {
queue.push(r);
}
}
}
if (paused && !results.flowing)
results.once("drain", process2);
};
process2();
return results;
}
chdir(path = this.cwd) {
const oldCwd = this.cwd;
this.cwd = typeof path === "string" ? this.cwd.resolve(path) : path;
this.cwd[setAsCwd](oldCwd);
}
};
var PathScurryWin32 = class extends PathScurryBase {
/**
* separator for generating path strings
*/
sep = "\\";
constructor(cwd = process.cwd(), opts = {}) {
const { nocase = true } = opts;
super(cwd, win32, "\\", { ...opts, nocase });
this.nocase = nocase;
for (let p = this.cwd; p; p = p.parent) {
p.nocase = this.nocase;
}
}
/**
* @internal
*/
parseRootPath(dir) {
return win32.parse(dir).root.toUpperCase();
}
/**
* @internal
*/
newRoot(fs) {
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs });
}
/**
* Return true if the provided path string is an absolute path
*/
isAbsolute(p) {
return p.startsWith("/") || p.startsWith("\\") || /^[a-z]:(\/|\\)/i.test(p);
}
};
var PathScurryPosix = class extends PathScurryBase {
/**
* separator for generating path strings
*/
sep = "/";
constructor(cwd = process.cwd(), opts = {}) {
const { nocase = false } = opts;
super(cwd, posix, "/", { ...opts, nocase });
this.nocase = nocase;
}
/**
* @internal
*/
parseRootPath(_dir) {
return "/";
}
/**
* @internal
*/
newRoot(fs) {
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs });
}
/**
* Return true if the provided path string is an absolute path
*/
isAbsolute(p) {
return p.startsWith("/");
}
};
var PathScurryDarwin = class extends PathScurryPosix {
constructor(cwd = process.cwd(), opts = {}) {
const { nocase = true } = opts;
super(cwd, { ...opts, nocase });
}
};
var Path = process.platform === "win32" ? PathWin32 : PathPosix;
var PathScurry = process.platform === "win32" ? PathScurryWin32 : process.platform === "darwin" ? PathScurryDarwin : PathScurryPosix;
// ../../node_modules/.pnpm/glob@11.0.2/node_modules/glob/dist/esm/glob.js
import { fileURLToPath as fileURLToPath2 } from "node:url";
// ../../node_modules/.pnpm/glob@11.0.2/node_modules/glob/dist/esm/pattern.js
var isPatternList = (pl) => pl.length >= 1;
var isGlobList = (gl) => gl.length >= 1;
var Pattern = class _Pattern {
#patternList;
#globList;
#index;
length;
#platform;
#rest;
#globString;
#isDrive;
#isUNC;
#isAbsolute;
#followGlobstar = true;
constructor(patternList, globList, index, platform) {
if (!isPatternList(patternList)) {
throw new TypeError("empty pattern list");
}
if (!isGlobList(globList)) {
throw new TypeError("empty glob list");
}
if (globList.length !== patternList.length) {
throw new TypeError("mismatched pattern list and glob list lengths");
}
this.length = patternList.length;
if (index < 0 || index >= this.length) {
throw new TypeError("index out of range");
}
this.#patternList = patternList;
this.#globList = globList;
this.#index = index;
this.#platform = platform;
if (this.#index === 0) {
if (this.isUNC()) {
const [p0, p1, p2, p3, ...prest] = this.#patternList;
const [g0, g1, g2, g3, ...grest] = this.#globList;
if (prest[0] === "") {
prest.shift();
grest.shift();
}
const p = [p0, p1, p2, p3, ""].join("/");