Skip to main content

mago_reporting/formatter/
mod.rs

1use std::io::Write;
2
3use mago_database::ReadDatabase;
4
5use crate::IssueCollection;
6use crate::Level;
7use crate::color::ColorChoice;
8use crate::error::ReportingError;
9
10pub mod ariadne;
11pub mod checkstyle;
12pub mod code_count;
13pub mod count;
14pub mod emacs;
15pub mod github;
16pub mod gitlab;
17pub mod json;
18pub mod medium;
19pub mod rich;
20pub mod sarif;
21pub mod short;
22pub mod utils;
23
24/// Configuration for formatters.
25#[derive(Debug, Clone)]
26pub struct FormatterConfig {
27    /// Choice for colorizing output.
28    pub color_choice: ColorChoice,
29    /// Whether to sort issues before formatting.
30    pub sort: bool,
31    /// Minimum report level (filter out lower severity issues).
32    pub minimum_level: Option<Level>,
33    /// Whether to filter to only fixable issues.
34    pub filter_fixable: bool,
35    /// Optional editor URL template for OSC 8 terminal hyperlinks.
36    ///
37    /// Supported placeholders: `%file%` (absolute path), `%line%`, `%column%`.
38    /// Example: `"phpstorm://open?file=%file%&line=%line%"`
39    pub editor_url: Option<String>,
40}
41
42/// Trait for formatting issues to a writer.
43pub trait Formatter {
44    /// Format issues and write them to the provided writer.
45    ///
46    /// # Arguments
47    ///
48    /// * `writer` - The writer to output formatted issues to
49    /// * `issues` - The collection of issues to format
50    /// * `database` - The read database for accessing source files
51    /// * `config` - Configuration for formatting behavior
52    ///
53    /// # Errors
54    ///
55    /// Returns an error if formatting or writing fails.
56    fn format(
57        &self,
58        writer: &mut dyn Write,
59        issues: &IssueCollection,
60        database: &ReadDatabase,
61        config: &FormatterConfig,
62    ) -> Result<(), ReportingError>;
63}
64
65/// The format to use for reporting.
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumString, strum::VariantNames, Default)]
67#[strum(serialize_all = "kebab-case")]
68pub enum ReportingFormat {
69    /// Rich diagnostic format with full context.
70    #[default]
71    Rich,
72    /// Medium diagnostic format with balanced context.
73    Medium,
74    /// Short diagnostic format with minimal context.
75    Short,
76    /// Ariadne diagnostic format.
77    Ariadne,
78    /// GitHub Actions format.
79    Github,
80    /// GitLab Code Quality format.
81    Gitlab,
82    /// JSON format.
83    Json,
84    /// Issue count by severity.
85    Count,
86    /// Issue count by code.
87    CodeCount,
88    /// Checkstyle XML format.
89    Checkstyle,
90    /// Emacs compilation mode format.
91    Emacs,
92    /// SARIF format (Static Analysis Results Interchange Format).
93    Sarif,
94}
95
96/// Dispatch to the appropriate formatter based on the format type.
97///
98/// This function performs static dispatch using enum matching for optimal performance.
99pub(crate) fn dispatch_format(
100    format: ReportingFormat,
101    writer: &mut dyn Write,
102    issues: &IssueCollection,
103    database: &ReadDatabase,
104    config: &FormatterConfig,
105) -> Result<(), ReportingError> {
106    match format {
107        ReportingFormat::Rich => rich::RichFormatter.format(writer, issues, database, config),
108        ReportingFormat::Medium => medium::MediumFormatter.format(writer, issues, database, config),
109        ReportingFormat::Short => short::ShortFormatter.format(writer, issues, database, config),
110        ReportingFormat::Ariadne => ariadne::AriadneFormatter.format(writer, issues, database, config),
111        ReportingFormat::Json => json::JsonFormatter.format(writer, issues, database, config),
112        ReportingFormat::Github => github::GithubFormatter.format(writer, issues, database, config),
113        ReportingFormat::Gitlab => gitlab::GitlabFormatter.format(writer, issues, database, config),
114        ReportingFormat::Checkstyle => checkstyle::CheckstyleFormatter.format(writer, issues, database, config),
115        ReportingFormat::Emacs => emacs::EmacsFormatter.format(writer, issues, database, config),
116        ReportingFormat::Count => count::CountFormatter.format(writer, issues, database, config),
117        ReportingFormat::CodeCount => code_count::CodeCountFormatter.format(writer, issues, database, config),
118        ReportingFormat::Sarif => sarif::SarifFormatter.format(writer, issues, database, config),
119    }
120}