Skip to content

Commit

Permalink
add filter option
Browse files Browse the repository at this point in the history
Re: #140
Fix: #160
  • Loading branch information
isaacs committed Mar 4, 2023
1 parent e828fe2 commit ed3288e
Show file tree
Hide file tree
Showing 19 changed files with 793 additions and 177 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 4.3

- Return boolean indicating whether the path was fully removed
- Add filter option

# v4.2

- Brought back `glob` support, using the new and improved glob v9
Expand Down
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Install with `npm install rimraf`.
resolve the situation.
- Simplified implementation on Posix, since the Windows
affordances are not necessary there.
- As of 4.3, return/resolve value is boolean instead of undefined

## API

Expand All @@ -32,6 +33,12 @@ import { rimraf, rimrafSync, native, nativeSync } from 'rimraf'
const { rimraf, rimrafSync, native, nativeSync } = require('rimraf')
```

All removal functions return a boolean indicating that all
entries were successfully removed.

The only case in which this will not return `true` is if
something was omitted from the removal via a `filter` option.

### `rimraf(f, [opts]) -> Promise`

This first parameter is a path or array of paths. The second
Expand Down Expand Up @@ -64,9 +71,24 @@ Options:
linear backoff. Default `100`.
- `signal` Pass in an AbortSignal to cancel the directory
removal. This is useful when removing large folder structures,
if you'd like to limit the amount of time spent. Using a
`signal` option prevents the use of Node's built-in `fs.rm`
because that implementation does not support abort signals.
if you'd like to limit the amount of time spent.

Using a `signal` option prevents the use of Node's built-in
`fs.rm` because that implementation does not support abort
signals.

- `filter` Method that receives a path string as an argument, and
returns a boolean indicating whether that path should be
deleted.

If a filter method is provided, it _must_ return a truthy
value, or nothing will be removed. Filtering out a directory
will still allow its children to be removed, unless they are
also filtered out, but any parents of a filtered entry will not
be removed.

Using a filter method prevents the use of Node's built-in
`fs.rm` because that implementation does not support filtering.

Any other options are provided to the native Node.js `fs.rm` implementation
when that is used.
Expand Down
2 changes: 1 addition & 1 deletion libtap-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ const rimraf = require('./')
module.exports = {
rmdirRecursiveSync: path => rimraf.sync(path),
rmdirRecursive(path, cb) {
rimraf(path).then(cb, cb)
rimraf(path, {}).then(() => cb(), cb)
},
}
128 changes: 69 additions & 59 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"eslint-config-prettier": "^8.6.0",
"mkdirp": "1",
"prettier": "^2.8.2",
"tap": "^16.3.3",
"tap": "^16.3.4",
"ts-node": "^10.9.1",
"typedoc": "^0.23.21",
"typescript": "^4.9.3"
Expand Down
2 changes: 1 addition & 1 deletion src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const main = async (...args: string[]) => {
const opt: RimrafOptions = {}
const paths: string[] = []
let dashdash = false
let impl: (path: string | string[], opt?: RimrafOptions) => Promise<void> =
let impl: (path: string | string[], opt?: RimrafOptions) => Promise<boolean> =
rimraf

for (const arg of args) {
Expand Down
32 changes: 21 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface RimrafOptions {
maxBackoff?: number
signal?: AbortSignal
glob?: boolean | GlobOptions
filter?: (path: string) => boolean
}

const typeOrUndef = (val: any, t: string) =>
Expand All @@ -26,7 +27,8 @@ export const isRimrafOptions = (o: any): o is RimrafOptions =>
typeOrUndef(o.retryDelay, 'number') &&
typeOrUndef(o.backoff, 'number') &&
typeOrUndef(o.maxBackoff, 'number') &&
(typeOrUndef(o.glob, 'boolean') || (o.glob && typeof o.glob === 'object'))
(typeOrUndef(o.glob, 'boolean') || (o.glob && typeof o.glob === 'object')) &&
typeOrUndef(o.filter, 'function')

export const assertRimrafOptions: (o: any) => void = (
o: any
Expand All @@ -44,27 +46,35 @@ import { rimrafWindows, rimrafWindowsSync } from './rimraf-windows.js'
import { useNative, useNativeSync } from './use-native.js'

const wrap =
(fn: (p: string, o: RimrafOptions) => Promise<void>) =>
async (path: string | string[], opt?: RimrafOptions): Promise<void> => {
(fn: (p: string, o: RimrafOptions) => Promise<boolean>) =>
async (path: string | string[], opt?: RimrafOptions): Promise<boolean> => {
const options = optArg(opt)
if (options.glob) {
path = await glob(path, options.glob)
}
await (Array.isArray(path)
? Promise.all(path.map(p => fn(pathArg(p, options), options)))
: fn(pathArg(path, options), options))
if (Array.isArray(path)) {
return !!(
await Promise.all(path.map(p => fn(pathArg(p, options), options)))
).reduce((a, b) => a && b, true)
} else {
return !!(await fn(pathArg(path, options), options))
}
}

const wrapSync =
(fn: (p: string, o: RimrafOptions) => void) =>
(path: string | string[], opt?: RimrafOptions): void => {
(fn: (p: string, o: RimrafOptions) => boolean) =>
(path: string | string[], opt?: RimrafOptions): boolean => {
const options = optArg(opt)
if (options.glob) {
path = globSync(path, options.glob)
}
return Array.isArray(path)
? path.forEach(p => fn(pathArg(p, options), options))
: fn(pathArg(path, options), options)
if (Array.isArray(path)) {
return !!path
.map(p => fn(pathArg(p, options), options))
.reduce((a, b) => a && b, true)
} else {
return !!fn(pathArg(path, options), options)
}
}

export const nativeSync = wrapSync(rimrafNativeSync)
Expand Down
Loading

0 comments on commit ed3288e

Please sign in to comment.