use crate::*;
pub fn parse_class(input: TokenStream) -> TokenStream {
let tokens: proc_macro2::TokenStream = match syn::parse::<ClassInput>(input) {
Ok(class_input) => class_input.into_token_stream(),
Err(error) => return error.to_compile_error().into(),
};
TokenStream::from(tokens)
}
pub(crate) fn expand_var_macros(expr: &Expr) -> proc_macro2::TokenStream {
match expr {
Expr::Macro(expr_macro) => {
if expr_macro.mac.path.is_ident("var") {
let body_tokens: &proc_macro2::TokenStream = &expr_macro.mac.tokens;
let body_str: String = reconstruct_kebab_from_tokens(body_tokens);
let css_name: String = format!("var(--{})", body_str);
quote! { #css_name }
} else if expr_macro.mac.path.is_ident("format") {
let mac_tokens: &proc_macro2::TokenStream = &expr_macro.mac.tokens;
let expanded: proc_macro2::TokenStream = expand_var_macros_in_tokens(mac_tokens);
let path: &syn::Path = &expr_macro.mac.path;
quote! { #path!(#expanded) }
} else {
expr.into_token_stream()
}
}
_ => expr.into_token_stream(),
}
}
pub(crate) fn expand_var_macros_in_tokens(
tokens: &proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
let mut result: Vec<proc_macro2::TokenTree> = Vec::new();
let mut iter: std::iter::Peekable<proc_macro2::token_stream::IntoIter> =
tokens.clone().into_iter().peekable();
while let Some(token) = iter.next() {
match &token {
proc_macro2::TokenTree::Ident(ident)
if *ident == "var"
&& iter.peek().is_some_and(
|t| matches!(t, proc_macro2::TokenTree::Punct(p) if p.as_char() == '!'),
) =>
{
iter.next();
if iter
.peek()
.is_some_and(|t| matches!(t, proc_macro2::TokenTree::Group(_)))
{
if let Some(proc_macro2::TokenTree::Group(group)) = iter.next() {
let inner: proc_macro2::TokenStream = group.stream();
let var_name: String = reconstruct_kebab_from_tokens(&inner);
let css_name: String = format!("var(--{})", var_name);
let expanded: proc_macro2::TokenStream = quote! { #css_name };
result.extend(expanded);
}
} else {
result.push(proc_macro2::TokenTree::Ident(ident.clone()));
result.push(proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
'!',
proc_macro2::Spacing::Alone,
)));
}
}
proc_macro2::TokenTree::Group(group) => {
let expanded_inner: proc_macro2::TokenStream =
expand_var_macros_in_tokens(&group.stream());
let new_group: proc_macro2::Group =
proc_macro2::Group::new(group.delimiter(), expanded_inner);
result.push(proc_macro2::TokenTree::Group(new_group));
}
_ => {
result.push(token);
}
}
}
result.into_iter().collect()
}
pub(crate) fn is_static_string_expr(tokens: &proc_macro2::TokenStream) -> bool {
for token in tokens.clone() {
match token {
proc_macro2::TokenTree::Literal(_) => continue,
_ => return false,
}
}
true
}
pub(crate) fn expr_to_string(tokens: &proc_macro2::TokenStream) -> String {
let mut result: String = String::new();
for token in tokens.clone() {
if let proc_macro2::TokenTree::Literal(lit) = token {
let lit_ts: proc_macro2::TokenStream = proc_macro2::TokenTree::Literal(lit).into();
if let Ok(lit_str) = syn::parse2::<LitStr>(lit_ts) {
result.push_str(&lit_str.value());
}
}
}
result
}