- My Development Notes/
- Today I Learned/
- TIL: Preventing Inline Styles at Compile Time with Rust Proc-Macros/
TIL: Preventing Inline Styles at Compile Time with Rust Proc-Macros
1 min
What I Learned #
You can create a custom proc-macro in Rust that wraps Maud’s html! macro to prevent inline style attributes at compile time, enforcing the use of CSS classes instead.
Example #
// oxidesk-macros/src/lib.rs
use proc_macro::TokenStream;
use proc_macro2::TokenTree;
use quote::quote;
#[proc_macro]
pub fn html(input: TokenStream) -> TokenStream {
let input2: proc_macro2::TokenStream = input.clone().into();
let tokens: Vec<TokenTree> = input2.into_iter().collect();
// Check for style= attribute
for window in tokens.windows(2) {
if let (TokenTree::Ident(ident), TokenTree::Punct(punct)) = (&window[0], &window[1]) {
if ident.to_string() == "style" && punct.as_char() == '=' {
return syn::Error::new(ident.span(),
"inline `style` attribute is not allowed; use CSS classes instead")
.to_compile_error()
.into();
}
}
}
// Delegate to maud
let input3: proc_macro2::TokenStream = input.into();
let expanded = quote! {
::maud::html! { #input3 }
};
expanded.into()
}
Why It’s Useful #
This prevents inline styles from creeping into your codebase, maintaining a consistent design system through CSS classes. The compiler catches violations before the code even runs. For edge cases like email templates, you can provide an html_unchecked! escape hatch.