diff --git a/ftd/src/executor/dummy.rs b/ftd/src/executor/dummy.rs index 399ca5d5e..5d3360f8a 100644 --- a/ftd/src/executor/dummy.rs +++ b/ftd/src/executor/dummy.rs @@ -57,6 +57,8 @@ impl DummyElement { inherited_variables: &mut ftd::VecMap<(String, Vec)>, found_elements: &mut std::collections::HashSet, ) -> ftd::executor::Result { + use ftd::executor::fastn_type_functions::ComponentExt; + if let Some(iteration) = instruction.iteration.take() { return Ok(ftd::executor::Element::IterativeElement( ftd::executor::IterativeElement { diff --git a/ftd/src/executor/element.rs b/ftd/src/executor/element.rs index 87db84431..65ab1c39c 100644 --- a/ftd/src/executor/element.rs +++ b/ftd/src/executor/element.rs @@ -283,7 +283,7 @@ impl ImageSrc { doc: &ftd::executor::TDoc, line_number: usize, ) -> ftd::executor::Result { - use ftd::executor::fastn_type_functions::PropertyValueExt as _; + use ftd::executor::fastn_type_functions::{PropertySourceExt, PropertyValueExt as _}; use ftd::interpreter::{PropertyValueExt, ValueExt}; let light = { @@ -388,7 +388,7 @@ impl RawImage { doc: &ftd::executor::TDoc, line_number: usize, ) -> ftd::executor::Result { - use ftd::executor::fastn_type_functions::PropertyValueExt as _; + use ftd::executor::fastn_type_functions::{PropertySourceExt, PropertyValueExt as _}; use ftd::interpreter::{PropertyValueExt, ValueExt}; let src = { diff --git a/ftd/src/executor/fastn_type_functions.rs b/ftd/src/executor/fastn_type_functions.rs index 9b5464a42..9df4c8f4f 100644 --- a/ftd/src/executor/fastn_type_functions.rs +++ b/ftd/src/executor/fastn_type_functions.rs @@ -12,3 +12,72 @@ impl PropertyValueExt for fastn_type::PropertyValue { } } } + +pub(crate) trait ComponentExt { + fn get_children( + &self, + doc: &ftd::interpreter::TDoc, + ) -> ftd::interpreter::Result>; + fn get_children_property(&self) -> Option; + fn get_children_properties(&self) -> Vec; + fn is_variable(&self) -> bool; +} + +impl ComponentExt for fastn_type::Component { + fn get_children( + &self, + doc: &ftd::interpreter::TDoc, + ) -> ftd::interpreter::Result> { + use ftd::interpreter::PropertyValueExt; + + let property = if let Some(property) = self.get_children_property() { + property + } else { + return Ok(vec![]); + }; + + let value = property.value.clone().resolve(doc, property.line_number)?; + if let fastn_type::Value::UI { component, .. } = value { + return Ok(vec![component]); + } + if let fastn_type::Value::List { data, kind } = value { + if kind.is_ui() { + let mut children = vec![]; + for value in data { + let value = value.resolve(doc, property.line_number)?; + if let fastn_type::Value::UI { component, .. } = value { + children.push(component); + } + } + return Ok(children); + } + } + + Ok(vec![]) + } + + fn get_children_property(&self) -> Option { + self.get_children_properties().first().map(|v| v.to_owned()) + } + + fn get_children_properties(&self) -> Vec { + ftd::interpreter::utils::get_children_properties_from_properties(&self.properties) + } + + fn is_variable(&self) -> bool { + self.source.eq(&fastn_type::ComponentSource::Variable) + } +} + +pub(crate) trait PropertySourceExt { + fn header(name: &str) -> fastn_type::PropertySource; +} + +impl PropertySourceExt for fastn_type::PropertySource { + fn header(name: &str) -> fastn_type::PropertySource { + fastn_type::PropertySource::Header { + name: name.to_string(), + mutable: false, + } + } +} diff --git a/ftd/src/executor/main.rs b/ftd/src/executor/main.rs index 1eaf9c67c..c5cb9c8c4 100644 --- a/ftd/src/executor/main.rs +++ b/ftd/src/executor/main.rs @@ -198,6 +198,8 @@ impl ExecuteDoc<'_> { start_index: usize, inherited_variables: &mut ftd::VecMap<(String, Vec)>, ) -> ftd::executor::Result, Vec, fastn_type::Component)>> { + use ftd::js::fastn_type_functions::ComponentExt; + if instruction.is_loop() { ExecuteDoc::get_loop_instructions( instruction, @@ -436,6 +438,7 @@ impl ExecuteDoc<'_> { instructions: &[fastn_type::Component], doc: &mut ftd::executor::TDoc, ) -> ftd::executor::Result> { + use ftd::executor::fastn_type_functions::ComponentExt; use ftd::interpreter::{PropertyValueExt, ValueExt}; let mut elements = vec![]; diff --git a/ftd/src/executor/styles.rs b/ftd/src/executor/styles.rs index 48b208028..560967a3a 100644 --- a/ftd/src/executor/styles.rs +++ b/ftd/src/executor/styles.rs @@ -458,8 +458,9 @@ impl BreakpointWidth { doc: &ftd::executor::TDoc, line_number: usize, ) -> ftd::executor::Result { - use ftd::executor::fastn_type_functions::PropertyValueExt as _; + use ftd::executor::fastn_type_functions::{PropertySourceExt, PropertyValueExt as _}; use ftd::interpreter::{PropertyValueExt, ValueExt}; + let get_property_value = |field_name: &str| { values .get(field_name) @@ -935,7 +936,7 @@ impl BackgroundImage { doc: &ftd::executor::TDoc, line_number: usize, ) -> ftd::executor::Result { - use ftd::executor::fastn_type_functions::PropertyValueExt; + use ftd::executor::fastn_type_functions::{PropertySourceExt, PropertyValueExt}; let get_property_value = |field_name: &str| { values @@ -1109,7 +1110,7 @@ impl LinearGradientColor { doc: &ftd::executor::TDoc, line_number: usize, ) -> ftd::executor::Result { - use ftd::executor::fastn_type_functions::PropertyValueExt; + use ftd::executor::fastn_type_functions::{PropertySourceExt, PropertyValueExt}; let get_property_value = |field_name: &str| { values @@ -1332,7 +1333,8 @@ impl LinearGradient { doc: &ftd::executor::TDoc, line_number: usize, ) -> ftd::executor::Result { - use ftd::executor::fastn_type_functions::PropertyValueExt; + use ftd::executor::fastn_type_functions::{PropertySourceExt, PropertyValueExt}; + let get_property_value = |field_name: &str| { values .get(field_name) @@ -1822,7 +1824,7 @@ impl Shadow { doc: &ftd::executor::TDoc, line_number: usize, ) -> ftd::executor::Result { - use ftd::executor::fastn_type_functions::PropertyValueExt as _; + use ftd::executor::fastn_type_functions::{PropertySourceExt, PropertyValueExt as _}; use ftd::interpreter::{PropertyValueExt, ValueExt}; let get_property_value = |field_name: &str| { @@ -1999,7 +2001,7 @@ impl Color { doc: &ftd::executor::TDoc, line_number: usize, ) -> ftd::executor::Result { - use ftd::executor::fastn_type_functions::PropertyValueExt as _; + use ftd::executor::fastn_type_functions::{PropertySourceExt, PropertyValueExt as _}; use ftd::interpreter::{PropertyValueExt, ValueExt}; let light = { diff --git a/ftd/src/executor/tdoc.rs b/ftd/src/executor/tdoc.rs index 4309f2271..c98b78764 100644 --- a/ftd/src/executor/tdoc.rs +++ b/ftd/src/executor/tdoc.rs @@ -125,6 +125,8 @@ impl TDoc<'_> { inherited_variables: &mut ftd::VecMap<(String, Vec)>, insert_null: bool, ) -> ftd::executor::Result)>> { + use ftd::interpreter::PropertyExt; + let string_container = ftd::executor::utils::get_string_container(container); let source = argument.to_sources(); let properties = ftd::interpreter::utils::find_properties_by_source( diff --git a/ftd/src/executor/utils.rs b/ftd/src/executor/utils.rs index fae906d1b..11c70f2b7 100644 --- a/ftd/src/executor/utils.rs +++ b/ftd/src/executor/utils.rs @@ -175,6 +175,8 @@ pub(crate) fn update_local_variable_references_in_component_( doc: &mut ftd::executor::TDoc, is_children: bool, ) { + use ftd::executor::fastn_type_functions::ComponentExt; + if component.is_variable() { let mut component_name = fastn_type::PropertyValue::Reference { name: component.name.to_string(), diff --git a/ftd/src/executor/value.rs b/ftd/src/executor/value.rs index 3c736363f..00358b6e1 100644 --- a/ftd/src/executor/value.rs +++ b/ftd/src/executor/value.rs @@ -114,6 +114,8 @@ pub(crate) fn find_value_by_argument( is_dummy: bool, inherited_variables: &ftd::VecMap<(String, Vec)>, ) -> ftd::executor::Result>> { + use ftd::interpreter::PropertyExt; + let properties = { let new_properties = ftd::interpreter::utils::find_properties_by_source( source, diff --git a/ftd/src/interpreter/fastn_type_functions.rs b/ftd/src/interpreter/fastn_type_functions.rs index 784317713..dbbbebd67 100644 --- a/ftd/src/interpreter/fastn_type_functions.rs +++ b/ftd/src/interpreter/fastn_type_functions.rs @@ -2121,6 +2121,33 @@ impl FunctionCallExt for fastn_type::FunctionCall { } } +pub(crate) trait PropertyExt { + fn resolve( + &self, + doc: &ftd::interpreter::TDoc, + inherited_variables: &ftd::VecMap<(String, Vec)>, + ) -> ftd::interpreter::Result>; +} + +impl PropertyExt for fastn_type::Property { + fn resolve( + &self, + doc: &ftd::interpreter::TDoc, + inherited_variables: &ftd::VecMap<(String, Vec)>, + ) -> ftd::interpreter::Result> { + use ftd::interpreter::PropertyValueExt; + + Ok(match self.condition { + Some(ref condition) if !condition.eval(doc)? => None, + _ => Some(self.value.clone().resolve_with_inherited( + doc, + self.line_number, + inherited_variables, + )?), + }) + } +} + pub fn check_for_caption_and_body(s: &mut String) -> (bool, bool) { use itertools::Itertools; diff --git a/ftd/src/interpreter/mod.rs b/ftd/src/interpreter/mod.rs index 5bea1b501..b99e5124b 100644 --- a/ftd/src/interpreter/mod.rs +++ b/ftd/src/interpreter/mod.rs @@ -43,7 +43,7 @@ pub use prelude::*; pub use fastn_type_functions::KindDataExt; pub(crate) use fastn_type_functions::{ - FunctionCallExt, PropertyValueExt, PropertyValueSourceExt, ValueExt, + FunctionCallExt, PropertyExt, PropertyValueExt, PropertyValueSourceExt, ValueExt, }; pub use tdoc::{BagOrState, TDoc}; pub use things::expression; diff --git a/ftd/src/interpreter/things/component.rs b/ftd/src/interpreter/things/component.rs index 48b58568c..660dd62fd 100644 --- a/ftd/src/interpreter/things/component.rs +++ b/ftd/src/interpreter/things/component.rs @@ -2,7 +2,7 @@ pub struct ComponentDefinition { pub name: String, pub arguments: Vec, - pub definition: Component, + pub definition: fastn_type::Component, pub css: Option, pub line_number: usize, } @@ -639,23 +639,6 @@ pub struct Property { } impl Property { - pub(crate) fn resolve( - &self, - doc: &ftd::interpreter::TDoc, - inherited_variables: &ftd::VecMap<(String, Vec)>, - ) -> ftd::interpreter::Result> { - use ftd::interpreter::PropertyValueExt; - - Ok(match self.condition { - Some(ref condition) if !condition.eval(doc)? => None, - _ => Some(self.value.clone().resolve_with_inherited( - doc, - self.line_number, - inherited_variables, - )?), - }) - } - fn from_ast_properties_and_children( ast_properties: Vec, ast_children: Vec, @@ -1311,7 +1294,7 @@ fn get_module_name_and_thing( definition_name_with_arguments: &mut Option<(&str, &mut [Argument])>, component_argument: &ftd::interpreter::Argument, ) -> ftd::interpreter::Result<(String, ftd::Map)> { - use ftd::interpreter::PropertyValueExt; + use ftd::interpreter::{PropertyExt, PropertyValueExt}; let default_things = { let value = if let Some(ref value) = component_argument.value { diff --git a/ftd/src/js/element.rs b/ftd/src/js/element.rs index 7259f318b..5b27d1bc8 100644 --- a/ftd/src/js/element.rs +++ b/ftd/src/js/element.rs @@ -2642,6 +2642,8 @@ impl Common { doc: &ftd::interpreter::TDoc, rdata: &ftd::js::ResolverData, ) -> Vec { + use ftd::js::fastn_type_functions::EventExt; + let mut component_statements = vec![]; for event in self.events.iter() { if let Some(event_handler) = event.to_event_handler_js(element_name, doc, rdata) { @@ -3279,51 +3281,6 @@ impl Common { } } -impl fastn_type::Event { - pub(crate) fn to_event_handler_js( - &self, - element_name: &str, - doc: &ftd::interpreter::TDoc, - rdata: &ftd::js::ResolverData, - ) -> Option { - use ftd::js::fastn_type_functions::FunctionCallExt; - - self.name - .to_js_event_name() - .map(|event| fastn_js::EventHandler { - event, - action: self.action.to_js_function(doc, rdata), - element_name: element_name.to_string(), - }) - } -} - -impl fastn_type::EventName { - fn to_js_event_name(&self) -> Option { - use itertools::Itertools; - - match self { - fastn_type::EventName::Click => Some(fastn_js::Event::Click), - fastn_type::EventName::MouseEnter => Some(fastn_js::Event::MouseEnter), - fastn_type::EventName::MouseLeave => Some(fastn_js::Event::MouseLeave), - fastn_type::EventName::ClickOutside => Some(fastn_js::Event::ClickOutside), - fastn_type::EventName::GlobalKey(gk) => Some(fastn_js::Event::GlobalKey( - gk.iter().map(|v| ftd::js::utils::to_key(v)).collect_vec(), - )), - fastn_type::EventName::GlobalKeySeq(gk) => Some(fastn_js::Event::GlobalKeySeq( - gk.iter().map(|v| ftd::js::utils::to_key(v)).collect_vec(), - )), - fastn_type::EventName::Input => Some(fastn_js::Event::Input), - fastn_type::EventName::Change => Some(fastn_js::Event::Change), - fastn_type::EventName::Blur => Some(fastn_js::Event::Blur), - fastn_type::EventName::Focus => Some(fastn_js::Event::Focus), - fastn_type::EventName::RivePlay(_) - | fastn_type::EventName::RivePause(_) - | fastn_type::EventName::RiveStateChange(_) => None, - } - } -} - pub fn is_kernel(s: &str) -> bool { [ "ftd#text", diff --git a/ftd/src/js/fastn_type_functions.rs b/ftd/src/js/fastn_type_functions.rs index ba100baa0..a84d10d11 100644 --- a/ftd/src/js/fastn_type_functions.rs +++ b/ftd/src/js/fastn_type_functions.rs @@ -1,5 +1,3 @@ -use crate::js::value::ReferenceData; - pub(crate) trait FunctionCallExt { fn to_js_function( &self, @@ -128,7 +126,7 @@ impl PropertyValueExt for fastn_type::PropertyValue { ftd::js::Value::Data(value.to_owned()) } fastn_type::PropertyValue::Reference { ref name, .. } => { - ftd::js::Value::Reference(ReferenceData { + ftd::js::Value::Reference(ftd::js::value::ReferenceData { name: name.clone().to_string(), value: Some(self.clone()), }) @@ -284,3 +282,504 @@ impl ValueExt for fastn_type::Value { } } } + +pub(crate) trait EventExt { + fn to_event_handler_js( + &self, + element_name: &str, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + ) -> Option; +} + +impl EventExt for fastn_type::Event { + fn to_event_handler_js( + &self, + element_name: &str, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + ) -> Option { + use ftd::js::fastn_type_functions::FunctionCallExt; + + self.name + .to_js_event_name() + .map(|event| fastn_js::EventHandler { + event, + action: self.action.to_js_function(doc, rdata), + element_name: element_name.to_string(), + }) + } +} + +pub(crate) trait EventNameExt { + fn to_js_event_name(&self) -> Option; +} + +impl EventNameExt for fastn_type::EventName { + fn to_js_event_name(&self) -> Option { + use itertools::Itertools; + + match self { + fastn_type::EventName::Click => Some(fastn_js::Event::Click), + fastn_type::EventName::MouseEnter => Some(fastn_js::Event::MouseEnter), + fastn_type::EventName::MouseLeave => Some(fastn_js::Event::MouseLeave), + fastn_type::EventName::ClickOutside => Some(fastn_js::Event::ClickOutside), + fastn_type::EventName::GlobalKey(gk) => Some(fastn_js::Event::GlobalKey( + gk.iter().map(|v| ftd::js::utils::to_key(v)).collect_vec(), + )), + fastn_type::EventName::GlobalKeySeq(gk) => Some(fastn_js::Event::GlobalKeySeq( + gk.iter().map(|v| ftd::js::utils::to_key(v)).collect_vec(), + )), + fastn_type::EventName::Input => Some(fastn_js::Event::Input), + fastn_type::EventName::Change => Some(fastn_js::Event::Change), + fastn_type::EventName::Blur => Some(fastn_js::Event::Blur), + fastn_type::EventName::Focus => Some(fastn_js::Event::Focus), + fastn_type::EventName::RivePlay(_) + | fastn_type::EventName::RivePause(_) + | fastn_type::EventName::RiveStateChange(_) => None, + } + } +} + +pub(crate) trait ComponentExt { + fn to_component_statements( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Vec; + fn to_component_statements_( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Vec; + fn kernel_to_component_statements( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Option>; + fn defined_component_to_component_statements( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Option>; + fn header_defined_component_to_component_statements( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Option>; + fn variable_defined_component_to_component_statements( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Option>; + fn is_loop(&self) -> bool; +} + +impl ComponentExt for fastn_type::Component { + fn to_component_statements( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Vec { + use ftd::js::fastn_type_functions::PropertyValueExt; + use itertools::Itertools; + + let loop_alias = self.iteration.clone().map(|v| v.alias); + let loop_counter_alias = self.iteration.clone().and_then(|v| { + if let Some(ref loop_counter_alias) = v.loop_counter_alias { + let (_, loop_counter_alias, _remaining) = + ftd::interpreter::utils::get_doc_name_and_thing_name_and_remaining( + loop_counter_alias.as_str(), + doc.name, + v.line_number, + ); + return Some(loop_counter_alias); + } + None + }); + let mut component_statements = if self.is_loop() || self.condition.is_some() { + self.to_component_statements_( + fastn_js::FUNCTION_PARENT, + 0, + doc, + &rdata.clone_with_new_loop_alias( + &loop_alias, + &loop_counter_alias, + doc.name.to_string(), + ), + true, + has_rive_components, + ) + } else { + self.to_component_statements_( + parent, + index, + doc, + &rdata.clone_with_new_loop_alias(&None, &None, doc.name.to_string()), + should_return, + has_rive_components, + ) + }; + + if let Some(condition) = self.condition.as_ref() { + component_statements = vec![fastn_js::ComponentStatement::ConditionalComponent( + fastn_js::ConditionalComponent { + deps: condition + .references + .values() + .flat_map(|v| { + v.get_deps(&rdata.clone_with_new_loop_alias( + &loop_alias, + &loop_counter_alias, + doc.name.to_string(), + )) + }) + .collect_vec(), + condition: condition.update_node_with_variable_reference_js( + &rdata.clone_with_new_loop_alias( + &loop_alias, + &loop_counter_alias, + doc.name.to_string(), + ), + ), + statements: component_statements, + parent: parent.to_string(), + should_return: self.is_loop() || should_return, + }, + )]; + } + + if let Some(iteration) = self.iteration.as_ref() { + component_statements = vec![fastn_js::ComponentStatement::ForLoop(fastn_js::ForLoop { + list_variable: iteration.on.to_fastn_js_value( + doc, + &rdata.clone_with_new_loop_alias( + &loop_alias, + &loop_counter_alias, + doc.name.to_string(), + ), + false, + ), + statements: component_statements, + parent: parent.to_string(), + should_return, + })]; + } + + component_statements + } + + fn to_component_statements_( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Vec { + if let Some(kernel_component_statements) = self.kernel_to_component_statements( + parent, + index, + doc, + rdata, + should_return, + has_rive_components, + ) { + kernel_component_statements + } else if let Some(defined_component_statements) = self + .defined_component_to_component_statements( + parent, + index, + doc, + rdata, + should_return, + has_rive_components, + ) + { + defined_component_statements + } else if let Some(header_defined_component_statements) = self + .header_defined_component_to_component_statements( + parent, + index, + doc, + rdata, + should_return, + has_rive_components, + ) + { + header_defined_component_statements + } else if let Some(variable_defined_component_to_component_statements) = self + .variable_defined_component_to_component_statements( + parent, + index, + doc, + rdata, + should_return, + has_rive_components, + ) + { + variable_defined_component_to_component_statements + } else { + panic!("Can't find, {}", self.name) + } + } + + fn kernel_to_component_statements( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Option> { + if ftd::js::element::is_kernel(self.name.as_str()) { + if !*has_rive_components { + *has_rive_components = ftd::js::element::is_rive_component(self.name.as_str()); + } + Some( + ftd::js::Element::from_interpreter_component(self, doc).to_component_statements( + parent, + index, + doc, + rdata, + should_return, + has_rive_components, + ), + ) + } else { + None + } + } + + fn defined_component_to_component_statements( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Option> { + if let Some(arguments) = + ftd::js::utils::get_set_property_values_for_provided_component_properties( + doc, + rdata, + self.name.as_str(), + self.properties.as_slice(), + self.line_number, + has_rive_components, + ) + { + let mut component_statements = vec![]; + let instantiate_component = fastn_js::InstantiateComponent::new( + self.name.as_str(), + arguments, + parent, + rdata.inherited_variable_name, + index, + false, + ); + + let instantiate_component_var_name = instantiate_component.var_name.clone(); + + component_statements.push(fastn_js::ComponentStatement::InstantiateComponent( + instantiate_component, + )); + + component_statements.extend(self.events.iter().filter_map(|event| { + event + .to_event_handler_js(instantiate_component_var_name.as_str(), doc, rdata) + .map(|event_handler| { + fastn_js::ComponentStatement::AddEventHandler(event_handler) + }) + })); + + if should_return { + component_statements.push(fastn_js::ComponentStatement::Return { + component_name: instantiate_component_var_name.to_string(), + }); + } + + Some(component_statements) + } else { + None + } + } + + // ftd.ui type header + fn header_defined_component_to_component_statements( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Option> { + let (component_name, remaining) = ftd::interpreter::utils::get_doc_name_and_remaining( + self.name.as_str(), + doc.name, + self.line_number, + ); + + let remaining = remaining?; + + match rdata.component_definition_name { + Some(ref component_definition_name) if component_name.eq(component_definition_name) => { + } + _ => return None, + } + + let component = doc + .get_component(component_name.as_str(), self.line_number) + .ok()?; + + let mut arguments = vec![]; + + if let Some(component_name) = + ftd::js::utils::is_module_argument(component.arguments.as_slice(), remaining.as_str()) + { + arguments = ftd::js::utils::get_set_property_values_for_provided_component_properties( + doc, + rdata, + component_name.as_str(), + self.properties.as_slice(), + self.line_number, + has_rive_components, + )?; + } else if !ftd::js::utils::is_ui_argument( + component.arguments.as_slice(), + remaining.as_str(), + ) { + return None; + } + + let value = ftd::js::Value::Reference(ftd::js::value::ReferenceData { + name: self.name.to_owned(), + value: None, + }) + .to_set_property_value_with_ui(doc, rdata, has_rive_components, should_return); + let instantiate_component = fastn_js::InstantiateComponent::new_with_definition( + value, + arguments, + parent, + rdata.inherited_variable_name, + index, + true, + ); + + let mut component_statements = vec![]; + let instantiate_component_var_name = instantiate_component.var_name.clone(); + + component_statements.push(fastn_js::ComponentStatement::InstantiateComponent( + instantiate_component, + )); + + component_statements.extend(self.events.iter().filter_map(|event| { + event + .to_event_handler_js(&instantiate_component_var_name, doc, rdata) + .map(fastn_js::ComponentStatement::AddEventHandler) + })); + + if should_return { + component_statements.push(fastn_js::ComponentStatement::Return { + component_name: instantiate_component_var_name.to_string(), + }); + } + + Some(component_statements) + } + + fn variable_defined_component_to_component_statements( + &self, + parent: &str, + index: usize, + doc: &ftd::interpreter::TDoc, + rdata: &ftd::js::ResolverData, + should_return: bool, + has_rive_components: &mut bool, + ) -> Option> { + /* + Todo: Check if the `self.name` is a loop-alias of `ftd.ui list` variable and then + uncomment the bellow code which checks for `self.name` as variable of `ftd.ui` type + if !doc + .get_variable(self.name.as_str(), self.line_number) + .ok()? + .kind + .is_ui() + { + return None; + }*/ + + // The reference `self.name` is either the ftd.ui type variable or the loop-alias + let value = ftd::js::Value::Reference(ftd::js::value::ReferenceData { + name: self.name.to_owned(), + value: None, + }) + .to_set_property_value_with_ui(doc, rdata, has_rive_components, should_return); + + let instantiate_component = fastn_js::InstantiateComponent::new_with_definition( + value, + vec![], + parent, + rdata.inherited_variable_name, + index, + true, + ); + + let mut component_statements = vec![]; + let instantiate_component_var_name = instantiate_component.var_name.clone(); + + component_statements.push(fastn_js::ComponentStatement::InstantiateComponent( + instantiate_component, + )); + + component_statements.extend(self.events.iter().filter_map(|event| { + event + .to_event_handler_js(&instantiate_component_var_name, doc, rdata) + .map(fastn_js::ComponentStatement::AddEventHandler) + })); + + if should_return { + component_statements.push(fastn_js::ComponentStatement::Return { + component_name: instantiate_component_var_name.to_string(), + }); + } + + Some(component_statements) + } + + fn is_loop(&self) -> bool { + self.iteration.is_some() + } +} diff --git a/ftd/src/js/mod.rs b/ftd/src/js/mod.rs index a8058eb74..76458398b 100644 --- a/ftd/src/js/mod.rs +++ b/ftd/src/js/mod.rs @@ -271,6 +271,7 @@ impl ftd::interpreter::ComponentDefinition { doc: &ftd::interpreter::TDoc, has_rive_components: &mut bool, ) -> fastn_js::Ast { + use ftd::js::fastn_type_functions::ComponentExt; use itertools::Itertools; let mut statements = vec![]; @@ -315,6 +316,8 @@ pub fn from_tree( doc: &ftd::interpreter::TDoc, has_rive_components: &mut bool, ) -> fastn_js::Ast { + use ftd::js::fastn_type_functions::ComponentExt; + let mut statements = vec![]; for (index, component) in tree.iter().enumerate() { statements.extend(component.to_component_statements( @@ -329,387 +332,6 @@ pub fn from_tree( fastn_js::component0(fastn_js::MAIN_FUNCTION, statements) } -impl fastn_type::Component { - pub fn to_component_statements( - &self, - parent: &str, - index: usize, - doc: &ftd::interpreter::TDoc, - rdata: &ftd::js::ResolverData, - should_return: bool, - has_rive_components: &mut bool, - ) -> Vec { - use ftd::js::fastn_type_functions::PropertyValueExt; - use itertools::Itertools; - - let loop_alias = self.iteration.clone().map(|v| v.alias); - let loop_counter_alias = self.iteration.clone().and_then(|v| { - if let Some(ref loop_counter_alias) = v.loop_counter_alias { - let (_, loop_counter_alias, _remaining) = - ftd::interpreter::utils::get_doc_name_and_thing_name_and_remaining( - loop_counter_alias.as_str(), - doc.name, - v.line_number, - ); - return Some(loop_counter_alias); - } - None - }); - let mut component_statements = if self.is_loop() || self.condition.is_some() { - self.to_component_statements_( - fastn_js::FUNCTION_PARENT, - 0, - doc, - &rdata.clone_with_new_loop_alias( - &loop_alias, - &loop_counter_alias, - doc.name.to_string(), - ), - true, - has_rive_components, - ) - } else { - self.to_component_statements_( - parent, - index, - doc, - &rdata.clone_with_new_loop_alias(&None, &None, doc.name.to_string()), - should_return, - has_rive_components, - ) - }; - - if let Some(condition) = self.condition.as_ref() { - component_statements = vec![fastn_js::ComponentStatement::ConditionalComponent( - fastn_js::ConditionalComponent { - deps: condition - .references - .values() - .flat_map(|v| { - v.get_deps(&rdata.clone_with_new_loop_alias( - &loop_alias, - &loop_counter_alias, - doc.name.to_string(), - )) - }) - .collect_vec(), - condition: condition.update_node_with_variable_reference_js( - &rdata.clone_with_new_loop_alias( - &loop_alias, - &loop_counter_alias, - doc.name.to_string(), - ), - ), - statements: component_statements, - parent: parent.to_string(), - should_return: self.is_loop() || should_return, - }, - )]; - } - - if let Some(iteration) = self.iteration.as_ref() { - component_statements = vec![fastn_js::ComponentStatement::ForLoop(fastn_js::ForLoop { - list_variable: iteration.on.to_fastn_js_value( - doc, - &rdata.clone_with_new_loop_alias( - &loop_alias, - &loop_counter_alias, - doc.name.to_string(), - ), - false, - ), - statements: component_statements, - parent: parent.to_string(), - should_return, - })]; - } - - component_statements - } - - fn to_component_statements_( - &self, - parent: &str, - index: usize, - doc: &ftd::interpreter::TDoc, - rdata: &ftd::js::ResolverData, - should_return: bool, - has_rive_components: &mut bool, - ) -> Vec { - if let Some(kernel_component_statements) = self.kernel_to_component_statements( - parent, - index, - doc, - rdata, - should_return, - has_rive_components, - ) { - kernel_component_statements - } else if let Some(defined_component_statements) = self - .defined_component_to_component_statements( - parent, - index, - doc, - rdata, - should_return, - has_rive_components, - ) - { - defined_component_statements - } else if let Some(header_defined_component_statements) = self - .header_defined_component_to_component_statements( - parent, - index, - doc, - rdata, - should_return, - has_rive_components, - ) - { - header_defined_component_statements - } else if let Some(variable_defined_component_to_component_statements) = self - .variable_defined_component_to_component_statements( - parent, - index, - doc, - rdata, - should_return, - has_rive_components, - ) - { - variable_defined_component_to_component_statements - } else { - panic!("Can't find, {}", self.name) - } - } - - fn kernel_to_component_statements( - &self, - parent: &str, - index: usize, - doc: &ftd::interpreter::TDoc, - rdata: &ftd::js::ResolverData, - should_return: bool, - has_rive_components: &mut bool, - ) -> Option> { - if ftd::js::element::is_kernel(self.name.as_str()) { - if !*has_rive_components { - *has_rive_components = ftd::js::element::is_rive_component(self.name.as_str()); - } - Some( - ftd::js::Element::from_interpreter_component(self, doc).to_component_statements( - parent, - index, - doc, - rdata, - should_return, - has_rive_components, - ), - ) - } else { - None - } - } - - fn defined_component_to_component_statements( - &self, - parent: &str, - index: usize, - doc: &ftd::interpreter::TDoc, - rdata: &ftd::js::ResolverData, - should_return: bool, - has_rive_components: &mut bool, - ) -> Option> { - if let Some(arguments) = - ftd::js::utils::get_set_property_values_for_provided_component_properties( - doc, - rdata, - self.name.as_str(), - self.properties.as_slice(), - self.line_number, - has_rive_components, - ) - { - let mut component_statements = vec![]; - let instantiate_component = fastn_js::InstantiateComponent::new( - self.name.as_str(), - arguments, - parent, - rdata.inherited_variable_name, - index, - false, - ); - - let instantiate_component_var_name = instantiate_component.var_name.clone(); - - component_statements.push(fastn_js::ComponentStatement::InstantiateComponent( - instantiate_component, - )); - - component_statements.extend(self.events.iter().filter_map(|event| { - event - .to_event_handler_js(instantiate_component_var_name.as_str(), doc, rdata) - .map(|event_handler| { - fastn_js::ComponentStatement::AddEventHandler(event_handler) - }) - })); - - if should_return { - component_statements.push(fastn_js::ComponentStatement::Return { - component_name: instantiate_component_var_name.to_string(), - }); - } - - Some(component_statements) - } else { - None - } - } - - // ftd.ui type header - fn header_defined_component_to_component_statements( - &self, - parent: &str, - index: usize, - doc: &ftd::interpreter::TDoc, - rdata: &ftd::js::ResolverData, - should_return: bool, - has_rive_components: &mut bool, - ) -> Option> { - let (component_name, remaining) = ftd::interpreter::utils::get_doc_name_and_remaining( - self.name.as_str(), - doc.name, - self.line_number, - ); - - let remaining = remaining?; - - match rdata.component_definition_name { - Some(ref component_definition_name) if component_name.eq(component_definition_name) => { - } - _ => return None, - } - - let component = doc - .get_component(component_name.as_str(), self.line_number) - .ok()?; - - let mut arguments = vec![]; - - if let Some(component_name) = - ftd::js::utils::is_module_argument(component.arguments.as_slice(), remaining.as_str()) - { - arguments = ftd::js::utils::get_set_property_values_for_provided_component_properties( - doc, - rdata, - component_name.as_str(), - self.properties.as_slice(), - self.line_number, - has_rive_components, - )?; - } else if !ftd::js::utils::is_ui_argument( - component.arguments.as_slice(), - remaining.as_str(), - ) { - return None; - } - - let value = ftd::js::Value::Reference(value::ReferenceData { - name: self.name.to_owned(), - value: None, - }) - .to_set_property_value_with_ui(doc, rdata, has_rive_components, should_return); - let instantiate_component = fastn_js::InstantiateComponent::new_with_definition( - value, - arguments, - parent, - rdata.inherited_variable_name, - index, - true, - ); - - let mut component_statements = vec![]; - let instantiate_component_var_name = instantiate_component.var_name.clone(); - - component_statements.push(fastn_js::ComponentStatement::InstantiateComponent( - instantiate_component, - )); - - component_statements.extend(self.events.iter().filter_map(|event| { - event - .to_event_handler_js(&instantiate_component_var_name, doc, rdata) - .map(fastn_js::ComponentStatement::AddEventHandler) - })); - - if should_return { - component_statements.push(fastn_js::ComponentStatement::Return { - component_name: instantiate_component_var_name.to_string(), - }); - } - - Some(component_statements) - } - - fn variable_defined_component_to_component_statements( - &self, - parent: &str, - index: usize, - doc: &ftd::interpreter::TDoc, - rdata: &ftd::js::ResolverData, - should_return: bool, - has_rive_components: &mut bool, - ) -> Option> { - /* - Todo: Check if the `self.name` is a loop-alias of `ftd.ui list` variable and then - uncomment the bellow code which checks for `self.name` as variable of `ftd.ui` type - if !doc - .get_variable(self.name.as_str(), self.line_number) - .ok()? - .kind - .is_ui() - { - return None; - }*/ - - // The reference `self.name` is either the ftd.ui type variable or the loop-alias - let value = ftd::js::Value::Reference(value::ReferenceData { - name: self.name.to_owned(), - value: None, - }) - .to_set_property_value_with_ui(doc, rdata, has_rive_components, should_return); - - let instantiate_component = fastn_js::InstantiateComponent::new_with_definition( - value, - vec![], - parent, - rdata.inherited_variable_name, - index, - true, - ); - - let mut component_statements = vec![]; - let instantiate_component_var_name = instantiate_component.var_name.clone(); - - component_statements.push(fastn_js::ComponentStatement::InstantiateComponent( - instantiate_component, - )); - - component_statements.extend(self.events.iter().filter_map(|event| { - event - .to_event_handler_js(&instantiate_component_var_name, doc, rdata) - .map(fastn_js::ComponentStatement::AddEventHandler) - })); - - if should_return { - component_statements.push(fastn_js::ComponentStatement::Return { - component_name: instantiate_component_var_name.to_string(), - }); - } - - Some(component_statements) - } -} - impl ftd::interpreter::WebComponentDefinition { pub fn to_ast(&self, doc: &ftd::interpreter::TDoc) -> fastn_js::Ast { use itertools::Itertools;