///|
/// Stable machine-readable report. JSON uses "method" for the HTTP method.
pub fn Report::to_json_report(self : Report) -> String {
let findings : Array[Json] = self.findings.map(fn(f) {
{
"rule_id": f.rule_id.to_json(),
"method": f.http_method.to_json(),
"path": f.path.to_json(),
"old_location": location_json(f.old_location),
"new_location": location_json(f.new_location),
"reason": f.reason.to_json(),
}
})
let diagnostics : Array[Json] = self.diagnostics.map(fn(d) {
{
"code": d.code.to_json(),
"severity": d.severity.to_json(),
"side": d.side.to_json(),
"method": d.http_method.to_json(),
"path": d.path.to_json(),
"location": ToJson::to_json(d.location),
"reason": d.reason.to_json(),
}
})
canonical({
"tool": "MoonAPI Check",
"version": version().to_json(),
"scope": "openapi-3.0.3-request-v1",
"status": self.status.to_json(),
"exit_code": self.exit_code().to_json(),
"findings": Json::array(findings),
"diagnostics": Json::array(diagnostics),
})
}
///|
fn location_json(location : Location?) -> Json {
match location {
Some(value) => ToJson::to_json(value)
None => Json::null()
}
}
///|
fn location_text(location : Location) -> String {
let pointer = if location.pointer == "" {
"(document root)"
} else {
location.pointer
}
if location.pointer == location.definition_pointer {
pointer
} else {
pointer + " -> definition " + location.definition_pointer
}
}
///|
/// Human-readable report containing all findings and diagnostics.
pub fn Report::to_text(self : Report) -> String {
let lines : Array[String] = [
"MoonAPI Check " + version(),
"Scope: OpenAPI 3.0.3 request V1 (see support matrix)",
"Status: " +
self.status +
" | breaking changes: " +
self.findings.length().to_string() +
" | diagnostics: " +
self.diagnostics.length().to_string() +
" | exit: " +
self.exit_code().to_string(),
]
for f in self.findings {
lines.push("")
lines.push("BREAK [" + f.rule_id + "] " + f.http_method + " " + f.path)
lines.push(" " + f.reason)
if f.old_location is Some(loc) {
lines.push(" old: " + location_text(loc))
}
if f.new_location is Some(loc) {
lines.push(" new: " + location_text(loc))
}
}
for d in self.diagnostics {
lines.push("")
lines.push(
"DIAGNOSTIC [" +
d.code +
"] " +
d.side +
" " +
d.http_method +
" " +
d.path,
)
lines.push(" " + d.reason)
lines.push(" at: " + location_text(d.location))
}
if self.exit_code() == 0 {
lines.push("No breaking change found within the supported V1 profile.")
}
lines.join("\n") + "\n"
}
///|
/// Construct a host I/O or execution diagnostic without reimplementing reports in Node.
pub fn execution_error(message : String) -> Report {
{
status: "invalid",
findings: [],
diagnostics: [
{
code: "execution-error",
severity: "error",
side: "host",
http_method: "",
path: "",
location: { pointer: "", definition_pointer: "", },
reason: message,
},
],
}
}