Skip to main content

shape/
json.rs

1//! Declarative JSON
2//! ================
3//! A shape written back as the JSON that [`crate::expr::build`] reads: every
4//! string is an expression of the string DSL, a key expression (`"a: String"`)
5//! carries its example as the value, and a `"$$"` key applies an expression to
6//! the object that holds it, with `"$$0"`, `"$$1"`, ... beside it for the
7//! arguments an expression cannot spell inline (an object or array shape).
8//! The result reads back as the same shape: the JSON of the shape built from
9//! a shape's JSON is that JSON, and the two accept and produce the same
10//! values. Nothing a function does can be written down, so a shape carrying
11//! one (a check function, a transform, a key function) cannot be written, nor
12//! can a builder option the DSL has no word for (rename's keep and claim,
13//! refer's fill and strict) or a default that is an object, an array or a
14//! date.
15//!
16//! This mirrors `ts/src/shape.ts` nodeJson; the Go port carries the same.
17
18use crate::node::{Kind, ListMode, Node, Validator};
19use crate::value::{js_number, json_text, Map, Value};
20use std::fmt;
21
22const MARK: &str = "$$";
23
24/// What the JSON cannot say about a shape.
25#[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
42/// The type token a kind is written as, where it has one.
43fn 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
60/// An argument of a call: inline expression text, or a spec that rides in a
61/// sidecar (`"$$0"`) beside the expression.
62enum 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
86/// The inline text of a literal argument: a JSON scalar, or NaN.
87fn 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
96/// A value as JSON text: a string keeps its quotes.
97fn 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
104/// What a value is, in a message: the JavaScript typeof, or the number.
105fn 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
115/// An after check is a custom one, which cannot be written.
116fn 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
123/// The checks a node carries, as calls, in the order they run; the check at
124/// `skip` is the head of the expression and is left out.
125fn 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            // The taken checks run inside, so they read ahead of the taker.
144            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        // The list itself is the head of the expression.
176        "One" | "Some" | "All" | "Discriminated" => {}
177        _ if is_format(name) => calls.push(call(name)),
178        // The check of a regexp is named by its pattern.
179        _ if name.starts_with('/') => calls.push(call1("Check", name.to_string())),
180        _ => return cannot(format!("a custom check {}", name)),
181    }
182    Ok(())
183}
184
185/// Whether the node is required or skipped, as calls, for a head that says
186/// neither: Required where the head is optional by itself, Optional or Skip
187/// where it is required. Ignore says skipped already.
188fn 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
202/// The flags of the node, as calls. An empty literal head says Empty by
203/// itself. A rename reads first among the checks, as it does when written
204/// first.
205fn 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
228/// Ignore is a flag, read after the checks it silences, then the description
229/// and the fault text.
230fn 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
244/// The value form of a node as an argument: inline when it is a string.
245fn 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
252/// Whether an open object's child shape is the plain Any of Open.
253fn 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
262/// The text of a call, its sidecar arguments registered in refs. A shape is
263/// the call's last argument.
264fn 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
286/// A chain of calls after a head, or with no head as a bare chain; empty
287/// with neither.
288fn 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
302/// The calls around a shape that is not a node by itself (a literal, a
303/// regexp, a sidecar): the first takes it, the rest chain.
304fn 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
313/// A carrier object: the expression under `"$$"`, the sidecars beside it.
314fn 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
323/// A literal, held by the call that says whether it is required.
324fn 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
335/// The index of the validator that makes the node the head of its
336/// expression, so that the node has no key form: Key makes it, and Exact
337/// reads every argument as a value.
338fn 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
351/// The parts of a scalar: the head (a type token, a held literal, or Key),
352/// the token of the key form (none where the head is not one), the example
353/// of the key form, and the calls after the head.
354fn 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    // A literal stands for its own kind, but not for integer, and an empty
369    // string literal allows the empty string; a required zero is the type
370    // token.
371    } 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
398/// The key form of a property, the chain of `"name: chain"` with its
399/// example, or none where the node has no key form (a list, a regexp, a
400/// shape needing sidecars).
401fn 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        // With a literal head, the call that held the literal starts the chain.
408        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
439/// Whether a name has to be quoted in a key expression.
440fn 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
453/// The children of an object in key form, and the chain that applies to the
454/// object (empty when there is none).
455fn object(n: &Node) -> R<ObjectParts> {
456    let mut children = Map::new();
457    let mut refs: Vec<(String, Value)> = Vec::new();
458
459    // A type token brings the empty object as its default, which the walk
460    // makes for an absent object anyway; any other default is one the
461    // expression form cannot spell.
462    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            // A name that reads as a key expression is quoted, and so needs a
485            // chain; Optional says nothing about a node that is optional
486            // already.
487            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
544/// The elements of an array in value form: the fixed positions, or the one
545/// element shape. A single fixed position is closed, which `[X]` cannot say.
546fn 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        // A rest replaces a plain element shape, so a node has one or the
565        // other, never both.
566        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
595/// A node whose head is a call that makes it (Key on an object or an array):
596/// the head, then the rest of the chain. Exact reads its arguments as
597/// values, so an object or an array with it cannot be written.
598fn 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
612/// The value form of a node: the JSON that reads back as it.
613pub fn node_json(n: &Node) -> R<Value> {
614    if token_of(n.kind).is_some() {
615        let sc = scalar(n)?;
616        // A literal with nothing after it is the JSON value; a string is
617        // quoted, as a bare one would read as an expression.
618        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            // The calls take the array as their shape; a single position is
659            // closed first, as a one element array is an element shape.
660            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            // A regexp is not a node until a builder takes it, so the calls
713            // wrap it.
714            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        // The rest are a call that names the kind, then the chain.
740        _ => {
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                    // Check is the first call, and says required.
791                    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                // Optional(Date), Skip(Never): the call holds the token.
817                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
827/// The branches of a discriminated union by tag value. A branch's tag
828/// property is what the union added, unless the author declared it.
829fn 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}