1use crate::core::Adr;
4use crate::export::{ExportResult, Exporter};
5use crate::Error;
6use serde::Serialize;
7use std::path::Path;
8
9#[derive(Debug, Default)]
11pub struct JsonExporter {
12 pub pretty: bool,
14}
15
16impl JsonExporter {
17 #[must_use]
19 pub fn new() -> Self {
20 Self { pretty: true }
21 }
22
23 #[must_use]
25 pub fn compact(mut self) -> Self {
26 self.pretty = false;
27 self
28 }
29}
30
31#[derive(Debug, Serialize)]
33struct AdrJson<'a> {
34 id: &'a str,
35 commit: &'a str,
36 title: &'a str,
37 status: String,
38 date: Option<String>,
39 tags: &'a [String],
40 authors: &'a [String],
41 deciders: &'a [String],
42 body: &'a str,
43}
44
45impl<'a> AdrJson<'a> {
46 fn from_adr(adr: &'a Adr) -> Self {
47 Self {
48 id: &adr.id,
49 commit: &adr.commit,
50 title: &adr.frontmatter.title,
51 status: adr.frontmatter.status.to_string(),
52 date: adr
53 .frontmatter
54 .date
55 .as_ref()
56 .map(|d| d.datetime().to_rfc3339()),
57 tags: &adr.frontmatter.tags,
58 authors: &adr.frontmatter.authors,
59 deciders: &adr.frontmatter.deciders,
60 body: &adr.body,
61 }
62 }
63}
64
65impl Exporter for JsonExporter {
66 fn export(&self, adr: &Adr, path: &Path) -> Result<(), Error> {
67 let json_adr = AdrJson::from_adr(adr);
68
69 let content = if self.pretty {
70 serde_json::to_string_pretty(&json_adr)
71 } else {
72 serde_json::to_string(&json_adr)
73 }
74 .map_err(|e| Error::ExportError {
75 message: format!("Failed to serialize ADR: {e}"),
76 })?;
77
78 std::fs::write(path, content).map_err(|e| Error::IoError {
79 message: format!("Failed to write {}: {e}", path.display()),
80 })
81 }
82
83 fn export_all(&self, adrs: &[Adr], dir: &Path) -> Result<ExportResult, Error> {
84 std::fs::create_dir_all(dir).map_err(|e| Error::IoError {
85 message: format!("Failed to create directory {}: {e}", dir.display()),
86 })?;
87
88 let mut result = ExportResult::default();
89
90 for adr in adrs {
92 let path = dir.join(format!("{}.json", adr.id));
93 match self.export(adr, &path) {
94 Ok(()) => {
95 result.exported += 1;
96 result.files.push(path.display().to_string());
97 },
98 Err(e) => {
99 result.errors.push(format!("{}: {e}", adr.id));
100 },
101 }
102 }
103
104 let all_path = dir.join("all.json");
106 let all_json: Vec<AdrJson> = adrs.iter().map(AdrJson::from_adr).collect();
107
108 let content = if self.pretty {
109 serde_json::to_string_pretty(&all_json)
110 } else {
111 serde_json::to_string(&all_json)
112 }
113 .map_err(|e| Error::ExportError {
114 message: format!("Failed to serialize ADRs: {e}"),
115 })?;
116
117 std::fs::write(&all_path, content).map_err(|e| Error::IoError {
118 message: format!("Failed to write {}: {e}", all_path.display()),
119 })?;
120
121 result.files.push(all_path.display().to_string());
122
123 Ok(result)
124 }
125}