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 element_pointer = format!("{}/{}", normalized_path, index);
84 let resolved = self.resolve_element_ref_recursive(element.clone(), &element_path, &element_pointer);
85 resolved_elements.push(resolved);
86 }
87
88 if let Some(target) = self.evaluated_schema.pointer_mut(&normalized_path) {
90 *target = Value::Array(resolved_elements);
91 }
92 }
93
94 fn resolve_element_ref_recursive(&self, element: Value, path_context: &str, original_pointer_path: &str) -> Value {
95 let resolved = self.resolve_element_ref(element, original_pointer_path);
97
98 if let Value::Object(mut map) = resolved {
100 if !map.contains_key("$parentHide") {
102 map.insert("$parentHide".to_string(), Value::Bool(false));
103 }
104
105 if !map.contains_key("$fullpath") {
107 map.insert(
108 "$fullpath".to_string(),
109 Value::String(path_context.to_string()),
110 );
111 }
112
113 if !map.contains_key("$path") {
114 let last_segment = path_context.split('.').last().unwrap_or(path_context);
115 map.insert("$path".to_string(), Value::String(last_segment.to_string()));
116 }
117
118 if let Some(Value::Array(elements)) = map.get("elements") {
120 let mut resolved_nested = Vec::with_capacity(elements.len());
121 for (index, nested_element) in elements.iter().enumerate() {
122 let nested_path = format!("{}.elements.{}", path_context, index);
123 let nested_pointer = format!("{}/elements/{}", original_pointer_path, index);
124 resolved_nested.push(
125 self.resolve_element_ref_recursive(nested_element.clone(), &nested_path, &nested_pointer),
126 );
127 }
128 map.insert("elements".to_string(), Value::Array(resolved_nested));
129 }
130
131 return Value::Object(map);
132 }
133
134 resolved
135 }
136
137 fn resolve_element_ref(&self, element: Value, original_pointer_path: &str) -> Value {
139 match element {
140 Value::Object(mut map) => {
141 if let Some(Value::String(ref_path)) = map.get("$ref").cloned() {
143 let dotted_path = path_utils::pointer_to_dot_notation(&ref_path);
145
146 let last_segment = dotted_path.split('.').last().unwrap_or(&dotted_path);
148
149 map.insert("$fullpath".to_string(), Value::String(dotted_path.clone()));
151 map.insert("$path".to_string(), Value::String(last_segment.to_string()));
152 map.insert("$parentHide".to_string(), Value::Bool(false));
153
154 let normalized_path = if ref_path.starts_with('#') || ref_path.starts_with('/')
156 {
157 path_utils::normalize_to_json_pointer(&ref_path).into_owned()
158 } else {
159 let schema_pointer = path_utils::dot_notation_to_schema_pointer(&ref_path);
160 let schema_path =
161 path_utils::normalize_to_json_pointer(&schema_pointer).into_owned();
162
163 if self.evaluated_schema.pointer(&schema_path).is_some() {
164 schema_path
165 } else {
166 format!("/properties/{}", ref_path.replace('.', "/properties/"))
167 }
168 };
169
170 if let Some(referenced_value) = self.evaluated_schema.pointer(&normalized_path)
172 {
173 let resolved = referenced_value.clone();
174
175 if let Value::Object(mut resolved_map) = resolved {
176 map.remove("$ref");
177
178 if let Some(Value::Object(layout_obj)) = resolved_map.remove("$layout")
180 {
181 let mut result = layout_obj.clone();
182
183 for (key, value) in resolved_map {
187 if key != "type" || !result.contains_key("type") {
188 result.insert(key, value);
189 }
190 }
191
192 for (key, value) in map {
194 result.insert(key, value);
195 }
196
197 return Value::Object(result);
198 } else {
199 for (key, value) in map {
201 resolved_map.insert(key, value);
202 }
203
204 return Value::Object(resolved_map);
205 }
206 } else {
207 return resolved;
208 }
209 }
210 }
211
212 if let Some(Value::Object(evaluated_map)) = self.evaluated_schema.pointer(original_pointer_path) {
215 if let Some(hide_layout) = evaluated_map.get("hideLayout") {
216 map.insert("hideLayout".to_string(), hide_layout.clone());
217 }
218 if let Some(condition) = evaluated_map.get("condition") {
219 map.insert("condition".to_string(), condition.clone());
220 }
221 }
222
223 Value::Object(map)
224 }
225 _ => element,
226 }
227 }
228
229 fn propagate_parent_conditions(&mut self, layout_elements_path: &str) {
231 let normalized_path = path_utils::normalize_to_json_pointer(layout_elements_path);
232
233 let elements =
235 if let Some(Value::Array(arr)) = self.evaluated_schema.pointer_mut(&normalized_path) {
236 mem::take(arr)
237 } else {
238 return;
239 };
240
241 let mut updated_elements = Vec::with_capacity(elements.len());
243 for element in elements {
244 updated_elements.push(self.apply_parent_conditions(element, false, false));
245 }
246
247 if let Some(target) = self.evaluated_schema.pointer_mut(&normalized_path) {
249 *target = Value::Array(updated_elements);
250 }
251 }
252
253 fn apply_parent_conditions(
255 &self,
256 element: Value,
257 parent_hidden: bool,
258 parent_disabled: bool,
259 ) -> Value {
260 if let Value::Object(mut map) = element {
261 let mut element_hidden = parent_hidden;
263 let mut element_disabled = parent_disabled;
264
265 if let Some(Value::Object(condition)) = map.get("condition") {
267 if let Some(Value::Bool(hidden)) = condition.get("hidden") {
268 element_hidden = element_hidden || *hidden;
269 }
270 if let Some(Value::Bool(disabled)) = condition.get("disabled") {
271 element_disabled = element_disabled || *disabled;
272 }
273 }
274
275 if let Some(Value::Object(hide_layout)) = map.get("hideLayout") {
277 if let Some(Value::Bool(all)) = hide_layout.get("all") {
278 if *all {
279 element_hidden = true;
280 }
281 }
282 }
283
284 if parent_hidden || parent_disabled {
286 if map.contains_key("condition")
288 || map.contains_key("$ref")
289 || map.contains_key("$fullpath")
290 {
291 let mut condition = if let Some(Value::Object(c)) = map.get("condition") {
292 c.clone()
293 } else {
294 serde_json::Map::new()
295 };
296
297 if parent_hidden {
298 condition.insert("hidden".to_string(), Value::Bool(true));
299 element_hidden = true;
300 }
301 if parent_disabled {
302 condition.insert("disabled".to_string(), Value::Bool(true));
303 element_disabled = true;
304 }
305
306 map.insert("condition".to_string(), Value::Object(condition));
307 }
308
309 if parent_hidden && (map.contains_key("hideLayout") || map.contains_key("type")) {
311 let mut hide_layout = if let Some(Value::Object(h)) = map.get("hideLayout") {
312 h.clone()
313 } else {
314 serde_json::Map::new()
315 };
316
317 hide_layout.insert("all".to_string(), Value::Bool(true));
319 map.insert("hideLayout".to_string(), Value::Object(hide_layout));
320 }
321 }
322
323 if map.contains_key("$parentHide") {
325 map.insert("$parentHide".to_string(), Value::Bool(parent_hidden));
326 }
327
328 if let Some(Value::Array(elements)) = map.get("elements") {
330 let mut updated_children = Vec::with_capacity(elements.len());
331 for child in elements {
332 updated_children.push(self.apply_parent_conditions(
333 child.clone(),
334 element_hidden,
335 element_disabled,
336 ));
337 }
338 map.insert("elements".to_string(), Value::Array(updated_children));
339 }
340
341 return Value::Object(map);
342 }
343
344 element
345 }
346
347 fn sync_layout_hidden_to_schema(&mut self, layout_paths: &[String]) {
349 let mut hidden_paths = Vec::new();
350
351 for layout_path in layout_paths {
353 let normalized_path = path_utils::normalize_to_json_pointer(layout_path);
354 if let Some(Value::Array(elements)) = self.evaluated_schema.pointer(&normalized_path) {
355 for element in elements {
356 self.collect_hidden_paths_recursive(element, &mut hidden_paths);
357 }
358 }
359 }
360
361 for schema_path_dot in hidden_paths {
363 let schema_pointer = path_utils::dot_notation_to_schema_pointer(&schema_path_dot);
364 let normalized_pointer = path_utils::normalize_to_json_pointer(&schema_pointer);
365
366 if let Some(schema_node) = self.evaluated_schema.pointer_mut(&normalized_pointer) {
367 if let Value::Object(map) = schema_node {
368 let mut condition = if let Some(Value::Object(c)) = map.get("condition") {
370 c.clone()
371 } else {
372 serde_json::Map::new()
373 };
374
375 condition.insert("hidden".to_string(), Value::Bool(true));
376 map.insert("condition".to_string(), Value::Object(condition));
377 }
378 } else {
379 let alt_pointer = format!("/properties{}", normalized_pointer);
381 if let Some(schema_node) = self.evaluated_schema.pointer_mut(&alt_pointer) {
382 if let Value::Object(map) = schema_node {
383 let mut condition = if let Some(Value::Object(c)) = map.get("condition") {
384 c.clone()
385 } else {
386 serde_json::Map::new()
387 };
388
389 condition.insert("hidden".to_string(), Value::Bool(true));
390 map.insert("condition".to_string(), Value::Object(condition));
391 }
392 }
393 }
394 }
395 }
396
397 fn collect_hidden_paths_recursive(&self, element: &Value, hidden_paths: &mut Vec<String>) {
398 if let Value::Object(map) = element {
399 let is_hidden = if let Some(Value::Object(condition)) = map.get("condition") {
401 condition
402 .get("hidden")
403 .and_then(|v| v.as_bool())
404 .unwrap_or(false)
405 } else {
406 false
407 };
408
409 if is_hidden {
410 if let Some(Value::String(fullpath)) = map.get("fullpath") {
412 hidden_paths.push(fullpath.clone());
413 } else if let Some(Value::String(fullpath)) = map.get("$fullpath") {
414 hidden_paths.push(fullpath.clone());
415 }
416 }
417
418 if let Some(Value::Array(elements)) = map.get("elements") {
420 for child in elements {
421 self.collect_hidden_paths_recursive(child, hidden_paths);
422 }
423 }
424 }
425 }
426}