1mod types;
22mod validate;
23
24pub use types::*;
25pub use validate::*;
26
27use std::path::Path;
28use thiserror::Error;
29
30#[derive(Debug, Error)]
32pub enum SchemaError {
33 #[error("IO error: {0}")]
34 IoError(String),
35 #[error("Parse error: {0}")]
36 ParseError(String),
37 #[error("Validation error: {0}")]
38 ValidationError(String),
39}
40
41pub fn load_schema(path: &Path) -> Result<Schema, SchemaError> {
43 let content = std::fs::read_to_string(path).map_err(|e| SchemaError::IoError(e.to_string()))?;
44
45 parse_schema(&content)
46}
47
48pub fn parse_schema(json: &str) -> Result<Schema, SchemaError> {
50 let schema: Schema =
51 serde_json::from_str(json).map_err(|e| SchemaError::ParseError(e.to_string()))?;
52
53 validate_schema(&schema)?;
54
55 Ok(schema)
56}
57
58pub fn save_schema(schema: &Schema, path: &Path) -> Result<(), SchemaError> {
60 let content =
61 serde_json::to_string_pretty(schema).map_err(|e| SchemaError::ParseError(e.to_string()))?;
62
63 std::fs::write(path, content).map_err(|e| SchemaError::IoError(e.to_string()))?;
64
65 Ok(())
66}
67
68pub fn load_schema_from_bytes(bytes: &[u8]) -> Result<Schema, SchemaError> {
70 let schema: Schema =
71 serde_json::from_slice(bytes).map_err(|e| SchemaError::ParseError(e.to_string()))?;
72
73 validate_schema(&schema)?;
74
75 Ok(schema)
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn test_parse_minimal_schema() {
84 let json = r#"{
85 "version": 1,
86 "project": { "name": "Test" },
87 "enums": {},
88 "data_types": {},
89 "embedded_types": {}
90 }"#;
91
92 let schema = parse_schema(json).unwrap();
93 assert_eq!(schema.version, 1);
94 assert_eq!(schema.project.name, "Test");
95 }
96
97 #[test]
98 fn test_parse_schema_with_types() {
99 let json = r##"{
100 "version": 1,
101 "project": { "name": "Test" },
102 "enums": {
103 "ItemType": ["Weapon", "Armor", "Consumable"]
104 },
105 "data_types": {
106 "Item": {
107 "color": "#4CAF50",
108 "properties": [
109 { "name": "name", "type": "string", "required": true },
110 { "name": "itemType", "type": "enum", "enumType": "ItemType" }
111 ]
112 }
113 },
114 "embedded_types": {}
115 }"##;
116
117 let schema = parse_schema(json).unwrap();
118 assert!(schema.enums.contains_key("ItemType"));
119 assert!(schema.data_types.contains_key("Item"));
120
121 let item_type = schema.get_type("Item").unwrap();
122 assert_eq!(item_type.properties.len(), 2);
123 }
124
125 #[test]
126 fn test_invalid_enum_reference() {
127 let json = r#"{
128 "version": 1,
129 "project": { "name": "Test" },
130 "enums": {},
131 "data_types": {
132 "Item": {
133 "properties": [
134 { "name": "itemType", "type": "enum", "enumType": "NonExistent" }
135 ]
136 }
137 },
138 "embedded_types": {}
139 }"#;
140
141 let result = parse_schema(json);
142 assert!(result.is_err());
143 if let Err(SchemaError::ValidationError(msg)) = result {
144 assert!(msg.contains("NonExistent"));
145 }
146 }
147}