use crate::error::SiteError; use crate::page::PageMeta; use crate::site::Site; use crate::wikitext::ParsedDirective; use std::collections::HashSet; #[derive(Debug, Eq, PartialEq)] pub enum Directive { Simple, UnnamedArg, SimpleArg, QuotedArg, MultilineArg, Meta(Meta), Img(Img), Tag(Tag), } impl TryFrom for Directive { type Error = SiteError; fn try_from(p: ParsedDirective) -> Result { let d = match p.name() { "simple" => { Self::check_args(&p, &[], &[], false)?; Directive::Simple } "unnamedarg" => { Self::check_args(&p, &[], &[], true)?; Directive::UnnamedArg } "simplearg" => { Self::check_args(&p, &["foo"], &[], false)?; Directive::SimpleArg } "quotedarg" => { Self::check_args(&p, &["bar"], &[], false)?; Directive::QuotedArg } "multilinearg" => { Self::check_args(&p, &["yo"], &["then", "else"], false)?; Directive::MultilineArg } "img" => { Self::check_args(&p, Img::REQUIRED, Img::ALLOWED, Img::ALLOW_ANY_UNNAMED)?; Directive::Img(Img::from(p)) } "meta" => { Self::check_args(&p, Meta::REQUIRED, Meta::ALLOWED, Meta::ALLOW_ANY_UNNAMED)?; Directive::Meta(Meta::from(p)) } "tag" => { Self::check_args(&p, Tag::REQUIRED, Tag::ALLOWED, Tag::ALLOW_ANY_UNNAMED)?; Directive::Tag(Tag::from(p)) } _ => return Err(SiteError::UnknownDirective(p.name().into())), }; Ok(d) } } impl Directive { fn check_args( p: &ParsedDirective, required: &[&str], allowed: &[&str], allow_any_unnamed: bool, ) -> Result<(), SiteError> { let args = p.args(); for arg in required.iter() { if !args.contains_key(arg) { return Err(SiteError::DirectiveMissingArg( p.name().into(), arg.to_string(), )); } } let required: HashSet = required.iter().map(|arg| arg.to_string()).collect(); let allowed: HashSet = allowed.iter().map(|arg| arg.to_string()).collect(); let allowed: HashSet = required.union(&allowed).cloned().collect(); for (arg, value) in p.args().iter() { if allow_any_unnamed && value.is_empty() { } else if !allowed.contains(*arg) { return Err(SiteError::DirectiveUnknownArg( p.name().into(), arg.to_string(), )); } } Ok(()) } pub fn process(&self, site: &mut Site, meta: &mut PageMeta) -> Result { match self { Self::Simple | Self::UnnamedArg | Self::SimpleArg | Self::QuotedArg | Self::MultilineArg => { panic!("directive {:?} may only be used in parsing tests", self) } Self::Img(x) => x.process(site, meta), Self::Meta(x) => x.process(site, meta), Self::Tag(x) => x.process(site, meta), } } } mod meta; use meta::Meta; mod img; pub use img::Img; mod tag; use tag::Tag;