|
27 | 27 | const { |
28 | 28 | ArrayPrototypePush, |
29 | 29 | BigIntPrototypeToString, |
| 30 | + Boolean, |
30 | 31 | MathMax, |
31 | 32 | Number, |
32 | 33 | ObjectDefineProperties, |
@@ -97,6 +98,7 @@ const { |
97 | 98 | copyObject, |
98 | 99 | Dirent, |
99 | 100 | emitRecursiveRmdirWarning, |
| 101 | + getDirent, |
100 | 102 | getDirents, |
101 | 103 | getOptions, |
102 | 104 | getValidatedFd, |
@@ -1404,34 +1406,60 @@ function mkdirSync(path, options) { |
1404 | 1406 | } |
1405 | 1407 | } |
1406 | 1408 |
|
1407 | | -// TODO(Ethan-Arrowood): Make this iterative too |
1408 | | -function readdirSyncRecursive(path, origPath, options) { |
1409 | | - nullCheck(path, 'path', true); |
1410 | | - const ctx = { path }; |
1411 | | - const result = binding.readdir(pathModule.toNamespacedPath(path), |
1412 | | - options.encoding, !!options.withFileTypes, undefined, ctx); |
1413 | | - handleErrorFromBinding(ctx); |
1414 | | - return options.withFileTypes ? |
1415 | | - getDirents(path, result).flatMap((dirent) => { |
1416 | | - return [ |
1417 | | - dirent, |
1418 | | - ...(dirent.isDirectory() ? |
1419 | | - readdirSyncRecursive( |
1420 | | - pathModule.join(path, dirent.name), |
1421 | | - origPath, |
1422 | | - options, |
1423 | | - ) : []), |
1424 | | - ]; |
1425 | | - }) : |
1426 | | - result.flatMap((ent) => { |
1427 | | - const innerPath = pathModule.join(path, ent); |
1428 | | - const relativePath = pathModule.relative(origPath, innerPath); |
1429 | | - const stat = binding.internalModuleStat(innerPath); |
1430 | | - return [ |
1431 | | - relativePath, |
1432 | | - ...(stat === 1 ? readdirSyncRecursive(innerPath, origPath, options) : []), |
1433 | | - ]; |
1434 | | - }); |
| 1409 | +/** |
| 1410 | + * An iterative algorithm for reading the entire contents of the `basePath` directory. |
| 1411 | + * This function does not validate `basePath` as a directory. It is passed directly to |
| 1412 | + * `binding.readdir` after a `nullCheck`. |
| 1413 | + * @param {string} basePath |
| 1414 | + * @param {{ encoding: string, withFileTypes: boolean }} options |
| 1415 | + * @returns {string[] | Dirent[]} |
| 1416 | + */ |
| 1417 | +function readdirSyncRecursive(basePath, options) { |
| 1418 | + nullCheck(basePath, 'path', true); |
| 1419 | + |
| 1420 | + const withFileTypes = Boolean(options.withFileTypes); |
| 1421 | + const encoding = options.encoding; |
| 1422 | + |
| 1423 | + const readdirResults = []; |
| 1424 | + const pathsQueue = [basePath]; |
| 1425 | + |
| 1426 | + const ctx = { path: basePath }; |
| 1427 | + function read(path) { |
| 1428 | + ctx.path = path; |
| 1429 | + const readdirResult = binding.readdir( |
| 1430 | + pathModule.toNamespacedPath(path), |
| 1431 | + encoding, |
| 1432 | + withFileTypes, |
| 1433 | + undefined, |
| 1434 | + ctx, |
| 1435 | + ); |
| 1436 | + handleErrorFromBinding(ctx); |
| 1437 | + |
| 1438 | + for (let i = 0; i < readdirResult.length; i++) { |
| 1439 | + if (withFileTypes) { |
| 1440 | + const dirent = getDirent(path, readdirResult[0][i], readdirResult[1][i]); |
| 1441 | + ArrayPrototypePush(readdirResults, dirent); |
| 1442 | + if (dirent.isDirectory()) { |
| 1443 | + ArrayPrototypePush(pathsQueue, pathModule.join(dirent.path, dirent.name)); |
| 1444 | + } |
| 1445 | + } else { |
| 1446 | + const resultPath = pathModule.join(path, readdirResult[i]); |
| 1447 | + const relativeResultPath = pathModule.relative(basePath, resultPath); |
| 1448 | + const stat = binding.internalModuleStat(resultPath); |
| 1449 | + ArrayPrototypePush(readdirResults, relativeResultPath); |
| 1450 | + // 1 indicates directory |
| 1451 | + if (stat === 1) { |
| 1452 | + ArrayPrototypePush(pathsQueue, resultPath); |
| 1453 | + } |
| 1454 | + } |
| 1455 | + } |
| 1456 | + } |
| 1457 | + |
| 1458 | + for (let i = 0; i < pathsQueue.length; i++) { |
| 1459 | + read(pathsQueue[i]); |
| 1460 | + } |
| 1461 | + |
| 1462 | + return readdirResults; |
1435 | 1463 | } |
1436 | 1464 |
|
1437 | 1465 | /** |
@@ -1456,7 +1484,7 @@ function readdir(path, options, callback) { |
1456 | 1484 | } |
1457 | 1485 |
|
1458 | 1486 | if (options.recursive) { |
1459 | | - callback(null, readdirSyncRecursive(path, path, options)); |
| 1487 | + callback(null, readdirSyncRecursive(path, options)); |
1460 | 1488 | return; |
1461 | 1489 | } |
1462 | 1490 |
|
@@ -1494,7 +1522,7 @@ function readdirSync(path, options) { |
1494 | 1522 | } |
1495 | 1523 |
|
1496 | 1524 | if (options.recursive) { |
1497 | | - return readdirSyncRecursive(path, path, options); |
| 1525 | + return readdirSyncRecursive(path, options); |
1498 | 1526 | } |
1499 | 1527 |
|
1500 | 1528 | const ctx = { path }; |
|