fs: make readdir recursive algorithm iterative
PR-URL: https://github.com/nodejs/node/pull/47650 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
This commit is contained in:
parent
ded6b618be
commit
12a93ce630
88
lib/fs.js
88
lib/fs.js
@ -27,6 +27,7 @@
|
|||||||
const {
|
const {
|
||||||
ArrayPrototypePush,
|
ArrayPrototypePush,
|
||||||
BigIntPrototypeToString,
|
BigIntPrototypeToString,
|
||||||
|
Boolean,
|
||||||
MathMax,
|
MathMax,
|
||||||
Number,
|
Number,
|
||||||
ObjectDefineProperties,
|
ObjectDefineProperties,
|
||||||
@ -97,6 +98,7 @@ const {
|
|||||||
copyObject,
|
copyObject,
|
||||||
Dirent,
|
Dirent,
|
||||||
emitRecursiveRmdirWarning,
|
emitRecursiveRmdirWarning,
|
||||||
|
getDirent,
|
||||||
getDirents,
|
getDirents,
|
||||||
getOptions,
|
getOptions,
|
||||||
getValidatedFd,
|
getValidatedFd,
|
||||||
@ -1404,34 +1406,60 @@ function mkdirSync(path, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(Ethan-Arrowood): Make this iterative too
|
/**
|
||||||
function readdirSyncRecursive(path, origPath, options) {
|
* An iterative algorithm for reading the entire contents of the `basePath` directory.
|
||||||
nullCheck(path, 'path', true);
|
* This function does not validate `basePath` as a directory. It is passed directly to
|
||||||
const ctx = { path };
|
* `binding.readdir` after a `nullCheck`.
|
||||||
const result = binding.readdir(pathModule.toNamespacedPath(path),
|
* @param {string} basePath
|
||||||
options.encoding, !!options.withFileTypes, undefined, ctx);
|
* @param {{ encoding: string, withFileTypes: boolean }} options
|
||||||
handleErrorFromBinding(ctx);
|
* @returns {string[] | Dirent[]}
|
||||||
return options.withFileTypes ?
|
*/
|
||||||
getDirents(path, result).flatMap((dirent) => {
|
function readdirSyncRecursive(basePath, options) {
|
||||||
return [
|
nullCheck(basePath, 'path', true);
|
||||||
dirent,
|
|
||||||
...(dirent.isDirectory() ?
|
const withFileTypes = Boolean(options.withFileTypes);
|
||||||
readdirSyncRecursive(
|
const encoding = options.encoding;
|
||||||
pathModule.join(path, dirent.name),
|
|
||||||
origPath,
|
const readdirResults = [];
|
||||||
options,
|
const pathsQueue = [basePath];
|
||||||
) : []),
|
|
||||||
];
|
const ctx = { path: basePath };
|
||||||
}) :
|
function read(path) {
|
||||||
result.flatMap((ent) => {
|
ctx.path = path;
|
||||||
const innerPath = pathModule.join(path, ent);
|
const readdirResult = binding.readdir(
|
||||||
const relativePath = pathModule.relative(origPath, innerPath);
|
pathModule.toNamespacedPath(path),
|
||||||
const stat = binding.internalModuleStat(innerPath);
|
encoding,
|
||||||
return [
|
withFileTypes,
|
||||||
relativePath,
|
undefined,
|
||||||
...(stat === 1 ? readdirSyncRecursive(innerPath, origPath, options) : []),
|
ctx,
|
||||||
];
|
);
|
||||||
});
|
handleErrorFromBinding(ctx);
|
||||||
|
|
||||||
|
for (let i = 0; i < readdirResult.length; i++) {
|
||||||
|
if (withFileTypes) {
|
||||||
|
const dirent = getDirent(path, readdirResult[0][i], readdirResult[1][i]);
|
||||||
|
ArrayPrototypePush(readdirResults, dirent);
|
||||||
|
if (dirent.isDirectory()) {
|
||||||
|
ArrayPrototypePush(pathsQueue, pathModule.join(dirent.path, dirent.name));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const resultPath = pathModule.join(path, readdirResult[i]);
|
||||||
|
const relativeResultPath = pathModule.relative(basePath, resultPath);
|
||||||
|
const stat = binding.internalModuleStat(resultPath);
|
||||||
|
ArrayPrototypePush(readdirResults, relativeResultPath);
|
||||||
|
// 1 indicates directory
|
||||||
|
if (stat === 1) {
|
||||||
|
ArrayPrototypePush(pathsQueue, resultPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < pathsQueue.length; i++) {
|
||||||
|
read(pathsQueue[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return readdirResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1456,7 +1484,7 @@ function readdir(path, options, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.recursive) {
|
if (options.recursive) {
|
||||||
callback(null, readdirSyncRecursive(path, path, options));
|
callback(null, readdirSyncRecursive(path, options));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1494,7 +1522,7 @@ function readdirSync(path, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.recursive) {
|
if (options.recursive) {
|
||||||
return readdirSyncRecursive(path, path, options);
|
return readdirSyncRecursive(path, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
|
@ -160,8 +160,6 @@ class Dir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(Ethan-Arrowood): Review this implementation. Make it iterative.
|
|
||||||
// Can we better leverage the `kDirOperationQueue`?
|
|
||||||
readSyncRecursive(dirent) {
|
readSyncRecursive(dirent) {
|
||||||
const ctx = { path: dirent.path };
|
const ctx = { path: dirent.path };
|
||||||
const handle = dirBinding.opendir(
|
const handle = dirBinding.opendir(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user