summaryrefslogtreecommitdiff
path: root/cli/fmt_errors.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/fmt_errors.rs')
-rw-r--r--cli/fmt_errors.rs178
1 files changed, 148 insertions, 30 deletions
diff --git a/cli/fmt_errors.rs b/cli/fmt_errors.rs
index 8432d36c2..333c47756 100644
--- a/cli/fmt_errors.rs
+++ b/cli/fmt_errors.rs
@@ -3,30 +3,156 @@
use crate::colors;
use crate::source_maps::apply_source_map;
use crate::source_maps::SourceMapGetter;
-use deno_core::error::AnyError;
-use deno_core::error::JsError as CoreJsError;
+use deno_core::error::{AnyError, JsError as CoreJsError, JsStackFrame};
use std::error::Error;
use std::fmt;
use std::ops::Deref;
const SOURCE_ABBREV_THRESHOLD: usize = 150;
-pub fn format_location(filename: &str, line: i64, col: i64) -> String {
- format!(
- "{}:{}:{}",
- colors::cyan(filename),
- colors::yellow(&line.to_string()),
- colors::yellow(&col.to_string())
- )
+fn default_color(s: &str, internal: bool) -> String {
+ if internal {
+ colors::gray(s).to_string()
+ } else {
+ s.to_string()
+ }
+}
+
+fn cyan(s: &str, internal: bool) -> String {
+ if internal {
+ colors::gray(s).to_string()
+ } else {
+ colors::cyan(s).to_string()
+ }
+}
+
+fn yellow(s: &str, internal: bool) -> String {
+ if internal {
+ colors::gray(s).to_string()
+ } else {
+ colors::yellow(s).to_string()
+ }
+}
+
+fn italic_bold(s: &str, internal: bool) -> String {
+ if internal {
+ colors::italic_bold_gray(s).to_string()
+ } else {
+ colors::italic_bold(s).to_string()
+ }
+}
+
+// Keep in sync with `cli/rt/40_error_stack.js`.
+pub fn format_location(frame: &JsStackFrame) -> String {
+ let internal = frame
+ .file_name
+ .as_ref()
+ .map_or(false, |f| f.starts_with("deno:"));
+ if frame.is_native {
+ return cyan("native", internal);
+ }
+ let mut result = String::new();
+ if let Some(file_name) = &frame.file_name {
+ result += &cyan(&file_name, internal);
+ } else {
+ if frame.is_eval {
+ result += &(cyan(&frame.eval_origin.as_ref().unwrap(), internal) + ", ");
+ }
+ result += &cyan("<anonymous>", internal);
+ }
+ if let Some(line_number) = frame.line_number {
+ result += &format!(
+ "{}{}",
+ default_color(":", internal),
+ yellow(&line_number.to_string(), internal)
+ );
+ if let Some(column_number) = frame.column_number {
+ result += &format!(
+ "{}{}",
+ default_color(":", internal),
+ yellow(&column_number.to_string(), internal)
+ );
+ }
+ }
+ result
+}
+
+// Keep in sync with `cli/rt/40_error_stack.js`.
+fn format_frame(frame: &JsStackFrame) -> String {
+ let internal = frame
+ .file_name
+ .as_ref()
+ .map_or(false, |f| f.starts_with("deno:"));
+ let is_method_call =
+ !(frame.is_top_level.unwrap_or_default() || frame.is_constructor);
+ let mut result = String::new();
+ if frame.is_async {
+ result += &colors::gray("async ").to_string();
+ }
+ if frame.is_promise_all {
+ result += &italic_bold(
+ &format!(
+ "Promise.all (index {})",
+ frame.promise_index.unwrap_or_default().to_string()
+ ),
+ internal,
+ );
+ return result;
+ }
+ if is_method_call {
+ let mut formatted_method = String::new();
+ if let Some(function_name) = &frame.function_name {
+ if let Some(type_name) = &frame.type_name {
+ if !function_name.starts_with(type_name) {
+ formatted_method += &format!("{}.", type_name);
+ }
+ }
+ formatted_method += &function_name;
+ if let Some(method_name) = &frame.method_name {
+ if !function_name.ends_with(method_name) {
+ formatted_method += &format!(" [as {}]", method_name);
+ }
+ }
+ } else {
+ if let Some(type_name) = &frame.type_name {
+ formatted_method += &format!("{}.", type_name);
+ }
+ if let Some(method_name) = &frame.method_name {
+ formatted_method += &method_name
+ } else {
+ formatted_method += "<anonymous>";
+ }
+ }
+ result += &italic_bold(&formatted_method, internal);
+ } else if frame.is_constructor {
+ result += &colors::gray("new ").to_string();
+ if let Some(function_name) = &frame.function_name {
+ result += &italic_bold(&function_name, internal);
+ } else {
+ result += &cyan("<anonymous>", internal);
+ }
+ } else if let Some(function_name) = &frame.function_name {
+ result += &italic_bold(&function_name, internal);
+ } else {
+ result += &format_location(frame);
+ return result;
+ }
+ result += &format!(
+ " {}{}{}",
+ default_color("(", internal),
+ format_location(frame),
+ default_color(")", internal)
+ );
+ result
}
-pub fn format_stack(
+fn format_stack(
is_error: bool,
message_line: &str,
source_line: Option<&str>,
start_column: Option<i64>,
end_column: Option<i64>,
- formatted_frames: &[String],
+ frames: &[JsStackFrame],
level: usize,
) -> String {
let mut s = String::new();
@@ -38,11 +164,11 @@ pub fn format_stack(
is_error,
level,
));
- for formatted_frame in formatted_frames {
+ for frame in frames {
s.push_str(&format!(
"\n{:indent$} at {}",
"",
- formatted_frame,
+ format_frame(frame),
indent = level
));
}
@@ -128,31 +254,23 @@ impl Deref for JsError {
impl fmt::Display for JsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let mut formatted_frames = self.0.formatted_frames.clone();
-
- // The formatted_frames passed from prepareStackTrace() are colored.
- if !colors::use_color() {
- formatted_frames = formatted_frames
- .iter()
- .map(|s| colors::strip_ansi_codes(s).to_string())
- .collect();
- }
+ let mut frames = self.0.frames.clone();
// When the stack frame array is empty, but the source location given by
// (script_resource_name, line_number, start_column + 1) exists, this is
// likely a syntax error. For the sake of formatting we treat it like it was
// given as a single stack frame.
- if formatted_frames.is_empty()
+ if frames.is_empty()
&& self.0.script_resource_name.is_some()
&& self.0.line_number.is_some()
&& self.0.start_column.is_some()
{
- formatted_frames = vec![format_location(
- self.0.script_resource_name.as_ref().unwrap(),
- self.0.line_number.unwrap(),
- self.0.start_column.unwrap() + 1,
- )]
- };
+ frames = vec![JsStackFrame::from_location(
+ self.0.script_resource_name.clone(),
+ self.0.line_number,
+ self.0.start_column.map(|n| n + 1),
+ )];
+ }
write!(
f,
@@ -163,7 +281,7 @@ impl fmt::Display for JsError {
self.0.source_line.as_deref(),
self.0.start_column,
self.0.end_column,
- &formatted_frames,
+ &frames,
0
)
)?;