1#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
2
3mod config;
4mod error;
5
6pub use config::Config;
7pub use error::{EureToJsonError, JsonToEureError};
8use eure::document::OriginMap;
9use eure::document::node::NodeValue;
10use eure::document::{EureDocument, NodeId};
11use eure::query::{ParseDocument, TextFile, ValidCst};
12use eure::report::{ErrorReport, ErrorReports, Origin, OriginHints};
13use eure::tree::{Cst, InputSpan};
14use eure::value::{ObjectKey, PrimitiveValue};
15use eure_document::text::Text;
16use eure_schema::interop::VariantRepr;
17use num_bigint::BigInt;
18use query_flow::{Db, QueryError, query};
19use serde_json::Value as JsonValue;
20
21#[query]
22pub fn eure_to_json(
23 db: &impl Db,
24 text_file: TextFile,
25 config: Config,
26) -> Result<JsonValue, QueryError> {
27 let parsed = db.query(ParseDocument::new(text_file.clone()))?;
28 Ok(document_to_value(&parsed.doc, &config)?)
29}
30
31#[query]
36pub fn eure_to_json_formatted(
37 db: &impl Db,
38 text_file: TextFile,
39 config: Config,
40) -> Result<JsonValue, QueryError> {
41 let parsed = db.query(ParseDocument::new(text_file.clone()))?;
42
43 match document_to_value(&parsed.doc, &config) {
44 Ok(json) => Ok(json),
45 Err(e) => {
46 let cst = db.query(ValidCst::new(text_file.clone()))?;
48
49 let report = create_json_error_report(&e, text_file, &parsed.origins, &cst);
51 Err(ErrorReports::from(vec![report]))?
52 }
53 }
54}
55
56fn create_json_error_report(
58 error: &EureToJsonError,
59 file: TextFile,
60 origins: &OriginMap,
61 cst: &Cst,
62) -> ErrorReport {
63 let node_id = error.node_id();
64
65 let (span, is_fallback) = match origins.get_value_span(node_id, cst) {
67 Some(span) => (span, false),
68 None => (InputSpan::EMPTY, true),
69 };
70
71 let mut origin = Origin::with_hints(file, span, OriginHints::default().with_doc(node_id));
72 if is_fallback {
73 origin = origin.as_fallback();
74 }
75
76 ErrorReport::error(error.to_string(), origin)
80}
81
82#[query]
86pub fn json_to_eure(
87 db: &impl Db,
88 json_file: TextFile,
89 config: Config,
90) -> Result<EureDocument, QueryError> {
91 let content = db.asset(json_file.clone())?;
92 let json: JsonValue = serde_json::from_str(content.get())?;
93 Ok(value_to_document(&json, &config)?)
94}
95
96pub fn document_to_value(
97 doc: &EureDocument,
98 config: &Config,
99) -> Result<JsonValue, EureToJsonError> {
100 let root_id = doc.get_root_id();
101 convert_node(doc, root_id, config)
102}
103
104fn convert_node(
105 doc: &EureDocument,
106 node_id: NodeId,
107 config: &Config,
108) -> Result<JsonValue, EureToJsonError> {
109 let node = doc.node(node_id);
110
111 let variant_ext: Option<&str> = node
113 .extensions
114 .iter()
115 .find(|(k, _)| k.as_ref() == "variant")
116 .and_then(|(_, &ext_id)| {
117 if let NodeValue::Primitive(PrimitiveValue::Text(t)) = &doc.node(ext_id).content {
118 Some(t.as_str())
119 } else {
120 None
121 }
122 });
123
124 if let Some(tag) = variant_ext {
126 return convert_variant_node(doc, node_id, tag, config);
127 }
128
129 match &node.content {
130 NodeValue::Hole(_) => Err(EureToJsonError::HoleNotSupported { node_id }),
131 NodeValue::PartialMap(_) => Err(EureToJsonError::PartialMapNotSupported { node_id }),
132 NodeValue::Primitive(prim) => convert_primitive(prim, node_id),
133 NodeValue::Array(arr) => {
134 let mut result = Vec::new();
135 for &child_id in arr.iter() {
136 result.push(convert_node(doc, child_id, config)?);
137 }
138 Ok(JsonValue::Array(result))
139 }
140 NodeValue::Tuple(tuple) => {
141 let mut result = Vec::new();
142 for &child_id in tuple.iter() {
143 result.push(convert_node(doc, child_id, config)?);
144 }
145 Ok(JsonValue::Array(result))
146 }
147 NodeValue::Map(map) => {
148 let mut result = serde_json::Map::new();
149 for (key, &child_id) in map.iter() {
150 let key_string = convert_object_key(key)?;
151 let value = convert_node(doc, child_id, config)?;
152 result.insert(key_string, value);
153 }
154 Ok(JsonValue::Object(result))
155 }
156 }
157}
158
159fn convert_primitive(prim: &PrimitiveValue, node_id: NodeId) -> Result<JsonValue, EureToJsonError> {
160 match prim {
161 PrimitiveValue::Null => Ok(JsonValue::Null),
162 PrimitiveValue::Bool(b) => Ok(JsonValue::Bool(*b)),
163 PrimitiveValue::Integer(bi) => {
164 let i64_value = bi.to_string().parse::<i64>();
166 if let Ok(i) = i64_value {
167 return Ok(JsonValue::Number(i.into()));
168 }
169
170 let u64_value = bi.to_string().parse::<u64>();
172 if let Ok(u) = u64_value {
173 return Ok(JsonValue::Number(u.into()));
174 }
175
176 Err(EureToJsonError::BigIntOutOfRange { node_id })
177 }
178 PrimitiveValue::F32(f) => {
179 if let Some(num) = serde_json::Number::from_f64(*f as f64) {
180 Ok(JsonValue::Number(num))
181 } else {
182 Err(EureToJsonError::NonFiniteFloat { node_id })
184 }
185 }
186 PrimitiveValue::F64(f) => {
187 if let Some(num) = serde_json::Number::from_f64(*f) {
188 Ok(JsonValue::Number(num))
189 } else {
190 Err(EureToJsonError::NonFiniteFloat { node_id })
192 }
193 }
194 PrimitiveValue::Text(text) => Ok(JsonValue::String(text.content.clone())),
195 }
196}
197
198fn convert_variant_node(
200 doc: &EureDocument,
201 node_id: NodeId,
202 tag: &str,
203 config: &Config,
204) -> Result<JsonValue, EureToJsonError> {
205 let content_json = convert_node_content_only(doc, node_id, config)?;
207
208 match &config.variant_repr {
209 VariantRepr::External => {
210 let mut map = serde_json::Map::new();
212 map.insert(tag.to_string(), content_json);
213 Ok(JsonValue::Object(map))
214 }
215 VariantRepr::Internal { tag: tag_field } => {
216 if let JsonValue::Object(mut content_map) = content_json {
219 if content_map.contains_key(tag_field) {
221 return Err(EureToJsonError::VariantTagConflict {
222 tag: tag_field.clone(),
223 node_id,
224 });
225 }
226 content_map.insert(tag_field.clone(), JsonValue::String(tag.to_string()));
227 Ok(JsonValue::Object(content_map))
228 } else {
229 let mut map = serde_json::Map::new();
231 map.insert(tag.to_string(), content_json);
232 Ok(JsonValue::Object(map))
233 }
234 }
235 VariantRepr::Adjacent {
236 tag: tag_field,
237 content: content_key,
238 } => {
239 if tag_field == content_key {
242 return Err(EureToJsonError::VariantAdjacentConflict {
243 field: tag_field.clone(),
244 node_id,
245 });
246 }
247 let mut map = serde_json::Map::new();
248 map.insert(tag_field.clone(), JsonValue::String(tag.to_string()));
249 map.insert(content_key.clone(), content_json);
250 Ok(JsonValue::Object(map))
251 }
252 VariantRepr::Untagged => {
253 Ok(content_json)
255 }
256 }
257}
258
259fn convert_node_content_only(
261 doc: &EureDocument,
262 node_id: NodeId,
263 config: &Config,
264) -> Result<JsonValue, EureToJsonError> {
265 let node = doc.node(node_id);
266
267 match &node.content {
268 NodeValue::Hole(_) => Err(EureToJsonError::HoleNotSupported { node_id }),
269 NodeValue::PartialMap(_) => Err(EureToJsonError::PartialMapNotSupported { node_id }),
270 NodeValue::Primitive(prim) => convert_primitive(prim, node_id),
271 NodeValue::Array(arr) => {
272 let mut result = Vec::new();
273 for &child_id in arr.iter() {
274 result.push(convert_node(doc, child_id, config)?);
275 }
276 Ok(JsonValue::Array(result))
277 }
278 NodeValue::Tuple(tuple) => {
279 let mut result = Vec::new();
280 for &child_id in tuple.iter() {
281 result.push(convert_node(doc, child_id, config)?);
282 }
283 Ok(JsonValue::Array(result))
284 }
285 NodeValue::Map(map) => {
286 let mut result = serde_json::Map::new();
287 for (key, &child_id) in map.iter() {
288 let key_string = convert_object_key(key)?;
289 let value = convert_node(doc, child_id, config)?;
290 result.insert(key_string, value);
291 }
292 Ok(JsonValue::Object(result))
293 }
294 }
295}
296
297fn convert_object_key(key: &ObjectKey) -> Result<String, EureToJsonError> {
298 match key {
299 ObjectKey::Number(n) => Ok(n.to_string()),
300 ObjectKey::String(s) => Ok(s.clone()),
301 ObjectKey::Tuple(tuple) => {
302 let mut parts = Vec::new();
303 for item in &tuple.0 {
304 parts.push(convert_object_key(item)?);
305 }
306 Ok(format!("({})", parts.join(", ")))
307 }
308 }
309}
310
311pub fn value_to_document(
334 value: &JsonValue,
335 _config: &Config,
336) -> Result<EureDocument, JsonToEureError> {
337 let mut doc = EureDocument::new();
338 let root_id = doc.get_root_id();
339 convert_json_to_node(&mut doc, root_id, value);
340 Ok(doc)
341}
342
343fn convert_json_to_node(doc: &mut EureDocument, node_id: NodeId, value: &JsonValue) {
345 match value {
346 JsonValue::Null => {
347 doc.node_mut(node_id).content = NodeValue::Primitive(PrimitiveValue::Null);
348 }
349 JsonValue::Bool(b) => {
350 doc.node_mut(node_id).content = NodeValue::Primitive(PrimitiveValue::Bool(*b));
351 }
352 JsonValue::Number(n) => {
353 if let Some(i) = n.as_i64() {
354 doc.node_mut(node_id).content =
355 NodeValue::Primitive(PrimitiveValue::Integer(BigInt::from(i)));
356 } else if let Some(u) = n.as_u64() {
357 doc.node_mut(node_id).content =
358 NodeValue::Primitive(PrimitiveValue::Integer(BigInt::from(u)));
359 } else if let Some(f) = n.as_f64() {
360 doc.node_mut(node_id).content = NodeValue::Primitive(PrimitiveValue::F64(f));
361 }
362 }
363 JsonValue::String(s) => {
364 doc.node_mut(node_id).content =
365 NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext(s.clone())));
366 }
367 JsonValue::Array(arr) => {
368 doc.node_mut(node_id).content = NodeValue::empty_array();
369 for item in arr {
370 let child_id = doc.create_node(NodeValue::hole());
371 convert_json_to_node(doc, child_id, item);
372 if let NodeValue::Array(ref mut array) = doc.node_mut(node_id).content {
373 let _ = array.push(child_id);
374 }
375 }
376 }
377 JsonValue::Object(obj) => {
378 doc.node_mut(node_id).content = NodeValue::empty_map();
379 for (key, val) in obj {
380 let child_id = doc.create_node(NodeValue::hole());
381 convert_json_to_node(doc, child_id, val);
382 if let NodeValue::Map(ref mut map) = doc.node_mut(node_id).content {
383 map.insert(ObjectKey::String(key.clone()), child_id);
384 }
385 }
386 }
387 }
388}
389
390#[cfg(test)]
391mod tests {
392 use super::*;
393 use eure_document::eure;
394 use eure_schema::interop::VariantRepr;
395 use serde_json::json;
396
397 #[test]
402 fn test_null() {
403 let eure = eure!({ = null });
404 let json = json!(null);
405 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
406 }
407
408 #[test]
409 fn test_bool_true() {
410 let eure = eure!({ = true });
411 let json = json!(true);
412 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
413 }
414
415 #[test]
416 fn test_bool_false() {
417 let eure = eure!({ = false });
418 let json = json!(false);
419 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
420 }
421
422 #[test]
423 fn test_integer() {
424 let eure = eure!({ = 42 });
425 let json = json!(42);
426 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
427 }
428
429 #[test]
430 fn test_negative_integer() {
431 let eure = eure!({ = -42 });
432 let json = json!(-42);
433 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
434 }
435
436 #[test]
437 fn test_float() {
438 let eure = eure!({ = 1.5f64 });
439 let json = json!(1.5);
440 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
441 }
442
443 #[test]
444 fn test_string() {
445 let eure = eure!({ = "hello world" });
446 let json = json!("hello world");
447 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
448 }
449
450 #[test]
451 fn test_array() {
452 let eure = eure!({
453 items[] = 1,
454 items[] = 2,
455 items[] = 3,
456 });
457 let json = json!({"items": [1, 2, 3]});
458 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
459 }
460
461 #[test]
462 fn test_tuple() {
463 let eure = eure!({
464 point.#0 = 1.5f64,
465 point.#1 = 2.5f64,
466 });
467 let json = json!({"point": [1.5, 2.5]});
468 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
469 }
470
471 #[test]
472 fn test_empty_map() {
473 let eure = eure!({});
474 let json = json!({});
475 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
476 }
477
478 #[test]
479 fn test_map_with_fields() {
480 let eure = eure!({ key = true });
481 let json = json!({"key": true});
482 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
483 }
484
485 #[test]
486 fn test_nested_map() {
487 let eure = eure!({
488 user.name = "Alice",
489 user.age = 30,
490 });
491 let json = json!({"user": {"name": "Alice", "age": 30}});
492 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
493 }
494
495 #[test]
496 fn test_array_of_maps() {
497 let eure = eure!({
498 users[].name = "Alice",
499 users[].name = "Bob",
500 });
501 let json = json!({"users": [{"name": "Alice"}, {"name": "Bob"}]});
502 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
503 }
504
505 #[test]
507 fn test_variant_external() {
508 let eure = eure!({
509 = true,
510 %variant = "Success",
511 });
512 let config = Config {
513 variant_repr: VariantRepr::External,
514 };
515 let json = json!({"Success": true});
516 assert_eq!(document_to_value(&eure, &config).unwrap(), json);
517 }
518
519 #[test]
520 fn test_variant_untagged() {
521 let eure = eure!({
522 = true,
523 %variant = "Success",
524 });
525 let config = Config {
526 variant_repr: VariantRepr::Untagged,
527 };
528 let json = json!(true);
529 assert_eq!(document_to_value(&eure, &config).unwrap(), json);
530 }
531
532 #[test]
533 fn test_variant_internal() {
534 let eure = eure!({
535 field = 42,
536 %variant = "Success",
537 });
538 let config = Config {
539 variant_repr: VariantRepr::Internal {
540 tag: "type".to_string(),
541 },
542 };
543 let json = json!({"type": "Success", "field": 42});
544 assert_eq!(document_to_value(&eure, &config).unwrap(), json);
545 }
546
547 #[test]
548 fn test_variant_adjacent() {
549 let eure = eure!({
550 = true,
551 %variant = "Success",
552 });
553 let config = Config {
554 variant_repr: VariantRepr::Adjacent {
555 tag: "tag".to_string(),
556 content: "content".to_string(),
557 },
558 };
559 let json = json!({"tag": "Success", "content": true});
560 assert_eq!(document_to_value(&eure, &config).unwrap(), json);
561 }
562
563 #[test]
565 fn test_hole_error() {
566 let eure = eure!({ placeholder = ! });
567 let result = document_to_value(&eure, &Config::default());
568 assert!(matches!(
569 result,
570 Err(EureToJsonError::HoleNotSupported { .. })
571 ));
572 }
573
574 #[test]
575 fn test_f64_nan_error() {
576 let nan_value = f64::NAN;
577 let eure = eure!({ = nan_value });
578 let result = document_to_value(&eure, &Config::default());
579 assert!(matches!(
580 result,
581 Err(EureToJsonError::NonFiniteFloat { .. })
582 ));
583 }
584
585 #[test]
586 fn test_f64_infinity_error() {
587 let inf_value = f64::INFINITY;
588 let eure = eure!({ = inf_value });
589 let result = document_to_value(&eure, &Config::default());
590 assert!(matches!(
591 result,
592 Err(EureToJsonError::NonFiniteFloat { .. })
593 ));
594 }
595
596 #[test]
601 fn test_json_to_eure_null() {
602 let json = json!(null);
603 let expected = eure!({ = null });
604 assert_eq!(
605 value_to_document(&json, &Config::default()).unwrap(),
606 expected
607 );
608 }
609
610 #[test]
611 fn test_json_to_eure_bool() {
612 let json = json!(true);
613 let expected = eure!({ = true });
614 assert_eq!(
615 value_to_document(&json, &Config::default()).unwrap(),
616 expected
617 );
618 }
619
620 #[test]
621 fn test_json_to_eure_integer() {
622 let json = json!(42);
623 let expected = eure!({ = 42 });
624 assert_eq!(
625 value_to_document(&json, &Config::default()).unwrap(),
626 expected
627 );
628 }
629
630 #[test]
631 fn test_json_to_eure_float() {
632 let json = json!(1.5);
633 let expected = eure!({ = 1.5f64 });
634 assert_eq!(
635 value_to_document(&json, &Config::default()).unwrap(),
636 expected
637 );
638 }
639
640 #[test]
641 fn test_json_to_eure_string() {
642 let json = json!("hello");
643 let expected = eure!({ = "hello" });
644 assert_eq!(
645 value_to_document(&json, &Config::default()).unwrap(),
646 expected
647 );
648 }
649
650 #[test]
651 fn test_json_to_eure_array() {
652 let json = json!([1, 2, 3]);
654 let doc = value_to_document(&json, &Config::default()).unwrap();
655 let roundtrip = document_to_value(&doc, &Config::default()).unwrap();
656 assert_eq!(json, roundtrip);
657 }
658
659 #[test]
660 fn test_json_to_eure_empty_object() {
661 let json = json!({});
662 let expected = eure!({});
663 assert_eq!(
664 value_to_document(&json, &Config::default()).unwrap(),
665 expected
666 );
667 }
668
669 #[test]
670 fn test_json_to_eure_object() {
671 let json = json!({"name": "Alice", "age": 30});
672 let expected = eure!({
673 name = "Alice",
674 age = 30,
675 });
676 assert_eq!(
677 value_to_document(&json, &Config::default()).unwrap(),
678 expected
679 );
680 }
681
682 #[test]
683 fn test_json_to_eure_nested() {
684 let json = json!({"user": {"name": "Alice"}});
685 let expected = eure!({ user.name = "Alice" });
686 assert_eq!(
687 value_to_document(&json, &Config::default()).unwrap(),
688 expected
689 );
690 }
691
692 #[test]
693 fn test_json_to_eure_array_of_objects() {
694 let json = json!({"users": [{"name": "Alice"}, {"name": "Bob"}]});
695 let expected = eure!({
696 users[].name = "Alice",
697 users[].name = "Bob",
698 });
699 assert_eq!(
700 value_to_document(&json, &Config::default()).unwrap(),
701 expected
702 );
703 }
704
705 #[test]
710 fn test_roundtrip_primitives() {
711 for json in [
712 json!(null),
713 json!(true),
714 json!(42),
715 json!(1.5),
716 json!("hello"),
717 ] {
718 let doc = value_to_document(&json, &Config::default()).unwrap();
719 let roundtrip = document_to_value(&doc, &Config::default()).unwrap();
720 assert_eq!(json, roundtrip);
721 }
722 }
723
724 #[test]
725 fn test_roundtrip_array() {
726 let json = json!([1, 2, 3, "hello", true, null]);
727 let doc = value_to_document(&json, &Config::default()).unwrap();
728 let roundtrip = document_to_value(&doc, &Config::default()).unwrap();
729 assert_eq!(json, roundtrip);
730 }
731
732 #[test]
733 fn test_roundtrip_nested() {
734 let json = json!({"name": "test", "nested": {"a": 1, "b": [true, false]}});
735 let doc = value_to_document(&json, &Config::default()).unwrap();
736 let roundtrip = document_to_value(&doc, &Config::default()).unwrap();
737 assert_eq!(json, roundtrip);
738 }
739
740 #[test]
741 fn test_roundtrip_deeply_nested() {
742 let json = json!({"Ok": {"Some": {"method": "add"}}});
743 let doc = value_to_document(&json, &Config::default()).unwrap();
744 let roundtrip = document_to_value(&doc, &Config::default()).unwrap();
745 assert_eq!(json, roundtrip);
746 }
747}