Sign in

    openrpc

    Portable OpenRPC documents with exact JSON and source-preserving syntax

    Download zip
    Author
    Version
    0.2.0
    License
    Apache-2.0 AND Unicode-3.0
    Last updated
    8 hours ago
    Downloads
    53

    #OpenRPC documents

    moonrockz/openrpc is a portable OpenRPC 1.3.2/1.4.x reader, writer and document validator. It contains the complete typed OpenRPC and draft-07 models, exact JSON values, a source-preserving CST, reference resolution over explicit resources, versioned document validation with explicit profiles, canonical and pretty writing, and checked value edits. It depends only on the MoonBit core library. It is licensed under Apache-2.0; embedded metaschema and Unicode data keep their notices in OPENRPC-LICENSE.txt and UNICODE-LICENSE.txt.

    Reading keeps both the original JSON source and a typed document when structural decoding succeeds. Writing retains exact numeric tokens, extensions, absent fields and array order. Object keys sort by UTF-16 code units. Canonical writing does not insert defaults or change the document version.

    The examples import the root as @openrpc, exact JSON as @exact, schemas as @schema, and references as @reference.

    ///|
    test {
    let source = " {\"openrpc\":\"1.4.0\",\"info\":{\"title\":\"API\",\"version\":\"service-9\"},\"methods\":[],\"x-number\":9007199254740993} "
    let result = @openrpc.read(source)
    assert_eq(result.cst().unwrap().reproduce(), source)
    let document = result.document().unwrap()
    assert_eq(document.info().version(), "service-9")
    assert_eq(
    @openrpc.write(document).unwrap(),
    "{\"info\":{\"title\":\"API\",\"version\":\"service-9\"},\"methods\":[],\"openrpc\":\"1.4.0\",\"x-number\":9007199254740993}",
    )
    }

    The public json package provides immutable exact JSON values and an owned CST. Its node spans use half-open UTF-16 offsets. Nodes retain member occurrences and decoded keys; the owned source retains punctuation, whitespace and raw spelling. Duplicate decoded keys preserve the CST but fail semantic lowering. The parser, lowering and writer use explicit stacks.

    Default JSON limits are 8,388,608 UTF-16 code units of source/output, 100,000 nodes, 256 open containers, 4,096 code units per number and 256 lowering findings. json.Limits::new accepts explicit bounds. Source size is a text bound, not a UTF-8 byte bound. Large decimal exponents are kept exact without expanding powers of ten.

    CstDocument.tokens() partitions the original text into tokens and whitespace. Each token has its original text and span. source_map() maps decoded paths to all value occurrences, including duplicate members. A location separates the member-name span from the value span. Positions use one-based lines and UTF-16 columns; CRLF counts as one line break. Each location's node index belongs to the owning CST and is not stable across parses or edits. Generated AST values have no source map.

    ///|
    test {
    let cst = @exact.parse("{\"n\":9007199254740993}", source_id=Some("api.json")).unwrap()
    let location = cst.source_map().locations(["n"])[0]
    assert_eq(location.source_id(), Some("api.json"))
    assert_eq(cst.slice(location.value_span()).unwrap(), "9007199254740993")
    assert_eq(cst.slice(location.key_span().unwrap()).unwrap(), "\"n\"")
    }

    #Writing and editing

    There are three ways to produce text, and they differ on purpose:

    • CstDocument::reproduce returns the original source exactly, including whitespace, CRLF, member order and escape and number spelling. It works for valid JSON that is not a valid OpenRPC document.
    • write returns canonical compact JSON: object keys sorted by UTF-16 code units, minimal string escapes, no whitespace and no final newline.
    • write(format=@exact.Pretty) is the same text with two-space indentation.

    Canonical writing keeps every present field, extension and reference spelling, and keeps array order, so methods, parameters, examples and schema arrays are never reordered. It inserts no defaults: an absent paramStructure or deprecated stays absent. It is not RFC 8785 (JCS). JCS rewrites numbers in ECMAScript form; this writer keeps each number token, so 1.0 and 1 remain different bytes. Do not use it as a signing format. Strings with an unpaired UTF-16 surrogate are refused with InvalidValue, because they are not Unicode text and cannot be read back.

    ///|
    test {
    let source = "{\"x-n\": 1.0, \"methods\": [{\"name\": \"b\", \"params\": []}, {\"name\": \"a\", \"params\": [{\"$ref\": \"#/components/contentDescriptors/P\"}]}],\r\n \"info\": {\"version\": \"1\", \"title\": \"API\"}, \"openrpc\": \"1.4.0\", \"components\": {\"contentDescriptors\": {\"P\": {\"name\": \"p\", \"schema\": true}}}}"
    let read = @openrpc.read(source)
    let document = read.document().unwrap()
    assert_eq(read.cst().unwrap().reproduce(), source)
    let compact = @openrpc.write(document).unwrap()
    assert_eq(
    compact,
    "{\"components\":{\"contentDescriptors\":{\"P\":{\"name\":\"p\",\"schema\":true}}},\"info\":{\"title\":\"API\",\"version\":\"1\"},\"methods\":[{\"name\":\"b\",\"params\":[]},{\"name\":\"a\",\"params\":[{\"$ref\":\"#/components/contentDescriptors/P\"}]}],\"openrpc\":\"1.4.0\",\"x-n\":1.0}",
    )
    let pretty = @openrpc.write(document, format=@exact.Pretty).unwrap()
    assert_true(pretty.has_prefix("{\n \"components\": {"))
    // Both formats read back to the same document.
    let again = @openrpc.read(pretty).document().unwrap()
    assert_eq(@openrpc.write(again).unwrap(), compact)
    }

    replace_value edits one existing value in a parsed document. Find the node with CstDocument::node_at or a source-map location's node(). The new value is written compactly into that value's span, every other code unit is kept, and the text is read again into a fresh CST, document and source map. Node handles belong to one source text; using one after an edit that changed the text fails with StaleNode. Only existing values can be replaced; insertion, deletion and key renaming are not supported.

    ///|
    test {
    let source = "{\"openrpc\":\"1.4.0\",\"info\":{\"title\":\"API\",\"version\":\"1\"},\r\n \"methods\": [],\r\n \"x-owner\": \"team-a\"}"
    let cst = @openrpc.read(source).cst().unwrap()
    let node = cst.node_at(["x-owner"]).unwrap()
    let edited = @openrpc.replace_value(cst, node, @exact.Value::string("team-b")).unwrap()
    let new_cst = edited.cst().unwrap()
    assert_eq(new_cst.reproduce(), source.replace(old="team-a", new="team-b"))
    // The old handle is stale for the edited text.
    assert_true(new_cst.replace_value(node, @exact.Value::null()) is Err(_))
    // Validation of the edited document locates findings in the new text.
    let title = new_cst.node_at(["info", "title"]).unwrap()
    let broken = @openrpc.replace_value(new_cst, title, @exact.Value::null()).unwrap()
    assert_true(broken.document() is None)
    let span = broken.diagnostics()[0].span().unwrap()
    assert_eq(broken.cst().unwrap().slice(span), Some("null"))
    }

    Exact Value.equals compares object members without regard to their order and retains numeric token distinctions. Select numeric=true for mathematical numeric equality. Number.numeric_compare orders exact decimals and exponents. Neither operation converts numbers to binary floating point. Equality returns Result[Bool, Diagnostic] and reports exhaustion through LimitExceeded. It bounds visited and queued node pairs, depth, number tokens, and aggregate key/string/number text on each operand. It never treats exhaustion as inequality.

    Core Json interop is explicit. from_core_json uses a present numeric repr after checking its syntax; without repr, it captures the current finite Double representation. It cannot recover source digits that the caller lost. to_core_json always sets exact numeric repr. Core arithmetic and equality still use Double semantics. Both conversions copy collections and enforce the JSON limits. Limits.unlimited() removes policy bounds within the maximum representable String/Array sizes; available host memory is still finite.

    ///|
    test {
    let exact = @exact.parse("9007199254740993").unwrap().lower().unwrap()
    let core = @exact.to_core_json(exact).unwrap()
    assert_true(@exact.from_core_json(core).unwrap().equals(exact).unwrap())
    let code = @openrpc.ErrorCode::parse("-90071992547409931234567890").unwrap()
    assert_eq(code.number().token(), "-90071992547409931234567890")
    let extensions = @openrpc.Extensions::from_json(
    @exact.parse("{\"x-value\":false}").unwrap().lower().unwrap(),
    ).unwrap()
    assert_true(
    extensions.get(@openrpc.ExtensionName::parse("x-value").unwrap()) is Some(_),
    )
    }

    ComponentKey, ExtensionName, and ErrorCode have checked constructors. Component keys follow the OpenRPC component grammar. Extension names begin with lowercase x- and retain arbitrary exact values. Error codes are mathematical integers with no machine-integer restriction. Each field keeps its own rules; these constructors do not impose a common string restriction on unrelated fields.

    #Validation

    validate returns a report with five facets. Each is Passed, Failed or Incomplete; there is no single success flag.

    FacetChecks
    modelObjects reached by validation decode into the typed model
    schemasEmbedded draft-07 schema documents, including regex syntax
    referencesEvery reference resolves within the supplied resources
    normativeRules from the pinned prose of the document's version
    artifactThe document's own JSON against its version's pinned metaschema

    Normative rules follow the document version. Both versions require unique method names, unique parameter names per method, unique error codes per method (exact integer equality, so 1 and 1e0 collide) and links that name an existing method, all checked after references resolve. A referenced target of the wrong kind is a references failure. Required parameters must precede optional ones. OpenRPC 1.3.2 also requires server, license and link names and component keys matching ^[a-zA-Z0-9.\-_]+$; the 1.4 tables state neither. OpenRPC 1.4 requires each example's name and inline value; its tables do not include the 1.3.2 externalValue alternative. Reading keeps any component key as written. While a method fails to resolve, link targets are left unchecked and the facet is incomplete. Members outside a version's field table are UnknownField warnings and never fail the facet.

    The artifact facet uses the frozen 1.3.2 meta-schema (release 1.14.9) or the 1.4 schema at spec commit 876aa30e. Schema positions there are checked only as boolean-or-object; the schemas facet checks their keywords. Formats are annotations.

    #Profiles

    Specification, the default, reports every normative failure as an error. MetaschemaCompatibility serves producers that pass the pinned artifact but differ from the prose. It downgrades exactly the discrepancies in compatibility_discrepancies(), and each such finding names its Discrepancy:

    DiscrepancyProseArtifact
    OptionalParameterBeforeRequiredOptional params come lastNo rule
    ServerNameOmitted1.3.2 requires a server nameOptional
    LicenseNameOmitted1.3.2 requires a license nameOptional

    Every other normative failure stays an error under both profiles. Neither profile reorders, repairs or fills in the document.

    validate_closed returns the same report and, only when the required facets pass, a ValidatedDocument that records its profile, version and resource snapshot. Specification requires model, schemas, references and normative; an artifact failure stays in the report without blocking the wrapper. Compatibility requires those facets and artifact, with normative errors limited to the discrepancy list. An incomplete facet, including one truncated by limits, never produces a wrapper.

    ///|
    test {
    let document = @openrpc.read(
    "{\"openrpc\":\"1.3.2\",\"info\":{\"title\":\"API\",\"version\":\"1\"},\"methods\":[{\"name\":\"find\",\"params\":[{\"name\":\"limit\",\"required\":false,\"schema\":true},{\"name\":\"query\",\"required\":true,\"schema\":true}]}]}",
    )
    .document()
    .unwrap()
    // The prose forbids an optional parameter before a required one.
    let strict = @openrpc.validate_closed(document)
    assert_eq(strict.report().normative(), @openrpc.Failed)
    assert_true(strict.document() is None)
    // Compatibility reports the same finding as a listed warning.
    let compatible = @openrpc.validate_closed(
    document,
    profile=@openrpc.MetaschemaCompatibility,
    )
    let order = compatible.report().findings()[0]
    assert_eq(order.severity(), @openrpc.Warning)
    assert_eq(order.discrepancy(), Some(@openrpc.OptionalParameterBeforeRequired))
    let validated = compatible.document().unwrap()
    assert_eq(validated.profile(), @openrpc.MetaschemaCompatibility)
    // Parameter order is unchanged.
    assert_eq(
    @openrpc.write(validated.document()).unwrap(),
    @openrpc.write(document).unwrap(),
    )
    }

    #Findings

    Each finding has a typed code, severity, phase, document version and profile. Its location names the resource (None for the input document), a pointer, and for the input document a half-open UTF-16 span when the caller passes the source_map from read. related() gives other occurrences, such as the first of two duplicate names. chain() lists the OpenRPC $ref sites followed to reach the location. A missing member points at its parent and names the member in expected_field(). Documents built with constructors have no spans.

    ///|
    test {
    let source = "{\"openrpc\":\"1.4.0\",\"info\":{\"title\":\"😀\",\"version\":\"1\"},\n\"methods\":[{\"name\":\"a\",\"params\":[]},{\"$ref\":\"#/x-copy\"}],\"x-copy\":{\"name\":\"a\",\"params\":[]}}"
    let read = @openrpc.read(source, source_id=Some("api.json"))
    let source_map = read.source_map().unwrap()
    let report = @openrpc.validate(read.document().unwrap(), source_map=Some(source_map))
    let duplicate = report.findings()[0]
    assert_eq(duplicate.diagnostic().code(), @exact.DuplicateName)
    assert_eq(duplicate.location().path(), ["x-copy", "name"])
    assert_eq(duplicate.chain()[0].path(), ["methods", "1", "$ref"])
    assert_eq(duplicate.related()[0].path(), ["methods", "0", "name"])
    // The emoji counts as two UTF-16 units; lines and columns start at 1.
    let span = duplicate.location().span().unwrap()
    let position = source_map.position(span.start()).unwrap()
    assert_eq((position.line(), position.column()), (2, 75))
    }

    Findings are ordered by resource, pointer (array indices numerically), code, source position and message, so every target reports the same list. The max_findings limit (default 256) keeps the first findings in that order. Each phase that lost findings gets an Information LimitExceeded marker and becomes Incomplete.

    ///|
    test {
    let document = @openrpc.read(
    "{\"openrpc\":\"1.4.0\",\"info\":{\"title\":\"API\",\"version\":\"1\"},\"methods\":[{\"name\":\"a\",\"params\":[]},{\"name\":\"a\",\"params\":[]},{\"name\":\"a\",\"params\":[]}]}",
    )
    .document()
    .unwrap()
    let limits = @exact.Limits::new(max_findings=1)
    let report = @openrpc.validate(document, limits~)
    assert_eq(report.normative(), @openrpc.Failed)
    assert_true(
    report
    .findings()
    .any(f => f.diagnostic().code() == @exact.LimitExceeded),
    )
    assert_true(@openrpc.validate_closed(document, limits~).document() is None)
    }

    #Runtime boundary

    Document validation says nothing about runtime exchanges. It does not validate JSON-RPC envelopes, request or response IDs, batches, notifications, or examples and error data as instances of their schemas. An absent result and a result whose schema allows only null are both valid document shapes; neither is checked against any call.

    ///|
    test {
    let document = @openrpc.read(
    "{\"openrpc\":\"1.4.0\",\"info\":{\"title\":\"API\",\"version\":\"1\"},\"methods\":[{\"name\":\"log\",\"params\":[],\"result\":{\"name\":\"done\",\"schema\":{\"type\":\"null\"}},\"examples\":[{\"name\":\"e\",\"params\":[],\"result\":{\"name\":\"r\",\"value\":42}}]}]}",
    )
    .document()
    .unwrap()
    // The example value 42 does not match the null schema, and that is not a
    // document finding.
    let result = @openrpc.validate_closed(document)
    assert_true(result.document() is Some(_))
    assert_true(result.report().findings().is_empty())
    }

    #References

    References never trigger network or filesystem access. Validation resolves references only through an explicit @reference.ResourceSet and an optional document base URI. Each OpenRPC reference site (methods, parameters, results, errors, links, tags, example pairings and their examples) follows its reference-only chain. Each reference resolves against the resource that holds it, and the target is decoded with that kind's checked decoder. A target that does not decode is WrongType at the referencing site. A chain that revisits a location is ReferenceCycle. Schema references use draft-07 $id scopes and recursive schema graphs are valid. Server URL templates, example externalValue, error data, example values and x-* payloads are never resolved, even when they contain $ref.

    ///|
    test {
    let document = @openrpc.read(
    "{\"openrpc\":\"1.4.0\",\"info\":{\"title\":\"API\",\"version\":\"1\"},\"methods\":[{\"$ref\":\"shared.json#/methods/ping\"}]}",
    )
    .document()
    .unwrap()
    let base = @reference.UriReference::parse("https://api.example/openrpc.json").unwrap()
    // Without the shared resource the reference is unresolved, not failed.
    let open = @openrpc.validate(document, base=Some(base))
    assert_eq(open.references(), @openrpc.Incomplete)
    assert_true(
    @openrpc.validate_closed(document, base=Some(base)).document() is None,
    )
    // Supplying it, under an alias, closes the check. Nothing is fetched.
    let shared = @reference.Resource::new(
    @reference.UriReference::parse("https://cdn.example/v1/shared.json").unwrap(),
    @exact.parse(
    "{\"methods\":{\"ping\":{\"name\":\"ping\",\"params\":[],\"result\":{\"name\":\"pong\",\"schema\":{\"$ref\":\"#/definitions/Pong\"}}}},\"definitions\":{\"Pong\":{\"type\":\"string\"}}}",
    )
    .unwrap()
    .lower()
    .unwrap(),
    aliases=[
    @reference.UriReference::parse("https://api.example/shared.json").unwrap(),
    ],
    schema_roots=[@reference.JsonPointer::parse("/definitions/Pong").unwrap()],
    ).unwrap()
    let resources = @reference.ResourceSet::new([shared]).unwrap()
    let closed = @openrpc.validate_closed(document, resources~, base=Some(base))
    assert_eq(closed.report().references(), @openrpc.Passed)
    assert_true(closed.document() is Some(_))
    }

    Document::as_resource registers a document with every schema position in its typed model declared as a schema root, so other documents can reference it. When base names a registered resource that holds exactly the validated document, that resource is used. Without base, relative external references report MissingBaseUri and leave reference coverage incomplete; a relative schema $id still scopes the fragment-only references inside it. Findings for targets in another resource carry pointers relative to that resource. Chains are bounded by max_depth, and schema graphs by their node, edge and finding bounds. Schema graph defaults are 10,000 visited nodes, 4,096 reference edges and 256 findings per check.

    Schema-document validation checks schema keyword forms and references. It does not apply schemas to payload or example instances. Error data and arbitrary x-* payloads remain instance values. JSON-RPC envelopes, notifications, batches and exchanges require a separate runtime validator.

    The draft-07 model guide covers the complete typed keyword model, checked exact bounds, tuple items, dependencies and literal-data boundaries. Schema.from_json checks typed forms. Use schema.validate_json to report malformed untyped schema documents.

    The document API covers metadata, servers and variables, methods, descriptors, tags, links, errors, examples, pairings and all component tables. Each object offers checked new/from_json construction, typed accessors, to_json, shared extensions, and explicit additional_fields. Public arrays and maps are defensive copies. Generated values have no source locations.

    ///|
    test {
    let null_schema = @schema.Schema::from_keywords([
    @schema.Type(@schema.TypeConstraint::one(@schema.NullType)),
    ]).unwrap()
    let result = @openrpc.ContentDescriptor::new(
    "result",
    null_schema,
    required=Some(true),
    ).unwrap()
    let op = @openrpc.Method::new(
    @openrpc.MethodName::parse("ping").unwrap(),
    [],
    result=Some(@openrpc.Inline(result)),
    param_structure=Some(@openrpc.ByName),
    ).unwrap()
    let document = @openrpc.Document::new(
    @openrpc.DocumentVersion::parse("1.3.2").unwrap(),
    @openrpc.Info::new("Example API", "service-v9").unwrap(),
    [@openrpc.Inline(op)],
    ).unwrap()
    assert_eq(document.info().version(), "service-v9")
    assert_true(@openrpc.write(document).unwrap().contains("\"type\":\"null\""))
    let notification = @openrpc.Method::new(
    @openrpc.MethodName::parse("notify").unwrap(),
    [],
    ).unwrap()
    assert_true(notification.result() is None)
    }

    An absent method result describes a notification. A present result whose schema permits null describes a successful null result. Optional flags and collections retain explicit false, empty arrays/maps and absence. Server URL templates and link parameters are retained data and are never executed.

    ///|
    test {
    let schema = @schema.Schema::from_keywords([
    @schema.Type(@schema.TypeConstraint::one(@schema.StringType)),
    ]).unwrap()
    let components = @openrpc.Components::new(
    schemas=Some([(@openrpc.ComponentKey::parse("Text").unwrap(), schema)]),
    ).unwrap()
    let descriptor = @openrpc.ContentDescriptor::new(
    "text",
    @schema.Schema::from_json(
    @exact.parse("{\"$ref\":\"#/components/schemas/Text\"}")
    .unwrap()
    .lower()
    .unwrap(),
    ).unwrap(),
    ).unwrap()
    assert_eq(components.schemas().unwrap()[0].0.to_string(), "Text")
    assert_true(descriptor.schema().kind() is @schema.ReferenceSchema(_))
    let name = @openrpc.ExtensionName::parse("x-contract").unwrap()
    let extensions = @openrpc.Extensions::from_entries([(name, schema.to_json())]).unwrap()
    let submitted = @schema.Schema::from_json(extensions.get(name).unwrap()).unwrap()
    assert_true(
    @schema.validate(submitted, root=submitted.to_json())
    .diagnostics()
    .is_empty(),
    )
    }

    Extensions keep arbitrary exact values. A caller can explicitly submit an extension-held schema for schema-document checks. The library does not infer schemas from extension names or object keys.

    ///|
    test {
    let error = @openrpc.ErrorObject::new(
    @openrpc.ErrorCode::parse("-90071992547409931234567890").unwrap(),
    "Failed",
    data=Some(
    @exact.parse("{\"$ref\":\"literal\",\"schema\":17}")
    .unwrap()
    .lower()
    .unwrap(),
    ),
    ).unwrap()
    let external = @openrpc.Example::new(
    @openrpc.ExternalExample(
    @reference.UriReference::parse("https://example.invalid/value").unwrap(),
    ),
    ).unwrap()
    let components = @openrpc.Components::new(
    errors=Some([(@openrpc.ComponentKey::parse("E").unwrap(), error)]),
    examples=Some([
    (@openrpc.ComponentKey::parse("External").unwrap(), external),
    ]),
    example_pairings=Some([]),
    example_pairing_objects=Some([]),
    ).unwrap()
    assert_true(components.to_json().get("examplePairings") is Some(_))
    assert_true(components.to_json().get("examplePairingObjects") is Some(_))
    assert_true(components.errors().unwrap()[0].1.data() is Some(_))
    }

    The two pairing table spellings remain distinct; pointers are never redirected. Example payloads distinguish absent, literal and external values. Error data is an instance value. Names whose requirements differ by version or profile retain their presence so conformance checks can report the applicable rule.

    Run mise run check:openrpc-assets for the frozen asset checks and mise run check:openrpc for module tests, official inventories and the four-target public consumer comparison. No publication has occurred.

    ComponentKey

    Shared checked values for OpenRPC documents and embedded schemas.

    ExtensionName

    Format

    Output layout. Compact is canonical; Pretty adds two-space indentation and changes nothing else.

    ClosedValidation

    pub struct ClosedValidation {
    report : ValidationReport
    document : ValidatedDocument?
    } derive(
    Debug
    )

    ClosedValidation::document

    ClosedValidation::report

    Components

    Components::additional_fields

    fn Components::additional_fields(self : Components) -> Array[(String,
    Value
    )]

    Components::content_descriptors

    Components::example_pairing_objects

    Components::example_pairings

    Components::extensions

    Components::to_json

    Contact

    Contact::additional_fields

    fn Contact::additional_fields(self : Contact) -> Array[(String,
    Value
    )]

    Contact::email

    fn Contact::email(self : Contact) -> String?

    Contact::extensions

    Contact::name

    fn Contact::name(self : Contact) -> String?

    Contact::to_json

    Contact::to_repr

    ContentDescriptor

    pub struct ContentDescriptor {
    name : String
    schema :
    Schema

    required : Bool?
    value :
    Value

    } derive(
    Debug
    )

    ContentDescriptor::additional_fields

    ContentDescriptor::deprecated

    fn ContentDescriptor::deprecated(self : ContentDescriptor) -> Bool?

    ContentDescriptor::description

    fn ContentDescriptor::description(self : ContentDescriptor) -> String?

    ContentDescriptor::extensions

    ContentDescriptor::name

    fn ContentDescriptor::name(self : ContentDescriptor) -> String

    ContentDescriptor::new

    fn ContentDescriptor::new(name : String, schema :
    Schema
    , summary? : String?, description? : String?, required? : Bool?, deprecated? : Bool?, extensions? :
    Extensions
    , additional_fields? : Array[(String,
    Value
    )], limits? :
    Limits
    ) -> Result[ContentDescriptor,
    Diagnostic
    ]

    ContentDescriptor::required

    fn ContentDescriptor::required(self : ContentDescriptor) -> Bool?

    ContentDescriptor::summary

    fn ContentDescriptor::summary(self : ContentDescriptor) -> String?

    ContentDescriptor::to_json

    Coverage

    pub(all) enum Coverage {
    Passed
    Failed
    Incomplete
    } derive(Eq,
    Debug
    )

    Coverage::equal

    fn Coverage::equal(Coverage, Coverage) -> Bool

    Coverage::not_equal

    fn Coverage::not_equal(x : Coverage, y : Coverage) -> Bool

    Coverage::to_repr

    Discrepancy

    pub(all) enum Discrepancy {
    OptionalParameterBeforeRequired
    ServerNameOmitted
    LicenseNameOmitted
    } derive(Eq,
    Debug
    )

    A recorded disagreement between pinned prose and the pinned metaschema. Only these normative errors become warnings under MetaschemaCompatibility.

    Discrepancy::equal

    fn Discrepancy::equal(Discrepancy, Discrepancy) -> Bool

    Discrepancy::not_equal

    fn Discrepancy::not_equal(x : Discrepancy, y : Discrepancy) -> Bool

    Document

    Document::additional_fields

    fn Document::additional_fields(self : Document) -> Array[(String,
    Value
    )]

    Document::as_resource

    The document as an explicit resource whose schema roots are every schema position in its typed model. Other values stay opaque.

    Document::components

    fn Document::components(self : Document) -> Components?

    Document::extensions

    Document::external_docs

    fn Document::external_docs(self : Document) -> ExternalDocumentation?

    Document::info

    fn Document::info(self : Document) -> Info

    Document::methods

    Document::servers

    fn Document::servers(self : Document) -> Array[Server]?

    Document::to_json

    Document::to_repr

    Document::version

    fn Document::version(self : Document) -> DocumentVersion

    DocumentVersion

    pub struct DocumentVersion {
    text : String
    } derive(Eq,
    Debug
    )

    DocumentVersion::equal

    DocumentVersion::not_equal

    fn DocumentVersion::not_equal(x : DocumentVersion, y : DocumentVersion) -> Bool

    DocumentVersion::parse

    DocumentVersion::to_string

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

    ErrorObject

    ErrorObject::additional_fields

    fn ErrorObject::additional_fields(self : ErrorObject) -> Array[(String,
    Value
    )]

    ErrorObject::extensions

    ErrorObject::message

    fn ErrorObject::message(self : ErrorObject) -> String

    ErrorObject::to_json

    Example

    Example::additional_fields

    fn Example::additional_fields(self : Example) -> Array[(String,
    Value
    )]

    Example::description

    fn Example::description(self : Example) -> String?

    Example::extensions

    Example::name

    fn Example::name(self : Example) -> String?

    Example::new

    fn Example::new(payload : ExampleValue, name? : String?, summary? : String?, description? : String?, extensions? :
    Extensions
    , additional_fields? : Array[(String,
    Value
    )], limits? :
    Limits
    ) -> Result[Example,
    Diagnostic
    ]

    Example::payload

    fn Example::payload(self : Example) -> ExampleValue

    Example::summary

    fn Example::summary(self : Example) -> String?

    Example::to_json

    Example::to_repr

    ExamplePairing

    pub struct ExamplePairing {
    value :
    Value

    } derive(
    Debug
    )

    ExamplePairing::additional_fields

    fn ExamplePairing::additional_fields(self : ExamplePairing) -> Array[(String,
    Value
    )]

    ExamplePairing::description

    fn ExamplePairing::description(self : ExamplePairing) -> String?

    ExamplePairing::extensions

    ExamplePairing::name

    fn ExamplePairing::name(self : ExamplePairing) -> String

    ExamplePairing::new

    fn ExamplePairing::new(name : String, params : Array[InlineOrReference[Example]], summary? : String?, description? : String?, result? : InlineOrReference[Example]?, extensions? :
    Extensions
    , additional_fields? : Array[(String,
    Value
    )], limits? :
    Limits
    ) -> Result[ExamplePairing,
    Diagnostic
    ]

    ExamplePairing::params

    ExamplePairing::result

    ExamplePairing::summary

    fn ExamplePairing::summary(self : ExamplePairing) -> String?

    ExamplePairing::to_json

    ExampleValue

    pub(all) enum ExampleValue {
    NoExampleValue
    LiteralExample(
    Value
    )
    ExternalExample(
    UriReference
    )
    } derive(
    Debug
    )

    ExternalDocumentation

    pub struct ExternalDocumentation {
    value :
    Value

    } derive(
    Debug
    )

    ExternalDocumentation::additional_fields

    ExternalDocumentation::description

    fn ExternalDocumentation::description(self : ExternalDocumentation) -> String?

    ExternalDocumentation::to_json

    Finding

    pub struct Finding {
    diagnostic :
    Diagnostic

    severity : Severity
    phase : Phase
    // private fields
    } derive(
    Debug
    )

    Finding::chain

    fn Finding::chain(self : Finding) -> Array[FindingLocation]

    OpenRPC $ref sites followed, in order, to reach the location.

    Finding::diagnostic

    Finding::discrepancy

    fn Finding::discrepancy(self : Finding) -> Discrepancy?

    The recorded prose/artifact discrepancy this normative finding belongs to.

    Finding::expected_field

    fn Finding::expected_field(self : Finding) -> String?

    The missing member's name when the location is its parent object.

    Finding::location

    fn Finding::location(self : Finding) -> FindingLocation

    Finding::phase

    fn Finding::phase(self : Finding) -> Phase

    Finding::profile

    fn Finding::profile(self : Finding) -> ValidationProfile

    Finding::related

    fn Finding::related(self : Finding) -> Array[FindingLocation]

    Other occurrences involved, such as the first of two duplicates.

    Finding::severity

    fn Finding::severity(self : Finding) -> Severity

    Finding::to_repr

    Finding::version

    fn Finding::version(self : Finding) -> DocumentVersion

    FindingLocation

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

    Where a finding applies. resource is None for the unnamed input document. Spans exist only for the input document, and only when its source map was supplied.

    FindingLocation::path

    fn FindingLocation::path(self : FindingLocation) -> Array[String]

    FindingLocation::source_id

    fn FindingLocation::source_id(self : FindingLocation) -> String?

    Info

    pub struct Info {
    title : String
    version : String
    value :
    Value

    } derive(
    Debug
    )

    Info::additional_fields

    fn Info::additional_fields(self : Info) -> Array[(String,
    Value
    )]

    Info::contact

    fn Info::contact(self : Info) -> Contact?

    Info::description

    fn Info::description(self : Info) -> String?

    Info::extensions

    Info::license

    fn Info::license(self : Info) -> License?

    Info::new

    fn Info::new(title : String, version : String, description? : String?, terms_of_service? :
    UriReference
    ?, contact? : Contact?, license? : License?, extensions? :
    Extensions
    , additional_fields? : Array[(String,
    Value
    )], limits? :
    Limits
    ) -> Result[Info,
    Diagnostic
    ]

    Info::terms_of_service

    Info::title

    fn Info::title(self : Info) -> String

    Info::to_json

    Info::to_repr

    Info::version

    fn Info::version(self : Info) -> String

    InlineOrReference

    pub(all) enum InlineOrReference[T] {
    Inline(T)
    Reference(
    Reference
    )
    } derive(
    Debug
    )

    License

    License::additional_fields

    fn License::additional_fields(self : License) -> Array[(String,
    Value
    )]

    License::extensions

    License::name

    fn License::name(self : License) -> String?

    License::to_json

    License::to_repr

    Link::additional_fields

    fn Link::additional_fields(self : Link) -> Array[(String,
    Value
    )]

    Link::description

    fn Link::description(self : Link) -> String?

    Link::extensions

    Link::name

    fn Link::name(self : Link) -> String?

    Link::new

    fn Link::new(name? : String?, summary? : String?, description? : String?, target_method? : MethodName?, params? : Array[(String,
    Value
    )]?, server? : Server?, extensions? :
    Extensions
    , additional_fields? : Array[(String,
    Value
    )], limits? :
    Limits
    ) -> Result[Link,
    Diagnostic
    ]

    Link::params

    fn Link::params(self : Link) -> Array[(String,
    Value
    )]?

    Link::server

    fn Link::server(self : Link) -> Server?

    Link::summary

    fn Link::summary(self : Link) -> String?

    Link::target_method

    fn Link::target_method(self : Link) -> MethodName?

    Link::to_json

    Link::to_repr

    Method

    Method::additional_fields

    fn Method::additional_fields(self : Method) -> Array[(String,
    Value
    )]

    Method::deprecated

    fn Method::deprecated(self : Method) -> Bool?

    Method::description

    fn Method::description(self : Method) -> String?

    Method::errors

    Method::examples

    Method::extensions

    Method::external_docs

    fn Method::external_docs(self : Method) -> ExternalDocumentation?

    fn Method::links(self : Method) -> Array[InlineOrReference[Link]]?

    Method::name

    fn Method::name(self : Method) -> MethodName

    Method::new

    fn Method::new(name : MethodName, params : Array[InlineOrReference[ContentDescriptor]], result? : InlineOrReference[ContentDescriptor]?, tags? : Array[InlineOrReference[Tag]]?, summary? : String?, description? : String?, external_docs? : ExternalDocumentation?, deprecated? : Bool?, servers? : Array[Server]?, errors? : Array[InlineOrReference[ErrorObject]]?, links? : Array[InlineOrReference[Link]]?, param_structure? : ParamStructure?, examples? : Array[InlineOrReference[ExamplePairing]]?, extensions? :
    Extensions
    , additional_fields? : Array[(String,
    Value
    )], limits? :
    Limits
    ) -> Result[Method,
    Diagnostic
    ]

    Method::param_structure

    fn Method::param_structure(self : Method) -> ParamStructure?

    Method::params

    Method::result

    Method::servers

    fn Method::servers(self : Method) -> Array[Server]?

    Method::summary

    fn Method::summary(self : Method) -> String?

    Method::tags

    fn Method::tags(self : Method) -> Array[InlineOrReference[Tag]]?

    Method::to_json

    Method::to_repr

    MethodName

    pub struct MethodName {
    text : String
    } derive(Eq,
    Debug
    )

    MethodName::equal

    fn MethodName::equal(MethodName, MethodName) -> Bool

    MethodName::not_equal

    fn MethodName::not_equal(x : MethodName, y : MethodName) -> Bool

    MethodName::parse

    MethodName::to_string

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

    ObjectKind

    pub(all) enum ObjectKind {
    DocumentObject
    InfoObject
    ContactObject
    LicenseObject
    ExternalDocumentationObject
    ServerVariableObject
    ServerObject
    MethodObject
    ContentDescriptorObject
    TagObject
    ErrorObjectKind
    ExampleObject
    ExamplePairingObject
    LinkObject
    ComponentsObject
    ReferenceObject
    } derive(Eq,
    Debug
    )

    ObjectKind::equal

    fn ObjectKind::equal(ObjectKind, ObjectKind) -> Bool

    ObjectKind::name

    fn ObjectKind::name(self : ObjectKind) -> String

    ObjectKind::not_equal

    fn ObjectKind::not_equal(x : ObjectKind, y : ObjectKind) -> Bool

    ParamStructure

    pub(all) enum ParamStructure {
    ByName
    ByPosition
    Either
    } derive(Eq,
    Debug
    )

    ParamStructure::equal

    ParamStructure::not_equal

    fn ParamStructure::not_equal(x : ParamStructure, y : ParamStructure) -> Bool

    ParamStructure::to_string

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

    Phase

    pub(all) enum Phase {
    Model
    SchemaDocument
    References
    Normative
    Artifact
    } derive(Eq,
    Debug
    )

    Phase::equal

    fn Phase::equal(Phase, Phase) -> Bool

    Phase::not_equal

    fn Phase::not_equal(x : Phase, y : Phase) -> Bool

    Phase::to_repr

    ReadResult

    ReadResult::diagnostics

    ReadResult::document

    fn ReadResult::document(self : ReadResult) -> Document?

    ReadResult::source_map

    Server

    Server::additional_fields

    fn Server::additional_fields(self : Server) -> Array[(String,
    Value
    )]

    Server::description

    fn Server::description(self : Server) -> String?

    Server::extensions

    Server::name

    fn Server::name(self : Server) -> String?

    Server::new

    fn Server::new(url : String, name? : String?, summary? : String?, description? : String?, variables? : Array[(String, ServerVariable)]?, extensions? :
    Extensions
    , additional_fields? : Array[(String,
    Value
    )], limits? :
    Limits
    ) -> Result[Server,
    Diagnostic
    ]

    Server::summary

    fn Server::summary(self : Server) -> String?

    Server::to_json

    Server::to_repr

    Server::url

    fn Server::url(self : Server) -> String

    Server::variables

    fn Server::variables(self : Server) -> Array[(String, ServerVariable)]?

    ServerVariable

    pub struct ServerVariable {
    value :
    Value

    } derive(
    Debug
    )

    ServerVariable::additional_fields

    fn ServerVariable::additional_fields(self : ServerVariable) -> Array[(String,
    Value
    )]

    ServerVariable::default_value

    fn ServerVariable::default_value(self : ServerVariable) -> String

    ServerVariable::description

    fn ServerVariable::description(self : ServerVariable) -> String?

    ServerVariable::enum_values

    fn ServerVariable::enum_values(self : ServerVariable) -> Array[String]?

    ServerVariable::extensions

    ServerVariable::new

    fn ServerVariable::new(default_value : String, enum_values? : Array[String]?, description? : String?, extensions? :
    Extensions
    , additional_fields? : Array[(String,
    Value
    )], limits? :
    Limits
    ) -> Result[ServerVariable,
    Diagnostic
    ]

    ServerVariable::to_json

    Severity

    pub(all) enum Severity {
    Error
    Warning
    Information
    } derive(Eq,
    Debug
    )

    Severity::equal

    fn Severity::equal(Severity, Severity) -> Bool

    Severity::not_equal

    fn Severity::not_equal(x : Severity, y : Severity) -> Bool

    Severity::to_repr

    Tag

    Tag::additional_fields

    fn Tag::additional_fields(self : Tag) -> Array[(String,
    Value
    )]

    Tag::description

    fn Tag::description(self : Tag) -> String?

    Tag::extensions

    Tag::external_docs

    fn Tag::external_docs(self : Tag) -> ExternalDocumentation?

    Tag::name

    fn Tag::name(self : Tag) -> String

    Tag::new

    fn Tag::new(name : String, summary? : String?, description? : String?, external_docs? : ExternalDocumentation?, extensions? :
    Extensions
    , additional_fields? : Array[(String,
    Value
    )], limits? :
    Limits
    ) -> Result[Tag,
    Diagnostic
    ]

    Tag::summary

    fn Tag::summary(self : Tag) -> String?

    Tag::to_json

    Tag::to_repr

    ValidatedDocument

    pub struct ValidatedDocument {
    document : Document
    report : ValidationReport
    // private fields
    } derive(
    Debug
    )

    A document whose required facets all passed for one profile and one explicit resource snapshot.

    ValidatedDocument::document

    ValidatedDocument::profile

    ValidatedDocument::report

    ValidatedDocument::resources

    Retrieval URIs of the resource snapshot the document was closed against.

    ValidatedDocument::version

    ValidationProfile

    pub(all) enum ValidationProfile {
    Specification
    MetaschemaCompatibility
    } derive(Eq,
    Debug
    )

    ValidationProfile::equal

    ValidationProfile::not_equal

    fn ValidationProfile::not_equal(x : ValidationProfile, y : ValidationProfile) -> Bool

    ValidationReport

    pub struct ValidationReport {
    profile : ValidationProfile
    version : DocumentVersion
    findings : Array[Finding]
    model : Coverage
    schemas : Coverage
    references : Coverage
    normative : Coverage
    artifact : Coverage
    } derive(
    Debug
    )

    ValidationReport::artifact

    ValidationReport::findings

    Findings in deterministic order: resource, pointer tokens, code, source occurrence, then message.

    ValidationReport::model

    ValidationReport::normative

    fn ValidationReport::normative(self : ValidationReport) -> Coverage

    ValidationReport::profile

    ValidationReport::references

    fn ValidationReport::references(self : ValidationReport) -> Coverage

    ValidationReport::schemas

    ValidationReport::version

    compatibility_discrepancies

    fn compatibility_discrepancies() -> Array[Discrepancy]

    The frozen downgrade list. Adding an entry changes public behavior.

    field_names

    fn field_names(kind : ObjectKind) -> Array[String]

    object_kinds

    fn object_kinds() -> Array[ObjectKind]

    read

    fn read(source : String, source_id? : String?, limits? :
    Limits
    ) -> ReadResult

    replace_value

    Replace one existing value in a parsed document and read the result again. Diagnostics use the new source map; node handles from cst become stale.

    validate

    Validate a document against explicit resources. base is the document's retrieval URI; relative references and schema identifiers need it. Nothing is fetched. Unsupplied resources leave reference coverage incomplete. A source_map from reading the same document adds spans to its findings.

    write

    Canonical JSON for a document. It is not source reproduction (see CstDocument::reproduce) and not RFC 8785 canonicalization.

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io