Skip to main content

proef_core/pack/
schema.rs

1//! JSON Schema for packs: schemars-derived from the serde model **plus** the
2//! step-kind fragments contributed by registered engines (TECH-SPEC ยง6).
3
4use crate::engine::StepKindSpec;
5
6/// The pack JSON Schema with engine payload fragments merged into the step
7/// object's properties. Falls back to the plain derived schema when the
8/// generated shape does not match expectations (never fails).
9pub fn json_schema(kinds: &[StepKindSpec]) -> serde_json::Value {
10    let schema = schemars::schema_for!(super::RawPack);
11    let mut root = serde_json::to_value(&schema).unwrap_or(serde_json::Value::Bool(true));
12
13    if let Some(step_properties) = root
14        .pointer_mut("/$defs/RawStep/properties")
15        .and_then(serde_json::Value::as_object_mut)
16    {
17        for kind in kinds {
18            let fragment: serde_json::Value =
19                serde_json::from_str(kind.schema).unwrap_or(serde_json::Value::Bool(true));
20            step_properties.insert(kind.prefix.to_owned(), fragment);
21        }
22    }
23    root
24}
25
26#[cfg(test)]
27mod tests {
28    use super::*;
29
30    #[test]
31    fn engine_fragments_merge_into_the_step_schema() {
32        let kinds = [StepKindSpec {
33            prefix: "hurl",
34            schema: r#"{ "type": "string" }"#,
35            validate: None,
36        }];
37        let schema = json_schema(&kinds);
38        assert_eq!(
39            schema.pointer("/$defs/RawStep/properties/hurl/type"),
40            Some(&serde_json::Value::String("string".into()))
41        );
42        // The fixed schema part is still present.
43        assert!(schema.pointer("/$defs/RawMacro/properties/match").is_some());
44    }
45}