mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
refactor(cli/fmt_errors): Format stack frames in prepareStackTrace() (#4706)
This commit is contained in:
parent
2feb661b85
commit
2b362bef85
25 changed files with 224 additions and 427 deletions
|
@ -4,7 +4,6 @@ use crate::colors;
|
||||||
use crate::source_maps::apply_source_map;
|
use crate::source_maps::apply_source_map;
|
||||||
use crate::source_maps::SourceMapGetter;
|
use crate::source_maps::SourceMapGetter;
|
||||||
use deno_core::ErrBox;
|
use deno_core::ErrBox;
|
||||||
use deno_core::JSStackFrame;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -25,18 +24,13 @@ fn format_source_name(
|
||||||
script_name: String,
|
script_name: String,
|
||||||
line_number: i64,
|
line_number: i64,
|
||||||
column: i64,
|
column: i64,
|
||||||
is_internal: bool,
|
|
||||||
) -> String {
|
) -> String {
|
||||||
let line_number = line_number + 1;
|
let line_number = line_number + 1;
|
||||||
let column = column + 1;
|
let column = column + 1;
|
||||||
if is_internal {
|
let script_name_c = colors::cyan(script_name);
|
||||||
format!("{}:{}:{}", script_name, line_number, column)
|
let line_c = colors::yellow(line_number.to_string());
|
||||||
} else {
|
let column_c = colors::yellow(column.to_string());
|
||||||
let script_name_c = colors::cyan(script_name);
|
format!("{}:{}:{}", script_name_c, line_c, column_c)
|
||||||
let line_c = colors::yellow(line_number.to_string());
|
|
||||||
let column_c = colors::yellow(column.to_string());
|
|
||||||
format!("{}:{}:{}", script_name_c, line_c, column_c)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Formats optional source, line number and column into a single string.
|
/// Formats optional source, line number and column into a single string.
|
||||||
|
@ -55,7 +49,6 @@ pub fn format_maybe_source_name(
|
||||||
script_name.unwrap(),
|
script_name.unwrap(),
|
||||||
line_number.unwrap(),
|
line_number.unwrap(),
|
||||||
column.unwrap(),
|
column.unwrap(),
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,54 +120,6 @@ pub fn format_error_message(msg: String) -> String {
|
||||||
format!("{} {}", preamble, msg)
|
format!("{} {}", preamble, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_stack_frame(frame: &JSStackFrame, is_internal_frame: bool) -> String {
|
|
||||||
// Note when we print to string, we change from 0-indexed to 1-indexed.
|
|
||||||
let function_name = if is_internal_frame {
|
|
||||||
colors::italic_bold_gray(frame.function_name.clone()).to_string()
|
|
||||||
} else {
|
|
||||||
colors::italic_bold(frame.function_name.clone()).to_string()
|
|
||||||
};
|
|
||||||
let mut source_loc = format_source_name(
|
|
||||||
frame.script_name.clone(),
|
|
||||||
frame.line_number,
|
|
||||||
frame.column,
|
|
||||||
is_internal_frame,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Each chunk of styled text is auto-resetted on end,
|
|
||||||
// which make nesting not working.
|
|
||||||
// Explicitly specify color for each section.
|
|
||||||
let mut at_prefix = " at".to_owned();
|
|
||||||
if is_internal_frame {
|
|
||||||
at_prefix = colors::gray(at_prefix).to_string();
|
|
||||||
}
|
|
||||||
if !frame.function_name.is_empty() || frame.is_eval {
|
|
||||||
source_loc = format!("({})", source_loc); // wrap then style
|
|
||||||
}
|
|
||||||
if is_internal_frame {
|
|
||||||
source_loc = colors::gray(source_loc).to_string();
|
|
||||||
}
|
|
||||||
if !frame.function_name.is_empty() {
|
|
||||||
if frame.is_async {
|
|
||||||
format!(
|
|
||||||
"{} {} {} {}",
|
|
||||||
at_prefix,
|
|
||||||
colors::gray("async".to_owned()).to_string(),
|
|
||||||
function_name,
|
|
||||||
source_loc
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
format!("{} {} {}", at_prefix, function_name, source_loc)
|
|
||||||
}
|
|
||||||
} else if frame.is_eval {
|
|
||||||
format!("{} eval {}", at_prefix, source_loc)
|
|
||||||
} else if frame.is_async {
|
|
||||||
format!("{} async {}", at_prefix, source_loc)
|
|
||||||
} else {
|
|
||||||
format!("{} {}", at_prefix, source_loc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrapper around deno_core::JSError which provides color to_string.
|
/// Wrapper around deno_core::JSError which provides color to_string.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct JSError(deno_core::JSError);
|
pub struct JSError(deno_core::JSError);
|
||||||
|
@ -251,10 +196,8 @@ impl fmt::Display for JSError {
|
||||||
self.format_source_name(),
|
self.format_source_name(),
|
||||||
self.format_source_line(0),
|
self.format_source_line(0),
|
||||||
)?;
|
)?;
|
||||||
|
for formatted_frame in &self.0.formatted_frames {
|
||||||
for frame in &self.0.frames {
|
write!(f, "\n at {}", formatted_frame)?;
|
||||||
let is_internal_frame = frame.script_name.starts_with("$deno$");
|
|
||||||
write!(f, "\n{}", format_stack_frame(&frame, is_internal_frame))?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -267,52 +210,6 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::colors::strip_ansi_codes;
|
use crate::colors::strip_ansi_codes;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn js_error_to_string() {
|
|
||||||
let core_js_error = deno_core::JSError {
|
|
||||||
message: "Error: foo bar".to_string(),
|
|
||||||
source_line: None,
|
|
||||||
script_resource_name: None,
|
|
||||||
line_number: None,
|
|
||||||
start_column: None,
|
|
||||||
end_column: None,
|
|
||||||
frames: vec![
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 4,
|
|
||||||
column: 16,
|
|
||||||
script_name: "foo_bar.ts".to_string(),
|
|
||||||
function_name: "foo".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 5,
|
|
||||||
column: 20,
|
|
||||||
script_name: "bar_baz.ts".to_string(),
|
|
||||||
function_name: "qat".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 1,
|
|
||||||
column: 1,
|
|
||||||
script_name: "deno_main.js".to_string(),
|
|
||||||
function_name: "".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
already_source_mapped: true,
|
|
||||||
};
|
|
||||||
let formatted_error = JSError(core_js_error).to_string();
|
|
||||||
let actual = strip_ansi_codes(&formatted_error);
|
|
||||||
let expected = "error: Error: foo bar\n at foo (foo_bar.ts:5:17)\n at qat (bar_baz.ts:6:21)\n at deno_main.js:2:2";
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_format_none_source_name() {
|
fn test_format_none_source_name() {
|
||||||
let actual = format_maybe_source_name(None, None, None);
|
let actual = format_maybe_source_name(None, None, None);
|
||||||
|
|
|
@ -62,3 +62,16 @@ export function white(str: string): string {
|
||||||
export function gray(str: string): string {
|
export function gray(str: string): string {
|
||||||
return run(str, code(90, 39));
|
return run(str, code(90, 39));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/chalk/ansi-regex/blob/2b56fb0c7a07108e5b54241e8faec160d393aedb/index.js
|
||||||
|
const ANSI_PATTERN = new RegExp(
|
||||||
|
[
|
||||||
|
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
|
||||||
|
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
|
||||||
|
].join("|"),
|
||||||
|
"g"
|
||||||
|
);
|
||||||
|
|
||||||
|
export function stripColor(string: string): string {
|
||||||
|
return string.replace(ANSI_PATTERN, "");
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
// Some of the code here is adapted directly from V8 and licensed under a BSD
|
// Some of the code here is adapted directly from V8 and licensed under a BSD
|
||||||
// style license available here: https://github.com/v8/v8/blob/24886f2d1c565287d33d71e4109a53bf0b54b75c/LICENSE.v8
|
// style license available here: https://github.com/v8/v8/blob/24886f2d1c565287d33d71e4109a53bf0b54b75c/LICENSE.v8
|
||||||
|
import * as colors from "./colors.ts";
|
||||||
import { applySourceMap, Location } from "./ops/errors.ts";
|
import { applySourceMap, Location } from "./ops/errors.ts";
|
||||||
import { assert } from "./util.ts";
|
import { assert } from "./util.ts";
|
||||||
import { exposeForTest } from "./internals.ts";
|
import { exposeForTest } from "./internals.ts";
|
||||||
|
@ -93,9 +94,12 @@ function getMethodCall(callSite: CallSite): string {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFileLocation(callSite: CallSite): string {
|
function getFileLocation(callSite: CallSite, isInternal = false): string {
|
||||||
|
const cyan = isInternal ? colors.gray : colors.cyan;
|
||||||
|
const yellow = isInternal ? colors.gray : colors.yellow;
|
||||||
|
const black = isInternal ? colors.gray : (s: string): string => s;
|
||||||
if (callSite.isNative()) {
|
if (callSite.isNative()) {
|
||||||
return "native";
|
return cyan("native");
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = "";
|
let result = "";
|
||||||
|
@ -104,29 +108,32 @@ function getFileLocation(callSite: CallSite): string {
|
||||||
if (!fileName && callSite.isEval()) {
|
if (!fileName && callSite.isEval()) {
|
||||||
const evalOrigin = callSite.getEvalOrigin();
|
const evalOrigin = callSite.getEvalOrigin();
|
||||||
assert(evalOrigin != null);
|
assert(evalOrigin != null);
|
||||||
result += `${evalOrigin}, `;
|
result += cyan(`${evalOrigin}, `);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileName) {
|
if (fileName) {
|
||||||
result += fileName;
|
result += cyan(fileName);
|
||||||
} else {
|
} else {
|
||||||
result += "<anonymous>";
|
result += cyan("<anonymous>");
|
||||||
}
|
}
|
||||||
|
|
||||||
const lineNumber = callSite.getLineNumber();
|
const lineNumber = callSite.getLineNumber();
|
||||||
if (lineNumber != null) {
|
if (lineNumber != null) {
|
||||||
result += `:${lineNumber}`;
|
result += `${black(":")}${yellow(lineNumber.toString())}`;
|
||||||
|
|
||||||
const columnNumber = callSite.getColumnNumber();
|
const columnNumber = callSite.getColumnNumber();
|
||||||
if (columnNumber != null) {
|
if (columnNumber != null) {
|
||||||
result += `:${columnNumber}`;
|
result += `${black(":")}${yellow(columnNumber.toString())}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function callSiteToString(callSite: CallSite): string {
|
function callSiteToString(callSite: CallSite, isInternal = false): string {
|
||||||
|
const cyan = isInternal ? colors.gray : colors.cyan;
|
||||||
|
const black = isInternal ? colors.gray : (s: string): string => s;
|
||||||
|
|
||||||
let result = "";
|
let result = "";
|
||||||
const functionName = callSite.getFunctionName();
|
const functionName = callSite.getFunctionName();
|
||||||
|
|
||||||
|
@ -137,29 +144,33 @@ function callSiteToString(callSite: CallSite): string {
|
||||||
const isMethodCall = !(isTopLevel || isConstructor);
|
const isMethodCall = !(isTopLevel || isConstructor);
|
||||||
|
|
||||||
if (isAsync) {
|
if (isAsync) {
|
||||||
result += "async ";
|
result += colors.gray("async ");
|
||||||
}
|
}
|
||||||
if (isPromiseAll) {
|
if (isPromiseAll) {
|
||||||
result += `Promise.all (index ${callSite.getPromiseIndex()})`;
|
result += colors.bold(
|
||||||
|
colors.italic(black(`Promise.all (index ${callSite.getPromiseIndex()})`))
|
||||||
|
);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (isMethodCall) {
|
if (isMethodCall) {
|
||||||
result += getMethodCall(callSite);
|
result += colors.bold(colors.italic(black(getMethodCall(callSite))));
|
||||||
} else if (isConstructor) {
|
} else if (isConstructor) {
|
||||||
result += "new ";
|
result += colors.gray("new ");
|
||||||
if (functionName) {
|
if (functionName) {
|
||||||
result += functionName;
|
result += colors.bold(colors.italic(black(functionName)));
|
||||||
} else {
|
} else {
|
||||||
result += "<anonymous>";
|
result += cyan("<anonymous>");
|
||||||
}
|
}
|
||||||
} else if (functionName) {
|
} else if (functionName) {
|
||||||
result += functionName;
|
result += colors.bold(colors.italic(black(functionName)));
|
||||||
} else {
|
} else {
|
||||||
result += getFileLocation(callSite);
|
result += getFileLocation(callSite, isInternal);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result += ` (${getFileLocation(callSite)})`;
|
result += ` ${black("(")}${getFileLocation(callSite, isInternal)}${black(
|
||||||
|
")"
|
||||||
|
)}`;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +218,10 @@ function prepareStackTrace(
|
||||||
error: Error,
|
error: Error,
|
||||||
structuredStackTrace: CallSite[]
|
structuredStackTrace: CallSite[]
|
||||||
): string {
|
): string {
|
||||||
Object.defineProperty(error, "__callSiteEvals", { value: [] });
|
Object.defineProperties(error, {
|
||||||
|
__callSiteEvals: { value: [] },
|
||||||
|
__formattedFrames: { value: [] },
|
||||||
|
});
|
||||||
const errorString =
|
const errorString =
|
||||||
`${error.name}: ${error.message}\n` +
|
`${error.name}: ${error.message}\n` +
|
||||||
structuredStackTrace
|
structuredStackTrace
|
||||||
|
@ -230,16 +244,23 @@ function prepareStackTrace(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.map((callSite): string => {
|
.map((callSite): string => {
|
||||||
|
const isInternal =
|
||||||
|
callSite.getFileName()?.startsWith("$deno$") ?? false;
|
||||||
|
const string = callSiteToString(callSite, isInternal);
|
||||||
const callSiteEv = Object.freeze(evaluateCallSite(callSite));
|
const callSiteEv = Object.freeze(evaluateCallSite(callSite));
|
||||||
if (callSiteEv.lineNumber != null && callSiteEv.columnNumber != null) {
|
if (callSiteEv.lineNumber != null && callSiteEv.columnNumber != null) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
error["__callSiteEvals"].push(callSiteEv);
|
error.__callSiteEvals.push(callSiteEv);
|
||||||
|
// @ts-ignore
|
||||||
|
error.__formattedFrames.push(string);
|
||||||
}
|
}
|
||||||
return ` at ${callSiteToString(callSite)}`;
|
return ` at ${colors.stripColor(string)}`;
|
||||||
})
|
})
|
||||||
.join("\n");
|
.join("\n");
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
Object.freeze(error["__callSiteEvals"]);
|
Object.freeze(error.__callSiteEvals);
|
||||||
|
// @ts-ignore
|
||||||
|
Object.freeze(error.__formattedFrames);
|
||||||
return errorString;
|
return errorString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
//! This mod provides functions to remap a deno_core::deno_core::JSError based on a source map
|
//! This mod provides functions to remap a deno_core::deno_core::JSError based on a source map
|
||||||
use deno_core::JSStackFrame;
|
|
||||||
use sourcemap::SourceMap;
|
use sourcemap::SourceMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
@ -47,19 +46,10 @@ pub fn apply_source_map<G: SourceMapGetter>(
|
||||||
js_error: &deno_core::JSError,
|
js_error: &deno_core::JSError,
|
||||||
getter: &G,
|
getter: &G,
|
||||||
) -> deno_core::JSError {
|
) -> deno_core::JSError {
|
||||||
|
// Note that js_error.frames has already been source mapped in
|
||||||
|
// prepareStackTrace().
|
||||||
let mut mappings_map: CachedMaps = HashMap::new();
|
let mut mappings_map: CachedMaps = HashMap::new();
|
||||||
|
|
||||||
let frames = if !js_error.already_source_mapped {
|
|
||||||
let mut frames = Vec::<JSStackFrame>::new();
|
|
||||||
for frame in &js_error.frames {
|
|
||||||
let f = frame_apply_source_map(&frame, &mut mappings_map, getter);
|
|
||||||
frames.push(f);
|
|
||||||
}
|
|
||||||
frames
|
|
||||||
} else {
|
|
||||||
js_error.frames.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let (script_resource_name, line_number, start_column) =
|
let (script_resource_name, line_number, start_column) =
|
||||||
get_maybe_orig_position(
|
get_maybe_orig_position(
|
||||||
js_error.script_resource_name.clone(),
|
js_error.script_resource_name.clone(),
|
||||||
|
@ -102,32 +92,8 @@ pub fn apply_source_map<G: SourceMapGetter>(
|
||||||
line_number,
|
line_number,
|
||||||
start_column,
|
start_column,
|
||||||
end_column,
|
end_column,
|
||||||
frames,
|
frames: js_error.frames.clone(),
|
||||||
already_source_mapped: js_error.already_source_mapped,
|
formatted_frames: js_error.formatted_frames.clone(),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn frame_apply_source_map<G: SourceMapGetter>(
|
|
||||||
frame: &JSStackFrame,
|
|
||||||
mappings_map: &mut CachedMaps,
|
|
||||||
getter: &G,
|
|
||||||
) -> JSStackFrame {
|
|
||||||
let (script_name, line_number, column) = get_orig_position(
|
|
||||||
frame.script_name.to_string(),
|
|
||||||
frame.line_number,
|
|
||||||
frame.column,
|
|
||||||
mappings_map,
|
|
||||||
getter,
|
|
||||||
);
|
|
||||||
|
|
||||||
JSStackFrame {
|
|
||||||
script_name,
|
|
||||||
function_name: frame.function_name.clone(),
|
|
||||||
line_number,
|
|
||||||
column,
|
|
||||||
is_eval: frame.is_eval,
|
|
||||||
is_constructor: frame.is_constructor,
|
|
||||||
is_async: frame.is_async,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,116 +211,6 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn apply_source_map_1() {
|
|
||||||
let core_js_error = deno_core::JSError {
|
|
||||||
message: "Error: foo bar".to_string(),
|
|
||||||
source_line: None,
|
|
||||||
script_resource_name: None,
|
|
||||||
line_number: None,
|
|
||||||
start_column: None,
|
|
||||||
end_column: None,
|
|
||||||
frames: vec![
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 4,
|
|
||||||
column: 16,
|
|
||||||
script_name: "foo_bar.ts".to_string(),
|
|
||||||
function_name: "foo".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 5,
|
|
||||||
column: 20,
|
|
||||||
script_name: "bar_baz.ts".to_string(),
|
|
||||||
function_name: "qat".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 1,
|
|
||||||
column: 1,
|
|
||||||
script_name: "deno_main.js".to_string(),
|
|
||||||
function_name: "".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
already_source_mapped: false,
|
|
||||||
};
|
|
||||||
let getter = MockSourceMapGetter {};
|
|
||||||
let actual = apply_source_map(&core_js_error, &getter);
|
|
||||||
let expected = deno_core::JSError {
|
|
||||||
message: "Error: foo bar".to_string(),
|
|
||||||
source_line: None,
|
|
||||||
script_resource_name: None,
|
|
||||||
line_number: None,
|
|
||||||
start_column: None,
|
|
||||||
end_column: None,
|
|
||||||
frames: vec![
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 5,
|
|
||||||
column: 12,
|
|
||||||
script_name: "foo_bar.ts".to_string(),
|
|
||||||
function_name: "foo".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 4,
|
|
||||||
column: 14,
|
|
||||||
script_name: "bar_baz.ts".to_string(),
|
|
||||||
function_name: "qat".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 1,
|
|
||||||
column: 1,
|
|
||||||
script_name: "deno_main.js".to_string(),
|
|
||||||
function_name: "".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
already_source_mapped: false,
|
|
||||||
};
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn apply_source_map_2() {
|
|
||||||
let e = deno_core::JSError {
|
|
||||||
message: "TypeError: baz".to_string(),
|
|
||||||
source_line: None,
|
|
||||||
script_resource_name: None,
|
|
||||||
line_number: None,
|
|
||||||
start_column: None,
|
|
||||||
end_column: None,
|
|
||||||
frames: vec![JSStackFrame {
|
|
||||||
line_number: 11,
|
|
||||||
column: 12,
|
|
||||||
script_name: "CLI_SNAPSHOT.js".to_string(),
|
|
||||||
function_name: "setLogDebug".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
}],
|
|
||||||
already_source_mapped: false,
|
|
||||||
};
|
|
||||||
let getter = MockSourceMapGetter {};
|
|
||||||
let actual = apply_source_map(&e, &getter);
|
|
||||||
assert_eq!(actual.message, "TypeError: baz");
|
|
||||||
// Because this is accessing the live bundle, this test might be more fragile
|
|
||||||
assert_eq!(actual.frames.len(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn apply_source_map_line() {
|
fn apply_source_map_line() {
|
||||||
let e = deno_core::JSError {
|
let e = deno_core::JSError {
|
||||||
|
@ -365,7 +221,7 @@ mod tests {
|
||||||
start_column: Some(16),
|
start_column: Some(16),
|
||||||
end_column: None,
|
end_column: None,
|
||||||
frames: vec![],
|
frames: vec![],
|
||||||
already_source_mapped: false,
|
formatted_frames: vec![],
|
||||||
};
|
};
|
||||||
let getter = MockSourceMapGetter {};
|
let getter = MockSourceMapGetter {};
|
||||||
let actual = apply_source_map(&e, &getter);
|
let actual = apply_source_map(&e, &getter);
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
error: Uncaught BadResource: Bad resource ID
|
error: Uncaught BadResource: Bad resource ID
|
||||||
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
||||||
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at sendAsync ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at Object.sendAsync ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at async main ([WILDCARD]tests/044_bad_resource.ts:[WILDCARD])
|
at async main ([WILDCARD]tests/044_bad_resource.ts:[WILDCARD])
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
[WILDCARD]error: Uncaught NotFound: Cannot resolve module "[WILDCARD]/bad-module.ts" from "[WILDCARD]/error_004_missing_module.ts"
|
[WILDCARD]error: Uncaught NotFound: Cannot resolve module "[WILDCARD]/bad-module.ts" from "[WILDCARD]/error_004_missing_module.ts"
|
||||||
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
||||||
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at sendAsync ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at Object.sendAsync ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at async processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
|
||||||
at async processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at async processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
|
at async Object.processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
[WILDCARD]error: Uncaught NotFound: Cannot resolve module "[WILDCARD]/bad-module.ts" from "[WILDCARD]/error_005_missing_dynamic_import.ts"
|
[WILDCARD]error: Uncaught NotFound: Cannot resolve module "[WILDCARD]/bad-module.ts" from "[WILDCARD]/error_005_missing_dynamic_import.ts"
|
||||||
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
||||||
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at sendAsync ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at Object.sendAsync ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at async processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
|
||||||
at async processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at async processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
|
at async Object.processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
[WILDCARD]error: Uncaught NotFound: Cannot resolve module "[WILDCARD]/non-existent" from "[WILDCARD]/error_006_import_ext_failure.ts"
|
[WILDCARD]error: Uncaught NotFound: Cannot resolve module "[WILDCARD]/non-existent" from "[WILDCARD]/error_006_import_ext_failure.ts"
|
||||||
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
||||||
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at sendAsync[WILDCARD] ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at Object.sendAsync ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at async processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
|
||||||
at async processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at async processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
|
at async Object.processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[WILDCARD]error: Uncaught URIError: relative import path "bad-module.ts" not prefixed with / or ./ or ../ Imported from "[WILDCARD]/error_011_bad_module_specifier.ts"
|
[WILDCARD]error: Uncaught URIError: relative import path "bad-module.ts" not prefixed with / or ./ or ../ Imported from "[WILDCARD]/error_011_bad_module_specifier.ts"
|
||||||
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
||||||
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
||||||
at sendSync ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
at Object.sendSync ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
||||||
at resolveModules ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at resolveModules ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at Object.processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[WILDCARD]error: Uncaught URIError: relative import path "bad-module.ts" not prefixed with / or ./ or ../ Imported from "[WILDCARD]/error_012_bad_dynamic_import_specifier.ts"
|
[WILDCARD]error: Uncaught URIError: relative import path "bad-module.ts" not prefixed with / or ./ or ../ Imported from "[WILDCARD]/error_012_bad_dynamic_import_specifier.ts"
|
||||||
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
||||||
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
||||||
at sendSync ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
at Object.sendSync ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
||||||
at resolveModules ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at resolveModules ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at Object.processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
||||||
|
|
10
cli/tests/error_019_stack_function.ts
Normal file
10
cli/tests/error_019_stack_function.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
function foo(): never {
|
||||||
|
throw new Error("function");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
foo();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error.stack);
|
||||||
|
throw error;
|
||||||
|
}
|
6
cli/tests/error_019_stack_function.ts.out
Normal file
6
cli/tests/error_019_stack_function.ts.out
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[WILDCARD]Error: function
|
||||||
|
at foo ([WILDCARD]tests/error_019_stack_function.ts:[WILDCARD])
|
||||||
|
at [WILDCARD]tests/error_019_stack_function.ts:[WILDCARD]
|
||||||
|
error: Uncaught Error: function
|
||||||
|
at foo ([WILDCARD]tests/error_019_stack_function.ts:[WILDCARD])
|
||||||
|
at [WILDCARD]tests/error_019_stack_function.ts:[WILDCARD]
|
12
cli/tests/error_020_stack_constructor.ts
Normal file
12
cli/tests/error_020_stack_constructor.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
class A {
|
||||||
|
constructor() {
|
||||||
|
throw new Error("constructor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new A();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error.stack);
|
||||||
|
throw error;
|
||||||
|
}
|
6
cli/tests/error_020_stack_constructor.ts.out
Normal file
6
cli/tests/error_020_stack_constructor.ts.out
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[WILDCARD]Error: constructor
|
||||||
|
at new A ([WILDCARD]tests/error_020_stack_constructor.ts:[WILDCARD])
|
||||||
|
at [WILDCARD]tests/error_020_stack_constructor.ts:[WILDCARD]
|
||||||
|
error: Uncaught Error: constructor
|
||||||
|
at new A ([WILDCARD]tests/error_020_stack_constructor.ts:[WILDCARD])
|
||||||
|
at [WILDCARD]tests/error_020_stack_constructor.ts:[WILDCARD]
|
12
cli/tests/error_021_stack_method.ts
Normal file
12
cli/tests/error_021_stack_method.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
class A {
|
||||||
|
m(): never {
|
||||||
|
throw new Error("method");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new A().m();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error.stack);
|
||||||
|
throw error;
|
||||||
|
}
|
6
cli/tests/error_021_stack_method.ts.out
Normal file
6
cli/tests/error_021_stack_method.ts.out
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[WILDCARD]Error: method
|
||||||
|
at A.m ([WILDCARD]tests/error_021_stack_method.ts:[WILDCARD])
|
||||||
|
at [WILDCARD]tests/error_021_stack_method.ts:[WILDCARD]
|
||||||
|
error: Uncaught Error: method
|
||||||
|
at A.m ([WILDCARD]tests/error_021_stack_method.ts:[WILDCARD])
|
||||||
|
at [WILDCARD]tests/error_021_stack_method.ts:[WILDCARD]
|
10
cli/tests/error_022_stack_custom_error.ts
Normal file
10
cli/tests/error_022_stack_custom_error.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
class CustomError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
this.name = "CustomError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const error = new CustomError("custom error");
|
||||||
|
console.log(error.stack);
|
||||||
|
throw error;
|
4
cli/tests/error_022_stack_custom_error.ts.out
Normal file
4
cli/tests/error_022_stack_custom_error.ts.out
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[WILDCARD]CustomError: custom error
|
||||||
|
at [WILDCARD]tests/error_022_stack_custom_error.ts:[WILDCARD]
|
||||||
|
error: Uncaught CustomError: custom error
|
||||||
|
at [WILDCARD]tests/error_022_stack_custom_error.ts:[WILDCARD]
|
12
cli/tests/error_023_stack_async.ts
Normal file
12
cli/tests/error_023_stack_async.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
const p = (async (): Promise<void> => {
|
||||||
|
await Promise.resolve().then((): never => {
|
||||||
|
throw new Error("async");
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await p;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error.stack);
|
||||||
|
throw error;
|
||||||
|
}
|
8
cli/tests/error_023_stack_async.ts.out
Normal file
8
cli/tests/error_023_stack_async.ts.out
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[WILDCARD]Error: async
|
||||||
|
at [WILDCARD]tests/error_023_stack_async.ts:[WILDCARD]
|
||||||
|
at async [WILDCARD]tests/error_023_stack_async.ts:[WILDCARD]
|
||||||
|
at async [WILDCARD]tests/error_023_stack_async.ts:[WILDCARD]
|
||||||
|
error: Uncaught Error: async
|
||||||
|
at [WILDCARD]tests/error_023_stack_async.ts:[WILDCARD]
|
||||||
|
at async [WILDCARD]tests/error_023_stack_async.ts:[WILDCARD]
|
||||||
|
at async [WILDCARD]tests/error_023_stack_async.ts:[WILDCARD]
|
|
@ -1,10 +0,0 @@
|
||||||
function foo(): never {
|
|
||||||
throw new Error("foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
foo();
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
[WILDCARD]Error: foo
|
|
||||||
at foo ([WILDCARD]tests/error_stack.ts:2:9)
|
|
||||||
at [WILDCARD]tests/error_stack.ts:6:3
|
|
||||||
error: Uncaught Error: foo
|
|
||||||
at foo ([WILDCARD]tests/error_stack.ts:2:9)
|
|
||||||
at [WILDCARD]tests/error_stack.ts:6:3
|
|
|
@ -1,11 +1,12 @@
|
||||||
[WILDCARD]error: Uncaught URIError: relative import path "baz" not prefixed with / or ./ or ../ Imported from "[WILDCARD]/type_definitions/bar.d.ts"
|
[WILDCARD]error: Uncaught URIError: relative import path "baz" not prefixed with / or ./ or ../ Imported from "[WILDCARD]/type_definitions/bar.d.ts"
|
||||||
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
[WILDCARD]ops/dispatch_json.ts:[WILDCARD]
|
||||||
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
||||||
at sendSync ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
at Object.sendSync ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
||||||
|
at Object.resolveModules ([WILDCARD]ops/compiler.ts:[WILDCARD])
|
||||||
at resolveModules ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at resolveModules ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at async processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
at async Object.processImports ([WILDCARD]compiler/imports.ts:[WILDCARD])
|
||||||
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
at async compile ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
at async tsCompilerOnMessage ([WILDCARD]compiler.ts:[WILDCARD])
|
||||||
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
at async workerMessageRecvCallback ([WILDCARD]runtime_worker.ts:[WILDCARD])
|
||||||
|
|
|
@ -1371,11 +1371,39 @@ itest!(error_018_hide_long_source_js {
|
||||||
exit_code: 1,
|
exit_code: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
itest!(error_stack {
|
itest!(error_019_stack_function {
|
||||||
args: "run --reload error_stack.ts",
|
args: "error_019_stack_function.ts",
|
||||||
|
output: "error_019_stack_function.ts.out",
|
||||||
|
check_stderr: true,
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(error_020_stack_constructor {
|
||||||
|
args: "error_020_stack_constructor.ts",
|
||||||
|
output: "error_020_stack_constructor.ts.out",
|
||||||
|
check_stderr: true,
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(error_021_stack_method {
|
||||||
|
args: "error_021_stack_method.ts",
|
||||||
|
output: "error_021_stack_method.ts.out",
|
||||||
|
check_stderr: true,
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(error_022_stack_custom_error {
|
||||||
|
args: "error_022_stack_custom_error.ts",
|
||||||
|
output: "error_022_stack_custom_error.ts.out",
|
||||||
|
check_stderr: true,
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(error_023_stack_async {
|
||||||
|
args: "error_023_stack_async.ts",
|
||||||
|
output: "error_023_stack_async.ts.out",
|
||||||
check_stderr: true,
|
check_stderr: true,
|
||||||
exit_code: 1,
|
exit_code: 1,
|
||||||
output: "error_stack.ts.out",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
itest!(error_syntax {
|
itest!(error_syntax {
|
||||||
|
|
|
@ -28,12 +28,7 @@ pub struct JSError {
|
||||||
pub start_column: Option<i64>,
|
pub start_column: Option<i64>,
|
||||||
pub end_column: Option<i64>,
|
pub end_column: Option<i64>,
|
||||||
pub frames: Vec<JSStackFrame>,
|
pub frames: Vec<JSStackFrame>,
|
||||||
// TODO: Remove this field. It is required because JSError::from_v8_exception
|
pub formatted_frames: Vec<String>,
|
||||||
// will generally (but not always) return stack frames passed from
|
|
||||||
// `prepareStackTrace()` which have already been source-mapped, and we need a
|
|
||||||
// flag saying not to do it again. Note: applies to `frames` but not
|
|
||||||
// `source_line`.
|
|
||||||
pub already_source_mapped: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
@ -84,10 +79,17 @@ impl JSError {
|
||||||
let maybe_call_sites: Option<v8::Local<v8::Array>> =
|
let maybe_call_sites: Option<v8::Local<v8::Array>> =
|
||||||
maybe_call_sites.and_then(|a| a.try_into().ok());
|
maybe_call_sites.and_then(|a| a.try_into().ok());
|
||||||
|
|
||||||
let already_source_mapped;
|
let (frames, formatted_frames) = if let Some(call_sites) = maybe_call_sites
|
||||||
let frames = if let Some(call_sites) = maybe_call_sites {
|
{
|
||||||
already_source_mapped = true;
|
let mut frames: Vec<JSStackFrame> = vec![];
|
||||||
let mut output: Vec<JSStackFrame> = vec![];
|
let mut formatted_frames: Vec<String> = vec![];
|
||||||
|
|
||||||
|
let formatted_frames_v8 =
|
||||||
|
get_property(scope, context, exception.unwrap(), "__formattedFrames");
|
||||||
|
let formatted_frames_v8: v8::Local<v8::Array> = formatted_frames_v8
|
||||||
|
.and_then(|a| a.try_into().ok())
|
||||||
|
.expect("__formattedFrames should be defined if __callSiteEvals is.");
|
||||||
|
|
||||||
for i in 0..call_sites.length() {
|
for i in 0..call_sites.length() {
|
||||||
let call_site: v8::Local<v8::Object> = call_sites
|
let call_site: v8::Local<v8::Object> = call_sites
|
||||||
.get_index(scope, context, i)
|
.get_index(scope, context, i)
|
||||||
|
@ -136,7 +138,7 @@ impl JSError {
|
||||||
.try_into()
|
.try_into()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let is_async = is_async.is_true();
|
let is_async = is_async.is_true();
|
||||||
output.push(JSStackFrame {
|
frames.push(JSStackFrame {
|
||||||
line_number,
|
line_number,
|
||||||
column: column_number,
|
column: column_number,
|
||||||
script_name: file_name,
|
script_name: file_name,
|
||||||
|
@ -145,43 +147,17 @@ impl JSError {
|
||||||
is_eval,
|
is_eval,
|
||||||
is_async,
|
is_async,
|
||||||
});
|
});
|
||||||
|
let formatted_frame: v8::Local<v8::String> = formatted_frames_v8
|
||||||
|
.get_index(scope, context, i)
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
let formatted_frame = formatted_frame.to_rust_string_lossy(scope);
|
||||||
|
formatted_frames.push(formatted_frame)
|
||||||
}
|
}
|
||||||
output
|
(frames, formatted_frames)
|
||||||
} else {
|
} else {
|
||||||
already_source_mapped = false;
|
(vec![], vec![])
|
||||||
msg
|
|
||||||
.get_stack_trace(scope)
|
|
||||||
.map(|stack_trace| {
|
|
||||||
(0..stack_trace.get_frame_count())
|
|
||||||
.map(|i| {
|
|
||||||
let frame = stack_trace.get_frame(scope, i).unwrap();
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: frame
|
|
||||||
.get_line_number()
|
|
||||||
.checked_sub(1)
|
|
||||||
.and_then(|v| v.try_into().ok())
|
|
||||||
.unwrap(),
|
|
||||||
column: frame
|
|
||||||
.get_column()
|
|
||||||
.checked_sub(1)
|
|
||||||
.and_then(|v| v.try_into().ok())
|
|
||||||
.unwrap(),
|
|
||||||
script_name: frame
|
|
||||||
.get_script_name_or_source_url(scope)
|
|
||||||
.map(|v| v.to_rust_string_lossy(scope))
|
|
||||||
.unwrap_or_else(|| "<unknown>".to_owned()),
|
|
||||||
function_name: frame
|
|
||||||
.get_function_name(scope)
|
|
||||||
.map(|v| v.to_rust_string_lossy(scope))
|
|
||||||
.unwrap_or_else(|| "".to_owned()),
|
|
||||||
is_constructor: frame.is_constructor(),
|
|
||||||
is_eval: frame.is_eval(),
|
|
||||||
is_async: false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
})
|
|
||||||
.unwrap_or_else(Vec::<_>::new)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -197,7 +173,7 @@ impl JSError {
|
||||||
start_column: msg.get_start_column().try_into().ok(),
|
start_column: msg.get_start_column().try_into().ok(),
|
||||||
end_column: msg.get_end_column().try_into().ok(),
|
end_column: msg.get_end_column().try_into().ok(),
|
||||||
frames,
|
frames,
|
||||||
already_source_mapped,
|
formatted_frames,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,22 +191,6 @@ fn format_source_loc(
|
||||||
format!("{}:{}:{}", script_name, line_number, column)
|
format!("{}:{}:{}", script_name, line_number, column)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_stack_frame(frame: &JSStackFrame) -> String {
|
|
||||||
// Note when we print to string, we change from 0-indexed to 1-indexed.
|
|
||||||
let source_loc =
|
|
||||||
format_source_loc(&frame.script_name, frame.line_number, frame.column);
|
|
||||||
|
|
||||||
if !frame.function_name.is_empty() {
|
|
||||||
format!(" at {} ({})", frame.function_name, source_loc)
|
|
||||||
} else if frame.is_eval {
|
|
||||||
format!(" at eval ({})", source_loc)
|
|
||||||
} else if frame.is_async {
|
|
||||||
format!(" at async ({})", source_loc)
|
|
||||||
} else {
|
|
||||||
format!(" at {}", source_loc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for JSError {
|
impl fmt::Display for JSError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if self.script_resource_name.is_some() {
|
if self.script_resource_name.is_some() {
|
||||||
|
@ -261,59 +221,10 @@ impl fmt::Display for JSError {
|
||||||
|
|
||||||
write!(f, "{}", self.message)?;
|
write!(f, "{}", self.message)?;
|
||||||
|
|
||||||
for frame in &self.frames {
|
for formatted_frame in &self.formatted_frames {
|
||||||
write!(f, "\n{}", format_stack_frame(frame))?;
|
// TODO: Strip ANSI color from formatted_frame.
|
||||||
|
write!(f, "\n at {}", formatted_frame)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn js_error_to_string() {
|
|
||||||
let js_error = JSError {
|
|
||||||
message: "Error: foo bar".to_string(),
|
|
||||||
source_line: None,
|
|
||||||
script_resource_name: None,
|
|
||||||
line_number: None,
|
|
||||||
start_column: None,
|
|
||||||
end_column: None,
|
|
||||||
frames: vec![
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 4,
|
|
||||||
column: 16,
|
|
||||||
script_name: "foo_bar.ts".to_string(),
|
|
||||||
function_name: "foo".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 5,
|
|
||||||
column: 20,
|
|
||||||
script_name: "bar_baz.ts".to_string(),
|
|
||||||
function_name: "qat".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
JSStackFrame {
|
|
||||||
line_number: 1,
|
|
||||||
column: 1,
|
|
||||||
script_name: "deno_main.js".to_string(),
|
|
||||||
function_name: "".to_string(),
|
|
||||||
is_eval: false,
|
|
||||||
is_constructor: false,
|
|
||||||
is_async: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
already_source_mapped: true,
|
|
||||||
};
|
|
||||||
let actual = js_error.to_string();
|
|
||||||
let expected = "Error: foo bar\n at foo (foo_bar.ts:5:17)\n at qat (bar_baz.ts:6:21)\n at deno_main.js:2:2";
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue