I'll show the code first (node 10.15.3):
var ts = require("typescript");
require('source-map-support').install({
environment: 'node',
hookRequire: true
})
var content = "let a = 0;\n\nb = b * a";
var compilerOptions = {
module: ts.ModuleKind.CommonJS,
inlineSourceMap: true
};
var res1 = ts.transpileModule(content, {
compilerOptions: compilerOptions,
moduleName: "myModule2"
});
console.log(res1);
console.log('-------')
console.log(content)
console.log('-------')
console.log(res1.outputText)
console.log('-------')
eval(res1.outputText)
As a result of executing this code I want to have a traceback related to a given content variable (Error in line 3), but I constantly receive an error in line 2 - which is line of error in compiled version of code.
Here is an output
{ outputText:
'var a = 0;\nb = b * a;\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUVWLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBIn0=',
diagnostics: [],
sourceMapText: undefined }
-------
let a = 0;
b = b * a
-------
var a = 0;
b = b * a;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUVWLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBIn0=
-------
SS: /root/ts-eval/exal.js undefined
SS: internal/modules/cjs/loader.js undefined
SS: internal/bootstrap/node.js undefined
ReferenceError: b is not defined
at eval (eval at <anonymous> (/root/ts-eval/exal.js:24:1), <anonymous>:2:1)
at Object.<anonymous> (/root/ts-eval/exal.js:24:1)
at Module._compile (internal/modules/cjs/loader.js:701:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
at Module.load (internal/modules/cjs/loader.js:600:32)
at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
at Function.Module._load (internal/modules/cjs/loader.js:531:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
You are using inline source maps, and the documentation for source-map-support
states:
To support files with inline source maps, the
hookRequire
options can be specified, which will monitor all source files for inline source maps.
You've set hookRequire
to true. However, the passage I've quoted indicates source-map-support
relies on hooking into require
to detect inline source maps, and so if your code executes without passing through require
then its source map won't be detected and source-map-support
won't be able to fix the stack trace. Indeed if I replace your eval
call with this code:
fs.writeFileSync("myModule2.js", res1.outputText);
require("./myModule2");
I get a stack trace like this, with the correct line number:
ReferenceError: b is not defined
at Object.<anonymous> (/tmp/t4/module.ts:3:1)
[...]
The file name is module.ts
because the option fileName
has not been specified to ts.transpileModule
. You could set it to myModule2.ts
for consistency with moduleName
.
Also, if you change your compiler options to also inline the sources, like this:
var compilerOptions = {
module: ts.ModuleKind.CommonJS,
inlineSourceMap: true,
inlineSources: true,
};
You get a bit of a nicer stack trace. With compilerOptions
like shown above and fileName
as I suggested earlier, the trace is:
/tmp/t4/myModule2.ts:3
b = b * a
^
ReferenceError: b is not defined
at Object.<anonymous> (/tmp/t4/myModule2.ts:3:1)
You can see before the ReferenceError
a reference to the line of code that caused the problem.
The approach above is the simplest one that results in source-map-support
fixing source references. Here is another, more complicated approach, which does not require saving any files to disk but requires customizing how source-map-support
gets source code from a source file path. The comments in the source indicate what the new part do.
const fs = require("fs");
const ts = require("typescript");
const vm = require("vm");
const path = require("path");
// This establishes a mapping between sourcePaths and the actual source.
const sourcePathToSource = Object.create(null);
require("source-map-support").install({
environment: "node",
// Pass to source-map-support a custom function for retreiving sources
// from source paths. This runs after source-map-support's default logic,
// only if that logic fails to find the requested source.
retrieveFile: (sourcePath) => sourcePathToSource[sourcePath],
});
const content = "let a = 0;\n\nb = b * a";
const compilerOptions = {
module: ts.ModuleKind.CommonJS,
sourceMap: true,
inlineSources: true,
};
// The path that the ts module would have.
const tsPath = path.resolve("myModule2.ts");
const res1 = ts.transpileModule(content, {
compilerOptions: compilerOptions,
fileName: tsPath,
moduleName: "myModule2"
});
console.log(res1);
console.log("-------");
console.log(content);
console.log("-------");
console.log(res1.outputText);
console.log("-------");
// The path that the compiled module would have.
const jsPath = path.resolve("myModule2.js");
// Establish the relationship between the path and the source.
sourcePathToSource[jsPath] = res1.outputText;
// Ditto for the source map file.
sourcePathToSource[path.resolve("myModule2.js.map")] = res1.sourceMapText;
vm.runInThisContext(res1.outputText, {
filename: jsPath,
});
Running the code above results in this output:
/tmp/t4/myModule2.js:2
b = b * a;
^
ReferenceError: b is not defined
at /tmp/t4/myModule2.ts:3:1
at Script.runInThisContext (vm.js:123:20)
[...]
The source line numbers in the stack trace are modified by source-map-support
to point to the right place but the source reference at the very beginning is not modified. The problem is with the regular expression that source-map-support
uses. The regular expression requires the source file reference to be in parentheses (like (vm.js:123:20)
). I've tried transforming the exception before source-map-support
gets to it so that it fits the regular expression but source-map-support
does not see the transformation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With