///|
pub fn build_resolver(root_json : Json) -> Resolver raise ParseError {
Resolver::new(root_json)
}
///|
pub struct Resolver {
priv resolver_map : Map[JsonPointer, JsonSchema]
}
///|
pub fn Resolver::new(root_json : Json) -> Resolver raise ParseError {
let resolver_map : Map[JsonPointer, JsonSchema] = Map([])
let using_refs = collect_refs(root_json)
for ref_expr in using_refs {
guard JsonPointer::from_string(ref_expr) is Ok(pointer) else {
raise ParseError::PointerParseError(ref_expr)
}
match pointer.access(root_json) {
Some(json) =>
try {
let schema : JsonSchema = @json.from_json(json)
resolver_map.set(pointer, schema)
} catch {
_ =>
raise ParseError::InvalidSchema(
"Failed to parse schema at reference '\{ref_expr}'",
)
}
None => ()
}
}
Resolver::{ resolver_map, }
}
///|
pub fn Resolver::resolve(self : Resolver, pointer : JsonPointer) -> JsonSchema? {
self.resolver_map.get(pointer)
}
///|
pub fn Resolver::has(self : Resolver, ref_expr : JsonPointer) -> Bool {
self.resolver_map.contains(ref_expr)
}
///|
pub fn Resolver::get_refs(self : Resolver) -> Array[JsonPointer] {
self.resolver_map.keys().to_array()
}
///|
/// get $ref references in json
pub fn collect_refs(json : Json) -> Set[String] {
let set : Set[String] = Set([])
match json {
Object(obj) =>
for key, value in obj {
if key == "$ref" && value is String(s) {
set.add(s)
} else {
let newset = collect_refs(value)
for s in newset {
set.add(s)
}
}
}
Array(arr) =>
for item in arr {
let newset = collect_refs(item)
for s in newset {
set.add(s)
}
}
_ => ()
}
set
}
///|
test "collect_refs" {
let json : Json = {
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "$ref": "#/definitions/PositiveInteger" },
"friends": {
"type": "array",
"items": { "$ref": "#/definitions/Person" },
},
},
"definitions": {
"Person": {
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "$ref": "#/definitions/PositiveInteger" },
},
},
"PositiveInteger": { "type": "integer", "minimum": 0 },
},
}
let refs = collect_refs(json)
assert_eq(
refs,
Set::from_array(["#/definitions/PositiveInteger", "#/definitions/Person"]),
)
}