# `@tapjs/stack`

A comprehensive library for dealing with stack traces, supporting
source map lookup (when enabled in node with `--enable-source-maps`),
filtering of specified packages and/or Node.js internals, and
capturing call sites relative to a given function.

The spiritual descendant of
[stack-utils](https://github.com/tapjs/stack-utils).

## Class `CallSiteLike`

This is similar to the `CallSite` class in V8. However, rather
than provide methods to get all the relevant details about the
call site, it has them set as properties. Additionally, it may be
generated by parsing a line from a string stack trace, which is
useful when tracking down the source of thrown errors.

See
[the typedocs](https://tapjs.github.io/tapjs/classes/_tapjs_stack.call_site_like.CallSiteLike.html) for more information.

## Class `CallSiteLikeJSON`

This is the "plain old JavaScript object" form of a
`CallSiteLike` object, for use when serializing a `CallSiteLike`
to YAML or JSON.

It contains all the same fields as `CallSiteLike`, but fields are
unset rather than being set to `null` or `undefined` if they are
not relevant to the call site, to reduce noise when printing test
diagnostics.

The `toString()` value of CallSiteLike objects is a much terser
representation of the call site than the standard `Error.stack`
string, and it contains both the generated and origin call sites
in the case of source mapped files.

See [the
typedocs](https://tapjs.github.io/tapjs/interfaces/_tapjs_stack.call_site_like.CallSiteLikeJSON.html)
for more information.

## `at(fn?: Function): CallSiteLike | undefined`

Get the call site in the stack either where `at()` is called, or
where the supplied `fn` function is called.

If `fn` is provided, and is not in the current call stack, then
`undefined` will be returned.

## `capture(limit = 0, fn?: Function): CallSiteLike[]`

Get an array of CallSiteLike objects for the current location,
from the call to the `fn` argument if supplied, limited to the
number of frames specified by `limit`.

If `fn` is supplied, and not in the current call stack, then an
empty array will be returned.

If the `limit` argument is 0, then the current
`Error.stackTraceLimit` value will be used.

This method is not re-entry safe, due to the fact that it relies
on temporarily overriding the global `Error.prepareStackTrace`.
As a result, if a capture() is triggered in any of the methods
used by the `CallSiteLike` constructor (for example, if
[`@tapjs/intercept`](https://tapjs.github.io/tapjs/modules/_tapjs_intercept.html)
is used to capture the `process.cwd()` method, which is used by
`path.resolve()`), then that will cause problems. To work around
this, if a re-entry is detected, then an empty stack of `[]` is
returned.

Even if it was made re-entry safe, it would be easy to accidentally
trigger an infinite recursion and stack overflow in such a scenario, so
returning an empty stack in the case of re-entry is the best workaround.

## `captureString(limit = 0, fn?: Function): string`

The same as `capture()`, but returns a string stack where each
line is the `toString()` of the CallSiteLike object.

## `captureError(er: Error): CallSiteLike[]`

Get a stack of `CallSiteLike` objects by parsing the `stack`
property of the supplied Error object.

This does _not_ actually look at the current call site, or do
anything magical with the V8 engine. It's just parsing a string.

While some effort is made to interpret stacks correctly when an
Error contains a `name` and `message`, remember that the
`Error.stack` property in JavaScript is remarkably sloppy. In
some cases, if the `Error.message` contains `\n` and some lines
after the first look like stack trace lines, incorrect data may
result. It's only as good as the stack you pass to it.

## `captureErrorString(er: Error): string`

The same as `captureError` (with the same caveats) but presenting
the string stack where each line is the `toString()` value of the
CallSiteLike object.

## `parseStack(stack: string): CallSiteLike[]`

Turn a string stack (either from `@tapjs/stack` or from a native
Error object) into an array of CallSiteLike objects.

Only useful in some niche situations, most of the time you're
better off using `capture()` or `captureError()`.

## `expandStack(stack?: string | CallSiteLike[]): string`

Expand a stack string (either from `@tapjs/stack` or from a
JS Error object) into its conventional `Error.stack` form,
complete with absolute paths, indentation, and repetitive `at`
prefixes.

When a call site is source mapped, the origin source will be
shown if the generated source is outside the cwd. If the cwd is
not set on the CallSiteLike object, then generated location is
always shown.

## `setCwd(cwd: string | undefined)`

Set the current working directory used to shorten filename paths
in CallSiteLike objects.

Default value is `process.cwd()`. Setting it to `undefined` will
cause the CallSiteLike objects returned by the capture methods to
display full file paths.

## `getCwd(): string | undefined`

Get the current value of the effective cwd used by capture
methods.

## `getFilterNodeInternals(): boolean`

Tells you whether or not node internals are being filtered out.

Defaults to `true`

## `setFilterNodeInternals(f: boolean)`

Specify whether node internals should be filtered out.

## `getFilterIgnoredPackages(): boolean`

Tells you whether or not the set of ignored packages are being
filtered out.

Defaults to `true`

## `setFilterIgnoredPackages(f: boolean)`

Specify whether or not ignored packages should be filtered out.

## `getIgnoredPackages(): string[]`

Get the list of packages that are filtered out of captured stacks.

## `addIgnoredPackage(pkg: string)`

Add a package to the filter set.

## `removeIgnoredPackage(pkg: string)`

Remove a package from the filter set.
