Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creates an optional callback to check for other paths to omit #33

Merged
merged 12 commits into from Mar 21, 2023
9 changes: 9 additions & 0 deletions index.d.ts
Expand Up @@ -16,6 +16,15 @@ export type Options = {
`/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15` → `unicorn.js:2:15`
*/
readonly basePath?: string;

/**
Remove any paths that return false from this callback.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not just removing the paths, we are removing the stack lines with the matching paths. This should be clearer.


Example with `path => /unicorn/.test(path)` as `pathFilterCallback`:

`/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15` → ``
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a full example would be useful in this case. Something like:

@example

import cleanStack from 'clean-stack';

const error = new Error('Missing unicorn');

console.log(cleanStack(error.stack));
// Error: Missing unicorn
//     at Object.<anonymous> (/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15)
//     at Object.<anonymous> (/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15)

console.log(cleanStack(error.stack, {pathFilter ...}));
// Error: Missing unicorn
//     at Object.<anonymous> (/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15)

*/
readonly pathFilterCallback?: (string) => boolean;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
readonly pathFilterCallback?: (string) => boolean;
readonly pathFilter?: (string) => boolean;

I don't think Callback adds anything. The method signature is clear.

};

/**
Expand Down
6 changes: 4 additions & 2 deletions index.js
Expand Up @@ -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, pathFilterCallback} = {}) {
const basePathRegex = basePath && new RegExp(`(file://)?${escapeStringRegexp(basePath.replace(/\\/g, '/'))}/?`, 'g');
const homeDirectory = pretty ? getHomeDirectory() : '';

Expand Down Expand Up @@ -32,7 +32,9 @@ export default function cleanStack(stack, {pretty = false, basePath} = {}) {
return false;
}

return !pathRegex.test(match);
return pathFilterCallback
? !pathRegex.test(match) && pathFilterCallback(match)
: !pathRegex.test(match);
})
.filter(line => line.trim() !== '')
.map(line => {
Expand Down
10 changes: 10 additions & 0 deletions readme.md
Expand Up @@ -73,6 +73,16 @@ Example with `'/Users/sindresorhus/dev/clean-stack'` as `basePath`:

`/Users/sindresorhus/dev/clean-stack/unicorn.js:2:15` → `unicorn.js:2:15`

##### pathFilterCallback

Type: `(string) => boolean`

Remove any paths that return false from this callback.

Example with `path => /unicorn/.test(path)` as `pathFilterCallback`:

`/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
Expand Down
34 changes: 34 additions & 0 deletions test.js
Expand Up @@ -218,6 +218,40 @@ test('`basePath` option should support file URLs', t => {
t.is(cleanStack(stack, {basePath, pretty: true}), expected);
});

test('`pathFilterCallback` option allows for excluding custom lines if the callback returns true', t => {
const pathFilterCallback = 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, {pathFilterCallback}), pre);
});

test('`pathFilterCallback` 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)
Expand Down