Skip to main content

braze_sync/format/
mod.rs

1//! Output formatters for diff results.
2//!
3//! Two formatters are exposed:
4//!
5//! - [`TableFormatter`] — human-readable, multi-resource indented layout.
6//!   v0.1.0 ships without ANSI colors; the global `--no-color` flag is
7//!   therefore a no-op until a future cosmetic pass adds color.
8//! - [`JsonFormatter`] — frozen v1 schema for CI consumption. The wire
9//!   shape carries an explicit `version: 1` field so consumers can branch
10//!   on a future schema bump.
11//!
12//! The wire types in [`json`] are deliberately separate from the domain
13//! types in [`crate::resource`] / [`crate::diff`]. Refactoring a domain
14//! type cannot accidentally change the public JSON contract.
15
16pub mod json;
17pub mod table;
18
19use crate::diff::DiffSummary;
20use clap::ValueEnum;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum, Default)]
23#[value(rename_all = "snake_case")]
24pub enum OutputFormat {
25    #[default]
26    Table,
27    Json,
28}
29
30/// Format a [`DiffSummary`] for display. Implementations are stateless
31/// unit structs.
32pub trait DiffFormatter {
33    fn format(&self, summary: &DiffSummary) -> String;
34}
35
36#[derive(Debug, Default, Clone, Copy)]
37pub struct TableFormatter;
38
39#[derive(Debug, Default, Clone, Copy)]
40pub struct JsonFormatter;
41
42impl DiffFormatter for TableFormatter {
43    fn format(&self, summary: &DiffSummary) -> String {
44        table::render(summary)
45    }
46}
47
48impl DiffFormatter for JsonFormatter {
49    fn format(&self, summary: &DiffSummary) -> String {
50        json::render(summary)
51    }
52}
53
54impl OutputFormat {
55    /// Pick the formatter implementation for this format.
56    pub fn formatter(self) -> Box<dyn DiffFormatter> {
57        match self {
58            Self::Table => Box::new(TableFormatter),
59            Self::Json => Box::new(JsonFormatter),
60        }
61    }
62}
63
64#[cfg(test)]
65mod fixtures;
66
67#[cfg(test)]
68mod snapshot_tests;