1use crate::algebra::{extend_node, omit_node, partial_node, pick_node, Names};
6use crate::builders::*;
7use crate::node::{Kind, Node, Token};
8use crate::normalize::{literal_node, nan_node, normalize, regexp_node_src};
9use crate::spec::Spec;
10use crate::value::Value;
11use regex::Regex;
12use std::fmt;
13use std::sync::OnceLock;
14
15#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct ExprError(pub String);
18
19impl fmt::Display for ExprError {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 f.write_str(&self.0)
22 }
23}
24
25impl std::error::Error for ExprError {}
26
27fn err<T>(msg: String) -> Result<T, ExprError> {
28 Err(ExprError(msg))
29}
30
31pub fn expr(src: &str) -> Result<Node, ExprError> {
33 let tokens = tokenize(src)?;
34 let mut p = Parser::new(tokens, src);
35 p.parse_full()
36}
37
38pub fn expr_apply(src: &str, carrier: Spec) -> Result<Node, ExprError> {
42 let tokens = tokenize(src)?;
43 let mut p = Parser::new(tokens, src);
44 let mut val = carrier;
45 while !p.peek().is_empty() {
46 if p.peek() == "." {
47 p.take();
48 }
49 val = Spec::from(p.parse_chained(val)?);
50 }
51 Ok(normalize(val))
52}
53
54fn token_re() -> &'static Regex {
55 static RE: OnceLock<Regex> = OnceLock::new();
56 RE.get_or_init(|| {
57 Regex::new(
58 r#"\s*,?\s*(-?\d+\.\d+(?:[eE][+-]?\d+)?|[)(.]|"(?:\\.|[^"\\])*"|/(?:\\.|[^/\\])*/[a-z]?|[^)(,.\s]+)\s*"#,
59 )
60 .unwrap()
61 })
62}
63
64fn tokenize(src: &str) -> Result<Vec<String>, ExprError> {
65 if src.trim().is_empty() {
66 return err("Shape: empty expression".to_string());
67 }
68 let mut tokens = Vec::new();
69 let mut pos = 0;
70 for m in token_re().captures_iter(src) {
71 let whole = m.get(0).unwrap();
72 if whole.start() != pos {
73 return err(format!(
74 "Shape: unexpected character at offset {} in expression {:?}",
75 pos, src
76 ));
77 }
78 pos = whole.end();
79 tokens.push(m.get(1).unwrap().as_str().to_string());
80 }
81 if pos != src.len() {
82 return err(format!(
83 "Shape: unexpected trailing text in expression {:?}",
84 src
85 ));
86 }
87 Ok(tokens)
88}
89
90struct Parser<'s> {
91 tokens: Vec<String>,
92 src: &'s str,
93 i: usize,
94 refs: std::collections::HashMap<String, Spec>,
97}
98
99impl<'s> Parser<'s> {
100 fn new(tokens: Vec<String>, src: &'s str) -> Parser<'s> {
101 Parser {
102 tokens,
103 src,
104 i: 0,
105 refs: std::collections::HashMap::new(),
106 }
107 }
108}
109
110fn type_token(name: &str) -> Option<Token> {
111 Some(match name {
112 "Any" => Token::Any,
113 "String" => Token::String,
114 "Number" => Token::Number,
115 "Boolean" => Token::Boolean,
116 "Object" => Token::Object,
117 "Array" => Token::Array,
118 "Function" => Token::Function,
119 "Integer" => Token::Integer,
120 "Date" => Token::Date,
121 "BigInt" => Token::BigInt,
122 _ => return None,
123 })
124}
125
126const BUILDERS: [&str; 45] = [
127 "Required",
128 "Optional",
129 "Open",
130 "Closed",
131 "Skip",
132 "Ignore",
133 "Empty",
134 "Never",
135 "Func",
136 "Nullable",
137 "Coerce",
138 "Email",
139 "Url",
140 "Uuid",
141 "DateTime",
142 "Ip",
143 "Ipv4",
144 "Ipv6",
145 "Default",
146 "Catch",
147 "Describe",
148 "Pick",
149 "Omit",
150 "Partial",
151 "Extend",
152 "Fault",
153 "Type",
154 "Exact",
155 "Min",
156 "Max",
157 "Above",
158 "Below",
159 "Len",
160 "Check",
161 "One",
162 "Some",
163 "All",
164 "Child",
165 "Rest",
166 "Define",
167 "Refer",
168 "Rename",
169 "Key",
170 "Transform",
171 "Discriminated",
172];
173
174fn is_builder(name: &str) -> bool {
175 BUILDERS.contains(&name)
176}
177
178fn type_node(tok: Token, args: Vec<Spec>) -> Node {
182 let spec = args.into_iter().next().unwrap_or_else(|| Spec::from(any()));
183 type_(tok, spec)
184}
185
186fn regexp_token(head: &str) -> Option<Result<String, ExprError>> {
191 let bytes = head.as_bytes();
192 if head.len() >= 3
193 && head.starts_with('/')
194 && bytes[head.len() - 1].is_ascii_lowercase()
195 && bytes[head.len() - 2] == b'/'
196 {
197 let body = &head[1..head.len() - 2];
198 return Some(Err(ExprError(crate::regexp::regexp_fault(
199 body,
200 "flags are not supported",
201 ))));
202 }
203 if head.len() >= 2 && head.starts_with('/') && head.ends_with('/') {
204 let body = &head[1..head.len() - 1];
205 Some(
206 crate::regexp::canonical_regexp(body)
207 .map(|_| body.to_string())
208 .map_err(ExprError),
209 )
210 } else {
211 None
212 }
213}
214
215fn json_literal(head: &str) -> Option<Value> {
216 serde_json::from_str::<serde_json::Value>(head)
217 .ok()
218 .map(Value::from)
219}
220
221impl<'s> Parser<'s> {
222 fn peek(&self) -> &str {
223 self.tokens.get(self.i).map(|s| s.as_str()).unwrap_or("")
224 }
225
226 fn take(&mut self) -> String {
227 let t = self.peek().to_string();
228 if !t.is_empty() {
229 self.i += 1;
230 }
231 t
232 }
233
234 fn unexpected<T>(&self, head: &str) -> Result<T, ExprError> {
235 err(format!(
236 "Shape: unexpected token {} in builder expression {}",
237 head, self.src
238 ))
239 }
240
241 fn parse_full(&mut self) -> Result<Node, ExprError> {
242 let mut val = self.parse_term()?;
243 while !self.peek().is_empty() {
246 if self.peek() == "." {
247 self.take();
248 }
249 val = self.parse_chained(Spec::from(val))?;
250 }
251 Ok(val)
252 }
253
254 fn parse_term(&mut self) -> Result<Node, ExprError> {
258 let head = self.take();
259 if head == ")" || head == "(" || head == "." {
260 return self.unexpected(&head);
261 }
262 if is_builder(&head) {
263 let args = self.parse_args()?;
264 return call_builder(&head, args);
265 }
266 if let Some(tok) = type_token(&head) {
267 let args = self.parse_args()?;
268 return Ok(type_node(tok, args));
269 }
270 if head == "NaN" {
271 self.parse_args()?;
272 return Ok(nan_node());
273 }
274 if head == "undefined" || head == "null" {
275 self.parse_args()?;
276 return Ok(literal_node(Value::Null));
277 }
278 if let Some(re) = regexp_token(&head) {
279 return Ok(regexp_node_src(&re?));
282 }
283 if let Some(lit) = json_literal(&head) {
284 return Ok(default_of(lit));
285 }
286 self.unexpected(&head)
287 }
288
289 fn parse_chained(&mut self, carrier: Spec) -> Result<Node, ExprError> {
290 let head = self.take();
291 if head.is_empty() {
292 return Ok(normalize(carrier));
293 }
294 if let Some(r) = self.refs.get(&head) {
295 return Ok(normalize(r.clone()));
296 }
297 if head == "Exact" {
301 if let Spec::Node(n) = carrier {
302 let args = self.parse_args()?;
303 return Ok(n.exact(exact_vals(args)?));
304 }
305 }
306 if is_builder(&head) {
307 let mut args = self.parse_args()?;
308 args.push(carrier);
310 return call_builder(&head, args);
311 }
312 if let Some(tok) = type_token(&head) {
315 self.parse_args()?;
316 return Ok(type_(tok, carrier));
317 }
318 self.unexpected(&head)
319 }
320
321 fn parse_args(&mut self) -> Result<Vec<Spec>, ExprError> {
323 if self.peek() != "(" {
324 return Ok(Vec::new());
325 }
326 self.take();
327 let mut args = Vec::new();
328 loop {
329 if self.peek() == ")" {
330 self.take();
331 return Ok(args);
332 }
333 if self.peek().is_empty() {
334 return err(format!(
335 "Shape: unclosed argument list in expression {:?}",
336 self.src
337 ));
338 }
339 args.push(self.parse_arg()?);
340 }
341 }
342
343 fn parse_arg(&mut self) -> Result<Spec, ExprError> {
347 let head = self.take();
348 if let Some(r) = self.refs.get(&head) {
349 return Ok(r.clone());
350 }
351 if is_builder(&head) {
352 let args = self.parse_args()?;
353 let node = call_builder(&head, args)?;
354 return self.chain_continuation(node);
355 }
356 if let Some(tok) = type_token(&head) {
357 let args = self.parse_args()?;
358 return self.chain_continuation(type_node(tok, args));
359 }
360 if head == "NaN" {
361 return Ok(Spec::Value(Value::Num(f64::NAN)));
363 }
364 if head == "undefined" || head == "null" {
365 return Ok(Spec::Value(Value::Null));
366 }
367 if let Some(re) = regexp_token(&head) {
368 return Ok(Spec::Regexp(re?));
369 }
370 if let Some(lit) = json_literal(&head) {
371 return Ok(Spec::Value(lit));
372 }
373 self.unexpected(&head)
374 }
375
376 fn chain_continuation(&mut self, mut node: Node) -> Result<Spec, ExprError> {
377 while self.peek() == "." {
378 self.take();
379 node = self.parse_chained(Spec::from(node))?;
380 }
381 Ok(Spec::from(node))
382 }
383}
384
385fn shape_at(args: &mut Vec<Spec>, i: usize, bare: Spec) -> Spec {
387 if i < args.len() {
388 args.remove(i)
389 } else {
390 bare
391 }
392}
393
394fn value_at(args: &[Spec], i: usize) -> Option<Value> {
395 match args.get(i) {
396 Some(Spec::Value(v)) => Some(v.clone()),
397 _ => None,
398 }
399}
400
401fn string_at(name: &str, what: &str, args: &[Spec], i: usize) -> Result<String, ExprError> {
402 match args.get(i) {
403 None => err(format!("{}: missing {}", name, what)),
404 Some(Spec::Value(Value::Str(s))) => Ok(s.clone()),
405 Some(_) => err(format!("{}: {} must be a string", name, what)),
406 }
407}
408
409fn call_builder(name: &str, args: Vec<Spec>) -> Result<Node, ExprError> {
414 let node = build_call(name, args)?;
415 if crate::builders::is_fault(&node) {
416 return err(node.fault_msg.clone().unwrap_or_default());
417 }
418 Ok(node)
419}
420
421fn exact_vals(args: Vec<Spec>) -> Result<Vec<Value>, ExprError> {
423 let mut vals = Vec::with_capacity(args.len());
424 for a in args {
425 match a {
426 Spec::Value(v) => vals.push(v),
427 _ => return err("Exact: values expected".to_string()),
428 }
429 }
430 Ok(vals)
431}
432
433fn build_call(name: &str, mut args: Vec<Spec>) -> Result<Node, ExprError> {
434 let any_spec = || Spec::from(any());
435 let unary =
436 |args: &mut Vec<Spec>, f: fn(Spec) -> Node| Ok(f(shape_at(args, 0, Spec::from(any()))));
437 match name {
438 "Required" => unary(&mut args, required),
439 "Optional" => unary(&mut args, optional),
440 "Open" => Ok(open(shape_at(&mut args, 0, Spec::Obj(Vec::new())))),
441 "Closed" => unary(&mut args, closed),
442 "Skip" => unary(&mut args, skip),
443 "Ignore" => unary(&mut args, ignore),
444 "Empty" => unary(&mut args, empty),
445 "Never" => unary(&mut args, never),
446 "Func" => unary(&mut args, func),
447 "Nullable" => unary(&mut args, nullable),
448 "Coerce" => unary(&mut args, coerce),
449 "Email" => unary(&mut args, email),
450 "Url" => unary(&mut args, url),
451 "Uuid" => unary(&mut args, uuid),
452 "DateTime" => unary(&mut args, date_time),
453 "Ip" => unary(&mut args, ip),
454 "Ipv4" => unary(&mut args, ipv4),
455 "Ipv6" => unary(&mut args, ipv6),
456 "Default" => {
457 if args.is_empty() {
458 return err("Default: missing default value".to_string());
459 }
460 let Some(dval) = value_at(&args, 0) else {
461 return err("Default: default value must be a value".to_string());
462 };
463 if args.len() == 1 {
464 return Ok(default_of(dval));
465 }
466 Ok(default(dval, shape_at(&mut args, 1, any_spec())))
467 }
468 "Catch" => {
469 if args.is_empty() {
470 return err("Catch: missing fallback value".to_string());
471 }
472 let Some(fb) = value_at(&args, 0) else {
473 return err("Catch: fallback value must be a value".to_string());
474 };
475 Ok(catch(fb, shape_at(&mut args, 1, any_spec())))
476 }
477 "Describe" => {
478 let msg = string_at("Describe", "description", &args, 0)?;
479 Ok(describe(msg, shape_at(&mut args, 1, any_spec())))
480 }
481 "Fault" => {
482 let msg = string_at("Fault", "message", &args, 0)?;
483 Ok(fault(msg, shape_at(&mut args, 1, any_spec())))
484 }
485 "Type" => {
486 if args.is_empty() {
487 return err("Type: missing kind".to_string());
488 }
489 let kind = args.remove(0);
490 let spec = shape_at(&mut args, 0, any_spec());
491 Ok(match kind {
492 Spec::Node(n) => type_(*n, spec),
493 Spec::Token(t) => type_(t, spec),
494 Spec::Value(Value::Str(name)) => type_(name.as_str(), spec),
495 _ => normalize(spec),
497 })
498 }
499 "Exact" => Ok(exact(exact_vals(args)?)),
500 "Discriminated" => {
501 if args.len() < 2 {
502 return err("Discriminated: missing tag or branches".to_string());
503 }
504 let tag = string_at("Discriminated", "tag", &args, 0)?;
505 let Spec::Obj(branches) = args.remove(1) else {
506 return err("Discriminated: branches must be an object".to_string());
507 };
508 Ok(crate::discriminated::discriminated(tag, branches))
509 }
510 "Min" | "Max" | "Above" | "Below" => {
511 if args.is_empty() {
512 return err(format!("{}: missing limit", name));
513 }
514 let bound = value_at(&args, 0).unwrap_or(Value::Undefined);
517 let spec = shape_at(&mut args, 1, any_spec());
518 Ok(match name {
519 "Min" => min(bound, spec),
520 "Max" => max(bound, spec),
521 "Above" => above(bound, spec),
522 _ => below(bound, spec),
523 })
524 }
525 "Len" => {
526 if args.is_empty() {
527 return err("Len: missing length".to_string());
528 }
529 let Some(Value::Num(f)) = value_at(&args, 0) else {
530 return err("Len: length must be integer".to_string());
531 };
532 if f != f.trunc() {
533 return err("Shape: Len needs a whole number of zero or more".to_string());
534 }
535 Ok(len(f, shape_at(&mut args, 1, any_spec())))
536 }
537 "Check" => {
538 if args.is_empty() {
539 return err("Check: missing checker".to_string());
540 }
541 let checker = args.remove(0);
542 let spec = shape_at(&mut args, 0, any_spec());
543 Ok(match checker {
544 Spec::Regexp(src) => check_re_src(&src, spec),
545 _ => normalize(spec),
547 })
548 }
549 "One" => Ok(one(args)),
550 "Some" => Ok(some(args)),
551 "All" => Ok(all(args)),
552 "Child" => {
553 if args.is_empty() {
554 return err("Child: missing child shape".to_string());
555 }
556 let c = args.remove(0);
557 let spec = shape_at(
559 &mut args,
560 0,
561 Spec::from(default(
562 Value::Obj(Default::default()),
563 Spec::Obj(Vec::new()),
564 )),
565 );
566 Ok(child(c, spec))
567 }
568 "Rest" => {
569 if args.is_empty() {
570 return err("Rest: missing child shape".to_string());
571 }
572 let c = args.remove(0);
573 let spec = shape_at(&mut args, 0, Spec::Arr(Vec::new()));
574 Ok(rest(c, spec))
575 }
576 "Define" => {
577 let n = string_at("Define", "name", &args, 0)?;
578 Ok(define(n, shape_at(&mut args, 1, any_spec())))
579 }
580 "Refer" => {
581 let n = string_at("Refer", "name", &args, 0)?;
582 Ok(refer(n, shape_at(&mut args, 1, any_spec())))
583 }
584 "Rename" => {
585 let n = string_at("Rename", "name", &args, 0)?;
586 Ok(rename(n, shape_at(&mut args, 1, any_spec())))
587 }
588 "Key" => {
589 let vals: Vec<Value> = args
590 .into_iter()
591 .filter_map(|a| match a {
592 Spec::Value(v) => Some(v),
593 _ => None,
594 })
595 .collect();
596 Ok(key_args(&vals))
597 }
598 "Pick" | "Omit" => {
599 if args.is_empty() {
600 return err(format!("{}: missing property names", name));
601 }
602 let names = match value_at(&args, 0) {
603 Some(v) => {
604 Names::from_value(&v, name).map_err(|e| ExprError(format!("Shape: {}", e)))?
605 }
606 None => return err(format!("Shape: {} needs a list of property names", name)),
607 };
608 let spec = shape_at(&mut args, 1, any_spec());
609 let built = if name == "Pick" {
610 pick_node(names, spec)
611 } else {
612 omit_node(names, spec)
613 };
614 built.map_err(|e| ExprError(format!("Shape: {}", e)))
615 }
616 "Partial" => partial_node(shape_at(&mut args, 0, any_spec()))
617 .map_err(|e| ExprError(format!("Shape: {}", e))),
618 "Extend" => {
619 if args.is_empty() {
620 return err("Extend: missing extension".to_string());
621 }
622 let extra = args.remove(0);
623 let spec = shape_at(&mut args, 0, any_spec());
624 extend_node(extra, spec).map_err(|e| ExprError(format!("Shape: {}", e)))
625 }
626 _ => err(format!(
627 "Shape: {} is not available in the string form",
628 name
629 )),
630 }
631}
632
633fn same_shape_node(x: &Node, y: &Node) -> bool {
639 x.kind == y.kind
640 && x.required == y.required
641 && x.skippable == y.skippable
642 && x.befores.len() == y.befores.len()
643 && x.afters.len() == y.afters.len()
644 && x.has_default == y.has_default
645 && x.default == y.default
646 && x.obj_children.len() == y.obj_children.len()
647 && x.arr_children.len() == y.arr_children.len()
648 && x.obj_rest.is_some() == y.obj_rest.is_some()
649 && x.arr_child.is_some() == y.arr_child.is_some()
650 && x.arr_rest.is_some() == y.arr_rest.is_some()
651}
652
653pub(crate) fn key_expr_node(src: &str, example: Spec) -> Node {
662 let bare = expr(src);
663 let or_fault = |r: Result<Node, ExprError>| r.unwrap_or_else(|e| fault_node(e.0));
664 if matches!(example, Spec::Value(Value::Null)) {
665 return or_fault(bare);
666 }
667 let ex = normalize(example.clone());
668
669 if let Ok(bare) = &bare {
675 if bare.kind_set {
676 let mut b = bare.clone();
677 b.has_default = ex.has_default;
678 b.default = ex.default;
679 b.literal = ex.literal;
680 if b.kind == Kind::Object && ex.kind == Kind::Object {
681 b.obj_children = ex.obj_children;
682 if b.obj_rest.is_none() {
683 b.obj_rest = ex.obj_rest;
684 }
685 } else if b.kind == Kind::Array && ex.kind == Kind::Array {
686 b.arr_children = ex.arr_children;
687 if b.arr_child.is_none() && b.arr_rest.is_none() {
688 b.arr_child = ex.arr_child;
689 }
690 }
691 return b;
692 }
693 }
694
695 let Ok(mut node) = expr_apply(src, example.clone()) else {
696 return or_fault(bare);
700 };
701 let takes_example = match &bare {
702 Err(_) => ex.kind != node.kind,
707 Ok(bare) => same_shape_node(&node, bare),
708 };
709 if takes_example {
710 if let Spec::Value(v) = example {
711 node.has_default = true;
712 node.default = v.clone();
713 node.literal = Some(v);
714 }
715 }
716 node
717}
718
719pub(crate) fn split_key_expr(key: &str) -> Option<(String, String)> {
722 static RE: OnceLock<Regex> = OnceLock::new();
723 let re =
724 RE.get_or_init(|| Regex::new(r#"^\s*("(?:\\.|[^"\\])*"|[^\s]+):\s*(.*?)\s*$"#).unwrap());
725 let m = re.captures(key)?;
726 let src = m.get(2).unwrap().as_str();
727 if src.is_empty() {
728 return None;
729 }
730 let mut name = m.get(1).unwrap().as_str().to_string();
731 if name.len() >= 2 && name.starts_with('"') && name.ends_with('"') {
732 name = serde_json::from_str::<String>(&name)
734 .unwrap_or_else(|_| name[1..name.len() - 1].to_string());
735 }
736 Some((name, src.to_string()))
737}
738
739const COMPOSITION: [&str; 5] = ["One", "Some", "All", "Exact", "Discriminated"];
745
746pub fn build(v: &Value) -> Result<Spec, ExprError> {
752 build_value(v, false)
753}
754
755fn build_value(v: &Value, example: bool) -> Result<Spec, ExprError> {
758 match v {
759 Value::Str(s) if example || s.is_empty() => Ok(Spec::Value(Value::Str(s.clone()))),
762 Value::Str(s) => expr(s).map(Spec::from),
763 Value::Obj(m) => {
764 let mut pairs: Vec<(String, Spec)> = Vec::with_capacity(m.len());
765 let mut mark: Option<String> = None;
766 for (k, sv) in m {
767 if k == "$$" {
768 if let Value::Str(src) = sv {
769 mark = Some(src.clone());
770 continue;
771 }
772 }
773 let is_key_expr = matches!(sv, Value::Str(_)) && split_key_expr(k).is_some();
774 pairs.push((k.clone(), build_value(sv, is_key_expr)?));
775 }
776 match mark {
777 Some(src) => build_mark(&src, pairs),
778 None => Ok(Spec::Obj(pairs)),
779 }
780 }
781 Value::Arr(a) => {
782 let mut out = Vec::with_capacity(a.len());
783 for sv in a {
784 out.push(build_value(sv, false)?);
785 }
786 Ok(Spec::Arr(out))
787 }
788 other => Ok(Spec::Value(other.clone())),
789 }
790}
791
792fn build_mark(src: &str, pairs: Vec<(String, Spec)>) -> Result<Spec, ExprError> {
797 let mut refs = std::collections::HashMap::new();
798 let mut rest = Vec::with_capacity(pairs.len());
799 for (k, v) in pairs {
800 if k.starts_with("$$") {
801 refs.insert(k, v);
802 } else {
803 rest.push((k, v));
804 }
805 }
806 let tokens = tokenize(src)?;
807 let mut p = Parser::new(tokens, src);
808 p.refs = refs;
809 if COMPOSITION.contains(&p.peek()) {
810 return p.parse_full().map(Spec::from);
811 }
812 let mut val = Spec::Obj(rest);
813 while !p.peek().is_empty() {
814 if p.peek() == "." {
815 p.take();
816 }
817 val = Spec::from(p.parse_chained(val)?);
818 }
819 Ok(val)
820}
821
822#[cfg(test)]
823mod tests {
824 use super::*;
825 use crate::spec::{arr, obj};
826 use crate::stringify::stringify_node;
827 use crate::Schema;
828
829 fn render(src: &str) -> String {
830 stringify_node(
831 &expr(src).unwrap_or_else(|e| panic!("{}: {}", src, e)),
832 false,
833 )
834 }
835
836 fn fails(src: &str) -> String {
837 expr(src).unwrap_err().0
838 }
839
840 #[test]
841 fn a_wrong_builder_argument_is_a_parse_error() {
842 assert_eq!(fails("String.Min(\"x\")"), "Shape: Min needs a number");
843 assert_eq!(
844 fails("Len(-1)"),
845 "Shape: Len needs a whole number of zero or more"
846 );
847 assert_eq!(fails("Open(Define(\"\"))"), "Shape: Define needs a name");
848 assert_eq!(fails("Min(Number)"), "Shape: Min needs a number");
849 assert!(expr("Never.Fault(\"f\")").is_ok());
851 assert!(expr("Fault(\"f\", Never)").is_ok());
852 }
853
854 #[test]
855 fn parses_terms_chains_and_arguments() {
856 let cases = [
857 ("String.Min(2).Max(10)", "String.Min(2).Max(10)"),
858 ("Min(2, Number)", "Number.Min(2)"),
859 ("Number Min(2)", "Number.Min(2)"),
860 ("Min(2).Number", "Number.Min(2)"),
861 ("String.Array(1)", "[]"),
862 ("5", "5"),
863 ("\"x\"", "\"x\""),
864 ("null", "null"),
865 ("undefined", "null"),
866 ("null(1)", "null"),
867 ("NaN", "NaN"),
868 ("NaN(1)", "NaN"),
869 ("/^a/", "/^a/"),
870 ("Check(/^a/)", "Check.Check(/^a/)"),
871 ("Check(/^a/, String)", "String.Check(/^a/)"),
872 ("Check(1)", "Any"),
873 ("One(String, 1, NaN, /x/)", "One(String,1,NaN,/x/)"),
874 ("Some(Number)", "Some(Number)"),
875 ("All(Number)", "All(Number)"),
876 ("Optional(Number)", "0"),
877 ("Required()", "Any"),
878 ("Required(null)", "null"),
879 ("Open", "{}.Open()"),
880 ("Open(Number)", "Number"),
881 ("Closed", "Any"),
882 ("Child(Number)", "{}.Child(Number)"),
883 ("Rest(Number)", "[...Number]"),
884 ("Rest(Number, [1])", "[...Number]"),
886 ("Type(Number)", "Number"),
887 ("Type(\"String\")", "String"),
888 ("Type(Min(2))", "Any"),
889 ("Type(1)", "Any"),
890 ("Exact(1, \"a\", null)", "Exact(1, a, null)"),
891 ("Len(2)", "Len(2)"),
892 ("Key(1, \"/\")", "String.Key()"),
893 ("Key(Number)", "String.Key()"),
894 ("Default(7)", "7"),
895 ("Default(7, Number)", "7"),
896 ("Default(null, Number)", "null"),
897 ("Catch(0, Number)", "Number.Catch(0)"),
898 ("Describe(\"d\", Number)", "Number"),
899 ("Fault(\"f\")", "Any"),
900 ("Email", "String.Email"),
901 ("Url", "String.Url"),
902 ("Uuid", "String.Uuid"),
903 ("DateTime", "String.DateTime"),
904 ("Ip", "String.Ip"),
905 ("Ipv4", "String.Ipv4"),
906 ("Ipv6", "String.Ipv6"),
907 ("Coerce(Number)", "Number"),
908 ("Nullable(Number)", "Number"),
909 ("Never", "Never"),
910 ("Func", "Function"),
911 ("Empty", "Any"),
912 ("Ignore(Number)", "0"),
913 ("Skip(Number)", "0"),
914 ("Define(\"d\")", "Define(\"d\")"),
915 ("Refer(\"d\")", "Refer(\"d\")"),
916 ("Rename(\"b\")", "Any"),
917 ("Min(\"2\")", "Min(2)"),
918 ("Above(1).Below(3)", "Above(1).Below(3)"),
919 ("Max(3, Integer)", "Integer.Max(3)"),
920 ("Object", "{}"),
921 ("Array", "[]"),
922 ("Any", "Any"),
923 ("Date", "Date"),
924 ("BigInt", "BigInt"),
925 ("Boolean", "Boolean"),
926 ("Function", "Function"),
927 ("String(Min(2))", "String.Min(2)"),
928 ("Min(2).", "Min(2)"),
929 ("One(Number.Min(2), String)", "One(Number.Min(2),String)"),
930 ("Optional(Min(2).Number)", "0.Min(2)"),
931 ("Optional(Number)", "0"),
932 ("Min(2, /^a/)", "/^a/.Min(2)"),
933 ];
934 for (src, want) in cases {
935 assert_eq!(render(src), want, "{}", src);
936 }
937 assert_eq!(
939 call_builder("Len", vec![Spec::Value(Value::Num(2.7))]).unwrap_err(),
940 ExprError("Shape: Len needs a whole number of zero or more".to_string())
941 );
942 assert_eq!(
944 stringify_node(
945 &call_builder("Type", vec![Spec::Token(Token::Number)]).unwrap(),
946 false
947 ),
948 "Number"
949 );
950 let s = Schema::parse("Min(2).Array").unwrap();
951 assert!(s.valid(&Value::Arr(vec![Value::from(1), Value::from(2)])));
952 assert!(!s.valid(&Value::Arr(vec![Value::from(1)])));
953 assert!(Schema::parse("bogus").is_err());
954 assert_eq!(
955 stringify_node(&expr_apply(".Min(2)", Spec::from(1)).unwrap(), false),
956 "1.Min(2)"
957 );
958 assert_eq!(
959 stringify_node(
960 &expr_apply("Open", obj([("a", Spec::from(1))])).unwrap(),
961 false
962 ),
963 "{a: 1}.Open()"
964 );
965 assert!(expr_apply("bogus", Spec::from(1)).is_err());
966 assert_eq!(format!("{}", ExprError("x".into())), "x");
967 }
968
969 #[test]
970 fn rejects_what_it_cannot_read() {
971 let cases = [
972 ("", "Shape: empty expression"),
973 (" ", "Shape: empty expression"),
974 (
975 ",,a",
976 "Shape: unexpected character at offset 0 in expression \",,a\"",
977 ),
978 (",", "Shape: unexpected trailing text in expression \",\""),
979 ("(", "Shape: unexpected token ( in builder expression ("),
980 (")", "Shape: unexpected token ) in builder expression )"),
981 (".", "Shape: unexpected token . in builder expression ."),
982 (
983 "bogus",
984 "Shape: unexpected token bogus in builder expression bogus",
985 ),
986 (
987 "Min(2).bogus",
988 "Shape: unexpected token bogus in builder expression Min(2).bogus",
989 ),
990 (
991 "Min(2) )",
992 "Shape: unexpected token ) in builder expression Min(2) )",
993 ),
994 (
995 "Min(()",
996 "Shape: unexpected token ( in builder expression Min(()",
997 ),
998 (
999 "Min(2",
1000 "Shape: unclosed argument list in expression \"Min(2\"",
1001 ),
1002 (
1003 "Min(",
1004 "Shape: unclosed argument list in expression \"Min(\"",
1005 ),
1006 ("/a/i", "Shape: invalid regexp /a/: flags are not supported"),
1007 ("Min()", "Min: missing limit"),
1008 ("Max()", "Max: missing limit"),
1009 ("Above()", "Above: missing limit"),
1010 ("Below()", "Below: missing limit"),
1011 ("Len()", "Len: missing length"),
1012 ("Len(\"x\")", "Len: length must be integer"),
1013 ("Default()", "Default: missing default value"),
1014 ("Default(Number)", "Default: default value must be a value"),
1015 ("Catch()", "Catch: missing fallback value"),
1016 ("Catch(Number)", "Catch: fallback value must be a value"),
1017 ("Describe()", "Describe: missing description"),
1018 ("Describe(1)", "Describe: description must be a string"),
1019 ("Fault()", "Fault: missing message"),
1020 ("Fault(1)", "Fault: message must be a string"),
1021 ("Type()", "Type: missing kind"),
1022 ("Exact(Number)", "Exact: values expected"),
1023 ("Check()", "Check: missing checker"),
1024 ("Child()", "Child: missing child shape"),
1025 ("Rest()", "Rest: missing child shape"),
1026 ("Define()", "Define: missing name"),
1027 ("Define(1)", "Define: name must be a string"),
1028 ("Refer()", "Refer: missing name"),
1029 ("Rename()", "Rename: missing name"),
1030 ("Pick([\"a\"])", "Shape: Pick needs an object shape"),
1031 ("Pick()", "Pick: missing property names"),
1032 ("Omit(1)", "Shape: Omit needs a list of property names"),
1033 ("Omit(Number)", "Shape: Omit needs a list of property names"),
1034 ("Partial", "Shape: Partial needs an object shape"),
1035 ("Extend()", "Extend: missing extension"),
1036 (
1037 "Extend(Number, Number)",
1038 "Shape: Extend needs an object shape",
1039 ),
1040 (
1041 "Transform",
1042 "Shape: Transform is not available in the string form",
1043 ),
1044 ];
1045 for (src, want) in cases {
1046 assert_eq!(fails(src), want, "{}", src);
1047 }
1048 assert_eq!(
1049 fails("/[/"),
1050 "Shape: invalid regexp /[/: unterminated character class"
1051 );
1052 assert_eq!(
1053 fails("Min(2, /[/)"),
1054 "Shape: invalid regexp /[/: unterminated character class"
1055 );
1056 }
1057
1058 #[test]
1059 fn key_expressions_take_the_example() {
1060 let s = |src: &str, ex: Spec| stringify_node(&key_expr_node(src, ex), false);
1061 assert_eq!(s("Min(2)", Spec::Value(Value::Null)), "Min(2)");
1063 assert_eq!(s("5", Spec::from(3)), "5");
1065 assert_eq!(s("Min()", Spec::from(3)), "Any(3).Min(3)");
1068 assert_eq!(s("bogus()", Spec::from(3)), "Never");
1070 assert_eq!(
1072 s("Child()", arr([Spec::from(Token::Number)])),
1073 "{}.Child([Number])"
1074 );
1075 assert_eq!(s("Child(Number)", arr::<Spec>([])), "[Number]");
1077 assert_eq!(s("Optional(Number)", Spec::from(5)), "5");
1079 assert_eq!(s("Any", Spec::from(5)), "Any(5)");
1080 assert_eq!(
1081 split_key_expr("\"a\\\"b\": Min(1)"),
1082 Some(("a\"b".into(), "Min(1)".into()))
1083 );
1084 assert_eq!(
1085 split_key_expr("\"a\\q\": Min(1)"),
1086 Some(("a\\q".into(), "Min(1)".into()))
1087 );
1088 assert_eq!(split_key_expr("a:"), None);
1089 assert_eq!(split_key_expr("a b: Min(1)"), None);
1090 assert_eq!(
1091 split_key_expr("a: Min(1) "),
1092 Some(("a".into(), "Min(1)".into()))
1093 );
1094 }
1095}