use super::{MinifyError, MinifyOutput};
use serde_json::Value;
pub fn minify_json(source: &str) -> Result<MinifyOutput, MinifyError> {
let v: Value = serde_json::from_str(source).map_err(|e| MinifyError::new(e.to_string()))?;
let s = serde_json::to_string(&v).map_err(|e| MinifyError::new(e.to_string()))?;
Ok(MinifyOutput::body(s))
}
pub fn minify_jsonl(source: &str) -> Result<MinifyOutput, MinifyError> {
let mut out = String::with_capacity(source.len());
let mut first = true;
for (i, line) in source.lines().enumerate() {
if line.trim().is_empty() {
continue;
}
let v: Value = serde_json::from_str(line)
.map_err(|e| MinifyError::new(format!("line {}: {}", i + 1, e)))?;
let s = serde_json::to_string(&v).map_err(|e| MinifyError::new(e.to_string()))?;
if !first {
out.push('\n');
}
out.push_str(&s);
first = false;
}
Ok(MinifyOutput::body(out))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn json_strips_whitespace() {
let out = minify_json(
r#"{
"a": 1,
"b": [1, 2, 3]
}"#,
)
.unwrap();
assert_eq!(out.body, r#"{"a":1,"b":[1,2,3]}"#);
}
#[test]
fn json_preserves_field_order() {
let out = minify_json(r#"{"z":1,"a":2,"m":3}"#).unwrap();
assert_eq!(out.body, r#"{"z":1,"a":2,"m":3}"#);
}
#[test]
fn json_unicode_string() {
let out = minify_json(r#"{ "lang": "日本語" }"#).unwrap();
assert_eq!(out.body, r#"{"lang":"日本語"}"#);
}
#[test]
fn json_preserves_unicode_escape() {
let out = minify_json(r#"{"x":"é"}"#).unwrap();
let parsed: Value = serde_json::from_str(&out.body).unwrap();
assert_eq!(parsed["x"], serde_json::json!("é"));
}
#[test]
fn json_empty_object_and_array() {
assert_eq!(minify_json("{}").unwrap().body, "{}");
assert_eq!(minify_json("[]").unwrap().body, "[]");
}
#[test]
fn json_deeply_nested() {
let mut s = String::new();
for _ in 0..50 {
s.push('[');
}
s.push('1');
for _ in 0..50 {
s.push(']');
}
let out = minify_json(&s).unwrap();
assert_eq!(out.body, s);
}
#[test]
fn json_large_integer() {
let out = minify_json("9223372036854775807").unwrap();
assert_eq!(out.body, "9223372036854775807");
}
#[test]
fn json_invalid_returns_error() {
let r = minify_json("{ not valid json }");
assert!(r.is_err());
}
#[test]
fn jsonl_one_per_line() {
let src = "{\"a\":1}\n{\"b\":2}\n{\"c\":3}\n";
let out = minify_jsonl(src).unwrap();
assert_eq!(out.body, "{\"a\":1}\n{\"b\":2}\n{\"c\":3}");
}
#[test]
fn jsonl_drops_blank_lines() {
let src = "{\"a\":1}\n\n \n{\"b\":2}\n";
let out = minify_jsonl(src).unwrap();
assert_eq!(out.body, "{\"a\":1}\n{\"b\":2}");
}
#[test]
fn jsonl_invalid_line_fails() {
let src = "{\"a\":1}\nnot json\n{\"b\":2}\n";
let r = minify_jsonl(src);
assert!(r.is_err());
assert!(r.unwrap_err().message.contains("line 2"));
}
}