@@ -1372,6 +1372,102 @@ function mkdirSync(path, options) {
13721372 }
13731373}
13741374
1375+ /*
1376+ * An recursive algorithm for reading the entire contents of the `basePath` directory.
1377+ * This function does not validate `basePath` as a directory. It is passed directly to
1378+ * `binding.readdir`.
1379+ * @param {string} basePath
1380+ * @param {{ encoding: string, withFileTypes: boolean }} options
1381+ * @param {(
1382+ * err?: Error,
1383+ * files?: string[] | Buffer[] | Dirent[]
1384+ * ) => any} callback
1385+ * @returns {void}
1386+ */
1387+ function readdirRecursive(basePath, options, callback) {
1388+ const context = {
1389+ withFileTypes: Boolean(options.withFileTypes),
1390+ encoding: options.encoding,
1391+ basePath,
1392+ readdirResults: [],
1393+ pathsQueue: [basePath],
1394+ };
1395+
1396+ let i = 0;
1397+
1398+ function read(path) {
1399+ const req = new FSReqCallback();
1400+ req.oncomplete = (err, result) => {
1401+ if (err) {
1402+ callback(err);
1403+ return;
1404+ }
1405+
1406+ if (result === undefined) {
1407+ callback(null, context.readdirResults);
1408+ return;
1409+ }
1410+
1411+ processReaddirResult({
1412+ result,
1413+ currentPath: path,
1414+ context,
1415+ });
1416+
1417+ if (i < context.pathsQueue.length) {
1418+ read(context.pathsQueue[i++]);
1419+ } else {
1420+ callback(null, context.readdirResults);
1421+ }
1422+ };
1423+
1424+ binding.readdir(
1425+ path,
1426+ context.encoding,
1427+ context.withFileTypes,
1428+ req,
1429+ );
1430+ }
1431+
1432+ read(context.pathsQueue[i++]);
1433+ }
1434+
1435+ // Calling `readdir` with `withFileTypes=true`, the result is an array of arrays.
1436+ // The first array is the names, and the second array is the types.
1437+ // They are guaranteed to be the same length; hence, setting `length` to the length
1438+ // of the first array within the result.
1439+ const processReaddirResult = (args) => (args.context.withFileTypes ? handleDirents(args) : handleFilePaths(args));
1440+
1441+ function handleDirents({ result, currentPath, context }) {
1442+ const { 0: names, 1: types } = result;
1443+ const { length } = names;
1444+
1445+ for (let i = 0; i < length; i++) {
1446+ // Avoid excluding symlinks, as they are not directories.
1447+ // Refs: https://github.com/nodejs/node/issues/52663
1448+ const fullPath = pathModule.join(currentPath, names[i]);
1449+ const dirent = getDirent(currentPath, names[i], types[i]);
1450+ ArrayPrototypePush(context.readdirResults, dirent);
1451+
1452+ if (dirent.isDirectory() || binding.internalModuleStat(binding, fullPath) === 1) {
1453+ ArrayPrototypePush(context.pathsQueue, fullPath);
1454+ }
1455+ }
1456+ }
1457+
1458+ function handleFilePaths({ result, currentPath, context }) {
1459+ for (let i = 0; i < result.length; i++) {
1460+ const resultPath = pathModule.join(currentPath, result[i]);
1461+ const relativeResultPath = pathModule.relative(context.basePath, resultPath);
1462+ const stat = binding.internalModuleStat(binding, resultPath);
1463+ ArrayPrototypePush(context.readdirResults, relativeResultPath);
1464+
1465+ if (stat === 1) {
1466+ ArrayPrototypePush(context.pathsQueue, resultPath);
1467+ }
1468+ }
1469+ }
1470+
13751471/**
13761472 * An iterative algorithm for reading the entire contents of the `basePath` directory.
13771473 * This function does not validate `basePath` as a directory. It is passed directly to
@@ -1381,58 +1477,37 @@ function mkdirSync(path, options) {
13811477 * @returns {string[] | Dirent[]}
13821478 */
13831479function readdirSyncRecursive(basePath, options) {
1384- const withFileTypes = Boolean(options.withFileTypes);
1385- const encoding = options.encoding;
1386-
1387- const readdirResults = [];
1388- const pathsQueue = [basePath];
1480+ const context = {
1481+ withFileTypes: Boolean(options.withFileTypes),
1482+ encoding: options.encoding,
1483+ basePath,
1484+ readdirResults: [],
1485+ pathsQueue: [basePath],
1486+ };
13891487
13901488 function read(path) {
13911489 const readdirResult = binding.readdir(
13921490 path,
1393- encoding,
1394- withFileTypes,
1491+ context. encoding,
1492+ context. withFileTypes,
13951493 );
13961494
13971495 if (readdirResult === undefined) {
13981496 return;
13991497 }
14001498
1401- if (withFileTypes) {
1402- // Calling `readdir` with `withFileTypes=true`, the result is an array of arrays.
1403- // The first array is the names, and the second array is the types.
1404- // They are guaranteed to be the same length; hence, setting `length` to the length
1405- // of the first array within the result.
1406- const length = readdirResult[0].length;
1407- for (let i = 0; i < length; i++) {
1408- // Avoid excluding symlinks, as they are not directories.
1409- // Refs: https://github.com/nodejs/node/issues/52663
1410- const stat = binding.internalModuleStat(binding, pathModule.join(path, readdirResult[0][i]));
1411- const dirent = getDirent(path, readdirResult[0][i], readdirResult[1][i]);
1412- ArrayPrototypePush(readdirResults, dirent);
1413- if (dirent.isDirectory() || stat === 1) {
1414- ArrayPrototypePush(pathsQueue, pathModule.join(dirent.parentPath, dirent.name));
1415- }
1416- }
1417- } else {
1418- for (let i = 0; i < readdirResult.length; i++) {
1419- const resultPath = pathModule.join(path, readdirResult[i]);
1420- const relativeResultPath = pathModule.relative(basePath, resultPath);
1421- const stat = binding.internalModuleStat(binding, resultPath);
1422- ArrayPrototypePush(readdirResults, relativeResultPath);
1423- // 1 indicates directory
1424- if (stat === 1) {
1425- ArrayPrototypePush(pathsQueue, resultPath);
1426- }
1427- }
1428- }
1499+ processReaddirResult({
1500+ result: readdirResult,
1501+ currentPath: path,
1502+ context,
1503+ });
14291504 }
14301505
1431- for (let i = 0; i < pathsQueue.length; i++) {
1432- read(pathsQueue[i]);
1506+ for (let i = 0; i < context. pathsQueue.length; i++) {
1507+ read(context. pathsQueue[i]);
14331508 }
14341509
1435- return readdirResults;
1510+ return context. readdirResults;
14361511}
14371512
14381513/**
@@ -1458,7 +1533,7 @@ function readdir(path, options, callback) {
14581533 }
14591534
14601535 if (options.recursive) {
1461- callback(null, readdirSyncRecursive( path, options) );
1536+ readdirRecursive( path, options, callback );
14621537 return;
14631538 }
14641539
0 commit comments