Jelajahi Sumber

Merge pull request #473 from Demonthos/fix_hot_reloading_svg_attributes

Fix hot reloading svg attributes
Jon Kelley 3 tahun lalu
induk
melakukan
faf1103597

+ 55 - 41
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")))
-        })
-        .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)))
+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(|| {
-            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",

+ 3 - 1
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

+ 1 - 1
packages/rsx_interpreter/src/elements.rs

@@ -54,7 +54,7 @@ macro_rules! builder_constructors {
             $(
                 (
                     stringify!($name),
-                    stringify!($namespace),
+                    $namespace,
                     &[
                         $(
                             stringify!($fil),

+ 105 - 105
packages/rsx_interpreter/src/interperter.rs

@@ -76,81 +76,42 @@ fn build_node<'a>(
         }
         BodyNode::Element(el) => {
             let attributes: &mut Vec<Attribute> = 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!(),
-                            };
-
-                        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(),
-                                )));
-                            }
-                        }
-                    }
+            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!(),
+                                };
 
-                    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::<Expr>(*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::<Expr>(*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::<Expr>(*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::<Expr>(*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,