lenso_contracts/
schema.rs1use crate::{MODULE_MANIFEST_PROTOCOL, MODULE_RELEASE_PROTOCOL, ModuleManifest, ModuleRelease};
2use schemars::JsonSchema;
3use serde_json::{Value, json};
4
5const MODULE_ID_PATTERN: &str = "^[a-z][a-z0-9_-]*/[a-z][a-z0-9_-]*$";
6const SHA256_PATTERN: &str = "^sha256:[0-9a-f]{64}$";
7
8pub fn module_manifest_schema() -> Value {
9 generated_module_schema::<ModuleManifest>(MODULE_MANIFEST_PROTOCOL, "LensoModuleManifest")
10}
11
12pub fn module_release_schema() -> Value {
13 generated_module_schema::<ModuleRelease>(MODULE_RELEASE_PROTOCOL, "LensoModuleRelease")
14}
15
16fn generated_module_schema<T: JsonSchema>(protocol: &str, title: &str) -> Value {
17 let mut schema = serde_json::to_value(schemars::schema_for!(T))
18 .expect("generated Module schema must serialize");
19 let object = schema
20 .as_object_mut()
21 .expect("generated Module schema root must be an object");
22 object.insert(
23 "$id".to_owned(),
24 Value::String(format!(
25 "https://contracts.lenso.local/modules/{protocol}.schema.json"
26 )),
27 );
28 object.insert("title".to_owned(), Value::String(title.to_owned()));
29 tighten_module_schema(&mut schema, protocol);
30 schema
31}
32
33fn tighten_module_schema(schema: &mut Value, protocol: &str) {
34 if let Some(properties) = schema.get_mut("properties").and_then(Value::as_object_mut) {
35 properties.insert(
36 "protocol".to_owned(),
37 json!({ "type": "string", "const": protocol }),
38 );
39 if let Some(module_id) = properties.get_mut("module_id") {
40 *module_id = json!({ "type": "string", "pattern": MODULE_ID_PATTERN });
41 }
42 if let Some(manifest_digest) = properties.get_mut("manifest_digest") {
43 *manifest_digest = json!({ "type": "string", "pattern": SHA256_PATTERN });
44 }
45 }
46 if let Some(manifest) = schema
47 .get_mut("$defs")
48 .and_then(|defs| defs.get_mut("ModuleManifest"))
49 .and_then(Value::as_object_mut)
50 .and_then(|manifest| manifest.get_mut("properties"))
51 .and_then(Value::as_object_mut)
52 {
53 manifest.insert(
54 "protocol".to_owned(),
55 json!({ "type": "string", "const": MODULE_MANIFEST_PROTOCOL }),
56 );
57 manifest.insert(
58 "module_id".to_owned(),
59 json!({ "type": "string", "pattern": MODULE_ID_PATTERN }),
60 );
61 }
62}