Skip to content

Instantly share code, notes, and snippets.

@Phoenix35
Last active April 14, 2020 20:26
Show Gist options
  • Save Phoenix35/b5e742bbba92300d112827a8ecf82376 to your computer and use it in GitHub Desktop.
Save Phoenix35/b5e742bbba92300d112827a8ecf82376 to your computer and use it in GitHub Desktop.
An extension of getMatchingExt.js to support predicates in general
"use strict";
const fsP = require("fs").promises;
const path = require("path");
const { cwd, chdir } = process;
const MAX_ARRAY_LENGTH = 2**32 - 1;
/**
* getMatchingFiles - Lazily generates file paths in a given `targetDir` directory matching the predicate
* @param {Path} targetDir -
* @param {Object|String} options - If `options` is a string, it will be used as a string for options.predicate (UTF-8)
* @param {(function|string|array|Set)} options.predicate - Takes a predicate to match the file name against.
* Can also be a string, an array of file names, or a set of file names.
* @param {?string} options.encoding - Defaults to "utf8"
* @param {?number} options.depth - Defaults to MAX_ARRAY_LENGTH
* @return {AsyncIterableIterator<string>} - An async iterable yielding the paths, relative to `targetDir`
*/
async function *getMatchingFiles ( // eslint-disable-line complexity
targetDir,
options,
) {
let predicate,
encoding,
depth;
if (typeof options === "string") {
predicate = name => name === options;
encoding = "utf-8";
depth = Number.MAX_SAFE_INTEGER;
} else {
const possiblePredicate = options.predicate;
if (typeof possiblePredicate === "function")
predicate = possiblePredicate;
else if (typeof possiblePredicate === "string")
predicate = name => name === possiblePredicate;
else if (Array.isArray(possiblePredicate))
predicate = name => possiblePredicate.includes(name);
else if (Object.prototype.toString.call(possiblePredicate) === "[object Set]")
predicate = name => possiblePredicate.has(name);
encoding = options.encoding ?? "utf8";
const sensibleDepth = options.depth;
depth = (0 < sensibleDepth && sensibleDepth < MAX_ARRAY_LENGTH)
? sensibleDepth
: MAX_ARRAY_LENGTH;
}
const oldDir = cwd(),
pathsQueue = [["."]];
try {
chdir(targetDir);
while (pathsQueue.length) {
// Queue in breadth-first traversal implemented via push - shift.
const currentSegments = pathsQueue.shift(),
currentDepth = currentSegments.length,
currentPath = path.join(...currentSegments);
const files = await fsP.readdir( // eslint-disable-line no-await-in-loop
currentPath,
{ encoding,
withFileTypes: true },
);
for (const file of files) {
const { name } = file;
if (file.isFile() && predicate(name))
yield path.join(currentPath, name);
else if (file.isDirectory() && currentDepth <= depth)
pathsQueue.push(currentSegments.concat(name));
}
}
} finally {
chdir(oldDir);
}
}
module.exports = getMatchingFiles;
// Use
const path = require("path");
const fs = require("fs");
const getMatchingFiles = require("./path/to/getMatchingFiles");
//
for await (const pathOfFile of getMatchingFiles(dirPath, fileName))
fs.unlink(path.join(dirPath, pathOfFile), err => {
if (err)
throw err;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment