1use crate::node::{Kind, ListMode, Node, Validator};
19use crate::value::{js_number, json_text, Map, Value};
20use std::fmt;
21
22const MARK: &str = "$$";
23
24#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct JsonError(pub String);
27
28impl fmt::Display for JsonError {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 write!(f, "Shape: json cannot express {}", self.0)
31 }
32}
33
34impl std::error::Error for JsonError {}
35
36type R<T> = Result<T, JsonError>;
37
38fn cannot<T>(what: impl Into<String>) -> R<T> {
39 Err(JsonError(what.into()))
40}
41
42fn token_of(kind: Kind) -> Option<&'static str> {
44 match kind {
45 Kind::String => Some("String"),
46 Kind::Number => Some("Number"),
47 Kind::Integer => Some("Integer"),
48 Kind::Boolean => Some("Boolean"),
49 _ => None,
50 }
51}
52
53fn is_format(name: &str) -> bool {
54 matches!(
55 name,
56 "Email" | "Url" | "Uuid" | "DateTime" | "Ip" | "Ipv4" | "Ipv6"
57 )
58}
59
60enum Arg {
63 Text(String),
64 Side(Value),
65}
66
67struct Call {
68 name: String,
69 args: Vec<Arg>,
70}
71
72fn call(name: &str) -> Call {
73 Call {
74 name: name.to_string(),
75 args: Vec::new(),
76 }
77}
78
79fn call1(name: &str, arg: String) -> Call {
80 Call {
81 name: name.to_string(),
82 args: vec![Arg::Text(arg)],
83 }
84}
85
86fn literal(v: &Value, what: &str) -> R<String> {
88 match v {
89 Value::Null => Ok("null".to_string()),
90 Value::Bool(_) | Value::Str(_) => Ok(inline_json(v)),
91 Value::Num(n) if n.is_finite() || n.is_nan() => Ok(js_number(*n)),
92 other => cannot(format!("{} {}", what, kind_word(other))),
93 }
94}
95
96fn inline_json(v: &Value) -> String {
98 match v {
99 Value::Str(s) => json_text(s),
100 other => crate::value::json_render(other),
101 }
102}
103
104fn kind_word(v: &Value) -> String {
106 match v {
107 Value::Undefined => "undefined".to_string(),
108 Value::Num(n) => js_number(*n),
109 Value::Func(_) => "function".to_string(),
110 Value::BigInt(_) => "bigint".to_string(),
111 _ => "object".to_string(),
112 }
113}
114
115fn no_afters(afters: &[Validator]) -> R<()> {
117 match afters.first() {
118 Some(v) => cannot(format!("a custom after check {}", v.name)),
119 None => Ok(()),
120 }
121}
122
123fn validator_calls(n: &Node, skip: Option<usize>) -> R<Vec<Call>> {
126 let mut calls = Vec::new();
127 for (i, v) in n.befores.iter().enumerate() {
128 if Some(i) != skip {
129 validator_call(v, &mut calls)?;
130 }
131 }
132 no_afters(&n.afters)?;
133 Ok(calls)
134}
135
136fn validator_call(v: &Validator, calls: &mut Vec<Call>) -> R<()> {
137 let name = v.name.as_str();
138 match name {
139 "Min" | "Max" | "Above" | "Below" | "Len" => {
140 calls.push(call1(name, literal(&v.args[0], "the bound")?));
141 }
142 "Catch" => {
143 let inner = v.inner.as_ref().expect("Catch takes its checks inside");
145 for iv in &inner.befores {
146 validator_call(iv, calls)?;
147 }
148 no_afters(&inner.afters)?;
149 calls.push(call1(name, literal(&v.args[0], "the fallback")?));
150 }
151 "Transform" => return cannot("Transform"),
152 "Coerce" => calls.push(call(name)),
153 "Define" | "Refer" => calls.push(call1(name, inline_json(&v.args[0]))),
154 "Key" => {
155 let mut args = Vec::with_capacity(v.args.len());
156 for a in &v.args {
157 args.push(Arg::Text(literal(a, "the Key argument")?));
158 }
159 calls.push(Call {
160 name: name.to_string(),
161 args,
162 });
163 }
164 "Exact" => {
165 let mut args = Vec::with_capacity(v.args.len());
166 for a in &v.args {
167 args.push(Arg::Text(literal(a, "the Exact value")?));
168 }
169 calls.push(Call {
170 name: name.to_string(),
171 args,
172 });
173 }
174 "Check" => return cannot("a check function"),
175 "One" | "Some" | "All" | "Discriminated" => {}
177 _ if is_format(name) => calls.push(call(name)),
178 _ if name.starts_with('/') => calls.push(call1("Check", name.to_string())),
180 _ => return cannot(format!("a custom check {}", name)),
181 }
182 Ok(())
183}
184
185fn required_calls(n: &Node, head_required: bool) -> Vec<Call> {
189 let mut calls = Vec::new();
190 if n.required && !head_required {
191 calls.push(call("Required"));
192 } else if !n.required && !n.is_ignore() {
193 if n.skippable {
194 calls.push(call("Skip"));
195 } else if head_required {
196 calls.push(call("Optional"));
197 }
198 }
199 calls
200}
201
202fn flag_calls(n: &Node, literal_head: bool) -> R<Vec<Call>> {
206 let mut calls = Vec::new();
207 if n.kind == Kind::String
208 && n.empty
209 && !(literal_head && n.default == Value::Str(String::new()))
210 {
211 calls.push(call("Empty"));
212 }
213 if n.nullable {
214 calls.push(call("Nullable"));
215 }
216 if let Some(to) = &n.rename_to {
217 if n.rename_keep || !n.rename_claim.is_empty() {
218 return cannot("the options of Rename");
219 }
220 calls.push(call1("Rename", json_text(to)));
221 }
222 if n.refer_name.is_some() && (n.refer_fill || n.refer_strict) {
223 return cannot("the options of Refer");
224 }
225 Ok(calls)
226}
227
228fn tail_calls(n: &Node) -> Vec<Call> {
231 let mut calls = Vec::new();
232 if n.is_ignore() {
233 calls.push(call("Ignore"));
234 }
235 if let Some(Value::Str(d)) = n.meta.get("description") {
236 calls.push(call1("Describe", json_text(d)));
237 }
238 if let Some(msg) = &n.fault_msg {
239 calls.push(call1("Fault", json_text(msg)));
240 }
241 calls
242}
243
244fn arg_of(n: &Node) -> R<Arg> {
246 Ok(match node_json(n)? {
247 Value::Str(s) => Arg::Text(s),
248 other => Arg::Side(other),
249 })
250}
251
252fn is_open_any(c: &Node) -> bool {
254 c.kind == Kind::Any
255 && !c.required
256 && c.befores.is_empty()
257 && c.afters.is_empty()
258 && c.obj_rest.is_none()
259 && (!c.has_default || c.default.is_undefined())
260}
261
262fn call_text(c: &Call, refs: &mut Vec<(String, Value)>, shape: Option<&str>) -> String {
265 let mut parts: Vec<String> = Vec::with_capacity(c.args.len() + 1);
266 for a in &c.args {
267 match a {
268 Arg::Text(t) => parts.push(t.clone()),
269 Arg::Side(j) => {
270 let name = format!("{}{}", MARK, refs.len());
271 refs.push((name.clone(), j.clone()));
272 parts.push(name);
273 }
274 }
275 }
276 if let Some(s) = shape {
277 parts.push(s.to_string());
278 }
279 if parts.is_empty() {
280 c.name.clone()
281 } else {
282 format!("{}({})", c.name, parts.join(","))
283 }
284}
285
286fn chain_text(head: &str, calls: &[Call], refs: &mut Vec<(String, Value)>) -> String {
289 let mut out = head.to_string();
290 for c in calls {
291 let text = call_text(c, refs, None);
292 if out.is_empty() {
293 out = text;
294 } else {
295 out.push('.');
296 out.push_str(&text);
297 }
298 }
299 out
300}
301
302fn wrap_text(calls: &[Call], shape: &str, refs: &mut Vec<(String, Value)>) -> String {
305 let mut out = call_text(&calls[0], refs, Some(shape));
306 for c in &calls[1..] {
307 out.push('.');
308 out.push_str(&call_text(c, refs, None));
309 }
310 out
311}
312
313fn carrier(text: String, refs: Vec<(String, Value)>) -> Value {
315 let mut m = Map::new();
316 m.insert(MARK.to_string(), Value::Str(text));
317 for (k, v) in refs {
318 m.insert(k, v);
319 }
320 Value::Obj(m)
321}
322
323fn literal_head(n: &Node, lit: &str) -> String {
325 let name = if n.skippable {
326 "Skip"
327 } else if n.required {
328 "Required"
329 } else {
330 "Optional"
331 };
332 format!("{}({})", name, lit)
333}
334
335fn head_validator(n: &Node) -> Option<usize> {
339 n.befores
340 .iter()
341 .position(|v| v.name == "Key" || v.name == "Exact")
342}
343
344struct Scalar {
345 head: String,
346 token: Option<&'static str>,
347 example: Value,
348 calls: Vec<Call>,
349}
350
351fn scalar(n: &Node) -> R<Scalar> {
355 let zero = Node::zero_for(n.kind);
356 let is_zero = !n.has_default || n.default == zero;
357 let example = if is_zero { zero } else { n.default.clone() };
358 let hv = head_validator(n);
359 let keyed = matches!(hv, Some(i) if n.befores[i].name == "Key");
360
361 let (head, token, mut calls) = if keyed {
362 let mut kc = Vec::new();
363 validator_call(&n.befores[hv.unwrap()], &mut kc)?;
364 let head = call_text(&kc[0], &mut Vec::new(), None);
365 let mut calls = required_calls(n, false);
366 calls.extend(flag_calls(n, false)?);
367 (head, None, calls)
368 } else if (n.required && is_zero)
372 || n.kind == Kind::Integer
373 || (n.kind == Kind::String && !n.empty && n.default == Value::Str(String::new()))
374 {
375 let token = token_of(n.kind);
376 let mut calls = required_calls(n, true);
377 calls.extend(flag_calls(n, false)?);
378 (token.unwrap_or_default().to_string(), token, calls)
379 } else {
380 (
381 literal_head(n, &literal(&example, "the default")?),
382 None,
383 flag_calls(n, true)?,
384 )
385 };
386
387 calls.extend(validator_calls(n, if keyed { hv } else { None })?);
388 calls.extend(tail_calls(n));
389
390 Ok(Scalar {
391 head,
392 token,
393 example,
394 calls,
395 })
396}
397
398fn key_form(n: &Node) -> R<Option<(String, Value)>> {
402 if head_validator(n).is_some() {
403 return Ok(None);
404 }
405 if token_of(n.kind).is_some() {
406 let sc = scalar(n)?;
407 let head = sc.token.map(|t| t.to_string()).unwrap_or_else(|| {
409 if n.skippable {
410 "Skip".to_string()
411 } else if n.required {
412 "Required".to_string()
413 } else {
414 String::new()
415 }
416 });
417 return Ok(Some((
418 chain_text(&head, &sc.calls, &mut Vec::new()),
419 sc.example,
420 )));
421 }
422 if n.kind == Kind::Object {
423 let o = object(n)?;
424 if !o.refs.is_empty() {
425 return Ok(None);
426 }
427 return Ok(Some((o.chain, Value::Obj(o.children))));
428 }
429 if n.kind == Kind::Array {
430 let a = array(n)?;
431 if !a.refs.is_empty() || a.closed {
432 return Ok(None);
433 }
434 return Ok(Some((a.chain, Value::Arr(a.elements))));
435 }
436 Ok(None)
437}
438
439fn needs_quote(k: &str) -> bool {
441 k.is_empty()
442 || k.chars()
443 .any(|c| c.is_whitespace() || c == '"' || c == '\\')
444 || crate::expr::split_key_expr(k).is_some()
445}
446
447struct ObjectParts {
448 children: Map,
449 chain: String,
450 refs: Vec<(String, Value)>,
451}
452
453fn object(n: &Node) -> R<ObjectParts> {
456 let mut children = Map::new();
457 let mut refs: Vec<(String, Value)> = Vec::new();
458
459 if n.has_default
463 && !n.default.is_undefined()
464 && !matches!(&n.default, Value::Obj(m) if m.is_empty())
465 {
466 return cannot("an object default");
467 }
468
469 for (k, c) in &n.obj_children {
470 if k.starts_with(MARK) {
471 return cannot(format!("the property name {}", json_text(k)));
472 }
473 let kf = key_form(c)?;
474 let is_key_expr = crate::expr::split_key_expr(k).is_some();
475 match kf {
476 Some((chain, example)) if !chain.is_empty() => {
477 let name = if needs_quote(k) {
478 json_text(k)
479 } else {
480 k.clone()
481 };
482 children.insert(format!("{}: {}", name, chain), example);
483 }
484 Some((_, example)) if is_key_expr => {
488 children.insert(format!("{}: Optional", json_text(k)), example);
489 }
490 _ if is_key_expr => {
491 return cannot(format!(
492 "the property name {} of a value with no key form",
493 json_text(k)
494 ));
495 }
496 _ => {
497 children.insert(k.clone(), node_json(c)?);
498 }
499 }
500 }
501
502 let mut calls = required_calls(n, false);
503 calls.extend(flag_calls(n, false)?);
504 calls.extend(validator_calls(n, None)?);
505 match &n.obj_rest {
506 None => {
507 if n.obj_children.is_empty() {
508 calls.push(call("Closed"));
509 }
510 }
511 Some(rest) if is_open_any(rest) => {
512 if !n.obj_children.is_empty() {
513 calls.push(call("Open"));
514 }
515 }
516 Some(rest) => calls.push(Call {
517 name: "Child".to_string(),
518 args: vec![arg_of(rest)?],
519 }),
520 }
521 calls.extend(tail_calls(n));
522
523 let chain = if calls.is_empty() {
524 String::new()
525 } else {
526 chain_text("", &calls, &mut refs)
527 };
528
529 Ok(ObjectParts {
530 children,
531 chain,
532 refs,
533 })
534}
535
536struct ArrayParts {
537 elements: Vec<Value>,
538 calls: Vec<Call>,
539 chain: String,
540 refs: Vec<(String, Value)>,
541 closed: bool,
542}
543
544fn array(n: &Node) -> R<ArrayParts> {
547 let mut refs: Vec<(String, Value)> = Vec::new();
548 let mut elements = Vec::new();
549 let mut closed = false;
550
551 if n.has_default
552 && !n.default.is_undefined()
553 && !matches!(&n.default, Value::Arr(a) if a.is_empty())
554 {
555 return cannot("an array default");
556 }
557
558 if !n.arr_children.is_empty() {
559 for p in &n.arr_children {
560 elements.push(node_json(p)?);
561 }
562 closed = n.arr_children.len() == 1;
563 } else if let Some(c) = &n.arr_child {
564 elements.push(node_json(c)?);
567 }
568
569 let mut calls = required_calls(n, false);
570 calls.extend(flag_calls(n, false)?);
571 calls.extend(validator_calls(n, None)?);
572 if let Some(rest) = &n.arr_rest {
573 calls.push(Call {
574 name: "Rest".to_string(),
575 args: vec![arg_of(rest)?],
576 });
577 }
578 calls.extend(tail_calls(n));
579
580 let chain = if calls.is_empty() {
581 String::new()
582 } else {
583 chain_text("", &calls, &mut refs)
584 };
585
586 Ok(ArrayParts {
587 elements,
588 calls,
589 chain,
590 refs,
591 closed,
592 })
593}
594
595fn headed(n: &Node, hv: usize, what: &str) -> R<Value> {
599 if n.befores[hv].name == "Exact" {
600 return cannot(format!("Exact on {}", what));
601 }
602 let mut kc = Vec::new();
603 validator_call(&n.befores[hv], &mut kc)?;
604 let head = call_text(&kc[0], &mut Vec::new(), None);
605 let mut calls = required_calls(n, false);
606 calls.extend(flag_calls(n, false)?);
607 calls.extend(validator_calls(n, Some(hv))?);
608 calls.extend(tail_calls(n));
609 Ok(Value::Str(chain_text(&head, &calls, &mut Vec::new())))
610}
611
612pub fn node_json(n: &Node) -> R<Value> {
614 if token_of(n.kind).is_some() {
615 let sc = scalar(n)?;
616 if sc.token.is_none()
619 && sc.calls.is_empty()
620 && head_validator(n).is_none()
621 && !n.required
622 && !n.skippable
623 {
624 return Ok(match &sc.example {
625 Value::Str(s) => Value::Str(json_text(s)),
626 other => other.clone(),
627 });
628 }
629 return Ok(Value::Str(chain_text(&sc.head, &sc.calls, &mut Vec::new())));
630 }
631
632 let hv = head_validator(n);
633
634 match n.kind {
635 Kind::Object => {
636 if let Some(i) = hv {
637 return headed(n, i, "an object");
638 }
639 let o = object(n)?;
640 let mut children = o.children;
641 if !o.chain.is_empty() {
642 children.insert(MARK.to_string(), Value::Str(o.chain));
643 for (k, v) in o.refs {
644 children.insert(k, v);
645 }
646 }
647 Ok(Value::Obj(children))
648 }
649
650 Kind::Array => {
651 if let Some(i) = hv {
652 return headed(n, i, "an array");
653 }
654 let a = array(n)?;
655 if a.chain.is_empty() && !a.closed {
656 return Ok(Value::Arr(a.elements));
657 }
658 let name = format!("{}0", MARK);
661 let mut refs = vec![(name.clone(), Value::Arr(a.elements))];
662 let shape = if a.closed {
663 format!("Closed({})", name)
664 } else {
665 name
666 };
667 let text = if a.calls.is_empty() {
668 shape
669 } else {
670 wrap_text(&a.calls, &shape, &mut refs)
671 };
672 Ok(carrier(text, refs))
673 }
674
675 Kind::List => {
676 let mut refs: Vec<(String, Value)> = Vec::new();
677 let head = match &n.disc {
678 Some(d) => Call {
679 name: "Discriminated".to_string(),
680 args: vec![Arg::Text(json_text(&d.tag)), Arg::Side(branches(n)?)],
681 },
682 None => {
683 let mode = match n.list_mode {
684 ListMode::Some => "Some",
685 ListMode::All => "All",
686 _ => "One",
687 };
688 let mut args = Vec::with_capacity(n.list.len());
689 for b in &n.list {
690 args.push(arg_of(b)?);
691 }
692 Call {
693 name: mode.to_string(),
694 args,
695 }
696 }
697 };
698 let mut calls = required_calls(n, true);
699 calls.extend(flag_calls(n, false)?);
700 calls.extend(validator_calls(n, None)?);
701 calls.extend(tail_calls(n));
702 let head_text = call_text(&head, &mut refs, None);
703 let text = chain_text(&head_text, &calls, &mut refs);
704 Ok(if refs.is_empty() {
705 Value::Str(text)
706 } else {
707 carrier(text, refs)
708 })
709 }
710
711 Kind::Regexp => {
712 let mut calls = required_calls(n, true);
715 calls.extend(flag_calls(n, false)?);
716 calls.extend(validator_calls(n, None)?);
717 calls.extend(tail_calls(n));
718 let re = format!("/{}/", n.regexp_src);
719 Ok(Value::Str(if calls.is_empty() {
720 re
721 } else {
722 wrap_text(&calls, &re, &mut Vec::new())
723 }))
724 }
725
726 Kind::NaN => {
727 let mut calls = flag_calls(n, true)?;
728 calls.extend(validator_calls(n, None)?);
729 calls.extend(tail_calls(n));
730 Ok(Value::Str(
731 if calls.is_empty() && !n.required && !n.skippable {
732 "NaN".to_string()
733 } else {
734 chain_text(&literal_head(n, "NaN"), &calls, &mut Vec::new())
735 },
736 ))
737 }
738
739 _ => {
741 let mut head_required = true;
742 let mut head_skipped = false;
743 let head = match n.kind {
744 Kind::Any => {
745 let mut head = if n.required { "Required" } else { "Any" }.to_string();
746 head_required = n.required;
747 if n.has_default && !n.default.is_undefined() {
748 head = format!("{}({})", head, literal(&n.default, "the default")?);
749 }
750 head
751 }
752 Kind::Never => {
753 head_required = false;
754 "Never".to_string()
755 }
756 Kind::Null => {
757 if !n.required
758 && !n.skippable
759 && n.befores.is_empty()
760 && n.afters.is_empty()
761 && !n.nullable
762 && n.fault_msg.is_none()
763 && !n.meta.contains_key("description")
764 && n.rename_to.is_none()
765 {
766 return Ok(Value::Null);
767 }
768 head_required = n.required;
769 head_skipped = n.skippable;
770 if n.required {
771 "Required(null)".to_string()
772 } else if n.skippable {
773 "Skip(null)".to_string()
774 } else {
775 "null".to_string()
776 }
777 }
778 Kind::Date | Kind::Function => {
779 if n.has_default && !n.default.is_undefined() {
780 return cannot(format!("a {} default", n.kind));
781 }
782 if n.kind == Kind::Date {
783 "Date"
784 } else {
785 "Function"
786 }
787 .to_string()
788 }
789 Kind::Check => {
790 let first = match n.befores.first() {
792 Some(v) if v.name.starts_with('/') => v,
793 _ => return cannot("a check function"),
794 };
795 let mut kc = Vec::new();
796 validator_call(first, &mut kc)?;
797 let head = call_text(&kc[0], &mut Vec::new(), None);
798 let mut calls = required_calls(n, true);
799 calls.extend(flag_calls(n, false)?);
800 calls.extend(validator_calls(n, Some(0))?);
801 calls.extend(tail_calls(n));
802 return Ok(Value::Str(chain_text(&head, &calls, &mut Vec::new())));
803 }
804 other => return cannot(format!("a {} value", other)),
805 };
806
807 let rp = if head_skipped {
808 Vec::new()
809 } else {
810 required_calls(n, head_required)
811 };
812 let mut calls = flag_calls(n, false)?;
813 calls.extend(validator_calls(n, None)?);
814 calls.extend(tail_calls(n));
815 if head_required && !rp.is_empty() && n.kind != Kind::Any {
816 let held = format!("{}({})", rp[0].name, head);
818 return Ok(Value::Str(chain_text(&held, &calls, &mut Vec::new())));
819 }
820 let mut all = rp;
821 all.extend(calls);
822 Ok(Value::Str(chain_text(&head, &all, &mut Vec::new())))
823 }
824 }
825}
826
827fn branches(n: &Node) -> R<Value> {
830 let d = n.disc.as_ref().expect("a discriminated node has its tag");
831 let mut out = Map::new();
832 for (i, t) in d.tags.iter().enumerate() {
833 let b = &n.list[i];
834 let mut j = node_json(b)?;
835 let added = b.obj_children.get(&d.tag).is_some_and(|tn| {
836 tn.kind == Kind::String
837 && !tn.required
838 && tn.default == Value::Str(t.clone())
839 && tn.befores.is_empty()
840 && tn.afters.is_empty()
841 && tn.fault_msg.is_none()
842 });
843 if let (true, Value::Obj(m)) = (added, &mut j) {
844 m.shift_remove(&d.tag);
845 }
846 out.insert(t.clone(), j);
847 }
848 Ok(Value::Obj(out))
849}