javascriptnode.js

How can one get the file path of the caller function in node.js?


Here is some sample code from three files:

// foo.js
var myFunc = require("./myFunc");
function foo(){
   myFunc("message");
}

// bar.js
var myFunc = require("./myFunc");
function bar(){
   myFunc("message");
}

// myFunc.js
module.exports = myFunc;
function myFunc(arg1){
   console.log(arg1);
   // Here I need the file path of the caller function
   // For example, "/path/to/foo.js" and "/path/to/bar.js"
}

I need to get the file path of the caller function dynamically, without any extra argument passing, for myFunc.


Solution

  • You need to fiddle with the inner workings of v8. See: the wiki entry about the JavaScript Stack Trace API.

    I've based a little test on some code in a proposed commit and it seems to work. You end up with an absolute path.

    // omfg.js
    
    module.exports = omfg
    
    function omfg() {
      var caller = getCaller()
      console.log(caller.filename)
    }
    
    // private
    
    function getCaller() {
      var stack = getStack()
    
      // Remove superfluous function calls on stack
      stack.shift() // getCaller --> getStack
      stack.shift() // omfg --> getCaller
    
      // Return caller's caller
      return stack[1].receiver
    }
    
    function getStack() {
      // Save original Error.prepareStackTrace
      var origPrepareStackTrace = Error.prepareStackTrace
    
      // Override with function that just returns `stack`
      Error.prepareStackTrace = function (_, stack) {
        return stack
      }
    
      // Create a new `Error`, which automatically gets `stack`
      var err = new Error()
    
      // Evaluate `err.stack`, which calls our new `Error.prepareStackTrace`
      var stack = err.stack
    
      // Restore original `Error.prepareStackTrace`
      Error.prepareStackTrace = origPrepareStackTrace
    
      // Remove superfluous function call on stack
      stack.shift() // getStack --> Error
    
      return stack
    }
    

    And a test that includes omfg module:

    #!/usr/bin/env node
    // test.js
    
    var omfg = require("./omfg")
    
    omfg()
    

    And you will get on the console the absolute path of test.js.


    EXPLANATION

    This is not so much a "node.js" issue as it is a "v8" issue.

    See: Stack Trace Collection for Custom Exceptions

    Error.captureStackTrace(error, constructorOpt) adds to the error parameter a stack property, which evaluates by default to a String (by way of FormatStackTrace). If Error.prepareStackTrace(error, structuredStackTrace) is a Function, then it is called instead of FormatStackTrace.

    So, we can override Error.prepareStackTrace with our own function that will return whatever we want--in this case, just the structuredStackTrace parameter.

    Then, structuredStackTrace[1].receiver is an object representing the caller.