1use serde::{Serialize, de::DeserializeOwned};
2
3use crate::format::{FormatOptions, Formatted, wrap_whitespace};
4
5pub fn parse_yaml<T>(
7 text: &str,
8 options: Option<FormatOptions>,
9) -> Result<Formatted<T>, serde_yaml::Error>
10where
11 T: DeserializeOwned,
12{
13 let opts = FormatOptions {
14 preserve_indentation: false,
15 ..options.unwrap_or_default()
16 };
17 let value = serde_yaml::from_str(text)?;
18 Ok(Formatted::new(text, value, &opts))
19}
20
21pub fn stringify_yaml<T>(
23 formatted: &Formatted<T>,
24 _options: Option<FormatOptions>,
25) -> Result<String, serde_yaml::Error>
26where
27 T: Serialize,
28{
29 let yaml_str = serde_yaml::to_string(&formatted.value)?;
32 Ok(wrap_whitespace(&yaml_str, &formatted.format))
33}
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38 use crate::format::strip_line_comments;
39 use serde_json::Value as JsonValue;
40
41 const FIXTURE: &str = r#"
43types:
44 boolean: true
45 integer: 1
46 float: 3.14
47 string: hello
48 array:
49 - 1
50 - 2
51 - 3
52 object:
53 key: value
54 'null': null
55 date: 1979-05-27T15:32:00.000Z
56"#;
57
58 #[test]
59 fn parse_ok() {
60 let formatted = parse_yaml::<serde_yaml::Value>(FIXTURE, None).unwrap();
61 let root = formatted.value;
62
63 let types = root
64 .get("types")
65 .expect("types key should exist")
66 .as_mapping()
67 .expect("types should be a mapping");
68
69 assert_eq!(
70 types.get(&serde_yaml::Value::String("boolean".into())),
71 Some(&serde_yaml::Value::Bool(true))
72 );
73 assert_eq!(
74 types.get(&serde_yaml::Value::String("integer".into())),
75 Some(&serde_yaml::Value::Number(1.into()))
76 );
77 assert_eq!(
78 types.get(&serde_yaml::Value::String("float".into())),
79 Some(&serde_yaml::Value::Number(serde_yaml::Number::from(3.14)))
80 );
81 assert_eq!(
82 types.get(&serde_yaml::Value::String("string".into())),
83 Some(&serde_yaml::Value::String("hello".into()))
84 );
85 assert_eq!(
86 types.get(&serde_yaml::Value::String("array".into())),
87 Some(&serde_yaml::Value::Sequence(vec![
88 serde_yaml::Value::Number(1.into()),
89 serde_yaml::Value::Number(2.into()),
90 serde_yaml::Value::Number(3.into()),
91 ]))
92 );
93 assert_eq!(
95 types.get(&serde_yaml::Value::String("null".into())),
96 Some(&serde_yaml::Value::Null)
97 );
98 assert_eq!(
99 types.get(&serde_yaml::Value::String("date".into())),
100 Some(&serde_yaml::Value::String(
101 "1979-05-27T15:32:00.000Z".into()
102 ))
103 );
104 }
105
106 #[test]
107 fn stringify_roundtrip() {
108 let formatted = parse_yaml::<JsonValue>(FIXTURE, None).unwrap();
109 let out = stringify_yaml(&formatted, None).unwrap();
110
111 let without_comments = strip_line_comments(FIXTURE, "#");
112 let expected_val: serde_yaml::Value = serde_yaml::from_str(&without_comments).unwrap();
113
114 let out_val: serde_yaml::Value = serde_yaml::from_str(&out).unwrap();
115 assert_eq!(out_val, expected_val);
116 }
117
118 #[test]
119 fn preserves_outer_whitespace() {
120 let text = " \ntypes:\n key: value\n\n";
121 let formatted = parse_yaml::<JsonValue>(text, None).unwrap();
122 let out = stringify_yaml(&formatted, None).unwrap();
123
124 assert!(out.starts_with(" \n"));
125 assert!(out.ends_with("\n\n"));
126 }
127}