diff --git a/apps/oxlint/src/output_formatter/checkstyle.rs b/apps/oxlint/src/output_formatter/checkstyle.rs index 05655fb3dfad4..adcbd4eed824a 100644 --- a/apps/oxlint/src/output_formatter/checkstyle.rs +++ b/apps/oxlint/src/output_formatter/checkstyle.rs @@ -51,14 +51,14 @@ fn format_checkstyle(diagnostics: &[Error]) -> String { let messages = infos .iter() .fold(String::new(), |mut acc, info| { - let Info { line, column, message, severity, rule_id, .. } = info; + let Info { start, message, severity, rule_id, .. } = info; let severity = match severity { Severity::Error => "error", _ => "warning", }; let message = rule_id.as_ref().map_or_else(|| xml_escape(message), |rule_id| Cow::Owned(format!("{} ({rule_id})", xml_escape(message)))); let source = rule_id.as_ref().map_or_else(|| Cow::Borrowed(""), |rule_id| Cow::Owned(format!("eslint.rules.{rule_id}"))); - let line = format!(r#""#); + let line = format!(r#""#, start.line, start.column); acc.push_str(&line); acc }); diff --git a/apps/oxlint/src/output_formatter/github.rs b/apps/oxlint/src/output_formatter/github.rs index d6b9a33481835..f5739366e0641 100644 --- a/apps/oxlint/src/output_formatter/github.rs +++ b/apps/oxlint/src/output_formatter/github.rs @@ -35,7 +35,7 @@ impl DiagnosticReporter for GithubReporter { } fn format_github(diagnostic: &Error) -> String { - let Info { line, column, filename, message, severity, rule_id } = Info::new(diagnostic); + let Info { start, end, filename, message, severity, rule_id } = Info::new(diagnostic); let severity = match severity { Severity::Error => "error", Severity::Warning | miette::Severity::Advice => "warning", @@ -44,7 +44,11 @@ fn format_github(diagnostic: &Error) -> String { let filename = escape_property(&filename); let message = escape_data(&message); format!( - "::{severity} file={filename},line={line},endLine={line},col={column},endColumn={column},title={title}::{message}\n" + "::{severity} file={filename},line={},endLine={},col={},endColumn={},title={title}::{message}\n", + start.line, + end.line, + start.column, + end.column ) } @@ -108,6 +112,6 @@ mod test { let result = reporter.render_error(error); assert!(result.is_some()); - assert_eq!(result.unwrap(), "::warning file=file%3A//test.ts,line=1,endLine=1,col=1,endColumn=1,title=oxlint::error message\n"); + assert_eq!(result.unwrap(), "::warning file=file%3A//test.ts,line=1,endLine=1,col=1,endColumn=9,title=oxlint::error message\n"); } } diff --git a/apps/oxlint/src/output_formatter/stylish.rs b/apps/oxlint/src/output_formatter/stylish.rs index e6669d61ed82a..7f9e4e2e17bb9 100644 --- a/apps/oxlint/src/output_formatter/stylish.rs +++ b/apps/oxlint/src/output_formatter/stylish.rs @@ -49,7 +49,7 @@ fn format_stylish(diagnostics: &[Error]) -> String { let mut grouped: FxHashMap> = FxHashMap::default(); let mut sorted = diagnostics.iter().collect::>(); - sorted.sort_by_key(|diagnostic| Info::new(diagnostic).line); + sorted.sort_by_key(|diagnostic| Info::new(diagnostic).start.line); for diagnostic in sorted { let info = Info::new(diagnostic); diff --git a/apps/oxlint/src/output_formatter/unix.rs b/apps/oxlint/src/output_formatter/unix.rs index 4c34f334ebd4d..12cfa99699602 100644 --- a/apps/oxlint/src/output_formatter/unix.rs +++ b/apps/oxlint/src/output_formatter/unix.rs @@ -45,14 +45,14 @@ impl DiagnosticReporter for UnixReporter { /// fn format_unix(diagnostic: &Error) -> String { - let Info { line, column, filename, message, severity, rule_id } = Info::new(diagnostic); + let Info { start, end: _, filename, message, severity, rule_id } = Info::new(diagnostic); let severity = match severity { Severity::Error => "Error", _ => "Warning", }; let rule_id = rule_id.map_or_else(|| Cow::Borrowed(""), |rule_id| Cow::Owned(format!("/{rule_id}"))); - format!("{filename}:{line}:{column}: {message} [{severity}{rule_id}]\n") + format!("{filename}:{}:{}: {message} [{severity}{rule_id}]\n", start.line, start.column) } #[cfg(test)] diff --git a/crates/oxc_diagnostics/src/reporter.rs b/crates/oxc_diagnostics/src/reporter.rs index 34443c273a934..ffe44986c4586 100644 --- a/crates/oxc_diagnostics/src/reporter.rs +++ b/crates/oxc_diagnostics/src/reporter.rs @@ -1,5 +1,7 @@ //! [Reporters](DiagnosticReporter) for rendering and writing diagnostics. +use miette::SourceSpan; + use crate::{Error, Severity}; /// Reporters are responsible for rendering diagnostics to some format and writing them to some @@ -54,18 +56,23 @@ pub trait DiagnosticReporter { } pub struct Info { - pub line: usize, - pub column: usize, + pub start: InfoPosition, + pub end: InfoPosition, pub filename: String, pub message: String, pub severity: Severity, pub rule_id: Option, } +pub struct InfoPosition { + pub line: usize, + pub column: usize, +} + impl Info { pub fn new(diagnostic: &Error) -> Self { - let mut line = 0; - let mut column = 0; + let mut start = InfoPosition { line: 0, column: 0 }; + let mut end = InfoPosition { line: 0, column: 0 }; let mut filename = String::new(); let mut message = String::new(); let mut severity = Severity::Warning; @@ -74,8 +81,18 @@ impl Info { if let Some(source) = diagnostic.source_code() { if let Some(label) = labels.next() { if let Ok(span_content) = source.read_span(label.inner(), 0, 0) { - line = span_content.line() + 1; - column = span_content.column() + 1; + start.line = span_content.line() + 1; + start.column = span_content.column() + 1; + + let end_offset = label.inner().offset() + label.inner().len(); + + if let Ok(span_content) = + source.read_span(&SourceSpan::from((end_offset, 0)), 0, 0) + { + end.line = span_content.line() + 1; + end.column = span_content.column() + 1; + } + if let Some(name) = span_content.name() { filename = name.to_string(); }; @@ -92,6 +109,7 @@ impl Info { } } } - Self { line, column, filename, message, severity, rule_id } + + Self { start, end, filename, message, severity, rule_id } } }