Skip to main content

zuit_report/
lib.rs

1//! Output formatters for zuit analysis reports.
2//!
3//! This crate provides six output formats for a [`zuit_core::engine::Report`]:
4//!
5//! | Format | Function | Notes |
6//! |--------|----------|-------|
7//! | JSON | [`json::render_json`] | Pretty-printed, stable field order. Documented in `docs/json-schema.md`. |
8//! | Terminal | [`terminal::render_terminal`] | Grouped by dimension → severity. Optional ANSI colour and OSC-8 hyperlinks. |
9//! | Markdown | [`markdown::render_markdown`] | Scoreboard table + collapsible `<details>` blocks, PR-comment friendly. |
10//! | SARIF | [`sarif::render_sarif`] | Valid SARIF 2.1.0; single merged run strategy for v1. |
11//! | Checkstyle | [`checkstyle::render_checkstyle`] | Checkstyle v8 XML; consumed by `IntelliJ` and `SonarQube`. |
12//! | `JUnit` | [`junit::render_junit`] | `JUnit` XML (Surefire/Maven flavour); consumed by GitHub Actions, Jenkins, and GitLab CI. |
13//!
14//! The top-level entry point is [`render`], which dispatches to the appropriate
15//! sub-module based on a [`ReportFormat`] value.
16#![warn(missing_docs)]
17
18pub mod checkstyle;
19pub mod json;
20pub mod junit;
21pub mod markdown;
22pub mod sarif;
23pub mod terminal;
24
25use zuit_core::engine::Report;
26
27pub use checkstyle::render_checkstyle;
28pub use json::render_json;
29pub use junit::render_junit;
30pub use markdown::render_markdown;
31pub use sarif::render_sarif;
32pub use terminal::render_terminal;
33
34/// The output format to render a [`Report`] into.
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum ReportFormat {
37    /// Pretty-printed JSON with stable field order.
38    Json,
39    /// Coloured terminal output grouped by dimension and severity.
40    Terminal,
41    /// Markdown suitable for GitHub PR comments.
42    Markdown,
43    /// SARIF 2.1.0 — single merged run, valid per the SARIF 2.1.0 schema.
44    Sarif,
45    /// Checkstyle v8 XML — consumed by `IntelliJ` (Checkstyle plugin) and `SonarQube`.
46    Checkstyle,
47    /// `JUnit` XML (Surefire/Maven flavour) — consumed by GitHub Actions, Jenkins, and GitLab CI.
48    Junit,
49}
50
51/// Options that control how a report is rendered.
52///
53/// The default is CI-friendly (no colour, no hyperlinks).
54#[derive(Debug, Clone, Default)]
55pub struct RenderOptions {
56    /// When `true`, ANSI colour escape codes are emitted in terminal output.
57    /// When `false`, output is plain ASCII.
58    pub use_color: bool,
59    /// When `true`, file paths in terminal output are wrapped in OSC-8 hyperlinks.
60    pub use_hyperlinks: bool,
61}
62
63/// Errors that can occur while rendering a report.
64#[derive(Debug, thiserror::Error)]
65pub enum ReportError {
66    /// The requested format is not implemented.
67    #[error("not implemented: {0}")]
68    NotImplemented(&'static str),
69    /// A `serde_json` serialization failure.
70    #[error("serialization error: {0}")]
71    Serialize(#[from] serde_json::Error),
72    /// A `std::fmt::Write` failure (should never occur in practice because
73    /// `String`'s `Write` impl is infallible, but the `?` operator requires it).
74    #[error(transparent)]
75    Fmt(#[from] std::fmt::Error),
76    /// A `quick_xml` write or encoding failure.
77    #[error("XML error: {0}")]
78    Xml(#[from] quick_xml::Error),
79}
80
81/// Renders `report` in the requested format.
82///
83/// For [`ReportFormat::Terminal`] the default [`RenderOptions`] are used
84/// (no colour, no hyperlinks). Call [`render_terminal`] directly for full control.
85///
86/// # Errors
87///
88/// Returns [`ReportError::Serialize`] if JSON serialization fails (JSON or SARIF).
89/// Returns [`ReportError::Fmt`] if string formatting fails (Markdown or terminal).
90pub fn render(
91    format: ReportFormat,
92    report: &Report,
93    opts: &RenderOptions,
94) -> Result<String, ReportError> {
95    match format {
96        ReportFormat::Json => render_json(report),
97        ReportFormat::Terminal => render_terminal(report, opts),
98        ReportFormat::Markdown => render_markdown(report),
99        ReportFormat::Sarif => render_sarif(report),
100        ReportFormat::Checkstyle => render_checkstyle(report),
101        ReportFormat::Junit => render_junit(report),
102    }
103}