Description
Is there an existing issue or pull request for this?
- I have searched the existing issues and pull requests
Feature description
In #454 we added a script subpath-updater.mjs
which has a function walk
to deeply walk a directory path and find files matching a file extension. It would be useful if this would be ported to a proper function in the utilities package.
Desired solution
The following is a write-up of the function as it should approximately be. The name of the function is still open to discussion.
Other than that unit tests should be written.
Furthermore, the turbo.json
should be updated to require @sapphire/utilities
to be built before check-subpath
is ran.
import type { PathLike } from 'node:fs';
import { opendir } from 'node:fs/promises';
import { join } from 'node:path';
/**
*
* @param path The path in which to find files. This can be a string, buffer or {@link URL}.
* @param fileNameEndsWith The string pattern with which the file name must end.
* Ideally this is a file extension, however you can also provide more parts of the end of the file.
*
* Note that we do **not** support a full globby pattern using asterisk for wildcards. It has to be an exact match with {@link String.endsWith}
*
* @return An {@link AsyncIterableIterator<string>} of all the files. To loop over these use `for await (const file of walk(path, fileNameEndsWith)) {}`
*
*
* @example
* ```typescript
* // With CommonJS: To find all files ending with `.ts` in the src directory:
* const path = require('node:path');
*
* for await (const file of walk(path.join(__dirname, 'src'), '.ts')) {
* console.log(file);
* }
* ```
*
* @example
* ```typescript
* // With ESM: To find all files ending with `.ts` in the src directory:
* for await (const file of walk(new URL('src', import.meta.url), '.ts')) {
* console.log(file);
* }
* ```
*/
async function* findFilesRecursively(path: PathLike, fileNameEndsWith: string): AsyncIterableIterator<string> {
try {
const dir = await opendir(path);
for await (const item of dir) {
if (item.isFile() && (!fileNameEndsWith || item.name.endsWith(fileNameEndsWith))) {
yield join(dir.path, item.name);
} else if (item.isDirectory()) {
yield* findFilesRecursively(join(dir.path, item.name), fileNameEndsWith);
}
}
} catch (error) {
if ((error as any).code !== 'ENOENT') {
console.error(error);
}
}
}
Alternatives considered
N.A.
Additional context
The name of the function is still open for discussing. Likewise we can also considering extending this to several functions using 1 base function and passing a predicate so those several functions can do startsWith
, endsWith
, includes
and regex
. For example taking the code above for findFilesRecursively
we could have findFilesRecursivelyStringStartsWith
, findFilesRecursivelyStringEndsWith
, etc.
Metadata
Assignees
Type
Projects
Status
Done
Activity