kinetics_parser/
parser.rs1use crate::{
2 ParsedFunction, Role, params::{Cron, Endpoint, Params, Worker}
3};
4use color_eyre::eyre;
5use std::path::PathBuf;
6use syn::{parse::Parse, visit::Visit, Attribute, ItemFn};
7use walkdir::WalkDir;
8
9#[derive(Debug, Default)]
10pub struct Parser {
11 pub functions: Vec<ParsedFunction>,
13
14 pub relative_path: String,
16}
17
18impl Parser {
19 pub fn new(path: Option<&PathBuf>) -> eyre::Result<Self> {
23 let mut parser: Parser = Default::default();
24
25 if let Some(path) = path {
26 parser.walk_dir(path)?;
27 }
28
29 Ok(parser)
30 }
31
32 pub fn walk_dir(&mut self, path: &PathBuf) -> eyre::Result<()> {
33 for entry in WalkDir::new(path)
34 .into_iter()
35 .filter_map(|e| e.ok())
36 .filter(|e| {
37 e.path().strip_prefix(path).is_ok_and(|p| p.starts_with("src/")) && e.path().extension().is_some_and(|ext| ext == "rs") })
40 {
41 let content = std::fs::read_to_string(entry.path())?;
42 let syntax = syn::parse_file(&content)?;
43
44 self.set_relative_path(entry.path().strip_prefix(path)?.to_str());
47
48 self.visit_file(&syntax);
49 }
50
51 Ok(())
52 }
53
54 pub fn set_relative_path(&mut self, file_path: Option<&str>) {
55 self.relative_path = file_path.map_or_else(|| "".to_string(), |s| s.to_string());
56 }
57
58 fn parse_endpoint(&mut self, attr: &Attribute) -> syn::Result<Endpoint> {
59 attr.parse_args_with(Endpoint::parse)
60 }
61
62 fn parse_worker(&mut self, attr: &Attribute) -> syn::Result<Worker> {
63 attr.parse_args_with(Worker::parse)
64 }
65
66 fn parse_cron(&mut self, attr: &Attribute) -> syn::Result<Cron> {
67 attr.parse_args_with(Cron::parse)
68 }
69
70 fn parse_attr_role(&self, input: &Attribute) -> String {
74 let path = input.path();
75
76 if path.segments.len() == 1 {
77 let ident = &path.segments[0].ident;
78 return ident.to_string();
79 }
80
81 if path.segments.len() == 2 && &path.segments[0].ident == "kinetics_macro" {
82 let ident = &path.segments[1].ident;
83 return ident.to_string();
84 }
85
86 "".to_string()
87 }
88}
89
90impl Visit<'_> for Parser {
91 fn visit_item_fn(&mut self, item: &ItemFn) {
93 for attr in &item.attrs {
94 let (role, params) = match self.parse_attr_role(attr).as_str() {
96 "endpoint" => {
97 let params = self.parse_endpoint(attr).unwrap();
98 (Role::Endpoint, Params::Endpoint(params))
99 }
100 "worker" => {
101 let params = self.parse_worker(attr).unwrap();
102 (Role::Worker, Params::Worker(params))
103 }
104 "cron" => {
105 let params = self.parse_cron(attr).unwrap();
106 (Role::Cron, Params::Cron(params))
107 }
108 _ => continue,
109 };
110
111 self.functions.push(ParsedFunction {
112 role,
113 params,
114 rust_function_name: item.sig.ident.to_string(),
115 relative_path: self.relative_path.clone(),
116 });
117 }
118
119 }
121}