yaml2json_rs/
lib.rs

1use crate::Style::{COMPACT, PRETTY};
2use core::fmt::Debug;
3use std::io;
4use thiserror::Error;
5
6#[derive(Error, Debug)]
7pub enum Yaml2JsonError {
8    #[error(transparent)]
9    SerdeYamlError(#[from] serde_yaml::Error),
10
11    #[error(transparent)]
12    SerdeJsonError(#[from] serde_json::Error),
13
14    #[error(transparent)]
15    IOError(#[from] io::Error),
16}
17
18/// `Style` defines JSON output formats for `Yaml2Json`.
19pub enum Style {
20    /// `Style::COMPACT` outputs JSON on a single line.
21    /// e.g. for the following YAML:
22    /// ```yaml
23    /// ---
24    /// hello: world
25    /// spec:
26    ///   items:
27    ///     - a
28    ///     - b
29    /// ```
30    ///
31    /// the JSON output will be:
32    /// ```json
33    /// {"hello":"world","spec":{"items":["a","b"]}}
34    /// ```
35    COMPACT,
36    /// `Style::PRETTY` outputs JSON on multiple lines, with automatic indentation.
37    /// e.g. for the following YAML:
38    /// ```yaml
39    /// ---
40    /// hello: world
41    /// spec:
42    ///   items:
43    ///     - a
44    ///     - b
45    /// ```
46    ///
47    /// the JSON output will be:
48    /// ```json
49    /// {
50    ///   "hello": "world",
51    ///   "spec": {
52    ///     "items": [
53    ///       "a",
54    ///       "b"
55    ///     ]
56    ///   }
57    /// }
58    /// ```
59    PRETTY,
60}
61
62/// Yaml2Json can convert individual YAML documents into JSON. Each instance can be configured to
63/// have different styles of output.
64///
65/// The JSON output can be returned as a string:
66/// ```
67/// use yaml2json_rs::{Yaml2Json, Style};
68///
69/// let y2j = Yaml2Json::new(Style::COMPACT);
70/// let input = "hello: world";
71/// let output = y2j.document_to_string(input).unwrap();
72///
73/// assert_eq!(output, r#"{"hello":"world"}"#);
74/// ```
75///
76/// Or, the JSON output can be sent to a writer:
77/// ```
78/// use yaml2json_rs::{Yaml2Json, Style};
79/// use std::io;
80///
81/// let y2j = Yaml2Json::new(Style::COMPACT);
82/// let input = "hello: world";
83/// let mut stdout = io::stdout();
84///
85/// y2j.document_to_writer(input, &mut stdout).unwrap();
86///
87/// // {"hello":"world"}
88/// ```
89pub struct Yaml2Json {
90    style: Style,
91}
92
93impl Yaml2Json {
94    /// `new()` creates a new `Yaml2Json`. It expects you to provide an output `Style`.
95    /// ```
96    /// use yaml2json_rs::{Yaml2Json, Style};
97    ///
98    /// let y2j_pretty = Yaml2Json::new(Style::PRETTY);
99    /// let y2j_compact = Yaml2Json::new(Style::COMPACT);
100    /// ```
101    pub fn new(style: Style) -> Self {
102        Self { style }
103    }
104
105    /// `document_to_string()` takes a YAML document &str and converts it to a JSON String.
106    /// ```
107    /// use yaml2json_rs::{Yaml2Json, Style};
108    ///
109    /// let y2j = Yaml2Json::new(Style::COMPACT);
110    /// let input = "hello: world";
111    /// let output = y2j.document_to_string(input).unwrap();
112    ///
113    /// assert_eq!(output, r#"{"hello":"world"}"#);
114    /// ```
115    pub fn document_to_string(&self, document: &str) -> Result<String, Yaml2JsonError> {
116        let s: serde_json::Value = serde_yaml::from_str(document)?;
117
118        let res = match self.style {
119            COMPACT => serde_json::to_string(&s),
120            PRETTY => serde_json::to_string_pretty(&s),
121        };
122
123        match res {
124            Ok(s) => Ok(s),
125            Err(e) => Err(e.into()),
126        }
127    }
128
129    /// `document_to_writer()` takes a YAML document string, converts it to JSON and sends the output
130    /// to the provided writer.
131    ///
132    /// ```
133    /// use yaml2json_rs::{Yaml2Json, Style};
134    /// use std::io;
135    ///
136    /// let y2j = Yaml2Json::new(Style::COMPACT);
137    /// let input = "hello: world";
138    /// let mut stdout = io::stdout();
139    ///
140    /// y2j.document_to_writer(input, &mut stdout).unwrap();
141    ///
142    /// // {"hello":"world"}
143    /// ```
144    pub fn document_to_writer<W: io::Write>(
145        &self,
146        document: &str,
147        w: &mut W,
148    ) -> Result<(), Yaml2JsonError> {
149        let s: serde_json::Value = serde_yaml::from_str(document)?;
150
151        let res = match self.style {
152            PRETTY => serde_json::to_writer_pretty(w, &s),
153            COMPACT => serde_json::to_writer(w, &s),
154        };
155
156        match res {
157            Ok(_) => Ok(()),
158            Err(e) => Err(e.into()),
159        }
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use crate::{Style, Yaml2Json};
166    use std::io::Cursor;
167
168    #[test]
169    fn document_to_string_compact() {
170        let yaml2json = Yaml2Json::new(Style::COMPACT);
171        let input = r#"
172---
173abc: def
174"#;
175        let expected = r#"{"abc":"def"}"#;
176        let res = yaml2json.document_to_string(input).unwrap();
177        assert_eq!(expected, res);
178    }
179
180    #[test]
181    fn document_to_string_pretty() {
182        let yaml2json = Yaml2Json::new(Style::PRETTY);
183        let input = r#"
184---
185abc: def
186"#;
187        let expected = r#"{
188  "abc": "def"
189}"#;
190        let res = yaml2json.document_to_string(input).unwrap();
191        assert_eq!(expected, res);
192    }
193
194    #[test]
195    fn document_to_writer_compact() {
196        let yaml2json = Yaml2Json::new(Style::COMPACT);
197        let input = r#"
198---
199abc: def
200"#;
201        let expected = r#"{"abc":"def"}"#;
202
203        let mut buf = Cursor::new(Vec::<u8>::new());
204        yaml2json.document_to_writer(input, buf.get_mut()).unwrap();
205
206        let res = String::from_utf8(buf.into_inner()).unwrap();
207        assert_eq!(expected, res);
208    }
209
210    #[test]
211    fn document_to_writer_pretty() {
212        let yaml2json = Yaml2Json::new(Style::PRETTY);
213        let input = r#"
214---
215abc: def
216"#;
217        let expected = r#"{
218  "abc": "def"
219}"#;
220
221        let mut buf = Cursor::new(Vec::<u8>::new());
222        yaml2json.document_to_writer(input, buf.get_mut()).unwrap();
223
224        let res = String::from_utf8(buf.into_inner()).unwrap();
225        assert_eq!(expected, res);
226    }
227}