fix svg attributes

This commit is contained in:
Evan Almloff committed 2022-06-30 07:17:59 -05:00
1 parent ca13bf7358
commit e444d3d4bc
3 files changed
+156 -131

No files matched your search

+55 -41
View File
@@ -1,49 +1,62 @@
use crate::elements::*; use crate::elements::*;
// map the rsx name of the attribute to the html name of the attribute and the namespace that contains it // 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>)> { pub fn attrbute_to_static_str(
NO_NAMESPACE_ATTRIBUTES attr: &str,
.iter() element: &'static str,
.find(|&a| *a == attr) namespace: Option<&'static str>,
.map(|a| (*a, None)) ) -> Option<(&'static str, Option<&'static str>)> {
.or_else(|| { if namespace == Some("http://www.w3.org/2000/svg") {
STYLE_ATTRIBUTES svg::MAPPED_ATTRIBUTES
.iter() .iter()
.find(|(a, _)| *a == attr) .find(|(a, _)| *a == attr)
.map(|(_, b)| (*b, Some("style"))) .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 .or_else(|| {
.iter() ELEMENTS_WITHOUT_NAMESPACE.iter().find_map(|(el, attrs)| {
.find(|(a, _)| *a == attr) (element == *el)
.map(|(_, b)| (*b, None)) .then(|| attrs.iter().find(|a| **a == attr).map(|a| (*a, None)))
}) .flatten()
.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)))
}) })
})
} }
macro_rules! no_namespace_trait_methods { macro_rules! no_namespace_trait_methods {
@@ -615,6 +628,7 @@ mapped_trait_methods! {
} }
pub mod svg { pub mod svg {
mapped_trait_methods! { mapped_trait_methods! {
accent_height: "accent-height", accent_height: "accent-height",
accumulate: "accumulate", accumulate: "accumulate",
+1 -1
View File
@@ -54,7 +54,7 @@ macro_rules! builder_constructors {
$( $(
( (
stringify!($name), stringify!($name),
stringify!($namespace), $namespace,
&[ &[
$( $(
stringify!($fil), stringify!($fil),
+100 -89
View File
@@ -76,63 +76,39 @@ fn build_node<'a>(
Ok(factory.text(format_args!("{}", text))) Ok(factory.text(format_args!("{}", text)))
} }
BodyNode::Element(el) => { BodyNode::Element(el) => {
let attributes: &mut Vec<Attribute> = bump.alloc(Vec::new()); let tag = bump.alloc(el.name.to_string());
for attr in &el.attributes { if let Some((tag, ns)) = element_to_static_str(tag) {
match &attr.attr { let attributes: &mut Vec<Attribute> = bump.alloc(Vec::new());
ElementAttr::AttrText { .. } | ElementAttr::CustomAttrText { .. } => { for attr in &el.attributes {
let (name, value, span): (String, IfmtInput, Span) = match &attr.attr { match &attr.attr {
ElementAttr::AttrText { name, value } => ( ElementAttr::AttrText { .. } | ElementAttr::CustomAttrText { .. } => {
name.to_string(), let (name, value, span): (String, IfmtInput, Span) = match &attr.attr {
IfmtInput::from_str(&value.value()).map_err(|err| { ElementAttr::AttrText { name, value } => (
Error::ParseError(ParseError::new(err, ctx.location.clone())) name.to_string(),
})?, IfmtInput::from_str(&value.value()).map_err(|err| {
name.span(), Error::ParseError(ParseError::new(
), err,
ElementAttr::CustomAttrText { name, value } => ( ctx.location.clone(),
name.value(), ))
IfmtInput::from_str(&value.value()).map_err(|err| { })?,
Error::ParseError(ParseError::new(err, ctx.location.clone())) name.span(),
})?, ),
name.span(), ElementAttr::CustomAttrText { name, value } => (
), name.value(),
_ => unreachable!(), 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) { if let Some((name, namespace)) = attrbute_to_static_str(&name, tag, ns)
let value = bump.alloc(resolve_ifmt(&value, &ctx.captured)?); {
attributes.push(Attribute { let value = bump.alloc(resolve_ifmt(&value, &ctx.captured)?);
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::<Expr>(*n).unwrap() == *value)
{
if let Some((name, namespace)) = attrbute_to_static_str(&name) {
let value = bump.alloc(resulting_value.clone());
attributes.push(Attribute { attributes.push(Attribute {
name, name,
value: AttributeValue::Text(value), value: AttributeValue::Text(value),
@@ -140,47 +116,82 @@ fn build_node<'a>(
is_volatile: false, is_volatile: false,
namespace, 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::<Expr>(*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::<Expr>(*code) {
parsed == expr
} else {
false
}
}) {
let (_, listener) = ctx.listeners.remove(idx);
listeners.push(listener)
} else { } else {
return Err(Error::RecompileRequiredError( return Err(Error::RecompileRequiredError(
RecompileReason::CapturedExpression( RecompileReason::CapturedListener(
value.into_token_stream().to_string(), 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 { match el.key {
None => Ok(factory.raw_element( None => Ok(factory.raw_element(
tag, tag,