1use super::{MinifyError, MinifyOutput};
5use serde_json::Value;
6
7pub fn minify_json(source: &str) -> Result<MinifyOutput, MinifyError> {
11 let v: Value = serde_json::from_str(source).map_err(|e| MinifyError::new(e.to_string()))?;
12 let s = serde_json::to_string(&v).map_err(|e| MinifyError::new(e.to_string()))?;
13 Ok(MinifyOutput::body(s))
14}
15
16pub fn minify_jsonl(source: &str) -> Result<MinifyOutput, MinifyError> {
21 let mut out = String::with_capacity(source.len());
22 let mut first = true;
23 for (i, line) in source.lines().enumerate() {
24 if line.trim().is_empty() {
25 continue;
26 }
27 let v: Value = serde_json::from_str(line)
28 .map_err(|e| MinifyError::new(format!("line {}: {}", i + 1, e)))?;
29 let s = serde_json::to_string(&v).map_err(|e| MinifyError::new(e.to_string()))?;
30 if !first {
31 out.push('\n');
32 }
33 out.push_str(&s);
34 first = false;
35 }
36 Ok(MinifyOutput::body(out))
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
44 fn json_strips_whitespace() {
45 let out = minify_json(
46 r#"{
47 "a": 1,
48 "b": [1, 2, 3]
49 }"#,
50 )
51 .unwrap();
52 assert_eq!(out.body, r#"{"a":1,"b":[1,2,3]}"#);
53 }
54
55 #[test]
56 fn json_preserves_field_order() {
57 let out = minify_json(r#"{"z":1,"a":2,"m":3}"#).unwrap();
58 assert_eq!(out.body, r#"{"z":1,"a":2,"m":3}"#);
59 }
60
61 #[test]
62 fn json_unicode_string() {
63 let out = minify_json(r#"{ "lang": "日本語" }"#).unwrap();
64 assert_eq!(out.body, r#"{"lang":"日本語"}"#);
65 }
66
67 #[test]
68 fn json_preserves_unicode_escape() {
69 let out = minify_json(r#"{"x":"é"}"#).unwrap();
72 let parsed: Value = serde_json::from_str(&out.body).unwrap();
73 assert_eq!(parsed["x"], serde_json::json!("é"));
74 }
75
76 #[test]
77 fn json_empty_object_and_array() {
78 assert_eq!(minify_json("{}").unwrap().body, "{}");
79 assert_eq!(minify_json("[]").unwrap().body, "[]");
80 }
81
82 #[test]
83 fn json_deeply_nested() {
84 let mut s = String::new();
85 for _ in 0..50 {
86 s.push('[');
87 }
88 s.push('1');
89 for _ in 0..50 {
90 s.push(']');
91 }
92 let out = minify_json(&s).unwrap();
93 assert_eq!(out.body, s);
94 }
95
96 #[test]
97 fn json_large_integer() {
98 let out = minify_json("9223372036854775807").unwrap();
101 assert_eq!(out.body, "9223372036854775807");
102 }
103
104 #[test]
105 fn json_invalid_returns_error() {
106 let r = minify_json("{ not valid json }");
107 assert!(r.is_err());
108 }
109
110 #[test]
111 fn jsonl_one_per_line() {
112 let src = "{\"a\":1}\n{\"b\":2}\n{\"c\":3}\n";
113 let out = minify_jsonl(src).unwrap();
114 assert_eq!(out.body, "{\"a\":1}\n{\"b\":2}\n{\"c\":3}");
115 }
116
117 #[test]
118 fn jsonl_drops_blank_lines() {
119 let src = "{\"a\":1}\n\n \n{\"b\":2}\n";
120 let out = minify_jsonl(src).unwrap();
121 assert_eq!(out.body, "{\"a\":1}\n{\"b\":2}");
122 }
123
124 #[test]
125 fn jsonl_invalid_line_fails() {
126 let src = "{\"a\":1}\nnot json\n{\"b\":2}\n";
127 let r = minify_jsonl(src);
128 assert!(r.is_err());
129 assert!(r.unwrap_err().message.contains("line 2"));
131 }
132}