/// WASM runtime type detected on the system.
pub enum RuntimeType {
Wasmtime
Wasmer
Wazero
Node
Bun
Deno
}
/// Result for a single runtime probe.
pub struct RuntimeProbe {
name : String
kind : RuntimeType
installed : Bool
version : Option[String]
path : Option[String]
}
/// Overall WASM environment report.
pub struct WASMEnvReport {
moon_version : String
runtimes : Array[RuntimeProbe]
}
/// Serialize report to JSON string (CI-friendly, machine-parseable).
pub fn report_to_json(report : WASMEnvReport) -> String {
let sb = StringBuilder()
sb.write_string("{\n")
sb.write_string(" \"moon_version\": ")
sb.write_string(json_escape(report.moon_version))
sb.write_string(",\n")
// Collect missing runtimes while building the runtimes array
let mut all_installed = true
let missing_arr = Array::new()
sb.write_string(" \"runtimes\": [\n")
let mut first = true
report.runtimes.each(fn(r) {
if !first {
sb.write_string(",\n")
}
first = false
sb.write_string(" {")
sb.write_string("\"name\": ")
sb.write_string(json_escape(r.name))
sb.write_string(", \"installed\": ")
sb.write_string(if r.installed { "true" } else { "false" })
sb.write_string(", \"version\": ")
match r.version {
Some(v) => { sb.write_string(json_escape(v)) }
None => { sb.write_string("null") }
}
sb.write_string(", \"path\": ")
match r.path {
Some(p) => { sb.write_string(json_escape(p)) }
None => { sb.write_string("null") }
}
sb.write_string("}")
if !r.installed {
all_installed = false
missing_arr.push(r.name)
}
})
sb.write_string("\n ],\n")
// missing runtimes list
sb.write_string(" \"missing\": [\n")
let mut first_miss = true
missing_arr.each(fn(name) {
if !first_miss {
sb.write_string(",\n")
}
first_miss = false
sb.write_string(" ")
sb.write_string(json_escape(name))
})
sb.write_string("\n ],\n")
sb.write_string(" \"all_installed\": ")
sb.write_string(if all_installed { "true" } else { "false" })
sb.write_string("\n}\n")
sb.to_string()
}
/// JSON string escaping helper.
fn json_escape(s : String) -> String {
let sb = StringBuilder()
sb.write_char('"')
for i = 0; i < s.length(); i = i + 1 {
let ch = s[i]
if ch == '"'.to_int().to_uint16() {
sb.write_string("\\\"")
} else if ch == '\\'.to_int().to_uint16() {
sb.write_string("\\\\")
} else if ch == '\n'.to_int().to_uint16() {
sb.write_string("\\n")
} else if ch == '\r'.to_int().to_uint16() {
sb.write_string("\\r")
} else if ch == '\t'.to_int().to_uint16() {
sb.write_string("\\t")
} else {
sb.write_char(ch.unsafe_to_char())
}
}
sb.write_char('"')
sb.to_string()
}