///|
fn validate_keys(ctx : Context, value : Node, allowed : Array[String]) -> Unit {
for key in keys(value.raw) {
if !allowed.contains(key) && !key.has_prefix("x-") {
ctx.diagnose(
"unsupported-field",
"unsupported",
value.child(key, field(value.raw, key).unwrap()),
"Field is outside the OpenAPI V1 profile: " + key,
)
}
}
}
// Expand reachable response references for change detection, without claiming response compatibility analysis.
///|
fn resolved_response(
ctx : Context,
raw : Node,
name_map : Bool,
depth : Int,
) -> Json {
guard ctx.visit(raw) else { return Json::null() }
if depth > 64 {
ctx.diagnose(
"response-depth-limit", "unsupported", raw, "Response reference traversal exceeds 64 levels.",
)
return Json::null()
}
let value = if name_map {
raw
} else {
match ctx.resolve(raw) {
Some(n) => n
None => return Json::null()
}
}
match value.raw {
Object(fields) => {
let result : Map[String, Json] = Map([])
for key in keys(value.raw) {
if ctx.budget.exhausted {
break
}
let item = fields[key]
if name_map || !ignored_key(key) {
let child_map = !name_map &&
["properties", "headers", "content", "links", "responses"].contains(
key,
)
// Link parameters and requestBody contain arbitrary literal values or
// runtime expressions: their business keys and $ref strings are data.
result[key] = if !name_map &&
["default", "enum", "parameters", "requestBody"].contains(key) {
item
} else {
resolved_response(ctx, value.child(key, item), child_map, depth + 1)
}
}
}
Json::object(result)
}
Array(items) => {
let result : Array[Json] = []
for index, item in items {
if ctx.budget.exhausted {
break
}
result.push(
resolved_response(
ctx,
value.child(index.to_string(), item),
false,
depth + 1,
),
)
}
Json::array(result)
}
_ => value.raw
}
}
///|
fn numeric_constraints(ctx : Context, value : Node) -> Unit {
for
key in [
"minimum", "maximum", "multipleOf", "minLength", "maxLength", "minProperties",
"maxProperties",
] {
match field(value.raw, key) {
None => ()
Some(Number(number, ..)) => {
if ["minLength", "maxLength", "minProperties", "maxProperties"].contains(
key,
) &&
(number < 0 || number != number.floor()) {
ctx.diagnose(
"invalid-schema",
"error",
value,
key + " must be a nonnegative integer.",
)
}
if key == "multipleOf" && number <= 0 {
ctx.diagnose(
"invalid-schema", "error", value, "multipleOf must be positive.",
)
}
}
_ =>
ctx.diagnose(
"invalid-schema",
"error",
value,
key + " must be numeric.",
)
}
}
for key in ["format", "pattern"] {
match field(value.raw, key) {
None | Some(String(_)) => ()
_ =>
ctx.diagnose(
"invalid-schema",
"error",
value,
key + " must be a string.",
)
}
}
}