mirror of
https://github.com/denoland/deno.git
synced 2024-11-28 16:20:57 -05:00
Support source maps for internal code.
This commit is contained in:
parent
af6076f3c6
commit
8e2e17cdbe
10 changed files with 142 additions and 32 deletions
1
Makefile
1
Makefile
|
@ -1,4 +1,5 @@
|
|||
TS_FILES = \
|
||||
tsconfig.json \
|
||||
main.ts \
|
||||
msg.pb.d.ts \
|
||||
msg.pb.js \
|
||||
|
|
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"github.com/ry/v8worker2"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
@ -84,13 +83,6 @@ func UserHomeDir() string {
|
|||
return os.Getenv("HOME")
|
||||
}
|
||||
|
||||
func loadAsset(w *v8worker2.Worker, path string) {
|
||||
data, err := Asset(path)
|
||||
check(err)
|
||||
err = w.Load(path, string(data))
|
||||
check(err)
|
||||
}
|
||||
|
||||
func createDirs() {
|
||||
DenoDir = path.Join(UserHomeDir(), ".deno")
|
||||
CompileDir = path.Join(DenoDir, "compile")
|
||||
|
|
14
main.go
14
main.go
|
@ -42,6 +42,12 @@ func ResolveModule(moduleSpecifier string, containingFile string) (
|
|||
return
|
||||
}
|
||||
|
||||
func stringAsset(path string) string {
|
||||
data, err := Asset("dist/" + path)
|
||||
check(err)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
@ -53,7 +59,11 @@ func main() {
|
|||
|
||||
createDirs()
|
||||
worker := v8worker2.New(recv)
|
||||
loadAsset(worker, "dist/main.js")
|
||||
|
||||
main_js := stringAsset("main.js")
|
||||
check(worker.Load("/main.js", main_js))
|
||||
main_map := stringAsset("main.map")
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
check(err)
|
||||
|
||||
|
@ -66,6 +76,8 @@ func main() {
|
|||
Cwd: cwd,
|
||||
Argv: args,
|
||||
DebugFlag: *flagDebug,
|
||||
MainJs: main_js,
|
||||
MainMap: main_map,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
18
main.ts
18
main.ts
|
@ -8,10 +8,18 @@ import * as util from "./util";
|
|||
// Set with the -debug command-line flag.
|
||||
export let debug = false;
|
||||
|
||||
function start(cwd: string, argv: string[], debugFlag: boolean): void {
|
||||
function start(
|
||||
cwd: string,
|
||||
argv: string[],
|
||||
debugFlag: boolean,
|
||||
mainJs: string,
|
||||
mainMap: string
|
||||
): void {
|
||||
debug = debugFlag;
|
||||
util.log("start", { cwd, argv, debugFlag });
|
||||
|
||||
runtime.setup(mainJs, mainMap);
|
||||
|
||||
const inputFn = argv[0];
|
||||
const mod = runtime.resolveModule(inputFn, cwd + "/");
|
||||
mod.compileAndRun();
|
||||
|
@ -21,7 +29,13 @@ V8Worker2.recv((ab: ArrayBuffer) => {
|
|||
const msg = pb.Msg.decode(new Uint8Array(ab));
|
||||
switch (msg.payload) {
|
||||
case "start":
|
||||
start(msg.start.cwd, msg.start.argv, msg.start.debugFlag);
|
||||
start(
|
||||
msg.start.cwd,
|
||||
msg.start.argv,
|
||||
msg.start.debugFlag,
|
||||
msg.start.mainJs,
|
||||
msg.start.mainMap
|
||||
);
|
||||
break;
|
||||
case "timerReady":
|
||||
timers.timerReady(msg.timerReady.id, msg.timerReady.done);
|
||||
|
|
|
@ -18,6 +18,8 @@ message StartMsg {
|
|||
string cwd = 1;
|
||||
repeated string argv = 2;
|
||||
bool debug_flag = 3;
|
||||
string main_js = 4; // The contents of dist/main.js
|
||||
string main_map = 5; // The contents of dist/main.map
|
||||
}
|
||||
|
||||
message SourceCodeFetchMsg {
|
||||
|
|
16
runtime.ts
16
runtime.ts
|
@ -19,16 +19,24 @@ const EOL = "\n";
|
|||
type AmdFactory = (...args: any[]) => undefined | object;
|
||||
type AmdDefine = (deps: string[], factory: AmdFactory) => void;
|
||||
|
||||
export function setup(mainJs: string, mainMap: string): void {
|
||||
sourceMaps.install({
|
||||
installPrepareStackTrace: true,
|
||||
getGeneratedContents: (filename: string): string => {
|
||||
util.log("getGeneratedContents", filename);
|
||||
if (filename === "dist/main.js") {
|
||||
return null;
|
||||
if (filename === "/main.js") {
|
||||
return mainJs;
|
||||
} else if (filename === "/main.map") {
|
||||
return mainMap;
|
||||
} else {
|
||||
const mod = FileModule.load(filename);
|
||||
if (!mod) {
|
||||
console.error("getGeneratedContents cannot find", filename);
|
||||
}
|
||||
return mod.outputCode;
|
||||
}
|
||||
return FileModule.load(filename).outputCode;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// This class represents a module. We call it FileModule to make it explicit
|
||||
// that each module represents a single file.
|
||||
|
|
7
testdata/008_stack_trace.ts
vendored
Normal file
7
testdata/008_stack_trace.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { throwsError } from "./subdir/mod1.ts";
|
||||
|
||||
function foo() {
|
||||
throwsError();
|
||||
}
|
||||
|
||||
foo();
|
4
testdata/subdir/mod1.ts
vendored
4
testdata/subdir/mod1.ts
vendored
|
@ -11,3 +11,7 @@ export function returnsFoo2(): string {
|
|||
export function printHello3(): void {
|
||||
printHello2();
|
||||
}
|
||||
|
||||
export function throwsError(): void {
|
||||
throw Error("exception from mod1");
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"allowJs": true,
|
||||
"module": "commonjs",
|
||||
"noImplicitAny": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"declaration": true,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { SourceMapConsumer, MappedPosition } from "source-map";
|
||||
import * as base64 from "base64-js";
|
||||
|
||||
const consumers = new Map<string, SourceMapConsumer>();
|
||||
|
||||
interface Options {
|
||||
// A callback the returns generated file contents.
|
||||
getGeneratedContents: GetGeneratedContentsCallback;
|
||||
|
@ -60,20 +62,17 @@ export function wrapCallSite(frame: CallSite): CallSite {
|
|||
// passed to eval() ending in "//# sourceURL=..." will return the source file
|
||||
// from getScriptNameOrSourceURL() instead
|
||||
const source = frame.getFileName() || frame.getScriptNameOrSourceURL();
|
||||
|
||||
if (source) {
|
||||
const line = frame.getLineNumber();
|
||||
const column = frame.getColumnNumber() - 1;
|
||||
|
||||
const position = mapSourcePosition({
|
||||
source,
|
||||
line,
|
||||
column
|
||||
});
|
||||
const position = mapSourcePosition({ source, line, column });
|
||||
frame = cloneCallSite(frame);
|
||||
frame.getFileName = () => position.source;
|
||||
frame.getLineNumber = () => position.line;
|
||||
frame.getColumnNumber = () => Number(position.column) + 1;
|
||||
frame.getScriptNameOrSourceURL = () => position.source;
|
||||
frame.toString = () => CallSiteToString(frame);
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
@ -96,7 +95,7 @@ function cloneCallSite(frame: CallSite): CallSite {
|
|||
const frame_ = frame as any;
|
||||
const props = Object.getOwnPropertyNames(Object.getPrototypeOf(frame));
|
||||
props.forEach(name => {
|
||||
obj[name] = /^(?:is|get|toString)/.test(name)
|
||||
obj[name] = /^(?:is|get)/.test(name)
|
||||
? () => frame_[name].call(frame)
|
||||
: frame_[name];
|
||||
});
|
||||
|
@ -104,6 +103,79 @@ function cloneCallSite(frame: CallSite): CallSite {
|
|||
// tslint:enable:no-any
|
||||
}
|
||||
|
||||
// Taken from source-map-support, original copied from V8's messages.js
|
||||
// MIT License. Copyright (c) 2014 Evan Wallace
|
||||
function CallSiteToString(frame: CallSite): string {
|
||||
let fileName;
|
||||
let fileLocation = "";
|
||||
if (frame.isNative()) {
|
||||
fileLocation = "native";
|
||||
} else {
|
||||
fileName = frame.getScriptNameOrSourceURL();
|
||||
if (!fileName && frame.isEval()) {
|
||||
fileLocation = frame.getEvalOrigin();
|
||||
fileLocation += ", "; // Expecting source position to follow.
|
||||
}
|
||||
|
||||
if (fileName) {
|
||||
fileLocation += fileName;
|
||||
} else {
|
||||
// Source code does not originate from a file and is not native, but we
|
||||
// can still get the source position inside the source string, e.g. in
|
||||
// an eval string.
|
||||
fileLocation += "<anonymous>";
|
||||
}
|
||||
const lineNumber = frame.getLineNumber();
|
||||
if (lineNumber != null) {
|
||||
fileLocation += ":" + String(lineNumber);
|
||||
const columnNumber = frame.getColumnNumber();
|
||||
if (columnNumber) {
|
||||
fileLocation += ":" + String(columnNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let line = "";
|
||||
const functionName = frame.getFunctionName();
|
||||
let addSuffix = true;
|
||||
const isConstructor = frame.isConstructor();
|
||||
const isMethodCall = !(frame.isToplevel() || isConstructor);
|
||||
if (isMethodCall) {
|
||||
let typeName = frame.getTypeName();
|
||||
// Fixes shim to be backward compatable with Node v0 to v4
|
||||
if (typeName === "[object Object]") {
|
||||
typeName = "null";
|
||||
}
|
||||
const methodName = frame.getMethodName();
|
||||
if (functionName) {
|
||||
if (typeName && functionName.indexOf(typeName) !== 0) {
|
||||
line += typeName + ".";
|
||||
}
|
||||
line += functionName;
|
||||
if (
|
||||
methodName &&
|
||||
functionName.indexOf("." + methodName) !==
|
||||
functionName.length - methodName.length - 1
|
||||
) {
|
||||
line += " [as " + methodName + "]";
|
||||
}
|
||||
} else {
|
||||
line += typeName + "." + (methodName || "<anonymous>");
|
||||
}
|
||||
} else if (isConstructor) {
|
||||
line += "new " + (functionName || "<anonymous>");
|
||||
} else if (functionName) {
|
||||
line += functionName;
|
||||
} else {
|
||||
line += fileLocation;
|
||||
addSuffix = false;
|
||||
}
|
||||
if (addSuffix) {
|
||||
line += " (" + fileLocation + ")";
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
// Regex for detecting source maps
|
||||
const reSourceMap = /^data:application\/json[^,]+base64,/;
|
||||
|
||||
|
@ -124,16 +196,16 @@ function loadConsumer(source: string): SourceMapConsumer {
|
|||
if (reSourceMap.test(sourceMappingURL)) {
|
||||
// Support source map URL as a data url
|
||||
const rawData = sourceMappingURL.slice(sourceMappingURL.indexOf(",") + 1);
|
||||
//sourceMapData = bufferFrom(rawData, "base64").toString();
|
||||
const ui8 = base64.toByteArray(rawData);
|
||||
sourceMapData = arrayToStr(ui8);
|
||||
sourceMappingURL = source;
|
||||
} else {
|
||||
// Support source map URLs relative to the source URL
|
||||
//sourceMappingURL = supportRelativeURL(source, sourceMappingURL);
|
||||
//sourceMapData = retrieveFile(sourceMappingURL);
|
||||
sourceMapData = getGeneratedContents(sourceMappingURL);
|
||||
}
|
||||
|
||||
//console.log("sourceMapData", sourceMapData);
|
||||
const rawSourceMap = JSON.parse(sourceMapData);
|
||||
consumer = new SourceMapConsumer(rawSourceMap);
|
||||
consumers.set(source, consumer);
|
||||
|
@ -141,8 +213,6 @@ function loadConsumer(source: string): SourceMapConsumer {
|
|||
return consumer;
|
||||
}
|
||||
|
||||
const consumers = new Map<string, SourceMapConsumer>();
|
||||
|
||||
function retrieveSourceMapURL(fileData: string): string {
|
||||
// Get the URL of the source map
|
||||
// tslint:disable-next-line:max-line-length
|
||||
|
|
Loading…
Reference in a new issue