Skip to content

Commit

Permalink
make readdir alg iterative
Browse files Browse the repository at this point in the history
  • Loading branch information
Ethan Arrowood committed Apr 20, 2023
1 parent 7b39e80 commit 7de1599
Showing 1 changed file with 61 additions and 31 deletions.
92 changes: 61 additions & 31 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

const {
ArrayPrototypePush,
ArrayPrototypeShift,
BigIntPrototypeToString,
MathMax,
Number,
Expand Down Expand Up @@ -140,7 +141,6 @@ const {
validateObject,
validateString,
} = require('internal/validators');

let truncateWarn = true;
let fs;

Expand Down Expand Up @@ -1404,34 +1404,64 @@ function mkdirSync(path, options) {
}
}

// TODO(Ethan-Arrowood): Make this iterative too
function readdirSyncRecursive(path, origPath, options) {
nullCheck(path, 'path', true);
const ctx = { path };
const result = binding.readdir(pathModule.toNamespacedPath(path),
options.encoding, !!options.withFileTypes, undefined, ctx);
handleErrorFromBinding(ctx);
return options.withFileTypes ?
getDirents(path, result).flatMap((dirent) => {
return [
dirent,
...(dirent.isDirectory() ?
readdirSyncRecursive(
pathModule.join(path, dirent.name),
origPath,
options,
) : []),
];
}) :
result.flatMap((ent) => {
const innerPath = pathModule.join(path, ent);
const relativePath = pathModule.relative(origPath, innerPath);
const stat = binding.internalModuleStat(innerPath);
return [
relativePath,
...(stat === 1 ? readdirSyncRecursive(innerPath, origPath, options) : []),
];
});
/**
* An iterative algorithm for reading the entire contents of the `basePath` directory.
* This function does not validate `basePath` as a directory. It is passed directly to
* `binding.readdir` after a `nullCheck`.
* @param {string} basePath
* @param {{ encoding: string, withFileTypes: boolean }} options
* @returns {Array<string> | Array<Dirent>}
*/
function readdirSyncRecursive(basePath, options) {
nullCheck(basePath, 'path', true);

const results = [];
const opsQueue = [];

function _read(_path) {
const ctx = { _path };
const result = binding.readdir(
pathModule.toNamespacedPath(_path),
options.encoding,
!!options.withFileTypes,
undefined,
ctx,
);
handleErrorFromBinding(ctx);

if (options.withFileTypes) {
const dirents = getDirents(_path, result);
for (let i = 0; i < dirents.length; i++) {
const dirent = dirents[i];
ArrayPrototypePush(results, dirent);
if (dirent.isDirectory()) {
ArrayPrototypePush(opsQueue, curryRead(pathModule.join(dirent.path, dirent.name)));
}
}
} else {
for (let i = 0; i < result.length; i++) {
const ent = result[i];
const innerPath = pathModule.join(_path, ent);
const relativePath = pathModule.relative(basePath, innerPath);
const stat = binding.internalModuleStat(innerPath);
ArrayPrototypePush(results, relativePath);
if (stat === 1) {
ArrayPrototypePush(opsQueue, curryRead(innerPath));
}
}
}
}

const curryRead = (p) => () => _read(p);

ArrayPrototypePush(opsQueue, curryRead(basePath));

while (opsQueue.length !== 0) {
const op = ArrayPrototypeShift(opsQueue);
op();
}

return results;
}

/**
Expand All @@ -1456,7 +1486,7 @@ function readdir(path, options, callback) {
}

if (options.recursive) {
callback(null, readdirSyncRecursive(path, path, options));
callback(null, readdirSyncRecursive(path, options));
return;
}

Expand Down Expand Up @@ -1494,7 +1524,7 @@ function readdirSync(path, options) {
}

if (options.recursive) {
return readdirSyncRecursive(path, path, options);
return readdirSyncRecursive(path, options);
}

const ctx = { path };
Expand Down

0 comments on commit 7de1599

Please sign in to comment.