Skip to main content

shape/
node.rs

1//! The compiled form of a spec: a tree of nodes, each a kind with its flags,
2//! its children and its validators.
3
4use crate::context::{State, Update};
5use crate::value::Value;
6use indexmap::IndexMap;
7use regex::Regex;
8use std::fmt;
9use std::sync::Arc;
10
11/// The kind of value a node accepts. The names are the TypeScript ones,
12/// which the messages use.
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
14pub enum Kind {
15    #[default]
16    Any,
17    String,
18    Number,
19    Boolean,
20    Object,
21    Array,
22    Null,
23    NaN,
24    Function,
25    Never,
26    Check,
27    Regexp,
28    Integer,
29    Date,
30    BigInt,
31    List,
32}
33
34impl Kind {
35    pub fn as_str(self) -> &'static str {
36        match self {
37            Kind::Any => "any",
38            Kind::String => "string",
39            Kind::Number => "number",
40            Kind::Boolean => "boolean",
41            Kind::Object => "object",
42            Kind::Array => "array",
43            Kind::Null => "null",
44            Kind::NaN => "nan",
45            Kind::Function => "function",
46            Kind::Never => "never",
47            Kind::Check => "check",
48            Kind::Regexp => "regexp",
49            Kind::Integer => "integer",
50            Kind::Date => "date",
51            Kind::BigInt => "bigint",
52            Kind::List => "list",
53        }
54    }
55}
56
57impl Kind {
58    /// The kind of a name, as `as_str` renders it, or as a type token is
59    /// written ("String").
60    pub fn from_name(name: &str) -> Option<Kind> {
61        ALL_KINDS
62            .iter()
63            .copied()
64            .find(|k| k.as_str() == name || k.as_str().eq_ignore_ascii_case(name))
65    }
66}
67
68const ALL_KINDS: [Kind; 16] = [
69    Kind::Any,
70    Kind::String,
71    Kind::Number,
72    Kind::Boolean,
73    Kind::Object,
74    Kind::Array,
75    Kind::Null,
76    Kind::NaN,
77    Kind::Function,
78    Kind::Never,
79    Kind::Check,
80    Kind::Regexp,
81    Kind::Integer,
82    Kind::Date,
83    Kind::BigInt,
84    Kind::List,
85];
86
87impl fmt::Display for Kind {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        f.write_str(self.as_str())
90    }
91}
92
93/// A type token: the required kind a spec names by its constructor in
94/// TypeScript (`String`, `Number`, ...).
95#[derive(Clone, Copy, Debug, PartialEq, Eq)]
96pub enum Token {
97    Any,
98    String,
99    Number,
100    Boolean,
101    Object,
102    Array,
103    Function,
104    Integer,
105    Date,
106    BigInt,
107}
108
109impl Token {
110    pub fn kind(self) -> Kind {
111        match self {
112            Token::Any => Kind::Any,
113            Token::String => Kind::String,
114            Token::Number => Kind::Number,
115            Token::Boolean => Kind::Boolean,
116            Token::Object => Kind::Object,
117            Token::Array => Kind::Array,
118            Token::Function => Kind::Function,
119            Token::Integer => Kind::Integer,
120            Token::Date => Kind::Date,
121            Token::BigInt => Kind::BigInt,
122        }
123    }
124}
125
126/// How a composition node judges its branches.
127#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
128pub enum ListMode {
129    #[default]
130    None,
131    One,
132    Some,
133    All,
134}
135
136/// The function of a custom validator: the current state and an update to
137/// fill in; true to pass.
138pub type ValidatorFn = dyn Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync;
139
140/// A custom check attached to a node, before or after its structural check.
141#[derive(Clone)]
142pub struct Validator {
143    pub name: String,
144    pub func: Arc<ValidatorFn>,
145    pub args: Vec<Value>,
146    /// The `.Name(args)` suffix the validator renders as in a spec text.
147    pub suffix: Option<String>,
148    /// The checks a Catch or Transform took inside.
149    pub inner: Option<Arc<crate::isolate::Inner>>,
150}
151
152impl fmt::Debug for Validator {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        write!(f, "Validator({})", self.name)
155    }
156}
157
158/// A node of the compiled tree.
159#[derive(Clone, Debug, Default)]
160pub struct Node {
161    pub kind: Kind,
162    pub required: bool,
163    pub required_set: bool,
164    /// The kind was named by the spec (a type token, `type_`), as against
165    /// implied by a value: a key expression's example keeps the named kind
166    /// and supplies the default alone.
167    pub kind_set: bool,
168    /// Optional and no default injection (`p` in TypeScript).
169    pub skippable: bool,
170    /// Errors raised on or below this node are dropped (`e: false`).
171    pub silent: bool,
172    /// The empty string is allowed.
173    pub empty: bool,
174    /// An explicit null is accepted as the value.
175    pub nullable: bool,
176    pub has_default: bool,
177    /// Injected for a missing optional property.
178    pub default: Value,
179    /// The declarative value the node was built from, when it was one.
180    pub literal: Option<Value>,
181
182    /// Object children, in the order the spec declared them.
183    pub obj_children: IndexMap<String, Node>,
184    /// The shape of an unknown key (an open object); none for a closed one.
185    pub obj_rest: Option<Box<Node>>,
186    /// The keys a closed object accepts: its declared keys, the targets of
187    /// its renames and the sources they claim. Set when the tree is
188    /// prepared.
189    pub consumed: std::collections::HashSet<String>,
190    /// The declared keys in order, shared with the paths that name them.
191    /// Set when the tree is prepared.
192    pub obj_keys: Vec<Arc<str>>,
193    /// Nothing but the structural check applies to a present value: no
194    /// validator, rename, regexp or silence. Set when the tree is prepared,
195    /// and lets a walk judge such a value in place.
196    pub plain: bool,
197
198    /// The fixed positions of a tuple.
199    pub arr_children: Vec<Node>,
200    /// The shape of every element after the fixed positions.
201    pub arr_child: Option<Box<Node>>,
202    /// A `Rest` appended to an array.
203    pub arr_rest: Option<Box<Node>>,
204
205    pub befores: Vec<Validator>,
206    pub afters: Vec<Validator>,
207
208    /// The pattern of a `Regexp` node.
209    pub regexp: Option<Regex>,
210    /// The pattern as written, in the shared subset: what renders and exports.
211    pub regexp_src: String,
212    /// A `Fault` message overriding the structural text.
213    pub fault_msg: Option<String>,
214    /// Made by a builder given a wrong argument, as against a deliberate
215    /// `fault`: the string form refuses such a node.
216    pub arg_fault: bool,
217
218    pub list_mode: ListMode,
219    pub list: Vec<Node>,
220    /// A Discriminated union: the tag it chooses by, and its branch names,
221    /// which are the list in that order.
222    pub disc: Option<crate::discriminated::Disc>,
223
224    pub exact_vals: Vec<Value>,
225    pub has_exact: bool,
226
227    pub define_name: Option<String>,
228    pub refer_name: Option<String>,
229    pub refer_fill: bool,
230    pub refer_strict: bool,
231
232    pub rename_to: Option<String>,
233    pub rename_keep: bool,
234    pub rename_claim: Vec<String>,
235
236    /// Free-form metadata from `x$$` sidecar keys.
237    pub meta: IndexMap<String, Value>,
238}
239
240impl Node {
241    pub fn of(kind: Kind) -> Node {
242        Node {
243            kind,
244            ..Default::default()
245        }
246    }
247
248    /// Whether the object accepts keys it does not declare.
249    pub fn is_open(&self) -> bool {
250        self.obj_rest.is_some()
251    }
252
253    /// An `Ignore` node: optional, no default injection, and silent.
254    pub fn is_ignore(&self) -> bool {
255        self.silent && self.skippable
256    }
257
258    /// The empty value of a kind (`EMPTY_VAL` in TypeScript).
259    pub fn zero_for(kind: Kind) -> Value {
260        match kind {
261            Kind::String => Value::Str(String::new()),
262            Kind::Number | Kind::Integer => Value::Num(0.0),
263            Kind::Boolean => Value::Bool(false),
264            Kind::Object => Value::Obj(Default::default()),
265            Kind::Array => Value::Arr(Vec::new()),
266            _ => Value::Undefined,
267        }
268    }
269}
270
271#[cfg(test)]
272mod tests {
273    use super::*;
274
275    #[test]
276    fn kinds_and_tokens_name_themselves() {
277        let all = [
278            Kind::Any,
279            Kind::String,
280            Kind::Number,
281            Kind::Boolean,
282            Kind::Object,
283            Kind::Array,
284            Kind::Null,
285            Kind::NaN,
286            Kind::Function,
287            Kind::Never,
288            Kind::Check,
289            Kind::Regexp,
290            Kind::Integer,
291            Kind::Date,
292            Kind::BigInt,
293            Kind::List,
294        ];
295        let names: Vec<String> = all.iter().map(|k| k.to_string()).collect();
296        assert_eq!(names.join(","), "any,string,number,boolean,object,array,null,nan,function,never,check,regexp,integer,date,bigint,list");
297        let tokens = [
298            Token::Any,
299            Token::String,
300            Token::Number,
301            Token::Boolean,
302            Token::Object,
303            Token::Array,
304            Token::Function,
305            Token::Integer,
306            Token::Date,
307            Token::BigInt,
308        ];
309        let kinds: Vec<&str> = tokens.iter().map(|t| t.kind().as_str()).collect();
310        assert_eq!(
311            kinds.join(","),
312            "any,string,number,boolean,object,array,function,integer,date,bigint"
313        );
314        assert_eq!(Node::default().kind, Kind::Any);
315        assert_eq!(Node::default().list_mode, ListMode::None);
316        assert!(!Node::of(Kind::Object).is_open());
317        let v = Validator {
318            name: "x".into(),
319            func: Arc::new(|_, _| true),
320            args: vec![],
321            suffix: None,
322            inner: None,
323        };
324        assert_eq!(format!("{:?}", v), "Validator(x)");
325        assert_eq!(Node::zero_for(Kind::String), Value::Str(String::new()));
326        assert_eq!(Node::zero_for(Kind::Integer), Value::Num(0.0));
327        assert_eq!(Node::zero_for(Kind::Boolean), Value::Bool(false));
328        assert_eq!(Node::zero_for(Kind::Object), Value::Obj(Default::default()));
329        assert_eq!(Node::zero_for(Kind::Array), Value::Arr(vec![]));
330        assert_eq!(Node::zero_for(Kind::Date), Value::Undefined);
331    }
332}