~repos /tide-jsx

#rust#proc-macro#jsx

git clone https://pyrossh.dev/repos/tide-jsx.git

Tide + JSX



file:

impl/src/element_attribute.rs



use quote::quote;
use std::hash::{Hash, Hasher};
use syn::ext::IdentExt;
use syn::parse::{Parse, ParseStream, Result};
use syn::spanned::Spanned;
pub type AttributeKey = syn::punctuated::Punctuated<syn::Ident, syn::Token![-]>;
pub enum ElementAttribute {
Punned(AttributeKey),
WithValue(AttributeKey, syn::Block),
}
impl ElementAttribute {
pub fn ident(&self) -> &AttributeKey {
match self {
Self::Punned(ident) | Self::WithValue(ident, _) => ident,
}
}
pub fn idents(&self) -> Vec<&syn::Ident> {
self.ident().iter().collect::<Vec<_>>()
}
pub fn value_tokens(&self) -> proc_macro2::TokenStream {
match self {
Self::WithValue(_, value) => {
if value.stmts.len() == 1 {
let first = &value.stmts[0];
quote!(#first)
} else {
quote!(#value)
}
}
Self::Punned(ident) => quote!(#ident),
}
}
pub fn validate(self, is_custom_element: bool) -> Result<Self> {
if is_custom_element {
self.validate_for_custom_element()
} else {
self.validate_for_simple_element()
}
}
pub fn validate_for_custom_element(self) -> Result<Self> {
if self.idents().len() < 2 {
Ok(self)
} else {
let alternative_name = self
.idents()
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join("_");
let error_message = format!(
"Can't use dash-delimited values on custom components. Did you mean `{}`?",
alternative_name
);
Err(syn::Error::new(self.ident().span(), error_message))
}
}
pub fn validate_for_simple_element(self) -> Result<Self> {
match (&self, self.idents().len()) {
(Self::Punned(ref key), len) if len > 1 => {
let error_message = "Can't use punning with dash-delimited values";
Err(syn::Error::new(key.span(), error_message))
}
_ => Ok(self),
}
}
}
impl PartialEq for ElementAttribute {
fn eq(&self, other: &Self) -> bool {
let self_idents: Vec<_> = self.ident().iter().collect();
let other_idents: Vec<_> = other.ident().iter().collect();
self_idents == other_idents
}
}
impl Eq for ElementAttribute {}
impl Hash for ElementAttribute {
fn hash<H: Hasher>(&self, state: &mut H) {
let ident = self.idents();
Hash::hash(&ident, state)
}
}
impl Parse for ElementAttribute {
fn parse(input: ParseStream) -> Result<Self> {
let name = AttributeKey::parse_separated_nonempty_with(input, syn::Ident::parse_any)?;
let not_punned = input.peek(syn::Token![=]);
if !not_punned {
return Ok(Self::Punned(name));
}
input.parse::<syn::Token![=]>()?;
let value = input.parse::<syn::Block>()?;
Ok(Self::WithValue(name, value))
}
}