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
10pub type ResolvedProps = Arc<IndexMap<String, serde_json::Value>>;
19
20pub const DEFAULT_ROUTER_CACHE_SIZE: usize = 10;
25
26#[derive(Debug, Clone)]
28pub enum ControlFlowKind {
29 ForEach {
31 item_name: String,
32 key_path: Option<String>,
33 },
34 Conditional,
36 Router {
45 cache: IndexMap<String, Vec<NodeId>>,
52 current_route_key: Option<String>,
56 max_cache_size: usize,
58 },
59}
60
61#[derive(Debug, Clone)]
66pub struct InstanceNode {
67 pub id: NodeId,
69
70 pub element_type: String,
72
73 pub props: ResolvedProps,
76
77 pub raw_props: Props,
79
80 pub element_template: Option<Arc<Element>>,
84
85 pub ir_node_template: Option<Arc<IRNode>>,
89
90 pub control_flow: Option<ControlFlowKind>,
92
93 pub key: Option<String>,
96
97 pub parent: Option<NodeId>,
99
100 pub children: im::Vector<NodeId>,
102
103 pub module_scope: Option<String>,
107}
108
109impl InstanceNode {
110 pub fn new(id: NodeId, element: &Element, state: &serde_json::Value) -> Self {
111 Self::new_full(id, element, state, None)
112 }
113
114 pub fn new_full(
115 id: NodeId,
116 element: &Element,
117 state: &serde_json::Value,
118 data_sources: Option<&DataSources>,
119 ) -> Self {
120 let props = resolve_props_full(&element.props, state, None, data_sources);
121
122 Self {
123 id,
124 element_type: element.element_type.clone(),
125 props,
126 raw_props: element.props.clone(),
127 element_template: None,
128 ir_node_template: None,
129 control_flow: None,
130 key: element.key.clone(),
131 parent: None,
132 children: im::Vector::new(),
133 module_scope: element.module_scope.clone(),
134 }
135 }
136
137 pub fn new_control_flow(
139 id: NodeId,
140 element_type: &str,
141 props: ResolvedProps,
142 raw_props: Props,
143 control_flow: ControlFlowKind,
144 ir_node_template: IRNode,
145 ) -> Self {
146 Self {
147 id,
148 element_type: element_type.to_string(),
149 props,
150 raw_props,
151 element_template: None,
152 ir_node_template: Some(Arc::new(ir_node_template)),
153 control_flow: Some(control_flow),
154 key: None,
155 parent: None,
156 children: im::Vector::new(),
157 module_scope: None,
158 }
159 }
160
161 pub fn update_props(&mut self, state: &serde_json::Value) {
163 self.props = resolve_props(&self.raw_props, state);
164 }
165
166 pub fn update_props_with_data_sources(
168 &mut self,
169 state: &serde_json::Value,
170 data_sources: Option<&IndexMap<String, serde_json::Value>>,
171 ) {
172 self.props = resolve_props_full(&self.raw_props, state, None, data_sources);
173 }
174
175 pub fn is_foreach(&self) -> bool {
177 matches!(self.control_flow, Some(ControlFlowKind::ForEach { .. }))
178 }
179
180 pub fn is_conditional(&self) -> bool {
182 matches!(self.control_flow, Some(ControlFlowKind::Conditional))
183 }
184
185 pub fn is_router(&self) -> bool {
187 matches!(self.control_flow, Some(ControlFlowKind::Router { .. }))
188 }
189}
190
191pub struct InstanceTree {
193 nodes: SlotMap<NodeId, InstanceNode>,
195
196 root: Option<NodeId>,
198}
199
200impl InstanceTree {
201 pub fn new() -> Self {
202 Self {
203 nodes: SlotMap::with_key(),
204 root: None,
205 }
206 }
207
208 pub fn clear(&mut self) {
210 self.nodes.clear();
211 self.root = None;
212 }
213
214 pub fn create_node(&mut self, element: &Element, state: &serde_json::Value) -> NodeId {
216 self.nodes
217 .insert_with_key(|id| InstanceNode::new(id, element, state))
218 }
219
220 pub fn create_node_full(
222 &mut self,
223 element: &Element,
224 state: &serde_json::Value,
225 data_sources: Option<&DataSources>,
226 ) -> NodeId {
227 self.nodes
228 .insert_with_key(|id| InstanceNode::new_full(id, element, state, data_sources))
229 }
230
231 pub fn create_control_flow_node(
233 &mut self,
234 element_type: &str,
235 props: ResolvedProps,
236 raw_props: Props,
237 control_flow: ControlFlowKind,
238 ir_node_template: IRNode,
239 ) -> NodeId {
240 self.nodes.insert_with_key(|id| {
241 InstanceNode::new_control_flow(
242 id,
243 element_type,
244 props,
245 raw_props,
246 control_flow,
247 ir_node_template,
248 )
249 })
250 }
251
252 pub fn get(&self, id: NodeId) -> Option<&InstanceNode> {
254 self.nodes.get(id)
255 }
256
257 pub fn get_mut(&mut self, id: NodeId) -> Option<&mut InstanceNode> {
259 self.nodes.get_mut(id)
260 }
261
262 pub fn remove(&mut self, id: NodeId) -> Option<InstanceNode> {
264 if let Some(node) = self.nodes.get(id) {
265 let children = node.children.clone();
266 for child_id in children {
268 self.remove(child_id);
269 }
270 }
271 self.nodes.remove(id)
272 }
273
274 pub fn set_root(&mut self, id: NodeId) {
276 self.root = Some(id);
277 }
278
279 pub fn root(&self) -> Option<NodeId> {
281 self.root
282 }
283
284 pub fn add_child(&mut self, parent_id: NodeId, child_id: NodeId, before: Option<NodeId>) {
286 if let Some(parent) = self.nodes.get_mut(parent_id) {
287 if let Some(before_id) = before {
288 if let Some(pos) = parent.children.iter().position(|&id| id == before_id) {
289 parent.children.insert(pos, child_id);
290 } else {
291 parent.children.push_back(child_id);
292 }
293 } else {
294 parent.children.push_back(child_id);
295 }
296 }
297
298 if let Some(child) = self.nodes.get_mut(child_id) {
299 child.parent = Some(parent_id);
300 }
301 }
302
303 pub fn remove_child(&mut self, parent_id: NodeId, child_id: NodeId) {
305 if let Some(parent) = self.nodes.get_mut(parent_id) {
306 parent.children = parent
307 .children
308 .iter()
309 .filter(|&&id| id != child_id)
310 .copied()
311 .collect();
312 }
313
314 if let Some(child) = self.nodes.get_mut(child_id) {
315 child.parent = None;
316 }
317 }
318
319 pub fn update_nodes(
321 &mut self,
322 node_ids: &indexmap::IndexSet<NodeId>,
323 state: &serde_json::Value,
324 ) {
325 for &node_id in node_ids {
326 if let Some(node) = self.nodes.get_mut(node_id) {
327 node.update_props(state);
328 }
329 }
330 }
331
332 pub fn len(&self) -> usize {
334 self.nodes.len()
335 }
336
337 pub fn is_empty(&self) -> bool {
339 self.nodes.is_empty()
340 }
341
342 pub fn iter(&self) -> impl Iterator<Item = (NodeId, &InstanceNode)> {
344 self.nodes.iter()
345 }
346}
347
348impl Default for InstanceTree {
349 fn default() -> Self {
350 Self::new()
351 }
352}
353
354#[cfg(test)]
355mod tests {
356
357 use crate::reconcile::resolve::evaluate_binding;
358 use serde_json::json;
359
360 #[test]
361 fn test_evaluate_binding() {
362 use crate::reactive::Binding;
363
364 let state = json!({
365 "user": {
366 "name": "Alice",
367 "age": 30
368 }
369 });
370
371 let name_binding = Binding::state(vec!["user".to_string(), "name".to_string()]);
372 let age_binding = Binding::state(vec!["user".to_string(), "age".to_string()]);
373 let email_binding = Binding::state(vec!["user".to_string(), "email".to_string()]);
374
375 assert_eq!(
376 evaluate_binding(&name_binding, &state),
377 Some(json!("Alice"))
378 );
379 assert_eq!(evaluate_binding(&age_binding, &state), Some(json!(30)));
380 assert_eq!(evaluate_binding(&email_binding, &state), None);
381 }
382}