diff --git a/src/__tests__/volume.test.ts b/src/__tests__/volume.test.ts index cc7fd074..416e5f4f 100644 --- a/src/__tests__/volume.test.ts +++ b/src/__tests__/volume.test.ts @@ -954,6 +954,12 @@ describe('volume', () => { vol.rmdirSync('/dir'); expect(!!vol.root.getChild('dir')).toBe(false); }); + it('Remove dir /dir1/dir2/dir3 recursively', () => { + const vol = new Volume(); + vol.mkdirSync('/dir1/dir2/dir3', { recursive: true }); + vol.rmdirSync('/dir1', { recursive: true }); + expect(!!vol.root.getChild('/dir1')).toBe(false); + }); }); describe('.rmdir(path, callback)', () => { xit('Remove single dir', () => {}); diff --git a/src/volume.ts b/src/volume.ts index 2fd63950..39916dc4 100644 --- a/src/volume.ts +++ b/src/volume.ts @@ -342,6 +342,17 @@ const getMkdirOptions = (options): IMkdirOptions => { return extend({}, mkdirDefaults, options); }; +// Options for `fs.rmdir` and `fs.rmdirSync` +export interface IRmdirOptions { + recursive?: boolean; +} +const rmdirDefaults: IRmdirOptions = { + recursive: false, +}; +const getRmdirOptions = (options): IRmdirOptions => { + return extend({}, rmdirDefaults, options); +}; + // Options for `fs.readdir` and `fs.readdirSync` export interface IReaddirOptions extends IOptions { withFileTypes?: boolean; @@ -1901,20 +1912,25 @@ export class Volume { this.wrapAsync(this.mkdtempBase, [prefix, encoding], callback); } - private rmdirBase(filename: string) { + private rmdirBase(filename: string, options?: IRmdirOptions) { + const opts = getRmdirOptions(options); const link = this.getLinkAsDirOrThrow(filename, 'rmdir'); // Check directory is empty. - if (link.length) throw createError(ENOTEMPTY, 'rmdir', filename); + if (link.length && !opts.recursive) throw createError(ENOTEMPTY, 'rmdir', filename); this.deleteLink(link); } - rmdirSync(path: TFilePath) { - this.rmdirBase(pathToFilename(path)); + rmdirSync(path: TFilePath, options?: IRmdirOptions) { + this.rmdirBase(pathToFilename(path), options); } - rmdir(path: TFilePath, callback: TCallback) { + rmdir(path: TFilePath, callback: TCallback); + rmdir(path: TFilePath, options: IRmdirOptions, callback: TCallback); + rmdir(path: TFilePath, a: TCallback | IRmdirOptions, b?: TCallback) { + const opts: IRmdirOptions = getRmdirOptions(a); + const callback: TCallback = validateCallback(typeof a === 'function' ? a : b); this.wrapAsync(this.rmdirBase, [pathToFilename(path)], callback); }