A lightweight stack trace utility to retrieve CallSite
objects from a specific caller.
Useful for debugging, logging, or building tools that need to trace call origins at runtime.
- âś… Supports both ES Modules and CommonJS from a single source - see package
- âś… Minified and cleansed of unnecessary dependencies, files, and attributes - see contents
- âś… Tiny package - see size
- âś… Well tested - see coverage
- âś… Security checked - see scorecard
- âś… Verified all commits - see signatures
- âś… Semantic versioning - see commits
- âś… Actively maintained - pull requests, issues, discussions, and contributions are welcome!
npm i @mnrendra/stack-trace
Captures v8 stack trace from a specific caller.
(callee?: ((...args: any) => any) | null, options?: Options) => NodeJS.CallSite[]
Name | Type | Description |
---|---|---|
callee |
((...args: any) => any) | null |
Optional callee function to specify the caller. If undefined or null , tracing starts from the current caller. |
options |
Options |
Optional options to affect the captured frames. 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. |
NodeJS.CallSite[]
Array of CallSite
objects representing the captured stack trace frames.
Name | Type | Default | Description |
---|---|---|---|
limit |
number |
Infinity |
Specifies the number of stack frames to be collected by a stack trace. 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. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. |
Gets the caller's CallSite
object captured from stackTrace
.
(callee?: ((...args: any) => any) | null) => NodeJS.CallSite
Name | Type | Description |
---|---|---|
callee |
((...args: any) => any) | null |
Optional callee function to specify the caller. If undefined or null , tracing starts from the current caller. |
NodeJS.CallSite
First CallSite
object captured in the stack trace.
Extracts the file name from a CallSite
object and converts it to a file path if the value is a file URL.
This utility ensures that the returned value is an absolute path.
(callSite: NodeJS.CallSite) => string
Name | Type | Description |
---|---|---|
callSite |
NodeJS.CallSite |
CallSite object captured from stackTrace . |
string
Absolute path of the file name extracted from a CallSite
object.
If the extracted file name is not a string or not absolute.
Gets the caller's file extracted from the result of getCallerSite
and ensures it returns an absolute path using extractFilePath
.
(callee?: ((...args: any) => any) | null) => string
Name | Type | Description |
---|---|---|
callee |
((...args: any) => any) | null |
Optional callee function to specify the caller. If undefined or null , tracing starts from the current caller. |
string
Absolute path of the caller's file.
If the extracted file name is not a string or not absolute.
Gets the caller's directory extracted from the result of getCallerFile
.
(callee?: ((...args: any) => any) | null) => string
Name | Type | Description |
---|---|---|
callee |
((...args: any) => any) | null |
Optional callee function to specify the caller. If undefined or null , tracing starts from the current caller. |
string
Absolute path of the caller's directory.
If the extracted file name is not a string or not absolute.
/foo/callee.mjs
import { dirname } from 'node:path'
import {
stackTrace,
getCallerSite,
extractFilePath,
getCallerFile,
getCallerDir
} from '@mnrendra/stack-trace'
const callee = () => {
// `stackTrace`:
const [callSite1] = stackTrace()
const [callSite2] = stackTrace(callee, { limit: 1 }) // Pass the `callee` function as the callee.
console.log(callSite1.getFileName()) // Output: file:///foo/callee.mjs
console.log(callSite2.getFileName()) // Output: file:///foo/caller.mjs
console.log(callSite1.getFunctionName()) // Output: callee
console.log(callSite2.getFunctionName()) // Output: caller
// `getCallerSite`:
const callerSite1 = getCallerSite()
const callerSite2 = getCallerSite(callee) // Pass the `callee` function as the callee.
console.log(callerSite1.getFileName() === callSite1.getFileName()) // Output: true
console.log(callerSite2.getFileName() === callSite2.getFileName()) // Output: true
console.log(callerSite1.getFileName()) // Output: file:///foo/callee.mjs
console.log(callerSite2.getFileName()) // Output: file:///foo/caller.mjs
console.log(callerSite1.getFunctionName() === callSite1.getFunctionName()) // Output: true
console.log(callerSite2.getFunctionName() === callSite2.getFunctionName()) // Output: true
console.log(callerSite1.getFunctionName()) // Output: callee
console.log(callerSite2.getFunctionName()) // Output: caller
// `extractFilePath`:
const filePath1 = extractFilePath(callerSite1)
const filePath2 = extractFilePath(callerSite2)
console.log(filePath1) // Output: /foo/callee.mjs
console.log(filePath2) // Output: /foo/caller.mjs
// `getCallerFile`:
const callerFile1 = getCallerFile()
const callerFile2 = getCallerFile(callee) // Pass the `callee` function as the callee.
console.log(callerFile1 === filePath1) // Output: true
console.log(callerFile2 === filePath2) // Output: true
console.log(callerFile1) // Output: /foo/callee.mjs
console.log(callerFile2) // Output: /foo/caller.mjs
// `getCallerDir`:
const callerDir1 = getCallerDir()
const callerDir2 = getCallerDir(callee) // Pass the `callee` function as the callee.
console.log(callerDir1 === dirname(filePath1)) // Output: true
console.log(callerDir2 === dirname(filePath2)) // Output: true
console.log(callerDir1) // Output: /foo
console.log(callerDir2) // Output: /foo
}
export default callee
/foo/caller.mjs
import callee from './callee.mjs'
const caller = () => callee()
caller()
/foo/callee.cjs
const { dirname } = require('node:path')
const {
stackTrace,
getCallerSite,
extractFilePath,
getCallerFile,
getCallerDir
} = require('@mnrendra/stack-trace')
const callee = () => {
// `stackTrace`:
const [callSite1] = stackTrace()
const [callSite2] = stackTrace(callee, { limit: 1 }) // Pass the `callee` function as the callee.
console.log(callSite1.getFileName()) // Output: /foo/callee.cjs
console.log(callSite2.getFileName()) // Output: /foo/caller.cjs
console.log(callSite1.getFunctionName()) // Output: callee
console.log(callSite2.getFunctionName()) // Output: caller
// `getCallerSite`:
const callerSite1 = getCallerSite()
const callerSite2 = getCallerSite(callee) // Pass the `callee` function as the callee.
console.log(callerSite1.getFileName() === callSite1.getFileName()) // Output: true
console.log(callerSite2.getFileName() === callSite2.getFileName()) // Output: true
console.log(callerSite1.getFileName()) // Output: /foo/callee.cjs
console.log(callerSite2.getFileName()) // Output: /foo/caller.cjs
console.log(callerSite1.getFunctionName() === callSite1.getFunctionName()) // Output: true
console.log(callerSite2.getFunctionName() === callSite2.getFunctionName()) // Output: true
console.log(callerSite1.getFunctionName()) // Output: callee
console.log(callerSite2.getFunctionName()) // Output: caller
// `extractFilePath`:
const filePath1 = extractFilePath(callerSite1)
const filePath2 = extractFilePath(callerSite2)
console.log(filePath1) // Output: /foo/callee.cjs
console.log(filePath2) // Output: /foo/caller.cjs
// `getCallerFile`:
const callerFile1 = getCallerFile()
const callerFile2 = getCallerFile(callee) // Pass the `callee` function as the callee.
console.log(callerFile1 === filePath1) // Output: true
console.log(callerFile2 === filePath2) // Output: true
console.log(callerFile1) // Output: /foo/callee.cjs
console.log(callerFile2) // Output: /foo/caller.cjs
// `getCallerDir`:
const callerDir1 = getCallerDir()
const callerDir2 = getCallerDir(callee) // Pass the `callee` function as the callee.
console.log(callerDir1 === dirname(filePath1)) // Output: true
console.log(callerDir2 === dirname(filePath2)) // Output: true
console.log(callerDir1) // Output: /foo
console.log(callerDir2) // Output: /foo
}
module.exports = callee
/foo/caller.cjs
const callee = require('./callee.cjs')
const caller = () => callee()
caller()
Note:
In ES Modules,
getFileName
returns a file URL (e.g.,file:///foo
), instead of a file path (/foo
).
To convert it to a file path, use eitherurl.fileURLToPath
or theextractFilePath
utility.By default
stackTrace
will capture all caller's frames.
To capture only a specific number of frames, set thelimit
option to a positive number.
- Call from a development project
/foo/project-name/src/index.mjs
:
import { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import {
stackTrace,
getCallerSite,
extractFilePath,
getCallerFile,
getCallerDir
} from '@mnrendra/stack-trace'
// `stackTrace`:
const caller1 = () => stackTrace()
const [callSite] = caller1()
const fileName = callSite.getFileName()
console.log(fileName) // Output: file:///foo/project-name/src/index.mjs
console.log(fileURLToPath(fileName)) // Output: /foo/project-name/src/index.mjs
// `getCallerSite`:
const caller2 = () => getCallerSite()
const callerSite = caller2()
const callerFileName = callerSite.getFileName()
console.log(callerFileName === fileName) // Output: true
console.log(callerFileName) // Output: file:///foo/project-name/src/index.mjs
console.log(fileURLToPath(callerFileName)) // Output: /foo/project-name/src/index.mjs
// `extractFilePath`:
const filePath = extractFilePath(callerSite)
console.log(filePath === fileURLToPath(callerFileName)) // Output: true
console.log(filePath) // Output: /foo/project-name/src/index.mjs
// `getCallerFile`:
const caller3 = () => getCallerFile()
const callerFile = caller3()
console.log(callerFile === filePath) // Output: true
console.log(callerFile) // Output: /foo/project-name/src/index.mjs
// `getCallerDir`:
const caller4 = () => getCallerDir()
const callerDir = caller4()
console.log(callerDir === dirname(filePath)) // Output: true
console.log(callerDir) // Output: /foo/project-name/src
- Call from a production package
/foo/consumer/node_modules/module-name/dist/index.cjs
:
"use strict";
const { dirname } = require("node:path");
const {
stackTrace,
getCallerSite,
extractFilePath,
getCallerFile,
getCallerDir
} = require("@mnrendra/stack-trace");
// `stackTrace`:
const caller1 = () => stackTrace();
const [callSite] = caller1();
const fileName = callSite.getFileName();
console.log(fileName); // Output: /foo/consumer/node_modules/module-name/dist/index.cjs
// `getCallerSite`:
const caller2 = () => getCallerSite();
const callerSite = caller2();
const callerFileName = callerSite.getFileName();
console.log(callerFileName === fileName); // Output: true
console.log(callerFileName); // Output: /foo/consumer/node_modules/module-name/dist/index.cjs
// `extractFilePath`:
const filePath = extractFilePath(callerSite);
console.log(filePath === callerFileName); // Output: true
console.log(filePath); // Output: /foo/consumer/node_modules/module-name/dist/index.cjs
// `getCallerFile`:
const caller3 = () => getCallerFile()
const callerFile = caller3()
console.log(callerFile === filePath) // Output: true
console.log(callerFile) // Output: /foo/consumer/node_modules/module-name/dist/index.cjs
// `getCallerDir`:
const caller4 = () => getCallerDir();
const callerDir = caller4();
console.log(callerDir === dirname(filePath)); // Output: true
console.log(callerDir); // Output: /foo/consumer/node_modules/module-name/dist
stackTrace
's options interface.
import {
type Options,
stackTrace
} from '@mnrendra/stack-trace'
const options: Options = {
limit: 1
}
const caller = (): NodeJS.CallSite[] => stackTrace(caller, options)
const callSites = caller()
console.log(callSites.length) // Output: 1
We take security seriously in this project. If you discover a vulnerability, we strongly encourage you to report it in a responsible manner.
Please open a Security Advisory to report any vulnerabilities.
For more information, please refer to our Security Policy.
We appreciate your help in making this project better. Please follow the guidelines to ensure that your contributions are smoothly integrated.