json_eval_rs/jsoneval/
layout.rs1use super::JSONEval;
2use crate::jsoneval::path_utils;
3use crate::time_block;
4
5use serde_json::Value;
6use std::mem;
7
8impl JSONEval {
9 pub fn resolve_layout(&mut self, evaluate: bool) -> Result<(), String> {
19 if evaluate {
20 let data_str = serde_json::to_string(&self.data)
22 .map_err(|e| format!("Failed to serialize data: {}", e))?;
23 self.evaluate(&data_str, None, None)?;
24 }
25
26 self.resolve_layout_internal();
27 Ok(())
28 }
29
30 fn resolve_layout_internal(&mut self) {
31 time_block!(" resolve_layout_internal()", {
32 let layout_paths = self.layout_paths.clone();
34
35 time_block!(" resolve_layout_elements", {
36 for layout_path in layout_paths.iter() {
37 self.resolve_layout_elements(layout_path);
38 }
39 });
40
41 time_block!(" propagate_parent_conditions", {
43 for layout_path in layout_paths.iter() {
44 self.propagate_parent_conditions(layout_path);
45 }
46 });
47 });
48 }
49
50 fn resolve_layout_elements(&mut self, layout_elements_path: &str) {
52 let normalized_path = path_utils::normalize_to_json_pointer(layout_elements_path);
54
55 let elements = if let Some(Value::Array(arr)) = self.schema.pointer(&normalized_path) {
58 arr.clone()
59 } else {
60 return;
61 };
62
63 let parent_path = normalized_path
65 .trim_start_matches('/')
66 .replace("/elements", "")
67 .replace('/', ".");
68
69 let mut resolved_elements = Vec::with_capacity(elements.len());
71 for (index, element) in elements.iter().enumerate() {
72 let element_path = if parent_path.is_empty() {
73 format!("elements.{}", index)
74 } else {
75 format!("{}.elements.{}", parent_path, index)
76 };
77 let resolved = self.resolve_element_ref_recursive(element.clone(), &element_path);
78 resolved_elements.push(resolved);
79 }
80
81 if let Some(target) = self.evaluated_schema.pointer_mut(&normalized_path) {
83 *target = Value::Array(resolved_elements);
84 }
85 }
86
87 fn resolve_element_ref_recursive(&self, element: Value, path_context: &str) -> Value {
90 let resolved = self.resolve_element_ref(element);
92
93 if let Value::Object(mut map) = resolved {
95 if !map.contains_key("$parentHide") {
97 map.insert("$parentHide".to_string(), Value::Bool(false));
98 }
99
100 if !map.contains_key("$fullpath") {
102 map.insert("$fullpath".to_string(), Value::String(path_context.to_string()));
103 }
104
105 if !map.contains_key("$path") {
106 let last_segment = path_context.split('.').last().unwrap_or(path_context);
107 map.insert("$path".to_string(), Value::String(last_segment.to_string()));
108 }
109
110 if let Some(Value::Array(elements)) = map.get("elements") {
112 let mut resolved_nested = Vec::with_capacity(elements.len());
113 for (index, nested_element) in elements.iter().enumerate() {
114 let nested_path = format!("{}.elements.{}", path_context, index);
115 resolved_nested.push(self.resolve_element_ref_recursive(nested_element.clone(), &nested_path));
116 }
117 map.insert("elements".to_string(), Value::Array(resolved_nested));
118 }
119
120 return Value::Object(map);
121 }
122
123 resolved
124 }
125
126 fn resolve_element_ref(&self, element: Value) -> Value {
128 match element {
129 Value::Object(mut map) => {
130 if let Some(Value::String(ref_path)) = map.get("$ref").cloned() {
132 let dotted_path = path_utils::pointer_to_dot_notation(&ref_path);
134
135 let last_segment = dotted_path.split('.').last().unwrap_or(&dotted_path);
137
138 map.insert("$fullpath".to_string(), Value::String(dotted_path.clone()));
140 map.insert("$path".to_string(), Value::String(last_segment.to_string()));
141 map.insert("$parentHide".to_string(), Value::Bool(false));
142
143 let normalized_path = if ref_path.starts_with('#') || ref_path.starts_with('/') {
145 path_utils::normalize_to_json_pointer(&ref_path)
146 } else {
147 let schema_pointer = path_utils::dot_notation_to_schema_pointer(&ref_path);
149 let schema_path = path_utils::normalize_to_json_pointer(&schema_pointer);
150
151 if self.evaluated_schema.pointer(&schema_path).is_some() {
153 schema_path
154 } else {
155 format!("/properties/{}", ref_path.replace('.', "/properties/"))
157 }
158 };
159
160 if let Some(referenced_value) = self.evaluated_schema.pointer(&normalized_path) {
162 let resolved = referenced_value.clone();
163
164 if let Value::Object(mut resolved_map) = resolved {
165 map.remove("$ref");
166
167 if let Some(Value::Object(layout_obj)) = resolved_map.remove("$layout") {
169 let mut result = layout_obj.clone();
170
171 for (key, value) in resolved_map {
175 if key != "type" || !result.contains_key("type") {
176 result.insert(key, value);
177 }
178 }
179
180 for (key, value) in map {
182 result.insert(key, value);
183 }
184
185 return Value::Object(result);
186 } else {
187 for (key, value) in map {
189 resolved_map.insert(key, value);
190 }
191
192 return Value::Object(resolved_map);
193 }
194 } else {
195 return resolved;
196 }
197 }
198 }
199
200 Value::Object(map)
201 }
202 _ => element,
203 }
204 }
205
206 fn propagate_parent_conditions(&mut self, layout_elements_path: &str) {
208 let normalized_path = path_utils::normalize_to_json_pointer(layout_elements_path);
209
210 let elements = if let Some(Value::Array(arr)) = self.evaluated_schema.pointer_mut(&normalized_path) {
212 mem::take(arr)
213 } else {
214 return;
215 };
216
217 let mut updated_elements = Vec::with_capacity(elements.len());
219 for element in elements {
220 updated_elements.push(self.apply_parent_conditions(element, false, false));
221 }
222
223 if let Some(target) = self.evaluated_schema.pointer_mut(&normalized_path) {
225 *target = Value::Array(updated_elements);
226 }
227 }
228
229 fn apply_parent_conditions(&self, element: Value, parent_hidden: bool, parent_disabled: bool) -> Value {
231 if let Value::Object(mut map) = element {
232 let mut element_hidden = parent_hidden;
234 let mut element_disabled = parent_disabled;
235
236 if let Some(Value::Object(condition)) = map.get("condition") {
238 if let Some(Value::Bool(hidden)) = condition.get("hidden") {
239 element_hidden = element_hidden || *hidden;
240 }
241 if let Some(Value::Bool(disabled)) = condition.get("disabled") {
242 element_disabled = element_disabled || *disabled;
243 }
244 }
245
246 if let Some(Value::Object(hide_layout)) = map.get("hideLayout") {
248 if let Some(Value::Bool(all)) = hide_layout.get("all") {
249 if *all {
250 element_hidden = true;
251 }
252 }
253 }
254
255 if parent_hidden || parent_disabled {
257 if map.contains_key("condition")
259 || map.contains_key("$ref")
260 || map.contains_key("$fullpath")
261 {
262 let mut condition = if let Some(Value::Object(c)) = map.get("condition") {
263 c.clone()
264 } else {
265 serde_json::Map::new()
266 };
267
268 if parent_hidden {
269 condition.insert("hidden".to_string(), Value::Bool(true));
270 element_hidden = true;
271 }
272 if parent_disabled {
273 condition.insert("disabled".to_string(), Value::Bool(true));
274 element_disabled = true;
275 }
276
277 map.insert("condition".to_string(), Value::Object(condition));
278 }
279
280 if parent_hidden && (map.contains_key("hideLayout") || map.contains_key("type")) {
282 let mut hide_layout = if let Some(Value::Object(h)) = map.get("hideLayout") {
283 h.clone()
284 } else {
285 serde_json::Map::new()
286 };
287
288 hide_layout.insert("all".to_string(), Value::Bool(true));
290 map.insert("hideLayout".to_string(), Value::Object(hide_layout));
291 }
292 }
293
294 if map.contains_key("$parentHide") {
296 map.insert("$parentHide".to_string(), Value::Bool(parent_hidden));
297 }
298
299 if let Some(Value::Array(elements)) = map.get("elements") {
301 let mut updated_children = Vec::with_capacity(elements.len());
302 for child in elements {
303 updated_children.push(self.apply_parent_conditions(child.clone(), element_hidden, element_disabled));
304 }
305 map.insert("elements".to_string(), Value::Array(updated_children));
306 }
307
308 return Value::Object(map);
309 }
310
311 element
312 }
313}