pax_runtime/
cartridge.rs

1use_RefCell!();
2use crate::api::NodeContext;
3use crate::{
4    ConditionalProperties, ExpandedNode, HandlerRegistry, InstanceNode, InstantiationArgs,
5    ReusableInstanceNodeArgs, RuntimePropertiesStackFrame,
6};
7use pax_lang::Computable;
8use pax_manifest::{TypeId, ValueDefinition};
9use pax_message::borrow;
10use pax_runtime_api::pax_value::{CoercionRules, PaxAny, ToFromPaxAny};
11use pax_runtime_api::properties::PropertyValue;
12use pax_runtime_api::{use_RefCell, CommonProperties, Numeric, Property, Variable};
13use serde::de::DeserializeOwned;
14use std::borrow::Borrow;
15use std::collections::{BTreeMap, HashMap};
16use std::rc::Rc;
17
18pub trait PaxCartridge {}
19pub trait DefinitionToInstanceTraverser {
20    fn new(manifest: pax_manifest::PaxManifest) -> Self
21    where
22        Self: Sized;
23
24    fn get_manifest(&self) -> std::cell::Ref<pax_manifest::PaxManifest>;
25
26    #[cfg(any(feature = "designer", feature = "designtime"))]
27    fn get_designtime_manager(
28        &self,
29        project_query: String,
30    ) -> std::option::Option<std::rc::Rc<RefCell<pax_designtime::DesigntimeManager>>>;
31
32    fn get_main_component(&self, id: &str) -> std::rc::Rc<crate::ComponentInstance> {
33        let main_component_type_id = {
34            let manifest = self.get_manifest();
35            manifest.main_component_type_id.clone()
36        };
37
38        let wrapper_type_id = TypeId::build_singleton(id, Some("RootComponent"));
39
40        let mut args = self.build_component_args(&main_component_type_id);
41        args.template_node_identifier = Some(pax_manifest::UniqueTemplateNodeIdentifier::build(
42            wrapper_type_id,
43            pax_manifest::TemplateNodeId::build(0),
44        ));
45        let main_component = crate::ComponentInstance::instantiate(args);
46        main_component
47    }
48
49    fn get_component(
50        &mut self,
51        type_id: &pax_manifest::TypeId,
52    ) -> std::rc::Rc<dyn crate::rendering::InstanceNode> {
53        let factory = self
54            .get_component_factory(type_id)
55            .expect("Failed to get component factory");
56        let args = self.build_component_args(type_id);
57        factory.build_component(args)
58    }
59
60    fn get_component_factory(
61        &self,
62        type_id: &pax_manifest::TypeId,
63    ) -> Option<Box<dyn crate::ComponentFactory>>;
64
65    fn build_component_args(
66        &self,
67        type_id: &pax_manifest::TypeId,
68    ) -> crate::rendering::InstantiationArgs {
69        let manifest: std::cell::Ref<pax_manifest::PaxManifest> = self.get_manifest();
70        if let None = manifest.components.get(type_id) {
71            panic!("Components with type_id {} not found in manifest", type_id);
72        }
73        let component = manifest.components.get(type_id).unwrap();
74        let factory = self
75            .get_component_factory(&type_id)
76            .expect(&format!("No component factory for type: {}", type_id));
77        let prototypical_common_properties_factory = factory.build_default_common_properties();
78        let prototypical_properties_factory = factory.build_default_properties();
79
80        // pull handlers for this component
81        let handlers = manifest.get_component_handlers(type_id);
82        let handler_registry = Some(factory.build_component_handlers(handlers));
83
84        let mut component_template = None;
85        if let Some(template) = &component.template {
86            let root = template.get_root();
87            let mut instances = Vec::new();
88            for node_id in root {
89                let node = template.get_node(&node_id).unwrap();
90                match node.type_id.get_pax_type() {
91                    pax_manifest::PaxType::If
92                    | pax_manifest::PaxType::Slot
93                    | pax_manifest::PaxType::Repeat => {
94                        instances.push(self.build_control_flow(type_id, &node_id, None));
95                    }
96                    pax_manifest::PaxType::Comment => continue,
97                    _ => {
98                        instances.push(self.build_template_node(type_id, &node_id, None));
99                    }
100                }
101            }
102            component_template = Some(RefCell::new(instances));
103        }
104
105        crate::rendering::InstantiationArgs {
106            prototypical_common_properties_factory,
107            prototypical_properties_factory,
108            handler_registry,
109            component_template,
110            children: None,
111            template_node_identifier: None,
112            properties_scope_factory: Some(factory.get_properties_scope_factory()),
113        }
114    }
115
116    fn build_control_flow(
117        &self,
118        containing_component_type_id: &pax_manifest::TypeId,
119        node_id: &pax_manifest::TemplateNodeId,
120        prior_node: Option<ReusableInstanceNodeArgs>,
121    ) -> std::rc::Rc<dyn crate::rendering::InstanceNode> {
122        let manifest = self.get_manifest();
123        let prototypical_common_properties_factory =
124            Box::new(|_, _| Some(std::rc::Rc::new(RefCell::new(CommonProperties::default()))));
125
126        let containing_component = manifest
127            .components
128            .get(containing_component_type_id)
129            .unwrap();
130        let containing_template = containing_component.template.as_ref().unwrap();
131        let tnd = containing_template.get_node(node_id).unwrap();
132        let unique_identifier = pax_manifest::UniqueTemplateNodeIdentifier::build(
133            containing_component_type_id.clone(),
134            node_id.clone(),
135        );
136
137        let children: RefCell<Vec<Rc<dyn InstanceNode>>> = if let Some(prior_node) = prior_node {
138            prior_node.children
139        } else {
140            RefCell::new(self.build_children(containing_component_type_id, &node_id))
141        };
142        match tnd.type_id.get_pax_type() {
143            pax_manifest::PaxType::If => {
144                let expr_info = tnd
145                    .control_flow_settings
146                    .as_ref()
147                    .unwrap()
148                    .condition_expression
149                    .as_ref()
150                    .unwrap()
151                    .clone();
152                let prototypical_properties_factory: Box<
153                    dyn Fn(
154                        std::rc::Rc<crate::RuntimePropertiesStackFrame>,
155                        Option<std::rc::Rc<ExpandedNode>>,
156                    )
157                        -> Option<std::rc::Rc<RefCell<pax_runtime_api::pax_value::PaxAny>>>,
158                > = Box::new(move |stack_frame, expanded_node| {
159                    let cloned_stack = stack_frame.clone();
160                    let expr_ast = expr_info.expression.clone();
161
162                    let mut dependencies = Vec::new();
163                    for dependency in &expr_info.dependencies {
164                        if let Some(p) = stack_frame.resolve_symbol_as_erased_property(dependency) {
165                            dependencies.push(p);
166                        } else {
167                            log::warn!("Failed to resolve symbol {}", dependency);
168                        }
169                    }
170
171                    if let Some(expanded_node) = &expanded_node {
172                        let expanded_node = borrow!(**expanded_node);
173                        let outer_ref = expanded_node.properties.borrow();
174                        let rc = Rc::clone(&outer_ref);
175                        let mut inner_ref = (*rc).borrow_mut();
176                        let cp = ConditionalProperties::mut_from_pax_any(&mut inner_ref).unwrap();
177                        cp.boolean_expression
178                            .replace_with(Property::computed_with_name(
179                                move || {
180                                    let new_value = expr_ast
181                                        .compute(cloned_stack.clone())
182                                        .unwrap_or_else(|err| {
183                                            log::warn!("Failed to compute expression: {:?}", err);
184                                            Default::default()
185                                        });
186                                    let coerced =
187                                        bool::try_coerce(new_value).unwrap_or_else(|_e| {
188                                            log::warn!(
189                                                "Failed to parse boolean expression: {}",
190                                                expr_ast
191                                            );
192                                            Default::default()
193                                        });
194                                    coerced
195                                },
196                                &dependencies,
197                                "conditional (if) expr",
198                            ));
199                        return None;
200                    }
201
202                    Some(std::rc::Rc::new(RefCell::new({
203                        let mut properties = crate::ConditionalProperties::default();
204                        properties.boolean_expression = Property::computed_with_name(
205                            move || {
206                                let new_value = expr_ast.compute(cloned_stack.clone()).unwrap();
207                                let coerced = bool::try_coerce(new_value).unwrap_or_else(|_e| {
208                                    log::warn!("Failed to parse boolean expression: {}", expr_ast);
209                                    Default::default()
210                                });
211                                coerced
212                            },
213                            &dependencies,
214                            "conditional (if) expr",
215                        );
216                        properties.to_pax_any()
217                    })))
218                });
219                crate::ConditionalInstance::instantiate(crate::rendering::InstantiationArgs {
220                    prototypical_common_properties_factory,
221                    prototypical_properties_factory,
222                    handler_registry: None,
223                    component_template: None,
224                    children: Some(children),
225                    template_node_identifier: Some(unique_identifier),
226                    properties_scope_factory: None,
227                })
228            }
229            pax_manifest::PaxType::Slot => {
230                let expr_info = tnd
231                    .control_flow_settings
232                    .as_ref()
233                    .unwrap()
234                    .slot_index_expression
235                    .as_ref()
236                    .unwrap()
237                    .clone();
238
239                let prototypical_properties_factory: Box<
240                    dyn Fn(
241                        std::rc::Rc<crate::RuntimePropertiesStackFrame>,
242                        Option<std::rc::Rc<ExpandedNode>>,
243                    )
244                        -> Option<std::rc::Rc<RefCell<pax_runtime_api::pax_value::PaxAny>>>,
245                > = Box::new(move |stack_frame, expanded_node| {
246                    let cloned_stack = stack_frame.clone();
247                    let expr_ast = expr_info.expression.clone();
248
249                    let mut dependencies = Vec::new();
250                    for dependency in &expr_info.dependencies {
251                        if let Some(p) = stack_frame.resolve_symbol_as_erased_property(dependency) {
252                            dependencies.push(p);
253                        } else {
254                            log::warn!("Failed to resolve symbol {}", dependency);
255                        }
256                    }
257
258                    if let Some(expanded_node) = &expanded_node {
259                        let expanded_node = borrow!(**expanded_node);
260                        let outer_ref = expanded_node.properties.borrow();
261                        let rc = Rc::clone(&outer_ref);
262                        let mut inner_ref = (*rc).borrow_mut();
263                        let slot_properties =
264                            crate::Slot::mut_from_pax_any(&mut inner_ref).unwrap();
265                        slot_properties
266                            .index
267                            .replace_with(Property::computed_with_name(
268                                move || {
269                                    let new_value = expr_ast
270                                        .compute(cloned_stack.clone())
271                                        .unwrap_or_else(|op_err| {
272                                            log::warn!(
273                                                "Failed to compute expression: {:?}",
274                                                op_err
275                                            );
276                                            Default::default()
277                                        });
278                                    let coerced: Numeric = Numeric::try_coerce(new_value)
279                                        .unwrap_or_else(|_| {
280                                            log::warn!(
281                                                "Failed to parse slot index expression: {}",
282                                                expr_ast
283                                            );
284                                            Default::default()
285                                        });
286                                    coerced
287                                },
288                                &dependencies,
289                                "slot index",
290                            ));
291                        return None;
292                    }
293
294                    Some(std::rc::Rc::new(RefCell::new({
295                        let mut properties = crate::Slot::default();
296
297                        properties.index = Property::computed_with_name(
298                            move || {
299                                let new_value = expr_ast
300                                    .compute(cloned_stack.clone())
301                                    .unwrap_or_else(|op_err| {
302                                        log::warn!("Failed to compute expression: {:?}", op_err);
303                                        Default::default()
304                                    });
305                                let coerced: Numeric = Numeric::try_coerce(new_value)
306                                    .unwrap_or_else(|_| {
307                                        log::warn!(
308                                            "Failed to parse slot index expression: {}",
309                                            expr_ast
310                                        );
311                                        Default::default()
312                                    });
313                                coerced
314                            },
315                            &dependencies,
316                            "slot index",
317                        );
318                        properties.to_pax_any()
319                    })))
320                });
321                crate::SlotInstance::instantiate(crate::rendering::InstantiationArgs {
322                    prototypical_common_properties_factory,
323                    prototypical_properties_factory,
324                    handler_registry: None,
325                    component_template: None,
326                    children: Some(children),
327                    template_node_identifier: Some(unique_identifier),
328                    properties_scope_factory: None,
329                })
330            }
331            pax_manifest::PaxType::Repeat => {
332                let source_expression_info = tnd
333                    .control_flow_settings
334                    .as_ref()
335                    .unwrap()
336                    .repeat_source_expression
337                    .clone()
338                    .unwrap();
339                let predictate_definition = tnd
340                    .control_flow_settings
341                    .as_ref()
342                    .unwrap()
343                    .repeat_predicate_definition
344                    .clone()
345                    .unwrap();
346                let prototypical_properties_factory: Box<
347                    dyn Fn(
348                        std::rc::Rc<crate::RuntimePropertiesStackFrame>,
349                        Option<std::rc::Rc<ExpandedNode>>,
350                    )
351                        -> Option<std::rc::Rc<RefCell<pax_runtime_api::pax_value::PaxAny>>>,
352                > = Box::new(move |stack_frame, expanded_node| {
353                    let cloned_stack = stack_frame.clone();
354                    let expr = source_expression_info.expression.clone();
355                    let deps = source_expression_info.dependencies.clone();
356
357                    let mut dependencies = Vec::new();
358                    for dependency in &deps {
359                        if let Some(p) = stack_frame.resolve_symbol_as_erased_property(dependency) {
360                            dependencies.push(p);
361                        } else {
362                            log::warn!("Failed to resolve symbol {}", dependency);
363                        }
364                    }
365
366                    let (elem, index) = match &predictate_definition {
367                        pax_manifest::ControlFlowRepeatPredicateDefinition::ElemId(id) => {
368                            (Some(id.clone()), None)
369                        }
370                        pax_manifest::ControlFlowRepeatPredicateDefinition::ElemIdIndexId(
371                            t1,
372                            t2,
373                        ) => (Some(t1.clone()), Some(t2.clone())),
374                    };
375
376                    if let Some(expanded_node) = &expanded_node {
377                        let expanded_node = borrow!(**expanded_node);
378                        let outer_ref = expanded_node.properties.borrow();
379                        let rc = Rc::clone(&outer_ref);
380                        let mut inner_ref = (*rc).borrow_mut();
381                        let repeat =
382                            crate::RepeatProperties::mut_from_pax_any(&mut inner_ref).unwrap();
383                        repeat
384                            .source_expression
385                            .replace_with(Property::computed_with_name(
386                                move || {
387                                    expr.compute(cloned_stack.clone()).unwrap_or_else(|op_err| {
388                                        log::warn!("Failed to compute expression: {:?}", op_err);
389                                        Default::default()
390                                    })
391                                },
392                                &dependencies,
393                                "repeat source vec",
394                            ));
395                        repeat.iterator_i_symbol.replace_with(Property::new(index));
396                        repeat
397                            .iterator_elem_symbol
398                            .replace_with(Property::new(elem));
399                        return None;
400                    }
401
402                    Some(std::rc::Rc::new(RefCell::new({
403                        let mut properties = crate::RepeatProperties::default();
404
405                        properties.source_expression = Property::computed_with_name(
406                            move || {
407                                expr.compute(cloned_stack.clone()).unwrap_or_else(|op_err| {
408                                    log::warn!("Failed to compute expression: {:?}", op_err);
409                                    Default::default()
410                                })
411                            },
412                            &dependencies,
413                            "repeat source vec",
414                        );
415
416                        properties
417                            .iterator_i_symbol
418                            .replace_with(Property::new(index));
419                        properties
420                            .iterator_elem_symbol
421                            .replace_with(Property::new(elem));
422                        properties.to_pax_any()
423                    })))
424                });
425                crate::RepeatInstance::instantiate(crate::rendering::InstantiationArgs {
426                    prototypical_common_properties_factory,
427                    prototypical_properties_factory,
428                    handler_registry: None,
429                    component_template: None,
430                    children: Some(children),
431                    template_node_identifier: Some(unique_identifier),
432                    properties_scope_factory: None,
433                })
434            }
435            _ => {
436                unreachable!("Unexpected control flow type {}", tnd.type_id)
437            }
438        }
439    }
440
441    fn build_children(
442        &self,
443        containing_component_type_id: &pax_manifest::TypeId,
444        node_id: &pax_manifest::TemplateNodeId,
445    ) -> Vec<std::rc::Rc<dyn crate::rendering::InstanceNode>> {
446        let manifest = self.get_manifest();
447        let containing_component = manifest
448            .components
449            .get(containing_component_type_id)
450            .unwrap();
451        let containing_template = containing_component.template.as_ref().unwrap();
452        let children = containing_template.get_children(node_id);
453
454        let mut children_instances = Vec::new();
455        for child_id in &children.unwrap_or_default() {
456            let child = containing_template.get_node(&child_id).unwrap();
457            match child.type_id.get_pax_type() {
458                pax_manifest::PaxType::If
459                | pax_manifest::PaxType::Slot
460                | pax_manifest::PaxType::Repeat => {
461                    children_instances.push(self.build_control_flow(
462                        containing_component_type_id,
463                        &child_id,
464                        None,
465                    ));
466                }
467                pax_manifest::PaxType::Comment => continue,
468                _ => {
469                    children_instances.push(self.build_template_node(
470                        containing_component_type_id,
471                        child_id,
472                        None,
473                    ));
474                }
475            }
476        }
477        children_instances
478    }
479
480    fn build_template_node(
481        &self,
482        containing_component_type_id: &pax_manifest::TypeId,
483        node_id: &pax_manifest::TemplateNodeId,
484        prior_node: Option<ReusableInstanceNodeArgs>,
485    ) -> std::rc::Rc<dyn crate::rendering::InstanceNode> {
486        let manifest = self.get_manifest();
487
488        let containing_component = manifest
489            .components
490            .get(containing_component_type_id)
491            .unwrap();
492        let containing_template = containing_component.template.as_ref().unwrap();
493        let node = containing_template.get_node(node_id).unwrap();
494        let containing_component_factory = self
495            .get_component_factory(containing_component_type_id)
496            .unwrap();
497
498        let mut args = self.build_component_args(&node.type_id);
499        let node_component_factory = self.get_component_factory(&node.type_id).unwrap();
500
501        if let Some(prior_node) = prior_node {
502            args.handler_registry = prior_node.handler_registry;
503            args.children = Some(prior_node.children);
504            args.template_node_identifier = prior_node.template_node_identifier;
505        } else {
506            let handlers_from_tnd = manifest.get_inline_event_handlers(node);
507            let updated_registry = if let Some(registry) = args.handler_registry {
508                containing_component_factory.add_inline_handlers(handlers_from_tnd, registry)
509            } else {
510                containing_component_factory.add_inline_handlers(
511                    handlers_from_tnd,
512                    std::rc::Rc::new(RefCell::new(crate::HandlerRegistry::default())),
513                )
514            };
515            // update handlers from tnd
516            args.handler_registry = Some(updated_registry);
517
518            // update children from tnd
519            args.children = Some(RefCell::new(
520                self.build_children(containing_component_type_id, node_id),
521            ));
522
523            // update id
524            args.template_node_identifier =
525                Some(pax_manifest::UniqueTemplateNodeIdentifier::build(
526                    containing_component_type_id.clone(),
527                    node_id.clone(),
528                ));
529        }
530
531        // update properties from tnd
532        let inline_properties = manifest.get_inline_properties(containing_component_type_id, node);
533        let updated_properties =
534            node_component_factory.build_inline_properties(inline_properties.clone());
535        args.prototypical_properties_factory = updated_properties;
536
537        // update common properties from tnd
538        let updated_common_properties =
539            node_component_factory.build_inline_common_properties(inline_properties);
540        args.prototypical_common_properties_factory = updated_common_properties;
541
542        node_component_factory.build_component(args)
543    }
544
545    fn get_template_node_by_id(
546        &self,
547        id: &str,
548    ) -> Option<std::rc::Rc<dyn crate::rendering::InstanceNode>> {
549        let manifest = self.get_manifest();
550        let main_component_type_id = manifest.main_component_type_id.clone();
551        let main_component = manifest.components.get(&main_component_type_id).unwrap();
552        let template = main_component.template.as_ref().unwrap();
553        for node_id in template.get_ids() {
554            if let Some(found) =
555                self.recurse_get_template_node_by_id(id, &main_component_type_id, node_id)
556            {
557                return Some(self.build_template_node(&found.0, &found.1, None));
558            }
559        }
560        None
561    }
562
563    fn check_for_id_in_template_node(
564        &self,
565        id: &str,
566        tnd: &pax_manifest::TemplateNodeDefinition,
567    ) -> bool {
568        if let Some(settings) = &tnd.settings {
569            for setting in settings {
570                if let pax_manifest::SettingElement::Setting(token, value) = setting {
571                    if &token.token_value == "id" {
572                        if let pax_manifest::ValueDefinition::Identifier(ident) = value {
573                            if ident.name == id {
574                                return true;
575                            }
576                        }
577                    }
578                }
579            }
580        }
581        false
582    }
583
584    fn recurse_get_template_node_by_id<'a>(
585        &'a self,
586        id: &str,
587        containing_component_type_id: &'a pax_manifest::TypeId,
588        node_id: &'a pax_manifest::TemplateNodeId,
589    ) -> Option<(pax_manifest::TypeId, pax_manifest::TemplateNodeId)> {
590        let manifest = self.get_manifest();
591        let containing_component = manifest
592            .components
593            .get(containing_component_type_id)
594            .unwrap();
595        let containing_template = containing_component.template.as_ref().unwrap();
596        let tnd = containing_template.get_node(node_id).unwrap();
597
598        if self.check_for_id_in_template_node(id, tnd) {
599            return Some((containing_component_type_id.clone(), node_id.clone()));
600        }
601
602        if let Some(component) = &manifest.components.get(&tnd.type_id) {
603            if let Some(template) = &component.template {
604                for node_id in template.get_ids() {
605                    if let Some(found) =
606                        self.recurse_get_template_node_by_id(id, &tnd.type_id, node_id)
607                    {
608                        return Some(found.clone());
609                    }
610                }
611            }
612        }
613        None
614    }
615}
616
617fn resolve_property<T: CoercionRules + PropertyValue + DeserializeOwned>(
618    name: &str,
619    defined_properties: &BTreeMap<String, ValueDefinition>,
620    stack: &Rc<RuntimePropertiesStackFrame>,
621) -> Property<Option<T>> {
622    let Some(value_def) = defined_properties.get(name) else {
623        return Property::default();
624    };
625    let cloned_stack = stack.clone();
626    let resolved_property: Property<Option<T>> = match value_def.clone() {
627        pax_manifest::ValueDefinition::LiteralValue(lv) => {
628            let val = T::try_coerce(lv).unwrap_or_else(|err| {
629                log::warn!("Failed to coerce new value for property. Error: {:?}", err);
630                Default::default()
631            });
632            Property::new_with_name(Some(val), name)
633        }
634        pax_manifest::ValueDefinition::DoubleBinding(identifier) => {
635            let untyped_property =
636                if let Some(p) = stack.resolve_symbol_as_erased_property(&identifier.name) {
637                    p
638                } else {
639                    log::warn!("Failed to resolve symbol {}", identifier.name);
640                    return Default::default();
641                };
642            Property::new_from_untyped(untyped_property.clone())
643        }
644        pax_manifest::ValueDefinition::Expression(info) => {
645            let mut dependents = vec![];
646            for dependency in &info.dependencies {
647                if let Some(p) = stack.resolve_symbol_as_erased_property(dependency) {
648                    dependents.push(p);
649                } else {
650                    log::warn!("Failed to resolve symbol {}", dependency);
651                }
652            }
653            let name = &info.expression.to_string();
654            Property::computed_with_name(
655                move || {
656                    let new_value = info
657                        .expression
658                        .compute(cloned_stack.clone())
659                        .unwrap_or_else(|err| {
660                            log::warn!("Failed to compute expression: {:?}", err);
661                            Default::default()
662                        });
663                    let coerced = T::try_coerce(new_value.clone()).unwrap_or_else(|err| {
664                        log::warn!("Failed to coerce new value for property. Error: {:?}", err);
665                        Default::default()
666                    });
667                    Some(coerced)
668                },
669                &dependents,
670                name,
671            )
672        }
673        pax_manifest::ValueDefinition::Identifier(ident) => {
674            let property = if let Some(p) = stack.resolve_symbol_as_erased_property(&ident.name) {
675                Property::new_from_untyped(p.clone())
676            } else {
677                log::warn!("Failed to resolve symbol {}", ident.name);
678                return Default::default();
679            };
680            let untyped = property.untyped();
681            Property::computed_with_name(
682                move || {
683                    let new_value = property.get();
684                    Some(new_value)
685                },
686                &[untyped],
687                &ident.name,
688            )
689        }
690        _ => unreachable!("Invalid value definition for {}", stringify!($prop_name)),
691    };
692    resolved_property
693}
694
695pub trait ComponentFactory {
696    /// Returns the default CommonProperties factory
697    fn build_default_common_properties(
698        &self,
699    ) -> Box<
700        dyn Fn(
701            Rc<RuntimePropertiesStackFrame>,
702            Option<Rc<ExpandedNode>>,
703        ) -> Option<Rc<RefCell<CommonProperties>>>,
704    > {
705        Box::new(|_, _| Some(Rc::new(RefCell::new(CommonProperties::default()))))
706    }
707
708    /// Returns the default properties factory for this component
709    fn build_default_properties(
710        &self,
711    ) -> Box<
712        dyn Fn(
713            Rc<RuntimePropertiesStackFrame>,
714            Option<Rc<ExpandedNode>>,
715        ) -> Option<Rc<RefCell<PaxAny>>>,
716    >;
717
718    fn build_inline_common_properties(
719        &self,
720        defined_properties: BTreeMap<String, pax_manifest::ValueDefinition>,
721    ) -> Box<
722        dyn Fn(
723            Rc<RuntimePropertiesStackFrame>,
724            Option<Rc<ExpandedNode>>,
725        ) -> Option<Rc<RefCell<CommonProperties>>>,
726    > {
727        Box::new(move |stack_frame, expanded_node| {
728            if let Some(expanded_node) = &expanded_node {
729                update_existing_common_properties(expanded_node, &defined_properties, &stack_frame);
730                None
731            } else {
732                Some(create_new_common_properties(
733                    &defined_properties,
734                    &stack_frame,
735                ))
736            }
737        })
738    }
739
740    /// Returns the properties factory based on the defined properties
741    fn build_inline_properties(
742        &self,
743        defined_properties: BTreeMap<String, ValueDefinition>,
744    ) -> Box<
745        dyn Fn(
746            Rc<RuntimePropertiesStackFrame>,
747            Option<Rc<ExpandedNode>>,
748        ) -> Option<Rc<RefCell<PaxAny>>>,
749    >;
750
751    /// Returns the requested closure for the handler registry based on the defined handlers for this component
752    /// The argument type is extrapolated based on how the handler was used in the initial compiled template
753    fn build_handler(&self, fn_name: &str)
754        -> fn(Rc<RefCell<PaxAny>>, &NodeContext, Option<PaxAny>);
755
756    /// Returns the handler registry based on the defined handlers for this component
757    fn build_component_handlers(
758        &self,
759        handlers: Vec<(String, Vec<String>)>,
760    ) -> Rc<RefCell<HandlerRegistry>>;
761
762    // Takes a handler registry and adds the given inline handlers to it
763    fn add_inline_handlers(
764        &self,
765        handlers: Vec<(String, String)>,
766        registry: Rc<RefCell<HandlerRegistry>>,
767    ) -> Rc<RefCell<HandlerRegistry>>;
768
769    // Calls the instantiation function for the component
770    fn build_component(&self, args: InstantiationArgs) -> Rc<dyn InstanceNode>;
771
772    // Returns the property scope for the component
773    fn get_properties_scope_factory(
774        &self,
775    ) -> Box<dyn Fn(Rc<RefCell<PaxAny>>) -> HashMap<String, Variable>> {
776        Box::new(|_| HashMap::new())
777    }
778}
779
780fn update_existing_common_properties(
781    expanded_node: &Rc<ExpandedNode>,
782    defined_properties: &BTreeMap<String, pax_manifest::ValueDefinition>,
783    stack_frame: &Rc<RuntimePropertiesStackFrame>,
784) {
785    let expanded_node = borrow!(**expanded_node);
786    let outer_ref = expanded_node.common_properties.borrow();
787    let rc = Rc::clone(&outer_ref);
788    let inner_ref = (*rc).borrow_mut();
789    let mut cp = inner_ref;
790
791    update_common_properties(&mut cp, defined_properties, stack_frame);
792}
793
794fn create_id_property(
795    defined_properties: &BTreeMap<String, pax_manifest::ValueDefinition>,
796) -> Property<Option<String>> {
797    let id = defined_properties.get("id");
798    Property::new(
799        if let Some(pax_manifest::ValueDefinition::Identifier(pax_identifier)) = id {
800            Some(pax_identifier.name.clone())
801        } else {
802            None
803        },
804    )
805}
806
807fn create_new_common_properties(
808    defined_properties: &BTreeMap<String, pax_manifest::ValueDefinition>,
809    stack_frame: &Rc<RuntimePropertiesStackFrame>,
810) -> Rc<RefCell<CommonProperties>> {
811    Rc::new(RefCell::new(CommonProperties {
812        id: create_id_property(defined_properties),
813        x: resolve_property("x", defined_properties, stack_frame),
814        y: resolve_property("y", defined_properties, stack_frame),
815        width: resolve_property("width", defined_properties, stack_frame),
816        height: resolve_property("height", defined_properties, stack_frame),
817        scale_x: resolve_property("scale_x", defined_properties, stack_frame),
818        scale_y: resolve_property("scale_y", defined_properties, stack_frame),
819        skew_x: resolve_property("skew_x", defined_properties, stack_frame),
820        skew_y: resolve_property("skew_y", defined_properties, stack_frame),
821        rotate: resolve_property("rotate", defined_properties, stack_frame),
822        transform: resolve_property("transform", defined_properties, stack_frame),
823        anchor_x: resolve_property("anchor_x", defined_properties, stack_frame),
824        anchor_y: resolve_property("anchor_y", defined_properties, stack_frame),
825        unclippable: resolve_property("unclippable", defined_properties, stack_frame),
826        _raycastable: resolve_property("_raycastable", defined_properties, stack_frame),
827        _suspended: resolve_property("_suspended", defined_properties, stack_frame),
828    }))
829}
830
831fn update_common_properties(
832    cp: &mut CommonProperties,
833    defined_properties: &BTreeMap<String, pax_manifest::ValueDefinition>,
834    stack_frame: &Rc<RuntimePropertiesStackFrame>,
835) {
836    cp.id.replace_with(create_id_property(defined_properties));
837    cp.x.replace_with(resolve_property("x", defined_properties, stack_frame));
838    cp.y.replace_with(resolve_property("y", defined_properties, stack_frame));
839    cp.width
840        .replace_with(resolve_property("width", defined_properties, stack_frame));
841    cp.height
842        .replace_with(resolve_property("height", defined_properties, stack_frame));
843    cp.scale_x
844        .replace_with(resolve_property("scale_x", defined_properties, stack_frame));
845    cp.scale_y
846        .replace_with(resolve_property("scale_y", defined_properties, stack_frame));
847    cp.skew_x
848        .replace_with(resolve_property("skew_x", defined_properties, stack_frame));
849    cp.skew_y
850        .replace_with(resolve_property("skew_y", defined_properties, stack_frame));
851    cp.rotate
852        .replace_with(resolve_property("rotate", defined_properties, stack_frame));
853    cp.transform.replace_with(resolve_property(
854        "transform",
855        defined_properties,
856        stack_frame,
857    ));
858    cp.anchor_x.replace_with(resolve_property(
859        "anchor_x",
860        defined_properties,
861        stack_frame,
862    ));
863    cp.anchor_y.replace_with(resolve_property(
864        "anchor_y",
865        defined_properties,
866        stack_frame,
867    ));
868    cp.unclippable.replace_with(resolve_property(
869        "unclippable",
870        defined_properties,
871        stack_frame,
872    ));
873    cp._raycastable.replace_with(resolve_property(
874        "_raycastable",
875        defined_properties,
876        stack_frame,
877    ));
878    cp._suspended.replace_with(resolve_property(
879        "_suspended",
880        defined_properties,
881        stack_frame,
882    ));
883}