1use 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
23pub fn buildize(spec: impl Into<Spec>) -> Node {
25 normalize(spec.into())
26}
27
28pub fn any() -> Node {
30 Node::of(Kind::Any)
31}
32
33pub(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
61pub fn required(spec: impl Into<Spec>) -> Node {
66 buildize(spec).required()
67}
68
69pub fn optional(spec: impl Into<Spec>) -> Node {
71 buildize(spec).optional()
72}
73
74pub fn default(dval: impl Into<Value>, spec: impl Into<Spec>) -> Node {
78 buildize(spec).default_to(dval)
79}
80
81pub fn default_of(dval: impl Into<Value>) -> Node {
83 let dval = dval.into();
84 normalize(Spec::Value(dval.clone())).default_to(dval)
85}
86
87pub fn skip(spec: impl Into<Spec>) -> Node {
89 buildize(spec).skip()
90}
91
92pub fn ignore(spec: impl Into<Spec>) -> Node {
94 buildize(spec).ignore()
95}
96
97pub fn empty(spec: impl Into<Spec>) -> Node {
100 buildize(spec).empty()
101}
102
103pub fn nullable(spec: impl Into<Spec>) -> Node {
105 buildize(spec).nullable()
106}
107
108pub fn open(spec: impl Into<Spec>) -> Node {
110 buildize(spec).open()
111}
112
113pub fn closed(spec: impl Into<Spec>) -> Node {
116 buildize(spec).closed()
117}
118
119pub fn child(child: impl Into<Spec>, spec: impl Into<Spec>) -> Node {
121 buildize(spec).child(child)
122}
123
124pub fn rest(child: impl Into<Spec>, spec: impl Into<Spec>) -> Node {
126 buildize(spec).rest(child)
127}
128
129pub fn fault(msg: impl Into<String>, spec: impl Into<Spec>) -> Node {
131 buildize(spec).fault(msg)
132}
133
134pub fn never(spec: impl Into<Spec>) -> Node {
136 buildize(spec).never()
137}
138
139pub fn type_(kind: impl Into<TypeRef>, spec: impl Into<Spec>) -> Node {
142 buildize(spec).type_(kind)
143}
144
145pub fn func(spec: impl Into<Spec>) -> Node {
148 buildize(spec).func()
149}
150
151pub fn exact<I>(vals: I) -> Node
153where
154 I: IntoIterator,
155 I::Item: Into<Value>,
156{
157 any().exact(vals)
158}
159
160pub fn min(bound: impl Into<Value>, spec: impl Into<Spec>) -> Node {
162 buildize(spec).min(bound)
163}
164
165pub fn max(bound: impl Into<Value>, spec: impl Into<Spec>) -> Node {
167 buildize(spec).max(bound)
168}
169
170pub fn above(bound: impl Into<Value>, spec: impl Into<Spec>) -> Node {
172 buildize(spec).above(bound)
173}
174
175pub fn below(bound: impl Into<Value>, spec: impl Into<Spec>) -> Node {
177 buildize(spec).below(bound)
178}
179
180pub fn len(length: impl Into<Value>, spec: impl Into<Spec>) -> Node {
182 buildize(spec).len(length)
183}
184
185pub 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
199pub fn check_re(re: Regex, spec: impl Into<Spec>) -> Node {
202 check_re_src(re.as_str(), spec)
203}
204
205pub(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
216pub 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
224pub 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
232pub fn one<I>(shapes: I) -> Node
234where
235 I: IntoIterator,
236 I::Item: Into<Spec>,
237{
238 list_node(ListMode::One, shapes)
239}
240
241pub fn some<I>(shapes: I) -> Node
243where
244 I: IntoIterator,
245 I::Item: Into<Spec>,
246{
247 list_node(ListMode::Some, shapes)
248}
249
250pub 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
272pub fn define(name: impl Into<String>, spec: impl Into<Spec>) -> Node {
274 buildize(spec).define(name)
275}
276
277pub fn refer(name: impl Into<String>, spec: impl Into<Spec>) -> Node {
279 buildize(spec).refer_with(name, ReferOptions::default())
280}
281
282pub fn refer_with(name: impl Into<String>, opts: ReferOptions, spec: impl Into<Spec>) -> Node {
284 buildize(spec).refer_with(name, opts)
285}
286
287pub fn rename(name: impl Into<String>, spec: impl Into<Spec>) -> Node {
289 buildize(spec).rename_with(name, RenameOptions::default())
290}
291
292pub fn rename_with(name: impl Into<String>, opts: RenameOptions, spec: impl Into<Spec>) -> Node {
294 buildize(spec).rename_with(name, opts)
295}
296
297pub fn key() -> Node {
299 key_args(&[])
300}
301
302pub fn key_depth(depth: i64) -> Node {
304 key_args(&[Value::from(depth)])
305}
306
307pub fn key_join(depth: i64, sep: impl Into<String>) -> Node {
309 key_args(&[Value::from(depth), Value::Str(sep.into())])
310}
311
312pub 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 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 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 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
377fn 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
389pub fn catch(fallback: impl Into<Value>, spec: impl Into<Spec>) -> Node {
391 buildize(spec).catch(fallback)
392}
393
394pub 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
402pub fn describe(description: impl Into<String>, spec: impl Into<Spec>) -> Node {
404 buildize(spec).describe(description)
405}
406
407pub fn coerce(spec: impl Into<Spec>) -> Node {
410 buildize(spec).coerce()
411}
412
413pub fn email(spec: impl Into<Spec>) -> Node {
415 buildize(spec).email()
416}
417
418pub fn url(spec: impl Into<Spec>) -> Node {
420 buildize(spec).url()
421}
422
423pub fn uuid(spec: impl Into<Spec>) -> Node {
425 buildize(spec).uuid()
426}
427
428pub fn date_time(spec: impl Into<Spec>) -> Node {
430 buildize(spec).date_time()
431}
432
433pub fn ip(spec: impl Into<Spec>) -> Node {
435 buildize(spec).ip()
436}
437
438pub fn ipv4(spec: impl Into<Spec>) -> Node {
440 buildize(spec).ipv4()
441}
442
443pub fn ipv6(spec: impl Into<Spec>) -> Node {
445 buildize(spec).ipv6()
446}
447
448pub 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#[derive(Clone, Debug, Default)]
477pub struct ReferOptions {
478 pub fill: bool,
480 pub strict: bool,
483}
484
485#[derive(Clone, Debug, Default)]
487pub struct RenameOptions {
488 pub keep: bool,
490 pub claim: Vec<String>,
492}
493
494pub(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
505pub(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
515pub(crate) fn is_numeric(v: &Value) -> bool {
518 matches!(v, Value::Num(_) | Value::Date(_))
519}
520
521pub(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
535fn size_text(size: Option<f64>) -> String {
538 size.map(js_number).unwrap_or_else(|| "NaN".to_string())
539}
540
541pub(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
559pub(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
710pub(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 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 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 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 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 pub fn any(mut self) -> Node {
860 self.kind = Kind::Any;
861 self
862 }
863
864 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 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 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 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 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 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 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 if state.absent && !opts.fill {
1094 return true;
1095 }
1096 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 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 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 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 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 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 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 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 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 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 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(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}