diff --git a/README.md b/README.md index 1e0b5c98..4d4e9b27 100644 --- a/README.md +++ b/README.md @@ -79,13 +79,17 @@ Options: - `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. + deleted. With async rimraf methods, this may return a Promise + that resolves to a boolean. (Since Promises are truthy, + returning a Promise from a sync filter is the same as just not + filtering anything.) + + If a filter method is provided, it will _only_ remove entries + if the filter returns (or resolves to) a truthy value. Omitting + 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, since the directory would not be empty in + that case. Using a filter method prevents the use of Node's built-in `fs.rm` because that implementation does not support filtering. diff --git a/src/index.ts b/src/index.ts index 7d845f18..3c5443ca 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,9 @@ -import optArg from './opt-arg.js' +import { optArg, optArgSync } from './opt-arg.js' import pathArg from './path-arg.js' import { glob, GlobOptions, globSync } from 'glob' -export interface RimrafOptions { +export interface RimrafAsyncOptions { preserveRoot?: boolean tmp?: string maxRetries?: number @@ -12,9 +12,15 @@ export interface RimrafOptions { maxBackoff?: number signal?: AbortSignal glob?: boolean | GlobOptions + filter?: ((path: string) => boolean) | ((path: string) => Promise) +} + +export interface RimrafSyncOptions extends RimrafAsyncOptions { filter?: (path: string) => boolean } +export type RimrafOptions = RimrafSyncOptions | RimrafAsyncOptions + const typeOrUndef = (val: any, t: string) => typeof val === 'undefined' || typeof val === t @@ -46,8 +52,11 @@ import { rimrafWindows, rimrafWindowsSync } from './rimraf-windows.js' import { useNative, useNativeSync } from './use-native.js' const wrap = - (fn: (p: string, o: RimrafOptions) => Promise) => - async (path: string | string[], opt?: RimrafOptions): Promise => { + (fn: (p: string, o: RimrafAsyncOptions) => Promise) => + async ( + path: string | string[], + opt?: RimrafAsyncOptions + ): Promise => { const options = optArg(opt) if (options.glob) { path = await glob(path, options.glob) @@ -62,9 +71,9 @@ const wrap = } const wrapSync = - (fn: (p: string, o: RimrafOptions) => boolean) => - (path: string | string[], opt?: RimrafOptions): boolean => { - const options = optArg(opt) + (fn: (p: string, o: RimrafSyncOptions) => boolean) => + (path: string | string[], opt?: RimrafSyncOptions): boolean => { + const options = optArgSync(opt) if (options.glob) { path = globSync(path, options.glob) } diff --git a/src/opt-arg.ts b/src/opt-arg.ts index b2f7e61a..a9473c51 100644 --- a/src/opt-arg.ts +++ b/src/opt-arg.ts @@ -1,13 +1,23 @@ import { GlobOptions } from 'glob' -import { assertRimrafOptions, RimrafOptions } from './index.js' -export default ( - opt: RimrafOptions = {} -): RimrafOptions & { - glob?: GlobOptions & { withFileTypes: false } -} => { +import { + assertRimrafOptions, + RimrafAsyncOptions, + RimrafOptions, + RimrafSyncOptions, +} from './index.js' + +const optArgT = ( + opt: T +): + | (T & { + glob: GlobOptions & { withFileTypes: false } + }) + | (T & { glob: undefined }) => { assertRimrafOptions(opt) const { glob, ...options } = opt - if (!glob) return options + if (!glob) { + return options as T & { glob: undefined } + } const globOpt = glob === true ? opt.signal @@ -28,5 +38,8 @@ export default ( absolute: true, withFileTypes: false, }, - } + } as T & { glob: GlobOptions & { withFileTypes: false } } } + +export const optArg = (opt: RimrafAsyncOptions = {}) => optArgT(opt) +export const optArgSync = (opt: RimrafSyncOptions = {}) => optArgT(opt) diff --git a/src/path-arg.ts b/src/path-arg.ts index 4adaf5e8..68ca4403 100644 --- a/src/path-arg.ts +++ b/src/path-arg.ts @@ -1,9 +1,9 @@ -import platform from './platform.js' -import { resolve, parse } from 'path' +import { parse, resolve } from 'path' import { inspect } from 'util' -import { RimrafOptions } from './index.js' +import { RimrafAsyncOptions } from './index.js' +import platform from './platform.js' -const pathArg = (path: string, opt: RimrafOptions = {}) => { +const pathArg = (path: string, opt: RimrafAsyncOptions = {}) => { const type = typeof path if (type !== 'string') { const ctor = path && type === 'object' && path.constructor diff --git a/src/retry-busy.ts b/src/retry-busy.ts index 5f2eb3c6..0c09890f 100644 --- a/src/retry-busy.ts +++ b/src/retry-busy.ts @@ -1,6 +1,6 @@ // note: max backoff is the maximum that any *single* backoff will do -import { RimrafOptions } from '.' +import { RimrafAsyncOptions, RimrafOptions } from '.' export const MAXBACKOFF = 200 export const RATE = 1.2 @@ -10,7 +10,7 @@ export const codes = new Set(['EMFILE', 'ENFILE', 'EBUSY']) export const retryBusy = (fn: (path: string) => Promise) => { const method = async ( path: string, - opt: RimrafOptions, + opt: RimrafAsyncOptions, backoff = 1, total = 0 ) => { diff --git a/src/rimraf-move-remove.ts b/src/rimraf-move-remove.ts index a28262ed..2cac797b 100644 --- a/src/rimraf-move-remove.ts +++ b/src/rimraf-move-remove.ts @@ -25,7 +25,7 @@ import { } from './fs.js' const { rename, unlink, rmdir, chmod } = fsPromises -import { RimrafOptions } from '.' +import { RimrafAsyncOptions, RimrafSyncOptions } from '.' import { readdirOrError, readdirOrErrorSync } from './readdir-or-error.js' // crypto.randomBytes is much slower, and Math.random() is enough here @@ -71,7 +71,7 @@ const unlinkFixEPERMSync = (path: string) => { export const rimrafMoveRemove = async ( path: string, - opt: RimrafOptions + opt: RimrafAsyncOptions ): Promise => { if (opt?.signal?.aborted) { throw opt.signal.reason @@ -91,7 +91,7 @@ export const rimrafMoveRemove = async ( if (entries.code !== 'ENOTDIR') { throw entries } - if (opt.filter && !opt.filter(path)) { + if (opt.filter && !(await opt.filter(path))) { return false } await ignoreENOENT(tmpUnlink(path, opt.tmp, unlinkFixEPERM)) @@ -113,7 +113,7 @@ export const rimrafMoveRemove = async ( if (opt.preserveRoot === false && path === parse(path).root) { return false } - if (opt.filter && !opt.filter(path)) { + if (opt.filter && !(await opt.filter(path))) { return false } await ignoreENOENT(tmpUnlink(path, opt.tmp, rmdir)) @@ -132,7 +132,7 @@ const tmpUnlink = async ( export const rimrafMoveRemoveSync = ( path: string, - opt: RimrafOptions + opt: RimrafSyncOptions ): boolean => { if (opt?.signal?.aborted) { throw opt.signal.reason diff --git a/src/rimraf-native.ts b/src/rimraf-native.ts index 47e2bc34..4e793943 100644 --- a/src/rimraf-native.ts +++ b/src/rimraf-native.ts @@ -1,10 +1,10 @@ -import { RimrafOptions } from '.' +import { RimrafAsyncOptions, RimrafSyncOptions } from '.' import { promises, rmSync } from './fs.js' const { rm } = promises export const rimrafNative = async ( path: string, - opt: RimrafOptions + opt: RimrafAsyncOptions ): Promise => { await rm(path, { ...opt, @@ -14,7 +14,10 @@ export const rimrafNative = async ( return true } -export const rimrafNativeSync = (path: string, opt: RimrafOptions): boolean => { +export const rimrafNativeSync = ( + path: string, + opt: RimrafSyncOptions +): boolean => { rmSync(path, { ...opt, force: true, diff --git a/src/rimraf-posix.ts b/src/rimraf-posix.ts index 6fa79e2e..a4a4c69a 100644 --- a/src/rimraf-posix.ts +++ b/src/rimraf-posix.ts @@ -12,12 +12,12 @@ import { parse, resolve } from 'path' import { readdirOrError, readdirOrErrorSync } from './readdir-or-error.js' -import { RimrafOptions } from '.' +import { RimrafAsyncOptions, RimrafSyncOptions } from '.' import { ignoreENOENT, ignoreENOENTSync } from './ignore-enoent.js' export const rimrafPosix = async ( path: string, - opt: RimrafOptions + opt: RimrafAsyncOptions ): Promise => { if (opt?.signal?.aborted) { throw opt.signal.reason @@ -30,7 +30,7 @@ export const rimrafPosix = async ( if (entries.code !== 'ENOTDIR') { throw entries } - if (opt.filter && !opt.filter(path)) { + if (opt.filter && !(await opt.filter(path))) { return false } await ignoreENOENT(unlink(path)) @@ -54,7 +54,7 @@ export const rimrafPosix = async ( return false } - if (opt.filter && !opt.filter(path)) { + if (opt.filter && !(await opt.filter(path))) { return false } @@ -62,7 +62,10 @@ export const rimrafPosix = async ( return true } -export const rimrafPosixSync = (path: string, opt: RimrafOptions): boolean => { +export const rimrafPosixSync = ( + path: string, + opt: RimrafSyncOptions +): boolean => { if (opt?.signal?.aborted) { throw opt.signal.reason } @@ -84,11 +87,11 @@ export const rimrafPosixSync = (path: string, opt: RimrafOptions): boolean => { for (const entry of entries) { removedAll = rimrafPosixSync(resolve(path, entry), opt) && removedAll } - if (!removedAll) { + if (opt.preserveRoot === false && path === parse(path).root) { return false } - if (opt.preserveRoot === false && path === parse(path).root) { + if (!removedAll) { return false } diff --git a/src/rimraf-windows.ts b/src/rimraf-windows.ts index 68728f08..8582a1b5 100644 --- a/src/rimraf-windows.ts +++ b/src/rimraf-windows.ts @@ -9,7 +9,7 @@ // Note: "move then remove" is 2-10 times slower, and just as unreliable. import { parse, resolve } from 'path' -import { RimrafOptions } from '.' +import { RimrafAsyncOptions, RimrafSyncOptions } from '.' import { fixEPERM, fixEPERMSync } from './fix-eperm.js' import { promises, rmdirSync, unlinkSync } from './fs.js' import { ignoreENOENT, ignoreENOENTSync } from './ignore-enoent.js' @@ -25,7 +25,7 @@ const rimrafWindowsDirSync = retryBusySync(fixEPERMSync(rmdirSync)) const rimrafWindowsDirMoveRemoveFallback = async ( path: string, - opt: RimrafOptions + opt: RimrafAsyncOptions ): Promise => { /* c8 ignore start */ if (opt?.signal?.aborted) { @@ -46,7 +46,7 @@ const rimrafWindowsDirMoveRemoveFallback = async ( const rimrafWindowsDirMoveRemoveFallbackSync = ( path: string, - opt: RimrafOptions + opt: RimrafSyncOptions ): boolean => { if (opt?.signal?.aborted) { throw opt.signal.reason @@ -71,7 +71,7 @@ const states = new Set([START, CHILD, FINISH]) export const rimrafWindows = async ( path: string, - opt: RimrafOptions, + opt: RimrafAsyncOptions, state = START ): Promise => { if (opt?.signal?.aborted) { @@ -89,7 +89,7 @@ export const rimrafWindows = async ( if (entries.code !== 'ENOTDIR') { throw entries } - if (opt.filter && !opt.filter(path)) { + if (opt.filter && !(await opt.filter(path))) { return false } // is a file @@ -110,10 +110,10 @@ export const rimrafWindows = async ( if (opt.preserveRoot === false && path === parse(path).root) { return false } - if (opt.filter && !opt.filter(path)) { + if (!removedAll) { return false } - if (!removedAll) { + if (opt.filter && !(await opt.filter(path))) { return false } await ignoreENOENT(rimrafWindowsDirMoveRemoveFallback(path, opt)) @@ -123,7 +123,7 @@ export const rimrafWindows = async ( export const rimrafWindowsSync = ( path: string, - opt: RimrafOptions, + opt: RimrafSyncOptions, state = START ): boolean => { if (!states.has(state)) { @@ -158,10 +158,10 @@ export const rimrafWindowsSync = ( if (opt.preserveRoot === false && path === parse(path).root) { return false } - if (opt.filter && !opt.filter(path)) { + if (!removedAll) { return false } - if (!removedAll) { + if (opt.filter && !opt.filter(path)) { return false } ignoreENOENTSync(() => { diff --git a/src/use-native.ts b/src/use-native.ts index 76f47e55..915784e3 100644 --- a/src/use-native.ts +++ b/src/use-native.ts @@ -1,11 +1,11 @@ const version = process.env.__TESTING_RIMRAF_NODE_VERSION__ || process.version const versArr = version.replace(/^v/, '').split('.') const hasNative = +versArr[0] > 14 || (+versArr[0] === 14 && +versArr[1] >= 14) -import { RimrafOptions } from './index.js' +import { RimrafAsyncOptions, RimrafOptions } from './index.js' // we do NOT use native by default on Windows, because Node's native // rm implementation is less advanced. Change this code if that changes. import platform from './platform.js' -export const useNative: (opt?: RimrafOptions) => boolean = +export const useNative: (opt?: RimrafAsyncOptions) => boolean = !hasNative || platform === 'win32' ? () => false : opt => !opt?.signal && !opt?.filter diff --git a/tap-snapshots/test/rimraf-move-remove.js.test.cjs b/tap-snapshots/test/rimraf-move-remove.js.test.cjs index c6e8d882..def1c0c4 100644 --- a/tap-snapshots/test/rimraf-move-remove.js.test.cjs +++ b/tap-snapshots/test/rimraf-move-remove.js.test.cjs @@ -23,6 +23,24 @@ Array [ ] ` +exports[`test/rimraf-move-remove.js TAP filter function filter=i async filter > paths seen 1`] = ` +Array [ + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/a", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/b", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/c/d", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/c/e", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/c/f/g", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/c/f/h", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/c/f/i", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/c/f/i/j", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/c/f/i/k", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/c/f/i/l", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/c/f/i/m", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/c/f/i/m/n", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-async-filter/c/f/i/m/o", +] +` + exports[`test/rimraf-move-remove.js TAP filter function filter=i sync > paths seen 1`] = ` Array [ "test/tap-testdir-rimraf-move-remove-filter-function-filter-i-sync/a", @@ -58,6 +76,23 @@ Array [ ] ` +exports[`test/rimraf-move-remove.js TAP filter function filter=j async filter > paths seen 1`] = ` +Array [ + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/a", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/b", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/c/d", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/c/e", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/c/f/g", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/c/f/h", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/c/f/i/j", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/c/f/i/k", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/c/f/i/l", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/c/f/i/m", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/c/f/i/m/n", + "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-async-filter/c/f/i/m/o", +] +` + exports[`test/rimraf-move-remove.js TAP filter function filter=j sync > paths seen 1`] = ` Array [ "test/tap-testdir-rimraf-move-remove-filter-function-filter-j-sync/a", diff --git a/tap-snapshots/test/rimraf-posix.js.test.cjs b/tap-snapshots/test/rimraf-posix.js.test.cjs index 93ae5152..97c449bb 100644 --- a/tap-snapshots/test/rimraf-posix.js.test.cjs +++ b/tap-snapshots/test/rimraf-posix.js.test.cjs @@ -23,6 +23,24 @@ Array [ ] ` +exports[`test/rimraf-posix.js TAP filter function filter=i async filter > paths seen 1`] = ` +Array [ + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/a", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/b", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/c/d", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/c/e", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/c/f/g", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/c/f/h", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/c/f/i", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/c/f/i/j", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/c/f/i/k", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/c/f/i/l", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/c/f/i/m", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/c/f/i/m/n", + "test/tap-testdir-rimraf-posix-filter-function-filter-i-async-filter/c/f/i/m/o", +] +` + exports[`test/rimraf-posix.js TAP filter function filter=i sync > paths seen 1`] = ` Array [ "test/tap-testdir-rimraf-posix-filter-function-filter-i-sync/a", @@ -58,6 +76,23 @@ Array [ ] ` +exports[`test/rimraf-posix.js TAP filter function filter=j async filter > paths seen 1`] = ` +Array [ + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/a", + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/b", + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/c/d", + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/c/e", + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/c/f/g", + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/c/f/h", + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/c/f/i/j", + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/c/f/i/k", + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/c/f/i/l", + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/c/f/i/m", + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/c/f/i/m/n", + "test/tap-testdir-rimraf-posix-filter-function-filter-j-async-filter/c/f/i/m/o", +] +` + exports[`test/rimraf-posix.js TAP filter function filter=j sync > paths seen 1`] = ` Array [ "test/tap-testdir-rimraf-posix-filter-function-filter-j-sync/a", diff --git a/tap-snapshots/test/rimraf-windows.js.test.cjs b/tap-snapshots/test/rimraf-windows.js.test.cjs index 3c85c6c0..92cd6a42 100644 --- a/tap-snapshots/test/rimraf-windows.js.test.cjs +++ b/tap-snapshots/test/rimraf-windows.js.test.cjs @@ -7,13 +7,10 @@ 'use strict' exports[`test/rimraf-windows.js TAP filter function filter=i async > paths seen 1`] = ` Array [ - "test/tap-testdir-rimraf-windows-filter-function-filter-i-async", "test/tap-testdir-rimraf-windows-filter-function-filter-i-async/a", "test/tap-testdir-rimraf-windows-filter-function-filter-i-async/b", - "test/tap-testdir-rimraf-windows-filter-function-filter-i-async/c", "test/tap-testdir-rimraf-windows-filter-function-filter-i-async/c/d", "test/tap-testdir-rimraf-windows-filter-function-filter-i-async/c/e", - "test/tap-testdir-rimraf-windows-filter-function-filter-i-async/c/f", "test/tap-testdir-rimraf-windows-filter-function-filter-i-async/c/f/g", "test/tap-testdir-rimraf-windows-filter-function-filter-i-async/c/f/h", "test/tap-testdir-rimraf-windows-filter-function-filter-i-async/c/f/i", @@ -26,15 +23,30 @@ Array [ ] ` +exports[`test/rimraf-windows.js TAP filter function filter=i async filter > paths seen 1`] = ` +Array [ + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/a", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/b", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/c/d", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/c/e", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/c/f/g", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/c/f/h", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/c/f/i", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/c/f/i/j", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/c/f/i/k", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/c/f/i/l", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/c/f/i/m", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/c/f/i/m/n", + "test/tap-testdir-rimraf-windows-filter-function-filter-i-async-filter/c/f/i/m/o", +] +` + exports[`test/rimraf-windows.js TAP filter function filter=i sync > paths seen 1`] = ` Array [ - "test/tap-testdir-rimraf-windows-filter-function-filter-i-sync", "test/tap-testdir-rimraf-windows-filter-function-filter-i-sync/a", "test/tap-testdir-rimraf-windows-filter-function-filter-i-sync/b", - "test/tap-testdir-rimraf-windows-filter-function-filter-i-sync/c", "test/tap-testdir-rimraf-windows-filter-function-filter-i-sync/c/d", "test/tap-testdir-rimraf-windows-filter-function-filter-i-sync/c/e", - "test/tap-testdir-rimraf-windows-filter-function-filter-i-sync/c/f", "test/tap-testdir-rimraf-windows-filter-function-filter-i-sync/c/f/g", "test/tap-testdir-rimraf-windows-filter-function-filter-i-sync/c/f/h", "test/tap-testdir-rimraf-windows-filter-function-filter-i-sync/c/f/i", @@ -49,16 +61,12 @@ Array [ exports[`test/rimraf-windows.js TAP filter function filter=j async > paths seen 1`] = ` Array [ - "test/tap-testdir-rimraf-windows-filter-function-filter-j-async", "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/a", "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/b", - "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/c", "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/c/d", "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/c/e", - "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/c/f", "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/c/f/g", "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/c/f/h", - "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/c/f/i", "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/c/f/i/j", "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/c/f/i/j", "test/tap-testdir-rimraf-windows-filter-function-filter-j-async/c/f/i/k", @@ -69,18 +77,32 @@ Array [ ] ` +exports[`test/rimraf-windows.js TAP filter function filter=j async filter > paths seen 1`] = ` +Array [ + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/a", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/b", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/c/d", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/c/e", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/c/f/g", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/c/f/h", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/c/f/i/j", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/c/f/i/j", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/c/f/i/k", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/c/f/i/l", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/c/f/i/m", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/c/f/i/m/n", + "test/tap-testdir-rimraf-windows-filter-function-filter-j-async-filter/c/f/i/m/o", +] +` + exports[`test/rimraf-windows.js TAP filter function filter=j sync > paths seen 1`] = ` Array [ - "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync", "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/a", "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/b", - "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/c", "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/c/d", "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/c/e", - "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/c/f", "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/c/f/g", "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/c/f/h", - "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/c/f/i", "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/c/f/i/j", "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/c/f/i/j", "test/tap-testdir-rimraf-windows-filter-function-filter-j-sync/c/f/i/k", diff --git a/test/index.js b/test/index.js index ddac1778..ca23438f 100644 --- a/test/index.js +++ b/test/index.js @@ -37,9 +37,15 @@ t.test('mocky unit tests to select the correct function', t => { CALLS.push(['pathArg', path]) return path }, - '../dist/cjs/src/opt-arg.js': opt => { - CALLS.push(['optArg', opt]) - return opt + '../dist/cjs/src/opt-arg.js': { + optArg: opt => { + CALLS.push(['optArg', opt]) + return opt + }, + optArgSync: opt => { + CALLS.push(['optArg', opt]) + return opt + }, }, '../dist/cjs/src/rimraf-posix.js': { rimrafPosix: async (path, opt) => { diff --git a/test/opt-arg.js b/test/opt-arg.js index 13880255..fc08e367 100644 --- a/test/opt-arg.js +++ b/test/opt-arg.js @@ -1,13 +1,15 @@ const t = require('tap') -const optArg = require('../dist/cjs/src/opt-arg.js').default +const { optArg: oa, optArgSync: oas } = require('../dist/cjs/src/opt-arg.js') const opt = { a: 1 } -t.same(optArg(opt), opt, 'returns equivalent object if provided') -t.same(optArg(), {}, 'returns new object otherwise') -t.throws(() => optArg(true)) -t.throws(() => optArg(null)) -t.throws(() => optArg('hello')) -t.throws(() => optArg({ maxRetries: 'banana' })) +t.same(oa(opt), opt, 'returns equivalent object if provided') +t.same(oas(opt), oa(opt), 'optArgSync does the same thing') +t.same(oa(), {}, 'returns new object otherwise') + +t.throws(() => oa(true)) +t.throws(() => oa(null)) +t.throws(() => oa('hello')) +t.throws(() => oa({ maxRetries: 'banana' })) t.test('every kind of invalid option value', t => { // skip them when it's undefined, and skip the case @@ -33,7 +35,7 @@ t.test('every kind of invalid option value', t => { continue } t.throws(() => - optArg({ + oa({ preserveRoot, maxRetries, retryDelay, @@ -64,7 +66,7 @@ t.test('test every allowed combination', t => { for (const backoff of goodNum) { for (const maxBackoff of goodNum) { t.ok( - optArg({ + oa({ preserveRoot, maxRetries, retryDelay, @@ -83,19 +85,19 @@ t.test('test every allowed combination', t => { }) t.test('glob option handling', t => { - t.same(optArg({ glob: true }), { + t.same(oa({ glob: true }), { glob: { absolute: true, withFileTypes: false }, }) - const gws = optArg({ signal: { x: 1 }, glob: true }) + const gws = oa({ signal: { x: 1 }, glob: true }) t.same(gws, { signal: { x: 1 }, glob: { absolute: true, signal: { x: 1 }, withFileTypes: false }, }) t.equal(gws.signal, gws.glob.signal) - t.same(optArg({ glob: { nodir: true } }), { + t.same(oa({ glob: { nodir: true } }), { glob: { absolute: true, nodir: true, withFileTypes: false }, }) - const gwsg = optArg({ signal: { x: 1 }, glob: { nodir: true } }) + const gwsg = oa({ signal: { x: 1 }, glob: { nodir: true } }) t.same(gwsg, { signal: { x: 1 }, glob: { @@ -106,17 +108,14 @@ t.test('glob option handling', t => { }, }) t.equal(gwsg.signal, gwsg.glob.signal) - t.same( - optArg({ signal: { x: 1 }, glob: { nodir: true, signal: { y: 1 } } }), - { - signal: { x: 1 }, - glob: { - absolute: true, - nodir: true, - signal: { y: 1 }, - withFileTypes: false, - }, - } - ) + t.same(oa({ signal: { x: 1 }, glob: { nodir: true, signal: { y: 1 } } }), { + signal: { x: 1 }, + glob: { + absolute: true, + nodir: true, + signal: { y: 1 }, + withFileTypes: false, + }, + }) t.end() }) diff --git a/test/rimraf-move-remove.js b/test/rimraf-move-remove.js index 9ce9e982..1c98e56e 100644 --- a/test/rimraf-move-remove.js +++ b/test/rimraf-move-remove.js @@ -612,6 +612,39 @@ t.test('filter function', t => { t.throws(() => statSync(dir + '/c/f/i/l')) t.throws(() => statSync(dir + '/c/f/i/m')) }) + + t.test('async filter', async t => { + const dir = t.testdir(fixture) + const saw = [] + const filter = async p => { + saw.push(relative(process.cwd(), p).replace(/\\/g, '/')) + await new Promise(setImmediate) + return basename(p) !== f + } + await rimrafMoveRemove(dir, { filter }) + t.matchSnapshot( + saw.sort((a, b) => a.localeCompare(b, 'en')), + 'paths seen' + ) + statSync(dir) + statSync(dir + '/c') + statSync(dir + '/c/f') + statSync(dir + '/c/f/i') + if (f === 'j') { + statSync(dir + '/c/f/i/j') + } else { + t.throws(() => statSync(dir + '/c/f/i/j')) + } + t.throws(() => statSync(dir + '/a')) + t.throws(() => statSync(dir + '/b')) + t.throws(() => statSync(dir + '/c/d')) + t.throws(() => statSync(dir + '/c/e')) + t.throws(() => statSync(dir + '/c/f/g')) + t.throws(() => statSync(dir + '/c/f/h')) + t.throws(() => statSync(dir + '/c/f/i/k')) + t.throws(() => statSync(dir + '/c/f/i/l')) + t.throws(() => statSync(dir + '/c/f/i/m')) + }) t.end() }) } diff --git a/test/rimraf-posix.js b/test/rimraf-posix.js index e5ce11eb..7c7e0b28 100644 --- a/test/rimraf-posix.js +++ b/test/rimraf-posix.js @@ -308,6 +308,39 @@ t.test('filter function', t => { t.throws(() => statSync(dir + '/c/f/i/l')) t.throws(() => statSync(dir + '/c/f/i/m')) }) + + t.test('async filter', async t => { + const dir = t.testdir(fixture) + const saw = [] + const filter = async p => { + saw.push(relative(process.cwd(), p).replace(/\\/g, '/')) + await new Promise(setImmediate) + return basename(p) !== f + } + await rimrafPosix(dir, { filter }) + t.matchSnapshot( + saw.sort((a, b) => a.localeCompare(b, 'en')), + 'paths seen' + ) + statSync(dir) + statSync(dir + '/c') + statSync(dir + '/c/f') + statSync(dir + '/c/f/i') + if (f === 'j') { + statSync(dir + '/c/f/i/j') + } else { + t.throws(() => statSync(dir + '/c/f/i/j')) + } + t.throws(() => statSync(dir + '/a')) + t.throws(() => statSync(dir + '/b')) + t.throws(() => statSync(dir + '/c/d')) + t.throws(() => statSync(dir + '/c/e')) + t.throws(() => statSync(dir + '/c/f/g')) + t.throws(() => statSync(dir + '/c/f/h')) + t.throws(() => statSync(dir + '/c/f/i/k')) + t.throws(() => statSync(dir + '/c/f/i/l')) + t.throws(() => statSync(dir + '/c/f/i/m')) + }) t.end() }) } diff --git a/test/rimraf-windows.js b/test/rimraf-windows.js index 26b5605d..eca02e6e 100644 --- a/test/rimraf-windows.js +++ b/test/rimraf-windows.js @@ -602,6 +602,39 @@ t.test('filter function', t => { t.throws(() => statSync(dir + '/c/f/i/l')) t.throws(() => statSync(dir + '/c/f/i/m')) }) + + t.test('async filter', async t => { + const dir = t.testdir(fixture) + const saw = [] + const filter = async p => { + saw.push(relative(process.cwd(), p).replace(/\\/g, '/')) + await new Promise(setImmediate) + return basename(p) !== f + } + await rimrafWindows(dir, { filter }) + t.matchSnapshot( + saw.sort((a, b) => a.localeCompare(b, 'en')), + 'paths seen' + ) + statSync(dir) + statSync(dir + '/c') + statSync(dir + '/c/f') + statSync(dir + '/c/f/i') + if (f === 'j') { + statSync(dir + '/c/f/i/j') + } else { + t.throws(() => statSync(dir + '/c/f/i/j')) + } + t.throws(() => statSync(dir + '/a')) + t.throws(() => statSync(dir + '/b')) + t.throws(() => statSync(dir + '/c/d')) + t.throws(() => statSync(dir + '/c/e')) + t.throws(() => statSync(dir + '/c/f/g')) + t.throws(() => statSync(dir + '/c/f/h')) + t.throws(() => statSync(dir + '/c/f/i/k')) + t.throws(() => statSync(dir + '/c/f/i/l')) + t.throws(() => statSync(dir + '/c/f/i/m')) + }) t.end() }) }