From e444d3d4bc1b4bb7ff64e0f829db8fa623ec4979 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 30 Jun 2022 07:17:59 -0500 Subject: [PATCH] fix svg attributes --- packages/rsx_interpreter/src/attributes.rs | 96 +++++----- packages/rsx_interpreter/src/elements.rs | 2 +- packages/rsx_interpreter/src/interperter.rs | 189 +++++++++++--------- 3 files changed, 156 insertions(+), 131 deletions(-) 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/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 f35488c05..45b89cfc2 100644 --- a/packages/rsx_interpreter/src/interperter.rs +++ b/packages/rsx_interpreter/src/interperter.rs @@ -76,63 +76,39 @@ fn build_node<'a>( Ok(factory.text(format_args!("{}", text))) } 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): (String, IfmtInput, Span) = 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(), - ), - ElementAttr::CustomAttrText { name, value } => ( - name.value(), - IfmtInput::from_str(&value.value()).map_err(|err| { - Error::ParseError(ParseError::new(err, ctx.location.clone())) - })?, - name.span(), - ), - _ => unreachable!(), - }; + let tag = bump.alloc(el.name.to_string()); + if let Some((tag, ns)) = element_to_static_str(tag) { + let attributes: &mut Vec = bump.alloc(Vec::new()); + for attr in &el.attributes { + match &attr.attr { + ElementAttr::AttrText { .. } | ElementAttr::CustomAttrText { .. } => { + let (name, value, span): (String, IfmtInput, Span) = 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(), + ), + ElementAttr::CustomAttrText { name, value } => ( + name.value(), + IfmtInput::from_str(&value.value()).map_err(|err| { + Error::ParseError(ParseError::new( + err, + ctx.location.clone(), + )) + })?, + name.span(), + ), + _ => unreachable!(), + }; - if let Some((name, namespace)) = attrbute_to_static_str(&name) { - 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 { - return Err(Error::ParseError(ParseError::new( - syn::Error::new(span, format!("unknown attribute: {}", name)), - ctx.location.clone(), - ))); - } - } - - ElementAttr::AttrExpression { .. } - | ElementAttr::CustomAttrExpression { .. } => { - let (name, value) = match &attr.attr { - ElementAttr::AttrExpression { name, value } => { - (name.to_string(), value) - } - ElementAttr::CustomAttrExpression { name, value } => { - (name.value(), value) - } - _ => unreachable!(), - }; - if let Some((_, resulting_value)) = ctx - .expressions - .iter() - .find(|(n, _)| parse_str::(*n).unwrap() == *value) - { - if let Some((name, namespace)) = attrbute_to_static_str(&name) { - let value = bump.alloc(resulting_value.clone()); + if let Some((name, namespace)) = attrbute_to_static_str(&name, tag, ns) + { + let value = bump.alloc(resolve_ifmt(&value, &ctx.captured)?); attributes.push(Attribute { name, value: AttributeValue::Text(value), @@ -140,47 +116,82 @@ fn build_node<'a>( is_volatile: false, namespace, }); + } 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) = match &attr.attr { + ElementAttr::AttrExpression { name, value } => { + (name.to_string(), value) + } + ElementAttr::CustomAttrExpression { name, value } => { + (name.value(), value) + } + _ => unreachable!(), + }; + if let Some((_, resulting_value)) = ctx + .expressions + .iter() + .find(|(n, _)| parse_str::(*n).unwrap() == *value) + { + if let Some((name, namespace)) = + attrbute_to_static_str(&name, tag, ns) + { + let value = bump.alloc(resulting_value.clone()); + attributes.push(Attribute { + name, + value: AttributeValue::Text(value), + is_static: true, + is_volatile: false, + namespace, + }); + } + } else { + return Err(Error::RecompileRequiredError( + RecompileReason::CapturedExpression( + value.into_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::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,