Skip to main content

c12_parser/
json.rs

1use serde::{Serialize, de::DeserializeOwned};
2
3use crate::format::{FormatOptions, Formatted, compute_indent};
4
5/// Parses a JSON string into a value, capturing its formatting.
6pub fn parse_json<T>(text: &str, options: Option<FormatOptions>) -> serde_json::Result<Formatted<T>>
7where
8    T: DeserializeOwned,
9{
10    let opts = options.unwrap_or_default();
11    let value = serde_json::from_str(text)?;
12    Ok(Formatted::new(text, value, &opts))
13}
14
15/// Stringifies a JSON value with preserved or configured formatting.
16pub fn stringify_json<T>(
17    formatted: &Formatted<T>,
18    options: Option<FormatOptions>,
19) -> serde_json::Result<String>
20where
21    T: Serialize,
22{
23    let opts = options.unwrap_or_default();
24    let indent = compute_indent(&formatted.format, &opts);
25    let json = serde_json::to_string_pretty(&formatted.value)?;
26    let indent_str = " ".repeat(indent);
27
28    let indented = json
29        .lines()
30        .map(|line| {
31            if line.is_empty() {
32                line.to_string()
33            } else {
34                let trimmed = line.trim_start();
35                let mut s = String::with_capacity(indent_str.len() + trimmed.len());
36                s.push_str(&indent_str);
37                s.push_str(trimmed);
38                s
39            }
40        })
41        .collect::<Vec<_>>()
42        .join("\n");
43    Ok(format!(
44        "{}{}{}",
45        formatted.format.whitespace_start, indented, formatted.format.whitespace_end
46    ))
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52    use crate::format::{FormatInfo, Formatted};
53    use serde_json::Value as JsonValue;
54
55    const JSON_FIXTURE: &str = r#"
56{
57  "types": {
58    "boolean": true,
59    "integer": 1,
60    "float": 3.14,
61    "string": "hello",
62    "array": [
63      1,
64      2,
65      3
66    ],
67    "object": {
68      "key": "value"
69    },
70    "null": null,
71    "date": "1979-05-27T07:32:00-08:00"
72  }
73}
74"#;
75
76    #[test]
77    fn json_parse_ok() {
78        #[derive(Debug, serde::Deserialize)]
79        struct Types {
80            boolean: bool,
81            integer: i64,
82            float: f64,
83            string: String,
84            array: Vec<i64>,
85            object: serde_json::Value,
86            null: Option<serde_json::Value>,
87            date: String,
88        }
89
90        #[derive(Debug, serde::Deserialize)]
91        struct Root {
92            types: Types,
93        }
94
95        let formatted = parse_json::<Root>(JSON_FIXTURE, None).unwrap();
96        assert!(formatted.value.types.boolean);
97        assert_eq!(formatted.value.types.integer, 1);
98        assert!((formatted.value.types.float - 3.14).abs() < f64::EPSILON);
99        assert_eq!(formatted.value.types.string, "hello");
100        assert_eq!(formatted.value.types.array, vec![1, 2, 3]);
101        assert_eq!(formatted.value.types.object["key"].as_str(), Some("value"));
102        assert!(formatted.value.types.null.is_none());
103        assert_eq!(
104            formatted.value.types.date,
105            "1979-05-27T07:32:00-08:00".to_string()
106        );
107    }
108
109    #[test]
110    fn json_stringify_exact_fixture() {
111        let formatted = parse_json::<JsonValue>(JSON_FIXTURE, None).unwrap();
112        let out = stringify_json(&formatted, None).unwrap();
113        let out_val: JsonValue = serde_json::from_str(&out).unwrap();
114        let expected_val: JsonValue = serde_json::from_str(JSON_FIXTURE).unwrap();
115        assert_eq!(out_val, expected_val);
116    }
117
118    #[test]
119    fn json_stringify_from_raw_object_matches_trimmed_fixture() {
120        let value: JsonValue = serde_json::from_str(JSON_FIXTURE).unwrap();
121        let formatted = Formatted {
122            value,
123            format: FormatInfo {
124                sample: None,
125                whitespace_start: String::new(),
126                whitespace_end: String::new(),
127            },
128        };
129        let out = stringify_json(&formatted, None).unwrap();
130        let out_val: JsonValue = serde_json::from_str(&out).unwrap();
131        let expected_val: JsonValue = serde_json::from_str(JSON_FIXTURE).unwrap();
132        assert_eq!(out_val, expected_val);
133    }
134
135    #[test]
136    fn json_stringify_respects_explicit_indent() {
137        let formatted = parse_json::<JsonValue>(JSON_FIXTURE, None).unwrap();
138        let mut opts = FormatOptions::default();
139        opts.indent = Some(4);
140
141        let out = stringify_json(&formatted, Some(opts)).unwrap();
142
143        // 第一行是空行(前导换行),第二行应为带 4 个空格缩进的 "{".
144        let mut lines = out.lines();
145        assert_eq!(lines.next(), Some(""));
146        if let Some(second) = lines.next() {
147            let prefix = &second[..4.min(second.len())];
148            assert_eq!(prefix, "    ");
149        } else {
150            panic!("expected at least two lines in JSON output");
151        }
152    }
153
154    #[test]
155    fn json_preserves_outer_whitespace() {
156        let text = " \n{ \"a\": 1 }\n\t";
157        let formatted = parse_json::<JsonValue>(text, None).unwrap();
158        let out = stringify_json(&formatted, None).unwrap();
159
160        assert!(out.starts_with(" \n"));
161        assert!(out.ends_with("\n\t"));
162    }
163}