From 9e4a20224a2cc005775cb99b5ea888c253e48e3a Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sat, 19 Aug 2023 11:51:13 -0300 Subject: util: remove findFiles util, adapt traverse --- src/util/io.js | 23 ----------------------- src/util/node-utils.js | 51 +++++++++++++++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 42 deletions(-) delete mode 100644 src/util/io.js (limited to 'src/util') diff --git a/src/util/io.js b/src/util/io.js deleted file mode 100644 index 12e87f4d..00000000 --- a/src/util/io.js +++ /dev/null @@ -1,23 +0,0 @@ -// Utility functions for interacting with files and other external data -// interfacey constructs. - -import {readdir} from 'fs/promises'; -import * as path from 'path'; - -export async function findFiles(dataPath, { - filter = () => true, - joinParentDirectory = true, -} = {}) { - let files; - try { - files = await readdir(dataPath); - } catch (error) { - throw Object.assign( - new AggregateError([error], `Failed to list files from ${dataPath}`), - {code: error.code}); - } - - return files - .filter((file) => filter(file)) - .map((file) => (joinParentDirectory ? path.join(dataPath, file) : file)); -} diff --git a/src/util/node-utils.js b/src/util/node-utils.js index 3c0dd4cd..2fb7e8dd 100644 --- a/src/util/node-utils.js +++ b/src/util/node-utils.js @@ -1,6 +1,6 @@ // Utility functions which are only relevant to particular Node.js constructs. -import {readdir} from 'fs/promises'; +import {readdir, stat} from 'fs/promises'; import {fileURLToPath} from 'url'; import * as path from 'path'; @@ -56,34 +56,47 @@ export function isMain(importMetaURL) { ].includes(relative); } -// Like readdir... but it's recursive! -export function traverse(startDirPath, { +// Like readdir... but it's recursive! This returns a flat list of file paths. +// By default, the paths include the provided top/root path, but this can be +// changed with prefixPath to prefix some other path, or to just return paths +// relative to the root. Change pathStyle to specify posix or win32, or leave +// it as the default device-correct style. Provide a filterDir function to +// control which directory names are traversed at all, and filterFile to +// select which filenames are included in the final list. +export async function traverse(rootPath, { pathStyle = 'device', filterFile = () => true, - filterDir = () => true + filterDir = () => true, + prefixPath = rootPath, } = {}) { - const pathJoin = { + const pathJoinDevice = path.join; + const pathJoinStyle = { 'device': path.join, 'posix': path.posix.join, 'win32': path.win32.join, }[pathStyle]; - if (!pathJoin) { + if (!pathJoinStyle) { throw new Error(`Expected pathStyle to be device, posix, or win32`); } - const recursive = (names, subDirPath) => - Promise.all(names.map(name => - readdir(pathJoin(startDirPath, subDirPath, name)).then( - names => - (filterDir(name) - ? recursive(names, pathJoin(subDirPath, name)) - : []), - () => - (filterFile(name) - ? [pathJoin(subDirPath, name)] - : [])))) - .then(pathArrays => pathArrays.flat()); + const recursive = (names, ...subdirectories) => + Promise.all(names.map(async name => { + const devicePath = pathJoinDevice(rootPath, ...subdirectories, name); + const stats = await stat(devicePath); - return readdir(startDirPath).then(names => recursive(names, '')); + if (stats.isDirectory() && !filterDir(name)) return []; + else if (stats.isFile() && !filterFile(name)) return []; + else if (!stats.isDirectory() && !stats.isFile()) return []; + + if (stats.isDirectory()) { + return recursive(await readdir(devicePath), ...subdirectories, name); + } else { + return pathJoinStyle(prefixPath, ...subdirectories, name); + } + })); + + const names = await readdir(rootPath); + const results = await recursive(names); + return results.flat(Infinity); } -- cgit 1.3.0-6-gf8a5