use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned, ToTokens};
use syn::buffer::Cursor;
use syn::parse::{Parse, ParseStream, Result};
use syn::spanned::Spanned;
use syn::{Expr, Lit};
use super::ToNodeIterator;
use crate::stringify::Stringify;
use crate::{DisplayExt, PeekValue};
pub enum HtmlNode {
Literal(Box<Lit>),
Expression(Box<Expr>),
}
impl Parse for HtmlNode {
fn parse(input: ParseStream) -> Result<Self> {
let node = if HtmlNode::peek(input.cursor()).is_some() {
let lit = input.parse()?;
match lit {
Lit::ByteStr(lit) => {
return Err(syn::Error::new(
lit.span(),
"byte-strings can't be converted to HTML text\n\
note: remove the `b` prefix or convert this to a `String`",
))
}
Lit::Verbatim(lit) => {
return Err(syn::Error::new(lit.span(), "unsupported literal"))
}
_ => (),
}
HtmlNode::Literal(Box::new(lit))
} else {
HtmlNode::Expression(input.parse()?)
};
Ok(node)
}
}
impl PeekValue<()> for HtmlNode {
fn peek(cursor: Cursor) -> Option<()> {
cursor.literal().map(|_| ()).or_else(|| {
let (ident, _) = cursor.ident()?;
(ident.repr_eq("true") || ident.repr_eq("false")).then_some(())
})
}
}
impl ToTokens for HtmlNode {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(match &self {
HtmlNode::Literal(lit) => {
let sr = lit.stringify();
quote_spanned! {lit.span()=> ::yew::virtual_dom::VText::new(#sr) }
}
HtmlNode::Expression(expr) => quote! {#expr},
});
}
}
impl ToNodeIterator for HtmlNode {
fn to_node_iterator_stream(&self) -> Option<TokenStream> {
match self {
HtmlNode::Literal(_) => None,
HtmlNode::Expression(expr) => {
Some(quote_spanned! {expr.span().resolved_at(Span::call_site())=>
::std::convert::Into::<::yew::utils::NodeSeq<_, _>>::into(#expr)
})
}
}
}
}