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(if s.is_ascii() {
530 s.len()
531 } else {
532 s.encode_utf16().count()
533 } as f64),
534 Value::Arr(a) => Some(a.len() as f64),
535 Value::Obj(m) => Some(m.len() as f64),
536 _ => None,
537 }
538}
539
540fn size_text(size: Option<f64>) -> String {
543 size.map(js_number).unwrap_or_else(|| "NaN".to_string())
544}
545
546pub(crate) fn type_will_fail(n: &Node, v: &Value) -> bool {
548 match n.kind {
549 Kind::String | Kind::Regexp => !matches!(v, Value::Str(_)),
550 Kind::Number => !matches!(v, Value::Num(f) if !f.is_nan()),
551 Kind::Boolean => !matches!(v, Value::Bool(_)),
552 Kind::Object => !matches!(v, Value::Obj(_)),
553 Kind::Array => !matches!(v, Value::Arr(_)),
554 Kind::Function => !matches!(v, Value::Func(_)),
555 Kind::Null => !v.is_null(),
556 Kind::NaN => !matches!(v, Value::Num(f) if f.is_nan()),
557 Kind::Integer => !matches!(v, Value::Num(f) if is_integer(*f)),
558 Kind::Date => !matches!(v, Value::Date(_)),
559 Kind::BigInt => !matches!(v, Value::BigInt(_)),
560 _ => false,
561 }
562}
563
564pub(crate) fn bound_defers(state: &State<'_>) -> bool {
569 let n = state.node;
570 (state.absent && (n.skippable || !n.required)) || type_will_fail(n, state.value)
571}
572
573#[derive(Clone, Copy)]
574enum Bound {
575 Min,
576 Max,
577 Above,
578 Below,
579}
580
581impl Bound {
582 fn name(self) -> &'static str {
583 match self {
584 Bound::Min => "Min",
585 Bound::Max => "Max",
586 Bound::Above => "Above",
587 Bound::Below => "Below",
588 }
589 }
590
591 fn mark(self) -> i64 {
592 match self {
593 Bound::Min => 4011,
594 Bound::Max => 4012,
595 Bound::Above => 4013,
596 Bound::Below => 4014,
597 }
598 }
599
600 fn holds(self, limit: f64, size: f64) -> bool {
601 match self {
602 Bound::Min => limit <= size,
603 Bound::Max => size <= limit,
604 Bound::Above => limit < size,
605 Bound::Below => size < limit,
606 }
607 }
608
609 fn text(self, numeric: bool, bound: &str, size: &str) -> String {
610 match self {
611 Bound::Min | Bound::Max => {
612 let lenpart = if numeric { "" } else { "length " };
613 let word = if matches!(self, Bound::Min) {
614 "minimum"
615 } else {
616 "maximum"
617 };
618 format!(
619 "Value \"$VALUE\" for property \"$PATH\" must be a {} {}of {} (was {}).",
620 word, lenpart, bound, size
621 )
622 }
623 Bound::Above | Bound::Below => {
624 let verb = if numeric { "be" } else { "have length" };
625 let word = if matches!(self, Bound::Above) {
626 "above"
627 } else {
628 "below"
629 };
630 format!(
631 "Value \"$VALUE\" for property \"$PATH\" must {} {} {} (was {}).",
632 verb, word, bound, size
633 )
634 }
635 }
636 }
637}
638
639fn bound_node(kind: Bound, bound: Value) -> Node {
640 let Some(limit) = bound_arg(&bound) else {
641 return fault_node(format!("Shape: {} needs a number", kind.name()));
642 };
643 let text = num_text(&bound);
644 let mut n = any();
645 n.befores.push(validator(
646 kind.name(),
647 Some(format!("{}({})", kind.name(), text)),
648 vec![bound],
649 move |state, update| {
650 if bound_defers(state) {
651 return true;
652 }
653 let size = value_len(state.value);
654 if let Some(s) = size {
655 if kind.holds(limit, s) {
656 return true;
657 }
658 }
659 update.done = true;
660 update.mark = kind.mark();
661 if !state.ctx.terse {
663 update.why = Some(kind.name().to_string());
664 update.err = Some(UpdateErr::Text(kind.text(
665 is_numeric(state.value),
666 &text,
667 &size_text(size),
668 )));
669 }
670 false
671 },
672 ));
673 n
674}
675
676fn len_node(length: Value) -> Node {
677 let whole = match &length {
678 Value::Num(f) if f.is_finite() && *f >= 0.0 && f.fract() == 0.0 => Some(*f),
679 _ => None,
680 };
681 let Some(limit) = whole else {
682 return fault_node("Shape: Len needs a whole number of zero or more");
683 };
684 let text = js_number(limit);
685 let mut n = any();
686 n.befores.push(validator(
687 "Len",
688 Some(format!("Len({})", text)),
689 vec![length],
690 move |state, update| {
691 if bound_defers(state) {
692 return true;
693 }
694 let size = value_len(state.value);
695 if size == Some(limit) {
696 return true;
697 }
698 update.done = true;
699 update.mark = 4015;
700 if !state.ctx.terse {
702 let suffix = if is_numeric(state.value) {
703 ""
704 } else {
705 " in length"
706 };
707 update.why = Some("Len".to_string());
708 update.err = Some(UpdateErr::Text(format!(
709 "Value \"$VALUE\" for property \"$PATH\" must be exactly {}{} (was {}).",
710 text,
711 suffix,
712 size_text(size)
713 )));
714 }
715 false
716 },
717 ));
718 n
719}
720
721pub(crate) fn format_list(vals: &[Value]) -> String {
723 vals.iter()
724 .map(|v| match v {
725 Value::Null => "null".to_string(),
726 Value::Str(s) => s.clone(),
727 Value::Num(f) => js_number(*f),
728 Value::Undefined => "undefined".to_string(),
729 other => json_render(other),
730 })
731 .collect::<Vec<_>>()
732 .join(", ")
733}
734
735impl Node {
736 fn adopt(mut self, other: Node) -> Node {
739 if is_fault(&other) {
740 self.kind = Kind::Never;
741 self.fault_msg = other.fault_msg;
742 self.arg_fault = true;
743 return self;
744 }
745 self.befores.extend(other.befores);
746 self
747 }
748
749 pub fn required(mut self) -> Node {
750 self.required = true;
751 self.required_set = true;
752 self.skippable = false;
753 self
754 }
755
756 pub fn optional(mut self) -> Node {
757 self.required = false;
758 self.required_set = true;
759 self
760 }
761
762 pub fn default_to(mut self, dval: impl Into<Value>) -> Node {
766 let dval = dval.into();
767 if self.kind == Kind::Any && !dval.is_undefined() {
768 let mut base = normalize(Spec::Value(dval.clone()));
769 let mut befores = std::mem::take(&mut self.befores);
770 befores.append(&mut base.befores);
771 base.befores = befores;
772 let mut afters = std::mem::take(&mut self.afters);
773 afters.append(&mut base.afters);
774 base.afters = afters;
775 base.has_exact = self.has_exact;
776 base.exact_vals = std::mem::take(&mut self.exact_vals);
777 base.empty = self.empty;
778 base.nullable = self.nullable;
779 base.silent = self.silent;
780 base.fault_msg = self.fault_msg.take();
781 base.arg_fault = self.arg_fault;
782 base.meta.extend(std::mem::take(&mut self.meta));
783 self = base;
784 }
785 self.required = false;
786 self.required_set = true;
787 self.skippable = false;
788 self.has_default = true;
789 self.default = dval;
790 self
791 }
792
793 pub fn skip(mut self) -> Node {
794 self.required = false;
795 self.required_set = true;
796 self.skippable = true;
797 self
798 }
799
800 pub fn ignore(mut self) -> Node {
801 self.required = false;
802 self.required_set = true;
803 self.skippable = true;
804 self.silent = true;
805 self
806 }
807
808 pub fn empty(mut self) -> Node {
809 self.empty = true;
810 self
811 }
812
813 pub fn nullable(mut self) -> Node {
814 self.nullable = true;
815 self
816 }
817
818 pub fn open(mut self) -> Node {
819 if self.kind == Kind::Object && self.obj_rest.is_none() {
820 self.obj_rest = Some(Box::new(Node::of(Kind::Any)));
821 }
822 self
823 }
824
825 pub fn closed(mut self) -> Node {
826 self.obj_rest = None;
827 if self.kind == Kind::Array && self.arr_children.is_empty() {
828 if let Some(c) = self.arr_child.take() {
829 self.arr_children = vec![*c];
831 }
832 }
833 self
834 }
835
836 pub fn child(mut self, child: impl Into<Spec>) -> Node {
837 let cn = Box::new(buildize(child));
838 match self.kind {
839 Kind::Array => self.arr_child = Some(cn),
840 Kind::Object => self.obj_rest = Some(cn),
841 _ => {
842 self.kind = Kind::Object;
843 self.obj_rest = Some(cn);
844 }
845 }
846 self
847 }
848
849 pub fn rest(mut self, child: impl Into<Spec>) -> Node {
850 self.kind = Kind::Array;
851 self.arr_child = None;
855 self.arr_rest = Some(Box::new(buildize(child)));
856 self
857 }
858
859 pub fn fault(mut self, msg: impl Into<String>) -> Node {
860 self.fault_msg = Some(msg.into());
861 self
862 }
863
864 pub fn never(mut self) -> Node {
865 self.kind = Kind::Never;
866 self
867 }
868
869 pub fn any(mut self) -> Node {
871 self.kind = Kind::Any;
872 self
873 }
874
875 pub fn type_(mut self, kind: impl Into<TypeRef>) -> Node {
880 let tn = match kind.into() {
881 TypeRef::Kind(k) => type_token_node(k),
882 TypeRef::Node(n) => *n,
883 };
884 let keep = tn.kind == Kind::Any && self.has_default && !self.default.is_undefined();
887 self.kind = tn.kind;
888 self.kind_set = true;
889 self.required = tn.required;
890 self.required_set = tn.required_set;
891 self.skippable = tn.skippable;
892 if !keep {
893 self.has_default = tn.has_default;
894 self.default = tn.default;
895 self.literal = tn.literal;
896 }
897 self
898 }
899
900 pub fn string(self) -> Node {
901 self.type_(Kind::String)
902 }
903 pub fn number(self) -> Node {
904 self.type_(Kind::Number)
905 }
906 pub fn boolean(self) -> Node {
907 self.type_(Kind::Boolean)
908 }
909 pub fn object(self) -> Node {
910 self.type_(Kind::Object)
911 }
912 pub fn array(self) -> Node {
913 self.type_(Kind::Array)
914 }
915 pub fn function(self) -> Node {
916 self.type_(Kind::Function)
917 }
918 pub fn integer(self) -> Node {
919 self.type_(Kind::Integer)
920 }
921 pub fn date(self) -> Node {
922 self.type_(Kind::Date)
923 }
924
925 pub fn func(mut self) -> Node {
927 self.kind = Kind::Function;
928 self
929 }
930
931 pub fn exact<I>(mut self, vals: I) -> Node
932 where
933 I: IntoIterator,
934 I::Item: Into<Value>,
935 {
936 let vals: Vec<Value> = vals.into_iter().map(Into::into).collect();
937 self.has_exact = true;
938 self.exact_vals = vals.clone();
939 let list = format_list(&vals);
940 let wanted = vals.clone();
941 self.befores.push(validator(
942 "Exact",
943 Some(format!("Exact({})", list)),
944 vals,
945 move |state, update| {
946 if wanted.iter().any(|w| w == state.value) {
947 return true;
948 }
949 if state.absent && state.node.has_default && wanted.contains(&state.node.default) {
952 return true;
953 }
954 update.why = Some("Exact".to_string());
955 update.mark = 4010;
956 update.err = Some(UpdateErr::Text(format!(
957 "Value \"$VALUE\" for property \"$PATH\" must be exactly one of: {}",
958 list
959 )));
960 update.done = true;
961 false
962 },
963 ));
964 self
965 }
966
967 pub fn min(self, bound: impl Into<Value>) -> Node {
968 self.adopt(bound_node(Bound::Min, bound.into()))
969 }
970
971 pub fn max(self, bound: impl Into<Value>) -> Node {
972 self.adopt(bound_node(Bound::Max, bound.into()))
973 }
974
975 pub fn above(self, bound: impl Into<Value>) -> Node {
976 self.adopt(bound_node(Bound::Above, bound.into()))
977 }
978
979 pub fn below(self, bound: impl Into<Value>) -> Node {
980 self.adopt(bound_node(Bound::Below, bound.into()))
981 }
982
983 pub fn len(self, length: impl Into<Value>) -> Node {
984 self.adopt(len_node(length.into()))
985 }
986
987 pub fn check<F>(mut self, f: F) -> Node
988 where
989 F: Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync + 'static,
990 {
991 self.befores.push(validator(
992 "Check",
993 Some("Check()".to_string()),
994 Vec::new(),
995 move |state: &mut State<'_>, update: &mut Update| state.absent || f(state, update),
997 ));
998 self
999 }
1000
1001 pub fn check_re(self, re: Regex) -> Node {
1002 self.check_re_src(re.as_str())
1003 }
1004
1005 pub(crate) fn check_re_src(mut self, src: &str) -> Node {
1006 let src = src.to_string();
1007 let re = match crate::regexp::compile_regexp(&src) {
1008 Ok(engine) => engine,
1009 Err(msg) => return self.adopt(fault_node(msg)),
1010 };
1011 let name = format!("/{}/", src);
1012 let suffix = format!("Check({})", name);
1013 self.befores.push(validator(
1014 &name,
1015 Some(suffix),
1016 Vec::new(),
1017 move |state, update| {
1018 if state.absent {
1019 return true;
1020 }
1021 if let Value::Str(s) = state.value {
1022 if re.is_match(s) {
1023 return true;
1024 }
1025 }
1026 update.why = Some(WHY_CHECK.to_string());
1028 update.mark = MARK_CHECK_TYPE;
1029 false
1030 },
1031 ));
1032 self
1033 }
1034
1035 pub fn before<F>(mut self, f: F) -> Node
1036 where
1037 F: Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync + 'static,
1038 {
1039 self.befores.push(validator(
1040 "Before",
1041 Some("Before()".to_string()),
1042 Vec::new(),
1043 f,
1044 ));
1045 self
1046 }
1047
1048 pub fn after<F>(mut self, f: F) -> Node
1049 where
1050 F: Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync + 'static,
1051 {
1052 self.afters.push(validator(
1053 "After",
1054 Some("After()".to_string()),
1055 Vec::new(),
1056 f,
1057 ));
1058 self
1059 }
1060
1061 pub fn define(mut self, name: impl Into<String>) -> Node {
1062 let name = name.into();
1063 if name.is_empty() {
1064 return fault_node("Shape: Define needs a name");
1065 }
1066 self.define_name = Some(name.clone());
1067 let suffix = format!("Define({})", json_text(&name));
1068 self.befores.push(validator(
1069 "Define",
1070 Some(suffix),
1071 vec![Value::Str(name.clone())],
1072 move |state, _update| {
1073 if let Some(d) = state.defs.get(&name).cloned() {
1076 state.ctx.refs.insert(name.clone(), d);
1077 }
1078 true
1079 },
1080 ));
1081 self
1082 }
1083
1084 pub fn refer(self, name: impl Into<String>) -> Node {
1085 self.refer_with(name, ReferOptions::default())
1086 }
1087
1088 pub fn refer_with(mut self, name: impl Into<String>, opts: ReferOptions) -> Node {
1089 let name = name.into();
1090 if name.is_empty() {
1091 return fault_node("Shape: Refer needs a name");
1092 }
1093 self.refer_name = Some(name.clone());
1094 self.refer_fill = opts.fill;
1095 self.refer_strict = opts.strict;
1096 let suffix = format!("Refer({})", json_text(&name));
1097 self.befores.push(validator(
1098 "Refer",
1099 Some(suffix),
1100 vec![Value::Str(name.clone())],
1101 move |state, update| {
1102 if state.absent && !opts.fill {
1105 return true;
1106 }
1107 let found = state
1109 .ctx
1110 .refs
1111 .get(&name)
1112 .cloned()
1113 .or_else(|| state.defs.get(&name).cloned());
1114 match found {
1115 Some(rn) => update.node = Some(rn),
1116 None if opts.strict => {
1117 update.err = Some(UpdateErr::Text(format!(
1118 "Value \"$VALUE\" for property \"$PATH\" refers to \"{}\", which is not defined.",
1119 name
1120 )));
1121 return false;
1122 }
1123 None => {}
1124 }
1125 true
1126 },
1127 ));
1128 self
1129 }
1130
1131 pub fn rename(self, name: impl Into<String>) -> Node {
1132 self.rename_with(name, RenameOptions::default())
1133 }
1134
1135 pub fn rename_with(mut self, name: impl Into<String>, opts: RenameOptions) -> Node {
1136 let name = name.into();
1137 if name.is_empty() {
1138 return fault_node("Shape: Rename needs a name");
1139 }
1140 self.rename_to = Some(name);
1141 self.rename_keep = opts.keep;
1142 self.rename_claim = opts.claim;
1143 self
1144 }
1145
1146 pub fn catch(self, fallback: impl Into<Value>) -> Node {
1147 catch_node(self, fallback.into())
1148 }
1149
1150 pub fn transform<F>(self, f: F) -> Node
1151 where
1152 F: Fn(Value, &mut State<'_>) -> Value + Send + Sync + 'static,
1153 {
1154 let f: Arc<TransformFn> = Arc::new(f);
1155 transform_node(self, f)
1156 }
1157
1158 pub fn describe(mut self, description: impl Into<String>) -> Node {
1159 self.meta
1160 .insert("description".to_string(), Value::Str(description.into()));
1161 self
1162 }
1163
1164 pub fn coerce(mut self) -> Node {
1165 self.befores.insert(0, coerce_validator());
1166 self
1167 }
1168
1169 pub fn email(self) -> Node {
1170 with_format(self, FMT_EMAIL)
1171 }
1172 pub fn url(self) -> Node {
1173 with_format(self, FMT_URL)
1174 }
1175 pub fn uuid(self) -> Node {
1176 with_format(self, FMT_UUID)
1177 }
1178 pub fn date_time(self) -> Node {
1179 with_format(self, FMT_DATE_TIME)
1180 }
1181 pub fn ip(self) -> Node {
1182 with_format(self, FMT_IP)
1183 }
1184 pub fn ipv4(self) -> Node {
1185 with_format(self, FMT_IPV4)
1186 }
1187 pub fn ipv6(self) -> Node {
1188 with_format(self, FMT_IPV6)
1189 }
1190}
1191
1192#[cfg(test)]
1193mod tests {
1194 use super::*;
1195 use crate::context::Context;
1196 use crate::spec::{arr, null, obj};
1197 use crate::stringify::stringify_node;
1198 use crate::Schema;
1199
1200 fn j(s: &str) -> Value {
1201 Value::from(serde_json::from_str::<serde_json::Value>(s).unwrap())
1202 }
1203
1204 fn run(s: &Schema, input: &str) -> String {
1205 match s.validate(j(input)) {
1206 Ok(v) => serde_json::Value::from(v).to_string(),
1207 Err(e) => format!("ERR {}", e),
1208 }
1209 }
1210
1211 fn at_a(n: impl Into<Spec>) -> Schema {
1212 Schema::new(obj([("a", n.into())]))
1213 }
1214
1215 fn a(s: &str) -> String {
1216 format!("{{\"a\":{}}}", s)
1217 }
1218
1219 #[test]
1220 fn bounds_on_numbers_strings_and_containers() {
1221 let cases: Vec<(Node, &str, &str)> = vec![
1222 (min(3, Token::Number), "5", "{\"a\":5}"),
1223 (min(3, Token::Number), "1", "ERR Value \"1\" for property \"a\" must be a minimum of 3 (was 1)."),
1224 (max(3, Token::Number), "9", "ERR Value \"9\" for property \"a\" must be a maximum of 3 (was 9)."),
1225 (above(3, Token::Number), "3", "ERR Value \"3\" for property \"a\" must be above 3 (was 3)."),
1226 (below(3, Token::Number), "3", "ERR Value \"3\" for property \"a\" must be below 3 (was 3)."),
1227 (len(3, Token::Number), "4", "ERR Value \"4\" for property \"a\" must be exactly 3 (was 4)."),
1228 (min(3, Token::String), "\"hi\"", "ERR Value \"hi\" for property \"a\" must be a minimum length of 3 (was 2)."),
1229 (max(2, Token::String), "\"hey\"", "ERR Value \"hey\" for property \"a\" must be a maximum length of 2 (was 3)."),
1230 (len(3, Token::String), "\"abc\"", "{\"a\":\"abc\"}"),
1231 (len(3, Token::String), "\"ab\"", "ERR Value \"ab\" for property \"a\" must be exactly 3 in length (was 2)."),
1232 (min(2, any()), "[1]", "ERR Value \"[1]\" for property \"a\" must be a minimum length of 2 (was 1)."),
1233 (above(1, any()), "\"a\"", "ERR Value \"a\" for property \"a\" must have length above 1 (was 1)."),
1234 (below(1, any()), "\"ab\"", "ERR Value \"ab\" for property \"a\" must have length below 1 (was 2)."),
1235 (min(2, Token::Object), "{\"x\":1}", "ERR Value \"{x:1}\" for property \"a\" must be a minimum length of 2 (was 1)."),
1236 (min(2, null()), "null", "ERR Value \"null\" for property \"a\" must be a minimum length of 2 (was NaN)."),
1237 (min(2, null()), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type null."),
1238 (min(2, Token::String), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type string."),
1239 (min(2, Token::Integer), "1.5", "ERR Validation failed for property \"a\" with number \"1.5\" because the number is not of type integer."),
1240 (min(2, Token::Integer), "1", "ERR Value \"1\" for property \"a\" must be a minimum of 2 (was 1)."),
1241 (min("2", Token::Number), "1", "ERR Value \"1\" for property \"a\" must be a minimum of 2 (was 1)."),
1242 (min(2, Token::Boolean), "\"x\"", "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type boolean."),
1243 (min(2, true), "true", "ERR Value \"true\" for property \"a\" must be a minimum length of 2 (was NaN)."),
1244 (min(2, Token::Function), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type function."),
1245 (min(2, Token::Array), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type array."),
1246 (min(2, Token::Object), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type object."),
1247 (min(2, f64::NAN), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type nan."),
1248 (min(2, Token::Date), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type date."),
1249 (min(2, Token::BigInt), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type bigint."),
1250 (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."),
1251 (min(2, buildize(Regex::new("^a").unwrap())), "\"abc\"", "{\"a\":\"abc\"}"),
1252 (optional(min(2, Token::Number)), "{}", "{}"),
1253 (optional(len(2, Token::Number)), "{}", "{}"),
1254 (max(3, Token::String), "\"hi\"", "{\"a\":\"hi\"}"),
1255 (above(3, Token::Number), "4", "{\"a\":4}"),
1256 (below(3, Token::Number), "2", "{\"a\":2}"),
1257 (len(2, any()), "[1,2]", "{\"a\":[1,2]}"),
1258 ];
1259 for (n, input, want) in cases {
1260 let s = at_a(n);
1261 let got = if input == "{}" {
1262 run(&s, "{}")
1263 } else {
1264 run(&s, &a(input))
1265 };
1266 assert_eq!(got, want.replace("{}", "{\"a\":0}"), "{}", input);
1267 }
1268 let s = at_a(min(3, Token::Number));
1269 assert!(!s.valid(&j(&a("1"))));
1270 let e = &s.error(&j(&a("1")))[0];
1271 assert_eq!((e.why.as_str(), e.mark), ("Min", 4011));
1272 assert_eq!(s.error(&j(&a("\"x\"")))[0].why, "type");
1273 assert_eq!(at_a(max(3, any())).error(&j(&a("9")))[0].mark, 4012);
1274 assert_eq!(at_a(above(3, any())).error(&j(&a("1")))[0].mark, 4013);
1275 assert_eq!(at_a(below(3, any())).error(&j(&a("9")))[0].mark, 4014);
1276 assert_eq!(at_a(len(3, any())).error(&j(&a("9")))[0].mark, 4015);
1277 assert!(!at_a(len(3, any())).valid(&j(&a("9"))));
1279 assert!(!at_a(min(3, any())).valid(&j(&a("1"))));
1280 assert!(!at_a(max(3, any())).valid(&j(&a("9"))));
1281 assert!(!at_a(above(3, any())).valid(&j(&a("1"))));
1282 assert!(!at_a(below(3, any())).valid(&j(&a("9"))));
1283
1284 let s = at_a(min(Value::Date(1000), Token::Date));
1286 let dated =
1287 |ms: i64| Value::Obj([("a".to_string(), Value::Date(ms))].into_iter().collect());
1288 assert!(s.valid(&dated(2000)));
1289 assert!(!s.valid(&dated(5)));
1290 assert_eq!(num_text(&Value::Date(0)), "1970-01-01T00:00:00.000Z");
1291 assert_eq!(num_text(&Value::Bool(true)), "true");
1292 assert_eq!(value_len(&Value::Bool(true)), None);
1293 assert_eq!(value_len(&Value::Str("é😀".into())), Some(3.0));
1294 assert_eq!(bound_arg(&Value::Bool(true)), None);
1295 assert_eq!(bound_arg(&Value::Str("inf".into())), None);
1296 assert_eq!(bound_arg(&Value::Str(" 2.5 ".into())), Some(2.5));
1297 assert!(!is_numeric(&Value::Str("x".into())));
1298 assert!(!type_will_fail(&any(), &Value::Null));
1299 }
1300
1301 #[test]
1302 fn bad_bound_arguments_become_faults() {
1303 for (n, msg) in [
1304 (min("x", Token::Number), "Shape: Min needs a number"),
1305 (max(true, Token::Number), "Shape: Max needs a number"),
1306 (
1307 above(Value::Null, Token::Number),
1308 "Shape: Above needs a number",
1309 ),
1310 (
1311 below(f64::NAN, Token::Number),
1312 "Shape: Below needs a number",
1313 ),
1314 (
1315 len(-1, Token::Number),
1316 "Shape: Len needs a whole number of zero or more",
1317 ),
1318 (
1319 len(1.5, Token::Number),
1320 "Shape: Len needs a whole number of zero or more",
1321 ),
1322 (
1323 buildize(Token::Number).min("x"),
1324 "Shape: Min needs a number",
1325 ),
1326 (
1327 buildize(Token::Number).max("x"),
1328 "Shape: Max needs a number",
1329 ),
1330 (
1331 buildize(Token::Number).above("x"),
1332 "Shape: Above needs a number",
1333 ),
1334 (
1335 buildize(Token::Number).below("x"),
1336 "Shape: Below needs a number",
1337 ),
1338 (
1339 buildize(Token::Number).len("x"),
1340 "Shape: Len needs a whole number of zero or more",
1341 ),
1342 (define("", Token::Number), "Shape: Define needs a name"),
1343 (refer("", Token::Number), "Shape: Refer needs a name"),
1344 (rename("", Token::Number), "Shape: Rename needs a name"),
1345 ] {
1346 assert_eq!(run(&at_a(n), &a("1")), format!("ERR {}", msg));
1347 }
1348 }
1349
1350 #[test]
1351 fn exact_literals() {
1352 let s = Schema::new(obj([("role", exact(["admin", "user"]))]));
1353 assert_eq!(run(&s, r#"{"role":"user"}"#), r#"{"role":"user"}"#);
1354 assert_eq!(
1355 run(&s, r#"{"role":"root"}"#),
1356 "ERR Value \"root\" for property \"role\" must be exactly one of: admin, user"
1357 );
1358 let e = &s.error(&j(r#"{"role":"root"}"#))[0];
1359 assert_eq!((e.why.as_str(), e.mark), ("Exact", 4010));
1360 assert_eq!(
1361 run(&at_a(exact([Value::from(1), Value::Null])), &a("0")),
1362 "ERR Value \"0\" for property \"a\" must be exactly one of: 1, null"
1363 );
1364 assert_eq!(
1365 run(
1366 &at_a(exact([
1367 Value::from(1),
1368 Value::from("a"),
1369 Value::from(true),
1370 Value::Null
1371 ])),
1372 &a("0")
1373 ),
1374 "ERR Value \"0\" for property \"a\" must be exactly one of: 1, a, true, null"
1375 );
1376 assert_eq!(
1377 format_list(&[Value::Arr(vec![Value::from(1)]), Value::Undefined]),
1378 "[1], undefined"
1379 );
1380 let s = at_a(default(2, exact([2, 3])));
1382 assert_eq!(run(&s, "{}"), a("2"));
1383 assert_eq!(run(&s, &a("3")), a("3"));
1384 assert_eq!(
1385 run(&s, &a("4")),
1386 "ERR Value \"4\" for property \"a\" must be exactly one of: 2, 3"
1387 );
1388 assert_eq!(
1389 run(&s, &a("null")),
1390 "ERR Value \"null\" for property \"a\" must be exactly one of: 2, 3"
1391 );
1392 let s = at_a(buildize(Token::String).exact(["x"]));
1393 assert_eq!(run(&s, &a("\"x\"")), a("\"x\""));
1394 assert!(s.node().obj_children["a"].has_exact);
1395 assert_eq!(stringify_node(&exact(["a", "b"]), false), "Exact(a, b)");
1396 }
1397
1398 #[test]
1399 fn checks() {
1400 let s = at_a(check(|st, _| st.value.as_f64().unwrap_or(0.0) > 1.0, any()));
1401 assert_eq!(s.node().obj_children["a"].kind, Kind::Check);
1402 assert_eq!(run(&s, &a("2")), a("2"));
1403 assert_eq!(
1404 run(&s, &a("1")),
1405 "ERR Validation failed for property \"a\" with number \"1\" because check \"Check\" failed."
1406 );
1407 assert_eq!(
1409 run(&s, "{}"),
1410 "ERR Validation failed for property \"a\" because the property is missing."
1411 );
1412 let s = at_a(check(|_, _| true, Token::Number));
1413 assert_eq!(
1414 run(&s, "{}"),
1415 "ERR Validation failed for property \"a\" because the property is missing."
1416 );
1417 assert_eq!(s.node().obj_children["a"].kind, Kind::Number);
1418 let re = || Regex::new("^a.+").unwrap();
1419 let s = at_a(check_re(re(), any()));
1420 assert_eq!(run(&s, &a("\"abc\"")), a("\"abc\""));
1421 assert_eq!(
1422 run(&s, &a("\"zzz\"")),
1423 "ERR Validation failed for property \"a\" with string \"zzz\" because check \"/^a.+/\" failed."
1424 );
1425 assert_eq!(
1426 run(&s, &a("1")),
1427 "ERR Validation failed for property \"a\" with number \"1\" because check \"/^a.+/\" failed."
1428 );
1429 assert_eq!(s.error(&j(&a("1")))[0].mark, MARK_CHECK_TYPE);
1430 let s = at_a(check_re(re(), Token::String));
1431 assert_eq!(s.node().obj_children["a"].kind, Kind::String);
1432 assert_eq!(
1433 stringify_node(&check_re(re(), any()), false),
1434 "Check.Check(/^a.+/)"
1435 );
1436 let s = at_a(before(
1437 |_, u| {
1438 u.val = Some(Value::from(9));
1439 true
1440 },
1441 Token::Number,
1442 ));
1443 assert_eq!(run(&s, &a("1")), a("9"));
1444 let s = at_a(after(|_, _| false, Token::Number));
1445 assert_eq!(s.error(&j(&a("1")))[0].check, "After");
1446 assert_eq!(
1447 stringify_node(&after(|_, _| true, before(|_, _| true, any())), false),
1448 "Before().After()"
1449 );
1450 }
1451
1452 #[test]
1453 fn composition() {
1454 let one_ns = || one([Spec::from(Token::Number), Spec::from(Token::String)]);
1455 assert_eq!(run(&at_a(one_ns()), &a("\"x\"")), a("\"x\""));
1456 assert_eq!(
1457 run(&at_a(one_ns()), &a("true")),
1458 "ERR Value \"true\" for property \"a\" does not satisfy one of: Number, String"
1459 );
1460 assert!(!at_a(one_ns()).valid(&j(&a("true"))));
1461 assert!(at_a(one_ns()).valid(&j(&a("1"))));
1462 let e = &at_a(one_ns()).error(&j(&a("true")))[0];
1463 assert_eq!((e.why.as_str(), e.mark), ("One", 4030));
1464 let some_ns = || some([Spec::from(Token::Number), Spec::from(Token::String)]);
1465 assert_eq!(run(&at_a(some_ns()), &a("5")), a("5"));
1466 assert_eq!(
1467 run(&at_a(some_ns()), &a("true")),
1468 "ERR Value \"true\" for property \"a\" does not satisfy any of: Number, String"
1469 );
1470 assert_eq!(at_a(some_ns()).error(&j(&a("true")))[0].mark, 4031);
1471 let all_nm = || all([Spec::from(Token::Number), Spec::from(min(2, any()))]);
1472 assert_eq!(
1473 run(&at_a(all_nm()), &a("1")),
1474 "ERR Value \"1\" for property \"a\" does not satisfy all of: Number, Min(2)"
1475 );
1476 assert_eq!(run(&at_a(all_nm()), &a("5")), a("5"));
1477 assert_eq!(at_a(all_nm()).error(&j(&a("1")))[0].mark, 4032);
1478 assert_eq!(
1479 run(
1480 &at_a(one([Spec::from(Token::Number), Spec::from(min(2, any()))])),
1481 &a("\"x\"")
1482 ),
1483 "ERR Value \"x\" for property \"a\" does not satisfy one of: Number, Min(2)"
1484 );
1485 assert_eq!(
1486 run(
1487 &at_a(all([Spec::from(Token::String), Spec::from(Token::Any)])),
1488 &a("1")
1489 ),
1490 "ERR Value \"1\" for property \"a\" does not satisfy all of: String, Any"
1491 );
1492 assert_eq!(
1493 run(
1494 &at_a(one([
1495 Spec::from(ignore(min(2, Token::Number))),
1496 Spec::from(Token::String)
1497 ])),
1498 &a("1")
1499 ),
1500 a("1")
1501 );
1502 assert_eq!(
1503 run(
1504 &at_a(all([
1505 Spec::from(ignore(min(2, Token::Number))),
1506 Spec::from(Token::Number)
1507 ])),
1508 &a("1")
1509 ),
1510 a("1")
1511 );
1512 assert_eq!(run(&at_a(optional(one_ns())), "{}"), "{}");
1513 let re = || Regex::new("^a").unwrap();
1514 let one_rn = || one([Spec::from(re()), Spec::from(Token::Number)]);
1515 assert_eq!(run(&at_a(one_rn()), &a("\"abc\"")), a("\"abc\""));
1516 assert_eq!(run(&at_a(one_rn()), &a("5")), a("5"));
1517 assert_eq!(
1518 run(&at_a(one_rn()), &a("true")),
1519 "ERR Value \"true\" for property \"a\" does not satisfy one of: /^a/, Number"
1520 );
1521 assert_eq!(
1522 run(
1523 &at_a(some([Spec::from(re()), Spec::from(Token::Number)])),
1524 &a("true")
1525 ),
1526 "ERR Value \"true\" for property \"a\" does not satisfy any of: /^a/, Number"
1527 );
1528 assert_eq!(run(&at_a(fault("F", one_ns())), &a("true")), "ERR F");
1530 assert_eq!(run(&at_a(fault("F", some_ns())), &a("true")), "ERR F");
1531 assert_eq!(
1532 run(&at_a(fault("F", all_nm())), &a("1")),
1533 "ERR Value \"1\" for property \"a\" does not satisfy all of: Number, Min(2)"
1534 );
1535 assert!(!at_a(fault("F", one_ns())).valid(&j(&a("true"))));
1536 let s = at_a(some([
1539 Spec::from(Token::Number),
1540 Spec::from(coerce(Token::String)),
1541 ]));
1542 assert_eq!(run(&s, &a("5")), a("\"5\""));
1543 let s = at_a(all([
1545 Spec::from(coerce(Token::Number)),
1546 Spec::from(min(2, any())),
1547 ]));
1548 assert_eq!(run(&s, &a("\"5\"")), a("5"));
1549 let s = at_a(all([
1550 Spec::from(coerce(Token::Number)),
1551 Spec::from(min(9, any())),
1552 ]));
1553 assert_eq!(
1554 run(&s, &a("\"5\"")),
1555 "ERR Value \"5\" for property \"a\" does not satisfy all of: Number, Min(9)"
1556 );
1557 let missing = "ERR Validation failed for property \"a\" because the property is missing.";
1560 assert_eq!(
1561 run(&at_a(one([Spec::from(skip(Token::Number))])), "{}"),
1562 missing
1563 );
1564 assert_eq!(
1565 run(&at_a(some([Spec::from(skip(Token::Number))])), "{}"),
1566 missing
1567 );
1568 assert_eq!(
1569 run(&at_a(all([Spec::from(skip(Token::Number))])), "{}"),
1570 missing
1571 );
1572 let mut quiet = one_ns();
1573 quiet.silent = true;
1574 assert_eq!(run(&at_a(quiet), &a("true")), a("true"));
1575 }
1576
1577 #[test]
1578 fn define_and_refer() {
1579 let s = |strict: bool, fill: bool| {
1580 Schema::new(obj([
1581 ("a", Spec::from(define("d", Token::Number))),
1582 (
1583 "b",
1584 Spec::from(refer_with("d", ReferOptions { strict, fill }, any())),
1585 ),
1586 ]))
1587 };
1588 assert_eq!(
1589 run(&s(false, false), r#"{"a":1,"b":2}"#),
1590 r#"{"a":1,"b":2}"#
1591 );
1592 assert_eq!(run(&s(true, false), r#"{"a":1,"b":2}"#), r#"{"a":1,"b":2}"#);
1593 assert_eq!(
1594 run(&s(true, false), r#"{"a":1,"b":"x"}"#),
1595 "ERR Validation failed for property \"b\" with string \"x\" because the string is not of type number."
1596 );
1597 assert_eq!(run(&s(false, false), r#"{"a":1}"#), r#"{"a":1}"#);
1598 assert_eq!(
1599 run(&s(false, true), r#"{"a":1}"#),
1600 "ERR Validation failed for property \"b\" because the property is missing."
1601 );
1602 assert!(s(false, false).defs().contains_key("d"));
1603 let lax = at_a(any().refer("nope"));
1604 assert_eq!(run(&lax, &a("2")), a("2"));
1605 let strict = |fill| {
1606 at_a(refer_with(
1607 "nope",
1608 ReferOptions { strict: true, fill },
1609 any(),
1610 ))
1611 };
1612 assert_eq!(
1613 run(&strict(false), &a("2")),
1614 "ERR Value \"2\" for property \"a\" refers to \"nope\", which is not defined."
1615 );
1616 assert_eq!(run(&strict(false), "{}"), "{}");
1617 assert_eq!(run(&strict(true), "{}"), "{}");
1618 assert_eq!(
1619 stringify_node(&define("d", Token::Number), false),
1620 "Number.Define(\"d\")"
1621 );
1622 assert_eq!(stringify_node(&refer("d", any()), false), "Refer(\"d\")");
1623 let mut ctx = Context::new();
1626 let first = at_a(define("shared", Token::Number));
1627 first.validate_ctx(j(&a("1")), &mut ctx).unwrap();
1628 let second = at_a(refer("shared", any()));
1629 assert!(second.validate_ctx(j(&a("\"x\"")), &mut ctx).is_err());
1630 assert!(second.validate_ctx(j(&a("3")), &mut ctx).is_ok());
1631 }
1632
1633 #[test]
1634 fn renames() {
1635 let s = at_a(buildize(Token::Number).rename("b"));
1636 assert_eq!(run(&s, &a("1")), r#"{"b":1}"#);
1637 assert_eq!(run(&s, r#"{"a":1,"b":2}"#), r#"{"b":1}"#);
1638 assert!(s.valid(&j(&a("1"))));
1639 let s = at_a(rename_with(
1640 "b",
1641 RenameOptions {
1642 keep: true,
1643 claim: vec![],
1644 },
1645 Token::Number,
1646 ));
1647 assert_eq!(run(&s, &a("1")), r#"{"a":1,"b":1}"#);
1648 let claim = |keep| {
1649 at_a(rename_with(
1650 "b",
1651 RenameOptions {
1652 keep,
1653 claim: vec!["old".into(), "older".into()],
1654 },
1655 Token::Number,
1656 ))
1657 };
1658 assert_eq!(run(&claim(false), r#"{"older":1}"#), r#"{"b":1}"#);
1659 assert_eq!(
1660 run(&claim(true), r#"{"old":1}"#),
1661 r#"{"old":1,"a":1,"b":1}"#
1662 );
1663 assert_eq!(run(&claim(false), &a("2")), r#"{"b":2}"#);
1664 assert_eq!(
1665 run(&claim(false), "{}"),
1666 "ERR Validation failed for property \"a\" because the property is missing."
1667 );
1668 assert!(claim(false).valid(&j(r#"{"old":1}"#)));
1669 assert!(!claim(false).valid(&j(r#"{"old":"x"}"#)));
1670 assert!(!claim(false).valid(&j("{}")));
1671 assert_eq!(run(&at_a(rename("b", skip(Token::Number))), "{}"), "{}");
1673 assert_eq!(run(&at_a(rename("a", Token::Number)), &a("1")), a("1"));
1674 }
1675
1676 #[test]
1677 fn keys() {
1678 let nested = |n: Node| Schema::new(obj([("a", obj([("b", Spec::from(n))]))]));
1679 assert_eq!(
1680 run(&nested(key()), r#"{"a":{"b":"V"}}"#),
1681 r#"{"a":{"b":"a"}}"#
1682 );
1683 assert_eq!(
1684 run(&nested(key_depth(1)), r#"{"a":{"b":"V"}}"#),
1685 r#"{"a":{"b":["a"]}}"#
1686 );
1687 assert_eq!(
1688 run(&nested(key_join(1, "/")), r#"{"a":{"b":"V"}}"#),
1689 r#"{"a":{"b":"a"}}"#
1690 );
1691 assert_eq!(
1692 run(&nested(key_depth(-1)), r#"{"a":{"b":"V"}}"#),
1693 r#"{"a":{"b":["b"]}}"#
1694 );
1695 assert_eq!(
1696 run(&nested(key_join(0, "/")), r#"{"a":{"b":"V"}}"#),
1697 "ERR Validation failed for property \"a.b\" with string \"\" because an empty string is not allowed."
1698 );
1699 assert_eq!(
1700 run(&nested(key_join(2, "/")), r#"{"a":{"b":"V"}}"#),
1701 r#"{"a":{"b":"/a"}}"#
1702 );
1703 assert_eq!(
1704 run(&nested(key_join(5, ".")), r#"{"a":{"b":"V"}}"#),
1705 r#"{"a":{"b":".a"}}"#
1706 );
1707 assert_eq!(run(&at_a(key()), &a("\"V\"")), a("\"V\""));
1708 assert_eq!(
1709 run(&at_a(key_args(&[Value::from("/")])), &a("\"V\"")),
1710 a("\"V\"")
1711 );
1712 assert_eq!(key_args(&[Value::Null]).kind, Kind::String);
1713 assert_eq!(
1714 js_slice(&[Value::from(1), Value::from(2)], 5, 9),
1715 Vec::<Value>::new()
1716 );
1717 assert_eq!(
1718 js_slice(&[Value::from(1), Value::from(2)], -9, -1),
1719 vec![Value::from(1)]
1720 );
1721 assert_eq!(stringify_node(&key(), false), "String.Key()");
1722 }
1723
1724 #[test]
1725 fn catch_and_transform() {
1726 assert_eq!(run(&at_a(catch(0, Token::Number)), &a("\"x\"")), a("0"));
1727 assert_eq!(run(&at_a(catch(0, Token::Number)), &a("5")), a("5"));
1728 assert_eq!(
1729 run(&at_a(catch("none", min(2, Token::String))), &a("\"x\"")),
1730 a("\"none\"")
1731 );
1732 assert_eq!(
1733 run(&at_a(min(2, catch(0, Token::Number))), &a("\"x\"")),
1734 "ERR Value \"0\" for property \"a\" must be a minimum of 2 (was 0)."
1735 );
1736 assert_eq!(run(&at_a(catch(7, Token::Number)), "{}"), a("7"));
1737 assert_eq!(run(&at_a(optional(catch(7, Token::Number))), "{}"), a("0"));
1738 assert_eq!(
1739 run(&at_a(catch(Value::Null, Token::Number)), &a("\"x\"")),
1740 a("null")
1741 );
1742 assert!(at_a(catch(0, Token::Number)).valid(&j(&a("\"x\""))));
1743 let s = at_a(catch(
1744 Value::Obj(Default::default()),
1745 obj([("x", Spec::from(Token::Number))]),
1746 ));
1747 assert_eq!(run(&s, r#"{"a":{"x":"bad"}}"#), r#"{"a":{}}"#);
1748 assert_eq!(run(&s, r#"{"a":{"x":1}}"#), r#"{"a":{"x":1}}"#);
1749 assert_eq!(
1750 stringify_node(&catch(0, min(2, Token::Number)), false),
1751 "Number.Min(2).Catch(0)"
1752 );
1753 assert_eq!(
1754 stringify_node(&after(|_, _| true, Token::Number).catch("z"), false),
1755 "Number.After().Catch(z)"
1756 );
1757 let dbl = |n: Node| transform(|v, _| Value::Num(v.as_f64().unwrap_or(0.0) * 2.0), n);
1758 assert_eq!(run(&at_a(dbl(buildize(Token::Number))), &a("2")), a("4"));
1759 assert_eq!(
1760 run(&at_a(dbl(buildize(Token::Number))), &a("\"x\"")),
1761 "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number."
1762 );
1763 assert_eq!(
1764 run(&at_a(dbl(min(2, Token::Number))), &a("1")),
1765 "ERR Value \"1\" for property \"a\" must be a minimum of 2 (was 1)."
1766 );
1767 assert!(at_a(dbl(buildize(Token::Number))).valid(&j(&a("2"))));
1768 assert!(!at_a(dbl(buildize(Token::Number))).valid(&j(&a("\"x\""))));
1769 assert_eq!(
1770 stringify_node(&dbl(min(2, Token::Number)), false),
1771 "Number.Min(2).Transform"
1772 );
1773 assert!(catch(0, Token::Number).befores[0].inner.is_some());
1774 assert_eq!(run(&at_a(dbl(skip(Token::Number))), "{}"), a("0"));
1777 }
1778
1779 #[test]
1780 fn describe_coerce_and_formats() {
1781 let s = at_a(describe("a number", Token::Number));
1782 assert_eq!(
1783 s.node().obj_children["a"].meta.get("description"),
1784 Some(&Value::from("a number"))
1785 );
1786 assert_eq!(
1787 run(&s, &a("\"x\"")),
1788 "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number."
1789 );
1790 let cases: Vec<(Node, &str, &str)> = vec![
1791 (coerce(Token::Number), "\"5\"", "5"),
1792 (coerce(Token::Number), "true", "1"),
1793 (coerce(Token::Number), "\"x\"", "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number."),
1794 (coerce(Token::Number), "\"0x10\"", "ERR Validation failed for property \"a\" with string \"0x10\" because the string is not of type number."),
1795 (coerce(Token::Integer), "\"5.5\"", "ERR Validation failed for property \"a\" with number \"5.5\" because the number is not of type integer."),
1796 (coerce(Token::String), "1.5", "\"1.5\""),
1797 (coerce(Token::String), "1000000", "\"1000000\""),
1798 (coerce(Token::String), "false", "\"false\""),
1799 (coerce(Token::Boolean), "\" TRUE \"", "true"),
1800 (coerce(Token::Boolean), "0", "false"),
1801 (coerce(Token::Boolean), "\"yes\"", "ERR Validation failed for property \"a\" with string \"yes\" because the string is not of type boolean."),
1802 (coerce(Token::Date), "\"2020-01-01T00:00:00Z\"", "\"2020-01-01T00:00:00.000Z\""),
1803 (coerce(Token::Date), "\"2020-01-01T12:30:00.5+02:00\"", "\"2020-01-01T10:30:00.500Z\""),
1804 (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."),
1805 (coerce(Token::Date), "1577836800000", "\"2020-01-01T00:00:00.000Z\""),
1806 (coerce(min(2, Token::Number)), "\"1\"", "ERR Value \"1\" for property \"a\" must be a minimum of 2 (was 1)."),
1807 (email(any()), "\"a@b.co\"", "\"a@b.co\""),
1808 (email(any()), "\"nope\"", "ERR Value \"nope\" for property \"a\" is not a valid email address."),
1809 (email(any()), "1", "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type string."),
1810 (url(any()), "\"https://example.com/a?b=c#d\"", "\"https://example.com/a?b=c#d\""),
1811 (url(any()), "\"example.com\"", "ERR Value \"example.com\" for property \"a\" is not a valid URL."),
1812 (uuid(any()), "\"123e4567-e89b-12d3-a456-426614174000\"", "\"123e4567-e89b-12d3-a456-426614174000\""),
1813 (uuid(any()), "\"123e4567e89b12d3a456426614174000\"", "ERR Value \"123e4567e89b12d3a456426614174000\" for property \"a\" is not a valid UUID."),
1814 (date_time(any()), "\"2020-01-01T00:00:00Z\"", "\"2020-01-01T00:00:00Z\""),
1815 (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."),
1816 (ip(any()), "\"127.0.0.1\"", "\"127.0.0.1\""),
1817 (ip(any()), "\"::1\"", "\"::1\""),
1818 (ip(any()), "\"1.2.3\"", "ERR Value \"1.2.3\" for property \"a\" is not a valid IP address."),
1819 (ipv4(any()), "\"::1\"", "ERR Value \"::1\" for property \"a\" is not a valid IPv4 address."),
1820 (ipv6(any()), "\"1.2.3.4\"", "ERR Value \"1.2.3.4\" for property \"a\" is not a valid IPv6 address."),
1821 (ipv6(any()), "\"::ffff:192.168.1.1\"", "\"::ffff:192.168.1.1\""),
1822 (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."),
1823 (fault("boom", min(2, Token::Number)), "1", "ERR Value \"1\" for property \"a\" must be a minimum of 2 (was 1)."),
1824 (fault("boom", email(any())), "1", "ERR boom"),
1825 (
1826 email(Token::Number),
1827 "1",
1828 "ERR Value \"1\" for property \"a\" is not a valid email address.",
1829 ),
1830 (
1831 email(Token::Number),
1832 "\"x\"",
1833 "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number.",
1834 ),
1835 (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."),
1836 (buildize(Token::Number).coerce(), "\"7\"", "7"),
1837 (buildize(Token::Number).describe("n"), "7", "7"),
1838 ];
1839 for (n, input, want) in cases {
1840 let got = run(&at_a(n), &a(input));
1841 let want = if want.starts_with("ERR") {
1842 want.to_string()
1843 } else {
1844 a(want)
1845 };
1846 assert_eq!(got, want, "{}", input);
1847 }
1848 assert_eq!(
1849 run(&at_a(email(any())), "{}"),
1850 "ERR Validation failed for property \"a\" because the property is missing."
1851 );
1852 assert_eq!(run(&at_a(optional(email(any()))), "{}"), a("\"\""));
1853 let e = &at_a(email(any())).error(&j(&a("\"nope\"")))[0];
1854 assert_eq!((e.why.as_str(), e.mark), ("Email", 4000));
1855 assert!(!at_a(email(any())).valid(&j(&a("\"nope\""))));
1856 assert_eq!(stringify_node(&email(any()), false), "String.Email");
1857 }
1858
1859 #[test]
1860 fn types_and_structure() {
1861 assert_eq!(run(&at_a(type_(Kind::Number, any())), &a("3")), a("3"));
1862 assert_eq!(
1863 run(&at_a(type_(Token::Number, any())), &a("\"x\"")),
1864 "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number."
1865 );
1866 assert_eq!(
1867 run(&at_a(type_("String", any())), &a("3")),
1868 "ERR Validation failed for property \"a\" with number \"3\" because the number is not of type string."
1869 );
1870 assert_eq!(
1871 run(&Schema::new(type_("Object", any())), "1"),
1872 "ERR Validation failed for number \"1\" because the number is not of type object."
1873 );
1874 assert_eq!(
1875 run(&Schema::new(type_("Object", any())), r#"{"z":1}"#),
1876 "ERR Validation failed for object \"{z:1}\" because the property \"z\" is not allowed."
1877 );
1878 assert_eq!(type_("nonsense", any()).kind, Kind::Any);
1879 assert_eq!(type_(buildize(Token::Integer), any()).kind, Kind::Integer);
1880 assert_eq!(type_(min(2, any()), any()).kind, Kind::Any);
1881 for (n, k) in [
1882 (any().string(), Kind::String),
1883 (any().number(), Kind::Number),
1884 (any().boolean(), Kind::Boolean),
1885 (any().object(), Kind::Object),
1886 (any().array(), Kind::Array),
1887 (any().function(), Kind::Function),
1888 (any().integer(), Kind::Integer),
1889 (any().date(), Kind::Date),
1890 (buildize(Token::Number).any(), Kind::Any),
1891 ] {
1892 assert_eq!(n.kind, k);
1893 }
1894 assert_eq!(
1895 run(&Schema::new(obj([("n", Spec::from(func(any())))])), "{}"),
1896 "{}"
1897 );
1898 assert_eq!(
1899 run(
1900 &Schema::new(obj([("n", Spec::from(Token::Function))])),
1901 "{}"
1902 ),
1903 "ERR Validation failed for property \"n\" because the property is missing."
1904 );
1905 assert_eq!(buildize(Token::Number).func().kind, Kind::Function);
1906
1907 assert!(!open(Token::Number).is_open());
1908 let tuple = closed(arr([Spec::from(Token::Number)]));
1909 assert_eq!(tuple.arr_children.len(), 1);
1910 assert_eq!(run(&at_a(tuple.clone()), &a("[1]")), a("[1]"));
1911 assert!(!at_a(tuple).valid(&j(&a("[1,2]"))));
1912 assert!(closed(arr([Spec::from(1), Spec::from(2)]))
1913 .arr_child
1914 .is_none());
1915 let c = child(Token::Number, Token::Number);
1916 assert!(c.kind == Kind::Object && c.obj_rest.is_some());
1917 assert!(buildize(Token::Array)
1918 .child(Token::Number)
1919 .arr_child
1920 .is_some());
1921 assert!(buildize(Token::Object)
1922 .child(Token::Number)
1923 .obj_rest
1924 .is_some());
1925 assert_eq!(
1926 run(
1927 &at_a(rest(Token::Number, arr([Spec::from(1)]))),
1928 &a("[1,2,3]")
1929 ),
1930 a("[1,2,3]")
1931 );
1932 assert_eq!(run(&at_a(rest(Token::Number, any())), &a("[2]")), a("[2]"));
1933 assert!(!at_a(rest(Token::Number, arr([Spec::from(1)]))).valid(&j(&a("[1,\"x\"]"))));
1934 assert_eq!(default_of("x").kind, Kind::String);
1935 assert_eq!(run(&at_a(default_of("x")), "{}"), a("\"x\""));
1936 assert_eq!(run(&at_a(empty(any())), &a("\"\"")), a("\"\""));
1937 assert_eq!(run(&at_a(empty(any())), &a("0")), a("0"));
1938 assert_eq!(run(&at_a(ignore(empty(any()))), &a("0")), a("0"));
1939 assert_eq!(
1940 run(&at_a(required(null())), "{}"),
1941 "ERR Validation failed for property \"a\" because the property is missing."
1942 );
1943 assert_eq!(run(&at_a(skip(null())), "{}"), "{}");
1944 assert_eq!(run(&at_a(min(2, null())), "{}"), a("null"));
1945 assert_eq!(
1946 run(&at_a(required(f64::NAN)), "{}"),
1947 "ERR Validation failed for property \"a\" because the property is missing."
1948 );
1949 assert_eq!(run(&at_a(min(2, f64::NAN)), "{}"), a("null"));
1950 assert_eq!(run(&at_a(never(Token::String)), "{}"), "ERR Validation failed for property \"a\" with value \"undefined\" because no value is allowed.");
1951 assert_eq!(
1952 run(&at_a(nullable(closed(obj::<&str, Spec>([])))), &a("null")),
1953 a("null")
1954 );
1955 assert_eq!(run(&at_a(optional(nullable(Token::Number))), "{}"), a("0"));
1956 }
1957
1958 #[test]
1959 fn untyped_defaults_take_the_default_kind() {
1960 let cases: Vec<(Node, &str, &str)> = vec![
1961 (default(2, required(any())), "\"x\"", "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number."),
1962 (default(2, required(any())), "{}", "2"),
1963 (default(2, describe("two", required(any()))), "3", "3"),
1964 (default(2, fault("not two", exact([2]))), "3", "ERR Value \"3\" for property \"a\" must be exactly one of: 2"),
1965 (default(2, exact([2, 3])), "3", "3"),
1966 (default(2, nullable(required(any()))), "null", "null"),
1967 (default("x", empty(required(any()))), "\"\"", "\"\""),
1968 (default(2, after(|_, _| false, any())), "3", "ERR Validation failed for property \"a\" with number \"3\" because check \"After\" failed."),
1969 (default(2, ignore(any())), "\"x\"", "\"x\""),
1971 (default(Value::Undefined, any()), "\"x\"", "\"x\""),
1972 (default(7, Token::Number), "{}", "7"),
1973 ];
1974 for (n, input, want) in cases {
1975 let got = if input == "{}" {
1976 run(&at_a(n), "{}")
1977 } else {
1978 run(&at_a(n), &a(input))
1979 };
1980 let want = if want.starts_with("ERR") || want == "{}" {
1981 want.to_string()
1982 } else {
1983 a(want)
1984 };
1985 assert_eq!(got, want, "{}", input);
1986 }
1987 let d = default(2, describe("two", any()));
1988 assert_eq!(d.meta.get("description"), Some(&Value::from("two")));
1989 }
1990}