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, 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 time_block!(" sync_layout_hidden_to_schema", {
51 self.sync_layout_hidden_to_schema(&layout_paths);
52 });
53 });
54 }
55
56 fn resolve_layout_elements(&mut self, layout_elements_path: &str) {
58 let normalized_path = path_utils::normalize_to_json_pointer(layout_elements_path);
60
61 let elements = if let Some(Value::Array(arr)) = self.schema.pointer(&normalized_path) {
64 arr.clone()
65 } else {
66 return;
67 };
68
69 let parent_path = normalized_path
71 .trim_start_matches('/')
72 .replace("/elements", "")
73 .replace('/', ".");
74
75 let mut resolved_elements = Vec::with_capacity(elements.len());
77 for (index, element) in elements.iter().enumerate() {
78 let element_path = if parent_path.is_empty() {
79 format!("elements.{}", index)
80 } else {
81 format!("{}.elements.{}", parent_path, index)
82 };
83 let resolved = self.resolve_element_ref_recursive(element.clone(), &element_path);
84 resolved_elements.push(resolved);
85 }
86
87 if let Some(target) = self.evaluated_schema.pointer_mut(&normalized_path) {
89 *target = Value::Array(resolved_elements);
90 }
91 }
92
93 fn resolve_element_ref_recursive(&self, element: Value, path_context: &str) -> Value {
96 let resolved = self.resolve_element_ref(element);
98
99 if let Value::Object(mut map) = resolved {
101 if !map.contains_key("$parentHide") {
103 map.insert("$parentHide".to_string(), Value::Bool(false));
104 }
105
106 if !map.contains_key("$fullpath") {
108 map.insert("$fullpath".to_string(), Value::String(path_context.to_string()));
109 }
110
111 if !map.contains_key("$path") {
112 let last_segment = path_context.split('.').last().unwrap_or(path_context);
113 map.insert("$path".to_string(), Value::String(last_segment.to_string()));
114 }
115
116 if let Some(Value::Array(elements)) = map.get("elements") {
118 let mut resolved_nested = Vec::with_capacity(elements.len());
119 for (index, nested_element) in elements.iter().enumerate() {
120 let nested_path = format!("{}.elements.{}", path_context, index);
121 resolved_nested.push(self.resolve_element_ref_recursive(nested_element.clone(), &nested_path));
122 }
123 map.insert("elements".to_string(), Value::Array(resolved_nested));
124 }
125
126 return Value::Object(map);
127 }
128
129 resolved
130 }
131
132 fn resolve_element_ref(&self, element: Value) -> Value {
134 match element {
135 Value::Object(mut map) => {
136 if let Some(Value::String(ref_path)) = map.get("$ref").cloned() {
138 let dotted_path = path_utils::pointer_to_dot_notation(&ref_path);
140
141 let last_segment = dotted_path.split('.').last().unwrap_or(&dotted_path);
143
144 map.insert("$fullpath".to_string(), Value::String(dotted_path.clone()));
146 map.insert("$path".to_string(), Value::String(last_segment.to_string()));
147 map.insert("$parentHide".to_string(), Value::Bool(false));
148
149 let normalized_path = if ref_path.starts_with('#') || ref_path.starts_with('/') {
151 path_utils::normalize_to_json_pointer(&ref_path).into_owned()
152 } else {
153 let schema_pointer = path_utils::dot_notation_to_schema_pointer(&ref_path);
154 let schema_path = path_utils::normalize_to_json_pointer(&schema_pointer).into_owned();
155
156 if self.evaluated_schema.pointer(&schema_path).is_some() {
157 schema_path
158 } else {
159 format!("/properties/{}", ref_path.replace('.', "/properties/"))
160 }
161 };
162
163 if let Some(referenced_value) = self.evaluated_schema.pointer(&normalized_path) {
165 let resolved = referenced_value.clone();
166
167 if let Value::Object(mut resolved_map) = resolved {
168 map.remove("$ref");
169
170 if let Some(Value::Object(layout_obj)) = resolved_map.remove("$layout") {
172 let mut result = layout_obj.clone();
173
174 for (key, value) in resolved_map {
178 if key != "type" || !result.contains_key("type") {
179 result.insert(key, value);
180 }
181 }
182
183 for (key, value) in map {
185 result.insert(key, value);
186 }
187
188 return Value::Object(result);
189 } else {
190 for (key, value) in map {
192 resolved_map.insert(key, value);
193 }
194
195 return Value::Object(resolved_map);
196 }
197 } else {
198 return resolved;
199 }
200 }
201 }
202
203 Value::Object(map)
204 }
205 _ => element,
206 }
207 }
208
209 fn propagate_parent_conditions(&mut self, layout_elements_path: &str) {
211 let normalized_path = path_utils::normalize_to_json_pointer(layout_elements_path);
212
213 let elements = if let Some(Value::Array(arr)) = self.evaluated_schema.pointer_mut(&normalized_path) {
215 mem::take(arr)
216 } else {
217 return;
218 };
219
220 let mut updated_elements = Vec::with_capacity(elements.len());
222 for element in elements {
223 updated_elements.push(self.apply_parent_conditions(element, false, false));
224 }
225
226 if let Some(target) = self.evaluated_schema.pointer_mut(&normalized_path) {
228 *target = Value::Array(updated_elements);
229 }
230 }
231
232 fn apply_parent_conditions(&self, element: Value, parent_hidden: bool, parent_disabled: bool) -> Value {
234 if let Value::Object(mut map) = element {
235 let mut element_hidden = parent_hidden;
237 let mut element_disabled = parent_disabled;
238
239 if let Some(Value::Object(condition)) = map.get("condition") {
241 if let Some(Value::Bool(hidden)) = condition.get("hidden") {
242 element_hidden = element_hidden || *hidden;
243 }
244 if let Some(Value::Bool(disabled)) = condition.get("disabled") {
245 element_disabled = element_disabled || *disabled;
246 }
247 }
248
249 if let Some(Value::Object(hide_layout)) = map.get("hideLayout") {
251 if let Some(Value::Bool(all)) = hide_layout.get("all") {
252 if *all {
253 element_hidden = true;
254 }
255 }
256 }
257
258 if parent_hidden || parent_disabled {
260 if map.contains_key("condition")
262 || map.contains_key("$ref")
263 || map.contains_key("$fullpath")
264 {
265 let mut condition = if let Some(Value::Object(c)) = map.get("condition") {
266 c.clone()
267 } else {
268 serde_json::Map::new()
269 };
270
271 if parent_hidden {
272 condition.insert("hidden".to_string(), Value::Bool(true));
273 element_hidden = true;
274 }
275 if parent_disabled {
276 condition.insert("disabled".to_string(), Value::Bool(true));
277 element_disabled = true;
278 }
279
280 map.insert("condition".to_string(), Value::Object(condition));
281 }
282
283 if parent_hidden && (map.contains_key("hideLayout") || map.contains_key("type")) {
285 let mut hide_layout = if let Some(Value::Object(h)) = map.get("hideLayout") {
286 h.clone()
287 } else {
288 serde_json::Map::new()
289 };
290
291 hide_layout.insert("all".to_string(), Value::Bool(true));
293 map.insert("hideLayout".to_string(), Value::Object(hide_layout));
294 }
295 }
296
297 if map.contains_key("$parentHide") {
299 map.insert("$parentHide".to_string(), Value::Bool(parent_hidden));
300 }
301
302 if let Some(Value::Array(elements)) = map.get("elements") {
304 let mut updated_children = Vec::with_capacity(elements.len());
305 for child in elements {
306 updated_children.push(self.apply_parent_conditions(child.clone(), element_hidden, element_disabled));
307 }
308 map.insert("elements".to_string(), Value::Array(updated_children));
309 }
310
311 return Value::Object(map);
312 }
313
314 element
315 }
316
317 fn sync_layout_hidden_to_schema(&mut self, layout_paths: &[String]) {
319 let mut hidden_paths = Vec::new();
320
321 for layout_path in layout_paths {
323 let normalized_path = path_utils::normalize_to_json_pointer(layout_path);
324 if let Some(Value::Array(elements)) = self.evaluated_schema.pointer(&normalized_path) {
325 for element in elements {
326 self.collect_hidden_paths_recursive(element, &mut hidden_paths);
327 }
328 }
329 }
330
331 for schema_path_dot in hidden_paths {
333 let schema_pointer = path_utils::dot_notation_to_schema_pointer(&schema_path_dot);
334 let normalized_pointer = path_utils::normalize_to_json_pointer(&schema_pointer);
335
336 if let Some(schema_node) = self.evaluated_schema.pointer_mut(&normalized_pointer) {
337 if let Value::Object(map) = schema_node {
338 let mut condition = if let Some(Value::Object(c)) = map.get("condition") {
340 c.clone()
341 } else {
342 serde_json::Map::new()
343 };
344
345 condition.insert("hidden".to_string(), Value::Bool(true));
346 map.insert("condition".to_string(), Value::Object(condition));
347 }
348 } else {
349 let alt_pointer = format!("/properties{}", normalized_pointer);
351 if let Some(schema_node) = self.evaluated_schema.pointer_mut(&alt_pointer) {
352 if let Value::Object(map) = schema_node {
353 let mut condition = if let Some(Value::Object(c)) = map.get("condition") {
354 c.clone()
355 } else {
356 serde_json::Map::new()
357 };
358
359 condition.insert("hidden".to_string(), Value::Bool(true));
360 map.insert("condition".to_string(), Value::Object(condition));
361 }
362 }
363 }
364 }
365 }
366
367 fn collect_hidden_paths_recursive(&self, element: &Value, hidden_paths: &mut Vec<String>) {
368 if let Value::Object(map) = element {
369 let is_hidden = if let Some(Value::Object(condition)) = map.get("condition") {
371 condition.get("hidden").and_then(|v| v.as_bool()).unwrap_or(false)
372 } else {
373 false
374 };
375
376 if is_hidden {
377 if let Some(Value::String(fullpath)) = map.get("fullpath") {
379 hidden_paths.push(fullpath.clone());
380 } else if let Some(Value::String(fullpath)) = map.get("$fullpath") {
381 hidden_paths.push(fullpath.clone());
382 }
383 }
384
385 if let Some(Value::Array(elements)) = map.get("elements") {
387 for child in elements {
388 self.collect_hidden_paths_recursive(child, hidden_paths);
389 }
390 }
391 }
392 }
393}