boon now included
This commit is contained in:
128
validator/src/root.rs
Normal file
128
validator/src/root.rs
Normal file
@ -0,0 +1,128 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::{compiler::CompileError, draft::*, util::*};
|
||||
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
|
||||
pub(crate) struct Root {
|
||||
pub(crate) draft: &'static Draft,
|
||||
pub(crate) resources: HashMap<JsonPointer, Resource>, // ptr => _
|
||||
pub(crate) url: Url,
|
||||
pub(crate) meta_vocabs: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl Root {
|
||||
pub(crate) fn has_vocab(&self, name: &str) -> bool {
|
||||
if self.draft.version < 2019 || name == "core" {
|
||||
return true;
|
||||
}
|
||||
if let Some(vocabs) = &self.meta_vocabs {
|
||||
return vocabs.iter().any(|s| s == name);
|
||||
}
|
||||
self.draft.default_vocabs.contains(&name)
|
||||
}
|
||||
|
||||
fn resolve_fragment_in(&self, frag: &Fragment, res: &Resource) -> Result<UrlPtr, CompileError> {
|
||||
let ptr = match frag {
|
||||
Fragment::Anchor(anchor) => {
|
||||
let Some(ptr) = res.anchors.get(anchor) else {
|
||||
return Err(CompileError::AnchorNotFound {
|
||||
url: self.url.to_string(),
|
||||
reference: UrlFrag::format(&res.id, frag.as_str()),
|
||||
});
|
||||
};
|
||||
ptr.clone()
|
||||
}
|
||||
Fragment::JsonPointer(ptr) => res.ptr.concat(ptr),
|
||||
};
|
||||
Ok(UrlPtr {
|
||||
url: self.url.clone(),
|
||||
ptr,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_fragment(&self, frag: &Fragment) -> Result<UrlPtr, CompileError> {
|
||||
let res = self.resources.get("").ok_or(CompileError::Bug(
|
||||
format!("no root resource found for {}", self.url).into(),
|
||||
))?;
|
||||
self.resolve_fragment_in(frag, res)
|
||||
}
|
||||
|
||||
// resolves `UrlFrag` to `UrlPtr` from root.
|
||||
// returns `None` if it is external.
|
||||
pub(crate) fn resolve(&self, uf: &UrlFrag) -> Result<Option<UrlPtr>, CompileError> {
|
||||
let res = {
|
||||
if uf.url == self.url {
|
||||
self.resources.get("").ok_or(CompileError::Bug(
|
||||
format!("no root resource found for {}", self.url).into(),
|
||||
))?
|
||||
} else {
|
||||
// look for resource with id==uf.url
|
||||
let Some(res) = self.resources.values().find(|res| res.id == uf.url) else {
|
||||
return Ok(None); // external url
|
||||
};
|
||||
res
|
||||
}
|
||||
};
|
||||
|
||||
self.resolve_fragment_in(&uf.frag, res).map(Some)
|
||||
}
|
||||
|
||||
pub(crate) fn resource(&self, ptr: &JsonPointer) -> &Resource {
|
||||
let mut ptr = ptr.as_str();
|
||||
loop {
|
||||
if let Some(res) = self.resources.get(ptr) {
|
||||
return res;
|
||||
}
|
||||
let Some((prefix, _)) = ptr.rsplit_once('/') else {
|
||||
break;
|
||||
};
|
||||
ptr = prefix;
|
||||
}
|
||||
self.resources.get("").expect("root resource should exist")
|
||||
}
|
||||
|
||||
pub(crate) fn base_url(&self, ptr: &JsonPointer) -> &Url {
|
||||
&self.resource(ptr).id
|
||||
}
|
||||
|
||||
pub(crate) fn add_subschema(
|
||||
&mut self,
|
||||
doc: &Value,
|
||||
ptr: &JsonPointer,
|
||||
) -> Result<(), CompileError> {
|
||||
let v = ptr.lookup(doc, &self.url)?;
|
||||
let base_url = self.base_url(ptr).clone();
|
||||
self.draft
|
||||
.collect_resources(v, &base_url, ptr.clone(), &self.url, &mut self.resources)?;
|
||||
|
||||
// collect anchors
|
||||
if !self.resources.contains_key(ptr) {
|
||||
let res = self.resource(ptr);
|
||||
if let Some(res) = self.resources.get_mut(&res.ptr.clone()) {
|
||||
self.draft.collect_anchors(v, ptr, res, &self.url)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Resource {
|
||||
pub(crate) ptr: JsonPointer, // from root
|
||||
pub(crate) id: Url,
|
||||
pub(crate) anchors: HashMap<Anchor, JsonPointer>, // anchor => ptr
|
||||
pub(crate) dynamic_anchors: HashSet<Anchor>,
|
||||
}
|
||||
|
||||
impl Resource {
|
||||
pub(crate) fn new(ptr: JsonPointer, id: Url) -> Self {
|
||||
Self {
|
||||
ptr,
|
||||
id,
|
||||
anchors: HashMap::new(),
|
||||
dynamic_anchors: HashSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user