@@ -24,6 +24,8 @@ const nextTick = (functionToCall: Function, args: any[] = []) => {
2424 process . nextTick ( ( ) => functionToCall ( ...args ) ) ;
2525} ;
2626
27+ const binding = internalBinding ( 'fs' ) ;
28+
2729// Cache asar archive objects.
2830const cachedArchives = new Map < string , NodeJS . AsarArchive > ( ) ;
2931
@@ -705,7 +707,87 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
705707 } ;
706708
707709 type ReaddirOptions = { encoding : BufferEncoding | null ; withFileTypes ?: false , recursive ?: false } | undefined | null ;
708- type ReaddirCallback = ( err : NodeJS . ErrnoException | null , files : string [ ] ) => void ;
710+ type ReaddirCallback = ( err : NodeJS . ErrnoException | null , files ?: string [ ] ) => void ;
711+
712+ const processReaddirResult = ( args : any ) => ( args . context . withFileTypes ? handleDirents ( args ) : handleFilePaths ( args ) ) ;
713+
714+ function handleDirents ( { result, currentPath, context } : { result : string [ ] , currentPath : string , context : any } ) {
715+ const { 0 : names , 1 : types } = result ;
716+ const { length } = names ;
717+
718+ for ( let i = 0 ; i < length ; i ++ ) {
719+ // Avoid excluding symlinks, as they are not directories.
720+ // Refs: https://github.com/nodejs/node/issues/52663
721+ const fullPath = path . join ( currentPath , names [ i ] ) ;
722+ const dirent = getDirent ( currentPath , names [ i ] , types [ i ] ) ;
723+ context . readdirResults . push ( dirent ) ;
724+
725+ if ( dirent . isDirectory ( ) || binding . internalModuleStat ( binding , fullPath ) === 1 ) {
726+ context . pathsQueue . push ( fullPath ) ;
727+ }
728+ }
729+ }
730+
731+ function handleFilePaths ( { result, currentPath, context } : { result : string [ ] , currentPath : string , context : any } ) {
732+ for ( let i = 0 ; i < result . length ; i ++ ) {
733+ const resultPath = path . join ( currentPath , result [ i ] ) ;
734+ const relativeResultPath = path . relative ( context . basePath , resultPath ) ;
735+ const stat = binding . internalModuleStat ( binding , resultPath ) ;
736+ context . readdirResults . push ( relativeResultPath ) ;
737+
738+ if ( stat === 1 ) {
739+ context . pathsQueue . push ( resultPath ) ;
740+ }
741+ }
742+ }
743+
744+ function readdirRecursive ( basePath : string , options : ReaddirOptions , callback : ReaddirCallback ) {
745+ const context = {
746+ withFileTypes : Boolean ( options ! . withFileTypes ) ,
747+ encoding : options ! . encoding ,
748+ basePath,
749+ readdirResults : [ ] ,
750+ pathsQueue : [ basePath ]
751+ } ;
752+
753+ let i = 0 ;
754+
755+ function read ( pathArg : string ) {
756+ const req = new binding . FSReqCallback ( ) ;
757+ req . oncomplete = ( err : any , result : any ) => {
758+ if ( err ) {
759+ callback ( err ) ;
760+ return ;
761+ }
762+
763+ if ( result === undefined ) {
764+ callback ( null , context . readdirResults ) ;
765+ return ;
766+ }
767+
768+ processReaddirResult ( {
769+ result,
770+ currentPath : pathArg ,
771+ context
772+ } ) ;
773+
774+ if ( i < context . pathsQueue . length ) {
775+ read ( context . pathsQueue [ i ++ ] ) ;
776+ } else {
777+ callback ( null , context . readdirResults ) ;
778+ }
779+ } ;
780+
781+ binding . readdir (
782+ pathArg ,
783+ context . encoding ,
784+ context . withFileTypes ,
785+ req
786+ ) ;
787+ }
788+
789+ read ( context . pathsQueue [ i ++ ] ) ;
790+ }
709791
710792 const { readdir } = fs ;
711793 fs . readdir = function ( pathArgument : string , options : ReaddirOptions , callback : ReaddirCallback ) {
@@ -720,7 +802,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
720802 }
721803
722804 if ( options ?. recursive ) {
723- nextTick ( callback ! , [ null , readdirSyncRecursive ( pathArgument , options ) ] ) ;
805+ readdirRecursive ( pathArgument , options , callback ) ;
724806 return ;
725807 }
726808
@@ -771,7 +853,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
771853 }
772854
773855 if ( options ?. recursive ) {
774- return readdirRecursive ( pathArgument , options ) ;
856+ return readdirRecursivePromises ( pathArgument , options ) ;
775857 }
776858
777859 const pathInfo = splitPath ( pathArgument ) ;
@@ -868,8 +950,6 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
868950 return readPackageJSON ( realPath , isESM , base , specifier ) ;
869951 } ;
870952
871- const binding = internalBinding ( 'fs' ) ;
872-
873953 const { internalModuleStat } = binding ;
874954 internalBinding ( 'fs' ) . internalModuleStat = ( receiver : unknown , pathArgument : string ) => {
875955 const pathInfo = splitPath ( pathArgument ) ;
@@ -888,7 +968,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
888968 } ;
889969
890970 const { kUsePromises } = binding ;
891- async function readdirRecursive ( originalPath : string , options : ReaddirOptions ) {
971+ async function readdirRecursivePromises ( originalPath : string , options : ReaddirOptions ) {
892972 const result : any [ ] = [ ] ;
893973
894974 const pathInfo = splitPath ( originalPath ) ;
@@ -992,11 +1072,13 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
9921072 }
9931073
9941074 function readdirSyncRecursive ( basePath : string , options : ReaddirOptions ) {
995- const withFileTypes = Boolean ( options ! . withFileTypes ) ;
996- const encoding = options ! . encoding ;
997-
998- const readdirResults : string [ ] = [ ] ;
999- const pathsQueue = [ basePath ] ;
1075+ const context = {
1076+ withFileTypes : Boolean ( options ! . withFileTypes ) ,
1077+ encoding : options ! . encoding ,
1078+ basePath,
1079+ readdirResults : [ ] as any ,
1080+ pathsQueue : [ basePath ]
1081+ } ;
10001082
10011083 function read ( pathArg : string ) {
10021084 let readdirResult ;
@@ -1011,7 +1093,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
10111093 if ( ! readdirResult ) return ;
10121094 // If we're in an asar dir, we need to ensure the result is in the same format as the
10131095 // native call to readdir withFileTypes i.e. an array of arrays.
1014- if ( withFileTypes ) {
1096+ if ( context . withFileTypes ) {
10151097 readdirResult = [
10161098 [ ...readdirResult ] , readdirResult . map ( ( p : string ) => {
10171099 return internalBinding ( 'fs' ) . internalModuleStat ( binding , path . join ( pathArg , p ) ) ;
@@ -1021,14 +1103,14 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
10211103 } else {
10221104 readdirResult = binding . readdir (
10231105 path . toNamespacedPath ( pathArg ) ,
1024- encoding ,
1025- withFileTypes
1106+ context . encoding ,
1107+ context . withFileTypes
10261108 ) ;
10271109 }
10281110
10291111 if ( readdirResult === undefined ) return ;
10301112
1031- if ( withFileTypes ) {
1113+ if ( context . withFileTypes ) {
10321114 const length = readdirResult [ 0 ] . length ;
10331115 for ( let i = 0 ; i < length ; i ++ ) {
10341116 const resultPath = path . join ( pathArg , readdirResult [ 0 ] [ i ] ) ;
@@ -1045,9 +1127,9 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
10451127
10461128 const dirent = getDirent ( pathArg , readdirResult [ 0 ] [ i ] , type ) ;
10471129
1048- readdirResults . push ( dirent ) ;
1130+ context . readdirResults . push ( dirent ) ;
10491131 if ( dirent . isDirectory ( ) ) {
1050- pathsQueue . push ( path . join ( dirent . path , dirent . name ) ) ;
1132+ context . pathsQueue . push ( path . join ( dirent . path , dirent . name ) ) ;
10511133 }
10521134 }
10531135 } else {
@@ -1056,17 +1138,17 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
10561138 const relativeResultPath = path . relative ( basePath , resultPath ) ;
10571139 const stat = internalBinding ( 'fs' ) . internalModuleStat ( binding , resultPath ) ;
10581140
1059- readdirResults . push ( relativeResultPath ) ;
1060- if ( stat === 1 ) pathsQueue . push ( resultPath ) ;
1141+ context . readdirResults . push ( relativeResultPath ) ;
1142+ if ( stat === 1 ) context . pathsQueue . push ( resultPath ) ;
10611143 }
10621144 }
10631145 }
10641146
1065- for ( let i = 0 ; i < pathsQueue . length ; i ++ ) {
1066- read ( pathsQueue [ i ] ) ;
1147+ for ( let i = 0 ; i < context . pathsQueue . length ; i ++ ) {
1148+ read ( context . pathsQueue [ i ] ) ;
10671149 }
10681150
1069- return readdirResults ;
1151+ return context . readdirResults ;
10701152 }
10711153
10721154 // Calling mkdir for directory inside asar archive should throw ENOTDIR
0 commit comments