@augment-vir/node
Version:
A collection of augments, helpers types, functions, and classes only for Node.js (backend) JavaScript environments.
89 lines (80 loc) • 2.94 kB
text/typescript
import {awaitedForEach, type MaybePromise, type PartialWithUndefined} from '@augment-vir/common';
import {type Dirent, type PathLike} from 'node:fs';
import {type FileHandle, type readFile} from 'node:fs/promises';
import {join} from 'node:path';
/**
* Output from `readfile`, used in {@link WalkFilesParams}.
*
* @category Package : @augment-vir/node
* @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
*/
export type ReadFileOutput = Awaited<ReturnType<typeof readFile>>;
/**
* Params for {@link walkFiles}.
*
* @category Package : @augment-vir/node
* @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
*/
export type WalkFilesParams = {
/** The directory to start walking files at. */
startDirPath: string;
/** Do something with a read file's contents. */
handleFileContents: (params: {path: string; contents: ReadFileOutput}) => MaybePromise<void>;
} & PartialWithUndefined<{
/**
* Check if a file should be read or a directory should be traversed.
*
* If this is not provided, every file will be read and every directory will be traversed.
*/
shouldRead: (params: {path: string; isDir: boolean}) => MaybePromise<boolean>;
/** Optional overrides for the internally used `node:fs/promises' imports. */
fs: {
readFile: (path: PathLike | FileHandle) => MaybePromise<ReadFileOutput>;
readdir: (
path: PathLike,
options: {withFileTypes: true},
) => MaybePromise<Pick<Dirent, 'name' | 'isDirectory'>[]>;
};
}>;
/**
* Walks files within a directory.
*
* @category Node : File
* @category Package : @augment-vir/node
* @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
*/
export async function walkFiles({
handleFileContents,
shouldRead,
startDirPath,
fs,
}: Readonly<WalkFilesParams>): Promise<void> {
const {readFile, readdir} = {
/* node:coverage ignore next 2: dynamic imports are not branches. */
readFile: fs?.readFile || (await import('node:fs/promises')).readFile,
readdir: fs?.readdir || (await import('node:fs/promises')).readdir,
};
const children = await readdir(startDirPath, {
withFileTypes: true,
});
await awaitedForEach(children, async (file) => {
const childPath = join(startDirPath, file.name);
const isDir = file.isDirectory();
const willRead = shouldRead ? await shouldRead({path: childPath, isDir}) : true;
if (!willRead) {
return;
}
if (isDir) {
await walkFiles({
startDirPath: childPath,
shouldRead,
handleFileContents,
});
} else {
await handleFileContents({
path: childPath,
contents: await readFile(childPath),
});
}
});
}