Skip to main content

alint_output/
lib.rs

1//! Output formatters. Each format converts an [`alint_core::Report`] into
2//! bytes suitable for stdout or a file.
3
4mod agent;
5mod github;
6mod gitlab;
7mod human;
8mod json;
9mod junit;
10mod markdown;
11mod sarif;
12pub mod style;
13
14use std::io::Write;
15use std::str::FromStr;
16
17use alint_core::{FixReport, Report};
18
19pub use agent::write_agent;
20pub use github::write_github;
21pub use gitlab::write_gitlab;
22pub use human::{wrap_message, write_fix_human, write_human};
23pub use json::{write_fix_json, write_json};
24pub use junit::write_junit;
25pub use markdown::{write_fix_markdown, write_markdown};
26pub use sarif::write_sarif;
27pub use style::{ColorChoice, GlyphSet, HumanOptions};
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum Format {
31    Human,
32    Json,
33    Sarif,
34    Github,
35    Markdown,
36    Junit,
37    Gitlab,
38    Agent,
39}
40
41impl FromStr for Format {
42    type Err = String;
43    fn from_str(s: &str) -> Result<Self, Self::Err> {
44        match s.to_ascii_lowercase().as_str() {
45            "human" | "pretty" | "text" => Ok(Self::Human),
46            "json" => Ok(Self::Json),
47            "sarif" => Ok(Self::Sarif),
48            "github" | "github-actions" => Ok(Self::Github),
49            "markdown" | "md" => Ok(Self::Markdown),
50            "junit" | "junit-xml" => Ok(Self::Junit),
51            "gitlab" | "gitlab-codequality" | "code-quality" => Ok(Self::Gitlab),
52            "agent" | "agentic" | "ai" => Ok(Self::Agent),
53            other => Err(format!("unknown output format: {other}")),
54        }
55    }
56}
57
58impl Format {
59    /// Write a check-report. Convenience wrapper that uses default
60    /// [`HumanOptions`] (Unicode glyphs, no hyperlinks). Callers
61    /// that care about glyph fallback or hyperlink support — i.e.
62    /// the CLI — should use [`Format::write_with_options`].
63    pub fn write(self, report: &Report, w: &mut dyn Write) -> std::io::Result<()> {
64        self.write_with_options(report, w, HumanOptions::default())
65    }
66
67    /// Like [`Format::write`], but with explicit rendering options.
68    /// Only the `Human` format inspects `opts`; the others ignore it.
69    pub fn write_with_options(
70        self,
71        report: &Report,
72        w: &mut dyn Write,
73        opts: HumanOptions,
74    ) -> std::io::Result<()> {
75        match self {
76            Self::Human => write_human(report, w, opts),
77            Self::Json => write_json(report, w),
78            Self::Sarif => write_sarif(report, w),
79            Self::Github => write_github(report, w),
80            Self::Markdown => write_markdown(report, w),
81            Self::Junit => write_junit(report, w),
82            Self::Gitlab => write_gitlab(report, w),
83            Self::Agent => write_agent(report, w),
84        }
85    }
86
87    /// Write a fix-report. `Human`, `Json`, and `Markdown` have
88    /// dedicated renderers; SARIF, GitHub annotations, `JUnit`,
89    /// and `GitLab` Code Quality describe findings, not
90    /// remediations, so they fall back to the human formatter
91    /// for fix reports.
92    pub fn write_fix(self, report: &FixReport, w: &mut dyn Write) -> std::io::Result<()> {
93        self.write_fix_with_options(report, w, HumanOptions::default())
94    }
95
96    /// Like [`Format::write_fix`], but with explicit rendering options.
97    pub fn write_fix_with_options(
98        self,
99        report: &FixReport,
100        w: &mut dyn Write,
101        opts: HumanOptions,
102    ) -> std::io::Result<()> {
103        match self {
104            Self::Human
105            | Self::Sarif
106            | Self::Github
107            | Self::Junit
108            | Self::Gitlab
109            // Agent format is check-side only; an agent confirming a
110            // fix landed should re-run `alint check --format=agent`
111            // against the now-modified tree. The fix-report itself
112            // falls back to the human formatter so logs from
113            // `alint fix --format=agent` still read sensibly.
114            | Self::Agent => write_fix_human(report, w, opts),
115            Self::Json => write_fix_json(report, w),
116            Self::Markdown => write_fix_markdown(report, w),
117        }
118    }
119}