Skip to main content

lenso_contracts/
schema.rs

1use 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}