38

I wonder how-to get an absolute path of a caller of a function?

Let say that:

in file a.js I call b(); b() is a function defined in file b.js. a.jsrequires b . So how do I get a.js absolute path from b.js in node?

einstein
  • 13,389
  • 27
  • 80
  • 110
  • 1
    See also http://stackoverflow.com/questions/13227489/how-can-one-get-the-file-path-of-the-caller-function-in-node-js – Myrne Stol May 22 '13 at 17:27
  • And see also http://stackoverflow.com/questions/10111163/in-node-js-how-can-i-get-the-path-of-a-module-i-have-loaded-via-require-that-is – basilikum May 22 '13 at 17:29
  • See my answer [here](https://stackoverflow.com/a/44872310/52499). – x-yuri Jul 02 '17 at 15:16
  • `console.log((new Error()).stack.split("\n")[1].split("/").slice(-1)[0].split(":")[0]) // "caller_file_name.js"` – marcelosalloum Aug 23 '21 at 14:25

8 Answers8

51

Failing to restore the prepareStackTrace function can cause issues. Here's an example that removes side-effects

function _getCallerFile() {
    var originalFunc = Error.prepareStackTrace;

    var callerfile;
    try {
        var err = new Error();
        var currentfile;

        Error.prepareStackTrace = function (err, stack) { return stack; };

        currentfile = err.stack.shift().getFileName();

        while (err.stack.length) {
            callerfile = err.stack.shift().getFileName();

            if(currentfile !== callerfile) break;
        }
    } catch (e) {}

    Error.prepareStackTrace = originalFunc; 

    return callerfile;
}
Rhionin
  • 639
  • 6
  • 5
34

This is an example how to use stacktrace to find caller file in node

function _getCallerFile() {
    var filename;

    var _pst = Error.prepareStackTrace
    Error.prepareStackTrace = function (err, stack) { return stack; };
    try {
        var err = new Error();
        var callerfile;
        var currentfile;

        currentfile = err.stack.shift().getFileName();

        while (err.stack.length) {
            callerfile = err.stack.shift().getFileName();

            if(currentfile !== callerfile) {
                filename = callerfile;
                break;
            }
        }
    } catch (err) {}
    Error.prepareStackTrace = _pst;

    return filename;
}
coolaj86
  • 74,004
  • 20
  • 105
  • 125
Bagus Budiarto
  • 364
  • 3
  • 4
  • 5
    IMPORTANT! Scroll down a bit and there are updated answers that don't have the same potential bugs and pitfalls as this one (though I did edit it to omit the most egregious bug). @Christoph's seems to be the best. – coolaj86 Jul 17 '21 at 19:30
  • This fails when using a bundler. – brillout Mar 13 '23 at 13:36
8

Not exactly answering the question here but some might appreciate this information.

With NodeJS & Forever(-monitor), the following contains a filename from which the process was started:

process.mainModule.filename

Haven't tried many uses™ though.

This seems to be a pretty decent explanation: https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi.

imme
  • 598
  • 1
  • 9
  • 22
7

In case the function you need the caller file of is not called in the file where it is implemented – as is the case in the OP's scenario – you can just write:

function _getCallerFile()
{
    const prepareStackTraceOrg = Error.prepareStackTrace;
    const err = new Error();

    Error.prepareStackTrace = (_, stack) => stack;

    const stack = err.stack;

    Error.prepareStackTrace = prepareStackTraceOrg;

    return stack[1].getFileName();
}

The try...catch is unnecessary since the Error will not be thrown if you assign it to a variable.

Furthermore, you might want to put _getCallerFile in its own file if you want to use it in multiple projects, but then, you will get the name of the file where _getCallerFile has been called. In this case, just write return stack[2].getFileName();, i. e. go one more step back in the call stack.

If you are using TypeScript, you must write const stack = err.stack as unknown as NodeJS.CallSite[]; because Error.stack's declared type is string, but our prepareStackTrace function returns an array of NodeJS.CallSite objects.

And just FYI: NodeJS.CallSite has further interesting methods, e. g. getFunctionName.

Update

I noticed that Error.prepareStackTrace === undefined before assigning the lambda. If you don't trust me, just add console.log('prepareStackTraceOrg:', prepareStackTraceOrg); to the function. Thus, we can simplify the function:

function _getCallerFile()
{
    const err = new Error();

    Error.prepareStackTrace = (_, stack) => stack;

    const stack = err.stack;

    Error.prepareStackTrace = undefined;

    return stack[1].getFileName();
}
Christoph
  • 712
  • 1
  • 6
  • 17
4

Use https://github.com/sindresorhus/callsites

If you use the first answer you could mess up with other libraries trying to do the same thing. See for example: https://github.com/facebook/jest/issues/5303

cancerbero
  • 6,799
  • 1
  • 32
  • 24
3

The npm caller package has a function that returns the path and filename of the callers.

Rob Bednark
  • 25,981
  • 23
  • 80
  • 125
Tim Long
  • 2,039
  • 1
  • 22
  • 25
1

Getting a stacktrace in JavaScript is quite hard. The best method I've found is to throw an Error, catch it, get the stack from Error.getStack() (not implemented in all browsers, that means you IE.) and formatting the output.

Each stack frame gives you a filepath, line number and function name. Webkit even has support for arguments but that wasn't working yet when I last checked.

Then there is the problem of tracing code across different events.

I actually wrote a blog post about this: http://fritsvancampen.wordpress.com/2013/03/28/error-handling-in-javascript-a-better-way/

Halcyon
  • 57,230
  • 10
  • 89
  • 128
-1

You can use require.resolve(module) to determine the full path of a module:

var path = require.resolve("a");

//or

var path = require.resolve("./a.js");
basilikum
  • 10,378
  • 5
  • 45
  • 58