extern crate proc_macro;
use proc_macro::TokenStream;
use quote::{quote, format_ident};
use syn::{parse_macro_input, ItemFn, FnArg, Pat};
#[proc_macro_attribute]
pub fn action(attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemFn);
let fn_name = &input.sig.ident;
let fn_vis = &input.vis;
let attr_str = attr.to_string();
let description = if attr_str.is_empty() {
format!("Action {}", fn_name)
} else {
attr_str.trim_matches('"').to_string()
};
let meta_fn_name = format_ident!("{}_metadata", fn_name);
let mut param_defs = Vec::new();
for arg in &input.sig.inputs {
if let FnArg::Typed(pat_type) = arg {
if let Pat::Ident(pat_ident) = &*pat_type.pat {
let param_name = &pat_ident.ident;
if param_name == "self" {
continue;
}
let param_name_str = param_name.to_string();
param_defs.push(quote! {
ActionParameter {
name: #param_name_str.to_string(),
description: format!("Parameter {}", #param_name_str),
required: true,
param_type: ParamType::String, default_value: None,
}
});
}
}
}
let meta_fn = if param_defs.is_empty() {
quote! {
fn #meta_fn_name() -> ActionDefinition {
ActionDefinition {
name: #fn_name.to_string(),
description: #description.to_string(),
parameters: vec![],
}
}
}
} else {
quote! {
fn #meta_fn_name() -> ActionDefinition {
ActionDefinition {
name: #fn_name.to_string(),
description: #description.to_string(),
parameters: vec![
#(#param_defs),*
],
}
}
}
};
let result = quote! {
#input
#meta_fn
};
result.into()
}