use crate::*;
pub fn parse_html(input: TokenStream) -> TokenStream {
let nodes: HtmlRoot = parse_macro_input!(input as HtmlRoot);
let tokens: TokenStream2 = nodes.into_token_stream();
TokenStream::from(tokens)
}
pub(crate) fn camel_case_event_name(name: &str) -> String {
let mut result: String = String::new();
let mut capitalize_next: bool = true;
for ch in name.chars() {
if ch == '_' {
capitalize_next = true;
} else if capitalize_next {
result.push(ch.to_ascii_uppercase());
capitalize_next = false;
} else {
result.push(ch);
}
}
result
}
pub(crate) fn parse_html_children(content: ParseStream) -> SynResult<Vec<HtmlNode>> {
let mut children: Vec<HtmlNode> = Vec::new();
while !content.is_empty() {
if content.peek(LitStr) {
let lit: LitStr = content.parse()?;
children.push(HtmlNode::Text(lit.value()));
} else if content.peek(Token![if]) {
let html_if: HtmlIf = content.parse()?;
children.push(HtmlNode::If(html_if));
} else if content.peek(Token![match]) {
let html_match: HtmlMatch = content.parse()?;
children.push(HtmlNode::Match(html_match));
} else if content.peek(Token![for]) {
let html_for: HtmlFor = content.parse()?;
children.push(HtmlNode::For(html_for));
} else if content.peek(syn::token::Brace) {
let child_content;
braced!(child_content in content);
let expr: Expr = child_content.parse()?;
children.push(HtmlNode::Dynamic(expr));
} else if (content.peek(Ident) || content.peek(syn::LitStr)) && content.peek2(Colon) {
break;
} else if content.peek(Ident) {
if content.peek2(syn::token::Brace) {
let element: HtmlElement = content.parse()?;
children.push(HtmlNode::Element(element));
} else {
let expr: Expr = content.parse()?;
children.push(HtmlNode::Expr(expr));
}
} else {
return Err(content.error("unexpected token in HTML"));
}
}
Ok(children)
}
pub(crate) fn children_to_tokens(children: &[HtmlNode]) -> TokenStream2 {
let child_tokens: Vec<TokenStream2> = children
.iter()
.map(|child| {
let mut ts: TokenStream2 = TokenStream2::new();
child.to_tokens(&mut ts);
ts
})
.collect();
quote! { vec![#(#child_tokens),*] }
}
pub(crate) fn parse_attr_value(content: ParseStream, key_str: &str) -> SynResult<HtmlAttrValue> {
if key_str == "style" && content.peek(syn::token::Brace) {
let style_content;
braced!(style_content in content);
let is_style_object: bool = style_content.peek(LitStr) || style_content.peek(Ident);
if is_style_object {
let mut style_props: Vec<(String, HtmlStylePropValue)> = Vec::new();
while !style_content.is_empty() {
let css_key: String = parse_kebab_name(&style_content)?;
style_content.parse::<Colon>()?;
let prop_value: HtmlStylePropValue = if style_content.peek(LitStr) {
let lit: LitStr = style_content.parse()?;
HtmlStylePropValue::Literal(lit.value())
} else if style_content.peek(syn::token::Brace) {
let expr_content;
braced!(expr_content in style_content);
let expr: Expr = expr_content.parse()?;
HtmlStylePropValue::Expr(expr)
} else {
let expr: Expr = style_content.parse()?;
HtmlStylePropValue::Expr(expr)
};
style_props.push((css_key, prop_value));
if style_content.peek(Semi) {
style_content.parse::<Semi>()?;
}
}
Ok(HtmlAttrValue::Style(style_props))
} else {
Ok(HtmlAttrValue::Expr(style_content.parse()?))
}
} else {
Ok(HtmlAttrValue::Expr(content.parse()?))
}
}