summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--deno_dir.go8
-rw-r--r--main.go14
-rw-r--r--main.ts18
-rw-r--r--msg.proto2
-rw-r--r--runtime.ts26
-rw-r--r--testdata/008_stack_trace.ts7
-rw-r--r--testdata/subdir/mod1.ts4
-rw-r--r--tsconfig.json2
-rw-r--r--v8_source_maps.ts92
10 files changed, 142 insertions, 32 deletions
diff --git a/Makefile b/Makefile
index 6f74d8593..45d402c99 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
TS_FILES = \
+ tsconfig.json \
main.ts \
msg.pb.d.ts \
msg.pb.js \
diff --git a/deno_dir.go b/deno_dir.go
index b3a8c78b9..185f7abe0 100644
--- a/deno_dir.go
+++ b/deno_dir.go
@@ -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")
diff --git a/main.go b/main.go
index 1c2a99720..9b4b6c120 100644
--- a/main.go
+++ b/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,
},
},
})
diff --git a/main.ts b/main.ts
index 356fe329a..28c1ecdff 100644
--- a/main.ts
+++ b/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);
diff --git a/msg.proto b/msg.proto
index dba8cab94..821d00a20 100644
--- a/msg.proto
+++ b/msg.proto
@@ -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 {
diff --git a/runtime.ts b/runtime.ts
index 9ca3b4944..57b556c21 100644
--- a/runtime.ts
+++ b/runtime.ts
@@ -19,16 +19,24 @@ const EOL = "\n";
type AmdFactory = (...args: any[]) => undefined | object;
type AmdDefine = (deps: string[], factory: AmdFactory) => void;
-sourceMaps.install({
- installPrepareStackTrace: true,
- getGeneratedContents: (filename: string): string => {
- util.log("getGeneratedContents", filename);
- if (filename === "dist/main.js") {
- return null;
+export function setup(mainJs: string, mainMap: string): void {
+ sourceMaps.install({
+ installPrepareStackTrace: true,
+ getGeneratedContents: (filename: string): string => {
+ 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.
diff --git a/testdata/008_stack_trace.ts b/testdata/008_stack_trace.ts
new file mode 100644
index 000000000..6aa0fcc3b
--- /dev/null
+++ b/testdata/008_stack_trace.ts
@@ -0,0 +1,7 @@
+import { throwsError } from "./subdir/mod1.ts";
+
+function foo() {
+ throwsError();
+}
+
+foo();
diff --git a/testdata/subdir/mod1.ts b/testdata/subdir/mod1.ts
index c09755a3b..393535588 100644
--- a/testdata/subdir/mod1.ts
+++ b/testdata/subdir/mod1.ts
@@ -11,3 +11,7 @@ export function returnsFoo2(): string {
export function printHello3(): void {
printHello2();
}
+
+export function throwsError(): void {
+ throw Error("exception from mod1");
+}
diff --git a/tsconfig.json b/tsconfig.json
index d598b8ce0..4de82936c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -3,7 +3,7 @@
"allowJs": true,
"module": "commonjs",
"noImplicitAny": true,
- "sourceMap": true,
+ "baseUrl": ".",
"removeComments": true,
"preserveConstEnums": true,
"declaration": true,
diff --git a/v8_source_maps.ts b/v8_source_maps.ts
index d80efb921..5f5b1c779 100644
--- a/v8_source_maps.ts
+++ b/v8_source_maps.ts
@@ -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