use proc_macro2::TokenStream;
use syn::{Attribute, parse_quote, spanned::Spanned};
use crate::models::{
Tusk,
ExternalModule,
TusksModule
};
use quote::quote;
impl TusksModule {
pub fn generate_command_attribute(&self) -> TokenStream {
let existing_attrs = self.extract_attributes(&["command"]);
if !existing_attrs.is_empty() {
quote! { #(#existing_attrs)* }
} else {
quote! { #[command()] }
}
}
pub fn generate_command_attribute_for_subcommands(&self) -> TokenStream {
let existing_attrs = self.extract_attributes(&["subcommands"]);
if !existing_attrs.is_empty() {
transform_attributes_to_command(existing_attrs, "subcommand")
} else {
quote! { #[command(subcommand)] }
}
}
pub fn generate_command_attribute_for_external_subcommands(&self) -> TokenStream {
let existing_attrs = self.extract_attributes(&["external_subcommands"]);
if !existing_attrs.is_empty() {
transform_attributes_to_command(existing_attrs, "flatten")
} else {
quote! { #[command(flatten)] }
}
}
}
impl Tusk {
pub fn generate_command_attribute(&self) -> TokenStream {
let existing_attrs = self.extract_attributes(&["command"]);
use_attributes_or_default(&existing_attrs, quote! { #[command()] })
}
}
impl ExternalModule {
pub fn generate_command_attribute(&self) -> TokenStream {
let existing_attrs = self.extract_attributes(&["command"]);
use_attributes_or_default(&existing_attrs, quote! { #[command()] })
}
}
fn use_attributes_or_default(attrs: &[&Attribute], default: TokenStream) -> TokenStream {
if !attrs.is_empty() {
quote! { #(#attrs)* }
} else {
default
}
}
fn transform_attributes_to_command(attrs: Vec<&syn::Attribute>, target_keyword: &str) -> TokenStream {
let mut result = TokenStream::new();
let mut target_ident = syn::Ident::new(target_keyword, proc_macro2::Span::call_site());
for attr in attrs {
let pound_span = attr.pound_token.span;
let bracket_span = attr.bracket_token.span;
target_ident.set_span(attr.span());
if let syn::Meta::List(meta_list) = &attr.meta {
let inner_tokens = &meta_list.tokens;
let new_attr: syn::Attribute = parse_quote! {
#[command(#target_ident, #inner_tokens)]
};
let mut new_attr_with_span = new_attr;
new_attr_with_span.pound_token.span = pound_span;
new_attr_with_span.bracket_token.span = bracket_span;
result.extend(quote! { #new_attr_with_span });
} else {
let new_attr: syn::Attribute = parse_quote! {
#[command(#target_ident)]
};
let mut new_attr_with_span = new_attr;
new_attr_with_span.pound_token.span = pound_span;
new_attr_with_span.bracket_token.span = bracket_span;
result.extend(quote! { #new_attr_with_span });
}
}
result
}