use json5 as json5_crate;
use serde::{Serialize, de::DeserializeOwned};
use crate::format::{FormatOptions, Formatted, wrap_whitespace};
pub fn parse_json5<T>(
text: &str,
options: Option<FormatOptions>,
) -> Result<Formatted<T>, json5_crate::Error>
where
T: DeserializeOwned,
{
let opts = options.unwrap_or_default();
let value = json5_crate::from_str(text)?;
Ok(Formatted::new(text, value, &opts))
}
pub fn stringify_json5<T>(
formatted: &Formatted<T>,
_options: Option<FormatOptions>,
) -> Result<String, json5_crate::Error>
where
T: Serialize,
{
let json5 = json5_crate::to_string(&formatted.value)?;
Ok(wrap_whitespace(&json5, &formatted.format))
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::Value as JsonValue;
const FIXTURE: &str = r#"
{
types: {
boolean: true,
integer: 1,
float: 3.14,
string: 'hello',
array: [
1,
2,
3,
],
object: {
key: 'value',
},
null: null,
date: '1979-05-27T07:32:00-08:00',
},
}
"#;
#[test]
fn parse_ok() {
#[derive(Debug, serde::Deserialize)]
struct Types {
boolean: bool,
integer: i64,
float: f64,
string: String,
array: Vec<i64>,
object: serde_json::Value,
null: Option<serde_json::Value>,
date: String,
}
#[derive(Debug, serde::Deserialize)]
struct Root {
types: Types,
}
let formatted = parse_json5::<Root>(FIXTURE, None).unwrap();
assert!(formatted.value.types.boolean);
assert_eq!(formatted.value.types.integer, 1);
assert!((formatted.value.types.float - 3.14).abs() < f64::EPSILON);
assert_eq!(formatted.value.types.string, "hello");
assert_eq!(formatted.value.types.array, vec![1, 2, 3]);
assert_eq!(formatted.value.types.object["key"].as_str(), Some("value"));
assert!(formatted.value.types.null.is_none());
assert_eq!(
formatted.value.types.date,
"1979-05-27T07:32:00-08:00".to_string()
);
}
#[test]
fn stringify_roundtrip() {
let formatted = parse_json5::<JsonValue>(FIXTURE, None).unwrap();
let out = stringify_json5(&formatted, None).unwrap();
let expected: JsonValue = ::json5::from_str(FIXTURE).unwrap();
let expected_str = ::json5::to_string(&expected).unwrap();
let expected_str = format!("\n{}", expected_str);
assert_eq!(out.trim(), expected_str.trim());
}
#[test]
fn preserves_outer_whitespace() {
let text = " \n{ types: { boolean: true } }\n\t";
let formatted = parse_json5::<JsonValue>(text, None).unwrap();
let out = stringify_json5(&formatted, None).unwrap();
assert!(out.starts_with(" \n"));
assert!(out.ends_with("\n\t"));
}
}