jsonc_parser/
parse_to_value.rs1use super::CollectOptions;
2use super::ParseOptions;
3use super::ast;
4use super::errors::ParseError;
5use super::parse_to_ast;
6use super::value::*;
7use crate::value::Map;
8
9pub fn parse_to_value<'a>(text: &'a str, options: &ParseOptions) -> Result<Option<JsonValue<'a>>, ParseError> {
21 let value = parse_to_ast(
22 text,
23 &CollectOptions {
24 comments: crate::CommentCollectionStrategy::Off,
25 tokens: false,
26 },
27 options,
28 )?
29 .value;
30 Ok(value.map(handle_value))
31}
32
33fn handle_value(value: ast::Value) -> JsonValue {
34 match value {
35 ast::Value::StringLit(lit) => JsonValue::String(lit.value),
36 ast::Value::NumberLit(lit) => JsonValue::Number(lit.value),
37 ast::Value::BooleanLit(lit) => JsonValue::Boolean(lit.value),
38 ast::Value::Object(obj) => JsonValue::Object(handle_object(obj)),
39 ast::Value::Array(arr) => JsonValue::Array(handle_array(arr)),
40 ast::Value::NullKeyword(_) => JsonValue::Null,
41 }
42}
43
44fn handle_array(arr: ast::Array) -> JsonArray {
45 let elements = arr.elements.into_iter().map(handle_value).collect();
46
47 JsonArray::new(elements)
48}
49
50fn handle_object(obj: ast::Object) -> JsonObject {
51 let mut props = Map::with_capacity(obj.properties.len());
52 for prop in obj.properties.into_iter() {
53 let prop_name = prop.name.into_string();
54 let prop_value = handle_value(prop.value);
55 props.insert(prop_name, prop_value);
56 }
57 JsonObject::new(props)
58}
59
60#[cfg(test)]
61mod tests {
62 use crate::errors::ParseErrorKind;
63
64 use super::*;
65 use std::borrow::Cow;
66
67 #[test]
68 fn it_should_parse_object() {
69 let value = parse_to_value(
70 r#"{
71 "a": null,
72 "b": [null, "text"],
73 "c": true,
74 d: 25.55
75}"#,
76 &Default::default(),
77 )
78 .unwrap()
79 .unwrap();
80
81 let mut object_map = Map::new();
82 object_map.insert(String::from("a"), JsonValue::Null);
83 object_map.insert(
84 String::from("b"),
85 JsonValue::Array(vec![JsonValue::Null, JsonValue::String(Cow::Borrowed("text"))].into()),
86 );
87 object_map.insert(String::from("c"), JsonValue::Boolean(true));
88 object_map.insert(String::from("d"), JsonValue::Number("25.55"));
89 assert_eq!(value, JsonValue::Object(object_map.into()));
90 }
91
92 #[test]
93 fn it_should_parse_boolean_false() {
94 let value = parse_to_value("false", &Default::default()).unwrap().unwrap();
95 assert_eq!(value, JsonValue::Boolean(false));
96 let value = parse_to_value("true", &Default::default()).unwrap().unwrap();
97 assert_eq!(value, JsonValue::Boolean(true));
98 }
99
100 #[test]
101 fn it_should_parse_boolean_true() {
102 let value = parse_to_value("true", &Default::default()).unwrap().unwrap();
103 assert_eq!(value, JsonValue::Boolean(true));
104 }
105
106 #[test]
107 fn it_should_parse_number() {
108 let value = parse_to_value("50", &Default::default()).unwrap().unwrap();
109 assert_eq!(value, JsonValue::Number("50"));
110 }
111
112 #[test]
113 fn it_should_parse_string() {
114 let value = parse_to_value(r#""test""#, &Default::default()).unwrap().unwrap();
115 assert_eq!(value, JsonValue::String(Cow::Borrowed("test")));
116 }
117
118 #[test]
119 fn it_should_parse_string_with_quotes() {
120 let value = parse_to_value(r#""echo \"test\"""#, &Default::default())
121 .unwrap()
122 .unwrap();
123 assert_eq!(value, JsonValue::String(Cow::Borrowed(r#"echo "test""#)));
124 }
125
126 #[test]
127 fn it_should_parse_array() {
128 let value = parse_to_value(r#"[false, true]"#, &Default::default())
129 .unwrap()
130 .unwrap();
131 assert_eq!(
132 value,
133 JsonValue::Array(vec![JsonValue::Boolean(false), JsonValue::Boolean(true)].into())
134 );
135 }
136
137 #[test]
138 fn it_should_parse_null() {
139 let value = parse_to_value("null", &Default::default()).unwrap().unwrap();
140 assert_eq!(value, JsonValue::Null);
141 }
142
143 #[test]
144 fn it_should_parse_empty() {
145 let value = parse_to_value("", &Default::default()).unwrap();
146 assert!(value.is_none());
147 }
148
149 #[test]
150 fn error_unexpected_token() {
151 let err = parse_to_value("{\n \"a\":\u{200b}5 }", &Default::default())
152 .err()
153 .unwrap();
154 assert_eq!(err.range().start, 8);
155 assert_eq!(err.range().end, 11);
156 assert_eq!(err.kind().clone(), ParseErrorKind::UnexpectedToken);
157 }
158
159 #[test]
160 fn it_should_parse_surrogate_pair() {
161 let src = r#""\uD834\uDD1E""#;
163 let v = parse_to_value(src, &Default::default()).unwrap().unwrap();
164 if let JsonValue::String(s) = v {
165 assert_eq!("\u{1D11E}", s.as_ref());
166 } else {
167 panic!("Expected string value, got {:?}", v);
168 }
169 }
170
171 #[test]
172 fn it_should_parse_multiple_surrogate_pairs() {
173 let src = r#""\uD834\uDD1E\uD834\uDD1E""#;
174 let v = parse_to_value(src, &Default::default()).unwrap().unwrap();
175 if let JsonValue::String(s) = v {
176 assert_eq!("\u{1D11E}\u{1D11E}", s.as_ref());
177 } else {
178 panic!("Expected string value, got {:?}", v);
179 }
180 }
181
182 #[test]
183 fn it_should_parse_mixed_escapes_with_surrogate_pairs() {
184 let src = r#""\u0041\uD834\uDD1E\u0042""#;
186 let v = parse_to_value(src, &Default::default()).unwrap().unwrap();
187 if let JsonValue::String(s) = v {
188 assert_eq!("A\u{1D11E}B", s.as_ref());
189 } else {
190 panic!("Expected string value, got {:?}", v);
191 }
192 }
193
194 #[test]
195 fn it_should_error_on_unpaired_high_surrogate_with_text() {
196 let src = r#""\uD834x""#;
197 let err = parse_to_value(src, &Default::default()).err().unwrap();
198 assert!(err.to_string().contains("unpaired high surrogate"));
199 }
200
201 #[test]
202 fn it_should_error_on_unpaired_high_surrogate_at_eof() {
203 let src = r#""\uD834""#;
204 let err = parse_to_value(src, &Default::default()).err().unwrap();
205 assert!(err.to_string().contains("unpaired high surrogate"));
206 }
207
208 #[test]
209 fn it_should_error_on_high_surrogate_followed_by_non_low_surrogate() {
210 let src = r#""\uD834\u0041""#;
211 let err = parse_to_value(src, &Default::default()).err().unwrap();
212 assert!(err.to_string().contains("not followed by low surrogate"));
213 }
214
215 #[test]
216 fn it_should_error_on_unpaired_low_surrogate() {
217 let src = r#""\uDC00""#;
219 let err = parse_to_value(src, &Default::default()).err().unwrap();
220 assert!(err.to_string().contains("unpaired low surrogate"));
221 }
222}