|
1 | 1 | # @mnrendra/stack-trace |
2 | 2 |
|
3 | | - |
| 3 | + |
4 | 4 |  |
5 | 5 |  |
| 6 | + |
| 7 | + |
6 | 8 |
|
7 | | -A utility for stack tracing based on the [NodeJS.CallSite](https://nodejs.org/api/errors.html#callsite-object) object, enabling dynamic inspection of function calls.<br/> |
8 | | -*Useful for debugging, logging, or building tools that need to understand call origins and file references at runtime.* |
| 9 | +A utility for tracing the caller's call sites starting from a specific callee.<br/> |
| 10 | +*Useful for debugging, logging, or building tools that need to get the call origins or file locations at runtime.* |
9 | 11 |
|
10 | 12 | ## Install |
11 | 13 | ```bash |
12 | 14 | npm i @mnrendra/stack-trace |
13 | 15 | ``` |
14 | 16 |
|
| 17 | +## API |
| 18 | + |
| 19 | +### **`stackTrace`** |
| 20 | +Traces the caller's call sites starting from a specific callee.<br/> |
| 21 | +*Captures the current stack trace as an array of `NodeJS.CallSite` objects. If a callee is provided, the trace will start from the caller of the callee.*<br/> |
| 22 | + |
| 23 | +#### **Type**: |
| 24 | +```typescript |
| 25 | +(callee?: ((...args: any) => any) | null, options?: Options) => NodeJS.CallSite[] |
| 26 | +``` |
| 27 | + |
| 28 | +#### Parameters |
| 29 | + |
| 30 | +| Name | Type | Description | |
| 31 | +|-----------|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |
| 32 | +| `callee` | `((...args: any) => any) \| null` | Optional callee function or method to start tracing from. If `undefined` or `null`, tracing starts from the current caller. | |
| 33 | +| `options` | `Options` | Configuration options for tracing behavior. By default, the `limit` option is set to `Infinity` to capture all frames. To capture only a specific number of frames, set the `limit` option to a positive number. | |
| 34 | + |
| 35 | +#### **Return Type**: |
| 36 | +```typescript |
| 37 | +NodeJS.CallSite[] |
| 38 | +``` |
| 39 | +An array of call sites representing the captured stack trace. |
| 40 | + |
15 | 41 | ## Usage |
16 | | -- `traceStacks(targetFn?, options?)`:<br/> |
17 | | -Returns an array of `NodeJS.CallSite` objects representing the captured stack trace. |
18 | | -- `traceFiles(targetFn?, options?)`:<br/> |
19 | | -Returns an array of file names (as `string` in **CommonJS** or `URL` in **ES Modules**) extracted from the stack trace of the specified function. |
20 | | -- `traceFnNames(targetFn?, options?)`:<br/> |
21 | | -Returns an array of function names extracted from the stack trace of the given function. |
22 | 42 |
|
23 | | -**Note**: If `targetFn` is not provided, it captures the current call stack. |
| 43 | +### **CommonJS** |
24 | 44 |
|
25 | | -### Usage in `CommonJS`: |
| 45 | +`/foo/callee.cjs` |
26 | 46 | ```javascript |
27 | | -const { traceStacks, traceFiles, traceFnNames } = require('@mnrendra/stack-trace') |
| 47 | +const { stackTrace } = require('@mnrendra/stack-trace') |
28 | 48 |
|
29 | | -const caller1 = () => traceStacks() |
30 | | -const [stack] = caller1() |
31 | | -console.log(stack.getFileName() === __filename) // Output: true |
| 49 | +const callee = () => { |
| 50 | + const [callSite1] = stackTrace() |
| 51 | + const [callSite2] = stackTrace(callee, { limit: 1 }) // set the `callee` function as the callee. |
32 | 52 |
|
33 | | -const caller2 = () => traceFiles() |
34 | | -const [file] = caller2() |
35 | | -console.log(file === __filename) // Output: true |
| 53 | + console.log(callSite1.getFileName()) // output: /foo/callee.cjs |
| 54 | + console.log(callSite2.getFileName()) // output: /foo/caller.cjs |
36 | 55 |
|
37 | | -const caller3 = () => traceFnNames() |
38 | | -const [fnName] = caller3() |
39 | | -console.log(fnName) // Output: caller3 |
| 56 | + console.log(callSite1.getFunctionName()) // output: callee |
| 57 | + console.log(callSite2.getFunctionName()) // output: caller |
| 58 | +} |
| 59 | + |
| 60 | +module.exports = callee |
| 61 | +``` |
| 62 | +`/foo/caller.cjs` |
| 63 | +```javascript |
| 64 | +const callee = require('./callee.cjs') |
| 65 | +const caller = () => callee() |
| 66 | +caller() |
40 | 67 | ``` |
41 | 68 |
|
42 | | -### Usage in `ES Modules`: |
| 69 | +### **ES Modules** |
| 70 | + |
| 71 | +`/foo/callee.mjs` |
43 | 72 | ```javascript |
44 | | -import { traceStacks, traceFiles, traceFnNames } from '@mnrendra/stack-trace' |
| 73 | +import { stackTrace } from '@mnrendra/stack-trace' |
45 | 74 |
|
46 | | -const caller1 = () => traceStacks() |
47 | | -const [stack] = caller1() |
48 | | -console.log(stack.getFileName() === import.meta.url) // Output: true |
| 75 | +const callee = () => { |
| 76 | + const [callSite1] = stackTrace() |
| 77 | + const [callSite2] = stackTrace(callee, { limit: 1 }) // set the `callee` function as the callee. |
49 | 78 |
|
50 | | -const caller2 = () => traceFiles() |
51 | | -const [file] = caller2() |
52 | | -console.log(file === import.meta.url) // Output: true |
| 79 | + console.log(callSite1.getFileName()) // output: file:///foo/callee.mjs |
| 80 | + console.log(callSite2.getFileName()) // output: file:///foo/caller.mjs |
| 81 | + |
| 82 | + console.log(callSite1.getFunctionName()) // output: callee |
| 83 | + console.log(callSite2.getFunctionName()) // output: caller |
| 84 | +} |
53 | 85 |
|
54 | | -const caller3 = () => traceFnNames() |
55 | | -const [fnName] = caller3() |
56 | | -console.log(fnName) // Output: caller3 |
| 86 | +export default callee |
57 | 87 | ``` |
| 88 | +`/foo/caller.mjs` |
| 89 | +```javascript |
| 90 | +import callee from './callee.mjs' |
| 91 | +const caller = () => callee() |
| 92 | +caller() |
| 93 | +``` |
| 94 | + |
| 95 | +**Note**: |
| 96 | +- When calling `getFileName` in an **ES Modules**, the file name will be returned as a **file URL** (e.g., `'file:///foo'`) instead of a **file path** (e.g., `'/foo'`).<br/> |
| 97 | +*You can use `url.fileURLToPath` to convert the **file URL** to a **file path**.* |
| 98 | +- By default `stackTrace` will capture all caller frames.<br/> |
| 99 | +*To capture only a specific number of frames, set the `limit` option to a positive number.* |
58 | 100 |
|
59 | 101 | ### Examples |
60 | | -1. Call from your development project `/foo/project-name/src/index.mjs`: |
| 102 | +1. Call from your development project:<br/> |
| 103 | +`/foo/project-name/src/index.mjs`: |
61 | 104 | ```javascript |
62 | | -import { traceStacks, traceFiles, traceFnNames } from '@mnrendra/stack-trace' |
| 105 | +import { fileURLToPath } from 'node:url' |
| 106 | +import { stackTrace } from '@mnrendra/stack-trace' |
63 | 107 |
|
64 | | -const caller1 = () => traceStacks() |
65 | | -const [stack] = caller1() |
66 | | -console.log(stack.getFileName()) // Output: file:///foo/project-name/src/index.mjs |
| 108 | +const caller = () => stackTrace() |
| 109 | +const [stack] = caller() |
67 | 110 |
|
68 | | -const caller2 = () => traceFiles() |
69 | | -const [file] = caller2() |
70 | | -console.log(file) // Output: file:///foo/project-name/src/index.mjs |
| 111 | +const fileName = stack.getFileName() |
71 | 112 |
|
72 | | -const caller3 = () => traceFnNames() |
73 | | -const [fnName] = caller3() |
74 | | -console.log(fnName) // Output: caller3 |
| 113 | +console.log(fileName) // output: file:///foo/project-name/src/index.mjs |
| 114 | +console.log(fileURLToPath(fileName)) // output: /foo/project-name/src/index.mjs |
75 | 115 | ``` |
76 | 116 |
|
77 | | -2. Call from your production module `/foo/project-name/node_modules/module-name/dist/index.js`: |
| 117 | +2. Call from your production package:<br/> |
| 118 | +`/foo/consumer/node_modules/module-name/dist/index.js`: |
78 | 119 | ```javascript |
79 | 120 | "use strict"; |
80 | 121 |
|
81 | | -const { traceStacks, traceFiles, traceFnNames } = require('@mnrendra/stack-trace'); |
| 122 | +const { stackTrace } = require("@mnrendra/stack-trace"); |
82 | 123 |
|
83 | | -const caller1 = () => traceStacks(); |
84 | | -const [stack] = caller1(); |
85 | | -console.log(stack.getFileName()); // Output: /foo/project-name/node_modules/module-name/dist/index.js |
| 124 | +const caller = () => stackTrace(); |
| 125 | +const [stack] = caller(); |
86 | 126 |
|
87 | | -const caller2 = () => traceFiles(); |
88 | | -const [file] = caller2(); |
89 | | -console.log(file); // Output: /foo/project-name/node_modules/module-name/dist/index.js |
| 127 | +const fileName = stack.getFileName(); |
90 | 128 |
|
91 | | -const caller3 = () => traceFnNames(); |
92 | | -const [fnName] = caller3(); |
93 | | -console.log(fnName); // Output: caller3 |
| 129 | +console.log(fileName); // output: /foo/consumer/node_modules/module-name/dist/index.js |
94 | 130 | ``` |
95 | 131 |
|
96 | | -**Note**: When calling `getFileName` in an **ES Modules** module, the file name will be returned as a **URL** instead of a file path. |
97 | | -
|
98 | 132 | ## Options |
99 | | -```javascript |
100 | | -import { traceStacks, traceFiles, traceFnNames } from '@mnrendra/stack-trace' |
101 | | - |
102 | | -const options = { |
103 | | - limit: 10 // The maximum number of stack frames to capture (default: 10). |
104 | | -} |
105 | | - |
106 | | -const caller1 = () => traceStacks( |
107 | | - caller1, // The option target function to be traced. |
108 | | - options |
109 | | -) |
110 | 133 |
|
111 | | -const caller2 = () => traceFiles( |
112 | | - caller2, // The option target function to be traced. |
113 | | - options |
114 | | -) |
| 134 | +### **`limit`** |
| 135 | +#### **Type:** `number` |
| 136 | +#### **Default:** `Infinity` |
115 | 137 |
|
116 | | -const caller3 = () => traceFnNames( |
117 | | - caller3, // The option target function to be traced. |
118 | | - options |
119 | | -) |
120 | | -``` |
| 138 | +Specifies the number of stack frames to be collected by a stack trace.<br> |
| 139 | +*The default value is `Infinity` but may be set to any valid JavaScript number. Changes will affect any stack trace captured after the value has been changed.*<br> |
| 140 | +*If set to a non-number value, or set to a negative number, stack traces will not capture any frames.* |
121 | 141 |
|
122 | 142 | ## Types |
123 | 143 | ```typescript |
124 | 144 | import type { |
125 | | - CallSite, // The alias of `NodeJS.CallSite`. |
126 | | - Options, // The options object for `traceStacks`, `traceFiles`, or `traceFnNames`. |
| 145 | + Options |
127 | 146 | } from '@mnrendra/stack-trace' |
128 | 147 | ``` |
129 | 148 |
|
|
0 commit comments