1use json5 as json5_crate;
2use serde::{Serialize, de::DeserializeOwned};
3
4use crate::format::{FormatOptions, Formatted, wrap_whitespace};
5
6pub fn parse_json5<T>(
8 text: &str,
9 options: Option<FormatOptions>,
10) -> Result<Formatted<T>, json5_crate::Error>
11where
12 T: DeserializeOwned,
13{
14 let opts = options.unwrap_or_default();
15 let value = json5_crate::from_str(text)?;
16 Ok(Formatted::new(text, value, &opts))
17}
18
19pub fn stringify_json5<T>(
21 formatted: &Formatted<T>,
22 _options: Option<FormatOptions>,
23) -> Result<String, json5_crate::Error>
24where
25 T: Serialize,
26{
27 let json5 = json5_crate::to_string(&formatted.value)?;
31 Ok(wrap_whitespace(&json5, &formatted.format))
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use serde_json::Value as JsonValue;
38
39 const FIXTURE: &str = r#"
41{
42 types: {
43 boolean: true,
44 integer: 1,
45 float: 3.14,
46 string: 'hello',
47 array: [
48 1,
49 2,
50 3,
51 ],
52 object: {
53 key: 'value',
54 },
55 null: null,
56 date: '1979-05-27T07:32:00-08:00',
57 },
58}
59"#;
60
61 #[test]
62 fn parse_ok() {
63 #[derive(Debug, serde::Deserialize)]
64 struct Types {
65 boolean: bool,
66 integer: i64,
67 float: f64,
68 string: String,
69 array: Vec<i64>,
70 object: serde_json::Value,
71 null: Option<serde_json::Value>,
72 date: String,
73 }
74
75 #[derive(Debug, serde::Deserialize)]
76 struct Root {
77 types: Types,
78 }
79
80 let formatted = parse_json5::<Root>(FIXTURE, None).unwrap();
81 assert!(formatted.value.types.boolean);
82 assert_eq!(formatted.value.types.integer, 1);
83 assert!((formatted.value.types.float - 3.14).abs() < f64::EPSILON);
84 assert_eq!(formatted.value.types.string, "hello");
85 assert_eq!(formatted.value.types.array, vec![1, 2, 3]);
86 assert_eq!(formatted.value.types.object["key"].as_str(), Some("value"));
87 assert!(formatted.value.types.null.is_none());
88 assert_eq!(
89 formatted.value.types.date,
90 "1979-05-27T07:32:00-08:00".to_string()
91 );
92 }
93
94 #[test]
95 fn stringify_roundtrip() {
96 let formatted = parse_json5::<JsonValue>(FIXTURE, None).unwrap();
97 let out = stringify_json5(&formatted, None).unwrap();
98 let expected: JsonValue = ::json5::from_str(FIXTURE).unwrap();
99 let expected_str = ::json5::to_string(&expected).unwrap();
100 let expected_str = format!("\n{}", expected_str);
101 assert_eq!(out.trim(), expected_str.trim());
102 }
103
104 #[test]
105 fn preserves_outer_whitespace() {
106 let text = " \n{ types: { boolean: true } }\n\t";
107 let formatted = parse_json5::<JsonValue>(text, None).unwrap();
108 let out = stringify_json5(&formatted, None).unwrap();
109
110 assert!(out.starts_with(" \n"));
111 assert!(out.ends_with("\n\t"));
112 }
113}