lottie_tools/validator/schema.rs
1// Copyright 2025 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Representation of a JSON Schema. Note that this is built to be used for
16//! Lottie schema. As a result some assumptions have been made and features that
17//! are not used by Lottie schema specification might not be implemented.
18
19use pointer::RefResolver;
20use serde_json::Value;
21use subschema::{SchemaKeyword, Subschema};
22use thiserror::Error;
23
24mod applicator;
25mod assertion;
26mod pointer;
27mod subschema;
28mod utils;
29
30#[derive(Debug, Error)]
31pub enum SchemaError<'a> {
32 #[error("Unkown instance type <{0}>.")]
33 UnkownInstanceType(&'a str),
34 #[error("Expected {expected}, but received <{value}>.")]
35 UnexpectedValue { expected: &'a str, value: &'a Value },
36 #[error("Unknown keyword <{0}>.")]
37 UnkownKeyword(&'a str),
38 #[error(transparent)]
39 RegexError(#[from] regex::Error),
40 #[error("Failed to resolve pointer <{0}>")]
41 UnresolvableRef(&'a str),
42}
43
44#[derive(Debug, Error)]
45#[error("Node {instance} failed to validate against subschema {subschema:?}")]
46pub struct ValidationError<'i, 's> {
47 instance: &'i Value,
48 subschema: &'s Subschema<'s>,
49}
50
51/// Represents a schema file.
52pub struct Schema<'a> {
53 // ref_resolver: Rc<RefResolver<'a>>,
54 root_subschema: Subschema<'a>,
55}
56
57impl<'a> Schema<'a> {
58 /// Creates a new [Schema] from a root [Value]. The result can be later to
59 /// validate JSON instances against this schema.
60 ///
61 /// ```
62 /// # use serde_json::json;
63 /// # use lottie_tools::validator::Schema;
64 /// let s = Schema::from_json(&json!(true)).unwrap();
65 /// assert!(s.validate(&json!(42)).is_ok());
66 /// ```
67 pub fn from_json(input: &'a Value) -> Result<Self, SchemaError<'a>> {
68 let ref_resolver = RefResolver::new(input);
69 let root_subschema = Subschema::from_json(input, &ref_resolver)?;
70
71 Ok(Schema { root_subschema })
72 }
73
74 /// Validates a JSON [Value] against this [Schema].
75 ///
76 /// ```
77 /// # use serde_json::json;
78 /// # use lottie_tools::validator::Schema;
79 /// let s = Schema::from_json(&json!(true)).unwrap();
80 /// assert!(s.validate(&json!(42)).is_ok());
81 /// ```
82 pub fn validate<'i>(&'a self, instance: &'i Value) -> Result<(), ValidationError<'i, 'a>> {
83 self.root_subschema.validate(instance)
84 }
85}