capability_skeleton_string/
string_skeleton.rs

1// ---------------- [ File: capability-skeleton-string/src/string_skeleton.rs ]
2crate::ix!();
3
4/// Use this object to specify our whole tree of generated data.
5#[derive(AiJsonTemplateWithJustification,AiJsonTemplate,SaveLoad,Debug, Clone, PartialEq, Eq,Serialize, Deserialize, Builder, Default, Getters,MutGetters)]
6#[builder(pattern="owned", setter(into))]
7#[getset(get="pub",get_mut="pub")]
8pub struct StringSkeleton {
9
10    /// This field holds *verbatim* the lower-kebab-case target-name belonging to the tree grow process.
11    #[builder(default = "\"target\".to_string()")]
12    #[serde(default)]
13    target_name: String,
14
15    /// Set this field to specify the whole map of nodes within our tree.
16    map: HashMap<String, StringSkeletonNode>,
17}
18
19impl FuzzyFromJsonValue for JustifiedStringSkeleton {
20
21    fn fuzzy_from_json_value(value: &Value) -> Result<Self, FuzzyFromJsonValueError> {
22        trace!("(JustifiedStringSkeleton) Entering fuzzy_from_json_value => {}", value);
23
24        // Flatten top-level "fields" if present
25        let mut top_cloned = value.clone();
26        flatten_fields_if_present_in_value(&mut top_cloned);
27
28        let obj = match top_cloned.as_object() {
29            Some(o) => {
30                let keys_collected: Vec<_> = o.keys().cloned().collect();
31                trace!("(JustifiedStringSkeleton) Top-level keys after flatten => {:?}", keys_collected);
32                o
33            }
34            None => {
35                error!("(JustifiedStringSkeleton) Not an object => fail");
36                return Err(FuzzyFromJsonValueError::NotAnObject {
37                    target_type: "JustifiedStringSkeleton",
38                    actual: top_cloned,
39                });
40            }
41        };
42
43        let target_name_val = if let Some(raw) = obj.get("target_name") {
44            raw.to_string().to_kebab_case()
45        } else {
46            warn!("(JustifiedGrowerTreeConfiguration) 'depth' missing => default 0");
47            "target-name-unset".to_string()
48        };
49
50        let target_name_conf = get_f64_field(&obj, "target_name_confidence", "JustifiedGrowerTreeConfiguration").unwrap_or(0.0);
51        let target_name_just = get_string_field(&obj, "target_name_justification", "JustifiedGrowerTreeConfiguration").unwrap_or_default();
52
53        // Must have "map" (the object containing our nodes)
54        let map_val = obj.get("map").ok_or_else(|| {
55            error!("(JustifiedStringSkeleton) Missing 'map' => fail");
56            FuzzyFromJsonValueError::MissingField {
57                field_name: "map",
58                target_type: "JustifiedStringSkeleton",
59            }
60        })?;
61        let map_obj = match map_val.as_object() {
62            Some(m) => {
63                let map_keys_vec: Vec<_> = m.keys().cloned().collect();
64                trace!("(JustifiedStringSkeleton) 'map' object => child keys => {:?}", map_keys_vec);
65                m
66            }
67            None => {
68                error!("(JustifiedStringSkeleton) 'map' must be object => fail");
69                return Err(FuzzyFromJsonValueError::Other {
70                    target_type: "JustifiedStringSkeleton",
71                    detail: format!("'map' must be an object, got {:?}", map_val),
72                });
73            }
74        };
75
76        let mut final_map = HashMap::new();
77
78        // Here we skip well‐known “schema” keys that are not actual domain nodes.
79        // We already skip "map_key_template", "map_value_template", "generation_instructions".
80        // Now we also skip "required" (bool), "type", "struct_docs", "variant_docs", etc. 
81        // That way, anything like `"required": true` does not get parsed as a node name.
82        for (k, v) in map_obj {
83            // Skip known “schema” or “metadata” keys:
84            if k == "generation_instructions"
85                || k == "map_key_template"
86                || k == "map_value_template"
87                || k == "required"          // NEW
88                || k == "type"             // also skip if it appears 
89                || k == "struct_docs"      // skip if present
90                || k == "variant_docs"     // skip if present
91            {
92                trace!("(JustifiedStringSkeleton) Skipping meta key='{}' => not a node", k);
93                continue;
94            }
95
96            trace!("(JustifiedStringSkeleton) Parsing node key='{}' => {}", k, v);
97            let node_just = match JustifiedStringSkeletonNode::fuzzy_from_json_value(v) {
98                Ok(nj) => {
99                    trace!("(JustifiedStringSkeleton) Successfully parsed node='{}' => Justified form", k);
100                    nj
101                }
102                Err(e) => {
103                    error!("(JustifiedStringSkeleton) Error parsing node='{}' => {:?}", k, e);
104                    return Err(FuzzyFromJsonValueError::Other {
105                        target_type: "JustifiedStringSkeleton",
106                        detail: format!("Error parsing node for key='{}': {:?}", k, e),
107                    });
108                }
109            };
110
111            // Insert into final map if successfully parsed
112            final_map.insert(k.clone(), node_just.into());
113        }
114
115        // parse map_confidence => f64
116        let map_conf = get_f64_field(obj, "map_confidence", "JustifiedStringSkeleton")
117            .unwrap_or(0.0);
118        let map_just = get_string_field(obj, "map_justification", "JustifiedStringSkeleton")
119            .unwrap_or_default();
120
121        trace!("(JustifiedStringSkeleton) Successfully built final => map size={}", final_map.len());
122
123        Ok(JustifiedStringSkeleton {
124            target_name:               target_name_val,
125            target_name_confidence:    target_name_conf,
126            target_name_justification: target_name_just,
127            map: final_map,
128            map_confidence: map_conf,
129            map_justification: map_just,
130        })
131    }
132}