capability-full-annotated-leaf-holders 0.1.0

A Rust crate for crafting fully annotated leaf holders mimicking detailed domain observations, using advanced serialization and error management.
Documentation
// ---------------- [ File: capability-full-annotated-leaf-holders/src/fuzzy_from_json_value.rs ]
crate::ix!();

use serde_json::Map;

/// Flattens any `"fields": {...}` subobject into the top-level.
fn flatten_fields_if_present_in_obj(obj: &mut Map<String, JsonValue>) {
    if let Some(fields_val) = obj.remove("fields") {
        if let JsonValue::Object(fields_map) = fields_val {
            debug!("Flattening 'fields' object into top-level.");
            for (k, v) in fields_map {
                if obj.contains_key(&k) {
                    warn!("Collision while flattening 'fields': key '{}' already exists => skipping.", k);
                } else {
                    obj.insert(k, v);
                }
            }
        } else {
            // Put it back if not an object
            obj.insert("fields".to_string(), fields_val);
        }
    }
}

/// If `"type":"array_of"|"map_of"` + `"value": ...`, unify.  
fn maybe_unwrap_meta_container(obj: &mut Map<String, JsonValue>) {
    let container_kind = obj
        .get("type")
        .and_then(|val| val.as_str())
        .map(str::to_lowercase)
        .unwrap_or_default();

    if !(container_kind == "array_of" || container_kind == "map_of") {
        return;
    }

    // If there's no "value", skip
    let value_val = match obj.get("value") {
        Some(v) => v.clone(),
        None => return,
    };

    debug!("Unwrapping container (type='{}') => discarding leftover meta.", container_kind);

    // Overwrite the entire object with just the contents of "value"
    obj.clear();
    obj.insert("value___unwrapped".to_string(), value_val);
}

/// If the object has exactly one key `"value"`, unify it as well.  
/// This handles shapes like `"leaf_name": { "value": "Foo" }`,  
/// turning them into `"leaf_name": "Foo"`.  
fn maybe_unwrap_single_value(obj: &mut Map<String, JsonValue>) {
    if obj.len() == 1 && obj.contains_key("value") {
        let unwrapped = obj.remove("value").unwrap();
        debug!("Unwrapping single-key object => using the child 'value' directly.");
        obj.clear();
        obj.insert("value___unwrapped".to_string(), unwrapped);
    }
}

/// Recursively unify “meta” shapes for AnnotatedLeafHolder expansions.
/// - Flattens `"fields": {...}`
/// - If `"type":"array_of"|"map_of"` + `"value": ...`, unify them
/// - If exactly one key is `"value"`, unify that as well (common in e.g. `{"value":"X"}`)
/// - Removes leftover known meta keys
fn recursively_unify_annotated_leaf_meta(value: &mut JsonValue) {
    match value {
        JsonValue::Object(obj) => {
            // 1) Flatten "fields"
            flatten_fields_if_present_in_obj(obj);

            // 2) Maybe unwrap "type":"array_of|map_of"
            maybe_unwrap_meta_container(obj);

            // 3) Maybe also unwrap single-key { "value": ... } 
            //    (common for sub-objects that do not carry "type").
            maybe_unwrap_single_value(obj);

            // 4) Remove leftover meta
            let skip_keys = [
                "generation_instructions",
                "nested_template",
                "required",
                "type",
                "variant_docs",
                "map_key_template",
                "map_value_template",
                "struct_docs",
                "struct_name",
                "enum_docs",
                "map_confidence",
                "map_justification",
            ];
            for &k in &skip_keys {
                obj.remove(k);
            }

            // 5) Recurse into children
            for child_val in obj.values_mut() {
                recursively_unify_annotated_leaf_meta(child_val);
            }

            // 6) If there's exactly one key "value___unwrapped", unify it
            if obj.len() == 1 && obj.contains_key("value___unwrapped") {
                let unwrapped = obj.remove("value___unwrapped").unwrap();
                *value = unwrapped;
            }
        }
        JsonValue::Array(arr) => {
            // Recurse for each element
            for elem in arr {
                recursively_unify_annotated_leaf_meta(elem);
            }
        }
        // If scalar => do nothing
        _ => {}
    }
}

/// Finally, the FuzzyFromJsonValue implementation with minimal logs.
impl FuzzyFromJsonValue for AnnotatedLeafHolderExpansions {
    fn fuzzy_from_json_value(value: &serde_json::Value) -> Result<Self, crate::FuzzyFromJsonValueError> {
        // Optionally log the raw input once
        trace!(
            "Fuzzy parse for AnnotatedLeafHolderExpansions => raw input:\n{}",
            value
        );

        let mut cloned = value.clone();

        // Recursively unify meta
        recursively_unify_annotated_leaf_meta(&mut cloned);

        // Then convert final shape => bytes => normal Serde
        let bytes = match serde_json::to_vec(&cloned) {
            Ok(b) => b,
            Err(e) => {
                return Err(crate::FuzzyFromJsonValueError::Other {
                    target_type: "AnnotatedLeafHolderExpansions",
                    detail: format!("Could not convert unified shape to bytes => {}", e),
                });
            }
        };

        let mut track = serde_path_to_error::Track::new();
        let mut d = serde_json::Deserializer::from_slice(&bytes);
        let mut path_d = serde_path_to_error::Deserializer::new(&mut d, &mut track);

        match <AnnotatedLeafHolderExpansions as Deserialize>::deserialize(path_d) {
            Ok(obj) => {
                trace!("Parsed AnnotatedLeafHolderExpansions successfully!");
                Ok(obj)
            }
            Err(path_err) => {
                error!("Fuzzy parse for AnnotatedLeafHolderExpansions failed: {:?}", path_err);
                Err(crate::FuzzyFromJsonValueError::SerdeError {
                    target_type: "AnnotatedLeafHolderExpansions",
                    source: path_err,
                })
            }
        }
    }
}

#[cfg(test)]
mod fuzzy_annotated_leaf_holder_tests {
    use super::*;
    use serde_json::{json, Value};

    /// A helper that runs `recursively_unify_annotated_leaf_meta`
    /// and returns the final Value for easy comparison.
    fn unify_meta(mut v: Value) -> Value {
        recursively_unify_annotated_leaf_meta(&mut v);
        v
    }

    #[test]
    fn test_no_meta_fields_remains_unchanged() {
        // If there's no "fields" subobject or "type":"array_of"/"map_of",
        // the JSON should remain the same.
        let original = json!({
            "some_array": [1,2,3],
            "some_object": { "inner": 42 }
        });
        let final_val = unify_meta(original.clone());
        assert_eq!(final_val, original, "Should remain unchanged if no meta fields");
    }

    #[test]
    fn test_flatten_fields_if_present_in_obj() {
        // If there's a "fields" object, we want to flatten it.
        let original = json!({
            "fields": {
                "foo": "bar",
                "nested": 123
            },
            "another": "field"
        });
        let expected = json!({
            "foo": "bar",
            "nested": 123,
            "another": "field"
        });
        let final_val = unify_meta(original);
        assert_eq!(final_val, expected, "Should flatten 'fields' subobject");
    }

    #[test]
    fn test_meta_container_array_of() {
        // The object says "type":"array_of" plus a "value":[...].
        // We want to unify so that it's replaced by an actual array.
        let original = json!({
            "annotated_leaf_holders": {
                "type": "array_of",
                "required": true,
                "generation_instructions": "some instructions",
                "nested_template": { "dummy": "stuff" },
                "value": [
                    { "leaf_holder_name": "HolderA" },
                    { "leaf_holder_name": "HolderB" }
                ]
            }
        });
        let expected = json!({
            "annotated_leaf_holders": [
                { "leaf_holder_name": "HolderA" },
                { "leaf_holder_name": "HolderB" }
            ]
        });
        let final_val = unify_meta(original);
        assert_eq!(final_val, expected, "Should unwrap 'array_of' => final array");
    }

    #[test]
    fn test_meta_container_map_of() {
        // The object says "type":"map_of" plus a "value":{...}.
        // We unify so that it's replaced by that final object.
        let original = json!({
            "some_map": {
                "type": "map_of",
                "map_key_template": "string",
                "map_value_template": { "generation_instructions": "..." },
                "value": {
                    "KeyA": { "foo": "bar" },
                    "KeyB": { "numbers": [1,2,3] }
                }
            }
        });
        let expected = json!({
            "some_map": {
                "KeyA": { "foo": "bar" },
                "KeyB": { "numbers": [1,2,3] }
            }
        });
        let final_val = unify_meta(original);
        assert_eq!(final_val, expected, "Should unwrap 'map_of' => final object");
    }

    #[test]
    fn test_nested_case_fields_and_array_of() {
        // A more complex nested scenario:
        //   - Outer has "fields":{...} => flatten
        //   - Inside, "type":"array_of" => unwrap "value"
        //   - The array elements might themselves have "fields": subobjects
        let original = json!({
            "fields": {
                "outer_meta": "some meta"
            },
            "some_nested": {
                "type": "array_of",
                "value": [
                    {
                        "fields": { "subfield": 123 },
                        "another": "prop"
                    },
                    {
                        "fields": { "hello": "world" },
                        "arr": [1,2]
                    }
                ],
                "required": true
            }
        });
        let expected = json!({
            "outer_meta": "some meta",
            "some_nested": [
                {
                    "subfield": 123,
                    "another": "prop"
                },
                {
                    "hello": "world",
                    "arr": [1,2]
                }
            ]
        });
        let final_val = unify_meta(original);
        assert_eq!(final_val, expected, "Nested flatten + unwrap array_of");
    }

    #[test]
    fn test_container_lacking_value_is_unchanged() {
        // If we see "type":"array_of" but there's no "value", we do nothing.
        let original = json!({
            "weird": {
                "type": "array_of",
                "nested_template": {},
                "fields": {}
                // no "value" => can't unwrap anything
            }
        });
        // We'll flatten fields => none in "fields"? => okay.
        // We'll detect "type":"array_of", but no "value" => skip.
        // So final remains an empty object after skipping leftover keys?
        // Actually let's see:
        // - flatten "fields" => no changes
        // - skip known keys => "type" and "nested_template" removed
        // => end up with { "weird": {} } since there's no "value".
        let expected = json!({
            "weird": {}
        });
        let final_val = unify_meta(original);
        assert_eq!(final_val, expected, "No 'value' => we do not unwrap anything");
    }

    #[test]
    fn test_collision_when_flattening_fields() {
        // If "fields" has a key that also exists at top-level, we skip overwriting it.
        let original = json!({
            "foo": "keep me",
            "fields": {
                "foo": "would overwrite if we didn't skip",
                "other": 999
            }
        });
        let expected = json!({
            "foo": "keep me",   // not overwritten
            "other": 999       // added
        });
        let final_val = unify_meta(original);
        assert_eq!(final_val, expected, "Should skip collisions");
    }
}