@@ -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