diff options
author | Nayeem Rahman <nayeemrmn99@gmail.com> | 2020-04-13 15:54:16 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-13 10:54:16 -0400 |
commit | 0ea6eb83a906bff543be4c3301f23444986b022b (patch) | |
tree | 923e5b1c7608839c9a7be545f8973ae751ee7e73 | |
parent | 5105c6839904f35351481137160459fdc2edadd2 (diff) |
refactor(core/js_error): Align JSStackFrame with CallSite (#4715)
Renames and adds missing fields to JSStackFrame from CallSite. Fixes #4705.
Cleans up base changes for line and column numbers.
-rw-r--r-- | cli/diagnostics.rs | 8 | ||||
-rw-r--r-- | cli/fmt_errors.rs | 47 | ||||
-rw-r--r-- | cli/js/error_stack.ts | 55 | ||||
-rw-r--r-- | cli/js/globals.ts | 12 | ||||
-rw-r--r-- | cli/js/lib.deno.ns.d.ts | 12 | ||||
-rw-r--r-- | cli/js/ops/errors.ts | 24 | ||||
-rw-r--r-- | cli/js/tests/error_stack_test.ts | 36 | ||||
-rw-r--r-- | cli/ops/errors.rs | 28 | ||||
-rw-r--r-- | cli/source_maps.rs | 74 | ||||
-rw-r--r-- | cli/tests/error_024_stack_promise_all.ts | 13 | ||||
-rw-r--r-- | cli/tests/error_024_stack_promise_all.ts.out | 8 | ||||
-rw-r--r-- | cli/tests/integration_tests.rs | 7 | ||||
-rw-r--r-- | core/js_errors.rs | 137 |
13 files changed, 270 insertions, 191 deletions
diff --git a/cli/diagnostics.rs b/cli/diagnostics.rs index d73004b21..b0b284360 100644 --- a/cli/diagnostics.rs +++ b/cli/diagnostics.rs @@ -232,9 +232,10 @@ impl DisplayFormatter for DiagnosticItem { } fn format_source_line(&self, level: usize) -> String { + // Formatter expects 1-based line numbers, but ours are 0-based. format_maybe_source_line( self.source_line.clone(), - self.line_number, + self.line_number.map(|n| n + 1), self.start_column, self.end_column, match self.category { @@ -246,10 +247,11 @@ impl DisplayFormatter for DiagnosticItem { } fn format_source_name(&self) -> String { + // Formatter expects 1-based line and column numbers, but ours are 0-based. format_maybe_source_name( self.script_resource_name.clone(), - self.line_number, - self.start_column, + self.line_number.map(|n| n + 1), + self.start_column.map(|n| n + 1), ) } } diff --git a/cli/fmt_errors.rs b/cli/fmt_errors.rs index 784bcc9c9..19e6616ca 100644 --- a/cli/fmt_errors.rs +++ b/cli/fmt_errors.rs @@ -21,34 +21,34 @@ pub trait DisplayFormatter { } fn format_source_name( - script_name: String, + file_name: String, line_number: i64, - column: i64, + column_number: i64, ) -> String { - let line_number = line_number + 1; - let column = column + 1; - let script_name_c = colors::cyan(script_name); + let line_number = line_number; + let column_number = column_number; + let file_name_c = colors::cyan(file_name); 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) + let column_c = colors::yellow(column_number.to_string()); + format!("{}:{}:{}", file_name_c, line_c, column_c) } -/// Formats optional source, line number and column into a single string. +/// Formats optional source, line and column numbers into a single string. pub fn format_maybe_source_name( - script_name: Option<String>, + file_name: Option<String>, line_number: Option<i64>, - column: Option<i64>, + column_number: Option<i64>, ) -> String { - if script_name.is_none() { + if file_name.is_none() { return "".to_string(); } assert!(line_number.is_some()); - assert!(column.is_some()); + assert!(column_number.is_some()); format_source_name( - script_name.unwrap(), + file_name.unwrap(), line_number.unwrap(), - column.unwrap(), + column_number.unwrap(), ) } @@ -76,7 +76,7 @@ pub fn format_maybe_source_line( assert!(start_column.is_some()); assert!(end_column.is_some()); - let line_number = (1 + line_number.unwrap()).to_string(); + let line_number = line_number.unwrap().to_string(); let line_color = colors::black_on_white(line_number.to_string()); let line_number_len = line_number.len(); let line_padding = @@ -93,12 +93,11 @@ pub fn format_maybe_source_line( } else { '~' }; - for i in 0..end_column { - if i >= start_column { - s.push(underline_char); - } else { - s.push(' '); - } + for _i in 0..start_column { + s.push(' '); + } + for _i in 0..(end_column - start_column) { + s.push(underline_char); } let color_underline = if is_error { colors::red(s).to_string() @@ -181,7 +180,7 @@ impl DisplayFormatter for JSError { format_maybe_source_name( e.script_resource_name.clone(), e.line_number, - e.start_column, + e.start_column.map(|n| n + 1), ) ) } @@ -223,7 +222,7 @@ mod tests { Some(1), Some(2), ); - assert_eq!(strip_ansi_codes(&actual), "file://foo/bar.ts:2:3"); + assert_eq!(strip_ansi_codes(&actual), "file://foo/bar.ts:1:2"); } #[test] @@ -244,7 +243,7 @@ mod tests { ); assert_eq!( strip_ansi_codes(&actual), - "\n\n9 console.log(\'foo\');\n ~~~\n" + "\n\n8 console.log(\'foo\');\n ~~~\n" ); } diff --git a/cli/js/error_stack.ts b/cli/js/error_stack.ts index 43723dff6..e77f0865c 100644 --- a/cli/js/error_stack.ts +++ b/cli/js/error_stack.ts @@ -11,31 +11,31 @@ function patchCallSite(callSite: CallSite, location: Location): CallSite { getThis(): unknown { return callSite.getThis(); }, - getTypeName(): string { + getTypeName(): string | null { return callSite.getTypeName(); }, - getFunction(): Function { + getFunction(): Function | null { return callSite.getFunction(); }, - getFunctionName(): string { + getFunctionName(): string | null { return callSite.getFunctionName(); }, - getMethodName(): string { + getMethodName(): string | null { return callSite.getMethodName(); }, - getFileName(): string { - return location.filename; + getFileName(): string | null { + return location.fileName; }, getLineNumber(): number { - return location.line; + return location.lineNumber; }, getColumnNumber(): number { - return location.column; + return location.columnNumber; }, getEvalOrigin(): string | null { return callSite.getEvalOrigin(); }, - isToplevel(): boolean { + isToplevel(): boolean | null { return callSite.isToplevel(); }, isEval(): boolean { @@ -176,15 +176,15 @@ function callSiteToString(callSite: CallSite, isInternal = false): string { interface CallSiteEval { this: unknown; - typeName: string; - function: Function; - functionName: string; - methodName: string; - fileName: string; + typeName: string | null; + function: Function | null; + functionName: string | null; + methodName: string | null; + fileName: string | null; lineNumber: number | null; columnNumber: number | null; evalOrigin: string | null; - isToplevel: boolean; + isToplevel: boolean | null; isEval: boolean; isNative: boolean; isConstructor: boolean; @@ -227,16 +227,16 @@ function prepareStackTrace( structuredStackTrace .map( (callSite): CallSite => { - const filename = callSite.getFileName(); - const line = callSite.getLineNumber(); - const column = callSite.getColumnNumber(); - if (filename && line != null && column != null) { + const fileName = callSite.getFileName(); + const lineNumber = callSite.getLineNumber(); + const columnNumber = callSite.getColumnNumber(); + if (fileName && lineNumber != null && columnNumber != null) { return patchCallSite( callSite, applySourceMap({ - filename, - line, - column, + fileName, + lineNumber, + columnNumber, }) ); } @@ -244,16 +244,13 @@ function prepareStackTrace( } ) .map((callSite): string => { + // @ts-ignore + error.__callSiteEvals.push(Object.freeze(evaluateCallSite(callSite))); const isInternal = callSite.getFileName()?.startsWith("$deno$") ?? false; const string = callSiteToString(callSite, isInternal); - const callSiteEv = Object.freeze(evaluateCallSite(callSite)); - if (callSiteEv.lineNumber != null && callSiteEv.columnNumber != null) { - // @ts-ignore - error.__callSiteEvals.push(callSiteEv); - // @ts-ignore - error.__formattedFrames.push(string); - } + // @ts-ignore + error.__formattedFrames.push(string); return ` at ${colors.stripColor(string)}`; }) .join("\n"); diff --git a/cli/js/globals.ts b/cli/js/globals.ts index 7e708d018..5a5f54ee1 100644 --- a/cli/js/globals.ts +++ b/cli/js/globals.ts @@ -31,15 +31,15 @@ import { core } from "./core.ts"; declare global { interface CallSite { getThis(): unknown; - getTypeName(): string; - getFunction(): Function; - getFunctionName(): string; - getMethodName(): string; - getFileName(): string; + getTypeName(): string | null; + getFunction(): Function | null; + getFunctionName(): string | null; + getMethodName(): string | null; + getFileName(): string | null; getLineNumber(): number | null; getColumnNumber(): number | null; getEvalOrigin(): string | null; - isToplevel(): boolean; + isToplevel(): boolean | null; isEval(): boolean; isNative(): boolean; isConstructor(): boolean; diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts index 75d10642b..550b6cffc 100644 --- a/cli/js/lib.deno.ns.d.ts +++ b/cli/js/lib.deno.ns.d.ts @@ -1612,11 +1612,11 @@ declare namespace Deno { interface Location { /** The full url for the module, e.g. `file://some/file.ts` or * `https://some/file.ts`. */ - filename: string; + fileName: string; /** The line number in the file. It is assumed to be 1-indexed. */ - line: number; + lineNumber: number; /** The column number in the file. It is assumed to be 1-indexed. */ - column: number; + columnNumber: number; } /** UNSTABLE: new API, yet to be vetted. @@ -1636,9 +1636,9 @@ declare namespace Deno { * An example: * * const orig = Deno.applySourceMap({ - * location: "file://my/module.ts", - * line: 5, - * column: 15 + * fileName: "file://my/module.ts", + * lineNumber: 5, + * columnNumber: 15 * }); * console.log(`${orig.filename}:${orig.line}:${orig.column}`); */ diff --git a/cli/js/ops/errors.ts b/cli/js/ops/errors.ts index 5b65d102a..bd3e6d809 100644 --- a/cli/js/ops/errors.ts +++ b/cli/js/ops/errors.ts @@ -7,25 +7,21 @@ export function formatDiagnostics(items: DiagnosticItem[]): string { } export interface Location { - filename: string; - - line: number; - - column: number; + fileName: string; + lineNumber: number; + columnNumber: number; } export function applySourceMap(location: Location): Location { - const { filename, line, column } = location; - // On this side, line/column are 1 based, but in the source maps, they are - // 0 based, so we have to convert back and forth + const { fileName, lineNumber, columnNumber } = location; const res = sendSync("op_apply_source_map", { - filename, - line: line - 1, - column: column - 1, + fileName, + lineNumber: lineNumber, + columnNumber: columnNumber, }); return { - filename: res.filename, - line: res.line + 1, - column: res.column + 1, + fileName: res.fileName, + lineNumber: res.lineNumber, + columnNumber: res.columnNumber, }; } diff --git a/cli/js/tests/error_stack_test.ts b/cli/js/tests/error_stack_test.ts index 6868be215..83a2020ac 100644 --- a/cli/js/tests/error_stack_test.ts +++ b/cli/js/tests/error_stack_test.ts @@ -6,15 +6,15 @@ const { setPrepareStackTrace } = Deno[Deno.symbols.internal]; interface CallSite { getThis(): unknown; - getTypeName(): string; - getFunction(): Function; - getFunctionName(): string; - getMethodName(): string; - getFileName(): string; + getTypeName(): string | null; + getFunction(): Function | null; + getFunctionName(): string | null; + getMethodName(): string | null; + getFileName(): string | null; getLineNumber(): number | null; getColumnNumber(): number | null; getEvalOrigin(): string | null; - isToplevel(): boolean; + isToplevel(): boolean | null; isEval(): boolean; isNative(): boolean; isConstructor(): boolean; @@ -24,9 +24,9 @@ interface CallSite { } function getMockCallSite( - filename: string, - line: number | null, - column: number | null + fileName: string, + lineNumber: number | null, + columnNumber: number | null ): CallSite { return { getThis(): unknown { @@ -45,13 +45,13 @@ function getMockCallSite( return ""; }, getFileName(): string { - return filename; + return fileName; }, getLineNumber(): number | null { - return line; + return lineNumber; }, getColumnNumber(): number | null { - return column; + return columnNumber; }, getEvalOrigin(): null { return null; @@ -98,11 +98,11 @@ unitTest(function prepareStackTrace(): void { unitTest(function applySourceMap(): void { const result = Deno.applySourceMap({ - filename: "CLI_SNAPSHOT.js", - line: 23, - column: 0, + fileName: "CLI_SNAPSHOT.js", + lineNumber: 23, + columnNumber: 0, }); - assert(result.filename.endsWith(".ts")); - assert(result.line != null); - assert(result.column != null); + assert(result.fileName.endsWith(".ts")); + assert(result.lineNumber != null); + assert(result.columnNumber != null); }); diff --git a/cli/ops/errors.rs b/cli/ops/errors.rs index 4d2ce1bef..2eab3a953 100644 --- a/cli/ops/errors.rs +++ b/cli/ops/errors.rs @@ -20,10 +20,11 @@ pub fn init(i: &mut Isolate, s: &State) { } #[derive(Deserialize)] +#[serde(rename_all = "camelCase")] struct ApplySourceMap { - filename: String, - line: i32, - column: i32, + file_name: String, + line_number: i32, + column_number: i32, } fn op_apply_source_map( @@ -34,18 +35,19 @@ fn op_apply_source_map( let args: ApplySourceMap = serde_json::from_value(args)?; let mut mappings_map: CachedMaps = HashMap::new(); - let (orig_filename, orig_line, orig_column) = get_orig_position( - args.filename, - args.line.into(), - args.column.into(), - &mut mappings_map, - &state.borrow().global_state.ts_compiler, - ); + let (orig_file_name, orig_line_number, orig_column_number) = + get_orig_position( + args.file_name, + args.line_number.into(), + args.column_number.into(), + &mut mappings_map, + &state.borrow().global_state.ts_compiler, + ); Ok(JsonOp::Sync(json!({ - "filename": orig_filename, - "line": orig_line as u32, - "column": orig_column as u32, + "fileName": orig_file_name, + "lineNumber": orig_line_number as u32, + "columnNumber": orig_column_number as u32, }))) } diff --git a/cli/source_maps.rs b/cli/source_maps.rs index 2d442b823..90780e042 100644 --- a/cli/source_maps.rs +++ b/cli/source_maps.rs @@ -6,10 +6,10 @@ use std::str; pub trait SourceMapGetter { /// Returns the raw source map file. - fn get_source_map(&self, script_name: &str) -> Option<Vec<u8>>; + fn get_source_map(&self, file_name: &str) -> Option<Vec<u8>>; fn get_source_line( &self, - script_name: &str, + file_name: &str, line_number: usize, ) -> Option<String>; } @@ -29,10 +29,10 @@ fn builtin_source_map(_: &str) -> Option<Vec<u8>> { } #[cfg(not(feature = "check-only"))] -fn builtin_source_map(script_name: &str) -> Option<Vec<u8>> { - if script_name.ends_with("CLI_SNAPSHOT.js") { +fn builtin_source_map(file_name: &str) -> Option<Vec<u8>> { + if file_name.ends_with("CLI_SNAPSHOT.js") { Some(crate::js::CLI_SNAPSHOT_MAP.to_vec()) - } else if script_name.ends_with("COMPILER_SNAPSHOT.js") { + } else if file_name.ends_with("COMPILER_SNAPSHOT.js") { Some(crate::js::COMPILER_SNAPSHOT_MAP.to_vec()) } else { None @@ -54,10 +54,12 @@ pub fn apply_source_map<G: SourceMapGetter>( get_maybe_orig_position( js_error.script_resource_name.clone(), js_error.line_number, - js_error.start_column, + // start_column is 0-based, we need 1-based here. + js_error.start_column.map(|n| n + 1), &mut mappings_map, getter, ); + let start_column = start_column.map(|n| n - 1); // It is better to just move end_column to be the same distance away from // start column because sometimes the code point is not available in the // source file map. @@ -79,7 +81,8 @@ pub fn apply_source_map<G: SourceMapGetter>( { getter.get_source_line( &js_error.script_resource_name.clone().unwrap(), - ln as usize, + // Getter expects 0-based line numbers, but ours are 1-based. + ln as usize - 1, ) } _ => js_error.source_line.clone(), @@ -98,48 +101,47 @@ pub fn apply_source_map<G: SourceMapGetter>( } fn get_maybe_orig_position<G: SourceMapGetter>( - script_name: Option<String>, + file_name: Option<String>, line_number: Option<i64>, - column: Option<i64>, + column_number: Option<i64>, mappings_map: &mut CachedMaps, getter: &G, ) -> (Option<String>, Option<i64>, Option<i64>) { - match (script_name, line_number, column) { - (Some(script_name_v), Some(line_v), Some(column_v)) => { - let (script_name, line_number, column) = get_orig_position( - script_name_v, - line_v - 1, - column_v, - mappings_map, - getter, - ); - (Some(script_name), Some(line_number), Some(column)) + match (file_name, line_number, column_number) { + (Some(file_name_v), Some(line_v), Some(column_v)) => { + let (file_name, line_number, column_number) = + get_orig_position(file_name_v, line_v, column_v, mappings_map, getter); + (Some(file_name), Some(line_number), Some(column_number)) } _ => (None, None, None), } } pub fn get_orig_position<G: SourceMapGetter>( - script_name: String, + file_name: String, line_number: i64, - column: i64, + column_number: i64, mappings_map: &mut CachedMaps, getter: &G, ) -> (String, i64, i64) { - let maybe_source_map = get_mappings(&script_name, mappings_map, getter); - let default_pos = (script_name, line_number, column); + let maybe_source_map = get_mappings(&file_name, mappings_map, getter); + let default_pos = (file_name, line_number, column_number); + + // Lookup expects 0-based line and column numbers, but ours are 1-based. + let line_number = line_number - 1; + let column_number = column_number - 1; match maybe_source_map { None => default_pos, Some(source_map) => { - match source_map.lookup_token(line_number as u32, column as u32) { + match source_map.lookup_token(line_number as u32, column_number as u32) { None => default_pos, Some(token) => match token.get_source() { None => default_pos, Some(original) => ( original.to_string(), - i64::from(token.get_src_line()), - i64::from(token.get_src_col()), + i64::from(token.get_src_line()) + 1, + i64::from(token.get_src_col()) + 1, ), }, } @@ -148,23 +150,23 @@ pub fn get_orig_position<G: SourceMapGetter>( } fn get_mappings<'a, G: SourceMapGetter>( - script_name: &str, + file_name: &str, mappings_map: &'a mut CachedMaps, getter: &G, ) -> &'a Option<SourceMap> { mappings_map - .entry(script_name.to_string()) - .or_insert_with(|| parse_map_string(script_name, getter)) + .entry(file_name.to_string()) + .or_insert_with(|| parse_map_string(file_name, getter)) } // TODO(kitsonk) parsed source maps should probably be cached in state in // the module meta data. fn parse_map_string<G: SourceMapGetter>( - script_name: &str, + file_name: &str, getter: &G, ) -> Option<SourceMap> { - builtin_source_map(script_name) - .or_else(|| getter.get_source_map(script_name)) + builtin_source_map(file_name) + .or_else(|| getter.get_source_map(file_name)) .and_then(|raw_source_map| SourceMap::from_slice(&raw_source_map).ok()) } @@ -175,8 +177,8 @@ mod tests { struct MockSourceMapGetter {} impl SourceMapGetter for MockSourceMapGetter { - fn get_source_map(&self, script_name: &str) -> Option<Vec<u8>> { - let s = match script_name { + fn get_source_map(&self, file_name: &str) -> Option<Vec<u8>> { + let s = match file_name { "foo_bar.ts" => { r#"{"sources": ["foo_bar.ts"], "mappings":";;;IAIA,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAE3C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC"}"# } @@ -190,10 +192,10 @@ mod tests { fn get_source_line( &self, - script_name: &str, + file_name: &str, line_number: usize, ) -> Option<String> { - let s = match script_name { + let s = match file_name { "foo_bar.ts" => vec![ "console.log('foo');", "console.log('foo');", diff --git a/cli/tests/error_024_stack_promise_all.ts b/cli/tests/error_024_stack_promise_all.ts new file mode 100644 index 000000000..5334e8d77 --- /dev/null +++ b/cli/tests/error_024_stack_promise_all.ts @@ -0,0 +1,13 @@ +const p = Promise.all([ + (async (): Promise<never> => { + await Promise.resolve(); + throw new Error("Promise.all()"); + })(), +]); + +try { + await p; +} catch (error) { + console.log(error.stack); + throw error; +} diff --git a/cli/tests/error_024_stack_promise_all.ts.out b/cli/tests/error_024_stack_promise_all.ts.out new file mode 100644 index 000000000..38cb4ac31 --- /dev/null +++ b/cli/tests/error_024_stack_promise_all.ts.out @@ -0,0 +1,8 @@ +[WILDCARD]Error: Promise.all() + at [WILDCARD]tests/error_024_stack_promise_all.ts:[WILDCARD] + at async Promise.all (index 0) + at async [WILDCARD]tests/error_024_stack_promise_all.ts:[WILDCARD] +error: Uncaught Error: Promise.all() + at [WILDCARD]tests/error_024_stack_promise_all.ts:[WILDCARD] + at async Promise.all (index 0) + at async [WILDCARD]tests/error_024_stack_promise_all.ts:[WILDCARD] diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs index d043958a9..905870c29 100644 --- a/cli/tests/integration_tests.rs +++ b/cli/tests/integration_tests.rs @@ -1406,6 +1406,13 @@ itest!(error_023_stack_async { exit_code: 1, }); +itest!(error_024_stack_promise_all { + args: "error_024_stack_promise_all.ts", + output: "error_024_stack_promise_all.ts.out", + check_stderr: true, + exit_code: 1, +}); + itest!(error_syntax { args: "run --reload error_syntax.js", check_stderr: true, diff --git a/core/js_errors.rs b/core/js_errors.rs index 87f603a16..06a8d188f 100644 --- a/core/js_errors.rs +++ b/core/js_errors.rs @@ -1,8 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -// Note that source_map_mappings requires 0-indexed line and column numbers but -// V8 Exceptions are 1-indexed. - // TODO: This currently only applies to uncaught exceptions. It would be nice to // also have source maps for situations like this: // const err = new Error("Boo!"); @@ -25,22 +22,28 @@ pub struct JSError { pub source_line: Option<String>, pub script_resource_name: Option<String>, pub line_number: Option<i64>, - pub start_column: Option<i64>, - pub end_column: Option<i64>, + pub start_column: Option<i64>, // 0-based + pub end_column: Option<i64>, // 0-based pub frames: Vec<JSStackFrame>, pub formatted_frames: Vec<String>, } #[derive(Debug, PartialEq, Clone)] pub struct JSStackFrame { - pub line_number: i64, // zero indexed - pub column: i64, // zero indexed - pub script_name: String, - pub function_name: String, + pub type_name: Option<String>, + pub function_name: Option<String>, + pub method_name: Option<String>, + pub file_name: Option<String>, + pub line_number: Option<i64>, + pub column_number: Option<i64>, + pub eval_origin: Option<String>, + pub is_top_level: Option<bool>, pub is_eval: bool, + pub is_native: bool, pub is_constructor: bool, pub is_async: bool, - // TODO(nayeemrmn): Support more CallSite fields. + pub is_promise_all: bool, + pub promise_index: Option<i64>, } fn get_property<'a>( @@ -96,56 +99,106 @@ impl JSError { .unwrap() .try_into() .unwrap(); - let line_number: v8::Local<v8::Integer> = - get_property(scope, context, call_site, "lineNumber") + let type_name: Option<v8::Local<v8::String>> = + get_property(scope, context, call_site, "typeName") .unwrap() .try_into() - .unwrap(); - let line_number = line_number.value() - 1; - let column_number: v8::Local<v8::Integer> = - get_property(scope, context, call_site, "columnNumber") + .ok(); + let type_name = type_name.map(|s| s.to_rust_string_lossy(scope)); + let function_name: Option<v8::Local<v8::String>> = + get_property(scope, context, call_site, "functionName") .unwrap() .try_into() - .unwrap(); - let column_number = column_number.value() - 1; - let file_name: Result<v8::Local<v8::String>, _> = + .ok(); + let function_name = + function_name.map(|s| s.to_rust_string_lossy(scope)); + let method_name: Option<v8::Local<v8::String>> = + get_property(scope, context, call_site, "methodName") + .unwrap() + .try_into() + .ok(); + let method_name = method_name.map(|s| s.to_rust_string_lossy(scope)); + let file_name: Option<v8::Local<v8::String>> = get_property(scope, context, call_site, "fileName") .unwrap() - .try_into(); - let file_name = file_name - .map_or_else(|_| String::new(), |s| s.to_rust_string_lossy(scope)); - let function_name: Result<v8::Local<v8::String>, _> = - get_property(scope, context, call_site, "functionName") + .try_into() + .ok(); + let file_name = file_name.map(|s| s.to_rust_string_lossy(scope)); + let line_number: Option<v8::Local<v8::Integer>> = + get_property(scope, context, call_site, "lineNumber") .unwrap() - .try_into(); - let function_name = function_name - .map_or_else(|_| String::new(), |s| s.to_rust_string_lossy(scope)); - let is_constructor: v8::Local<v8::Boolean> = - get_property(scope, context, call_site, "isConstructor") + .try_into() + .ok(); + let line_number = line_number.map(|n| n.value()); + let column_number: Option<v8::Local<v8::Integer>> = + get_property(scope, context, call_site, "columnNumber") .unwrap() .try_into() - .unwrap(); - let is_constructor = is_constructor.is_true(); + .ok(); + let column_number = column_number.map(|n| n.value()); + let eval_origin: Option<v8::Local<v8::String>> = + get_property(scope, context, call_site, "evalOrigin") + .unwrap() + .try_into() + .ok(); + let eval_origin = eval_origin.map(|s| s.to_rust_string_lossy(scope)); + let is_top_level: Option<v8::Local<v8::Boolean>> = + get_property(scope, context, call_site, "isTopLevel") + .unwrap() + .try_into() + .ok(); + let is_top_level = is_top_level.map(|b| b.is_true()); let is_eval: v8::Local<v8::Boolean> = get_property(scope, context, call_site, "isEval") .unwrap() .try_into() .unwrap(); let is_eval = is_eval.is_true(); + let is_native: v8::Local<v8::Boolean> = + get_property(scope, context, call_site, "isNative") + .unwrap() + .try_into() + .unwrap(); + let is_native = is_native.is_true(); + let is_constructor: v8::Local<v8::Boolean> = + get_property(scope, context, call_site, "isConstructor") + .unwrap() + .try_into() + .unwrap(); + let is_constructor = is_constructor.is_true(); let is_async: v8::Local<v8::Boolean> = get_property(scope, context, call_site, "isAsync") .unwrap() .try_into() .unwrap(); let is_async = is_async.is_true(); + let is_promise_all: v8::Local<v8::Boolean> = + get_property(scope, context, call_site, "isPromiseAll") + .unwrap() + .try_into() + .unwrap(); + let is_promise_all = is_promise_all.is_true(); + let promise_index: Option<v8::Local<v8::Integer>> = + get_property(scope, context, call_site, "columnNumber") + .unwrap() + .try_into() + .ok(); + let promise_index = promise_index.map(|n| n.value()); frames.push(JSStackFrame { - line_number, - column: column_number, - script_name: file_name, + type_name, function_name, - is_constructor, + method_name, + file_name, + line_number, + column_number, + eval_origin, + is_top_level, is_eval, + is_native, + is_constructor, is_async, + is_promise_all, + promise_index, }); let formatted_frame: v8::Local<v8::String> = formatted_frames_v8 .get_index(scope, context, i) @@ -181,14 +234,14 @@ impl JSError { impl Error for JSError {} fn format_source_loc( - script_name: &str, + file_name: &str, line_number: i64, - column: i64, + column_number: i64, ) -> String { // TODO match this style with how typescript displays errors. - let line_number = line_number + 1; - let column = column + 1; - format!("{}:{}:{}", script_name, line_number, column) + let line_number = line_number; + let column_number = column_number; + format!("{}:{}:{}", file_name, line_number, column_number) } impl fmt::Display for JSError { @@ -200,8 +253,8 @@ impl fmt::Display for JSError { assert!(self.start_column.is_some()); let source_loc = format_source_loc( script_resource_name, - self.line_number.unwrap() - 1, - self.start_column.unwrap() - 1, + self.line_number.unwrap(), + self.start_column.unwrap(), ); write!(f, "{}", source_loc)?; } |