A faithful MoonBit port of python-jsonschema/referencing: cross-specification JSON referencing.
| package | upstream | contents |
|---|---|---|
| bobzhang/referencing | referencing, referencing.exceptions, referencing.retrieval (and the definitions behind referencing.jsonschema) | Specification, Resource, Registry, Resolver, Resolved, Retrieved, Anchor, ReferencingError, to_cached_resource |
| bobzhang/referencing/jsonschema | referencing.jsonschema | draft202012() … draft3(), specification_with, dynamic_anchor, lookup_recursive_ref, empty_registry, the $id/anchor rules (re-exported from the root) |
| bobzhang/referencing/urllib | urllib.parse | urljoin, urlsplit, urlparse, urlunsplit, urlunparse, urldefrag, unquote — exact ports, tested against CPython |
///|
test "resolve a reference" {
let schema : Json = {
"$id": "https://example.com/person",
"$defs": { "name": { "$anchor": "name", "type": "string" } },
}
let resource = @referencing.draft202012().create_resource(schema)
let registry = @referencing.Registry::new().with_resource(
"https://example.com/person", resource,
)
let resolver = registry.resolver()
// by URI + JSON pointer
let resolved = resolver.lookup("https://example.com/person#/$defs/name")
json_inspect(resolved.contents, content={
"$anchor": "name",
"type": "string",
})
// by plain-name anchor
let by_anchor = resolver.lookup("https://example.com/person#name")
assert_true(by_anchor.contents == resolved.contents)
// `resolved.resolver` carries the new base URI (and dynamic scope) for
// resolving references found *inside* the resolved contents
inspect(resolved.resolver.base_uri(), content="https://example.com/person")
}///|
test "detect specifications" {
let resource = @referencing.Resource::from_contents({
"$schema": "http://json-schema.org/draft-07/schema#",
})
inspect(resource.specification, content="<Specification name='draft-07'>")
let fallback = @referencing.Resource::from_contents(
{ "type": "integer" },
default_specification=@referencing.draft202012(),
)
inspect(fallback.specification, content="<Specification name='draft2020-12'>")
}///|
test "unresolvable references" {
let resolver = @referencing.Registry::new().resolver_with_root(
@referencing.Resource::new_opaque({ "foo": {} }),
)
try resolver.lookup("#/foo/bar") catch {
error => {
assert_true(@referencing.is_unresolvable(error))
inspect(error, content="'/foo/bar' does not exist within {'foo': {}}")
}
} noraise {
_ => fail("expected an error")
}
}///|
test "retrieval" {
let retrieve = @referencing.to_cached_resource(uri => {
guard uri == "urn:example:positive" else {
raise @referencing.NoSuchResource(reference=uri)
}
"{\"$schema\": \"https://json-schema.org/draft/2020-12/schema\", \"minimum\": 0}"
})
let resolver = @referencing.Registry::new(retrieve~).resolver()
let resolved = resolver.lookup("urn:example:positive")
json_inspect(resolved.contents, content={
"$schema": "https://json-schema.org/draft/2020-12/schema",
"minimum": 0,
})
// the registry inside the returned resolver now contains the resource
assert_true(resolved.resolver.registry().contains("urn:example:positive"))
}///|
test "dynamic scope" {
let root = @referencing.draft202012().create_resource({
"$id": "https://example.com/tree",
"$dynamicAnchor": "node",
"$defs": { "strict": { "$id": "strict", "$dynamicAnchor": "node" } },
})
let resolver = @referencing.Registry::new()
.with_resource("https://example.com/tree", root)
.resolver()
let tree = resolver.lookup("https://example.com/tree")
let strict = tree.resolver.lookup("strict")
let scope = strict.resolver.dynamic_scope().map(pair => pair.0).to_array()
assert_eq(scope, ["https://example.com/tree"])
// `#node` is a dynamic anchor: the outermost one in the dynamic scope wins
let node = strict.resolver.lookup("#node")
assert_true(node.contents == root.contents)
}pub(all) suberror ReferencingError {
NoSuchResource(reference~ : String)
NoInternalID(resource~ : Resource)
Unretrievable(reference~ : String, cause~ : Error?)
CannotDetermineSpecification(contents~ : Json)
Unresolvable(reference~ : String)
PointerToNowhere(reference~ : String, resource~ : Resource)
NoSuchAnchor(reference~ : String, resource~ : Resource, anchor~ : String)
InvalidAnchor(reference~ : String, resource~ : Resource, anchor~ : String)
UnknownDialect(uri~ : String)
}impl Eq for ReferencingErrorimpl Show for ReferencingErrorpub struct Registry {
// private fields
}fn Registry::with_contents(self : Registry, pairs : ArrayView[(String, Json)], default_specification? : Specification) -> Registry raise ReferencingErrorfn Registry::with_identified_resource(self : Registry, resource : Resource) -> Registry raise ReferencingErrorpub struct Resolver {
// private fields
}fn Resource::from_contents(contents : Json, default_specification? : Specification) -> Resource raise ReferencingErrorimpl Eq for Specificationimpl Show for Specificationfn Specification::detect(contents : Json, default? : Specification) -> Specification raise ReferencingErrorfn Specification::maybe_in_subresource(self : Specification, segments : Array[Segment], resolver : Resolver, subresource : Resource) -> Resolver raisefn Specification::new(name~ : String, id_of~ : (Json) -> String?, subresources_of~ : (Json) -> Array[Json], anchors_in~ : (Specification, Json) -> Array[Anchor], maybe_in_subresource~ : (Array[Segment], Resolver, Resource) -> Resolver raise) -> Specificationfn is_unresolvable(error : Error) -> Boolfn specification_with(dialect_id : String, default? : Specification) -> Specification raise ReferencingErrortest {
let spec = @referencing.specification_with(
"http://json-schema.org/draft-07/schema#",
)
inspect(spec, content="<Specification name='draft-07'>")
}test {
let calls = []
let retrieve = @referencing.to_cached_resource(uri => {
calls.push(uri)
"{\"$schema\": \"https://json-schema.org/draft/2020-12/schema\", \"foo\": \"bar\"}"
})
let one = @referencing.Registry::new(retrieve~).get_or_retrieve(
"urn:example:foo",
)
let two = @referencing.Registry::new(retrieve~).get_or_retrieve(
"urn:example:foo",
)
inspect(
one.value.contents.stringify(),
content=(
#|{"$schema":"https://json-schema.org/draft/2020-12/schema","foo":"bar"}
),
)
assert_true(physical_equal(one.value, two.value))
assert_eq(calls, ["urn:example:foo"])
}Install
Download zipA faithful MoonBit port of python-jsonschema/referencing: cross-specification JSON referencing.