Skip to content

Commit

Permalink
feat: 🎸 add support for "recursive" and "force" flags in .rm()
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Sep 19, 2021
1 parent 2414fb6 commit 7f6714c
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 3 deletions.
94 changes: 94 additions & 0 deletions src/__tests__/volume/rmSync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,98 @@ describe('rmSync', () => {
'/oof': 'zab',
});
});

it('removes a single file', () => {
const vol = create({
'/a/b/c.txt': 'content',
});

vol.rmSync('/a/b/c.txt');

expect(vol.toJSON()).toEqual({
'/a/b': null,
});
});

describe('when file does not exist', () => {
it('throws by default', () => {
const vol = create({
'/foo.txt': 'content',
});

expect(() => vol.rmSync('/bar.txt')).toThrowError(new Error("ENOENT: no such file or directory, stat '/bar.txt'"));
});

it('does not throw if "force" is set to true', () => {
const vol = create({
'/foo.txt': 'content',
});

vol.rmSync('/bar.txt', {force: true});
});
});

describe('when deleting a directory', () => {
it('throws by default', () => {
const vol = create({
'/usr/bin/bash': '...',
});

expect(() => vol.rmSync('/usr/bin')).toThrowError(new Error("[ERR_FS_EISDIR]: Path is a directory: rm returned EISDIR (is a directory) /usr/bin"));
});

it('throws by when force flag is set', () => {
const vol = create({
'/usr/bin/bash': '...',
});

expect(() => vol.rmSync('/usr/bin', {force: true})).toThrowError(new Error("[ERR_FS_EISDIR]: Path is a directory: rm returned EISDIR (is a directory) /usr/bin"));
});

it('deletes all directory contents when recursive flag is set', () => {
const vol = create({
'/usr/bin/bash': '...',
});

vol.rmSync('/usr/bin', {recursive: true});

expect(vol.toJSON()).toEqual({'/usr': null});
});

it('deletes all directory contents recursively when recursive flag is set', () => {
const vol = create({
'/a/a/a': '1',
'/a/a/b': '2',
'/a/a/c': '3',
'/a/b/a': '4',
'/a/b/b': '5',
'/a/c/a': '6',
});

vol.rmSync('/a/a', {recursive: true});

expect(vol.toJSON()).toEqual({
'/a/b/a': '4',
'/a/b/b': '5',
'/a/c/a': '6',
});

vol.rmSync('/a/c', {recursive: true});

expect(vol.toJSON()).toEqual({
'/a/b/a': '4',
'/a/b/b': '5',
});

vol.rmSync('/a/b', {recursive: true});

expect(vol.toJSON()).toEqual({
'/a': null,
});

vol.rmSync('/a', {recursive: true});

expect(vol.toJSON()).toEqual({});
});
});
});
17 changes: 14 additions & 3 deletions src/volume.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const EACCES = 'EACCES';
const EISDIR = 'EISDIR';
const ENOTEMPTY = 'ENOTEMPTY';
const ENOSYS = 'ENOSYS';
const ERR_FS_EISDIR = 'ERR_FS_EISDIR';

function formatError(errorCode: string, func = '', path = '', path2 = '') {
let pathFormatted = '';
Expand Down Expand Up @@ -130,6 +131,8 @@ function formatError(errorCode: string, func = '', path = '', path2 = '') {
return `EMFILE: too many open files, ${func}${pathFormatted}`;
case ENOSYS:
return `ENOSYS: function not implemented, ${func}${pathFormatted}`;
case ERR_FS_EISDIR:
return `[ERR_FS_EISDIR]: Path is a directory: ${func} returned EISDIR (is a directory) ${path}`
default:
return `${errorCode}: error occurred, ${func}${pathFormatted}`;
}
Expand Down Expand Up @@ -1986,9 +1989,17 @@ export class Volume {
}

private rmBase(filename: string, options: IRmOptions = {}): void {
const force = !!options.force;
const recursive = !!options.recursive;
const link = this.getLinkAsDirOrThrow(filename, 'rm');
const link = this.getResolvedLink(filename);
if (!link) {
// "stat" is used to match Node's native error message.
if (!options.force) throw createError(ENOENT, 'stat', filename);
return;
}
if (link.getNode().isDirectory()) {
if (!options.recursive) {
throw createError(ERR_FS_EISDIR, 'rm', filename);
}
}
this.deleteLink(link);
}

Expand Down

0 comments on commit 7f6714c

Please sign in to comment.