hwpforge_blueprint/
schema.rs

1//! JSON Schema generation for Template validation.
2//!
3//! Uses [`schemars`] to derive a JSON Schema from the [`Template`] type.
4//! This schema can be used by editors (VS Code, Zed) for YAML autocompletion
5//! and validation, and by LLM agents to understand the template format.
6
7use crate::template::Template;
8
9/// Generates the JSON Schema for [`Template`] as a [`Schema`](schemars::Schema).
10///
11/// Use this for programmatic access to the schema object.
12pub fn template_schema() -> schemars::Schema {
13    schemars::schema_for!(Template)
14}
15
16/// Generates the JSON Schema for [`Template`] as a pretty-printed JSON string.
17///
18/// Useful for writing to a file or embedding in documentation.
19///
20/// # Panics
21///
22/// Panics if JSON serialization fails (should never happen for a valid schema).
23pub fn template_schema_json() -> String {
24    serde_json::to_string_pretty(&template_schema()).expect("schema serialization should not fail")
25}
26
27#[cfg(test)]
28mod tests {
29    use super::*;
30    use pretty_assertions::assert_eq;
31
32    #[test]
33    fn schema_is_valid_json() {
34        let json = template_schema_json();
35        let _: serde_json::Value = serde_json::from_str(&json).unwrap();
36    }
37
38    #[test]
39    fn schema_has_template_title() {
40        let json = template_schema_json();
41        let value: serde_json::Value = serde_json::from_str(&json).unwrap();
42        let title = value.get("title").and_then(|t| t.as_str());
43        assert_eq!(title, Some("Template"));
44    }
45
46    #[test]
47    fn schema_contains_meta_property() {
48        let json = template_schema_json();
49        assert!(json.contains("\"meta\""), "Schema should reference 'meta' property");
50    }
51
52    #[test]
53    fn schema_contains_styles_property() {
54        let json = template_schema_json();
55        assert!(json.contains("\"styles\""), "Schema should reference 'styles' property");
56    }
57
58    #[test]
59    fn schema_contains_page_property() {
60        let json = template_schema_json();
61        assert!(json.contains("\"page\""), "Schema should reference 'page' property");
62    }
63
64    #[test]
65    fn schema_references_partial_char_shape() {
66        let json = template_schema_json();
67        assert!(json.contains("PartialCharShape"), "Schema should reference PartialCharShape type");
68    }
69
70    #[test]
71    fn schema_references_partial_para_shape() {
72        let json = template_schema_json();
73        assert!(json.contains("PartialParaShape"), "Schema should reference PartialParaShape type");
74    }
75
76    #[test]
77    fn schema_roundtrip_through_json() {
78        let json = template_schema_json();
79        let parsed: schemars::Schema = serde_json::from_str(&json).unwrap();
80        let json2 = serde_json::to_string_pretty(&parsed).unwrap();
81        assert_eq!(json, json2);
82    }
83}