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
.
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.
And a test that includes
omfg
module: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 theerror
parameter astack
property, which evaluates by default to aString
(by way ofFormatStackTrace
). IfError.prepareStackTrace(error, structuredStackTrace)
is aFunction
, then it is called instead ofFormatStackTrace
.So, we can override
Error.prepareStackTrace
with our own function that will return whatever we want--in this case, just thestructuredStackTrace
parameter.Then,
structuredStackTrace[1].receiver
is an object representing the caller.You can make use of
caller-callsite
package:The alternatives are
callsites
andstackman
packages.callsites
provides you with all call sites ("stack frame" inv8
terminology). Andstackman
gives the call sites decorated with custom functions and behavior. Source context, among other things. Which is lines of code surrounding call site line. Also it makes use of source maps if available.The issue with
stackman
is that it returns call sites asynchronously. Which is not particularly usable when running from debugger.Here's some code I used which you might find useful:
My 2 cents:
Let's say you have a
log
object which adds as extra information to the console the filename of the caller, for examplelog
responds tolog.info(msg)
and will do something similar to:info
would be:Problem: as said before,
parent.filename
will return you who did require the module in first place, not the caller itself.Alternative: stack-trace is a module which will do the trick:
The point:
stackTrace.get()[0]
returns the lastCaller
which responds to (just some of them)getFileName()
getColumnNumber()
getFunctionName()
getLineNumber()
getMethodName()
Or instead of fiddling with inner workings of the V8 engine, you use
module.parent.filename
to get absolute path to the module that required your module. As demonstrated here: https://gist.github.com/capaj/a9ba9d313b79f1dcd9a2Just keep in mind that modules are cached, so if any other file requires it and calls it, it will always be the path to the first importer.