mirror of
https://github.com/denoland/deno.git
synced 2024-12-25 16:49:18 -05:00
refactor(cli/fmt_errors): Improve source line formatting (#4832)
This commit is contained in:
parent
f72f045de5
commit
ef6ee25e09
21 changed files with 218 additions and 271 deletions
|
@ -6,9 +6,7 @@
|
||||||
// serde_json.
|
// serde_json.
|
||||||
|
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::fmt_errors::format_maybe_source_line;
|
use crate::fmt_errors::format_stack;
|
||||||
use crate::fmt_errors::format_maybe_source_name;
|
|
||||||
use crate::fmt_errors::DisplayFormatter;
|
|
||||||
use serde_json::value::Value;
|
use serde_json::value::Value;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -56,14 +54,14 @@ impl fmt::Display for Diagnostic {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
for item in &self.items {
|
for item in &self.items {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
writeln!(f)?;
|
write!(f, "\n\n")?;
|
||||||
}
|
}
|
||||||
write!(f, "{}", item.to_string())?;
|
write!(f, "{}", item.to_string())?;
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if i > 1 {
|
if i > 1 {
|
||||||
write!(f, "\n\nFound {} errors.\n", i)?;
|
write!(f, "\n\nFound {} errors.", i)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -181,91 +179,126 @@ impl DiagnosticItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayFormatter for DiagnosticItem {
|
fn format_category_and_code(
|
||||||
fn format_category_and_code(&self) -> String {
|
category: &DiagnosticCategory,
|
||||||
let category = match self.category {
|
code: i64,
|
||||||
DiagnosticCategory::Error => {
|
) -> String {
|
||||||
format!("{}", colors::red_bold("error".to_string()))
|
let category = match category {
|
||||||
}
|
DiagnosticCategory::Error => {
|
||||||
DiagnosticCategory::Warning => "warn".to_string(),
|
format!("{}", colors::red_bold("error".to_string()))
|
||||||
DiagnosticCategory::Debug => "debug".to_string(),
|
}
|
||||||
DiagnosticCategory::Info => "info".to_string(),
|
DiagnosticCategory::Warning => "warn".to_string(),
|
||||||
_ => "".to_string(),
|
DiagnosticCategory::Debug => "debug".to_string(),
|
||||||
};
|
DiagnosticCategory::Info => "info".to_string(),
|
||||||
|
_ => "".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
let code =
|
let code = colors::bold(format!("TS{}", code.to_string())).to_string();
|
||||||
colors::bold(format!(" TS{}", self.code.to_string())).to_string();
|
|
||||||
|
|
||||||
format!("{}{}: ", category, code)
|
format!("{} {}", category, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_message(
|
||||||
|
message_chain: &Option<DiagnosticMessageChain>,
|
||||||
|
message: &str,
|
||||||
|
level: usize,
|
||||||
|
) -> String {
|
||||||
|
debug!("format_message");
|
||||||
|
if message_chain.is_none() {
|
||||||
|
return format!("{:indent$}{}", "", message, indent = level);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_message(&self, level: usize) -> String {
|
let mut s = message_chain.clone().unwrap().format_message(level);
|
||||||
debug!("format_message");
|
s.pop();
|
||||||
if self.message_chain.is_none() {
|
|
||||||
return format!("{:indent$}{}", "", self.message, indent = level);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut s = self.message_chain.clone().unwrap().format_message(level);
|
s
|
||||||
s.pop();
|
}
|
||||||
|
|
||||||
s
|
/// Formats optional source, line and column numbers into a single string.
|
||||||
|
fn format_maybe_frame(
|
||||||
|
file_name: Option<String>,
|
||||||
|
line_number: Option<i64>,
|
||||||
|
column_number: Option<i64>,
|
||||||
|
) -> String {
|
||||||
|
if file_name.is_none() {
|
||||||
|
return "".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_related_info(&self) -> String {
|
assert!(line_number.is_some());
|
||||||
if self.related_information.is_none() {
|
assert!(column_number.is_some());
|
||||||
return "".to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut s = String::new();
|
let line_number = line_number.unwrap();
|
||||||
let related_information = self.related_information.clone().unwrap();
|
let column_number = column_number.unwrap();
|
||||||
for related_diagnostic in related_information {
|
let file_name_c = colors::cyan(file_name.unwrap());
|
||||||
let rd = &related_diagnostic;
|
let line_c = colors::yellow(line_number.to_string());
|
||||||
s.push_str(&format!(
|
let column_c = colors::yellow(column_number.to_string());
|
||||||
"\n{}\n\n ► {}{}\n",
|
format!("{}:{}:{}", file_name_c, line_c, column_c)
|
||||||
rd.format_message(2),
|
}
|
||||||
rd.format_source_name(),
|
|
||||||
rd.format_source_line(4),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
s
|
fn format_maybe_related_information(
|
||||||
|
related_information: &Option<Vec<DiagnosticItem>>,
|
||||||
|
) -> String {
|
||||||
|
if related_information.is_none() {
|
||||||
|
return "".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_source_line(&self, level: usize) -> String {
|
let mut s = String::new();
|
||||||
// Formatter expects 1-based line numbers, but ours are 0-based.
|
let related_information = related_information.clone().unwrap();
|
||||||
format_maybe_source_line(
|
for rd in related_information {
|
||||||
self.source_line.clone(),
|
s.push_str("\n\n");
|
||||||
self.line_number.map(|n| n + 1),
|
s.push_str(&format_stack(
|
||||||
self.start_column,
|
match rd.category {
|
||||||
self.end_column,
|
|
||||||
match self.category {
|
|
||||||
DiagnosticCategory::Error => true,
|
DiagnosticCategory::Error => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
level,
|
format_message(&rd.message_chain, &rd.message, 0),
|
||||||
)
|
rd.source_line.clone(),
|
||||||
|
rd.start_column,
|
||||||
|
rd.end_column,
|
||||||
|
// Formatter expects 1-based line and column numbers, but ours are 0-based.
|
||||||
|
&[format_maybe_frame(
|
||||||
|
rd.script_resource_name.clone(),
|
||||||
|
rd.line_number.map(|n| n + 1),
|
||||||
|
rd.start_column.map(|n| n + 1),
|
||||||
|
)],
|
||||||
|
4,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_source_name(&self) -> String {
|
s
|
||||||
// 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.map(|n| n + 1),
|
|
||||||
self.start_column.map(|n| n + 1),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for DiagnosticItem {
|
impl fmt::Display for DiagnosticItem {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{}\n\n► {}{}{}",
|
"{}",
|
||||||
self.format_category_and_code(),
|
format_stack(
|
||||||
self.format_message(0),
|
match self.category {
|
||||||
self.format_source_name(),
|
DiagnosticCategory::Error => true,
|
||||||
self.format_source_line(0),
|
_ => false,
|
||||||
self.format_related_info(),
|
},
|
||||||
|
format!(
|
||||||
|
"{}: {}",
|
||||||
|
format_category_and_code(&self.category, self.code),
|
||||||
|
format_message(&self.message_chain, &self.message, 0)
|
||||||
|
),
|
||||||
|
self.source_line.clone(),
|
||||||
|
self.start_column,
|
||||||
|
self.end_column,
|
||||||
|
// Formatter expects 1-based line and column numbers, but ours are 0-based.
|
||||||
|
&[format_maybe_frame(
|
||||||
|
self.script_resource_name.clone(),
|
||||||
|
self.line_number.map(|n| n + 1),
|
||||||
|
self.start_column.map(|n| n + 1)
|
||||||
|
)],
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)?;
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
format_maybe_related_information(&self.related_information),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -575,14 +608,30 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn diagnostic_to_string1() {
|
fn diagnostic_to_string1() {
|
||||||
let d = diagnostic1();
|
let d = diagnostic1();
|
||||||
let expected = "error TS2322: Type \'(o: T) => { v: any; f: (x: B) => string; }[]\' is not assignable to type \'(r: B) => Value<B>[]\'.\n Types of parameters \'o\' and \'r\' are incompatible.\n Type \'B\' is not assignable to type \'T\'.\n\n► deno/tests/complex_diagnostics.ts:19:3\n\n19 values: o => [\n ~~~~~~\n\n The expected type comes from property \'values\' which is declared here on type \'SettingsInterface<B>\'\n\n ► deno/tests/complex_diagnostics.ts:7:3\n\n 7 values?: (r: T) => Array<Value<T>>;\n ~~~~~~\n\n";
|
let expected = "error TS2322: Type \'(o: T) => { v: any; f: (x: B) => string; }[]\' is not assignable to type \'(r: B) => Value<B>[]\'.\n Types of parameters \'o\' and \'r\' are incompatible.\n Type \'B\' is not assignable to type \'T\'.\n values: o => [\n ~~~~~~\n at deno/tests/complex_diagnostics.ts:19:3\n\n The expected type comes from property \'values\' which is declared here on type \'SettingsInterface<B>\'\n values?: (r: T) => Array<Value<T>>;\n ~~~~~~\n at deno/tests/complex_diagnostics.ts:7:3";
|
||||||
assert_eq!(expected, strip_ansi_codes(&d.to_string()));
|
assert_eq!(expected, strip_ansi_codes(&d.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn diagnostic_to_string2() {
|
fn diagnostic_to_string2() {
|
||||||
let d = diagnostic2();
|
let d = diagnostic2();
|
||||||
let expected = "error TS2322: Example 1\n\n► deno/tests/complex_diagnostics.ts:19:3\n\n19 values: o => [\n ~~~~~~\n\nerror TS2000: Example 2\n\n► /foo/bar.ts:129:3\n\n129 values: undefined,\n ~~~~~~\n\n\nFound 2 errors.\n";
|
let expected = "error TS2322: Example 1\n values: o => [\n ~~~~~~\n at deno/tests/complex_diagnostics.ts:19:3\n\nerror TS2000: Example 2\n values: undefined,\n ~~~~~~\n at /foo/bar.ts:129:3\n\nFound 2 errors.";
|
||||||
assert_eq!(expected, strip_ansi_codes(&d.to_string()));
|
assert_eq!(expected, strip_ansi_codes(&d.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_none_frame() {
|
||||||
|
let actual = format_maybe_frame(None, None, None);
|
||||||
|
assert_eq!(actual, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_some_frame() {
|
||||||
|
let actual = format_maybe_frame(
|
||||||
|
Some("file://foo/bar.ts".to_string()),
|
||||||
|
Some(1),
|
||||||
|
Some(2),
|
||||||
|
);
|
||||||
|
assert_eq!(strip_ansi_codes(&actual), "file://foo/bar.ts:1:2");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,63 +10,49 @@ use std::ops::Deref;
|
||||||
|
|
||||||
const SOURCE_ABBREV_THRESHOLD: usize = 150;
|
const SOURCE_ABBREV_THRESHOLD: usize = 150;
|
||||||
|
|
||||||
/// A trait which specifies parts of a diagnostic like item needs to be able to
|
pub fn format_stack(
|
||||||
/// generate to conform its display to other diagnostic like items
|
is_error: bool,
|
||||||
pub trait DisplayFormatter {
|
message_line: String,
|
||||||
fn format_category_and_code(&self) -> String;
|
source_line: Option<String>,
|
||||||
fn format_message(&self, level: usize) -> String;
|
start_column: Option<i64>,
|
||||||
fn format_related_info(&self) -> String;
|
end_column: Option<i64>,
|
||||||
fn format_source_line(&self, level: usize) -> String;
|
formatted_frames: &[String],
|
||||||
fn format_source_name(&self) -> String;
|
level: usize,
|
||||||
}
|
|
||||||
|
|
||||||
fn format_source_name(
|
|
||||||
file_name: String,
|
|
||||||
line_number: i64,
|
|
||||||
column_number: i64,
|
|
||||||
) -> String {
|
) -> String {
|
||||||
let line_number = line_number;
|
let mut s = String::new();
|
||||||
let column_number = column_number;
|
s.push_str(&format!("{:indent$}{}", "", message_line, indent = level));
|
||||||
let file_name_c = colors::cyan(file_name);
|
s.push_str(&format_maybe_source_line(
|
||||||
let line_c = colors::yellow(line_number.to_string());
|
source_line,
|
||||||
let column_c = colors::yellow(column_number.to_string());
|
start_column,
|
||||||
format!("{}:{}:{}", file_name_c, line_c, column_c)
|
end_column,
|
||||||
}
|
is_error,
|
||||||
|
level,
|
||||||
/// Formats optional source, line and column numbers into a single string.
|
));
|
||||||
pub fn format_maybe_source_name(
|
for formatted_frame in formatted_frames {
|
||||||
file_name: Option<String>,
|
s.push_str(&format!(
|
||||||
line_number: Option<i64>,
|
"\n{:indent$} at {}",
|
||||||
column_number: Option<i64>,
|
"",
|
||||||
) -> String {
|
formatted_frame,
|
||||||
if file_name.is_none() {
|
indent = level
|
||||||
return "".to_string();
|
));
|
||||||
}
|
}
|
||||||
|
s
|
||||||
assert!(line_number.is_some());
|
|
||||||
assert!(column_number.is_some());
|
|
||||||
format_source_name(
|
|
||||||
file_name.unwrap(),
|
|
||||||
line_number.unwrap(),
|
|
||||||
column_number.unwrap(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take an optional source line and associated information to format it into
|
/// Take an optional source line and associated information to format it into
|
||||||
/// a pretty printed version of that line.
|
/// a pretty printed version of that line.
|
||||||
pub fn format_maybe_source_line(
|
fn format_maybe_source_line(
|
||||||
source_line: Option<String>,
|
source_line: Option<String>,
|
||||||
line_number: Option<i64>,
|
|
||||||
start_column: Option<i64>,
|
start_column: Option<i64>,
|
||||||
end_column: Option<i64>,
|
end_column: Option<i64>,
|
||||||
is_error: bool,
|
is_error: bool,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> String {
|
) -> 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();
|
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
|
// sometimes source_line gets set with an empty string, which then outputs
|
||||||
// an empty source line when displayed, so need just short circuit here.
|
// an empty source line when displayed, so need just short circuit here.
|
||||||
// Also short-circuit on error line too long.
|
// Also short-circuit on error line too long.
|
||||||
|
@ -76,12 +62,6 @@ pub fn format_maybe_source_line(
|
||||||
|
|
||||||
assert!(start_column.is_some());
|
assert!(start_column.is_some());
|
||||||
assert!(end_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 mut s = String::new();
|
||||||
let start_column = start_column.unwrap();
|
let start_column = start_column.unwrap();
|
||||||
let end_column = end_column.unwrap();
|
let end_column = end_column.unwrap();
|
||||||
|
@ -107,16 +87,7 @@ pub fn format_maybe_source_line(
|
||||||
|
|
||||||
let indent = format!("{:indent$}", "", indent = level);
|
let indent = format!("{:indent$}", "", indent = level);
|
||||||
|
|
||||||
format!(
|
format!("\n{}{}\n{}{}", indent, source_line, indent, color_underline)
|
||||||
"\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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper around deno_core::JSError which provides color to_string.
|
/// 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 {
|
impl fmt::Display for JSError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
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!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{}{}",
|
"{}",
|
||||||
self.format_message(0),
|
&format_stack(
|
||||||
self.format_source_name(),
|
true,
|
||||||
self.format_source_line(0),
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,25 +161,9 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::colors::strip_ansi_codes;
|
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]
|
#[test]
|
||||||
fn test_format_none_source_line() {
|
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, "");
|
assert_eq!(actual, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,20 +172,13 @@ mod tests {
|
||||||
let actual = format_maybe_source_line(
|
let actual = format_maybe_source_line(
|
||||||
Some("console.log('foo');".to_string()),
|
Some("console.log('foo');".to_string()),
|
||||||
Some(8),
|
Some(8),
|
||||||
Some(8),
|
|
||||||
Some(11),
|
Some(11),
|
||||||
true,
|
true,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
strip_ansi_codes(&actual),
|
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
[WILDCARD]
|
[WILDCARD]error TS2552: Cannot find name 'consol'. Did you mean 'console'?
|
||||||
error TS2552: Cannot find name 'consol'. Did you mean 'console'?
|
consol.log("hello world!");
|
||||||
|
~~~~~~
|
||||||
|
at [WILDCARD]tests/038_checkjs.js:2:1
|
||||||
|
|
||||||
[WILDCARD]tests/038_checkjs.js:2:1
|
'console' is declared here.
|
||||||
|
declare var console: Console;
|
||||||
|
~~~~~~~
|
||||||
|
at [WILDCARD]
|
||||||
|
|
||||||
2 consol.log("hello world!");
|
|
||||||
[WILDCARD]
|
|
||||||
error TS2552: Cannot find name 'Foo'. Did you mean 'foo'?
|
error TS2552: Cannot find name 'Foo'. Did you mean 'foo'?
|
||||||
|
const foo = new Foo();
|
||||||
|
~~~
|
||||||
|
at [WILDCARD]tests/038_checkjs.js:6:17
|
||||||
|
|
||||||
[WILDCARD]tests/038_checkjs.js:6:17
|
'foo' is declared here.
|
||||||
|
const foo = new Foo();
|
||||||
|
~~~
|
||||||
|
at [WILDCARD]tests/038_checkjs.js:6:7
|
||||||
|
|
||||||
6 const foo = new Foo();
|
|
||||||
[WILDCARD]
|
|
||||||
Found 2 errors.
|
Found 2 errors.
|
||||||
[WILDCARD]
|
|
|
@ -1,6 +1,4 @@
|
||||||
[WILDCARD]
|
[WILDCARD]error: Uncaught BadResource: Bad resource ID
|
||||||
error: Uncaught BadResource: Bad resource ID
|
|
||||||
[WILDCARD]dispatch_json.ts:[WILDCARD]
|
|
||||||
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at Object.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])
|
||||||
|
|
|
@ -2,10 +2,7 @@
|
||||||
before error
|
before error
|
||||||
world
|
world
|
||||||
error: Uncaught Error: error
|
error: Uncaught Error: error
|
||||||
[WILDCARD]tests/async_error.ts:5:9
|
throw Error("error");
|
||||||
|
^
|
||||||
5 throw Error("error");
|
|
||||||
^
|
|
||||||
|
|
||||||
at foo ([WILDCARD]tests/async_error.ts:5:9)
|
at foo ([WILDCARD]tests/async_error.ts:5:9)
|
||||||
at [WILDCARD]tests/async_error.ts:8:1
|
at [WILDCARD]tests/async_error.ts:8:1
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
[WILDCARD]Unsupported compiler options in "[WILDCARD]config.tsconfig.json"
|
[WILDCARD]Unsupported compiler options in "[WILDCARD]config.tsconfig.json"
|
||||||
The following options were ignored:
|
The following options were ignored:
|
||||||
module, target
|
module, target
|
||||||
[WILDCARD]error TS2532: Object is possibly 'undefined'.
|
error TS2532: Object is possibly 'undefined'.
|
||||||
|
if (map.get("bar").foo) {
|
||||||
[WILDCARD]tests/config.ts:3:5
|
~~~~~~~~~~~~~~
|
||||||
|
at [WILDCARD]tests/config.ts:3:5
|
||||||
3 if (map.get("bar").foo) {
|
|
||||||
~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
[WILDCARD]error: Uncaught Error: bad
|
[WILDCARD]error: Uncaught Error: bad
|
||||||
[WILDCARD]tests/error_001.ts:2:9
|
throw Error("bad");
|
||||||
|
^
|
||||||
2 throw Error("bad");
|
|
||||||
^
|
|
||||||
|
|
||||||
at foo ([WILDCARD]tests/error_001.ts:2:9)
|
at foo ([WILDCARD]tests/error_001.ts:2:9)
|
||||||
at bar ([WILDCARD]tests/error_001.ts:6:3)
|
at bar ([WILDCARD]tests/error_001.ts:6:3)
|
||||||
at [WILDCARD]tests/error_001.ts:9:1
|
at [WILDCARD]tests/error_001.ts:9:1
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
[WILDCARD]error: Uncaught Error: exception from mod1
|
[WILDCARD]error: Uncaught Error: exception from mod1
|
||||||
[WILDCARD]tests/subdir/mod1.ts:16:9
|
throw Error("exception from mod1");
|
||||||
|
^
|
||||||
16 throw Error("exception from mod1");
|
|
||||||
^
|
|
||||||
|
|
||||||
at throwsError ([WILDCARD]tests/subdir/mod1.ts:16:9)
|
at throwsError ([WILDCARD]tests/subdir/mod1.ts:16:9)
|
||||||
at foo ([WILDCARD]tests/error_002.ts:4:3)
|
at foo ([WILDCARD]tests/error_002.ts:4:3)
|
||||||
at [WILDCARD]tests/error_002.ts:7:1
|
at [WILDCARD]tests/error_002.ts:7:1
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
[WILDCARD]error TS2322: Type '{ a: { b: { c(): { d: number; }; }; }; }' is not assignable to type '{ a: { b: { c(): { d: string; }; }; }; }'.
|
[WILDCARD]error TS2322: Type '{ a: { b: { c(): { d: number; }; }; }; }' is not assignable to type '{ a: { b: { c(): { d: string; }; }; }; }'.
|
||||||
The types of 'a.b.c().d' are incompatible between these types.
|
The types of 'a.b.c().d' are incompatible between these types.
|
||||||
Type 'number' is not assignable to type 'string'.
|
Type 'number' is not assignable to type 'string'.
|
||||||
|
x = y;
|
||||||
[WILDCARD]/cli/tests/error_003_typescript.ts:20:1
|
^
|
||||||
|
at [WILDCARD]/tests/error_003_typescript.ts:20:1
|
||||||
20 x = y;
|
|
||||||
^
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
[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]
|
|
||||||
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at Object.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])
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
[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]
|
|
||||||
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at Object.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])
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
[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]
|
|
||||||
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]dispatch_json.ts:[WILDCARD])
|
||||||
at Object.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])
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
[WILDCARD]error: Uncaught ReferenceError: consol is not defined
|
[WILDCARD]error: Uncaught ReferenceError: consol is not defined
|
||||||
[WILDCARD]tests/error_008_checkjs.js:2:1
|
consol.log("hello world!");
|
||||||
|
^
|
||||||
2 consol.log("hello world!");
|
|
||||||
^
|
|
||||||
|
|
||||||
at [WILDCARD]tests/error_008_checkjs.js:2:1
|
at [WILDCARD]tests/error_008_checkjs.js:2:1
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
[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]
|
|
||||||
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
||||||
at Object.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])
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
[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]
|
|
||||||
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
||||||
at Object.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])
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
[WILDCARD]error TS2532: Object is possibly 'undefined'.
|
[WILDCARD]error TS2532: Object is possibly 'undefined'.
|
||||||
|
at [WILDCARD]tests/error_017_hide_long_source_ts.ts:2:1
|
||||||
► file:///[WILDCARD]cli/tests/error_017_hide_long_source_ts.ts:2:1
|
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
error: Uncaught TypeError: Cannot read property 'a' of undefined
|
error: Uncaught TypeError: Cannot read property 'a' of undefined
|
||||||
► file:///[WILDCARD]cli/tests/error_018_hide_long_source_js.js:2:206
|
|
||||||
at file:///[WILDCARD]cli/tests/error_018_hide_long_source_js.js:2:206
|
at file:///[WILDCARD]cli/tests/error_018_hide_long_source_js.js:2:206
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
error: Uncaught SyntaxError: Unexpected identifier
|
error: Uncaught SyntaxError: Unexpected identifier
|
||||||
[WILDCARD]tests/error_syntax.js:3:6
|
(the following is a syntax error ^^ ! )
|
||||||
|
~~~~~~~~~
|
||||||
3 (the following is a syntax error ^^ ! )
|
at [WILDCARD]tests/error_syntax.js:3:6
|
||||||
~~~~~~~~~
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
error: Uncaught SyntaxError: Unexpected end of input
|
error: Uncaught SyntaxError: Unexpected end of input
|
||||||
► file:///[WILDCARD]cli/tests/error_syntax_empty_trailing_line.mjs:[WILDCARD]
|
at [WILDCARD]tests/error_syntax_empty_trailing_line.mjs:[WILDCARD]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
[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]ops/dispatch_json.ts:[WILDCARD]
|
|
||||||
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
at unwrapResponse ([WILDCARD]ops/dispatch_json.ts:[WILDCARD])
|
||||||
at Object.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 Object.resolveModules ([WILDCARD]ops/compiler.ts:[WILDCARD])
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
// 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!");
|
|
||||||
// console.log(err.stack);
|
|
||||||
// It would require calling into Rust from Error.prototype.prepareStackTrace.
|
|
||||||
|
|
||||||
use crate::ErrBox;
|
use crate::ErrBox;
|
||||||
use rusty_v8 as v8;
|
use rusty_v8 as v8;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
@ -260,7 +254,6 @@ fn format_source_loc(
|
||||||
line_number: i64,
|
line_number: i64,
|
||||||
column_number: i64,
|
column_number: i64,
|
||||||
) -> String {
|
) -> String {
|
||||||
// TODO match this style with how typescript displays errors.
|
|
||||||
let line_number = line_number;
|
let line_number = line_number;
|
||||||
let column_number = column_number;
|
let column_number = column_number;
|
||||||
format!("{}:{}:{}", file_name, line_number, column_number)
|
format!("{}:{}:{}", file_name, line_number, column_number)
|
||||||
|
|
Loading…
Reference in a new issue