1use crate::value::Value;
7use crate::value::error::Error;
8use crate::value::keys::Keys;
9use crate::value::list::List;
10use crate::value::map::Map;
11use crate::value::span::Span;
12use crate::value::tracer::Segment;
13use crate::value::tracer::Tracer;
14use saphyr::AnnotatedMapping;
15use saphyr::AnnotatedSequence;
16use saphyr::LoadableYamlNode;
17use saphyr::MarkedYaml;
18use saphyr::Scalar;
19use saphyr::YamlData;
20
21pub(crate) fn usize(value: &[u8]) -> Result<usize, Error> {
22 str(value)?
23 .parse::<usize>()
24 .map_err(|e| Error::Parse(e.to_string()))
25}
26
27pub(crate) fn str(value: &[u8]) -> Result<&str, Error> {
28 core::str::from_utf8(value)
29 .map_err(|_| Error::Parse(String::from_utf8_lossy(value).into_owned()))
30}
31
32pub fn json_map(data: &[u8]) -> Result<Map, Error> {
33 let data = parse_bytes(data)?;
34
35 let Ok(json) = serde_json::from_str(data) else {
36 return Err(Error::Parse(display_bytes(data)));
37 };
38
39 match json {
40 serde_json::Value::Object(v) => Ok(json_object(v)),
41 _ => Err(Error::Parse(display_bytes(data))),
42 }
43}
44
45fn json_value(json: serde_json::Value) -> Value {
46 match json {
47 serde_json::Value::Null => Value::default(),
48 serde_json::Value::Bool(v) => v.into(),
49 serde_json::Value::Number(v) => v.to_string().into(),
50 serde_json::Value::String(v) => v.into(),
51 serde_json::Value::Array(v) => json_array(v).into(),
52 serde_json::Value::Object(v) => json_object(v).into(),
53 }
54}
55
56fn json_object(json: serde_json::Map<String, serde_json::Value>) -> Map {
57 json.into_iter().map(|(k, v)| (k, json_value(v))).collect()
58}
59
60fn json_array(json: Vec<serde_json::Value>) -> List {
61 json.into_iter().map(json_value).collect()
62}
63
64pub fn yaml_map(source: String, span: Span, segment: Segment, data: &[u8]) -> Result<Map, Error> {
65 let data = parse_bytes(data)?;
66 let keys = Keys::default();
67
68 if data.trim().is_empty() {
69 return Ok(Map::default());
70 }
71
72 let yaml = MarkedYaml::load_from_str(data)?;
73
74 if yaml.len() != 1 {
75 return Err(Error::Parse(display_bytes(data)));
76 }
77
78 let Some(yaml) = yaml.into_iter().next() else {
79 return Err(Error::Parse(display_bytes(data)));
80 };
81
82 let Ok(Value::Map(mut map)) = yaml_value(&source, span, segment, data, &keys, yaml) else {
83 return Err(Error::Parse(display_bytes(data)));
84 };
85
86 map.tracer = Tracer::default()
87 .with_source(source)
88 .with_span(span)
89 .with_segment(segment);
90
91 Ok(map)
92}
93
94fn yaml_value(
95 source: &str,
96 span: Span,
97 segment: Segment,
98 data: &str,
99 keys: &Keys,
100 yaml: MarkedYaml<'_>,
101) -> Result<Value, ()> {
102 let i0 = yaml.span.start.index();
103 let i1 = yaml.span.end.index();
104
105 let yaml_span = match &yaml.data {
106 YamlData::Sequence(_) if data.chars().nth(i0) == Some('[') => {
107 span.zoom(Span::new(i0.saturating_add(1), i1))
108 }
109 _ => span.zoom(Span::new(i0, i1)),
110 };
111
112 let value = match yaml.data {
113 YamlData::Sequence(d) => yaml_sequence(source, span, segment, data, keys, d)?,
114 YamlData::Mapping(d) => yaml_mapping(source, span, segment, data, keys, d)?,
115 YamlData::Value(Scalar::Null) => Value::default(),
116 YamlData::Value(Scalar::Boolean(d)) => d.into(),
117 YamlData::Value(Scalar::FloatingPoint(d)) => Value::from(d.to_string()),
118 YamlData::Value(Scalar::Integer(d)) => Value::from(d.to_string()),
119 YamlData::Value(Scalar::String(d)) => Value::from(d.into_owned()),
120 YamlData::Representation(..) => return Err(()),
121 YamlData::Tagged(..) => return Err(()),
122 YamlData::Alias(_) => return Err(()),
123 YamlData::BadValue => return Err(()),
124 };
125
126 let tracer = Tracer::default()
127 .with_source(source.to_string())
128 .with_span(yaml_span)
129 .with_segment(segment)
130 .with_keys(keys.clone());
131
132 Ok(value.with_tracer(tracer))
133}
134
135fn yaml_sequence(
136 source: &str,
137 span: Span,
138 segment: Segment,
139 data: &str,
140 keys: &Keys,
141 yaml: AnnotatedSequence<MarkedYaml<'_>>,
142) -> Result<Value, ()> {
143 Ok(Value::List(
144 yaml.into_iter()
145 .enumerate()
146 .map(|(i, v)| yaml_value(source, span, segment, data, &keys.clone().fold(i), v))
147 .collect::<Result<List, _>>()?,
148 ))
149}
150
151fn yaml_mapping(
152 source: &str,
153 span: Span,
154 segment: Segment,
155 data: &str,
156 keys: &Keys,
157 yaml: AnnotatedMapping<'_, MarkedYaml<'_>>,
158) -> Result<Value, ()> {
159 Ok(Value::Map(
160 yaml.into_iter()
161 .map(|(k, v)| yaml_entry(source, span, segment, data, keys, k, v))
162 .collect::<Result<Map, _>>()?,
163 ))
164}
165
166fn yaml_entry(
167 source: &str,
168 span: Span,
169 segment: Segment,
170 data: &str,
171 keys: &Keys,
172 k: MarkedYaml<'_>,
173 v: MarkedYaml<'_>,
174) -> Result<(String, Value), ()> {
175 yaml_value(source, span, segment, data, keys, k)
176 .and_then(|k| String::from_utf8(k.join()).map_err(|_| ()))
177 .map(|k| (k.clone(), keys.clone().fold(k)))
178 .and_then(|(k, keys)| yaml_value(source, span, segment, data, &keys, v).map(|v| (k, v)))
179}
180
181#[cfg(test)]
182mod test {
183 use crate::value::Value;
184 use crate::value::equivalent::Equivalent;
185 use crate::value::keys::Keys;
186 use crate::value::list::List;
187 use crate::value::map::Map;
188 use crate::value::parse::json_map;
189 use crate::value::parse::yaml_map;
190 use crate::value::span::Span;
191 use crate::value::tracer::Segment;
192 use crate::value::tracer::Tracer;
193
194 #[test]
195 fn test_json_map() {
196 let parsed = json_map(br#"{ "a": [1,2,"b"] }"#).unwrap();
197 let list = List::default().with("1").with("2").with("b");
198 let map = Map::default().with("a", list);
199
200 assert!(parsed.equivalent(&map), "{parsed}");
201 }
202
203 #[test]
204 fn test_yaml_map() {
205 let value = Value::from(String::from("value")).with_tracer(
206 Tracer::default()
207 .with_source(String::from("index.html"))
208 .with_span(Span::new(1016, 1021))
209 .with_keys(Keys::parse(b"outer.inner")),
210 );
211
212 let inner = Value::Map(Map::default().with("inner", value)).with_tracer(
213 Tracer::default()
214 .with_source(String::from("index.html"))
215 .with_span(Span::new(1000, 1023))
216 .with_keys(Keys::parse(b"outer")),
217 );
218
219 let outer = Value::Map(Map::default().with("outer", inner)).with_tracer(
220 Tracer::default()
221 .with_source("index.html".to_string())
222 .with_span(Span::new(1000, 1023)),
223 );
224
225 let parsed = yaml_map(
226 String::from("index.html"),
227 Span::new(1000, 1023),
228 Segment::Field,
229 b"outer: { inner: value }",
230 );
231
232 assert!(parsed.unwrap().equivalent(&outer.try_into().unwrap()));
233 }
234}
235
236fn parse_bytes(data: &[u8]) -> Result<&str, Error> {
237 str::from_utf8(data).map_err(|_| Error::Parse(display_bytes(data)))
238}
239
240fn display_bytes<T: AsRef<[u8]>>(t: T) -> String {
241 String::from_utf8_lossy(t.as_ref()).into_owned()
242}