Captures and cleans stack traces for JavaScript applications
npx @tessl/cli install tessl/npm-stack-utils@2.0.00
# Stack Utils
1
2
Stack Utils is a JavaScript library for capturing, cleaning, and manipulating stack traces in Node.js applications. It provides powerful utilities to remove internal Node.js lines from stack traces, shorten file paths relative to a working directory, and parse individual stack trace lines into structured objects. Originally extracted from the node-tap testing framework, it's particularly useful for testing frameworks, error handling systems, and debugging tools that need to present clean, readable stack traces.
3
4
## Package Information
5
6
- **Package Name**: stack-utils
7
- **Package Type**: npm
8
- **Language**: JavaScript
9
- **Installation**: `npm install stack-utils`
10
11
## Core Imports
12
13
```javascript
14
const StackUtils = require('stack-utils');
15
```
16
17
## Basic Usage
18
19
```javascript
20
const StackUtils = require('stack-utils');
21
22
// Create a new instance with default settings
23
const stack = new StackUtils({
24
cwd: process.cwd(),
25
internals: StackUtils.nodeInternals()
26
});
27
28
// Clean a stack trace from an error
29
console.log(stack.clean(new Error().stack));
30
31
// Capture current stack trace as string
32
const currentStack = stack.captureString();
33
console.log(currentStack);
34
35
// Get information about current location
36
const location = stack.at();
37
console.log(location); // { line: 15, column: 23, file: 'app.js' }
38
```
39
40
## Capabilities
41
42
### Constructor
43
44
Creates a new StackUtils instance with customizable filtering and formatting options.
45
46
```javascript { .api }
47
/**
48
* Creates a new StackUtils instance
49
* @param options - Configuration options
50
*/
51
new StackUtils(options);
52
53
interface StackUtilsOptions {
54
/** Array of npm package names to ignore in stack traces */
55
ignoredPackages?: string[];
56
/** Array of RegExp patterns for internal lines to filter */
57
internals?: RegExp[];
58
/** Current working directory for relative path resolution */
59
cwd?: string;
60
/** Optional function to wrap CallSite objects */
61
wrapCallSite?: (callSite: CallSite) => CallSite;
62
}
63
```
64
65
**Usage Example:**
66
67
```javascript
68
const stack = new StackUtils({
69
cwd: process.cwd(),
70
ignoredPackages: ['lodash', 'bluebird'],
71
internals: StackUtils.nodeInternals().concat([
72
/\/my-internal-module\//
73
]),
74
wrapCallSite: (callSite) => {
75
// Custom CallSite manipulation for source maps
76
return callSite;
77
}
78
});
79
```
80
81
### Static Methods
82
83
#### Node Internals
84
85
Returns default regular expressions for filtering Node.js internal stack trace lines.
86
87
```javascript { .api }
88
/**
89
* Get default RegExp patterns for Node.js internals
90
* @returns Array of RegExp objects for filtering Node.js internal lines
91
*/
92
static nodeInternals(): RegExp[];
93
```
94
95
### Stack Trace Cleaning
96
97
#### Clean Stack Traces
98
99
Removes internal lines and formats stack traces for better readability.
100
101
```javascript { .api }
102
/**
103
* Clean and format a stack trace by removing internal lines
104
* @param stack - Stack trace string or array of lines
105
* @param indent - Number of spaces to indent each line
106
* @returns Cleaned stack trace string
107
*/
108
clean(stack: string | string[], indent?: number): string;
109
```
110
111
**Usage Examples:**
112
113
```javascript
114
// Clean an error stack trace
115
try {
116
throw new Error('Something went wrong');
117
} catch (err) {
118
const cleanStack = stack.clean(err.stack);
119
console.log(cleanStack);
120
}
121
122
// Clean with custom indentation
123
const indentedStack = stack.clean(err.stack, 4);
124
125
// Clean an array of stack lines
126
const stackLines = err.stack.split('\n');
127
const cleaned = stack.clean(stackLines);
128
```
129
130
### Stack Trace Capture
131
132
#### Capture as String
133
134
Captures the current stack trace and returns it as a cleaned string.
135
136
```javascript { .api }
137
/**
138
* Capture current stack trace as cleaned string
139
* @param limit - Maximum number of stack frames or start function
140
* @param fn - Function to start capture from
141
* @returns Cleaned stack trace string
142
*/
143
captureString(limit?: number | function, fn?: function): string;
144
```
145
146
**Usage Examples:**
147
148
```javascript
149
// Capture current stack with default settings
150
const stack1 = stackUtils.captureString();
151
152
// Limit to 5 frames
153
const stack2 = stackUtils.captureString(5);
154
155
// Start capture from specific function
156
function myFunction() {
157
return stackUtils.captureString(myFunction);
158
}
159
160
// Using limit and start function
161
const stack3 = stackUtils.captureString(10, myFunction);
162
```
163
164
#### Capture as CallSites
165
166
Captures the current stack trace as an array of CallSite objects for programmatic analysis.
167
168
```javascript { .api }
169
/**
170
* Capture current stack trace as CallSite objects
171
* @param limit - Maximum number of stack frames or start function
172
* @param fn - Function to start capture from
173
* @returns Array of CallSite objects
174
*/
175
capture(limit?: number | function, fn?: function): CallSite[];
176
```
177
178
### Location Information
179
180
#### Get Current Location
181
182
Captures information about the current execution location as a serializable object.
183
184
```javascript { .api }
185
/**
186
* Get current execution location information
187
* @param fn - Function to start capture from
188
* @returns Object with location information
189
*/
190
at(fn?: function): LocationInfo;
191
192
interface LocationInfo {
193
/** Line number */
194
line?: number;
195
/** Column number */
196
column?: number;
197
/** File path (relative to cwd) */
198
file?: string;
199
/** Whether this is a constructor call */
200
constructor?: boolean;
201
/** Eval origin information if applicable */
202
evalOrigin?: string;
203
/** Whether this is native code */
204
native?: boolean;
205
/** Type name */
206
type?: string;
207
/** Function name */
208
function?: string;
209
/** Method name */
210
method?: string;
211
}
212
```
213
214
**Usage Examples:**
215
216
```javascript
217
function exampleFunction() {
218
const location = stack.at();
219
console.log(`Called from ${location.file}:${location.line}:${location.column}`);
220
console.log(`Function: ${location.function}`);
221
}
222
223
// Get location starting from specific function
224
function wrapper() {
225
const location = stack.at(wrapper);
226
return location;
227
}
228
```
229
230
### Stack Line Parsing
231
232
#### Parse Individual Lines
233
234
Parses a single stack trace line into a structured object with detailed information.
235
236
```javascript { .api }
237
/**
238
* Parse a single stack trace line into structured object
239
* @param line - Single line from a stack trace
240
* @returns Parsed line information or null if no match
241
*/
242
parseLine(line: string): ParsedLine | null;
243
244
interface ParsedLine {
245
/** Line number */
246
line?: number;
247
/** Column number */
248
column?: number;
249
/** File path */
250
file?: string;
251
/** Whether this is a constructor call */
252
constructor?: boolean;
253
/** Eval origin information */
254
evalOrigin?: string;
255
/** Eval line number */
256
evalLine?: number;
257
/** Eval column number */
258
evalColumn?: number;
259
/** Eval file path */
260
evalFile?: string;
261
/** Whether this is native code */
262
native?: boolean;
263
/** Function name */
264
function?: string;
265
/** Method name */
266
method?: string;
267
}
268
```
269
270
**Usage Examples:**
271
272
```javascript
273
// Parse individual stack trace lines
274
const stackTrace = new Error().stack;
275
const lines = stackTrace.split('\n');
276
277
lines.forEach(line => {
278
const parsed = stack.parseLine(line);
279
if (parsed) {
280
console.log(`${parsed.function} in ${parsed.file}:${parsed.line}`);
281
}
282
});
283
284
// Handle different line formats
285
const testLines = [
286
' at myFunction (app.js:10:5)',
287
' at new Constructor (lib.js:25:12)',
288
' at eval (eval at <anonymous> (app.js:5:1), <anonymous>:1:1)',
289
' at native'
290
];
291
292
testLines.forEach(line => {
293
const result = stack.parseLine(line);
294
console.log(result);
295
});
296
```
297
298
## Types
299
300
### CallSite Interface
301
302
The native V8 CallSite interface provides detailed information about stack frames.
303
304
```javascript { .api }
305
interface CallSite {
306
getThis(): any;
307
getTypeName(): string | null;
308
getFunction(): Function;
309
getFunctionName(): string | null;
310
getMethodName(): string | null;
311
getFileName(): string | null;
312
getLineNumber(): number | null;
313
getColumnNumber(): number | null;
314
getEvalOrigin(): string | null;
315
isToplevel(): boolean;
316
isEval(): boolean;
317
isNative(): boolean;
318
isConstructor(): boolean;
319
}
320
```
321
322
## Error Handling
323
324
Stack Utils gracefully handles various edge cases:
325
326
- **Invalid stack traces**: Returns empty results for malformed input
327
- **Missing files**: Handles stack traces with missing or invalid file paths
328
- **Native code**: Properly identifies and handles native code frames
329
- **Eval contexts**: Parses and preserves eval origin information
330
- **Process availability**: Works even when `process` object is not available
331
332
## Common Use Cases
333
334
### Testing Frameworks
335
336
```javascript
337
const StackUtils = require('stack-utils');
338
339
class TestFramework {
340
constructor() {
341
this.stack = new StackUtils({
342
ignoredPackages: ['tap', 'mocha', 'jest'],
343
cwd: process.cwd()
344
});
345
}
346
347
reportError(error) {
348
console.error('Test failed:');
349
console.error(this.stack.clean(error.stack, 2));
350
}
351
352
getCurrentTestLocation() {
353
return this.stack.at(this.reportError);
354
}
355
}
356
```
357
358
### Error Logging
359
360
```javascript
361
const StackUtils = require('stack-utils');
362
363
const logger = {
364
stack: new StackUtils({
365
ignoredPackages: ['winston', 'pino'],
366
cwd: process.cwd()
367
}),
368
369
error(message, error) {
370
console.log({
371
message,
372
stack: this.stack.clean(error.stack),
373
location: this.stack.at(this.error)
374
});
375
}
376
};
377
```
378
379
### Debug Information
380
381
```javascript
382
const StackUtils = require('stack-utils');
383
384
function createDebugger(namespace) {
385
const stack = new StackUtils();
386
387
return function debug(message) {
388
const location = stack.at(debug);
389
console.log(`[${namespace}] ${location.file}:${location.line} - ${message}`);
390
};
391
}
392
393
const debug = createDebugger('myapp');
394
debug('Something happened'); // [myapp] app.js:15 - Something happened
395
```