use schemars::{schema_for, JsonSchema};
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchemaEnvelope {
pub module: String,
pub version: String,
pub schema: Value,
#[serde(default)]
pub ui_hints: Value,
}
pub fn build_envelope<T: JsonSchema>(
module: &str,
version: &str,
ui_hints_json: Option<&str>,
) -> SchemaEnvelope {
let schema = schema_for!(T);
let schema_value = serde_json::to_value(schema).unwrap_or(Value::Null);
let ui_hints = match ui_hints_json {
Some(raw) => serde_json::from_str(raw).unwrap_or_else(|err| {
log::warn!(
"module {}: ui_hints sidecar failed to parse ({}); serving null",
module,
err
);
Value::Null
}),
None => Value::Null,
};
SchemaEnvelope {
module: module.to_string(),
version: version.to_string(),
schema: schema_value,
ui_hints,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Serialize, Deserialize, JsonSchema)]
struct DemoConfig {
name: String,
port: u16,
}
#[test]
fn builds_envelope_with_schema_and_hints() {
let hints = r#"{"properties.name.widget": "variable-picker"}"#;
let env = build_envelope::<DemoConfig>("demo", "0.1.0", Some(hints));
assert_eq!(env.module, "demo");
assert_eq!(env.version, "0.1.0");
assert!(env.schema.get("properties").is_some(), "schema has properties");
assert_eq!(
env.ui_hints["properties.name.widget"], "variable-picker"
);
}
#[test]
fn null_hints_when_omitted() {
let env = build_envelope::<DemoConfig>("demo", "0.1.0", None);
assert_eq!(env.ui_hints, Value::Null);
}
#[test]
fn malformed_hints_become_null() {
let env = build_envelope::<DemoConfig>("demo", "0.1.0", Some("{not json"));
assert_eq!(env.ui_hints, Value::Null);
}
}