use std::io::{self, Write};
use pedant_core::GateVerdict;
use pedant_core::json_format::JsonViolation;
use pedant_core::violation::Violation;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, clap::ValueEnum)]
pub enum OutputFormat {
#[default]
Text,
Json,
}
pub struct Reporter {
format: OutputFormat,
quiet: bool,
}
impl Reporter {
pub fn new(format: OutputFormat, quiet: bool) -> Self {
Self { format, quiet }
}
pub fn report<W: Write>(&self, violations: &[Violation], writer: &mut W) -> io::Result<()> {
match self.format {
OutputFormat::Text => self.report_text(violations, writer),
OutputFormat::Json => self.report_json(violations, writer),
}
}
fn report_text<W: Write>(&self, violations: &[Violation], writer: &mut W) -> io::Result<()> {
for v in violations {
writeln!(writer, "{v}")?;
}
if !self.quiet && !violations.is_empty() {
writeln!(writer)?;
writeln!(writer, "Found {} violation(s)", violations.len())?;
}
Ok(())
}
fn report_json<W: Write>(&self, violations: &[Violation], writer: &mut W) -> io::Result<()> {
let json_violations: Vec<JsonViolation<'_>> =
violations.iter().map(JsonViolation::from).collect();
serde_json::to_writer_pretty(&mut *writer, &json_violations).map_err(io::Error::other)?;
writeln!(writer)?;
Ok(())
}
pub fn report_gate<W: Write>(
&self,
verdicts: &[GateVerdict],
writer: &mut W,
) -> io::Result<()> {
match self.format {
OutputFormat::Text => self.report_gate_text(verdicts, writer),
OutputFormat::Json => self.report_gate_json(verdicts, writer),
}
}
fn report_gate_text<W: Write>(
&self,
verdicts: &[GateVerdict],
writer: &mut W,
) -> io::Result<()> {
for v in verdicts {
writeln!(writer, "{}: {} — {}", v.severity, v.rule, v.rationale)?;
}
Ok(())
}
fn report_gate_json<W: Write>(
&self,
verdicts: &[GateVerdict],
writer: &mut W,
) -> io::Result<()> {
serde_json::to_writer_pretty(&mut *writer, verdicts).map_err(io::Error::other)?;
writeln!(writer)?;
Ok(())
}
}