mirror of https://github.com/zkat/miette.git
fix(handlers): source code propagation for JSON handler
A part of fix of #99, follow up of #117
This commit is contained in:
parent
32520108ae
commit
410d847b0b
|
|
@ -1,6 +1,6 @@
|
|||
use std::fmt::{self, Write};
|
||||
|
||||
use crate::{protocol::Diagnostic, ReportHandler, Severity};
|
||||
use crate::{protocol::Diagnostic, ReportHandler, Severity, SourceCode};
|
||||
|
||||
/**
|
||||
[ReportHandler] that renders json output.
|
||||
|
|
@ -62,6 +62,15 @@ impl JSONReportHandler {
|
|||
&self,
|
||||
f: &mut impl fmt::Write,
|
||||
diagnostic: &(dyn Diagnostic),
|
||||
) -> fmt::Result {
|
||||
self._render_report(f, diagnostic, None)
|
||||
}
|
||||
|
||||
fn _render_report(
|
||||
&self,
|
||||
f: &mut impl fmt::Write,
|
||||
diagnostic: &(dyn Diagnostic),
|
||||
parent_src: Option<&dyn SourceCode>,
|
||||
) -> fmt::Result {
|
||||
write!(f, r#"{{"message": "{}","#, escape(&diagnostic.to_string()))?;
|
||||
if let Some(code) = diagnostic.code() {
|
||||
|
|
@ -79,8 +88,9 @@ impl JSONReportHandler {
|
|||
if let Some(help) = diagnostic.help() {
|
||||
write!(f, r#""help": "{}","#, escape(&help.to_string()))?;
|
||||
}
|
||||
if diagnostic.source_code().is_some() {
|
||||
self.render_snippets(f, diagnostic)?;
|
||||
let src = diagnostic.source_code().or(parent_src);
|
||||
if let Some(src) = src {
|
||||
self.render_snippets(f, diagnostic, src)?;
|
||||
}
|
||||
if let Some(labels) = diagnostic.labels() {
|
||||
write!(f, r#""labels": ["#)?;
|
||||
|
|
@ -114,7 +124,7 @@ impl JSONReportHandler {
|
|||
} else {
|
||||
add_comma = true;
|
||||
}
|
||||
self.render_report(f, related)?;
|
||||
self._render_report(f, related, src)?;
|
||||
}
|
||||
write!(f, "]")?;
|
||||
} else {
|
||||
|
|
@ -127,14 +137,13 @@ impl JSONReportHandler {
|
|||
&self,
|
||||
f: &mut impl fmt::Write,
|
||||
diagnostic: &(dyn Diagnostic),
|
||||
source: &dyn SourceCode,
|
||||
) -> fmt::Result {
|
||||
if let Some(source) = diagnostic.source_code() {
|
||||
if let Some(mut labels) = diagnostic.labels() {
|
||||
if let Some(label) = labels.next() {
|
||||
if let Ok(span_content) = source.read_span(label.inner(), 0, 0) {
|
||||
let filename = span_content.name().unwrap_or_default();
|
||||
return write!(f, r#""filename": "{}","#, escape(filename));
|
||||
}
|
||||
if let Some(mut labels) = diagnostic.labels() {
|
||||
if let Some(label) = labels.next() {
|
||||
if let Ok(span_content) = source.read_span(label.inner(), 0, 0) {
|
||||
let filename = span_content.name().unwrap_or_default();
|
||||
return write!(f, r#""filename": "{}","#, escape(filename));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -809,4 +809,99 @@ mod json_report_handler {
|
|||
assert_eq!(expected, out);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn related_source_code_propagation() -> Result<(), MietteError> {
|
||||
#[derive(Debug, Diagnostic, Error)]
|
||||
#[error("oops!")]
|
||||
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
||||
struct MyBad {
|
||||
#[source_code]
|
||||
src: NamedSource,
|
||||
#[label("this bit here")]
|
||||
highlight: SourceSpan,
|
||||
#[related]
|
||||
related: Vec<InnerError>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Diagnostic, Error)]
|
||||
#[error("oops!")]
|
||||
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
||||
struct InnerError {
|
||||
#[label("this bit here")]
|
||||
highlight: SourceSpan,
|
||||
}
|
||||
|
||||
let src = "source\n text\n here".to_string();
|
||||
let err = MyBad {
|
||||
src: NamedSource::new("bad_file.rs", src.clone()),
|
||||
highlight: (9, 4).into(),
|
||||
related: vec![
|
||||
InnerError {
|
||||
highlight: (0, 6).into(),
|
||||
},
|
||||
InnerError {
|
||||
highlight: (0, 6).into(),
|
||||
},
|
||||
],
|
||||
};
|
||||
let out = fmt_report(err.into());
|
||||
println!("Error: {}", out);
|
||||
let expected: String = r#"
|
||||
{
|
||||
"message": "oops!",
|
||||
"code": "oops::my::bad",
|
||||
"severity": "error",
|
||||
"help": "try doing it better next time?",
|
||||
"filename": "bad_file.rs",
|
||||
"labels": [
|
||||
{
|
||||
"label": "this bit here",
|
||||
"span": {
|
||||
"offset": 9,
|
||||
"length": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"related": [{
|
||||
"message": "oops!",
|
||||
"code": "oops::my::bad",
|
||||
"severity": "error",
|
||||
"help": "try doing it better next time?",
|
||||
"filename": "bad_file.rs",
|
||||
"labels": [
|
||||
{
|
||||
"label": "this bit here",
|
||||
"span": {
|
||||
"offset": 0,
|
||||
"length": 6
|
||||
}
|
||||
}
|
||||
],
|
||||
"related": []
|
||||
},{
|
||||
"message": "oops!",
|
||||
"code": "oops::my::bad",
|
||||
"severity": "error",
|
||||
"help": "try doing it better next time?",
|
||||
"filename": "bad_file.rs",
|
||||
"labels": [
|
||||
{
|
||||
"label": "this bit here",
|
||||
"span": {
|
||||
"offset": 0,
|
||||
"length": 6
|
||||
}
|
||||
}
|
||||
],
|
||||
"related": []
|
||||
}]
|
||||
}"#
|
||||
.lines()
|
||||
.into_iter()
|
||||
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
||||
.collect();
|
||||
assert_eq!(expected, out);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue