summaryrefslogtreecommitdiff
path: root/cli/fmt_errors.rs
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2020-04-20 20:39:02 +0100
committerGitHub <noreply@github.com>2020-04-20 15:39:02 -0400
commitef6ee25e09c902e1f9d89a40cf05660432e7143c (patch)
treeb43745fa471693e7d8787b4a5e9a2489f895c873 /cli/fmt_errors.rs
parentf72f045de586a7d0e428b77f6a3e381178cc6674 (diff)
refactor(cli/fmt_errors): Improve source line formatting (#4832)
Diffstat (limited to 'cli/fmt_errors.rs')
-rw-r--r--cli/fmt_errors.rs201
1 files changed, 65 insertions, 136 deletions
diff --git a/cli/fmt_errors.rs b/cli/fmt_errors.rs
index 19e6616ca..d2c69819f 100644
--- a/cli/fmt_errors.rs
+++ b/cli/fmt_errors.rs
@@ -10,63 +10,49 @@ use std::ops::Deref;
const SOURCE_ABBREV_THRESHOLD: usize = 150;
-/// A trait which specifies parts of a diagnostic like item needs to be able to
-/// generate to conform its display to other diagnostic like items
-pub trait DisplayFormatter {
- fn format_category_and_code(&self) -> String;
- fn format_message(&self, level: usize) -> String;
- fn format_related_info(&self) -> String;
- fn format_source_line(&self, level: usize) -> String;
- fn format_source_name(&self) -> String;
-}
-
-fn format_source_name(
- file_name: String,
- line_number: i64,
- column_number: i64,
-) -> String {
- 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_number.to_string());
- format!("{}:{}:{}", file_name_c, line_c, column_c)
-}
-
-/// Formats optional source, line and column numbers into a single string.
-pub fn format_maybe_source_name(
- file_name: Option<String>,
- line_number: Option<i64>,
- column_number: Option<i64>,
+pub fn format_stack(
+ is_error: bool,
+ message_line: String,
+ source_line: Option<String>,
+ start_column: Option<i64>,
+ end_column: Option<i64>,
+ formatted_frames: &[String],
+ level: usize,
) -> String {
- if file_name.is_none() {
- return "".to_string();
- }
-
- assert!(line_number.is_some());
- assert!(column_number.is_some());
- format_source_name(
- file_name.unwrap(),
- line_number.unwrap(),
- column_number.unwrap(),
- )
+ let mut s = String::new();
+ s.push_str(&format!("{:indent$}{}", "", message_line, indent = level));
+ s.push_str(&format_maybe_source_line(
+ source_line,
+ start_column,
+ end_column,
+ is_error,
+ level,
+ ));
+ for formatted_frame in formatted_frames {
+ s.push_str(&format!(
+ "\n{:indent$} at {}",
+ "",
+ formatted_frame,
+ indent = level
+ ));
+ }
+ s
}
/// Take an optional source line and associated information to format it into
/// a pretty printed version of that line.
-pub fn format_maybe_source_line(
+fn format_maybe_source_line(
source_line: Option<String>,
- line_number: Option<i64>,
start_column: Option<i64>,
end_column: Option<i64>,
is_error: bool,
level: usize,
) -> String {
- if source_line.is_none() || line_number.is_none() {
+ if source_line.is_none() || start_column.is_none() || end_column.is_none() {
return "".to_string();
}
- let source_line = source_line.as_ref().unwrap();
+ let source_line = source_line.unwrap();
// sometimes source_line gets set with an empty string, which then outputs
// an empty source line when displayed, so need just short circuit here.
// Also short-circuit on error line too long.
@@ -76,12 +62,6 @@ pub fn format_maybe_source_line(
assert!(start_column.is_some());
assert!(end_column.is_some());
- 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 =
- colors::black_on_white(format!("{:indent$}", "", indent = line_number_len))
- .to_string();
let mut s = String::new();
let start_column = start_column.unwrap();
let end_column = end_column.unwrap();
@@ -107,16 +87,7 @@ pub fn format_maybe_source_line(
let indent = format!("{:indent$}", "", indent = level);
- format!(
- "\n\n{}{} {}\n{}{} {}\n",
- indent, line_color, source_line, indent, line_padding, color_underline
- )
-}
-
-/// Format a message to preface with `error: ` with ansi codes for red.
-pub fn format_error_message(msg: String) -> String {
- let preamble = colors::red("error:".to_string());
- format!("{} {}", preamble, msg)
+ format!("\n{}{}\n{}{}", indent, source_line, indent, color_underline)
}
/// Wrapper around deno_core::JSError which provides color to_string.
@@ -141,63 +112,44 @@ impl Deref for JSError {
}
}
-impl DisplayFormatter for JSError {
- fn format_category_and_code(&self) -> String {
- "".to_string()
- }
-
- fn format_message(&self, _level: usize) -> String {
- format!(
- "{}{}",
- colors::red_bold("error: ".to_string()),
- self.0.message.clone()
- )
- }
-
- fn format_related_info(&self) -> String {
- "".to_string()
- }
-
- fn format_source_line(&self, level: usize) -> String {
- format_maybe_source_line(
- self.0.source_line.clone(),
- self.0.line_number,
- self.0.start_column,
- self.0.end_column,
- true,
- level,
- )
- }
-
- fn format_source_name(&self) -> String {
- let e = &self.0;
- if e.script_resource_name.is_none() {
- return "".to_string();
- }
-
- format!(
- "\n► {}",
- format_maybe_source_name(
- e.script_resource_name.clone(),
- e.line_number,
- e.start_column.map(|n| n + 1),
- )
- )
- }
-}
-
impl fmt::Display for JSError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // 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.
+ let formatted_frames = if self.0.formatted_frames.is_empty()
+ && self.0.script_resource_name.is_some()
+ && self.0.line_number.is_some()
+ && self.0.start_column.is_some()
+ {
+ vec![format!(
+ "{}:{}:{}",
+ colors::cyan(self.0.script_resource_name.clone().unwrap()),
+ colors::yellow(self.0.line_number.unwrap().to_string()),
+ colors::yellow((self.0.start_column.unwrap() + 1).to_string())
+ )]
+ } else {
+ self.0.formatted_frames.clone()
+ };
+
write!(
f,
- "{}{}{}",
- self.format_message(0),
- self.format_source_name(),
- self.format_source_line(0),
+ "{}",
+ &format_stack(
+ true,
+ format!(
+ "{}: {}",
+ colors::red_bold("error".to_string()),
+ self.0.message.clone()
+ ),
+ self.0.source_line.clone(),
+ self.0.start_column,
+ self.0.end_column,
+ &formatted_frames,
+ 0
+ )
)?;
- for formatted_frame in &self.0.formatted_frames {
- write!(f, "\n at {}", formatted_frame)?;
- }
Ok(())
}
}
@@ -210,24 +162,8 @@ mod tests {
use crate::colors::strip_ansi_codes;
#[test]
- fn test_format_none_source_name() {
- let actual = format_maybe_source_name(None, None, None);
- assert_eq!(actual, "");
- }
-
- #[test]
- fn test_format_some_source_name() {
- let actual = format_maybe_source_name(
- Some("file://foo/bar.ts".to_string()),
- Some(1),
- Some(2),
- );
- assert_eq!(strip_ansi_codes(&actual), "file://foo/bar.ts:1:2");
- }
-
- #[test]
fn test_format_none_source_line() {
- let actual = format_maybe_source_line(None, None, None, None, false, 0);
+ let actual = format_maybe_source_line(None, None, None, false, 0);
assert_eq!(actual, "");
}
@@ -236,20 +172,13 @@ mod tests {
let actual = format_maybe_source_line(
Some("console.log('foo');".to_string()),
Some(8),
- Some(8),
Some(11),
true,
0,
);
assert_eq!(
strip_ansi_codes(&actual),
- "\n\n8 console.log(\'foo\');\n ~~~\n"
+ "\nconsole.log(\'foo\');\n ~~~"
);
}
-
- #[test]
- fn test_format_error_message() {
- let actual = format_error_message("foo".to_string());
- assert_eq!(strip_ansi_codes(&actual), "error: foo");
- }
}