yaml_schema/schemas/
root_schema.rs1use jsonptr::Pointer;
4use log::debug;
5use saphyr::MarkedYaml;
6use saphyr::Scalar;
7use saphyr::YamlData;
8use url::Url;
9
10use crate::Error;
11use crate::Result;
12use crate::YamlSchema;
13use crate::loader::marked_yaml_to_string;
14use crate::validation::Context;
15use crate::validation::Validator;
16
17#[derive(Debug, PartialEq)]
21pub struct RootSchema {
22 pub meta_schema: Option<String>,
23 pub schema: YamlSchema,
24 pub base_uri: Option<Url>,
26}
27
28impl RootSchema {
29 pub fn empty() -> Self {
31 Self {
32 meta_schema: None,
33 schema: YamlSchema::Empty,
34 base_uri: None,
35 }
36 }
37
38 pub fn new(schema: YamlSchema) -> Self {
40 Self {
41 meta_schema: None,
42 schema,
43 base_uri: None,
44 }
45 }
46
47 pub fn id(&self) -> Option<String> {
49 match &self.schema {
50 YamlSchema::Subschema(subschema) => subschema.metadata_and_annotations.id.clone(),
51 _ => None,
52 }
53 }
54
55 pub fn cache_key(&self, fallback: &str) -> String {
58 self.id()
59 .filter(|s| Url::parse(s).is_ok())
60 .unwrap_or_else(|| fallback.to_string())
61 }
62
63 pub fn resolve(&self, pointer: &Pointer) -> Option<&YamlSchema> {
65 let components = pointer.components().collect::<Vec<_>>();
66 debug!("[RootSchema#resolve] components: {components:?}");
67 components.first().and_then(|component| {
68 debug!("[RootSchema#resolve] component: {component:?}");
69 match component {
70 jsonptr::Component::Root => {
71 let components = &components[1..];
72 components.first().and_then(|component| {
73 debug!("[RootSchema#resolve] component: {component:?}");
74 match component {
75 jsonptr::Component::Root => unimplemented!(),
76 jsonptr::Component::Token(token) => {
77 self.schema.resolve(Some(token), &components[1..])
78 }
79 }
80 })
81 }
82 jsonptr::Component::Token(token) => {
83 self.schema.resolve(Some(token), &components[1..])
84 }
85 }
86 })
87 }
88}
89
90impl<'r> TryFrom<&MarkedYaml<'r>> for RootSchema {
91 type Error = Error;
92
93 fn try_from(marked_yaml: &MarkedYaml<'r>) -> Result<Self> {
94 match &marked_yaml.data {
95 YamlData::Value(scalar) => match scalar {
96 Scalar::Boolean(r#bool) => Ok(Self {
97 meta_schema: None,
98 schema: YamlSchema::BooleanLiteral(*r#bool),
99 base_uri: None,
100 }),
101 Scalar::Null => Ok(RootSchema {
102 meta_schema: None,
103 schema: YamlSchema::Null,
104 base_uri: None,
105 }),
106 _ => Err(generic_error!(
107 "[loader#load_from_doc] Don't know how to a handle scalar: {:?}",
108 scalar
109 )),
110 },
111 YamlData::Mapping(mapping) => {
112 debug!(
113 "[loader#load_from_doc] Found mapping, trying to load as RootSchema: {mapping:?}"
114 );
115 let meta_schema = mapping
116 .get(&MarkedYaml::value_from_str("$schema"))
117 .map(|my| marked_yaml_to_string(my, "$schema must be a string"))
118 .transpose()?;
119
120 let schema = YamlSchema::try_from(marked_yaml)?;
121 Ok(RootSchema {
122 meta_schema,
123 schema,
124 base_uri: None,
125 })
126 }
127 _ => Err(generic_error!(
128 "[loader#load_from_doc] Don't know how to load: {:?}",
129 marked_yaml
130 )),
131 }
132 }
133}
134
135impl Validator for RootSchema {
136 fn validate(&self, context: &Context, value: &saphyr::MarkedYaml) -> Result<()> {
137 self.schema.validate(context, value)
138 }
139}