diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/console.ts | 5 | ||||
-rw-r--r-- | js/console_test.ts | 5 | ||||
-rw-r--r-- | js/format_error.ts | 21 | ||||
-rw-r--r-- | js/libdeno.ts | 47 | ||||
-rw-r--r-- | js/repl.ts | 19 |
5 files changed, 63 insertions, 34 deletions
diff --git a/js/console.ts b/js/console.ts index 0797ab8e9..e5dafceee 100644 --- a/js/console.ts +++ b/js/console.ts @@ -3,6 +3,8 @@ import { isTypedArray } from "./util"; import { TextEncoder } from "./text_encoding"; import { File, stdout } from "./files"; import { cliTable } from "./console_table"; +import { formatError } from "./format_error"; +import { libdeno } from "./libdeno"; // tslint:disable-next-line:no-any type ConsoleContext = Set<any>; @@ -263,7 +265,8 @@ function createObjectString( ...args: [ConsoleContext, number, number] ): string { if (value instanceof Error) { - return value.stack! || ""; + const errorJSON = libdeno.errorToJSON(value); + return formatError(errorJSON); } else if (Array.isArray(value)) { return createArrayString(value, ...args); } else if (value instanceof Number) { diff --git a/js/console_test.ts b/js/console_test.ts index 577c8bf5d..f84dc247a 100644 --- a/js/console_test.ts +++ b/js/console_test.ts @@ -1,6 +1,6 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. import { Console, libdeno, stringifyArgs, inspect, write, stdout } from "deno"; -import { test, assertEqual } from "./test_util.ts"; +import { test, assertEqual, assert } from "./test_util.ts"; const console = new Console(libdeno.print); @@ -245,7 +245,8 @@ test(function consoleTestError() { try { throw new MyError("This is an error"); } catch (e) { - assertEqual(stringify(e).split("\n")[0], "MyError: This is an error"); + assert(stringify(e).split("\n")[3] + .includes("MyError: This is an error")); } }); diff --git a/js/format_error.ts b/js/format_error.ts new file mode 100644 index 000000000..ebc579355 --- /dev/null +++ b/js/format_error.ts @@ -0,0 +1,21 @@ +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +import * as msg from "gen/msg_generated"; +import * as flatbuffers from "./flatbuffers"; +import { sendSync } from "./dispatch"; +import { assert } from "./util"; + +export function formatError(errString: string): string { + const builder = flatbuffers.createBuilder(); + const errString_ = builder.createString(errString); + msg.FormatError.startFormatError(builder); + msg.FormatError.addError(builder, errString_); + const offset = msg.FormatError.endFormatError(builder); + const baseRes = sendSync(builder, msg.Any.FormatError, offset); + assert(baseRes != null); + assert(msg.Any.FormatErrorRes === baseRes!.innerType()); + const formatErrorResMsg = new msg.FormatErrorRes(); + assert(baseRes!.inner(formatErrorResMsg) != null); + const formattedError = formatErrorResMsg.error(); + assert(formatError != null); + return formattedError!; +} diff --git a/js/libdeno.ts b/js/libdeno.ts index 401ffae40..7d2bc3ede 100644 --- a/js/libdeno.ts +++ b/js/libdeno.ts @@ -3,11 +3,17 @@ import { globalEval } from "./global_eval"; // The libdeno functions are moved so that users can't access them. type MessageCallback = (msg: Uint8Array) => void; -export type PromiseRejectEvent = - | "RejectWithNoHandler" - | "HandlerAddedAfterReject" - | "ResolveAfterResolved" - | "RejectAfterResolved"; + +interface EvalErrorInfo { + // Is the object thrown a native Error? + isNativeError: boolean; + // Was the error happened during compilation? + isCompileError: boolean; + // The actual thrown entity + // (might be an Error or anything else thrown by the user) + // If isNativeError is true, this is an Error + thrown: any; // tslint:disable-line:no-any +} interface Libdeno { recv(cb: MessageCallback): void; @@ -20,26 +26,17 @@ interface Libdeno { builtinModules: { [s: string]: object }; - setGlobalErrorHandler: ( - handler: ( - message: string, - source: string, - line: number, - col: number, - error: Error - ) => void - ) => void; - - setPromiseRejectHandler: ( - handler: ( - error: Error | string, - event: PromiseRejectEvent, - /* tslint:disable-next-line:no-any */ - promise: Promise<any> - ) => void - ) => void; - - setPromiseErrorExaminer: (handler: () => boolean) => void; + /** Evaluate provided code in the current context. + * It differs from eval(...) in that it does not create a new context. + * Returns an array: [output, errInfo]. + * If an error occurs, `output` becomes null and `errInfo` is non-null. + */ + evalContext( + code: string + ): [any, EvalErrorInfo | null] /* tslint:disable-line:no-any */; + + // tslint:disable-next-line:no-any + errorToJSON: (e: Error) => string; } const window = globalEval("this"); diff --git a/js/repl.ts b/js/repl.ts index 6fb395e1b..6676721fc 100644 --- a/js/repl.ts +++ b/js/repl.ts @@ -7,6 +7,8 @@ import { close } from "./files"; import * as dispatch from "./dispatch"; import { exit } from "./os"; import { globalEval } from "./global_eval"; +import { libdeno } from "./libdeno"; +import { formatError } from "./format_error"; const window = globalEval("this"); @@ -96,14 +98,19 @@ export async function replLoop(): Promise<void> { } function evaluate(code: string): void { - try { - const result = eval.call(window, code); // FIXME use a new scope. + if (code.trim() === "") { + return; + } + const [result, errInfo] = libdeno.evalContext(code); + if (!errInfo) { console.log(result); - } catch (err) { - if (err instanceof Error) { - console.error(`${err.constructor.name}: ${err.message}`); + } else { + if (errInfo.isNativeError) { + const formattedError = formatError( + libdeno.errorToJSON(errInfo.thrown as Error)); + console.error(formattedError); } else { - console.error("Thrown:", err); + console.error("Thrown:", errInfo.thrown); } } } |