feat: Better formatting for AggregateError (#14285)

This commit adds "aggregated" field to "deno_core::JsError" that stores
instances of "JsError" recursively to properly handle "AggregateError"
formatting. Appropriate logics was added to "PrettyJsError" and
"console" API to format AggregateErrors.

Co-authored-by: Nayeem Rahman <nayeemrmn99@gmail.com>
This commit is contained in:
Bartek Iwańczuk 2022-04-16 16:12:26 +02:00 committed by GitHub
parent 0bb96cde72
commit a87be28a46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 210 additions and 78 deletions

View file

@ -128,45 +128,6 @@ fn format_frame(frame: &JsStackFrame) -> String {
result
}
#[allow(clippy::too_many_arguments)]
fn format_stack(
is_error: bool,
message_line: &str,
cause: Option<&str>,
source_line: Option<&str>,
source_line_frame_index: Option<usize>,
frames: &[JsStackFrame],
level: usize,
) -> String {
let mut s = String::new();
s.push_str(&format!("{:indent$}{}", "", message_line, indent = level));
let column_number =
source_line_frame_index.and_then(|i| frames.get(i).unwrap().column_number);
s.push_str(&format_maybe_source_line(
source_line,
column_number,
is_error,
level,
));
for frame in frames {
s.push_str(&format!(
"\n{:indent$} at {}",
"",
format_frame(frame),
indent = level
));
}
if let Some(cause) = cause {
s.push_str(&format!(
"\n{:indent$}Caused by: {}",
"",
cause,
indent = level
));
}
s
}
/// Take an optional source line and associated information to format it into
/// a pretty printed version of that line.
fn format_maybe_source_line(
@ -219,6 +180,43 @@ fn format_maybe_source_line(
format!("\n{}{}\n{}{}", indent, source_line, indent, color_underline)
}
fn format_js_error(js_error: &JsError, is_child: bool) -> String {
let mut s = String::new();
s.push_str(&js_error.exception_message);
if let Some(aggregated) = &js_error.aggregated {
for aggregated_error in aggregated {
let error_string = format_js_error(aggregated_error, true);
for line in error_string.trim_start_matches("Uncaught ").lines() {
s.push_str(&format!("\n {}", line));
}
}
}
let column_number = js_error
.source_line_frame_index
.and_then(|i| js_error.frames.get(i).unwrap().column_number);
s.push_str(&format_maybe_source_line(
if is_child {
None
} else {
js_error.source_line.as_deref()
},
column_number,
true,
0,
));
for frame in &js_error.frames {
s.push_str(&format!("\n at {}", format_frame(frame)));
}
if let Some(cause) = &js_error.cause {
let error_string = format_js_error(cause, true);
s.push_str(&format!(
"\nCaused by: {}",
error_string.trim_start_matches("Uncaught ")
));
}
s
}
/// Wrapper around deno_core::JsError which provides colorful
/// string representation.
#[derive(Debug)]
@ -240,26 +238,7 @@ impl Deref for PrettyJsError {
impl fmt::Display for PrettyJsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let cause = self
.0
.cause
.clone()
.map(|cause| format!("{}", PrettyJsError(*cause)));
write!(
f,
"{}",
&format_stack(
true,
&self.0.exception_message,
cause.as_deref(),
self.0.source_line.as_deref(),
self.0.source_line_frame_index,
&self.0.frames,
0
)
)?;
Ok(())
write!(f, "{}", &format_js_error(&self.0, false))
}
}