gen-html-proc 0.4.0

Generate HTML using Rust
Documentation
use proc_macro2::Span;
use quote::{ToTokens, quote_spanned};
use syn::Ident;

#[derive(Debug, Clone)]
pub enum Error {
    InvalidTag(Ident),
    SelfClosing(Ident),
    NotSelfClosing(Ident),
    AttributeSpecifiedMoreThenOnce { spans: Vec<Span>, key: String },
    Multi(Vec<Error>),
}

impl Error {
    pub fn empty() -> Self {
        Self::Multi(Vec::new())
    }

    pub fn is_empty(&self) -> bool {
        matches!(self, Self::Multi(vec) if vec.is_empty())
    }

    pub fn push(&mut self, other: Self) {
        if let Self::Multi(v) = self {
            v.push(other);
        } else {
            *self = Self::Multi(vec![self.clone(), other])
        }
    }
}

impl ToTokens for Error {
    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
        match self {
            Self::InvalidTag(tag) => {
                let msg = format!("`{tag}` is not a valid HTML tag");
                quote_spanned!(tag.span() => compile_error!(#msg);).to_tokens(tokens);
            }
            Self::SelfClosing(tag) => {
                let msg = format!("`{tag}` must be used like a self closing tag");
                quote_spanned!(tag.span() => compile_error!(#msg);).to_tokens(tokens);
            }
            Self::NotSelfClosing(tag) => {
                let msg = format!("`{tag}` cannot be used like a self closing tag");
                quote_spanned!(tag.span() => compile_error!(#msg);).to_tokens(tokens);
            }
            Self::AttributeSpecifiedMoreThenOnce { spans, key: name } => {
                let msg = format!("attribute `{name}` specified more then once");
                for span in spans {
                    quote_spanned!(*span => compile_error!(#msg);).to_tokens(tokens);
                }
            }
            Self::Multi(errors) => errors.iter().for_each(|e| e.to_tokens(tokens)),
        }
    }
}