1use super::resolve::{resolve_props, resolve_props_full};
2use crate::ir::{Element, IRNode, NodeId, Props};
3use indexmap::IndexMap;
4use slotmap::SlotMap;
5use std::sync::Arc;
6
7type DataSources = indexmap::IndexMap<String, serde_json::Value>;
9
10#[derive(Debug, Clone)]
12pub enum ControlFlowKind {
13 ForEach {
15 item_name: String,
16 key_path: Option<String>,
17 },
18 Conditional,
20 Router,
23}
24
25#[derive(Debug, Clone)]
30pub struct InstanceNode {
31 pub id: NodeId,
33
34 pub element_type: String,
36
37 pub props: IndexMap<String, serde_json::Value>,
39
40 pub raw_props: Props,
42
43 pub element_template: Option<Arc<Element>>,
47
48 pub ir_node_template: Option<Arc<IRNode>>,
52
53 pub control_flow: Option<ControlFlowKind>,
55
56 pub key: Option<String>,
59
60 pub parent: Option<NodeId>,
62
63 pub children: im::Vector<NodeId>,
65
66 pub module_scope: Option<String>,
70}
71
72impl InstanceNode {
73 pub fn new(id: NodeId, element: &Element, state: &serde_json::Value) -> Self {
74 Self::new_full(id, element, state, None)
75 }
76
77 pub fn new_full(
78 id: NodeId,
79 element: &Element,
80 state: &serde_json::Value,
81 data_sources: Option<&DataSources>,
82 ) -> Self {
83 let props = resolve_props_full(&element.props, state, None, data_sources);
84
85 Self {
86 id,
87 element_type: element.element_type.clone(),
88 props,
89 raw_props: element.props.clone(),
90 element_template: None,
91 ir_node_template: None,
92 control_flow: None,
93 key: element.key.clone(),
94 parent: None,
95 children: im::Vector::new(),
96 module_scope: element.module_scope.clone(),
97 }
98 }
99
100 pub fn new_control_flow(
102 id: NodeId,
103 element_type: &str,
104 props: IndexMap<String, serde_json::Value>,
105 raw_props: Props,
106 control_flow: ControlFlowKind,
107 ir_node_template: IRNode,
108 ) -> Self {
109 Self {
110 id,
111 element_type: element_type.to_string(),
112 props,
113 raw_props,
114 element_template: None,
115 ir_node_template: Some(Arc::new(ir_node_template)),
116 control_flow: Some(control_flow),
117 key: None,
118 parent: None,
119 children: im::Vector::new(),
120 module_scope: None,
121 }
122 }
123
124 pub fn update_props(&mut self, state: &serde_json::Value) {
126 self.props = resolve_props(&self.raw_props, state);
127 }
128
129 pub fn update_props_with_data_sources(
131 &mut self,
132 state: &serde_json::Value,
133 data_sources: Option<&indexmap::IndexMap<String, serde_json::Value>>,
134 ) {
135 self.props = resolve_props_full(&self.raw_props, state, None, data_sources);
136 }
137
138 pub fn is_foreach(&self) -> bool {
140 matches!(self.control_flow, Some(ControlFlowKind::ForEach { .. }))
141 }
142
143 pub fn is_conditional(&self) -> bool {
145 matches!(self.control_flow, Some(ControlFlowKind::Conditional))
146 }
147
148 pub fn is_router(&self) -> bool {
150 matches!(self.control_flow, Some(ControlFlowKind::Router))
151 }
152}
153
154pub struct InstanceTree {
156 nodes: SlotMap<NodeId, InstanceNode>,
158
159 root: Option<NodeId>,
161}
162
163impl InstanceTree {
164 pub fn new() -> Self {
165 Self {
166 nodes: SlotMap::with_key(),
167 root: None,
168 }
169 }
170
171 pub fn clear(&mut self) {
173 self.nodes.clear();
174 self.root = None;
175 }
176
177 pub fn create_node(&mut self, element: &Element, state: &serde_json::Value) -> NodeId {
179 self.nodes
180 .insert_with_key(|id| InstanceNode::new(id, element, state))
181 }
182
183 pub fn create_node_full(
185 &mut self,
186 element: &Element,
187 state: &serde_json::Value,
188 data_sources: Option<&DataSources>,
189 ) -> NodeId {
190 self.nodes
191 .insert_with_key(|id| InstanceNode::new_full(id, element, state, data_sources))
192 }
193
194 pub fn create_control_flow_node(
196 &mut self,
197 element_type: &str,
198 props: IndexMap<String, serde_json::Value>,
199 raw_props: Props,
200 control_flow: ControlFlowKind,
201 ir_node_template: IRNode,
202 ) -> NodeId {
203 self.nodes.insert_with_key(|id| {
204 InstanceNode::new_control_flow(
205 id,
206 element_type,
207 props,
208 raw_props,
209 control_flow,
210 ir_node_template,
211 )
212 })
213 }
214
215 pub fn get(&self, id: NodeId) -> Option<&InstanceNode> {
217 self.nodes.get(id)
218 }
219
220 pub fn get_mut(&mut self, id: NodeId) -> Option<&mut InstanceNode> {
222 self.nodes.get_mut(id)
223 }
224
225 pub fn remove(&mut self, id: NodeId) -> Option<InstanceNode> {
227 if let Some(node) = self.nodes.get(id) {
228 let children = node.children.clone();
229 for child_id in children {
231 self.remove(child_id);
232 }
233 }
234 self.nodes.remove(id)
235 }
236
237 pub fn set_root(&mut self, id: NodeId) {
239 self.root = Some(id);
240 }
241
242 pub fn root(&self) -> Option<NodeId> {
244 self.root
245 }
246
247 pub fn add_child(&mut self, parent_id: NodeId, child_id: NodeId, before: Option<NodeId>) {
249 if let Some(parent) = self.nodes.get_mut(parent_id) {
250 if let Some(before_id) = before {
251 if let Some(pos) = parent.children.iter().position(|&id| id == before_id) {
252 parent.children.insert(pos, child_id);
253 } else {
254 parent.children.push_back(child_id);
255 }
256 } else {
257 parent.children.push_back(child_id);
258 }
259 }
260
261 if let Some(child) = self.nodes.get_mut(child_id) {
262 child.parent = Some(parent_id);
263 }
264 }
265
266 pub fn remove_child(&mut self, parent_id: NodeId, child_id: NodeId) {
268 if let Some(parent) = self.nodes.get_mut(parent_id) {
269 parent.children = parent
270 .children
271 .iter()
272 .filter(|&&id| id != child_id)
273 .copied()
274 .collect();
275 }
276
277 if let Some(child) = self.nodes.get_mut(child_id) {
278 child.parent = None;
279 }
280 }
281
282 pub fn update_nodes(
284 &mut self,
285 node_ids: &indexmap::IndexSet<NodeId>,
286 state: &serde_json::Value,
287 ) {
288 for &node_id in node_ids {
289 if let Some(node) = self.nodes.get_mut(node_id) {
290 node.update_props(state);
291 }
292 }
293 }
294
295 pub fn len(&self) -> usize {
297 self.nodes.len()
298 }
299
300 pub fn is_empty(&self) -> bool {
302 self.nodes.is_empty()
303 }
304
305 pub fn iter(&self) -> impl Iterator<Item = (NodeId, &InstanceNode)> {
307 self.nodes.iter()
308 }
309}
310
311impl Default for InstanceTree {
312 fn default() -> Self {
313 Self::new()
314 }
315}
316
317#[cfg(test)]
318mod tests {
319
320 use crate::reconcile::resolve::evaluate_binding;
321 use serde_json::json;
322
323 #[test]
324 fn test_evaluate_binding() {
325 use crate::reactive::Binding;
326
327 let state = json!({
328 "user": {
329 "name": "Alice",
330 "age": 30
331 }
332 });
333
334 let name_binding = Binding::state(vec!["user".to_string(), "name".to_string()]);
335 let age_binding = Binding::state(vec!["user".to_string(), "age".to_string()]);
336 let email_binding = Binding::state(vec!["user".to_string(), "email".to_string()]);
337
338 assert_eq!(
339 evaluate_binding(&name_binding, &state),
340 Some(json!("Alice"))
341 );
342 assert_eq!(evaluate_binding(&age_binding, &state), Some(json!(30)));
343 assert_eq!(evaluate_binding(&email_binding, &state), None);
344 }
345}