lean_ctx/core/extractors/
json.rs1use serde_json::Value;
9
10#[must_use]
13pub fn to_text(input: &str) -> String {
14 match serde_json::from_str::<Value>(input) {
15 Ok(v) => serde_json::to_string_pretty(&v).unwrap_or_else(|_| input.trim().to_string()),
16 Err(_) => input.trim().to_string(),
17 }
18}
19
20#[must_use]
24pub fn chunks(input: &str) -> Vec<String> {
25 let out = match serde_json::from_str::<Value>(input) {
26 Ok(Value::Array(items)) if !items.is_empty() => items
27 .iter()
28 .map(|v| serde_json::to_string_pretty(v).unwrap_or_else(|_| v.to_string()))
29 .collect(),
30 Ok(Value::Object(map)) if !map.is_empty() => map
31 .iter()
32 .map(|(k, v)| {
33 let val = serde_json::to_string_pretty(v).unwrap_or_else(|_| v.to_string());
34 format!("{}: {}", serde_json::to_string(k).unwrap_or_default(), val)
35 })
36 .collect(),
37 Ok(other) => {
38 vec![serde_json::to_string_pretty(&other).unwrap_or_else(|_| other.to_string())]
39 }
40 Err(_) => vec![input.trim().to_string()],
41 };
42 out.into_iter().filter(|c| !c.trim().is_empty()).collect()
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn array_chunks_per_element() {
51 let c = chunks(r#"[{"a":1},{"b":2}]"#);
52 assert_eq!(c.len(), 2);
53 assert!(c[0].contains("\"a\""));
54 assert!(c[1].contains("\"b\""));
55 }
56
57 #[test]
58 fn object_chunks_per_entry() {
59 let c = chunks(r#"{"name":"x","age":3}"#);
60 assert_eq!(c.len(), 2);
61 assert!(c.iter().any(|s| s.contains("\"name\"")));
62 }
63
64 #[test]
65 fn invalid_json_is_single_chunk() {
66 let c = chunks("not json at all");
67 assert_eq!(c, vec!["not json at all".to_string()]);
68 }
69
70 #[test]
71 fn to_text_normalizes() {
72 let t = to_text(r#"{"b":2,"a":1}"#);
73 assert!(t.contains("\"a\": 1"));
74 }
75}