// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0
// References: how one document reaches another part of itself, and how it
// reaches a document that is not itself. Run it with
// `moon run examples/references`.
///|
fn main raise {
// A `$defs` entry and a `$ref` to it. The fault names the place in the
// instance and the place in the schema, so a message can point at both.
let order = @moonschema.Schema::new(
@json.parse(
(
#|{
#| "$defs": { "port": { "type": "integer", "minimum": 1, "maximum": 65535 } },
#| "type": "object",
#| "properties": { "port": { "$ref": "#/$defs/port" } },
#| "required": ["port"]
#|}
),
),
)
for
instance in [
@json.parse("{\"port\": 8080}"),
@json.parse("{\"port\": 70000}"),
] {
println("\{instance.stringify()} -> \{order.valid(instance)}")
for fault in order.faults(instance) {
println(" " + fault.to_string())
}
}
// `$id` gives a subschema a URI of its own, and a reference inside it
// resolves against that URI rather than against the document's. "money" is a
// relative name, so it lands at https://example.test/money — beside the
// document, not inside it.
let nested = @moonschema.Schema::new(
@json.parse(
(
#|{
#| "$id": "https://example.test/order",
#| "$defs": {
#| "money": {
#| "$id": "money",
#| "type": "object",
#| "properties": { "cents": { "type": "integer" } },
#| "required": ["cents"]
#| }
#| },
#| "type": "object",
#| "properties": { "total": { "$ref": "money" } }
#|}
),
),
)
println("\nnested resource:")
for
text in [
"{\"total\": {\"cents\": 1250}}", "{\"total\": {\"cents\": \"12.50\"}}",
] {
let instance = @json.parse(text)
println(" \{text} -> \{nested.valid(instance)}")
for fault in nested.faults(instance) {
println(" " + fault.to_string())
}
}
// An `$anchor` names a place inside a document by a plain word, which is
// what a reference written by hand usually wants.
let anchored = @moonschema.Schema::new(
@json.parse(
(
#|{
#| "$id": "https://example.test/customer",
#| "$defs": { "name": { "$anchor": "name", "type": "string", "minLength": 1 } },
#| "properties": { "name": { "$ref": "#name" } }
#|}
),
),
)
println("\nanchor:")
for text in ["{\"name\": \"Ada\"}", "{\"name\": \"\"}"] {
let instance = @json.parse(text)
println(" \{text} -> \{anchored.valid(instance)}")
for fault in anchored.faults(instance) {
println(" " + fault.to_string())
}
}
// A reference to a document outside this one resolves only when the caller
// hands that document over: this opens no sockets, so what is not fed to it
// does not exist. Nothing is fetched, and a reference that lands nowhere is a
// fault rather than a silent pass.
let remote = @json.parse("{ \"$ref\": \"https://example.test/int\" }")
let alone = @moonschema.Schema::new(remote)
println("\nwith nothing fed to it:")
println(" 1 -> \{alone.valid(Json::number(1.0))}")
for fault in alone.faults(Json::number(1.0)) {
println(" " + fault.to_string())
}
let fed = @moonschema.Schema::new(remote, remotes={
"https://example.test/int": @json.parse(
"{ \"type\": \"integer\", \"minimum\": 0 }",
),
})
println("\nwith the document fed in:")
for instance in [Json::number(1.0), Json::number(-1.0)] {
println(" \{instance.stringify()} -> \{fed.valid(instance)}")
for fault in fed.faults(instance) {
println(" " + fault.to_string())
}
}
}