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