oino-ui 1.0.0

Wire types and ratatui-mirroring builder for the Oino extension UI protocol v2 (serde-only, wasm32-wasip2-safe)
Documentation
//! Exports the normative JSON Schema of the protocol (Appendix A) plus the
//! registry envelope schema (§6.1, §4.7, §9.2). The files are checked in under
//! `schema/`; `tests/schema_parity.rs` asserts that `node.schema.json` stays
//! identical to the Appendix A block in the spec document, and that the fixture
//! corpus validates against it — the Rust types are thereby locked to the spec.

use serde_json::Value as Json;

/// The node schema (ui-protocol v2 Appendix A), verbatim.
pub const NODE_SCHEMA: &str = include_str!("../schema/node.schema.json");

/// The registry envelope schema (`UiEntry`, `UiSnapshot`, `UiPatch`,
/// `RegistryOp`, `NodeOp`, §6.1 / §4.7 / §9.2).
pub const REGISTRY_SCHEMA: &str = include_str!("../schema/registry.schema.json");

/// The node schema, parsed.
///
/// # Errors
/// When the checked-in file is not valid JSON (a build-time test catches this).
pub fn node_schema() -> Result<Json, String> {
    serde_json::from_str(NODE_SCHEMA).map_err(|e| e.to_string())
}

/// The registry envelope schema, parsed.
///
/// # Errors
/// When the checked-in file is not valid JSON (a build-time test catches this).
pub fn registry_schema() -> Result<Json, String> {
    serde_json::from_str(REGISTRY_SCHEMA).map_err(|e| e.to_string())
}

/// Protocol version the exported schemas describe.
pub const PROTOCOL_VERSION: u8 = 2;

#[cfg(test)]
mod tests {
    #![allow(
        clippy::unwrap_used,
        clippy::expect_used,
        clippy::panic,
        reason = "tests assert by unwrapping"
    )]

    use super::*;

    #[test]
    fn exports_parse_and_match_the_spec_ids() {
        let node = node_schema().expect("node schema parses");
        let registry = registry_schema().expect("registry schema parses");
        assert_eq!(
            node["$id"],
            "https://oino.dev/schemas/ui/2/node.schema.json"
        );
        assert_eq!(
            registry["$id"],
            "https://oino.dev/schemas/ui/2/registry.schema.json"
        );
        assert_eq!(
            node["$schema"],
            "https://json-schema.org/draft/2020-12/schema"
        );
        assert_eq!(
            registry["$schema"],
            "https://json-schema.org/draft/2020-12/schema"
        );
    }

    #[test]
    fn node_schema_lists_every_kind() {
        let schema = node_schema().expect("node schema parses");
        let defs = schema["$defs"].as_object().expect("$defs object");
        let kinds: Vec<&str> = schema["$defs"]["Node"]["oneOf"]
            .as_array()
            .expect("Node oneOf")
            .iter()
            .filter_map(|r| r["$ref"].as_str())
            .map(|r| r.trim_start_matches("#/$defs/"))
            .collect();
        assert_eq!(kinds.len(), crate::node::NODE_KINDS.len());
        for kind in crate::node::NODE_KINDS {
            assert!(kinds.contains(&kind), "schema misses node kind {kind}");
            assert!(defs.contains_key(kind), "schema $defs misses {kind}");
        }
    }
}