Skip to content

Instantly share code, notes, and snippets.

@ryangoree
Last active May 23, 2024 17:31
Show Gist options
  • Save ryangoree/b82256d70c5d9bed769b94a8d72bb38a to your computer and use it in GitHub Desktop.
Save ryangoree/b82256d70c5d9bed769b94a8d72bb38a to your computer and use it in GitHub Desktop.
Attempts to get the path to the file that called the function that called this function.
/**
* Attempts to get the path to the file that called the function that called
* this function.
* @example
*
* #### Caller:
* ```ts
* // /path/to/file.ts
* import { foo } from './path/to/foo.ts';
*
* foo();
* ```
*
* #### Callee:
*
* ```ts
* // /path/to/foo.ts
* import { getCallerPath } from 'src/utils/get-caller';
*
* export function foo() {
* console.log(getCallerPath()); // /path/to/file.ts
* }
* ```
*/
export function getCallerPath(): string | undefined {
/**
* 0 = error name and message
*
* 1 = path to this file
*
* 2 = path to the file that called this function. The one that wants to know
* it's caller.
*
* 3 = path to the file that called the function that called this function
* (this is the file that the caller of this function wants)
*/
const callerIndex = 3;
const err = new Error();
// Attempt to overwrite the `prepareStackTrace` function. This will work in
// v8 environments, but will be ignored otherwise.
// https://v8.dev/docs/stack-trace-api#customizing-stack-traces
const originalPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (_, stack) => stack;
Error.captureStackTrace(err);
Error.prepareStackTrace = originalPrepareStackTrace;
if (!err.stack) return undefined;
// If the stack is an array, we're in a v8 environment and can use the
// `getFileName` method on the call site.
if (Array.isArray(err.stack)) {
const caller = err.stack[callerIndex] as NodeJS.CallSite;
return caller?.getFileName();
}
// If the stack is a string, we're in a non-v8 environment and need to parse
// the stack string to get the file path.
// https://regex101.com/r/yyMI5W/1
const callerLine = err.stack.split('\n')[callerIndex].trim();
const callerFile = callerLine.match(/(file|\/)[^\s]+?(?=(:\d|\)))/)?.[0];
if (!callerFile) return undefined;
return new URL(callerFile, import.meta.url).pathname;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment