« get me outta code hell

util: remove findFiles util, adapt traverse - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/util/node-utils.js
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2023-08-19 11:51:13 -0300
committer(quasar) nebula <qznebula@protonmail.com>2023-08-19 12:24:03 -0300
commit9e4a20224a2cc005775cb99b5ea888c253e48e3a (patch)
tree7757c2b5a269657a760a076fd25e724457c4941b /src/util/node-utils.js
parent3b601adf3945a487f4aa07eb8c0f62161460345a (diff)
util: remove findFiles util, adapt traverse
Diffstat (limited to 'src/util/node-utils.js')
-rw-r--r--src/util/node-utils.js51
1 files changed, 32 insertions, 19 deletions
diff --git a/src/util/node-utils.js b/src/util/node-utils.js
index 3c0dd4c..2fb7e8d 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);
 }