holt-macros 0.2.1

A UI toolkit for Leptos
Documentation
use syn::{Expr, Lit, Meta, Path, Token, punctuated::Punctuated};

pub(crate) struct StoryMacroArgs {
    pub(crate) id: String,
    pub(crate) name: String,
    pub(crate) extra_docs: Option<Path>,
}

impl StoryMacroArgs {
    pub(crate) fn new(args: Punctuated<Meta, Token![,]>) -> Self {
        let mut story_id: Option<String> = None;
        let mut story_name: Option<String> = None;
        let mut extra_docs: Option<Path> = None;

        for arg in args {
            if let Meta::NameValue(nv) = arg {
                if let Expr::Lit(expr) = &nv.value
                    && let Lit::Str(lit) = &expr.lit
                    && nv.path.is_ident("id")
                {
                    story_id = Some(lit.value());
                } else if let Expr::Lit(expr) = &nv.value
                    && let Lit::Str(lit) = &expr.lit
                    && nv.path.is_ident("name")
                {
                    story_name = Some(lit.value());
                } else if let Expr::Path(path) = &nv.value
                    && nv.path.is_ident("extra_docs")
                {
                    extra_docs = Some(path.path.clone());
                }
            }
        }

        Self {
            id: story_id.expect("story macro requires id attribute"),
            name: story_name.expect("story macro requires name attribute"),
            extra_docs,
        }
    }
}

#[cfg(test)]
mod test {
    use syn::parse_quote;

    use crate::StoryMacroArgs;

    #[test]
    fn test_parse_attributes_with_valid_id_and_name() {
        let args = parse_quote! { id = "test_id", name = "Test Story" };
        let StoryMacroArgs {
            id,
            name,
            extra_docs,
        } = StoryMacroArgs::new(args);

        assert_eq!(id, "test_id");
        assert_eq!(name, "Test Story");
        assert!(extra_docs.is_none())
    }

    #[test]
    fn test_parse_attributes_with_extra_docs() {
        let args = parse_quote! { id = "test_id", name = "Test Story", extra_docs = FULL };
        let StoryMacroArgs {
            id,
            name,
            extra_docs,
        } = StoryMacroArgs::new(args);

        assert_eq!(id, "test_id");
        assert_eq!(name, "Test Story");
        assert!(
            extra_docs.is_some_and(|p| { p.segments.get(0).is_some_and(|s| s.ident == "FULL") })
        )
    }

    #[test]
    #[should_panic(expected = "story macro requires id attribute")]
    fn test_parse_attributes_missing_id() {
        let args = parse_quote! { name = "Test Story" };
        StoryMacroArgs::new(args);
    }

    #[test]
    #[should_panic(expected = "story macro requires name attribute")]
    fn test_parse_attributes_missing_name() {
        let args = parse_quote! { id = "test_id" };
        StoryMacroArgs::new(args);
    }
}