diff --git a/packages/rsx_interpreter/src/attributes.rs b/packages/rsx_interpreter/src/attributes.rs index f8d19fddb..77daa243a 100644 --- a/packages/rsx_interpreter/src/attributes.rs +++ b/packages/rsx_interpreter/src/attributes.rs @@ -1,49 +1,62 @@ use crate::elements::*; // map the rsx name of the attribute to the html name of the attribute and the namespace that contains it -pub fn attrbute_to_static_str(attr: &str) -> Option<(&'static str, Option<&'static str>)> { - NO_NAMESPACE_ATTRIBUTES - .iter() - .find(|&a| *a == attr) - .map(|a| (*a, None)) - .or_else(|| { - STYLE_ATTRIBUTES - .iter() - .find(|(a, _)| *a == attr) - .map(|(_, b)| (*b, Some("style"))) +pub fn attrbute_to_static_str( + attr: &str, + element: &'static str, + namespace: Option<&'static str>, +) -> Option<(&'static str, Option<&'static str>)> { + if namespace == Some("http://www.w3.org/2000/svg") { + svg::MAPPED_ATTRIBUTES + .iter() + .find(|(a, _)| *a == attr) + .map(|(_, b)| (*b, None)) + } else { + NO_NAMESPACE_ATTRIBUTES + .iter() + .find(|&a| *a == attr) + .map(|a| (*a, None)) + .or_else(|| { + STYLE_ATTRIBUTES + .iter() + .find(|(a, _)| *a == attr) + .map(|(_, b)| (*b, Some("style"))) + }) + .or_else(|| { + MAPPED_ATTRIBUTES + .iter() + .find(|(a, _)| *a == attr) + .map(|(_, b)| (*b, None)) + }) + } + .or_else(|| { + ELEMENTS_WITH_MAPPED_ATTRIBUTES + .iter() + .find_map(|(el, attrs)| { + (element == *el) + .then(|| { + attrs + .iter() + .find(|(a, _)| *a == attr) + .map(|(_, b)| (*b, None)) + }) + .flatten() + }) + }) + .or_else(|| { + ELEMENTS_WITH_NAMESPACE.iter().find_map(|(el, ns, attrs)| { + (element == *el && namespace == Some(*ns)) + .then(|| attrs.iter().find(|a| **a == attr).map(|a| (*a, None))) + .flatten() }) - .or_else(|| { - MAPPED_ATTRIBUTES - .iter() - .find(|(a, _)| *a == attr) - .map(|(_, b)| (*b, None)) - }) - .or_else(|| { - svg::MAPPED_ATTRIBUTES - .iter() - .find(|(a, _)| *a == attr) - .map(|(_, b)| (*b, None)) - }) - .or_else(|| { - ELEMENTS_WITH_MAPPED_ATTRIBUTES - .iter() - .find_map(|(_, attrs)| { - attrs - .iter() - .find(|(a, _)| *a == attr) - .map(|(_, b)| (*b, None)) - }) - }) - .or_else(|| { - ELEMENTS_WITH_NAMESPACE - .iter() - .find_map(|(_, _, attrs)| attrs.iter().find(|a| **a == attr).map(|a| (*a, None))) - }) - .or_else(|| { - ELEMENTS_WITHOUT_NAMESPACE - .iter() - .find_map(|(_, attrs)| attrs.iter().find(|a| **a == attr).map(|a| (*a, None))) + }) + .or_else(|| { + ELEMENTS_WITHOUT_NAMESPACE.iter().find_map(|(el, attrs)| { + (element == *el) + .then(|| attrs.iter().find(|a| **a == attr).map(|a| (*a, None))) + .flatten() }) + }) } macro_rules! no_namespace_trait_methods { @@ -615,6 +628,7 @@ mapped_trait_methods! { } pub mod svg { + mapped_trait_methods! { accent_height: "accent-height", accumulate: "accumulate", diff --git a/packages/rsx_interpreter/src/captuered_context.rs b/packages/rsx_interpreter/src/captuered_context.rs index b3ee7636d..e05957787 100644 --- a/packages/rsx_interpreter/src/captuered_context.rs +++ b/packages/rsx_interpreter/src/captuered_context.rs @@ -182,9 +182,11 @@ impl<'a> CapturedContext<'a> { pub fn attrbute_to_static_str( &self, attr: &str, + tag: &'static str, + ns: Option<&'static str>, literal: bool, ) -> Option<(&'static str, Option<&'static str>)> { - if let Some(attr) = attrbute_to_static_str(attr) { + if let Some(attr) = attrbute_to_static_str(attr, tag, ns) { Some(attr) } else if literal { self.custom_attributes diff --git a/packages/rsx_interpreter/src/elements.rs b/packages/rsx_interpreter/src/elements.rs index 0668f57ff..b868b3537 100644 --- a/packages/rsx_interpreter/src/elements.rs +++ b/packages/rsx_interpreter/src/elements.rs @@ -54,7 +54,7 @@ macro_rules! builder_constructors { $( ( stringify!($name), - stringify!($namespace), + $namespace, &[ $( stringify!($fil), diff --git a/packages/rsx_interpreter/src/interperter.rs b/packages/rsx_interpreter/src/interperter.rs index 73dd1ebdb..e143fa907 100644 --- a/packages/rsx_interpreter/src/interperter.rs +++ b/packages/rsx_interpreter/src/interperter.rs @@ -76,81 +76,42 @@ fn build_node<'a>( } BodyNode::Element(el) => { let attributes: &mut Vec = bump.alloc(Vec::new()); - for attr in &el.attributes { - match &attr.attr { - ElementAttr::AttrText { .. } | ElementAttr::CustomAttrText { .. } => { - let (name, value, span, literal): (String, IfmtInput, Span, bool) = - match &attr.attr { - ElementAttr::AttrText { name, value } => ( - name.to_string(), - IfmtInput::from_str(&value.value()).map_err(|err| { - Error::ParseError(ParseError::new( - err, - ctx.location.clone(), - )) - })?, - name.span(), - false, - ), - ElementAttr::CustomAttrText { name, value } => ( - name.value(), - IfmtInput::from_str(&value.value()).map_err(|err| { - Error::ParseError(ParseError::new( - err, - ctx.location.clone(), - )) - })?, - name.span(), - true, - ), - _ => unreachable!(), - }; + let tag = &el.name.to_string(); + if let Some((tag, ns)) = element_to_static_str(tag) { + for attr in &el.attributes { + match &attr.attr { + ElementAttr::AttrText { .. } | ElementAttr::CustomAttrText { .. } => { + let (name, value, span, literal): (String, IfmtInput, Span, bool) = + match &attr.attr { + ElementAttr::AttrText { name, value } => ( + name.to_string(), + IfmtInput::from_str(&value.value()).map_err(|err| { + Error::ParseError(ParseError::new( + err, + ctx.location.clone(), + )) + })?, + name.span(), + false, + ), + ElementAttr::CustomAttrText { name, value } => ( + name.value(), + IfmtInput::from_str(&value.value()).map_err(|err| { + Error::ParseError(ParseError::new( + err, + ctx.location.clone(), + )) + })?, + name.span(), + true, + ), + _ => unreachable!(), + }; - if let Some((name, namespace)) = ctx.attrbute_to_static_str(&name, literal) - { - let value = bump.alloc(resolve_ifmt(&value, &ctx.captured)?); - attributes.push(Attribute { - name, - value: AttributeValue::Text(value), - is_static: true, - is_volatile: false, - namespace, - }); - } else { - if literal { - // literals will be captured when a full recompile is triggered - return Err(Error::RecompileRequiredError( - RecompileReason::CapturedAttribute(name.to_string()), - )); - } else { - return Err(Error::ParseError(ParseError::new( - syn::Error::new(span, format!("unknown attribute: {}", name)), - ctx.location.clone(), - ))); - } - } - } - - ElementAttr::AttrExpression { .. } - | ElementAttr::CustomAttrExpression { .. } => { - let (name, value, span, literal) = match &attr.attr { - ElementAttr::AttrExpression { name, value } => { - (name.to_string(), value, name.span(), false) - } - ElementAttr::CustomAttrExpression { name, value } => { - (name.value(), value, name.span(), true) - } - _ => unreachable!(), - }; - if let Some((_, resulting_value)) = ctx - .expressions - .iter() - .find(|(n, _)| parse_str::(*n).unwrap() == *value) - { if let Some((name, namespace)) = - ctx.attrbute_to_static_str(&name, literal) + ctx.attrbute_to_static_str(&name, tag, ns, literal) { - let value = bump.alloc(resulting_value.clone()); + let value = bump.alloc(resolve_ifmt(&value, &ctx.captured)?); attributes.push(Attribute { name, value: AttributeValue::Text(value), @@ -174,46 +135,85 @@ fn build_node<'a>( ))); } } + } + + ElementAttr::AttrExpression { .. } + | ElementAttr::CustomAttrExpression { .. } => { + let (name, value, span, literal) = match &attr.attr { + ElementAttr::AttrExpression { name, value } => { + (name.to_string(), value, name.span(), false) + } + ElementAttr::CustomAttrExpression { name, value } => { + (name.value(), value, name.span(), true) + } + _ => unreachable!(), + }; + if let Some((_, resulting_value)) = ctx + .expressions + .iter() + .find(|(n, _)| parse_str::(*n).unwrap() == *value) + { + if let Some((name, namespace)) = + ctx.attrbute_to_static_str(&name, tag, ns, literal) + { + let value = bump.alloc(resulting_value.clone()); + attributes.push(Attribute { + name, + value: AttributeValue::Text(value), + is_static: true, + is_volatile: false, + namespace, + }); + } else { + if literal { + // literals will be captured when a full recompile is triggered + return Err(Error::RecompileRequiredError( + RecompileReason::CapturedAttribute(name.to_string()), + )); + } else { + return Err(Error::ParseError(ParseError::new( + syn::Error::new( + span, + format!("unknown attribute: {}", name), + ), + ctx.location.clone(), + ))); + } + } + } + } + _ => (), + } + } + let children = bump.alloc(Vec::new()); + for child in el.children { + let node = build_node(child, ctx, factory)?; + children.push(node); + } + let listeners = bump.alloc(Vec::new()); + for attr in el.attributes { + if let ElementAttr::EventTokens { .. } = attr.attr { + let expr: Expr = parse2(attr.to_token_stream()).map_err(|err| { + Error::ParseError(ParseError::new(err, ctx.location.clone())) + })?; + if let Some(idx) = ctx.listeners.iter().position(|(code, _)| { + if let Ok(parsed) = parse_str::(*code) { + parsed == expr + } else { + false + } + }) { + let (_, listener) = ctx.listeners.remove(idx); + listeners.push(listener) } else { return Err(Error::RecompileRequiredError( - RecompileReason::CapturedExpression( - value.into_token_stream().to_string(), + RecompileReason::CapturedListener( + expr.to_token_stream().to_string(), ), )); } } - _ => (), - }; - } - let children = bump.alloc(Vec::new()); - for child in el.children { - let node = build_node(child, ctx, factory)?; - children.push(node); - } - let listeners = bump.alloc(Vec::new()); - for attr in el.attributes { - if let ElementAttr::EventTokens { .. } = attr.attr { - let expr: Expr = parse2(attr.to_token_stream()).map_err(|err| { - Error::ParseError(ParseError::new(err, ctx.location.clone())) - })?; - if let Some(idx) = ctx.listeners.iter().position(|(code, _)| { - if let Ok(parsed) = parse_str::(*code) { - parsed == expr - } else { - false - } - }) { - let (_, listener) = ctx.listeners.remove(idx); - listeners.push(listener) - } else { - return Err(Error::RecompileRequiredError( - RecompileReason::CapturedListener(expr.to_token_stream().to_string()), - )); - } } - } - let tag = bump.alloc(el.name.to_string()); - if let Some((tag, ns)) = element_to_static_str(tag) { match el.key { None => Ok(factory.raw_element( tag,