chore: Add ref resolving

This commit is contained in:
Dmitry Dygalo 2022-05-07 18:50:27 +02:00 committed by Dmitry Dygalo
parent 73026c4bd8
commit 53acb03304
2 changed files with 50 additions and 10 deletions

View File

@ -7,7 +7,7 @@
use serde_json::Value;
pub mod resolver;
use resolver::Resolver;
use resolver::LocalResolver;
pub fn build(schema: &Value) {
// The input graph may be incomplete:
@ -22,25 +22,54 @@ pub fn build(schema: &Value) {
//
// Remote schemas could also have references that should be resolved, therefore
// this step is applied recursively to all resolved schemas.
let resolver = Resolver::new(schema);
let mut output = vec![schema];
let mut output = vec![Node::Value(schema)];
let resolver = LocalResolver::new(schema);
build_one(schema, &resolver, &mut output);
}
pub(crate) fn build_one<'schema>(
schema: &'schema Value,
resolver: &'schema LocalResolver,
graph: &mut Vec<Node<'schema>>,
) {
let mut stack = vec![schema];
while let Some(node) = stack.pop() {
match node {
Value::Object(object) => {
for (key, value) in object {
stack.push(value);
output.push(value);
if key == "$ref" {
// TODO.
// - Local reference - use local resolver,
// - remote - then, resolve and run the same procedure
let resolved = resolver.resolve(value.as_str().unwrap()).unwrap();
// Do not push onto the stack, because the reference is local, therefore
// it will be processed in any case
graph.push(Node::Reference(resolved));
} else {
stack.push(value);
graph.push(Node::Value(value));
}
}
}
Value::Array(array) => {}
_ => {}
}
}
for r in &output {
println!("REF: {:p}", *r as *const Value);
}
#[derive(Debug)]
pub(crate) enum Node<'schema> {
Value(&'schema Value),
Reference(&'schema Value),
}
impl<'schema> Node<'schema> {
pub(crate) fn as_inner(&self) -> &'schema Value {
match self {
Node::Value(value) => value,
Node::Reference(value) => value,
}
}
println!("{:?}", output);
}
#[cfg(test)]

View File

@ -22,18 +22,29 @@ pub(crate) fn scope_of(schema: &Value) -> Url {
Url::parse(url).unwrap()
}
pub(crate) struct Resolver<'schema> {
pub(crate) struct LocalResolver<'schema> {
root: &'schema Value,
schemas: SchemaStore<'schema>,
}
impl<'schema> Resolver<'schema> {
impl<'schema> LocalResolver<'schema> {
pub(crate) fn new(root: &'schema Value) -> Self {
Self {
root,
schemas: collect_schemas(root),
}
}
pub(crate) fn resolve(&'schema self, reference: &str) -> Option<&'schema Value> {
if reference == "#" {
Some(self.root)
} else if let Some(document) = self.schemas.get(reference) {
Some(document)
} else {
// TODO. use a more efficient impl
self.root.pointer(reference)
}
}
}
macro_rules! push_map {