cha_plugin_sdk_macros/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{Ident, parse_macro_input};
4
5const WIT: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/wit/plugin.wit"));
7
8#[proc_macro]
24pub fn plugin(input: TokenStream) -> TokenStream {
25 let ty = parse_macro_input!(input as Ident);
26 let wit = WIT;
27
28 quote! {
29 wit_bindgen::generate!({
30 inline: #wit,
31 world: "analyzer",
32 });
33 #[allow(unused_imports)]
34 use cha::plugin::types::{
35 ArmValue, ClassInfo, CommentInfo, FileRole, FunctionInfo, ImportInfo,
36 Location, OptionValue, Severity, SmellCategory,
37 };
38 #[allow(unused_imports)]
39 pub use cha::plugin::{project_query, tree_query};
40
41 pub trait PluginImpl {
44 fn name() -> String;
45 fn analyze(input: AnalysisInput) -> Vec<Finding>;
46 fn smells() -> Vec<String> { vec![] }
50 }
51
52 struct __ChaPluginWrapper(std::marker::PhantomData<#ty>);
53
54 impl Guest for __ChaPluginWrapper {
55 fn name() -> String { <#ty as PluginImpl>::name() }
56 fn version() -> String { env!("CARGO_PKG_VERSION").to_string() }
57 fn description() -> String {
58 let d = env!("CARGO_PKG_DESCRIPTION");
59 if d.is_empty() { <#ty as PluginImpl>::name() } else { d.to_string() }
60 }
61 fn authors() -> Vec<String> {
62 let a = env!("CARGO_PKG_AUTHORS");
63 if a.is_empty() { vec![] } else { a.split(':').map(str::to_string).collect() }
64 }
65 fn smells() -> Vec<String> { <#ty as PluginImpl>::smells() }
66 fn analyze(input: AnalysisInput) -> Vec<Finding> { <#ty as PluginImpl>::analyze(input) }
67 }
68
69 export!(__ChaPluginWrapper);
70 }
71 .into()
72}