Sign in

    #URI references and JSON Pointers

    UriReference checks the generic ASCII URI grammar in RFC 3986. It retains scheme, authority, user information, host alternative, exact port token, path, query and fragment spelling. Empty queries and fragments remain distinct from absent ones. Generic URI ports have no assumed transport range. IPv6 and IPvFuture literals are checked; zone identifiers from later URI extensions are outside this grammar.

    ///|
    test {
    let base = @reference.UriReference::parse("HTTPS://Example.test/a/b").unwrap()
    let relative = @reference.UriReference::parse("../c%2fd?#fragment").unwrap()
    let resolved = relative.resolve(base).unwrap()
    assert_eq(resolved.text(), "HTTPS://Example.test/c%2fd?#fragment")
    assert_eq(resolved.identity(), "https://example.test/c%2Fd?#fragment")
    assert_eq(relative.text(), "../c%2fd?#fragment")
    assert_eq(resolved.query(), Some(""))
    }

    URI resolution follows RFC 3986 section 5.2 and computes an absolute URI; it does not retrieve or inspect a resource. identity() is separate from retained text. It folds scheme and host case, normalizes percent hex and unreserved characters, and removes dot segments from absolute or rooted paths. Relative rootless paths need a base before removing dots. It does not guess default ports, equate HTTP and HTTPS, follow redirects or perform DNS lookup.

    Reference adds JSON-target fragment meaning to a URI. Its alternatives are the whole resource, a checked JSON Pointer, or a decoded named identifier. JsonPointer uses plain RFC 6901 escaping; URI percent decoding belongs to the Reference layer. A named identifier remains unresolved until a resource/scope index supplies its target.

    ///|
    test {
    let parts = ["a/b", "~key", "🛰"]
    let pointer = @reference.JsonPointer::from_tokens(parts).unwrap()
    parts.clear()
    assert_eq(pointer.to_string(), "/a~1b/~0key/🛰")
    let reference = @reference.Reference::parse("#/%7E01").unwrap()
    assert_eq(reference.local_pointer().unwrap().tokens(), ["~1"])
    let url = @reference.UriReference::parse("https://example.test/page#/raw~2").unwrap()
    assert_eq(url.fragment(), Some("/raw~2"))
    assert_true(@reference.Reference::from_uri(url) is Err(_))
    }

    Metadata URLs, editor/dialect identifiers and example externalValue use the general URI type because their fragments need not identify JSON values. OpenRPC and schema $ref values use Reference. Both retain original text for writing. Server URL templates remain uninterpreted strings.

    Checked URI/pointer operations accept shared Limits. Defaults allow 8,388,608 UTF-16 source/output units and 100,000 value/token nodes; pointer depth is at most 256 tokens. Resolution bounds both input URIs, merged paths and output before growing their buffers. Pointer lookup inspects immutable children without copying whole array/object views and constructs a diagnostic path only on failure. Raising bounds on a containing document/schema is inherited by its decoders, and typed getters retain values accepted under those chosen bounds.

    #Explicit resources

    A Resource is an immutable JSON value registered under an absolute, fragment-free retrieval URI and optional aliases. The value can be a whole document or an extracted fragment. Aliases name the same resource; they do not add a second retrieval base. schema_roots declares which locations hold draft-07 schemas; nothing else in a generic resource is treated as a schema.

    A ResourceSet indexes resources by identity() and has an optional root base URI. Two registrations with the same normalized identity are a ConflictingIdentifier error. Constructors copy their input arrays and getters return copies. Registration counts and the total node count of all values are checked against Limits before the index is built.

    ///|
    test {
    let doc = @json.parse("{\"defs\":{\"a/b\":[1,{\"ok\":true}]}}")
    .unwrap()
    .lower()
    .unwrap()
    let resource = @reference.Resource::new(
    @reference.UriReference::parse("https://example.test/api/doc.json").unwrap(),
    doc,
    aliases=[
    @reference.UriReference::parse("HTTPS://Example.test/api/./doc.json").unwrap(),
    ],
    ).unwrap()
    let set = @reference.ResourceSet::new(
    [resource],
    root_base=Some(
    @reference.UriReference::parse("https://example.test/api/").unwrap(),
    ),
    ).unwrap()
    let found = set.resolve(
    @reference.Reference::parse("doc.json#/defs/a~1b/1").unwrap(),
    )
    assert_true(found.complete())
    let target = found.target().unwrap()
    assert_eq(
    target.resource().unwrap().text(),
    "https://example.test/api/doc.json",
    )
    assert_eq(@json.write(target.target()).unwrap(), "{\"ok\":true}")
    let absent = set.resolve(
    @reference.Reference::parse("file:///etc/passwd").unwrap(),
    )
    assert_false(absent.complete())
    assert_eq(absent.diagnostics()[0].code(), @json.UnavailableResource)
    }

    ResourceSet::resolve resolves one reference. A relative reference uses the given base, otherwise the root base. Results are a Resolution: the owned target Location (resource URI, pointer and immutable value), the chain of ReferenceStep sites with their absolute URIs, diagnostics, and a complete flag. Missing input gives an incomplete result: MissingBaseUri when there is no absolute base, and UnavailableResource when a resource was not supplied. Broken pointers (UnresolvedReference) and malformed syntax (InvalidReference) are complete failures. A URI scheme never causes an action; file:, javascript: and unknown schemes are only lookup keys.

    ResourceSet::follow follows a chain while a caller-supplied function reports that a target is itself a reference. Each later reference resolves against the URI of the resource that holds it. Revisiting a location is a ReferenceCycle. A chain longer than max_depth is incomplete with LimitExceeded. The generic layer never decides by itself that a $ref member is a reference, so $ref inside literal data is not followed. Typed schema and OpenRPC resolution supply that decision.

    #Draft-07 identifier scopes

    The generic resolver reports identifier fragments such as #node as incomplete UnsupportedCheck. SchemaIndex resolves them. It walks the declared schema roots of each resource, plus an optional unnamed input document, through draft-07 subschema positions only. A $id with a URI part names a schema resource at that location and becomes the scope for its subschemas. A $id plain-name fragment names a location within the current scope. Literal and unknown keywords, $ref siblings and declared foreign dialects are not indexed.

    ///|
    test {
    let doc = @json.parse(
    "{\"$id\":\"http://x.test/root.json\",\"definitions\":{\"B\":{\"$id\":\"b.json\",\"definitions\":{\"X\":{\"$id\":\"#x\"}}}}}",
    )
    .unwrap()
    .lower()
    .unwrap()
    let index = @reference.SchemaIndex::new(
    @reference.ResourceSet::empty(),
    input=Some(doc),
    input_roots=[@reference.JsonPointer::parse("").unwrap()],
    )
    let b = index.resolve(
    @reference.Reference::parse("http://x.test/b.json").unwrap(),
    )
    let scope = index.scope(b.target().unwrap())
    assert_eq(scope.unwrap().text(), "http://x.test/b.json")
    for
    text in ["#x", "#/definitions/X", "root.json#/definitions/B/definitions/X"] {
    let found = index.resolve(
    @reference.Reference::parse(text).unwrap(),
    base=scope,
    )
    assert_eq(
    found.target().unwrap().identity(),
    "#/definitions/B/definitions/X",
    )
    }
    }

    Every access path resolves to the same owned Location: the physical resource (None for the unnamed input) and the pointer within it. Resolving never copies or expands a schema. An identifier that claims a location already named by another identifier or registered resource is a ConflictingIdentifier; the first binding is kept. A relative $id without a base is MissingBaseUri. A non-plain-name fragment such as #/a, which draft-07 leaves undefined, is kept and reported as incomplete UnsupportedCheck. In an unnamed input with no base, a relative $id names its own location: fragment-only references inside it resolve there, and references that change the path report MissingBaseUri. Schemas reached by $ref are indexed too, even outside the declared roots, and nested roots are walked after their ancestors. Plain names are keyed by the location that sets their scope, so retrieval URIs, aliases and $id spellings of a document all reach them. Typed OpenRPC targets are resolved by the root package's document validation. This development module is not a qualified release candidate.

    Authority

    pub struct Authority {
    raw : String
    userinfo : String?
    host : Host
    port : String?
    } derive(
    Debug
    )

    Authority::host

    fn Authority::host(self : Authority) -> Host

    Authority::port

    fn Authority::port(self : Authority) -> String?

    Port is an exact digit token. Generic URI syntax imposes no transport range.

    Authority::text

    fn Authority::text(self : Authority) -> String

    Authority::userinfo

    fn Authority::userinfo(self : Authority) -> String?

    Host

    pub enum Host {
    RegisteredName(String)
    Ipv4(String)
    Ipv6(String)
    IpvFuture(String)
    } derive(
    Debug
    )

    Host::to_repr

    JsonPointer

    pub struct JsonPointer {
    // private fields
    } derive(
    Debug
    )

    JsonPointer::from_tokens

    JsonPointer::parse

    Parse the plain RFC 6901 representation, without URI percent decoding.

    JsonPointer::to_string

    fn JsonPointer::to_string(self : JsonPointer) -> String

    JsonPointer::tokens

    fn JsonPointer::tokens(self : JsonPointer) -> Array[String]

    Location

    pub struct Location {
    resource : UriReference?
    pointer : JsonPointer
    target :
    Value

    } derive(
    Debug
    )

    An owned resolved target: the owning resource's retrieval URI (None for an unnamed input document), the pointer within it, and the immutable value found there.

    Location::identity

    fn Location::identity(self : Location) -> String

    Normalized resource identity plus pointer; equal for every access path.

    Location::pointer

    fn Location::pointer(self : Location) -> JsonPointer

    Location::resource

    fn Location::resource(self : Location) -> UriReference?

    Location::target

    Location::to_repr

    Reference

    pub struct Reference {
    uri : UriReference
    fragment : ReferenceFragment
    } derive(
    Debug
    )

    Reference::fragment

    fn Reference::fragment(self : Reference) -> ReferenceFragment

    Reference::local_pointer

    fn Reference::local_pointer(self : Reference) -> JsonPointer?

    Reference::parse

    Checked JSON-target reference; reading performs no resolution or fetching.

    Reference::text

    fn Reference::text(self : Reference) -> String

    Reference::uri

    fn Reference::uri(self : Reference) -> UriReference

    ReferenceFragment

    pub enum ReferenceFragment {
    WholeResource
    PointerFragment(JsonPointer)
    IdentifierFragment(String)
    } derive(
    Debug
    )

    ReferenceStep

    pub struct ReferenceStep {
    site : Location?
    reference : Reference
    resolved : UriReference?
    } derive(
    Debug
    )

    One reference in a chain: where it appeared (None for the initial input), its source text, and its absolute form when a base was available.

    ReferenceStep::reference

    fn ReferenceStep::reference(self : ReferenceStep) -> Reference

    ReferenceStep::resolved

    fn ReferenceStep::resolved(self : ReferenceStep) -> UriReference?

    ReferenceStep::site

    fn ReferenceStep::site(self : ReferenceStep) -> Location?

    Resolution

    pub struct Resolution {
    target : Location?
    complete : Bool
    // private fields
    } derive(
    Debug
    )

    A resolution result. complete is false when the answer depends on input that was not supplied or on work beyond the limits; a broken pointer or a cycle is a complete failure.

    Resolution::chain

    Resolution::complete

    fn Resolution::complete(self : Resolution) -> Bool

    Resolution::diagnostics

    Resolution::target

    fn Resolution::target(self : Resolution) -> Location?

    Resource

    pub struct Resource {
    uri : UriReference
    value :
    Value

    // private fields
    } derive(
    Debug
    )

    An immutable caller-supplied JSON resource. Its retrieval URI and aliases are absolute and fragment-free; the value can be any extracted JSON fragment.

    Resource::aliases

    fn Resource::aliases(self : Resource) -> Array[UriReference]

    Resource::schema_roots

    fn Resource::schema_roots(self : Resource) -> Array[JsonPointer]

    Locations whose values are declared draft-07 schema roots.

    Resource::to_repr

    Resource::uri

    fn Resource::uri(self : Resource) -> UriReference

    Resource::value

    ResourceSet

    pub struct ResourceSet {
    root_base : UriReference?
    // private fields
    } derive(
    Debug
    )

    Explicit immutable resource snapshots with an optional root base URI. Lookup uses syntax-based URI identity and never retrieves anything.

    ResourceSet::empty

    fn ResourceSet::empty() -> ResourceSet

    ResourceSet::follow

    fn ResourceSet::follow(self : ResourceSet, reference : Reference, next : (Location) -> Reference?, base? : UriReference?, limits? :
    Limits
    ) -> Resolution

    Follow a reference chain while next reports that a target is itself a reference. Each later reference resolves against its owning resource URI. Revisiting a location is a ReferenceCycle; chains longer than max_depth are incomplete.

    ResourceSet::get

    fn ResourceSet::get(self : ResourceSet, uri : UriReference) -> Resource?

    The resource registered under the fragment-free identity of uri.

    ResourceSet::resolve

    fn ResourceSet::resolve(self : ResourceSet, reference : Reference, base? : UriReference?, limits? :
    Limits
    ) -> Resolution

    Resolve one reference against the explicit resources. A relative reference uses base, else the set's root base. Nothing is fetched or executed.

    ResourceSet::resources

    fn ResourceSet::resources(self : ResourceSet) -> Array[Resource]

    ResourceSet::root_base

    fn ResourceSet::root_base(self : ResourceSet) -> UriReference?

    SchemaIndex

    pub struct SchemaIndex {
    // private fields
    } derive(
    Debug
    )

    Draft-07 identifier scopes over declared schema roots. Indexing walks only draft-07 subschema positions: literal keywords, unknown keywords, $ref siblings and declared foreign dialects never establish identifiers. The optional input is the caller's own document, named by input_base when it has one, and is never registered as a resource.

    SchemaIndex::complete

    fn SchemaIndex::complete(self : SchemaIndex) -> Bool

    False when identifiers could not all be indexed: missing bases, undefined fragment forms or exhausted limits.

    SchemaIndex::diagnostics

    SchemaIndex::indexed_scope

    fn SchemaIndex::indexed_scope(self : SchemaIndex, identity : String) -> UriReference??

    The scope recorded for the indexed schema whose Location::identity is identity, or None when that location was not indexed.

    SchemaIndex::locate

    The physical location at pointer in a registered resource, or in the input when resource is None or names the input base.

    SchemaIndex::new

    SchemaIndex::resolve

    fn SchemaIndex::resolve(self : SchemaIndex, reference : Reference, base? : UriReference?, limits? :
    Limits
    ) -> Resolution

    Resolve a schema reference from a site whose scope is base. Without a base, the input's base or else the set's root base applies; a same-document reference in an unnamed input targets that input.

    SchemaIndex::resources

    fn SchemaIndex::resources(self : SchemaIndex) -> ResourceSet

    SchemaIndex::scope

    fn SchemaIndex::scope(self : SchemaIndex, location : Location) -> UriReference?

    The base URI in effect for the schema at location: its nearest $id scope when indexed, otherwise its document's retrieval URI. A relative result means the scope is undetermined for lack of an absolute base.

    UriReference

    pub struct UriReference {
    raw : String
    scheme : String?
    authority : Authority?
    path : String
    query : String?
    fragment : String?
    } derive(
    Debug
    )

    Checked generic RFC3986 URI-reference components, with original spelling.

    UriReference::authority

    fn UriReference::authority(self : UriReference) -> Authority?

    UriReference::fragment

    fn UriReference::fragment(self : UriReference) -> String?

    Encoded fragment text, preserving absent versus present-empty.

    UriReference::identity

    fn UriReference::identity(self : UriReference) -> String

    Syntax-based identity. Relative rootless dot segments need a base first.

    UriReference::is_absolute

    fn UriReference::is_absolute(self : UriReference) -> Bool

    UriReference::path

    fn UriReference::path(self : UriReference) -> String

    UriReference::query

    fn UriReference::query(self : UriReference) -> String?

    UriReference::resolve

    Strict RFC3986 section5.2 resolution. Neither value's original text changes.

    UriReference::scheme

    fn UriReference::scheme(self : UriReference) -> String?

    UriReference::text

    fn UriReference::text(self : UriReference) -> String

    UriReference::without_fragment

    fn UriReference::without_fragment(self : UriReference) -> UriReference

    schema_scope

    fn schema_scope(id : UriReference, scope : UriReference?, limits? :
    Limits
    ) -> UriReference?

    The scope in effect below a schema whose $id is id, given the enclosing scope. Without an absolute base, a relative identifier gives a relative scope: fragment-only references resolve within the location the index bound to it, and other references report MissingBaseUri.

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io