jtool_grep/output/
json.rs1use super::{OutputFormatter, OutputOptions};
4use crate::types::GrepResult;
5use anyhow::Result;
6use serde_json::json;
7
8pub struct JsonFormatter {
10 options: OutputOptions,
11}
12
13impl JsonFormatter {
14 pub fn new(options: OutputOptions) -> Self {
15 Self { options }
16 }
17}
18
19impl Default for JsonFormatter {
20 fn default() -> Self {
21 Self::new(OutputOptions::default())
22 }
23}
24
25impl OutputFormatter for JsonFormatter {
26 fn format_result(&self, result: &GrepResult) -> Result<String> {
27 if self.options.count_mode {
28 let output = json!({
29 "notebook": result.notebook,
30 "count": result.matches.len(),
31 });
32 Ok(serde_json::to_string_pretty(&output)?)
33 } else {
34 let output = json!({
35 "notebook": result.notebook,
36 "matches": result.matches,
37 "total": result.matches.len(),
38 });
39 Ok(serde_json::to_string_pretty(&output)?)
40 }
41 }
42
43 fn format_results(&self, results: &[GrepResult]) -> Result<String> {
44 let total_matches: usize = results.iter().map(|r| r.matches.len()).sum();
45
46 if self.options.count_mode {
47 let counts: Vec<_> = results
48 .iter()
49 .map(|r| {
50 json!({
51 "notebook": r.notebook,
52 "count": r.matches.len(),
53 })
54 })
55 .collect();
56
57 let output = json!({
58 "counts": counts,
59 "total_notebooks": results.len(),
60 "total_matches": total_matches,
61 });
62 Ok(serde_json::to_string_pretty(&output)?)
63 } else {
64 let output = json!({
65 "results": results,
66 "total_notebooks": results.len(),
67 "total_matches": total_matches,
68 });
69 Ok(serde_json::to_string_pretty(&output)?)
70 }
71 }
72}