Skip to main content

fallow_types/
output_format.rs

1/// Output format for fallow results.
2///
3/// This is command-line and integration metadata, not stored in config files.
4/// Keeping it in `fallow-types` lets config, output, CLI, MCP, and API layers
5/// agree on the same contract without creating a config-to-output dependency.
6#[derive(Debug, Default, Clone, Copy)]
7pub enum OutputFormat {
8    /// Human-readable terminal output with source context.
9    #[default]
10    Human,
11    /// Machine-readable JSON.
12    Json,
13    /// SARIF format for GitHub Code Scanning.
14    Sarif,
15    /// One issue per line (grep-friendly).
16    Compact,
17    /// Markdown for PR comments.
18    Markdown,
19    /// `CodeClimate` JSON for GitLab Code Quality.
20    ///
21    /// CLI aliases: `codeclimate`, `gitlab-codequality`, `gitlab-code-quality`.
22    CodeClimate,
23    /// GitHub-flavored sticky PR comment markdown.
24    PrCommentGithub,
25    /// GitLab-flavored sticky MR comment markdown.
26    PrCommentGitlab,
27    /// GitHub PR review JSON envelope.
28    ReviewGithub,
29    /// GitLab MR review JSON envelope.
30    ReviewGitlab,
31    /// Shields.io-compatible SVG badge (health command only).
32    Badge,
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38
39    const VARIANTS: [OutputFormat; 11] = [
40        OutputFormat::Human,
41        OutputFormat::Json,
42        OutputFormat::Sarif,
43        OutputFormat::Compact,
44        OutputFormat::Markdown,
45        OutputFormat::CodeClimate,
46        OutputFormat::PrCommentGithub,
47        OutputFormat::PrCommentGitlab,
48        OutputFormat::ReviewGithub,
49        OutputFormat::ReviewGitlab,
50        OutputFormat::Badge,
51    ];
52
53    #[test]
54    fn default_is_human() {
55        assert!(matches!(OutputFormat::default(), OutputFormat::Human));
56    }
57
58    #[test]
59    fn debug_names_remain_stable() {
60        let names: Vec<String> = VARIANTS
61            .iter()
62            .map(|variant| format!("{variant:?}"))
63            .collect();
64        assert_eq!(
65            names,
66            vec![
67                "Human",
68                "Json",
69                "Sarif",
70                "Compact",
71                "Markdown",
72                "CodeClimate",
73                "PrCommentGithub",
74                "PrCommentGitlab",
75                "ReviewGithub",
76                "ReviewGitlab",
77                "Badge",
78            ]
79        );
80    }
81
82    #[test]
83    fn variants_are_distinct() {
84        let names: Vec<String> = VARIANTS
85            .iter()
86            .map(|variant| format!("{variant:?}"))
87            .collect();
88
89        for (i, a) in names.iter().enumerate() {
90            for (j, b) in names.iter().enumerate() {
91                if i != j {
92                    assert_ne!(a, b);
93                }
94            }
95        }
96    }
97}