//#region rolldown:runtime var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { key = keys[i]; if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: ((k) => from[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); //#endregion const path = __toESM(require("path")); const fs = __toESM(require("fs")); //#region src/utils.ts function cleanPath(path$1) { let normalized = (0, path.normalize)(path$1); if (normalized.length > 1 && normalized[normalized.length - 1] === path.sep) normalized = normalized.substring(0, normalized.length - 1); return normalized; } const SLASHES_REGEX = /[\\/]/g; function convertSlashes(path$1, separator) { return path$1.replace(SLASHES_REGEX, separator); } const WINDOWS_ROOT_DIR_REGEX = /^[a-z]:[\\/]$/i; function isRootDirectory(path$1) { return path$1 === "/" || WINDOWS_ROOT_DIR_REGEX.test(path$1); } function normalizePath(path$1, options) { const { resolvePaths, normalizePath: normalizePath$1, pathSeparator } = options; const pathNeedsCleaning = process.platform === "win32" && path$1.includes("/") || path$1.startsWith("."); if (resolvePaths) path$1 = (0, path.resolve)(path$1); if (normalizePath$1 || pathNeedsCleaning) path$1 = cleanPath(path$1); if (path$1 === ".") return ""; const needsSeperator = path$1[path$1.length - 1] !== pathSeparator; return convertSlashes(needsSeperator ? path$1 + pathSeparator : path$1, pathSeparator); } //#endregion //#region src/api/functions/join-path.ts function joinPathWithBasePath(filename, directoryPath) { return directoryPath + filename; } function joinPathWithRelativePath(root, options) { return function(filename, directoryPath) { const sameRoot = directoryPath.startsWith(root); if (sameRoot) return directoryPath.replace(root, "") + filename; else return convertSlashes((0, path.relative)(root, directoryPath), options.pathSeparator) + options.pathSeparator + filename; }; } function joinPath(filename) { return filename; } function joinDirectoryPath(filename, directoryPath, separator) { return directoryPath + filename + separator; } function build$7(root, options) { const { relativePaths, includeBasePath } = options; return relativePaths && root ? joinPathWithRelativePath(root, options) : includeBasePath ? joinPathWithBasePath : joinPath; } //#endregion //#region src/api/functions/push-directory.ts function pushDirectoryWithRelativePath(root) { return function(directoryPath, paths) { paths.push(directoryPath.substring(root.length) || "."); }; } function pushDirectoryFilterWithRelativePath(root) { return function(directoryPath, paths, filters) { const relativePath = directoryPath.substring(root.length) || "."; if (filters.every((filter) => filter(relativePath, true))) paths.push(relativePath); }; } const pushDirectory = (directoryPath, paths) => { paths.push(directoryPath || "."); }; const pushDirectoryFilter = (directoryPath, paths, filters) => { const path$1 = directoryPath || "."; if (filters.every((filter) => filter(path$1, true))) paths.push(path$1); }; const empty$2 = () => {}; function build$6(root, options) { const { includeDirs, filters, relativePaths } = options; if (!includeDirs) return empty$2; if (relativePaths) return filters && filters.length ? pushDirectoryFilterWithRelativePath(root) : pushDirectoryWithRelativePath(root); return filters && filters.length ? pushDirectoryFilter : pushDirectory; } //#endregion //#region src/api/functions/push-file.ts const pushFileFilterAndCount = (filename, _paths, counts, filters) => { if (filters.every((filter) => filter(filename, false))) counts.files++; }; const pushFileFilter = (filename, paths, _counts, filters) => { if (filters.every((filter) => filter(filename, false))) paths.push(filename); }; const pushFileCount = (_filename, _paths, counts, _filters) => { counts.files++; }; const pushFile = (filename, paths) => { paths.push(filename); }; const empty$1 = () => {}; function build$5(options) { const { excludeFiles, filters, onlyCounts } = options; if (excludeFiles) return empty$1; if (filters && filters.length) return onlyCounts ? pushFileFilterAndCount : pushFileFilter; else if (onlyCounts) return pushFileCount; else return pushFile; } //#endregion //#region src/api/functions/get-array.ts const getArray = (paths) => { return paths; }; const getArrayGroup = () => { return [""].slice(0, 0); }; function build$4(options) { return options.group ? getArrayGroup : getArray; } //#endregion //#region src/api/functions/group-files.ts const groupFiles = (groups, directory, files) => { groups.push({ directory, files, dir: directory }); }; const empty = () => {}; function build$3(options) { return options.group ? groupFiles : empty; } //#endregion //#region src/api/functions/resolve-symlink.ts const resolveSymlinksAsync = function(path$1, state, callback$1) { const { queue, options: { suppressErrors } } = state; queue.enqueue(); fs.default.realpath(path$1, (error, resolvedPath) => { if (error) return queue.dequeue(suppressErrors ? null : error, state); fs.default.stat(resolvedPath, (error$1, stat) => { if (error$1) return queue.dequeue(suppressErrors ? null : error$1, state); if (stat.isDirectory() && isRecursive(path$1, resolvedPath, state)) return queue.dequeue(null, state); callback$1(stat, resolvedPath); queue.dequeue(null, state); }); }); }; const resolveSymlinks = function(path$1, state, callback$1) { const { queue, options: { suppressErrors } } = state; queue.enqueue(); try { const resolvedPath = fs.default.realpathSync(path$1); const stat = fs.default.statSync(resolvedPath); if (stat.isDirectory() && isRecursive(path$1, resolvedPath, state)) return; callback$1(stat, resolvedPath); } catch (e) { if (!suppressErrors) throw e; } }; function build$2(options, isSynchronous) { if (!options.resolveSymlinks || options.excludeSymlinks) return null; return isSynchronous ? resolveSymlinks : resolveSymlinksAsync; } function isRecursive(path$1, resolved, state) { if (state.options.useRealPaths) return isRecursiveUsingRealPaths(resolved, state); let parent = (0, path.dirname)(path$1); let depth = 1; while (parent !== state.root && depth < 2) { const resolvedPath = state.symlinks.get(parent); const isSameRoot = !!resolvedPath && (resolvedPath === resolved || resolvedPath.startsWith(resolved) || resolved.startsWith(resolvedPath)); if (isSameRoot) depth++; else parent = (0, path.dirname)(parent); } state.symlinks.set(path$1, resolved); return depth > 1; } function isRecursiveUsingRealPaths(resolved, state) { return state.visited.includes(resolved + state.options.pathSeparator); } //#endregion //#region src/api/functions/invoke-callback.ts const onlyCountsSync = (state) => { return state.counts; }; const groupsSync = (state) => { return state.groups; }; const defaultSync = (state) => { return state.paths; }; const limitFilesSync = (state) => { return state.paths.slice(0, state.options.maxFiles); }; const onlyCountsAsync = (state, error, callback$1) => { report(error, callback$1, state.counts, state.options.suppressErrors); return null; }; const defaultAsync = (state, error, callback$1) => { report(error, callback$1, state.paths, state.options.suppressErrors); return null; }; const limitFilesAsync = (state, error, callback$1) => { report(error, callback$1, state.paths.slice(0, state.options.maxFiles), state.options.suppressErrors); return null; }; const groupsAsync = (state, error, callback$1) => { report(error, callback$1, state.groups, state.options.suppressErrors); return null; }; function report(error, callback$1, output, suppressErrors) { if (error && !suppressErrors) callback$1(error, output); else callback$1(null, output); } function build$1(options, isSynchronous) { const { onlyCounts, group, maxFiles } = options; if (onlyCounts) return isSynchronous ? onlyCountsSync : onlyCountsAsync; else if (group) return isSynchronous ? groupsSync : groupsAsync; else if (maxFiles) return isSynchronous ? limitFilesSync : limitFilesAsync; else return isSynchronous ? defaultSync : defaultAsync; } //#endregion //#region src/api/functions/walk-directory.ts const readdirOpts = { withFileTypes: true }; const walkAsync = (state, crawlPath, directoryPath, currentDepth, callback$1) => { state.queue.enqueue(); if (currentDepth <= 0) return state.queue.dequeue(null, state); state.visited.push(crawlPath); state.counts.directories++; fs.default.readdir(crawlPath || ".", readdirOpts, (error, entries = []) => { callback$1(entries, directoryPath, currentDepth); state.queue.dequeue(state.options.suppressErrors ? null : error, state); }); }; const walkSync = (state, crawlPath, directoryPath, currentDepth, callback$1) => { if (currentDepth <= 0) return; state.visited.push(crawlPath); state.counts.directories++; let entries = []; try { entries = fs.default.readdirSync(crawlPath || ".", readdirOpts); } catch (e) { if (!state.options.suppressErrors) throw e; } callback$1(entries, directoryPath, currentDepth); }; function build(isSynchronous) { return isSynchronous ? walkSync : walkAsync; } //#endregion //#region src/api/queue.ts /** * This is a custom stateless queue to track concurrent async fs calls. * It increments a counter whenever a call is queued and decrements it * as soon as it completes. When the counter hits 0, it calls onQueueEmpty. */ var Queue = class { count = 0; constructor(onQueueEmpty) { this.onQueueEmpty = onQueueEmpty; } enqueue() { this.count++; return this.count; } dequeue(error, output) { if (this.onQueueEmpty && (--this.count <= 0 || error)) { this.onQueueEmpty(error, output); if (error) { output.controller.abort(); this.onQueueEmpty = void 0; } } } }; //#endregion //#region src/api/counter.ts var Counter = class { _files = 0; _directories = 0; set files(num) { this._files = num; } get files() { return this._files; } set directories(num) { this._directories = num; } get directories() { return this._directories; } /** * @deprecated use `directories` instead */ /* c8 ignore next 3 */ get dirs() { return this._directories; } }; //#endregion //#region src/api/walker.ts var Walker = class { root; isSynchronous; state; joinPath; pushDirectory; pushFile; getArray; groupFiles; resolveSymlink; walkDirectory; callbackInvoker; constructor(root, options, callback$1) { this.isSynchronous = !callback$1; this.callbackInvoker = build$1(options, this.isSynchronous); this.root = normalizePath(root, options); this.state = { root: isRootDirectory(this.root) ? this.root : this.root.slice(0, -1), paths: [""].slice(0, 0), groups: [], counts: new Counter(), options, queue: new Queue((error, state) => this.callbackInvoker(state, error, callback$1)), symlinks: /* @__PURE__ */ new Map(), visited: [""].slice(0, 0), controller: new AbortController() }; this.joinPath = build$7(this.root, options); this.pushDirectory = build$6(this.root, options); this.pushFile = build$5(options); this.getArray = build$4(options); this.groupFiles = build$3(options); this.resolveSymlink = build$2(options, this.isSynchronous); this.walkDirectory = build(this.isSynchronous); } start() { this.pushDirectory(this.root, this.state.paths, this.state.options.filters); this.walkDirectory(this.state, this.root, this.root, this.state.options.maxDepth, this.walk); return this.isSynchronous ? this.callbackInvoker(this.state, null) : null; } walk = (entries, directoryPath, depth) => { const { paths, options: { filters, resolveSymlinks: resolveSymlinks$1, excludeSymlinks, exclude, maxFiles, signal, useRealPaths, pathSeparator }, controller } = this.state; if (controller.signal.aborted || signal && signal.aborted || maxFiles && paths.length > maxFiles) return; const files = this.getArray(this.state.paths); for (let i = 0; i < entries.length; ++i) { const entry = entries[i]; if (entry.isFile() || entry.isSymbolicLink() && !resolveSymlinks$1 && !excludeSymlinks) { const filename = this.joinPath(entry.name, directoryPath); this.pushFile(filename, files, this.state.counts, filters); } else if (entry.isDirectory()) { let path$1 = joinDirectoryPath(entry.name, directoryPath, this.state.options.pathSeparator); if (exclude && exclude(entry.name, path$1)) continue; this.pushDirectory(path$1, paths, filters); this.walkDirectory(this.state, path$1, path$1, depth - 1, this.walk); } else if (this.resolveSymlink && entry.isSymbolicLink()) { let path$1 = joinPathWithBasePath(entry.name, directoryPath); this.resolveSymlink(path$1, this.state, (stat, resolvedPath) => { if (stat.isDirectory()) { resolvedPath = normalizePath(resolvedPath, this.state.options); if (exclude && exclude(entry.name, useRealPaths ? resolvedPath : path$1 + pathSeparator)) return; this.walkDirectory(this.state, resolvedPath, useRealPaths ? resolvedPath : path$1 + pathSeparator, depth - 1, this.walk); } else { resolvedPath = useRealPaths ? resolvedPath : path$1; const filename = (0, path.basename)(resolvedPath); const directoryPath$1 = normalizePath((0, path.dirname)(resolvedPath), this.state.options); resolvedPath = this.joinPath(filename, directoryPath$1); this.pushFile(resolvedPath, files, this.state.counts, filters); } }); } } this.groupFiles(this.state.groups, directoryPath, files); }; }; //#endregion //#region src/api/async.ts function promise(root, options) { return new Promise((resolve$1, reject) => { callback(root, options, (err, output) => { if (err) return reject(err); resolve$1(output); }); }); } function callback(root, options, callback$1) { let walker = new Walker(root, options, callback$1); walker.start(); } //#endregion //#region src/api/sync.ts function sync(root, options) { const walker = new Walker(root, options); return walker.start(); } //#endregion //#region src/builder/api-builder.ts var APIBuilder = class { constructor(root, options) { this.root = root; this.options = options; } withPromise() { return promise(this.root, this.options); } withCallback(cb) { callback(this.root, this.options, cb); } sync() { return sync(this.root, this.options); } }; //#endregion //#region src/builder/index.ts var pm = null; /* c8 ignore next 6 */ try { require.resolve("picomatch"); pm = require("picomatch"); } catch (_e) {} var Builder = class { globCache = {}; options = { maxDepth: Infinity, suppressErrors: true, pathSeparator: path.sep, filters: [] }; globFunction; constructor(options) { this.options = { ...this.options, ...options }; this.globFunction = this.options.globFunction; } group() { this.options.group = true; return this; } withPathSeparator(separator) { this.options.pathSeparator = separator; return this; } withBasePath() { this.options.includeBasePath = true; return this; } withRelativePaths() { this.options.relativePaths = true; return this; } withDirs() { this.options.includeDirs = true; return this; } withMaxDepth(depth) { this.options.maxDepth = depth; return this; } withMaxFiles(limit) { this.options.maxFiles = limit; return this; } withFullPaths() { this.options.resolvePaths = true; this.options.includeBasePath = true; return this; } withErrors() { this.options.suppressErrors = false; return this; } withSymlinks({ resolvePaths = true } = {}) { this.options.resolveSymlinks = true; this.options.useRealPaths = resolvePaths; return this.withFullPaths(); } withAbortSignal(signal) { this.options.signal = signal; return this; } normalize() { this.options.normalizePath = true; return this; } filter(predicate) { this.options.filters.push(predicate); return this; } onlyDirs() { this.options.excludeFiles = true; this.options.includeDirs = true; return this; } exclude(predicate) { this.options.exclude = predicate; return this; } onlyCounts() { this.options.onlyCounts = true; return this; } crawl(root) { return new APIBuilder(root || ".", this.options); } withGlobFunction(fn) { this.globFunction = fn; return this; } /** * @deprecated Pass options using the constructor instead: * ```ts * new fdir(options).crawl("/path/to/root"); * ``` * This method will be removed in v7.0 */ /* c8 ignore next 4 */ crawlWithOptions(root, options) { this.options = { ...this.options, ...options }; return new APIBuilder(root || ".", this.options); } glob(...patterns) { if (this.globFunction) return this.globWithOptions(patterns); return this.globWithOptions(patterns, ...[{ dot: true }]); } globWithOptions(patterns, ...options) { const globFn = this.globFunction || pm; /* c8 ignore next 5 */ if (!globFn) throw new Error("Please specify a glob function to use glob matching."); var isMatch = this.globCache[patterns.join("\0")]; if (!isMatch) { isMatch = globFn(patterns, ...options); this.globCache[patterns.join("\0")] = isMatch; } this.options.filters.push((path$1) => isMatch(path$1)); return this; } }; //#endregion exports.fdir = Builder;