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 resolved_map.remove("properties");
173
174 for (key, value) in resolved_map {
176 if key != "type" || !result.contains_key("type") {
177 result.insert(key, value);
178 }
179 }
180
181 for (key, value) in map {
183 result.insert(key, value);
184 }
185
186 return Value::Object(result);
187 } else {
188 for (key, value) in map {
190 resolved_map.insert(key, value);
191 }
192
193 return Value::Object(resolved_map);
194 }
195 } else {
196 return resolved;
197 }
198 }
199 }
200
201 Value::Object(map)
202 }
203 _ => element,
204 }
205 }
206
207 fn propagate_parent_conditions(&mut self, layout_elements_path: &str) {
209 let normalized_path = path_utils::normalize_to_json_pointer(layout_elements_path);
210
211 let elements = if let Some(Value::Array(arr)) = self.evaluated_schema.pointer_mut(&normalized_path) {
213 mem::take(arr)
214 } else {
215 return;
216 };
217
218 let mut updated_elements = Vec::with_capacity(elements.len());
220 for element in elements {
221 updated_elements.push(self.apply_parent_conditions(element, false, false));
222 }
223
224 if let Some(target) = self.evaluated_schema.pointer_mut(&normalized_path) {
226 *target = Value::Array(updated_elements);
227 }
228 }
229
230 fn apply_parent_conditions(&self, element: Value, parent_hidden: bool, parent_disabled: bool) -> Value {
232 if let Value::Object(mut map) = element {
233 let mut element_hidden = parent_hidden;
235 let mut element_disabled = parent_disabled;
236
237 if let Some(Value::Object(condition)) = map.get("condition") {
239 if let Some(Value::Bool(hidden)) = condition.get("hidden") {
240 element_hidden = element_hidden || *hidden;
241 }
242 if let Some(Value::Bool(disabled)) = condition.get("disabled") {
243 element_disabled = element_disabled || *disabled;
244 }
245 }
246
247 if let Some(Value::Object(hide_layout)) = map.get("hideLayout") {
249 if let Some(Value::Bool(all)) = hide_layout.get("all") {
250 if *all {
251 element_hidden = true;
252 }
253 }
254 }
255
256 if parent_hidden || parent_disabled {
258 if map.contains_key("condition")
260 || map.contains_key("$ref")
261 || map.contains_key("$fullpath")
262 {
263 let mut condition = if let Some(Value::Object(c)) = map.get("condition") {
264 c.clone()
265 } else {
266 serde_json::Map::new()
267 };
268
269 if parent_hidden {
270 condition.insert("hidden".to_string(), Value::Bool(true));
271 element_hidden = true;
272 }
273 if parent_disabled {
274 condition.insert("disabled".to_string(), Value::Bool(true));
275 element_disabled = true;
276 }
277
278 map.insert("condition".to_string(), Value::Object(condition));
279 }
280
281 if parent_hidden && (map.contains_key("hideLayout") || map.contains_key("type")) {
283 let mut hide_layout = if let Some(Value::Object(h)) = map.get("hideLayout") {
284 h.clone()
285 } else {
286 serde_json::Map::new()
287 };
288
289 hide_layout.insert("all".to_string(), Value::Bool(true));
291 map.insert("hideLayout".to_string(), Value::Object(hide_layout));
292 }
293 }
294
295 if map.contains_key("$parentHide") {
297 map.insert("$parentHide".to_string(), Value::Bool(parent_hidden));
298 }
299
300 if let Some(Value::Array(elements)) = map.get("elements") {
302 let mut updated_children = Vec::with_capacity(elements.len());
303 for child in elements {
304 updated_children.push(self.apply_parent_conditions(child.clone(), element_hidden, element_disabled));
305 }
306 map.insert("elements".to_string(), Value::Array(updated_children));
307 }
308
309 return Value::Object(map);
310 }
311
312 element
313 }
314}