diff --git a/src/fsa-to-node/FsaNodeFs.ts b/src/fsa-to-node/FsaNodeFs.ts index ac5735379..74cd713ac 100644 --- a/src/fsa-to-node/FsaNodeFs.ts +++ b/src/fsa-to-node/FsaNodeFs.ts @@ -3,6 +3,7 @@ import { getDefaultOptsAndCb, getMkdirOptions, getReadFileOptions, + getReaddirOptsAndCb, getRmOptsAndCb, getRmdirOptions, optsAndCbGenerator, @@ -288,29 +289,34 @@ export class FsaNodeFs implements FsCallbackApi { throw new Error('Not implemented'); } - readdir(path: misc.PathLike, callback: misc.TCallback); - readdir( - path: misc.PathLike, - options: opts.IReaddirOptions | string, - callback: misc.TCallback, - ); - readdir(path: misc.PathLike, a?, b?) { - throw new Error('Not implemented'); - } + public readonly readdir: FsCallbackApi['readdir'] = (path: misc.PathLike, a?, b?) => { + const [options, callback] = getReaddirOptsAndCb(a, b); + const filename = pathToFilename(path); + const [folder, name] = pathToLocation(filename); + folder.push(name); + this.getDir(folder, false, 'readdir') + .then(dir => (async () => { + const list: string[] = []; + for await (const key of dir.keys()) list.push(key); + return list; + })()) + .then(res => callback(null, res), err => callback(err)); + }; - readlink(path: misc.PathLike, callback: misc.TCallback); - readlink(path: misc.PathLike, options: opts.IOptions, callback: misc.TCallback); - readlink(path: misc.PathLike, a: misc.TCallback | opts.IOptions, b?: misc.TCallback) { - throw new Error('Not implemented'); - } + public readonly readlink: FsCallbackApi['readlink'] = (path: misc.PathLike, a: misc.TCallback | opts.IOptions, b?: misc.TCallback) => { + const [opts, callback] = getDefaultOptsAndCb(a, b); + const filename = pathToFilename(path); + const buffer = Buffer.from(filename); + callback(null, bufferToEncoding(buffer, opts.encoding)); + }; - fsync(fd: number, callback: misc.TCallback): void { - throw new Error('Not implemented'); - } + public readonly fsync: FsCallbackApi['fsync'] = (fd: number, callback: misc.TCallback): void => { + callback(null); + }; - fdatasync(fd: number, callback: misc.TCallback): void { - throw new Error('Not implemented'); - } + public readonly fdatasync: FsCallbackApi['fdatasync'] = (fd: number, callback: misc.TCallback): void => { + callback(null); + }; public readonly ftruncate: FsCallbackApi['ftruncate'] = (fd: number, a: misc.TCallback | number, b?: misc.TCallback): void => { const len: number = typeof a === 'number' ? a : 0; diff --git a/src/fsa-to-node/__tests__/FsaNodeFs.test.ts b/src/fsa-to-node/__tests__/FsaNodeFs.test.ts index c2c8924d5..4c0993717 100644 --- a/src/fsa-to-node/__tests__/FsaNodeFs.test.ts +++ b/src/fsa-to-node/__tests__/FsaNodeFs.test.ts @@ -262,3 +262,14 @@ describe('.ftruncate()', () => { expect(mfs.readFileSync('/mountpoint/folder/file', 'utf8')).toBe('tes'); }); }); + +describe('.readdir()', () => { + test('can read directory contents as strings', async () => { + const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const res = await fs.promises.readdir('/') as string[]; + expect(res.length).toBe(3); + expect(res.includes('folder')).toBe(true); + expect(res.includes('empty-folder')).toBe(true); + expect(res.includes('f.html')).toBe(true); + }); +}); diff --git a/src/node/options.ts b/src/node/options.ts index b581f2d48..3e7b08302 100644 --- a/src/node/options.ts +++ b/src/node/options.ts @@ -69,3 +69,10 @@ const readFileOptsDefaults: opts.IReadFileOptions = { flag: 'r', }; export const getReadFileOptions = optsGenerator(readFileOptsDefaults); + +const readdirDefaults: opts.IReaddirOptions = { + encoding: 'utf8', + withFileTypes: false, +}; +export const getReaddirOptions = optsGenerator(readdirDefaults); +export const getReaddirOptsAndCb = optsAndCbGenerator(getReaddirOptions); diff --git a/src/volume.ts b/src/volume.ts index dbeca60d3..c177348f8 100644 --- a/src/volume.ts +++ b/src/volume.ts @@ -20,6 +20,8 @@ import { getMkdirOptions, getOptions, getReadFileOptions, + getReaddirOptions, + getReaddirOptsAndCb, getRmOptsAndCb, getRmdirOptions, optsAndCbGenerator, @@ -179,12 +181,6 @@ export interface IMkdirOptions { export interface IReaddirOptions extends opts.IOptions { withFileTypes?: boolean; } -const readdirDefaults: IReaddirOptions = { - encoding: 'utf8', - withFileTypes: false, -}; -const getReaddirOptions = optsGenerator(readdirDefaults); -const getReaddirOptsAndCb = optsAndCbGenerator(getReaddirOptions); // Options for `fs.lstat`, `fs.lstatSync`, `fs.stat`, and `fs.statSync` export interface IStatOptions { @@ -470,10 +466,6 @@ export class Volume { return node; } - private getNode(ino: number) { - return this.inodes[ino]; - } - private deleteNode(node: Node) { node.del(); delete this.inodes[node.ino];