use crate::block::*;
use crate::inherit::Inherit;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use voca_rs::case::snake_case;
pub(crate) trait Generate {
fn generate(&mut self, parent_props: Option<&DescribeProps>) -> TokenStream;
}
impl Generate for Root {
fn generate(&mut self, _parent_props: Option<&DescribeProps>) -> TokenStream {
self.0
.iter_mut()
.map(|block| {
let root_block = block.generate(None);
quote! {
#[cfg(test)]
#root_block
}
})
.collect::<TokenStream>()
}
}
impl Generate for Block {
fn generate(&mut self, parent_props: Option<&DescribeProps>) -> TokenStream {
match self {
Block::Test(test) => test.generate(parent_props),
Block::Describe(describe) => describe.generate(parent_props),
}
}
}
impl Generate for Describe {
fn generate(&mut self, parent_props: Option<&DescribeProps>) -> TokenStream {
let mut uses = self
.properties
.uses
.iter()
.map(|use_tree| quote!(use #use_tree;))
.collect::<TokenStream>();
if let Some(ref parent_props) = parent_props {
self.inherit(parent_props);
uses.extend(quote!(
use super::*;
));
}
let cloned_props = self.properties.clone();
let blocks = self
.blocks
.iter_mut()
.map(|block| block.generate(Some(&cloned_props)))
.collect::<TokenStream>();
let ident = Ident::new(
&snake_case(&self.properties.block_props.name),
Span::call_site(),
);
quote! {
mod #ident {
#uses
#blocks
}
}
}
}
impl Generate for Test {
fn generate(&mut self, parent_props: Option<&DescribeProps>) -> TokenStream {
if let Some(ref parent_props) = parent_props {
self.inherit(parent_props);
}
let BlockProps {
attributes,
is_async,
name,
return_type,
} = &self.properties;
let content = &self.content.0;
let (attr_tokens, async_token) = if *is_async {
(quote!(#(#attributes)*), Some(quote!(async)))
} else {
(
quote! {
#[test]
#(#attributes)*
},
None,
)
};
let ident = Ident::new(&snake_case(&name), Span::call_site());
if let Some(return_type) = return_type {
quote! {
#attr_tokens
#async_token fn #ident() -> #return_type {
#(#content)*
}
}
} else {
quote! {
#attr_tokens
#async_token fn #ident() {
#(#content)*
}
}
}
}
}