diff --git a/index.d.ts b/index.d.ts index bdd1a54..7129549 100644 --- a/index.d.ts +++ b/index.d.ts @@ -16,6 +16,29 @@ export type Options = { `/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15` → `unicorn.js:2:15` */ readonly basePath?: string; + + /** + Remove the stack lines where the given function returns `false`. The function receives the path part of the stack line. + + @example + ``` + import cleanStack from 'clean-stack'; + + const error = new Error('Missing unicorn'); + + console.log(cleanStack(error.stack)); + // Error: Missing unicorn + // at Object. (/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15) + // at Object. (/Users/sindresorhus/dev/clean-stack/omit-me.js:1:16) + + const pathFilter = path => !/omit-me/.test(path); + + console.log(cleanStack(error.stack, {pathFilter})); + // Error: Missing unicorn + // at Object. (/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15) + ``` + */ + readonly pathFilter?: (path: string) => boolean; }; /** diff --git a/index.js b/index.js index 649da79..3aa7409 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,7 @@ import getHomeDirectory from '#home-directory'; const extractPathRegex = /\s+at.*[(\s](.*)\)?/; const pathRegex = /^(?:(?:(?:node|node:[\w/]+|(?:(?:node:)?internal\/[\w/]*|.*node_modules\/(?:babel-polyfill|pirates)\/.*)?\w+)(?:\.js)?:\d+:\d+)|native)/; -export default function cleanStack(stack, {pretty = false, basePath} = {}) { +export default function cleanStack(stack, {pretty = false, basePath, pathFilter} = {}) { const basePathRegex = basePath && new RegExp(`(file://)?${escapeStringRegexp(basePath.replace(/\\/g, '/'))}/?`, 'g'); const homeDirectory = pretty ? getHomeDirectory() : ''; @@ -32,7 +32,9 @@ export default function cleanStack(stack, {pretty = false, basePath} = {}) { return false; } - return !pathRegex.test(match); + return pathFilter + ? !pathRegex.test(match) && pathFilter(match) + : !pathRegex.test(match); }) .filter(line => line.trim() !== '') .map(line => { diff --git a/readme.md b/readme.md index 3aa45a9..8c72ddc 100644 --- a/readme.md +++ b/readme.md @@ -73,6 +73,29 @@ Example with `'/Users/sindresorhus/dev/clean-stack'` as `basePath`: `/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15` → `unicorn.js:2:15` +##### pathFilter + +Type: `(path: string) => boolean` + +Remove the stack lines where the given function returns `false`. The function receives the path part of the stack line. + +```js +import cleanStack from 'clean-stack'; + +const error = new Error('Missing unicorn'); + +console.log(cleanStack(error.stack)); +// Error: Missing unicorn +// at Object. (/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15) +// at Object. (/Users/sindresorhus/dev/clean-stack/omit-me.js:1:16) + +const pathFilter = path => !/omit-me/.test(path); + +console.log(cleanStack(error.stack, {pathFilter})); +// Error: Missing unicorn +// at Object. (/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15) +``` + ## Related - [extract-stack](https://github.com/sindresorhus/extract-stack) - Extract the actual stack of an error diff --git a/test.js b/test.js index a91cff4..3a75169 100644 --- a/test.js +++ b/test.js @@ -218,6 +218,40 @@ test('`basePath` option should support file URLs', t => { t.is(cleanStack(stack, {basePath, pretty: true}), expected); }); +test('`pathFilter` option allows for excluding custom lines if the callback returns true', t => { + const pathFilter = path => !/home-directory/.test(path); + + const pre = `Error: foo + at Test.fn (/Users/sindresorhus/dev/clean-stack/test.js:6:15)`; + + const stack = `${pre}\n + at getHomeDirectory (/Users/sindresorhus/dev/clean-stack/home-directory.js:3:32) + at MySocket.emit (node:events:365:28) + at MySocket.emit (node:fs/promises:363:28) + at handleMessage (internal/child_process.js:695:10) + at Pipe.channel.onread (internal/child_process.js:440:11) + at process.emit (events.js:172:7)`; + + t.is(cleanStack(stack, {pathFilter}), pre); +}); + +test('`pathFilter` option keeps custom lines if the callback returns false', t => { + const pathFilterCallback = () => true; + + const pre = `Error: foo + at Test.fn (/Users/sindresorhus/dev/clean-stack/test.js:6:15) + at getHomeDirectory (/Users/sindresorhus/dev/clean-stack/home-directory.js:3:32)`; + + const stack = `${pre}\n + at MySocket.emit (node:events:365:28) + at MySocket.emit (node:fs/promises:363:28) + at handleMessage (internal/child_process.js:695:10) + at Pipe.channel.onread (internal/child_process.js:440:11) + at process.emit (events.js:172:7)`; + + t.is(cleanStack(stack, {pathFilterCallback}), pre); +}); + test('new stack format on Node.js 15 and later', t => { const stack = `Error at B (/home/fengkx/projects/test/stack.js:5:19)