@@ -36,6 +36,41 @@ const notImplemented: (...args: any[]) => any = () => {
3636
3737const noop : ( ...args : any [ ] ) => any = ( ) => { } ;
3838
39+ /** Lists a directory, descending into sub-directories when `recursive`. */
40+ const listDir = async (
41+ dir : fsa . IFileSystemDirectoryHandle ,
42+ parentPath : string ,
43+ recursive : boolean ,
44+ sort : boolean ,
45+ ) : Promise < FsaNodeDirent [ ] > => {
46+ const separator = FsaToNodeConstants . Separator ;
47+ const entries : [ name : string , handle : fsa . IFileSystemHandle ] [ ] = [ ] ;
48+ for await ( const entry of dir . entries ( ) ) entries . push ( entry ) ;
49+ if ( sort )
50+ entries . sort ( ( a , b ) => {
51+ if ( a [ 0 ] < b [ 0 ] ) return - 1 ;
52+ if ( a [ 0 ] > b [ 0 ] ) return 1 ;
53+ return 0 ;
54+ } ) ;
55+ const list : FsaNodeDirent [ ] = [ ] ;
56+ for ( const [ name , handle ] of entries ) {
57+ list . push ( new FsaNodeDirent ( name , parentPath , handle . kind ) ) ;
58+ if ( recursive && handle . kind === 'directory' ) {
59+ const childPath = parentPath === separator ? parentPath + name : parentPath + separator + name ;
60+ list . push ( ...( await listDir ( handle as fsa . IFileSystemDirectoryHandle , childPath , true , sort ) ) ) ;
61+ }
62+ }
63+ return list ;
64+ } ;
65+
66+ const direntToRelative = ( dirent : FsaNodeDirent , parentPath : string ) : string => {
67+ const separator = FsaToNodeConstants . Separator ;
68+ const name = String ( dirent . name ) ;
69+ if ( dirent . parentPath === parentPath ) return name ;
70+ const prefix = parentPath === separator ? parentPath : parentPath + separator ;
71+ return dirent . parentPath . slice ( prefix . length ) + separator + name ;
72+ } ;
73+
3974/**
4075 * Constructs a Node.js `fs` API from a File System Access API
4176 * [`FileSystemDirectoryHandle` object](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle).
@@ -461,29 +496,11 @@ export class FsaNodeFs extends FsaNodeCore implements FsCallbackApi, FsSynchrono
461496 this . getDir ( folder , false , 'readdir' )
462497 . then ( dir =>
463498 ( async ( ) => {
464- if ( options . withFileTypes ) {
465- const list : misc . IDirent [ ] = [ ] ;
466- const parentPath = folder . length ? '/' + folder . join ( FsaToNodeConstants . Separator ) : '/' ;
467- for await ( const [ name , handle ] of dir . entries ( ) ) {
468- const dirent = new FsaNodeDirent ( name , parentPath , handle . kind ) ;
469- list . push ( dirent ) ;
470- }
471- if ( ! isWin && options . encoding !== 'buffer' )
472- list . sort ( ( a , b ) => {
473- if ( a . name < b . name ) return - 1 ;
474- if ( a . name > b . name ) return 1 ;
475- return 0 ;
476- } ) ;
477- return list ;
478- } else {
479- const list : string [ ] = [ ] ;
480-
481- for await ( const key of dir . keys ( ) ) list . push ( key ) ;
482-
483- if ( ! isWin && options . encoding !== 'buffer' ) list . sort ( ) ;
484-
485- return list ;
486- }
499+ const parentPath = folder . length ? '/' + folder . join ( FsaToNodeConstants . Separator ) : '/' ;
500+ const sort = ! isWin && options . encoding !== 'buffer' ;
501+ const list = await listDir ( dir , parentPath , ! ! options . recursive , sort ) ;
502+ if ( options . withFileTypes ) return list ;
503+ return list . map ( dirent => direntToRelative ( dirent , parentPath ) ) ;
487504 } ) ( ) ,
488505 )
489506 . then (
@@ -1095,20 +1112,25 @@ export class FsaNodeFs extends FsaNodeCore implements FsCallbackApi, FsSynchrono
10951112 const filename = util . pathToFilename ( path ) ;
10961113 const [ folder ] = pathToLocation ( filename ) ;
10971114 const adapter = this . getSyncAdapter ( ) ;
1098- const list = adapter . call ( 'readdir' , [ filename ] ) ;
1099- if ( opts . withFileTypes ) {
1100- const res : misc . IDirent [ ] = [ ] ;
1101- const parentPath = folder . length ? '/' + folder . join ( FsaToNodeConstants . Separator ) : '/' ;
1102- for ( const entry of list ) res . push ( new FsaNodeDirent ( entry . name , parentPath , entry . kind ) ) ;
1103- return res ;
1104- } else {
1105- const res : misc . TDataOut [ ] = [ ] ;
1106- for ( const entry of list ) {
1107- const buffer = Buffer . from ( entry . name ) ;
1108- res . push ( util . bufferToEncoding ( buffer , opts . encoding ) ) ;
1115+ const separator = FsaToNodeConstants . Separator ;
1116+ const parentPath = folder . length ? separator + folder . join ( separator ) : separator ;
1117+ const walk = ( dir : string , at : string ) : FsaNodeDirent [ ] => {
1118+ const res : FsaNodeDirent [ ] = [ ] ;
1119+ for ( const entry of adapter . call ( 'readdir' , [ dir ] ) ) {
1120+ res . push ( new FsaNodeDirent ( entry . name , at , entry . kind ) ) ;
1121+ if ( opts . recursive && entry . kind === 'directory' )
1122+ res . push (
1123+ ...walk (
1124+ dir . endsWith ( separator ) ? dir + entry . name : dir + separator + entry . name ,
1125+ at === separator ? at + entry . name : at + separator + entry . name ,
1126+ ) ,
1127+ ) ;
11091128 }
11101129 return res ;
1111- }
1130+ } ;
1131+ const list = walk ( filename , parentPath ) ;
1132+ if ( opts . withFileTypes ) return list ;
1133+ return list . map ( dirent => util . bufferToEncoding ( Buffer . from ( direntToRelative ( dirent , parentPath ) ) , opts . encoding ) ) ;
11121134 } ;
11131135
11141136 public readonly realpathSync : FsSynchronousApi [ 'realpathSync' ] = (
0 commit comments