diff --git a/README.md b/README.md index e584c83d..2f83f982 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ This package provides methods for traversing the file system and returning pathn * [fs](#fs) * [ignore](#ignore) * [suppressErrors](#suppresserrors) + * [errorHandler](#errorhandler) * [throwErrorOnBrokenSymbolicLink](#throwerroronbrokensymboliclink) * [signal](#signal) * [Output control](#output-control) @@ -393,10 +394,32 @@ fg.globSync('*.json', { ignore: ['package-lock.json'] }); // ['package.json'] * Type: `boolean` * Default: `false` -By default this package suppress only `ENOENT` errors. Set to `true` to suppress any error. +By default this package suppress `ENOENT` errors. Set to `true` to suppress any error. > :book: Can be useful when the directory has entries with a special level of access. +#### errorHandler + +* Type: function (error: ErrnoException) => boolean + +Supply a custom error handler that takes the error as argument and allows you to +handle errors in a custom way. Return `true` to suppress the error, +`false` to throw the error. + +```js +fg.globSync('**', { + errorHandler: (error) => { + if (error.code === 'ENOENT') { + console.error('Directory not found:', error.path); + return true; + } else { + console.error('Error:', error.message); + return false; + } + } +}); +``` + #### throwErrorOnBrokenSymbolicLink * Type: `boolean` diff --git a/src/providers/filters/error.ts b/src/providers/filters/error.ts index 9dba5fae..25bb3da7 100644 --- a/src/providers/filters/error.ts +++ b/src/providers/filters/error.ts @@ -15,6 +15,18 @@ export default class ErrorFilter { } #isNonFatalError(error: ErrnoException): boolean { - return utils.errno.isEnoentCodeError(error) || this.#settings.suppressErrors; + if (this.#settings.suppressErrors) { + return true; + } + + if (this.#settings.errorHandler !== undefined) { + return this.#settings.errorHandler(error); + } + + if (utils.errno.isEnoentCodeError(error)) { + return true; + } + + return false; } } diff --git a/src/readers/reader.ts b/src/readers/reader.ts index 8dd7a41c..06b3b958 100644 --- a/src/readers/reader.ts +++ b/src/readers/reader.ts @@ -44,6 +44,18 @@ export abstract class Reader { } protected _isFatalError(error: ErrnoException): boolean { - return !utils.errno.isEnoentCodeError(error) && !this.#settings.suppressErrors; + if (this.#settings.suppressErrors) { + return false; + } + + if (this.#settings.errorHandler !== undefined) { + return !this.#settings.errorHandler(error); + } + + if (utils.errno.isEnoentCodeError(error)) { + return false; + } + + return true; } } diff --git a/src/settings.spec.ts b/src/settings.spec.ts index 0509bfd7..a79871fb 100644 --- a/src/settings.spec.ts +++ b/src/settings.spec.ts @@ -18,6 +18,7 @@ describe('Settings', () => { assert.ok(!settings.onlyDirectories); assert.ok(!settings.stats); assert.ok(!settings.suppressErrors); + assert.ok(!settings.errorHandler); assert.ok(!settings.throwErrorOnBrokenSymbolicLink); assert.ok(settings.braceExpansion); assert.ok(settings.caseSensitiveMatch); diff --git a/src/settings.ts b/src/settings.ts index 73b9465b..8189549b 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,6 +1,6 @@ import * as fs from 'node:fs'; -import type { FileSystemAdapter, Pattern } from './types'; +import type { ErrnoException, FileSystemAdapter, Pattern } from './types'; export const DEFAULT_FILE_SYSTEM_ADAPTER: FileSystemAdapter = { lstat: fs.lstat, @@ -125,6 +125,13 @@ export interface Options { * @default false */ suppressErrors?: boolean; + /** + * Callback for user-defined error handling. Ignored if + * `suppressErrors` is `true`. Return `true` to suppress an error, + * `false` to throw it. + * + */ + errorHandler?: (error: Error) => boolean; /** * Throw an error when symbolic link is broken if `true` or safely * return `lstat` call if `false`. @@ -166,6 +173,7 @@ export default class Settings { public readonly onlyFiles: boolean; public readonly stats: boolean; public readonly suppressErrors: boolean; + public readonly errorHandler: ((error: ErrnoException) => boolean) | undefined; public readonly throwErrorOnBrokenSymbolicLink: boolean; public readonly unique: boolean; public readonly signal?: AbortSignal; @@ -190,7 +198,8 @@ export default class Settings { this.onlyFiles = options.onlyFiles ?? true; this.stats = options.stats ?? false; this.suppressErrors = options.suppressErrors ?? false; - this.throwErrorOnBrokenSymbolicLink = options.throwErrorOnBrokenSymbolicLink ?? false; + this.errorHandler = options.errorHandler ?? undefined; + this.throwErrorOnBrokenSymbolicLink = options.throwErrorOnBrokenSymbolicLink ?? false; this.unique = options.unique ?? true; this.signal = options.signal;