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.js
requires b
. So how do I get a.js
absolute path from b.js
in node?
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.js
requires b
. So how do I get a.js
absolute path from b.js
in node?
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;
}
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;
}
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.
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();
}
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
The npm caller package has a function that returns the path and filename of the callers.
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/
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");