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) {
11 if evaluate {
12 if let Ok(data_str) = serde_json::to_string(&self.data) {
14 let _ = self.evaluate(&data_str, None, None);
15 }
16 }
17
18 self.resolve_layout_internal();
19 }
20
21 fn resolve_layout_internal(&mut self) {
22 time_block!(" resolve_layout_internal()", {
23 let layout_paths = self.layout_paths.clone();
25
26 time_block!(" resolve_layout_elements", {
27 for layout_path in layout_paths.iter() {
28 self.resolve_layout_elements(layout_path);
29 }
30 });
31
32 time_block!(" propagate_parent_conditions", {
34 for layout_path in layout_paths.iter() {
35 self.propagate_parent_conditions(layout_path);
36 }
37 });
38 });
39 }
40
41 fn resolve_layout_elements(&mut self, layout_elements_path: &str) {
43 let normalized_path = path_utils::normalize_to_json_pointer(layout_elements_path);
45
46 let elements = if let Some(Value::Array(arr)) = self.schema.pointer(&normalized_path) {
49 arr.clone()
50 } else {
51 return;
52 };
53
54 let parent_path = normalized_path
56 .trim_start_matches('/')
57 .replace("/elements", "")
58 .replace('/', ".");
59
60 let mut resolved_elements = Vec::with_capacity(elements.len());
62 for (index, element) in elements.iter().enumerate() {
63 let element_path = if parent_path.is_empty() {
64 format!("elements.{}", index)
65 } else {
66 format!("{}.elements.{}", parent_path, index)
67 };
68 let resolved = self.resolve_element_ref_recursive(element.clone(), &element_path);
69 resolved_elements.push(resolved);
70 }
71
72 if let Some(target) = self.evaluated_schema.pointer_mut(&normalized_path) {
74 *target = Value::Array(resolved_elements);
75 }
76 }
77
78 fn resolve_element_ref_recursive(&self, element: Value, path_context: &str) -> Value {
81 let resolved = self.resolve_element_ref(element);
83
84 if let Value::Object(mut map) = resolved {
86 if !map.contains_key("$parentHide") {
88 map.insert("$parentHide".to_string(), Value::Bool(false));
89 }
90
91 if !map.contains_key("$fullpath") {
93 map.insert("$fullpath".to_string(), Value::String(path_context.to_string()));
94 }
95
96 if !map.contains_key("$path") {
97 let last_segment = path_context.split('.').last().unwrap_or(path_context);
98 map.insert("$path".to_string(), Value::String(last_segment.to_string()));
99 }
100
101 if let Some(Value::Array(elements)) = map.get("elements") {
103 let mut resolved_nested = Vec::with_capacity(elements.len());
104 for (index, nested_element) in elements.iter().enumerate() {
105 let nested_path = format!("{}.elements.{}", path_context, index);
106 resolved_nested.push(self.resolve_element_ref_recursive(nested_element.clone(), &nested_path));
107 }
108 map.insert("elements".to_string(), Value::Array(resolved_nested));
109 }
110
111 return Value::Object(map);
112 }
113
114 resolved
115 }
116
117 fn resolve_element_ref(&self, element: Value) -> Value {
119 match element {
120 Value::Object(mut map) => {
121 if let Some(Value::String(ref_path)) = map.get("$ref").cloned() {
123 let dotted_path = path_utils::pointer_to_dot_notation(&ref_path);
125
126 let last_segment = dotted_path.split('.').last().unwrap_or(&dotted_path);
128
129 map.insert("$fullpath".to_string(), Value::String(dotted_path.clone()));
131 map.insert("$path".to_string(), Value::String(last_segment.to_string()));
132 map.insert("$parentHide".to_string(), Value::Bool(false));
133
134 let normalized_path = if ref_path.starts_with('#') || ref_path.starts_with('/') {
136 path_utils::normalize_to_json_pointer(&ref_path)
137 } else {
138 let schema_pointer = path_utils::dot_notation_to_schema_pointer(&ref_path);
140 let schema_path = path_utils::normalize_to_json_pointer(&schema_pointer);
141
142 if self.evaluated_schema.pointer(&schema_path).is_some() {
144 schema_path
145 } else {
146 format!("/properties/{}", ref_path.replace('.', "/properties/"))
148 }
149 };
150
151 if let Some(referenced_value) = self.evaluated_schema.pointer(&normalized_path) {
153 let resolved = referenced_value.clone();
154
155 if let Value::Object(mut resolved_map) = resolved {
156 map.remove("$ref");
157
158 if let Some(Value::Object(layout_obj)) = resolved_map.remove("$layout") {
160 let mut result = layout_obj.clone();
161
162 resolved_map.remove("properties");
164
165 for (key, value) in resolved_map {
167 if key != "type" || !result.contains_key("type") {
168 result.insert(key, value);
169 }
170 }
171
172 for (key, value) in map {
174 result.insert(key, value);
175 }
176
177 return Value::Object(result);
178 } else {
179 for (key, value) in map {
181 resolved_map.insert(key, value);
182 }
183
184 return Value::Object(resolved_map);
185 }
186 } else {
187 return resolved;
188 }
189 }
190 }
191
192 Value::Object(map)
193 }
194 _ => element,
195 }
196 }
197
198 fn propagate_parent_conditions(&mut self, layout_elements_path: &str) {
200 let normalized_path = path_utils::normalize_to_json_pointer(layout_elements_path);
201
202 let elements = if let Some(Value::Array(arr)) = self.evaluated_schema.pointer_mut(&normalized_path) {
204 mem::take(arr)
205 } else {
206 return;
207 };
208
209 let mut updated_elements = Vec::with_capacity(elements.len());
211 for element in elements {
212 updated_elements.push(self.apply_parent_conditions(element, false, false));
213 }
214
215 if let Some(target) = self.evaluated_schema.pointer_mut(&normalized_path) {
217 *target = Value::Array(updated_elements);
218 }
219 }
220
221 fn apply_parent_conditions(&self, element: Value, parent_hidden: bool, parent_disabled: bool) -> Value {
223 if let Value::Object(mut map) = element {
224 let mut element_hidden = parent_hidden;
226 let mut element_disabled = parent_disabled;
227
228 if let Some(Value::Object(condition)) = map.get("condition") {
230 if let Some(Value::Bool(hidden)) = condition.get("hidden") {
231 element_hidden = element_hidden || *hidden;
232 }
233 if let Some(Value::Bool(disabled)) = condition.get("disabled") {
234 element_disabled = element_disabled || *disabled;
235 }
236 }
237
238 if let Some(Value::Object(hide_layout)) = map.get("hideLayout") {
240 if let Some(Value::Bool(all)) = hide_layout.get("all") {
241 if *all {
242 element_hidden = true;
243 }
244 }
245 }
246
247 if parent_hidden || parent_disabled {
249 if map.contains_key("condition")
251 || map.contains_key("$ref")
252 || map.contains_key("$fullpath")
253 {
254 let mut condition = if let Some(Value::Object(c)) = map.get("condition") {
255 c.clone()
256 } else {
257 serde_json::Map::new()
258 };
259
260 if parent_hidden {
261 condition.insert("hidden".to_string(), Value::Bool(true));
262 element_hidden = true;
263 }
264 if parent_disabled {
265 condition.insert("disabled".to_string(), Value::Bool(true));
266 element_disabled = true;
267 }
268
269 map.insert("condition".to_string(), Value::Object(condition));
270 }
271
272 if parent_hidden && (map.contains_key("hideLayout") || map.contains_key("type")) {
274 let mut hide_layout = if let Some(Value::Object(h)) = map.get("hideLayout") {
275 h.clone()
276 } else {
277 serde_json::Map::new()
278 };
279
280 hide_layout.insert("all".to_string(), Value::Bool(true));
282 map.insert("hideLayout".to_string(), Value::Object(hide_layout));
283 }
284 }
285
286 if map.contains_key("$parentHide") {
288 map.insert("$parentHide".to_string(), Value::Bool(parent_hidden));
289 }
290
291 if let Some(Value::Array(elements)) = map.get("elements") {
293 let mut updated_children = Vec::with_capacity(elements.len());
294 for child in elements {
295 updated_children.push(self.apply_parent_conditions(child.clone(), element_hidden, element_disabled));
296 }
297 map.insert("elements".to_string(), Value::Array(updated_children));
298 }
299
300 return Value::Object(map);
301 }
302
303 element
304 }
305}