@plugjs/plug
Version:
PlugJS Build System ===================
84 lines • 3.44 kB
JavaScript
import { basename, join } from 'node:path';
import { opendir, stat } from "../fs.js";
import { $p, log } from "../logging.js";
import { resolveAbsolutePath } from "../paths.js";
import { match } from "./match.js";
/**
* Walk the specified directory, returning an asynchronous iterator over all
* the _relative_ files found matching the specified globs and matching options.
*/
export function walk(directory, globs, options = {}) {
const { maxDepth = Infinity, followSymlinks = true, allowNodeModules = false, ...opts } = options;
/* Make sure to also ignore node modules or dot directories if we have to */
const onDirectory = (dir) => {
// if we were told to start looking into "node_modules", or in a directory
// starting with ".", then we ignore any whatsoever option here!
if (dir === directory)
return true;
const name = basename(dir);
if (name === 'node_modules')
return !!allowNodeModules;
if (name.startsWith('.'))
return !!opts.dot;
return true;
};
/* Create our positive matcher to match our globs */
const positiveMatcher = match(globs, opts);
/* Do the walk! */
log.debug('Walking directory', $p(directory), { globs, options });
return walker({
directory,
relative: '',
matcher: positiveMatcher,
onDirectory,
followSymlinks,
maxDepth,
depth: 0,
});
}
/* Walk a directory and yield matching results until the given `maxDepth` */
async function* walker(args) {
const { directory, relative, matcher: positiveMatcher, onDirectory, followSymlinks, maxDepth, depth, } = args;
/* Read the directory, including file types */
const dir = resolveAbsolutePath(directory, relative);
if (!onDirectory(dir))
return;
log.trace('Reading directory', $p(dir));
let dirents;
try {
dirents = await opendir(dir);
}
catch (error) {
if (error.code !== 'ENOENT')
throw error;
log.warn('Directory', $p(dir), 'not found');
return;
}
/* For each entry we determine the full path */
for await (const dirent of dirents) {
const path = join(relative, dirent.name);
/* If the entry is a file and matches, yield it */
if (dirent.isFile() && positiveMatcher(path))
yield path;
/* If the entry is a directory within our depth, walk it recursively */
else if (dirent.isDirectory() && (depth < maxDepth)) {
const children = walker({ ...args, relative: path, depth: depth + 1 });
for await (const child of children)
yield child;
/* If this is a symlink and we're told to check them let's see what we have */
}
else if (dirent.isSymbolicLink() && followSymlinks) {
const info = await stat(join(directory, path));
/* If the link is a file and matches, yield it */
if (info.isFile() && positiveMatcher(path))
yield path;
/* If the link is a directory within our depth, walk it recursively */
else if (info.isDirectory() && (depth < maxDepth)) {
const children = walker({ ...args, relative: path, depth: depth + 1 });
for await (const child of children)
yield child;
}
}
}
}
//# sourceMappingURL=walk.js.map