Skip to main content

shape/
builders.rs

1//! The builders: functions that take a spec and return a node with the
2//! builder's rule applied, and the same as methods on a node so they chain.
3//!
4//! A builder given a wrong argument returns a node that accepts nothing and
5//! says why at validation, since a Rust builder cannot throw as the
6//! canonical one does; a chain method on such an argument turns its node
7//! into that fault.
8
9use crate::coerce::coerce_validator;
10use crate::context::{State, Update, UpdateErr};
11use crate::error::{MARK_CHECK_TYPE, WHY_CHECK};
12use crate::format::{
13    with_format, FMT_DATE_TIME, FMT_EMAIL, FMT_IP, FMT_IPV4, FMT_IPV6, FMT_URL, FMT_UUID,
14};
15use crate::isolate::{catch_node, transform_node, TransformFn};
16use crate::node::{Kind, ListMode, Node, Token, Validator};
17use crate::normalize::{normalize, type_token_node};
18use crate::spec::Spec;
19use crate::value::{is_integer, js_date_string, js_number, json_render, json_text, Value};
20use regex::Regex;
21use std::sync::Arc;
22
23/// A spec as a node: what every builder starts from.
24pub fn buildize(spec: impl Into<Spec>) -> Node {
25    normalize(spec.into())
26}
27
28/// An optional `Any`, the node a builder with no spec starts from.
29pub fn any() -> Node {
30    Node::of(Kind::Any)
31}
32
33/// A node that accepts nothing and says why: what a builder returns when
34/// called wrongly.
35pub(crate) fn fault_node(msg: impl Into<String>) -> Node {
36    let mut n = Node::of(Kind::Never);
37    n.fault_msg = Some(msg.into());
38    n.arg_fault = true;
39    n
40}
41
42pub(crate) fn is_fault(n: &Node) -> bool {
43    n.arg_fault
44}
45
46fn validator(
47    name: &str,
48    suffix: Option<String>,
49    args: Vec<Value>,
50    f: impl Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync + 'static,
51) -> Validator {
52    Validator {
53        name: name.to_string(),
54        func: Arc::new(f),
55        args,
56        suffix,
57        inner: None,
58    }
59}
60
61// The free functions: each takes the spec it applies to. Pass `any()` for
62// the bare form.
63
64/// The value must be present.
65pub fn required(spec: impl Into<Spec>) -> Node {
66    buildize(spec).required()
67}
68
69/// The value may be absent; the default is injected.
70pub fn optional(spec: impl Into<Spec>) -> Node {
71    buildize(spec).optional()
72}
73
74/// Optional, with an explicit default. The node is the spec's, so an object
75/// or array shape keeps its children; an untyped spec takes the default's
76/// kind.
77pub fn default(dval: impl Into<Value>, spec: impl Into<Spec>) -> Node {
78    buildize(spec).default_to(dval)
79}
80
81/// A default with no spec: the node takes the default's kind.
82pub fn default_of(dval: impl Into<Value>) -> Node {
83    let dval = dval.into();
84    normalize(Spec::Value(dval.clone())).default_to(dval)
85}
86
87/// Optional, and an absent value leaves the key out.
88pub fn skip(spec: impl Into<Spec>) -> Node {
89    buildize(spec).skip()
90}
91
92/// Like `skip`, and a value that fails is dropped with its errors.
93pub fn ignore(spec: impl Into<Spec>) -> Node {
94    buildize(spec).ignore()
95}
96
97/// The empty string is allowed. Untyped when bare: `empty(any())` allows
98/// the empty string without also demanding a string.
99pub fn empty(spec: impl Into<Spec>) -> Node {
100    buildize(spec).empty()
101}
102
103/// An explicit null is accepted as the value.
104pub fn nullable(spec: impl Into<Spec>) -> Node {
105    buildize(spec).nullable()
106}
107
108/// An object accepts keys it does not declare.
109pub fn open(spec: impl Into<Spec>) -> Node {
110    buildize(spec).open()
111}
112
113/// An object rejects keys it does not declare; a single-shape array becomes
114/// a tuple of one.
115pub fn closed(spec: impl Into<Spec>) -> Node {
116    buildize(spec).closed()
117}
118
119/// The shape of every unknown object value, or of every array element.
120pub fn child(child: impl Into<Spec>, spec: impl Into<Spec>) -> Node {
121    buildize(spec).child(child)
122}
123
124/// The shape of the array elements past the tuple positions.
125pub fn rest(child: impl Into<Spec>, spec: impl Into<Spec>) -> Node {
126    buildize(spec).rest(child)
127}
128
129/// A `Fault` message overriding the structural text.
130pub fn fault(msg: impl Into<String>, spec: impl Into<Spec>) -> Node {
131    buildize(spec).fault(msg)
132}
133
134/// A node that accepts nothing.
135pub fn never(spec: impl Into<Spec>) -> Node {
136    buildize(spec).never()
137}
138
139/// The kind the node asserts, given a kind, a token, a kind name or a node
140/// to take it from.
141pub fn type_(kind: impl Into<TypeRef>, spec: impl Into<Spec>) -> Node {
142    buildize(spec).type_(kind)
143}
144
145/// A function-typed value. A builder, not a type token, so it does not
146/// require a value of itself.
147pub fn func(spec: impl Into<Spec>) -> Node {
148    buildize(spec).func()
149}
150
151/// The value must equal one of the literals.
152pub fn exact<I>(vals: I) -> Node
153where
154    I: IntoIterator,
155    I::Item: Into<Value>,
156{
157    any().exact(vals)
158}
159
160/// A minimum value, or length.
161pub fn min(bound: impl Into<Value>, spec: impl Into<Spec>) -> Node {
162    buildize(spec).min(bound)
163}
164
165/// A maximum value, or length.
166pub fn max(bound: impl Into<Value>, spec: impl Into<Spec>) -> Node {
167    buildize(spec).max(bound)
168}
169
170/// A strict lower bound on value, or length.
171pub fn above(bound: impl Into<Value>, spec: impl Into<Spec>) -> Node {
172    buildize(spec).above(bound)
173}
174
175/// A strict upper bound on value, or length.
176pub fn below(bound: impl Into<Value>, spec: impl Into<Spec>) -> Node {
177    buildize(spec).below(bound)
178}
179
180/// An exact value, or length.
181pub fn len(length: impl Into<Value>, spec: impl Into<Spec>) -> Node {
182    buildize(spec).len(length)
183}
184
185/// A custom check, run before the structural check.
186pub fn check<F>(f: F, spec: impl Into<Spec>) -> Node
187where
188    F: Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync + 'static,
189{
190    let mut n = buildize(spec);
191    if n.kind == Kind::Any {
192        n.kind = Kind::Check;
193    }
194    n.required = true;
195    n.required_set = true;
196    n.check(f)
197}
198
199/// A regexp check: the value must be a string matching it. A failure reads
200/// `check "/re/" failed`.
201pub fn check_re(re: Regex, spec: impl Into<Spec>) -> Node {
202    check_re_src(re.as_str(), spec)
203}
204
205/// `check_re` from a pattern text.
206pub(crate) fn check_re_src(src: &str, spec: impl Into<Spec>) -> Node {
207    let mut n = buildize(spec);
208    if n.kind == Kind::Any {
209        n.kind = Kind::Check;
210    }
211    n.required = true;
212    n.required_set = true;
213    n.check_re_src(src)
214}
215
216/// A custom validator run before the structural check.
217pub fn before<F>(f: F, spec: impl Into<Spec>) -> Node
218where
219    F: Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync + 'static,
220{
221    buildize(spec).before(f)
222}
223
224/// A custom validator run after the structural check.
225pub fn after<F>(f: F, spec: impl Into<Spec>) -> Node
226where
227    F: Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync + 'static,
228{
229    buildize(spec).after(f)
230}
231
232/// The value must satisfy exactly one of the shapes.
233pub fn one<I>(shapes: I) -> Node
234where
235    I: IntoIterator,
236    I::Item: Into<Spec>,
237{
238    list_node(ListMode::One, shapes)
239}
240
241/// The value must satisfy at least one of the shapes.
242pub fn some<I>(shapes: I) -> Node
243where
244    I: IntoIterator,
245    I::Item: Into<Spec>,
246{
247    list_node(ListMode::Some, shapes)
248}
249
250/// The value must satisfy every shape.
251pub fn all<I>(shapes: I) -> Node
252where
253    I: IntoIterator,
254    I::Item: Into<Spec>,
255{
256    list_node(ListMode::All, shapes)
257}
258
259fn list_node<I>(mode: ListMode, shapes: I) -> Node
260where
261    I: IntoIterator,
262    I::Item: Into<Spec>,
263{
264    let mut n = Node::of(Kind::List);
265    n.required = true;
266    n.required_set = true;
267    n.list_mode = mode;
268    n.list = shapes.into_iter().map(|s| normalize(s.into())).collect();
269    n
270}
271
272/// Name the node so a later `refer` can substitute it.
273pub fn define(name: impl Into<String>, spec: impl Into<Spec>) -> Node {
274    buildize(spec).define(name)
275}
276
277/// Substitute the named node at validation time.
278pub fn refer(name: impl Into<String>, spec: impl Into<Spec>) -> Node {
279    buildize(spec).refer_with(name, ReferOptions::default())
280}
281
282/// `refer` with options.
283pub fn refer_with(name: impl Into<String>, opts: ReferOptions, spec: impl Into<Spec>) -> Node {
284    buildize(spec).refer_with(name, opts)
285}
286
287/// Rename the property after validation. For object children only.
288pub fn rename(name: impl Into<String>, spec: impl Into<Spec>) -> Node {
289    buildize(spec).rename_with(name, RenameOptions::default())
290}
291
292/// `rename` with options.
293pub fn rename_with(name: impl Into<String>, opts: RenameOptions, spec: impl Into<Spec>) -> Node {
294    buildize(spec).rename_with(name, opts)
295}
296
297/// The value is replaced with the key of the property it sits under.
298pub fn key() -> Node {
299    key_args(&[])
300}
301
302/// The value is replaced with the path `depth` levels up, as an array.
303pub fn key_depth(depth: i64) -> Node {
304    key_args(&[Value::from(depth)])
305}
306
307/// The value is replaced with the path `depth` levels up, joined by `sep`.
308pub fn key_join(depth: i64, sep: impl Into<String>) -> Node {
309    key_args(&[Value::from(depth), Value::Str(sep.into())])
310}
311
312/// `key` from raw arguments: a numeric argument is the depth, a string the
313/// separator, as the string form of a spec supplies them.
314pub fn key_args(args: &[Value]) -> Node {
315    let mut depth: Option<i64> = None;
316    let mut sep: Option<String> = None;
317    for a in args {
318        match a {
319            Value::Str(s) => sep = Some(s.clone()),
320            Value::Num(f) if f.is_finite() => depth = Some(f.trunc() as i64),
321            _ => {}
322        }
323    }
324    // A depth without a separator yields a path slice, so the node must be
325    // an array to accept it.
326    let mut n = Node::of(if depth.is_some() && sep.is_none() {
327        Kind::Array
328    } else {
329        Kind::String
330    });
331    n.befores.push(validator(
332        "Key",
333        Some("Key()".to_string()),
334        args.to_vec(),
335        move |state, update| {
336            // The canonical path is [root, k1, ..., kn]; the leading root
337            // slot is kept so the index and slice arithmetic match.
338            let path = state.path_keys();
339            let mut ts_path: Vec<Value> = Vec::with_capacity(path.len() + 1);
340            ts_path.push(Value::Undefined);
341            ts_path.extend(path.iter().cloned().map(Value::Str));
342            let l = ts_path.len() as i64;
343            match (depth, &sep) {
344                (None, None) => {
345                    // The parent key. With no parent (the root, or a top-level
346                    // property) the slot is the root, and the value is left.
347                    if path.len() >= 2 {
348                        update.val = Some(Value::Str(path[path.len() - 2].clone()));
349                    }
350                }
351                (Some(d), sep) => {
352                    let lo = if d >= 0 { l - 1 - d } else { l - 1 };
353                    let hi = if d < 0 { l } else { l - 1 };
354                    let sl = js_slice(&ts_path, lo, hi);
355                    update.val = Some(match sep {
356                        Some(sep) => {
357                            let parts: Vec<String> = sl
358                                .iter()
359                                .map(|e| match e {
360                                    Value::Str(s) => s.clone(),
361                                    _ => String::new(),
362                                })
363                                .collect();
364                            Value::Str(parts.join(sep))
365                        }
366                        None => Value::Arr(sl),
367                    });
368                }
369                (None, Some(_)) => {}
370            }
371            true
372        },
373    ));
374    n
375}
376
377/// `Array.prototype.slice` index semantics: a negative bound counts from
378/// the end, out-of-range bounds clamp, and an empty range is empty.
379fn js_slice(arr: &[Value], start: i64, end: i64) -> Vec<Value> {
380    let n = arr.len() as i64;
381    let clamp = |i: i64| if i < 0 { (n + i).max(0) } else { i.min(n) };
382    let (s, e) = (clamp(start), clamp(end));
383    if s >= e {
384        return Vec::new();
385    }
386    arr[s as usize..e as usize].to_vec()
387}
388
389/// Whatever fails inside is replaced with the fallback, raising nothing.
390pub fn catch(fallback: impl Into<Value>, spec: impl Into<Spec>) -> Node {
391    buildize(spec).catch(fallback)
392}
393
394/// A valid value is replaced with a function of it.
395pub fn transform<F>(f: F, spec: impl Into<Spec>) -> Node
396where
397    F: Fn(Value, &mut State<'_>) -> Value + Send + Sync + 'static,
398{
399    buildize(spec).transform(f)
400}
401
402/// A description, read back from the node's meta.
403pub fn describe(description: impl Into<String>, spec: impl Into<Spec>) -> Node {
404    buildize(spec).describe(description)
405}
406
407/// The value is converted to the node's kind where the conversion is
408/// unambiguous, before the type check.
409pub fn coerce(spec: impl Into<Spec>) -> Node {
410    buildize(spec).coerce()
411}
412
413/// A string in email address form.
414pub fn email(spec: impl Into<Spec>) -> Node {
415    buildize(spec).email()
416}
417
418/// An absolute URL.
419pub fn url(spec: impl Into<Spec>) -> Node {
420    buildize(spec).url()
421}
422
423/// A UUID in 8-4-4-4-12 hex form.
424pub fn uuid(spec: impl Into<Spec>) -> Node {
425    buildize(spec).uuid()
426}
427
428/// A strict ISO 8601 date-time string.
429pub fn date_time(spec: impl Into<Spec>) -> Node {
430    buildize(spec).date_time()
431}
432
433/// An IPv4 or IPv6 address.
434pub fn ip(spec: impl Into<Spec>) -> Node {
435    buildize(spec).ip()
436}
437
438/// A dotted-quad IPv4 address.
439pub fn ipv4(spec: impl Into<Spec>) -> Node {
440    buildize(spec).ipv4()
441}
442
443/// An IPv6 address in RFC 4291 text form.
444pub fn ipv6(spec: impl Into<Spec>) -> Node {
445    buildize(spec).ipv6()
446}
447
448/// What `type_` takes its kind from.
449pub enum TypeRef {
450    Kind(Kind),
451    Node(Box<Node>),
452}
453
454impl From<Kind> for TypeRef {
455    fn from(k: Kind) -> Self {
456        TypeRef::Kind(k)
457    }
458}
459impl From<Token> for TypeRef {
460    fn from(t: Token) -> Self {
461        TypeRef::Kind(t.kind())
462    }
463}
464impl From<&str> for TypeRef {
465    fn from(name: &str) -> Self {
466        TypeRef::Kind(Kind::from_name(name).unwrap_or(Kind::Any))
467    }
468}
469impl From<Node> for TypeRef {
470    fn from(n: Node) -> Self {
471        TypeRef::Node(Box::new(n))
472    }
473}
474
475/// `refer` options.
476#[derive(Clone, Debug, Default)]
477pub struct ReferOptions {
478    /// Substitute even when the value is absent (not for self-recursion).
479    pub fill: bool,
480    /// A name with no `define` is an error, rather than a `refer` that does
481    /// nothing.
482    pub strict: bool,
483}
484
485/// `rename` options.
486#[derive(Clone, Debug, Default)]
487pub struct RenameOptions {
488    /// Keep the original key as well as writing under the new name.
489    pub keep: bool,
490    /// Alternative source keys to read from when the renamed key is missing.
491    pub claim: Vec<String>,
492}
493
494/// Whether a bound is a finite number: a number, a date, or a string that
495/// reads as a number, as the canonical `+size` reads it.
496pub(crate) fn bound_arg(v: &Value) -> Option<f64> {
497    match v {
498        Value::Num(f) if f.is_finite() => Some(*f),
499        Value::Date(ms) => Some(*ms as f64),
500        Value::Str(s) => s.trim().parse::<f64>().ok().filter(|f| f.is_finite()),
501        _ => None,
502    }
503}
504
505/// A bound argument rendered as JavaScript renders it.
506pub(crate) fn num_text(v: &Value) -> String {
507    match v {
508        Value::Num(f) => js_number(*f),
509        Value::Str(s) => s.clone(),
510        Value::Date(ms) => js_date_string(*ms),
511        other => json_render(other),
512    }
513}
514
515/// Whether a bound compares the value itself (a number, or a date by its
516/// time value) rather than a length or key count.
517pub(crate) fn is_numeric(v: &Value) -> bool {
518    matches!(v, Value::Num(_) | Value::Date(_))
519}
520
521/// The size a bound measures: a number itself, a date's time value, the
522/// length of a string (in UTF-16 units, as JavaScript counts) or array, the
523/// key count of an object. None when the value has no size.
524pub(crate) fn value_len(v: &Value) -> Option<f64> {
525    match v {
526        Value::Date(ms) => Some(*ms as f64),
527        Value::Num(f) => Some(*f),
528        Value::Str(s) => Some(s.encode_utf16().count() as f64),
529        Value::Arr(a) => Some(a.len() as f64),
530        Value::Obj(m) => Some(m.len() as f64),
531        _ => None,
532    }
533}
534
535/// A measured size, or NaN when the value has none: a boolean or null has
536/// no length, and the message says "(was NaN)" rather than nothing.
537fn size_text(size: Option<f64>) -> String {
538    size.map(js_number).unwrap_or_else(|| "NaN".to_string())
539}
540
541/// Whether the node declares a concrete type that this value does not have.
542pub(crate) fn type_will_fail(n: &Node, v: &Value) -> bool {
543    match n.kind {
544        Kind::String | Kind::Regexp => !matches!(v, Value::Str(_)),
545        Kind::Number => !matches!(v, Value::Num(f) if !f.is_nan()),
546        Kind::Boolean => !matches!(v, Value::Bool(_)),
547        Kind::Object => !matches!(v, Value::Obj(_)),
548        Kind::Array => !matches!(v, Value::Arr(_)),
549        Kind::Function => !matches!(v, Value::Func(_)),
550        Kind::Null => !v.is_null(),
551        Kind::NaN => !matches!(v, Value::Num(f) if f.is_nan()),
552        Kind::Integer => !matches!(v, Value::Num(f) if is_integer(*f)),
553        Kind::Date => !matches!(v, Value::Date(_)),
554        Kind::BigInt => !matches!(v, Value::BigInt(_)),
555        _ => false,
556    }
557}
558
559/// Whether a size bound should stand aside and let the rest of validation
560/// speak: the value is of the wrong type, so the structural check is about
561/// to report that and a bound message would mask it; or the value is absent
562/// on a node that does not require it, which is dropped.
563pub(crate) fn bound_defers(state: &State<'_>) -> bool {
564    let n = state.node;
565    (state.absent && (n.skippable || !n.required)) || type_will_fail(n, state.value)
566}
567
568#[derive(Clone, Copy)]
569enum Bound {
570    Min,
571    Max,
572    Above,
573    Below,
574}
575
576impl Bound {
577    fn name(self) -> &'static str {
578        match self {
579            Bound::Min => "Min",
580            Bound::Max => "Max",
581            Bound::Above => "Above",
582            Bound::Below => "Below",
583        }
584    }
585
586    fn mark(self) -> i64 {
587        match self {
588            Bound::Min => 4011,
589            Bound::Max => 4012,
590            Bound::Above => 4013,
591            Bound::Below => 4014,
592        }
593    }
594
595    fn holds(self, limit: f64, size: f64) -> bool {
596        match self {
597            Bound::Min => limit <= size,
598            Bound::Max => size <= limit,
599            Bound::Above => limit < size,
600            Bound::Below => size < limit,
601        }
602    }
603
604    fn text(self, numeric: bool, bound: &str, size: &str) -> String {
605        match self {
606            Bound::Min | Bound::Max => {
607                let lenpart = if numeric { "" } else { "length " };
608                let word = if matches!(self, Bound::Min) {
609                    "minimum"
610                } else {
611                    "maximum"
612                };
613                format!(
614                    "Value \"$VALUE\" for property \"$PATH\" must be a {} {}of {} (was {}).",
615                    word, lenpart, bound, size
616                )
617            }
618            Bound::Above | Bound::Below => {
619                let verb = if numeric { "be" } else { "have length" };
620                let word = if matches!(self, Bound::Above) {
621                    "above"
622                } else {
623                    "below"
624                };
625                format!(
626                    "Value \"$VALUE\" for property \"$PATH\" must {} {} {} (was {}).",
627                    verb, word, bound, size
628                )
629            }
630        }
631    }
632}
633
634fn bound_node(kind: Bound, bound: Value) -> Node {
635    let Some(limit) = bound_arg(&bound) else {
636        return fault_node(format!("Shape: {} needs a number", kind.name()));
637    };
638    let text = num_text(&bound);
639    let mut n = any();
640    n.befores.push(validator(
641        kind.name(),
642        Some(format!("{}({})", kind.name(), text)),
643        vec![bound],
644        move |state, update| {
645            if bound_defers(state) {
646                return true;
647            }
648            let size = value_len(state.value);
649            if let Some(s) = size {
650                if kind.holds(limit, s) {
651                    return true;
652                }
653            }
654            update.why = Some(kind.name().to_string());
655            update.done = true;
656            update.mark = kind.mark();
657            update.err = Some(UpdateErr::Text(kind.text(
658                is_numeric(state.value),
659                &text,
660                &size_text(size),
661            )));
662            false
663        },
664    ));
665    n
666}
667
668fn len_node(length: Value) -> Node {
669    let whole = match &length {
670        Value::Num(f) if f.is_finite() && *f >= 0.0 && f.fract() == 0.0 => Some(*f),
671        _ => None,
672    };
673    let Some(limit) = whole else {
674        return fault_node("Shape: Len needs a whole number of zero or more");
675    };
676    let text = js_number(limit);
677    let mut n = any();
678    n.befores.push(validator(
679        "Len",
680        Some(format!("Len({})", text)),
681        vec![length],
682        move |state, update| {
683            if bound_defers(state) {
684                return true;
685            }
686            let size = value_len(state.value);
687            if size == Some(limit) {
688                return true;
689            }
690            let suffix = if is_numeric(state.value) {
691                ""
692            } else {
693                " in length"
694            };
695            update.why = Some("Len".to_string());
696            update.done = true;
697            update.mark = 4015;
698            update.err = Some(UpdateErr::Text(format!(
699                "Value \"$VALUE\" for property \"$PATH\" must be exactly {}{} (was {}).",
700                text,
701                suffix,
702                size_text(size)
703            )));
704            false
705        },
706    ));
707    n
708}
709
710/// The literals of an Exact, dequoted: `admin, user`; `1, a, true, null`.
711pub(crate) fn format_list(vals: &[Value]) -> String {
712    vals.iter()
713        .map(|v| match v {
714            Value::Null => "null".to_string(),
715            Value::Str(s) => s.clone(),
716            Value::Num(f) => js_number(*f),
717            Value::Undefined => "undefined".to_string(),
718            other => json_render(other),
719        })
720        .collect::<Vec<_>>()
721        .join(", ")
722}
723
724impl Node {
725    /// Fold another builder's result in: its validators, or the fault it
726    /// became when its argument was wrong.
727    fn adopt(mut self, other: Node) -> Node {
728        if is_fault(&other) {
729            self.kind = Kind::Never;
730            self.fault_msg = other.fault_msg;
731            self.arg_fault = true;
732            return self;
733        }
734        self.befores.extend(other.befores);
735        self
736    }
737
738    pub fn required(mut self) -> Node {
739        self.required = true;
740        self.required_set = true;
741        self.skippable = false;
742        self
743    }
744
745    pub fn optional(mut self) -> Node {
746        self.required = false;
747        self.required_set = true;
748        self
749    }
750
751    /// Optional with the default; named to leave `Default::default` alone.
752    /// An untyped node is built over the default instead, and so takes the
753    /// default's kind, keeping the checks and flags it carried.
754    pub fn default_to(mut self, dval: impl Into<Value>) -> Node {
755        let dval = dval.into();
756        if self.kind == Kind::Any && !dval.is_undefined() {
757            let mut base = normalize(Spec::Value(dval.clone()));
758            let mut befores = std::mem::take(&mut self.befores);
759            befores.append(&mut base.befores);
760            base.befores = befores;
761            let mut afters = std::mem::take(&mut self.afters);
762            afters.append(&mut base.afters);
763            base.afters = afters;
764            base.has_exact = self.has_exact;
765            base.exact_vals = std::mem::take(&mut self.exact_vals);
766            base.empty = self.empty;
767            base.nullable = self.nullable;
768            base.silent = self.silent;
769            base.fault_msg = self.fault_msg.take();
770            base.arg_fault = self.arg_fault;
771            base.meta.extend(std::mem::take(&mut self.meta));
772            self = base;
773        }
774        self.required = false;
775        self.required_set = true;
776        self.skippable = false;
777        self.has_default = true;
778        self.default = dval;
779        self
780    }
781
782    pub fn skip(mut self) -> Node {
783        self.required = false;
784        self.required_set = true;
785        self.skippable = true;
786        self
787    }
788
789    pub fn ignore(mut self) -> Node {
790        self.required = false;
791        self.required_set = true;
792        self.skippable = true;
793        self.silent = true;
794        self
795    }
796
797    pub fn empty(mut self) -> Node {
798        self.empty = true;
799        self
800    }
801
802    pub fn nullable(mut self) -> Node {
803        self.nullable = true;
804        self
805    }
806
807    pub fn open(mut self) -> Node {
808        if self.kind == Kind::Object && self.obj_rest.is_none() {
809            self.obj_rest = Some(Box::new(Node::of(Kind::Any)));
810        }
811        self
812    }
813
814    pub fn closed(mut self) -> Node {
815        self.obj_rest = None;
816        if self.kind == Kind::Array && self.arr_children.is_empty() {
817            if let Some(c) = self.arr_child.take() {
818                // A single-shape array made fixed: a tuple of one.
819                self.arr_children = vec![*c];
820            }
821        }
822        self
823    }
824
825    pub fn child(mut self, child: impl Into<Spec>) -> Node {
826        let cn = Box::new(buildize(child));
827        match self.kind {
828            Kind::Array => self.arr_child = Some(cn),
829            Kind::Object => self.obj_rest = Some(cn),
830            _ => {
831                self.kind = Kind::Object;
832                self.obj_rest = Some(cn);
833            }
834        }
835        self
836    }
837
838    pub fn rest(mut self, child: impl Into<Spec>) -> Node {
839        self.kind = Kind::Array;
840        // The rest replaces a plain element shape, as it does in TypeScript,
841        // where Rest sets the one child an array has: Rest(Number, [String])
842        // is an array of numbers. Fixed positions are a tuple, and are kept.
843        self.arr_child = None;
844        self.arr_rest = Some(Box::new(buildize(child)));
845        self
846    }
847
848    pub fn fault(mut self, msg: impl Into<String>) -> Node {
849        self.fault_msg = Some(msg.into());
850        self
851    }
852
853    pub fn never(mut self) -> Node {
854        self.kind = Kind::Never;
855        self
856    }
857
858    /// The value may be anything.
859    pub fn any(mut self) -> Node {
860        self.kind = Kind::Any;
861        self
862    }
863
864    /// Adopt the reference type's kind and its required, skippable and
865    /// default state. Structural children are deliberately not copied:
866    /// `type_(Object)` is a closed object and `type_(Array)` accepts any
867    /// elements.
868    pub fn type_(mut self, kind: impl Into<TypeRef>) -> Node {
869        let tn = match kind.into() {
870            TypeRef::Kind(k) => type_token_node(k),
871            TypeRef::Node(n) => *n,
872        };
873        // Any keeps the value it is given as its default, as `Any(0)` does
874        // in TypeScript; the other tokens bring their own.
875        let keep = tn.kind == Kind::Any && self.has_default && !self.default.is_undefined();
876        self.kind = tn.kind;
877        self.kind_set = true;
878        self.required = tn.required;
879        self.required_set = tn.required_set;
880        self.skippable = tn.skippable;
881        if !keep {
882            self.has_default = tn.has_default;
883            self.default = tn.default;
884            self.literal = tn.literal;
885        }
886        self
887    }
888
889    pub fn string(self) -> Node {
890        self.type_(Kind::String)
891    }
892    pub fn number(self) -> Node {
893        self.type_(Kind::Number)
894    }
895    pub fn boolean(self) -> Node {
896        self.type_(Kind::Boolean)
897    }
898    pub fn object(self) -> Node {
899        self.type_(Kind::Object)
900    }
901    pub fn array(self) -> Node {
902        self.type_(Kind::Array)
903    }
904    pub fn function(self) -> Node {
905        self.type_(Kind::Function)
906    }
907    pub fn integer(self) -> Node {
908        self.type_(Kind::Integer)
909    }
910    pub fn date(self) -> Node {
911        self.type_(Kind::Date)
912    }
913
914    /// A function-typed value; the required state is kept.
915    pub fn func(mut self) -> Node {
916        self.kind = Kind::Function;
917        self
918    }
919
920    pub fn exact<I>(mut self, vals: I) -> Node
921    where
922        I: IntoIterator,
923        I::Item: Into<Value>,
924    {
925        let vals: Vec<Value> = vals.into_iter().map(Into::into).collect();
926        self.has_exact = true;
927        self.exact_vals = vals.clone();
928        let list = format_list(&vals);
929        let wanted = vals.clone();
930        self.befores.push(validator(
931            "Exact",
932            Some(format!("Exact({})", list)),
933            vals,
934            move |state, update| {
935                if wanted.iter().any(|w| w == state.value) {
936                    return true;
937                }
938                // The default stands in for an absent value only; a present
939                // null is a value in its own right.
940                if state.absent && state.node.has_default && wanted.contains(&state.node.default) {
941                    return true;
942                }
943                update.why = Some("Exact".to_string());
944                update.mark = 4010;
945                update.err = Some(UpdateErr::Text(format!(
946                    "Value \"$VALUE\" for property \"$PATH\" must be exactly one of: {}",
947                    list
948                )));
949                update.done = true;
950                false
951            },
952        ));
953        self
954    }
955
956    pub fn min(self, bound: impl Into<Value>) -> Node {
957        self.adopt(bound_node(Bound::Min, bound.into()))
958    }
959
960    pub fn max(self, bound: impl Into<Value>) -> Node {
961        self.adopt(bound_node(Bound::Max, bound.into()))
962    }
963
964    pub fn above(self, bound: impl Into<Value>) -> Node {
965        self.adopt(bound_node(Bound::Above, bound.into()))
966    }
967
968    pub fn below(self, bound: impl Into<Value>) -> Node {
969        self.adopt(bound_node(Bound::Below, bound.into()))
970    }
971
972    pub fn len(self, length: impl Into<Value>) -> Node {
973        self.adopt(len_node(length.into()))
974    }
975
976    pub fn check<F>(mut self, f: F) -> Node
977    where
978        F: Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync + 'static,
979    {
980        self.befores.push(validator(
981            "Check",
982            Some("Check()".to_string()),
983            Vec::new(),
984            // An absent value is left to the required check, as in TypeScript.
985            move |state: &mut State<'_>, update: &mut Update| state.absent || f(state, update),
986        ));
987        self
988    }
989
990    pub fn check_re(self, re: Regex) -> Node {
991        self.check_re_src(re.as_str())
992    }
993
994    pub(crate) fn check_re_src(mut self, src: &str) -> Node {
995        let src = src.to_string();
996        let re = match crate::regexp::compile_regexp(&src) {
997            Ok(engine) => engine,
998            Err(msg) => return self.adopt(fault_node(msg)),
999        };
1000        let name = format!("/{}/", src);
1001        let suffix = format!("Check({})", name);
1002        self.befores.push(validator(
1003            &name,
1004            Some(suffix),
1005            Vec::new(),
1006            move |state, update| {
1007                if state.absent {
1008                    return true;
1009                }
1010                if let Value::Str(s) = state.value {
1011                    if re.is_match(s) {
1012                        return true;
1013                    }
1014                }
1015                // No custom text: the default `check "/re/" failed` speaks.
1016                update.why = Some(WHY_CHECK.to_string());
1017                update.mark = MARK_CHECK_TYPE;
1018                false
1019            },
1020        ));
1021        self
1022    }
1023
1024    pub fn before<F>(mut self, f: F) -> Node
1025    where
1026        F: Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync + 'static,
1027    {
1028        self.befores.push(validator(
1029            "Before",
1030            Some("Before()".to_string()),
1031            Vec::new(),
1032            f,
1033        ));
1034        self
1035    }
1036
1037    pub fn after<F>(mut self, f: F) -> Node
1038    where
1039        F: Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync + 'static,
1040    {
1041        self.afters.push(validator(
1042            "After",
1043            Some("After()".to_string()),
1044            Vec::new(),
1045            f,
1046        ));
1047        self
1048    }
1049
1050    pub fn define(mut self, name: impl Into<String>) -> Node {
1051        let name = name.into();
1052        if name.is_empty() {
1053            return fault_node("Shape: Define needs a name");
1054        }
1055        self.define_name = Some(name.clone());
1056        let suffix = format!("Define({})", json_text(&name));
1057        self.befores.push(validator(
1058            "Define",
1059            Some(suffix),
1060            vec![Value::Str(name.clone())],
1061            move |state, _update| {
1062                // The definition met on this call, for a later refer on the
1063                // same context, is the compiled one of this name.
1064                if let Some(d) = state.ctx.defs.get(&name).cloned() {
1065                    state.ctx.refs.insert(name.clone(), d);
1066                }
1067                true
1068            },
1069        ));
1070        self
1071    }
1072
1073    pub fn refer(self, name: impl Into<String>) -> Node {
1074        self.refer_with(name, ReferOptions::default())
1075    }
1076
1077    pub fn refer_with(mut self, name: impl Into<String>, opts: ReferOptions) -> Node {
1078        let name = name.into();
1079        if name.is_empty() {
1080            return fault_node("Shape: Refer needs a name");
1081        }
1082        self.refer_name = Some(name.clone());
1083        self.refer_fill = opts.fill;
1084        self.refer_strict = opts.strict;
1085        let suffix = format!("Refer({})", json_text(&name));
1086        self.befores.push(validator(
1087            "Refer",
1088            Some(suffix),
1089            vec![Value::Str(name.clone())],
1090            move |state, update| {
1091                // An absent value is left alone unless fill asks; a present
1092                // null is a value.
1093                if state.absent && !opts.fill {
1094                    return true;
1095                }
1096                // A define met on this call first, then the schema's own.
1097                let found = state
1098                    .ctx
1099                    .refs
1100                    .get(&name)
1101                    .cloned()
1102                    .or_else(|| state.ctx.defs.get(&name).cloned());
1103                match found {
1104                    Some(rn) => update.node = Some(rn),
1105                    None if opts.strict => {
1106                        update.err = Some(UpdateErr::Text(format!(
1107                            "Value \"$VALUE\" for property \"$PATH\" refers to \"{}\", which is not defined.",
1108                            name
1109                        )));
1110                        return false;
1111                    }
1112                    None => {}
1113                }
1114                true
1115            },
1116        ));
1117        self
1118    }
1119
1120    pub fn rename(self, name: impl Into<String>) -> Node {
1121        self.rename_with(name, RenameOptions::default())
1122    }
1123
1124    pub fn rename_with(mut self, name: impl Into<String>, opts: RenameOptions) -> Node {
1125        let name = name.into();
1126        if name.is_empty() {
1127            return fault_node("Shape: Rename needs a name");
1128        }
1129        self.rename_to = Some(name);
1130        self.rename_keep = opts.keep;
1131        self.rename_claim = opts.claim;
1132        self
1133    }
1134
1135    pub fn catch(self, fallback: impl Into<Value>) -> Node {
1136        catch_node(self, fallback.into())
1137    }
1138
1139    pub fn transform<F>(self, f: F) -> Node
1140    where
1141        F: Fn(Value, &mut State<'_>) -> Value + Send + Sync + 'static,
1142    {
1143        let f: Arc<TransformFn> = Arc::new(f);
1144        transform_node(self, f)
1145    }
1146
1147    pub fn describe(mut self, description: impl Into<String>) -> Node {
1148        self.meta
1149            .insert("description".to_string(), Value::Str(description.into()));
1150        self
1151    }
1152
1153    pub fn coerce(mut self) -> Node {
1154        self.befores.insert(0, coerce_validator());
1155        self
1156    }
1157
1158    pub fn email(self) -> Node {
1159        with_format(self, FMT_EMAIL)
1160    }
1161    pub fn url(self) -> Node {
1162        with_format(self, FMT_URL)
1163    }
1164    pub fn uuid(self) -> Node {
1165        with_format(self, FMT_UUID)
1166    }
1167    pub fn date_time(self) -> Node {
1168        with_format(self, FMT_DATE_TIME)
1169    }
1170    pub fn ip(self) -> Node {
1171        with_format(self, FMT_IP)
1172    }
1173    pub fn ipv4(self) -> Node {
1174        with_format(self, FMT_IPV4)
1175    }
1176    pub fn ipv6(self) -> Node {
1177        with_format(self, FMT_IPV6)
1178    }
1179}
1180
1181#[cfg(test)]
1182mod tests {
1183    use super::*;
1184    use crate::context::Context;
1185    use crate::spec::{arr, null, obj};
1186    use crate::stringify::stringify_node;
1187    use crate::Schema;
1188
1189    fn j(s: &str) -> Value {
1190        Value::from(serde_json::from_str::<serde_json::Value>(s).unwrap())
1191    }
1192
1193    fn run(s: &Schema, input: &str) -> String {
1194        match s.validate(j(input)) {
1195            Ok(v) => serde_json::Value::from(v).to_string(),
1196            Err(e) => format!("ERR {}", e),
1197        }
1198    }
1199
1200    fn at_a(n: impl Into<Spec>) -> Schema {
1201        Schema::new(obj([("a", n.into())]))
1202    }
1203
1204    fn a(s: &str) -> String {
1205        format!("{{\"a\":{}}}", s)
1206    }
1207
1208    #[test]
1209    fn bounds_on_numbers_strings_and_containers() {
1210        let cases: Vec<(Node, &str, &str)> = vec![
1211            (min(3, Token::Number), "5", "{\"a\":5}"),
1212            (min(3, Token::Number), "1", "ERR Value \"1\" for property \"a\" must be a minimum of 3 (was 1)."),
1213            (max(3, Token::Number), "9", "ERR Value \"9\" for property \"a\" must be a maximum of 3 (was 9)."),
1214            (above(3, Token::Number), "3", "ERR Value \"3\" for property \"a\" must be above 3 (was 3)."),
1215            (below(3, Token::Number), "3", "ERR Value \"3\" for property \"a\" must be below 3 (was 3)."),
1216            (len(3, Token::Number), "4", "ERR Value \"4\" for property \"a\" must be exactly 3 (was 4)."),
1217            (min(3, Token::String), "\"hi\"", "ERR Value \"hi\" for property \"a\" must be a minimum length of 3 (was 2)."),
1218            (max(2, Token::String), "\"hey\"", "ERR Value \"hey\" for property \"a\" must be a maximum length of 2 (was 3)."),
1219            (len(3, Token::String), "\"abc\"", "{\"a\":\"abc\"}"),
1220            (len(3, Token::String), "\"ab\"", "ERR Value \"ab\" for property \"a\" must be exactly 3 in length (was 2)."),
1221            (min(2, any()), "[1]", "ERR Value \"[1]\" for property \"a\" must be a minimum length of 2 (was 1)."),
1222            (above(1, any()), "\"a\"", "ERR Value \"a\" for property \"a\" must have length above 1 (was 1)."),
1223            (below(1, any()), "\"ab\"", "ERR Value \"ab\" for property \"a\" must have length below 1 (was 2)."),
1224            (min(2, Token::Object), "{\"x\":1}", "ERR Value \"{x:1}\" for property \"a\" must be a minimum length of 2 (was 1)."),
1225            (min(2, null()), "null", "ERR Value \"null\" for property \"a\" must be a minimum length of 2 (was NaN)."),
1226            (min(2, null()), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type null."),
1227            (min(2, Token::String), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type string."),
1228            (min(2, Token::Integer), "1.5", "ERR Validation failed for property \"a\" with number \"1.5\" because the number is not of type integer."),
1229            (min(2, Token::Integer), "1", "ERR Value \"1\" for property \"a\" must be a minimum of 2 (was 1)."),
1230            (min("2", Token::Number), "1", "ERR Value \"1\" for property \"a\" must be a minimum of 2 (was 1)."),
1231            (min(2, Token::Boolean), "\"x\"", "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type boolean."),
1232            (min(2, true), "true", "ERR Value \"true\" for property \"a\" must be a minimum length of 2 (was NaN)."),
1233            (min(2, Token::Function), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type function."),
1234            (min(2, Token::Array), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type array."),
1235            (min(2, Token::Object), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type object."),
1236            (min(2, f64::NAN), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type nan."),
1237            (min(2, Token::Date), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type date."),
1238            (min(2, Token::BigInt), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type bigint."),
1239            (min(2, buildize(Regex::new("^a").unwrap())), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type string."),
1240            (min(2, buildize(Regex::new("^a").unwrap())), "\"abc\"", "{\"a\":\"abc\"}"),
1241            (optional(min(2, Token::Number)), "{}", "{}"),
1242            (optional(len(2, Token::Number)), "{}", "{}"),
1243            (max(3, Token::String), "\"hi\"", "{\"a\":\"hi\"}"),
1244            (above(3, Token::Number), "4", "{\"a\":4}"),
1245            (below(3, Token::Number), "2", "{\"a\":2}"),
1246            (len(2, any()), "[1,2]", "{\"a\":[1,2]}"),
1247        ];
1248        for (n, input, want) in cases {
1249            let s = at_a(n);
1250            let got = if input == "{}" {
1251                run(&s, "{}")
1252            } else {
1253                run(&s, &a(input))
1254            };
1255            assert_eq!(got, want.replace("{}", "{\"a\":0}"), "{}", input);
1256        }
1257        let s = at_a(min(3, Token::Number));
1258        assert!(!s.valid(&j(&a("1"))));
1259        let e = &s.error(&j(&a("1")))[0];
1260        assert_eq!((e.why.as_str(), e.mark), ("Min", 4011));
1261        assert_eq!(s.error(&j(&a("\"x\"")))[0].why, "type");
1262        assert_eq!(at_a(max(3, any())).error(&j(&a("9")))[0].mark, 4012);
1263        assert_eq!(at_a(above(3, any())).error(&j(&a("1")))[0].mark, 4013);
1264        assert_eq!(at_a(below(3, any())).error(&j(&a("9")))[0].mark, 4014);
1265        assert_eq!(at_a(len(3, any())).error(&j(&a("9")))[0].mark, 4015);
1266
1267        // Dates compare by their time value.
1268        let s = at_a(min(Value::Date(1000), Token::Date));
1269        let dated =
1270            |ms: i64| Value::Obj([("a".to_string(), Value::Date(ms))].into_iter().collect());
1271        assert!(s.valid(&dated(2000)));
1272        assert!(!s.valid(&dated(5)));
1273        assert_eq!(num_text(&Value::Date(0)), "1970-01-01T00:00:00.000Z");
1274        assert_eq!(num_text(&Value::Bool(true)), "true");
1275        assert_eq!(value_len(&Value::Bool(true)), None);
1276        assert_eq!(value_len(&Value::Str("é😀".into())), Some(3.0));
1277        assert_eq!(bound_arg(&Value::Bool(true)), None);
1278        assert_eq!(bound_arg(&Value::Str("inf".into())), None);
1279        assert_eq!(bound_arg(&Value::Str(" 2.5 ".into())), Some(2.5));
1280        assert!(!is_numeric(&Value::Str("x".into())));
1281        assert!(!type_will_fail(&any(), &Value::Null));
1282    }
1283
1284    #[test]
1285    fn bad_bound_arguments_become_faults() {
1286        for (n, msg) in [
1287            (min("x", Token::Number), "Shape: Min needs a number"),
1288            (max(true, Token::Number), "Shape: Max needs a number"),
1289            (
1290                above(Value::Null, Token::Number),
1291                "Shape: Above needs a number",
1292            ),
1293            (
1294                below(f64::NAN, Token::Number),
1295                "Shape: Below needs a number",
1296            ),
1297            (
1298                len(-1, Token::Number),
1299                "Shape: Len needs a whole number of zero or more",
1300            ),
1301            (
1302                len(1.5, Token::Number),
1303                "Shape: Len needs a whole number of zero or more",
1304            ),
1305            (
1306                buildize(Token::Number).min("x"),
1307                "Shape: Min needs a number",
1308            ),
1309            (
1310                buildize(Token::Number).max("x"),
1311                "Shape: Max needs a number",
1312            ),
1313            (
1314                buildize(Token::Number).above("x"),
1315                "Shape: Above needs a number",
1316            ),
1317            (
1318                buildize(Token::Number).below("x"),
1319                "Shape: Below needs a number",
1320            ),
1321            (
1322                buildize(Token::Number).len("x"),
1323                "Shape: Len needs a whole number of zero or more",
1324            ),
1325            (define("", Token::Number), "Shape: Define needs a name"),
1326            (refer("", Token::Number), "Shape: Refer needs a name"),
1327            (rename("", Token::Number), "Shape: Rename needs a name"),
1328        ] {
1329            assert_eq!(run(&at_a(n), &a("1")), format!("ERR {}", msg));
1330        }
1331    }
1332
1333    #[test]
1334    fn exact_literals() {
1335        let s = Schema::new(obj([("role", exact(["admin", "user"]))]));
1336        assert_eq!(run(&s, r#"{"role":"user"}"#), r#"{"role":"user"}"#);
1337        assert_eq!(
1338            run(&s, r#"{"role":"root"}"#),
1339            "ERR Value \"root\" for property \"role\" must be exactly one of: admin, user"
1340        );
1341        let e = &s.error(&j(r#"{"role":"root"}"#))[0];
1342        assert_eq!((e.why.as_str(), e.mark), ("Exact", 4010));
1343        assert_eq!(
1344            run(&at_a(exact([Value::from(1), Value::Null])), &a("0")),
1345            "ERR Value \"0\" for property \"a\" must be exactly one of: 1, null"
1346        );
1347        assert_eq!(
1348            run(
1349                &at_a(exact([
1350                    Value::from(1),
1351                    Value::from("a"),
1352                    Value::from(true),
1353                    Value::Null
1354                ])),
1355                &a("0")
1356            ),
1357            "ERR Value \"0\" for property \"a\" must be exactly one of: 1, a, true, null"
1358        );
1359        assert_eq!(
1360            format_list(&[Value::Arr(vec![Value::from(1)]), Value::Undefined]),
1361            "[1], undefined"
1362        );
1363        // The default stands in for an absent value.
1364        let s = at_a(default(2, exact([2, 3])));
1365        assert_eq!(run(&s, "{}"), a("2"));
1366        assert_eq!(run(&s, &a("3")), a("3"));
1367        assert_eq!(
1368            run(&s, &a("4")),
1369            "ERR Value \"4\" for property \"a\" must be exactly one of: 2, 3"
1370        );
1371        assert_eq!(
1372            run(&s, &a("null")),
1373            "ERR Value \"null\" for property \"a\" must be exactly one of: 2, 3"
1374        );
1375        let s = at_a(buildize(Token::String).exact(["x"]));
1376        assert_eq!(run(&s, &a("\"x\"")), a("\"x\""));
1377        assert!(s.node().obj_children["a"].has_exact);
1378        assert_eq!(stringify_node(&exact(["a", "b"]), false), "Exact(a, b)");
1379    }
1380
1381    #[test]
1382    fn checks() {
1383        let s = at_a(check(|st, _| st.value.as_f64().unwrap_or(0.0) > 1.0, any()));
1384        assert_eq!(s.node().obj_children["a"].kind, Kind::Check);
1385        assert_eq!(run(&s, &a("2")), a("2"));
1386        assert_eq!(
1387            run(&s, &a("1")),
1388            "ERR Validation failed for property \"a\" with number \"1\" because check \"Check\" failed."
1389        );
1390        // A check is not called for an absent value: the required check speaks.
1391        assert_eq!(
1392            run(&s, "{}"),
1393            "ERR Validation failed for property \"a\" because the property is missing."
1394        );
1395        let s = at_a(check(|_, _| true, Token::Number));
1396        assert_eq!(
1397            run(&s, "{}"),
1398            "ERR Validation failed for property \"a\" because the property is missing."
1399        );
1400        assert_eq!(s.node().obj_children["a"].kind, Kind::Number);
1401        let re = || Regex::new("^a.+").unwrap();
1402        let s = at_a(check_re(re(), any()));
1403        assert_eq!(run(&s, &a("\"abc\"")), a("\"abc\""));
1404        assert_eq!(
1405            run(&s, &a("\"zzz\"")),
1406            "ERR Validation failed for property \"a\" with string \"zzz\" because check \"/^a.+/\" failed."
1407        );
1408        assert_eq!(
1409            run(&s, &a("1")),
1410            "ERR Validation failed for property \"a\" with number \"1\" because check \"/^a.+/\" failed."
1411        );
1412        assert_eq!(s.error(&j(&a("1")))[0].mark, MARK_CHECK_TYPE);
1413        let s = at_a(check_re(re(), Token::String));
1414        assert_eq!(s.node().obj_children["a"].kind, Kind::String);
1415        assert_eq!(
1416            stringify_node(&check_re(re(), any()), false),
1417            "Check.Check(/^a.+/)"
1418        );
1419        let s = at_a(before(
1420            |_, u| {
1421                u.val = Some(Value::from(9));
1422                true
1423            },
1424            Token::Number,
1425        ));
1426        assert_eq!(run(&s, &a("1")), a("9"));
1427        let s = at_a(after(|_, _| false, Token::Number));
1428        assert_eq!(s.error(&j(&a("1")))[0].check, "After");
1429        assert_eq!(
1430            stringify_node(&after(|_, _| true, before(|_, _| true, any())), false),
1431            "Before().After()"
1432        );
1433    }
1434
1435    #[test]
1436    fn composition() {
1437        let one_ns = || one([Spec::from(Token::Number), Spec::from(Token::String)]);
1438        assert_eq!(run(&at_a(one_ns()), &a("\"x\"")), a("\"x\""));
1439        assert_eq!(
1440            run(&at_a(one_ns()), &a("true")),
1441            "ERR Value \"true\" for property \"a\" does not satisfy one of: Number, String"
1442        );
1443        assert!(!at_a(one_ns()).valid(&j(&a("true"))));
1444        assert!(at_a(one_ns()).valid(&j(&a("1"))));
1445        let e = &at_a(one_ns()).error(&j(&a("true")))[0];
1446        assert_eq!((e.why.as_str(), e.mark), ("One", 4030));
1447        let some_ns = || some([Spec::from(Token::Number), Spec::from(Token::String)]);
1448        assert_eq!(run(&at_a(some_ns()), &a("5")), a("5"));
1449        assert_eq!(
1450            run(&at_a(some_ns()), &a("true")),
1451            "ERR Value \"true\" for property \"a\" does not satisfy any of: Number, String"
1452        );
1453        assert_eq!(at_a(some_ns()).error(&j(&a("true")))[0].mark, 4031);
1454        let all_nm = || all([Spec::from(Token::Number), Spec::from(min(2, any()))]);
1455        assert_eq!(
1456            run(&at_a(all_nm()), &a("1")),
1457            "ERR Value \"1\" for property \"a\" does not satisfy all of: Number, Min(2)"
1458        );
1459        assert_eq!(run(&at_a(all_nm()), &a("5")), a("5"));
1460        assert_eq!(at_a(all_nm()).error(&j(&a("1")))[0].mark, 4032);
1461        assert_eq!(
1462            run(
1463                &at_a(one([Spec::from(Token::Number), Spec::from(min(2, any()))])),
1464                &a("\"x\"")
1465            ),
1466            "ERR Value \"x\" for property \"a\" does not satisfy one of: Number, Min(2)"
1467        );
1468        assert_eq!(
1469            run(
1470                &at_a(all([Spec::from(Token::String), Spec::from(Token::Any)])),
1471                &a("1")
1472            ),
1473            "ERR Value \"1\" for property \"a\" does not satisfy all of: String, Any"
1474        );
1475        assert_eq!(
1476            run(
1477                &at_a(one([
1478                    Spec::from(ignore(min(2, Token::Number))),
1479                    Spec::from(Token::String)
1480                ])),
1481                &a("1")
1482            ),
1483            a("1")
1484        );
1485        assert_eq!(
1486            run(
1487                &at_a(all([
1488                    Spec::from(ignore(min(2, Token::Number))),
1489                    Spec::from(Token::Number)
1490                ])),
1491                &a("1")
1492            ),
1493            a("1")
1494        );
1495        assert_eq!(run(&at_a(optional(one_ns())), "{}"), "{}");
1496        let re = || Regex::new("^a").unwrap();
1497        let one_rn = || one([Spec::from(re()), Spec::from(Token::Number)]);
1498        assert_eq!(run(&at_a(one_rn()), &a("\"abc\"")), a("\"abc\""));
1499        assert_eq!(run(&at_a(one_rn()), &a("5")), a("5"));
1500        assert_eq!(
1501            run(&at_a(one_rn()), &a("true")),
1502            "ERR Value \"true\" for property \"a\" does not satisfy one of: /^a/, Number"
1503        );
1504        assert_eq!(
1505            run(
1506                &at_a(some([Spec::from(re()), Spec::from(Token::Number)])),
1507                &a("true")
1508            ),
1509            "ERR Value \"true\" for property \"a\" does not satisfy any of: /^a/, Number"
1510        );
1511        // Fault applies to One and Some, not All.
1512        assert_eq!(run(&at_a(fault("F", one_ns())), &a("true")), "ERR F");
1513        assert_eq!(run(&at_a(fault("F", some_ns())), &a("true")), "ERR F");
1514        assert_eq!(
1515            run(&at_a(fault("F", all_nm())), &a("1")),
1516            "ERR Value \"1\" for property \"a\" does not satisfy all of: Number, Min(2)"
1517        );
1518        assert!(!at_a(fault("F", one_ns())).valid(&j(&a("true"))));
1519        // Every matching Some branch produces from the original; the last
1520        // one's result stands.
1521        let s = at_a(some([
1522            Spec::from(Token::Number),
1523            Spec::from(coerce(Token::String)),
1524        ]));
1525        assert_eq!(run(&s, &a("5")), a("\"5\""));
1526        // All threads the value through its branches.
1527        let s = at_a(all([
1528            Spec::from(coerce(Token::Number)),
1529            Spec::from(min(2, any())),
1530        ]));
1531        assert_eq!(run(&s, &a("\"5\"")), a("5"));
1532        let s = at_a(all([
1533            Spec::from(coerce(Token::Number)),
1534            Spec::from(min(9, any())),
1535        ]));
1536        assert_eq!(
1537            run(&s, &a("\"5\"")),
1538            "ERR Value \"5\" for property \"a\" does not satisfy all of: Number, Min(9)"
1539        );
1540        // A branch that produces nothing leaves a required composition with
1541        // no value, so the missing property is reported.
1542        let missing = "ERR Validation failed for property \"a\" because the property is missing.";
1543        assert_eq!(
1544            run(&at_a(one([Spec::from(skip(Token::Number))])), "{}"),
1545            missing
1546        );
1547        assert_eq!(
1548            run(&at_a(some([Spec::from(skip(Token::Number))])), "{}"),
1549            missing
1550        );
1551        assert_eq!(
1552            run(&at_a(all([Spec::from(skip(Token::Number))])), "{}"),
1553            missing
1554        );
1555        let mut quiet = one_ns();
1556        quiet.silent = true;
1557        assert_eq!(run(&at_a(quiet), &a("true")), a("true"));
1558    }
1559
1560    #[test]
1561    fn define_and_refer() {
1562        let s = |strict: bool, fill: bool| {
1563            Schema::new(obj([
1564                ("a", Spec::from(define("d", Token::Number))),
1565                (
1566                    "b",
1567                    Spec::from(refer_with("d", ReferOptions { strict, fill }, any())),
1568                ),
1569            ]))
1570        };
1571        assert_eq!(
1572            run(&s(false, false), r#"{"a":1,"b":2}"#),
1573            r#"{"a":1,"b":2}"#
1574        );
1575        assert_eq!(run(&s(true, false), r#"{"a":1,"b":2}"#), r#"{"a":1,"b":2}"#);
1576        assert_eq!(
1577            run(&s(true, false), r#"{"a":1,"b":"x"}"#),
1578            "ERR Validation failed for property \"b\" with string \"x\" because the string is not of type number."
1579        );
1580        assert_eq!(run(&s(false, false), r#"{"a":1}"#), r#"{"a":1}"#);
1581        assert_eq!(
1582            run(&s(false, true), r#"{"a":1}"#),
1583            "ERR Validation failed for property \"b\" because the property is missing."
1584        );
1585        assert!(s(false, false).defs().contains_key("d"));
1586        let lax = at_a(any().refer("nope"));
1587        assert_eq!(run(&lax, &a("2")), a("2"));
1588        let strict = |fill| {
1589            at_a(refer_with(
1590                "nope",
1591                ReferOptions { strict: true, fill },
1592                any(),
1593            ))
1594        };
1595        assert_eq!(
1596            run(&strict(false), &a("2")),
1597            "ERR Value \"2\" for property \"a\" refers to \"nope\", which is not defined."
1598        );
1599        assert_eq!(run(&strict(false), "{}"), "{}");
1600        assert_eq!(run(&strict(true), "{}"), "{}");
1601        assert_eq!(
1602            stringify_node(&define("d", Token::Number), false),
1603            "Number.Define(\"d\")"
1604        );
1605        assert_eq!(stringify_node(&refer("d", any()), false), "Refer(\"d\")");
1606        // A define met on one schema's call serves a refer on another, when
1607        // the calls share a context.
1608        let mut ctx = Context::new();
1609        let first = at_a(define("shared", Token::Number));
1610        first.validate_ctx(j(&a("1")), &mut ctx).unwrap();
1611        let second = at_a(refer("shared", any()));
1612        assert!(second.validate_ctx(j(&a("\"x\"")), &mut ctx).is_err());
1613        assert!(second.validate_ctx(j(&a("3")), &mut ctx).is_ok());
1614    }
1615
1616    #[test]
1617    fn renames() {
1618        let s = at_a(buildize(Token::Number).rename("b"));
1619        assert_eq!(run(&s, &a("1")), r#"{"b":1}"#);
1620        assert_eq!(run(&s, r#"{"a":1,"b":2}"#), r#"{"b":1}"#);
1621        assert!(s.valid(&j(&a("1"))));
1622        let s = at_a(rename_with(
1623            "b",
1624            RenameOptions {
1625                keep: true,
1626                claim: vec![],
1627            },
1628            Token::Number,
1629        ));
1630        assert_eq!(run(&s, &a("1")), r#"{"a":1,"b":1}"#);
1631        let claim = |keep| {
1632            at_a(rename_with(
1633                "b",
1634                RenameOptions {
1635                    keep,
1636                    claim: vec!["old".into(), "older".into()],
1637                },
1638                Token::Number,
1639            ))
1640        };
1641        assert_eq!(run(&claim(false), r#"{"older":1}"#), r#"{"b":1}"#);
1642        assert_eq!(
1643            run(&claim(true), r#"{"old":1}"#),
1644            r#"{"old":1,"a":1,"b":1}"#
1645        );
1646        assert_eq!(run(&claim(false), &a("2")), r#"{"b":2}"#);
1647        assert_eq!(
1648            run(&claim(false), "{}"),
1649            "ERR Validation failed for property \"a\" because the property is missing."
1650        );
1651        assert!(claim(false).valid(&j(r#"{"old":1}"#)));
1652        assert!(!claim(false).valid(&j(r#"{"old":"x"}"#)));
1653        assert!(!claim(false).valid(&j("{}")));
1654        // A renamed child that produced nothing has nothing to move.
1655        assert_eq!(run(&at_a(rename("b", skip(Token::Number))), "{}"), "{}");
1656        assert_eq!(run(&at_a(rename("a", Token::Number)), &a("1")), a("1"));
1657    }
1658
1659    #[test]
1660    fn keys() {
1661        let nested = |n: Node| Schema::new(obj([("a", obj([("b", Spec::from(n))]))]));
1662        assert_eq!(
1663            run(&nested(key()), r#"{"a":{"b":"V"}}"#),
1664            r#"{"a":{"b":"a"}}"#
1665        );
1666        assert_eq!(
1667            run(&nested(key_depth(1)), r#"{"a":{"b":"V"}}"#),
1668            r#"{"a":{"b":["a"]}}"#
1669        );
1670        assert_eq!(
1671            run(&nested(key_join(1, "/")), r#"{"a":{"b":"V"}}"#),
1672            r#"{"a":{"b":"a"}}"#
1673        );
1674        assert_eq!(
1675            run(&nested(key_depth(-1)), r#"{"a":{"b":"V"}}"#),
1676            r#"{"a":{"b":["b"]}}"#
1677        );
1678        assert_eq!(
1679            run(&nested(key_join(0, "/")), r#"{"a":{"b":"V"}}"#),
1680            "ERR Validation failed for property \"a.b\" with string \"\" because an empty string is not allowed."
1681        );
1682        assert_eq!(
1683            run(&nested(key_join(2, "/")), r#"{"a":{"b":"V"}}"#),
1684            r#"{"a":{"b":"/a"}}"#
1685        );
1686        assert_eq!(
1687            run(&nested(key_join(5, ".")), r#"{"a":{"b":"V"}}"#),
1688            r#"{"a":{"b":".a"}}"#
1689        );
1690        assert_eq!(run(&at_a(key()), &a("\"V\"")), a("\"V\""));
1691        assert_eq!(
1692            run(&at_a(key_args(&[Value::from("/")])), &a("\"V\"")),
1693            a("\"V\"")
1694        );
1695        assert_eq!(key_args(&[Value::Null]).kind, Kind::String);
1696        assert_eq!(
1697            js_slice(&[Value::from(1), Value::from(2)], 5, 9),
1698            Vec::<Value>::new()
1699        );
1700        assert_eq!(
1701            js_slice(&[Value::from(1), Value::from(2)], -9, -1),
1702            vec![Value::from(1)]
1703        );
1704        assert_eq!(stringify_node(&key(), false), "String.Key()");
1705    }
1706
1707    #[test]
1708    fn catch_and_transform() {
1709        assert_eq!(run(&at_a(catch(0, Token::Number)), &a("\"x\"")), a("0"));
1710        assert_eq!(run(&at_a(catch(0, Token::Number)), &a("5")), a("5"));
1711        assert_eq!(
1712            run(&at_a(catch("none", min(2, Token::String))), &a("\"x\"")),
1713            a("\"none\"")
1714        );
1715        assert_eq!(
1716            run(&at_a(min(2, catch(0, Token::Number))), &a("\"x\"")),
1717            "ERR Value \"0\" for property \"a\" must be a minimum of 2 (was 0)."
1718        );
1719        assert_eq!(run(&at_a(catch(7, Token::Number)), "{}"), a("7"));
1720        assert_eq!(run(&at_a(optional(catch(7, Token::Number))), "{}"), a("0"));
1721        assert_eq!(
1722            run(&at_a(catch(Value::Null, Token::Number)), &a("\"x\"")),
1723            a("null")
1724        );
1725        assert!(at_a(catch(0, Token::Number)).valid(&j(&a("\"x\""))));
1726        let s = at_a(catch(
1727            Value::Obj(Default::default()),
1728            obj([("x", Spec::from(Token::Number))]),
1729        ));
1730        assert_eq!(run(&s, r#"{"a":{"x":"bad"}}"#), r#"{"a":{}}"#);
1731        assert_eq!(run(&s, r#"{"a":{"x":1}}"#), r#"{"a":{"x":1}}"#);
1732        assert_eq!(
1733            stringify_node(&catch(0, min(2, Token::Number)), false),
1734            "Number.Min(2).Catch(0)"
1735        );
1736        assert_eq!(
1737            stringify_node(&after(|_, _| true, Token::Number).catch("z"), false),
1738            "Number.After().Catch(z)"
1739        );
1740        let dbl = |n: Node| transform(|v, _| Value::Num(v.as_f64().unwrap_or(0.0) * 2.0), n);
1741        assert_eq!(run(&at_a(dbl(buildize(Token::Number))), &a("2")), a("4"));
1742        assert_eq!(
1743            run(&at_a(dbl(buildize(Token::Number))), &a("\"x\"")),
1744            "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number."
1745        );
1746        assert_eq!(
1747            run(&at_a(dbl(min(2, Token::Number))), &a("1")),
1748            "ERR Value \"1\" for property \"a\" must be a minimum of 2 (was 1)."
1749        );
1750        assert!(at_a(dbl(buildize(Token::Number))).valid(&j(&a("2"))));
1751        assert!(!at_a(dbl(buildize(Token::Number))).valid(&j(&a("\"x\""))));
1752        assert_eq!(
1753            stringify_node(&dbl(min(2, Token::Number)), false),
1754            "Number.Min(2).Transform"
1755        );
1756        assert!(catch(0, Token::Number).befores[0].inner.is_some());
1757        // A transform of an absent optional value: nothing produced, nothing
1758        // transformed.
1759        assert_eq!(run(&at_a(dbl(skip(Token::Number))), "{}"), a("0"));
1760    }
1761
1762    #[test]
1763    fn describe_coerce_and_formats() {
1764        let s = at_a(describe("a number", Token::Number));
1765        assert_eq!(
1766            s.node().obj_children["a"].meta.get("description"),
1767            Some(&Value::from("a number"))
1768        );
1769        assert_eq!(
1770            run(&s, &a("\"x\"")),
1771            "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number."
1772        );
1773        let cases: Vec<(Node, &str, &str)> = vec![
1774            (coerce(Token::Number), "\"5\"", "5"),
1775            (coerce(Token::Number), "true", "1"),
1776            (coerce(Token::Number), "\"x\"", "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number."),
1777            (coerce(Token::Number), "\"0x10\"", "ERR Validation failed for property \"a\" with string \"0x10\" because the string is not of type number."),
1778            (coerce(Token::Integer), "\"5.5\"", "ERR Validation failed for property \"a\" with number \"5.5\" because the number is not of type integer."),
1779            (coerce(Token::String), "1.5", "\"1.5\""),
1780            (coerce(Token::String), "1000000", "\"1000000\""),
1781            (coerce(Token::String), "false", "\"false\""),
1782            (coerce(Token::Boolean), "\" TRUE \"", "true"),
1783            (coerce(Token::Boolean), "0", "false"),
1784            (coerce(Token::Boolean), "\"yes\"", "ERR Validation failed for property \"a\" with string \"yes\" because the string is not of type boolean."),
1785            (coerce(Token::Date), "\"2020-01-01T00:00:00Z\"", "\"2020-01-01T00:00:00.000Z\""),
1786            (coerce(Token::Date), "\"2020-01-01T12:30:00.5+02:00\"", "\"2020-01-01T10:30:00.500Z\""),
1787            (coerce(Token::Date), "\"2020-02-30T00:00:00Z\"", "ERR Validation failed for property \"a\" with string \"2020-02-30T00:00:00Z\" because the string is not of type date."),
1788            (coerce(Token::Date), "1577836800000", "\"2020-01-01T00:00:00.000Z\""),
1789            (coerce(min(2, Token::Number)), "\"1\"", "ERR Value \"1\" for property \"a\" must be a minimum of 2 (was 1)."),
1790            (email(any()), "\"a@b.co\"", "\"a@b.co\""),
1791            (email(any()), "\"nope\"", "ERR Value \"nope\" for property \"a\" is not a valid email address."),
1792            (email(any()), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type string."),
1793            (url(any()), "\"https://example.com/a?b=c#d\"", "\"https://example.com/a?b=c#d\""),
1794            (url(any()), "\"example.com\"", "ERR Value \"example.com\" for property \"a\" is not a valid URL."),
1795            (uuid(any()), "\"123e4567-e89b-12d3-a456-426614174000\"", "\"123e4567-e89b-12d3-a456-426614174000\""),
1796            (uuid(any()), "\"123e4567e89b12d3a456426614174000\"", "ERR Value \"123e4567e89b12d3a456426614174000\" for property \"a\" is not a valid UUID."),
1797            (date_time(any()), "\"2020-01-01T00:00:00Z\"", "\"2020-01-01T00:00:00Z\""),
1798            (date_time(any()), "\"2021-02-29T00:00:00Z\"", "ERR Value \"2021-02-29T00:00:00Z\" for property \"a\" is not a valid ISO 8601 date-time."),
1799            (ip(any()), "\"127.0.0.1\"", "\"127.0.0.1\""),
1800            (ip(any()), "\"::1\"", "\"::1\""),
1801            (ip(any()), "\"1.2.3\"", "ERR Value \"1.2.3\" for property \"a\" is not a valid IP address."),
1802            (ipv4(any()), "\"::1\"", "ERR Value \"::1\" for property \"a\" is not a valid IPv4 address."),
1803            (ipv6(any()), "\"1.2.3.4\"", "ERR Value \"1.2.3.4\" for property \"a\" is not a valid IPv6 address."),
1804            (ipv6(any()), "\"::ffff:192.168.1.1\"", "\"::ffff:192.168.1.1\""),
1805            (email(min(10, Token::String)), "\"nope\"", "ERR Value \"nope\" for property \"a\" must be a minimum length of 10 (was 4).\nValue \"nope\" for property \"a\" is not a valid email address."),
1806            (fault("boom", min(2, Token::Number)), "1", "ERR Value \"1\" for property \"a\" must be a minimum of 2 (was 1)."),
1807            (fault("boom", email(any())), "1", "ERR boom"),
1808            (
1809                email(Token::Number),
1810                "1",
1811                "ERR Value \"1\" for property \"a\" is not a valid email address.",
1812            ),
1813            (
1814                email(Token::Number),
1815                "\"x\"",
1816                "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number.",
1817            ),
1818            (buildize(Token::String).email().url().uuid().date_time().ip().ipv4().ipv6(), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type string."),
1819            (buildize(Token::Number).coerce(), "\"7\"", "7"),
1820            (buildize(Token::Number).describe("n"), "7", "7"),
1821        ];
1822        for (n, input, want) in cases {
1823            let got = run(&at_a(n), &a(input));
1824            let want = if want.starts_with("ERR") {
1825                want.to_string()
1826            } else {
1827                a(want)
1828            };
1829            assert_eq!(got, want, "{}", input);
1830        }
1831        assert_eq!(
1832            run(&at_a(email(any())), "{}"),
1833            "ERR Validation failed for property \"a\" because the property is missing."
1834        );
1835        assert_eq!(run(&at_a(optional(email(any()))), "{}"), a("\"\""));
1836        let e = &at_a(email(any())).error(&j(&a("\"nope\"")))[0];
1837        assert_eq!((e.why.as_str(), e.mark), ("Email", 4000));
1838        assert!(!at_a(email(any())).valid(&j(&a("\"nope\""))));
1839        assert_eq!(stringify_node(&email(any()), false), "String.Email");
1840    }
1841
1842    #[test]
1843    fn types_and_structure() {
1844        assert_eq!(run(&at_a(type_(Kind::Number, any())), &a("3")), a("3"));
1845        assert_eq!(
1846            run(&at_a(type_(Token::Number, any())), &a("\"x\"")),
1847            "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number."
1848        );
1849        assert_eq!(
1850            run(&at_a(type_("String", any())), &a("3")),
1851            "ERR Validation failed for property \"a\" with number \"3\" because the number is not of type string."
1852        );
1853        assert_eq!(
1854            run(&Schema::new(type_("Object", any())), "1"),
1855            "ERR Validation failed for number \"1\" because the number is not of type object."
1856        );
1857        assert_eq!(
1858            run(&Schema::new(type_("Object", any())), r#"{"z":1}"#),
1859            "ERR Validation failed for object \"{z:1}\" because the property \"z\" is not allowed."
1860        );
1861        assert_eq!(type_("nonsense", any()).kind, Kind::Any);
1862        assert_eq!(type_(buildize(Token::Integer), any()).kind, Kind::Integer);
1863        assert_eq!(type_(min(2, any()), any()).kind, Kind::Any);
1864        for (n, k) in [
1865            (any().string(), Kind::String),
1866            (any().number(), Kind::Number),
1867            (any().boolean(), Kind::Boolean),
1868            (any().object(), Kind::Object),
1869            (any().array(), Kind::Array),
1870            (any().function(), Kind::Function),
1871            (any().integer(), Kind::Integer),
1872            (any().date(), Kind::Date),
1873            (buildize(Token::Number).any(), Kind::Any),
1874        ] {
1875            assert_eq!(n.kind, k);
1876        }
1877        assert_eq!(
1878            run(&Schema::new(obj([("n", Spec::from(func(any())))])), "{}"),
1879            "{}"
1880        );
1881        assert_eq!(
1882            run(
1883                &Schema::new(obj([("n", Spec::from(Token::Function))])),
1884                "{}"
1885            ),
1886            "ERR Validation failed for property \"n\" because the property is missing."
1887        );
1888        assert_eq!(buildize(Token::Number).func().kind, Kind::Function);
1889
1890        assert!(!open(Token::Number).is_open());
1891        let tuple = closed(arr([Spec::from(Token::Number)]));
1892        assert_eq!(tuple.arr_children.len(), 1);
1893        assert_eq!(run(&at_a(tuple.clone()), &a("[1]")), a("[1]"));
1894        assert!(!at_a(tuple).valid(&j(&a("[1,2]"))));
1895        assert!(closed(arr([Spec::from(1), Spec::from(2)]))
1896            .arr_child
1897            .is_none());
1898        let c = child(Token::Number, Token::Number);
1899        assert!(c.kind == Kind::Object && c.obj_rest.is_some());
1900        assert!(buildize(Token::Array)
1901            .child(Token::Number)
1902            .arr_child
1903            .is_some());
1904        assert!(buildize(Token::Object)
1905            .child(Token::Number)
1906            .obj_rest
1907            .is_some());
1908        assert_eq!(
1909            run(
1910                &at_a(rest(Token::Number, arr([Spec::from(1)]))),
1911                &a("[1,2,3]")
1912            ),
1913            a("[1,2,3]")
1914        );
1915        assert_eq!(run(&at_a(rest(Token::Number, any())), &a("[2]")), a("[2]"));
1916        assert!(!at_a(rest(Token::Number, arr([Spec::from(1)]))).valid(&j(&a("[1,\"x\"]"))));
1917        assert_eq!(default_of("x").kind, Kind::String);
1918        assert_eq!(run(&at_a(default_of("x")), "{}"), a("\"x\""));
1919        assert_eq!(run(&at_a(empty(any())), &a("\"\"")), a("\"\""));
1920        assert_eq!(run(&at_a(empty(any())), &a("0")), a("0"));
1921        assert_eq!(run(&at_a(ignore(empty(any()))), &a("0")), a("0"));
1922        assert_eq!(
1923            run(&at_a(required(null())), "{}"),
1924            "ERR Validation failed for property \"a\" because the property is missing."
1925        );
1926        assert_eq!(run(&at_a(skip(null())), "{}"), "{}");
1927        assert_eq!(run(&at_a(min(2, null())), "{}"), a("null"));
1928        assert_eq!(
1929            run(&at_a(required(f64::NAN)), "{}"),
1930            "ERR Validation failed for property \"a\" because the property is missing."
1931        );
1932        assert_eq!(run(&at_a(min(2, f64::NAN)), "{}"), a("null"));
1933        assert_eq!(run(&at_a(never(Token::String)), "{}"), "ERR Validation failed for property \"a\" with value \"undefined\" because no value is allowed.");
1934        assert_eq!(
1935            run(&at_a(nullable(closed(obj::<&str, Spec>([])))), &a("null")),
1936            a("null")
1937        );
1938        assert_eq!(run(&at_a(optional(nullable(Token::Number))), "{}"), a("0"));
1939    }
1940
1941    #[test]
1942    fn untyped_defaults_take_the_default_kind() {
1943        let cases: Vec<(Node, &str, &str)> = vec![
1944            (default(2, required(any())), "\"x\"", "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number."),
1945            (default(2, required(any())), "{}", "2"),
1946            (default(2, describe("two", required(any()))), "3", "3"),
1947            (default(2, fault("not two", exact([2]))), "3", "ERR Value \"3\" for property \"a\" must be exactly one of: 2"),
1948            (default(2, exact([2, 3])), "3", "3"),
1949            (default(2, nullable(required(any()))), "null", "null"),
1950            (default("x", empty(required(any()))), "\"\"", "\"\""),
1951            (default(2, after(|_, _| false, any())), "3", "ERR Validation failed for property \"a\" with number \"3\" because check \"After\" failed."),
1952            // Default clears skippable, so an Ignore's silence remains alone.
1953            (default(2, ignore(any())), "\"x\"", "\"x\""),
1954            (default(Value::Undefined, any()), "\"x\"", "\"x\""),
1955            (default(7, Token::Number), "{}", "7"),
1956        ];
1957        for (n, input, want) in cases {
1958            let got = if input == "{}" {
1959                run(&at_a(n), "{}")
1960            } else {
1961                run(&at_a(n), &a(input))
1962            };
1963            let want = if want.starts_with("ERR") || want == "{}" {
1964                want.to_string()
1965            } else {
1966                a(want)
1967            };
1968            assert_eq!(got, want, "{}", input);
1969        }
1970        let d = default(2, describe("two", any()));
1971        assert_eq!(d.meta.get("description"), Some(&Value::from("two")));
1972    }
1973}