From f31b628db3906978b8b6bcf305ba228b645ecce9 Mon Sep 17 00:00:00 2001 From: dvermd <315743+dvermd@users.noreply.github.com> Date: Sun, 10 Oct 2021 04:48:56 +0200 Subject: [PATCH 1/2] feat(handlers): Add JSON handler --- Cargo.toml | 1 + src/handlers/json.rs | 129 +++++++ src/handlers/mod.rs | 5 + tests/test_json.rs | 793 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 928 insertions(+) create mode 100644 src/handlers/json.rs create mode 100644 tests/test_json.rs diff --git a/Cargo.toml b/Cargo.toml index ba57b3dd..b6bab2ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ fancy = [ "supports-unicode", "backtrace" ] +json = [] [workspace] members = ["miette-derive"] diff --git a/src/handlers/json.rs b/src/handlers/json.rs new file mode 100644 index 00000000..7508db09 --- /dev/null +++ b/src/handlers/json.rs @@ -0,0 +1,129 @@ +use std::fmt; + +use crate::{protocol::Diagnostic, ReportHandler, Severity}; + +/** +[ReportHandler] that renders json output. +It's a machine-readable output. +*/ +#[derive(Debug, Clone)] +pub struct JSONReportHandler; + +impl JSONReportHandler { + /// Create a new [JSONReportHandler]. There are no customization + /// options. + pub fn new() -> Self { + Self + } +} + +impl Default for JSONReportHandler { + fn default() -> Self { + Self::new() + } +} + +fn escape(input: &str) -> String { + input + .chars() + .map(|c| match c { + '"' => "\\\\\"".to_string(), + '\'' => "\\\\'".to_string(), + '\r' => "\\\\r".to_string(), + '\n' => "\\\\n".to_string(), + '\t' => "\\\\t".to_string(), + '\u{08}' => "\\\\b".to_string(), + '\u{0c}' => "\\\\f".to_string(), + c => format!("{}", c), + }) + .collect() +} + +impl JSONReportHandler { + /// Render a [Diagnostic]. This function is mostly internal and meant to + /// be called by the toplevel [ReportHandler] handler, but is + /// made public to make it easier (possible) to test in isolation from + /// global state. + pub fn render_report( + &self, + f: &mut impl fmt::Write, + diagnostic: &(dyn Diagnostic), + ) -> fmt::Result { + write!(f, r#"{{"message": "{}","#, escape(&diagnostic.to_string()))?; + if let Some(code) = diagnostic.code() { + write!(f, r#""code": "{}","#, escape(&code.to_string()))?; + } + let severity = match diagnostic.severity() { + Some(Severity::Error) | None => "error", + Some(Severity::Warning) => "warning", + Some(Severity::Advice) => "advice", + }; + write!(f, r#""severity": "{:}","#, severity)?; + if let Some(url) = diagnostic.url() { + write!(f, r#""url": "{}","#, &url.to_string())?; + } + 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)?; + } + if let Some(labels) = diagnostic.labels() { + write!(f, r#""labels": ["#)?; + let mut add_comma = false; + for label in labels { + if add_comma { + write!(f, ",")?; + } else { + add_comma = true; + } + write!(f, "{{")?; + if let Some(label_name) = label.label() { + write!(f, r#""label": "{}","#, escape(label_name))?; + } + write!(f, r#""span": {{"#)?; + write!(f, r#""offset": {},"#, label.offset())?; + write!(f, r#""length": {}"#, label.len())?; + + write!(f, "}}}}")?; + } + write!(f, "],")?; + } else { + write!(f, r#""labels": [],"#)?; + } + if let Some(relateds) = diagnostic.related() { + write!(f, r#""related": ["#)?; + for related in relateds { + self.render_report(f, related)?; + } + write!(f, "]")?; + } else { + write!(f, r#""related": []"#)?; + } + write!(f, "}}") + } + + fn render_snippets( + &self, + f: &mut impl fmt::Write, + diagnostic: &(dyn Diagnostic), + ) -> 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)); + } + } + } + } + write!(f, r#""filename": "","#) + } +} + +impl ReportHandler for JSONReportHandler { + fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.render_report(f, diagnostic) + } +} diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 7823937b..e8bc312b 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -8,6 +8,9 @@ pub use debug::*; #[cfg(feature = "fancy")] pub use graphical::*; #[allow(unreachable_pub)] +#[cfg(feature = "json")] +pub use json::*; +#[allow(unreachable_pub)] pub use narratable::*; #[allow(unreachable_pub)] #[cfg(feature = "fancy")] @@ -16,6 +19,8 @@ pub use theme::*; mod debug; #[cfg(feature = "fancy")] mod graphical; +#[cfg(feature = "json")] +mod json; mod narratable; #[cfg(feature = "fancy")] mod theme; diff --git a/tests/test_json.rs b/tests/test_json.rs new file mode 100644 index 00000000..8e9c7365 --- /dev/null +++ b/tests/test_json.rs @@ -0,0 +1,793 @@ +#[cfg(feature = "json")] +mod json_report_handler { + + use miette::{Diagnostic, MietteError, NamedSource, Report, SourceSpan}; + + use miette::JSONReportHandler; + + use thiserror::Error; + + fn fmt_report(diag: Report) -> String { + let mut out = String::new(); + if cfg!(feature = "json") { + #[cfg(feature = "json")] + JSONReportHandler::new() + .render_report(&mut out, diag.as_ref()) + .unwrap(); + } + out + } + + #[test] + fn single_line_with_wide_char() -> 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, + } + + let src = "source\n 👼🏼text\n here".to_string(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight: (9, 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": 6 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn single_line_highlight() -> 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, + } + + let src = "source\n text\n here".to_string(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight: (9, 4).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": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn single_line_highlight_offset_zero() -> 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, + } + + let src = "source\n text\n here".to_string(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight: (0, 0).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": 0, + "length": 0 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn single_line_highlight_with_empty_span() -> 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, + } + + let src = "source\n text\n here".to_string(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight: (9, 0).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": 0 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn single_line_highlight_no_label() -> 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] + highlight: SourceSpan, + } + + let src = "source\n text\n here".to_string(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight: (9, 4).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": [ + { + "span": { + "offset": 9, + "length": 4 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn single_line_highlight_at_line_start() -> 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, + } + + let src = "source\ntext\n here".to_string(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight: (7, 4).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": 7, + "length": 4 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn multiple_same_line_highlights() -> 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 = "x"] + highlight1: SourceSpan, + #[label = "y"] + highlight2: SourceSpan, + #[label = "z"] + highlight3: SourceSpan, + } + + let src = "source\n text text text text text\n here".to_string(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight1: (9, 4).into(), + highlight2: (14, 4).into(), + highlight3: (24, 4).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": "x", + "span": { + "offset": 9, + "length": 4 + } + }, + { + "label": "y", + "span": { + "offset": 14, + "length": 4 + } + }, + { + "label": "z", + "span": { + "offset": 24, + "length": 4 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn multiline_highlight_adjacent() -> 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 = "these two lines"] + highlight: SourceSpan, + } + + let src = "source\n text\n here".to_string(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight: (9, 11).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": "these two lines", + "span": { + "offset": 9, + "length": 11 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn multiline_highlight_flyby() -> 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 = "block 1"] + highlight1: SourceSpan, + #[label = "block 2"] + highlight2: SourceSpan, + } + + let src = r#"line1 + line2 + line3 + line4 + line5 + "# + .to_string(); + let len = src.len(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight1: (0, len).into(), + highlight2: (10, 9).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": "block 1", + "span": { + "offset": 0, + "length": 50 + } + }, + { + "label": "block 2", + "span": { + "offset": 10, + "length": 9 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn multiline_highlight_no_label() -> Result<(), MietteError> { + #[derive(Debug, Diagnostic, Error)] + #[error("wtf?!\nit broke :(")] + #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] + struct MyBad { + #[source] + source: Inner, + #[source_code] + src: NamedSource, + #[label = "block 1"] + highlight1: SourceSpan, + #[label] + highlight2: SourceSpan, + } + + #[derive(Debug, Error)] + #[error("something went wrong\n\nHere's a more detailed explanation of everything that actually went wrong because it's actually important.\n")] + struct Inner(#[source] InnerInner); + + #[derive(Debug, Error)] + #[error("very much went wrong")] + struct InnerInner; + + let src = r#"line1 + line2 + line3 + line4 + line5 + "# + .to_string(); + let len = src.len(); + let err = MyBad { + source: Inner(InnerInner), + src: NamedSource::new("bad_file.rs", src), + highlight1: (0, len).into(), + highlight2: (10, 9).into(), + }; + let out = fmt_report(err.into()); + println!("Error: {}", out); + let expected: String = r#" + { + "message": "wtf?!\\nit broke :(", + "code": "oops::my::bad", + "severity": "error", + "help": "try doing it better next time?", + "filename": "bad_file.rs", + "labels": [ + { + "label": "block 1", + "span": { + "offset": 0, + "length": 50 + } + }, + { + "span": { + "offset": 10, + "length": 9 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn multiple_multiline_highlights_adjacent() -> 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"] + highlight1: SourceSpan, + #[label = "also this bit"] + highlight2: SourceSpan, + } + + let src = "source\n text\n here\nmore here".to_string(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight1: (0, 10).into(), + highlight2: (20, 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": 0, + "length": 10 + } + }, + { + "label": "also this bit", + "span": { + "offset": 20, + "length": 6 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn multiple_multiline_highlights_overlapping_lines() -> 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"] + highlight1: SourceSpan, + #[label = "also this bit"] + highlight2: SourceSpan, + } + + let src = "source\n text\n here".to_string(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight1: (0, 8).into(), + highlight2: (9, 10).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": 0, + "length": 8 + } + }, + { + "label": "also this bit", + "span": { + "offset": 9, + "length": 10 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn multiple_multiline_highlights_overlapping_offsets() -> 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"] + highlight1: SourceSpan, + #[label = "also this bit"] + highlight2: SourceSpan, + } + + let src = "source\n text\n here".to_string(); + let err = MyBad { + src: NamedSource::new("bad_file.rs", src), + highlight1: (0, 8).into(), + highlight2: (10, 10).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": 0, + "length": 8 + } + }, + { + "label": "also this bit", + "span": { + "offset": 10, + "length": 10 + } + } + ], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn url() -> Result<(), MietteError> { + #[derive(Debug, Diagnostic, Error)] + #[error("oops!")] + #[diagnostic(help("try doing it better next time?"), url("https://example.com"))] + struct MyBad; + + let err = MyBad; + let out = fmt_report(err.into()); + println!("Error: {}", out); + let expected: String = r#" + { + "message": "oops!", + "severity": "error", + "url": "https://example.com", + "help": "try doing it better next time?", + "labels": [], + "related": [] + }"# + .lines() + .into_iter() + .map(|s| s.trim_matches(|c| c == ' ' || c == '\n')) + .collect(); + assert_eq!(expected, out); + Ok(()) + } + + #[test] + fn related() -> 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, + } + + 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![MyBad { + src: NamedSource::new("bad_file2.rs", src), + highlight: (0, 6).into(), + related: vec![], + }], + }; + 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_file2.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(()) + } +} From 15de09e558bb83ac3739cbf69f4413449f265af7 Mon Sep 17 00:00:00 2001 From: dvermd <315743+dvermd@users.noreply.github.com> Date: Mon, 25 Oct 2021 08:27:22 +0200 Subject: [PATCH 2/2] feat(handlers): Remove json feature flag --- Cargo.toml | 1 - src/handlers/mod.rs | 2 -- tests/test_json.rs | 10 +++------- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b6bab2ed..ba57b3dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,6 @@ fancy = [ "supports-unicode", "backtrace" ] -json = [] [workspace] members = ["miette-derive"] diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index e8bc312b..5df8e734 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -8,7 +8,6 @@ pub use debug::*; #[cfg(feature = "fancy")] pub use graphical::*; #[allow(unreachable_pub)] -#[cfg(feature = "json")] pub use json::*; #[allow(unreachable_pub)] pub use narratable::*; @@ -19,7 +18,6 @@ pub use theme::*; mod debug; #[cfg(feature = "fancy")] mod graphical; -#[cfg(feature = "json")] mod json; mod narratable; #[cfg(feature = "fancy")] diff --git a/tests/test_json.rs b/tests/test_json.rs index 8e9c7365..c56217cf 100644 --- a/tests/test_json.rs +++ b/tests/test_json.rs @@ -1,4 +1,3 @@ -#[cfg(feature = "json")] mod json_report_handler { use miette::{Diagnostic, MietteError, NamedSource, Report, SourceSpan}; @@ -9,12 +8,9 @@ mod json_report_handler { fn fmt_report(diag: Report) -> String { let mut out = String::new(); - if cfg!(feature = "json") { - #[cfg(feature = "json")] - JSONReportHandler::new() - .render_report(&mut out, diag.as_ref()) - .unwrap(); - } + JSONReportHandler::new() + .render_report(&mut out, diag.as_ref()) + .unwrap(); out }