1use elif_core::{ElifError, ResourceSpec};
2use serde::{Deserialize, Serialize};
3use std::path::PathBuf;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct ProjectMap {
7 pub routes: Vec<RouteInfo>,
8 pub models: Vec<ModelInfo>,
9 pub specs: Vec<SpecInfo>,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct RouteInfo {
14 pub op_id: String,
15 pub method: String,
16 pub path: String,
17 pub file: String,
18 pub marker: Option<String>,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct ModelInfo {
23 pub name: String,
24 pub file: String,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct SpecInfo {
29 pub name: String,
30 pub file: String,
31}
32
33pub struct MapGenerator {
34 project_root: PathBuf,
35}
36
37impl MapGenerator {
38 pub fn new(project_root: PathBuf) -> Self {
39 Self { project_root }
40 }
41
42 pub fn generate(&self) -> Result<ProjectMap, ElifError> {
43 let mut routes = Vec::new();
44 let mut models = Vec::new();
45 let mut specs = Vec::new();
46
47 let resources_dir = self.project_root.join("resources");
49 if resources_dir.exists() {
50 for entry in std::fs::read_dir(&resources_dir)? {
51 let entry = entry?;
52 let path = entry.path();
53
54 if path.extension().map_or(false, |ext| ext == "yaml") &&
55 path.file_stem().and_then(|s| s.to_str())
56 .map_or(false, |s| s.ends_with(".resource")) {
57
58 let content = std::fs::read_to_string(&path)?;
59 let spec = ResourceSpec::from_yaml(&content)?;
60
61 specs.push(SpecInfo {
63 name: spec.name.clone(),
64 file: path.to_string_lossy().to_string(),
65 });
66
67 models.push(ModelInfo {
69 name: spec.name.clone(),
70 file: format!("crates/orm/src/models/{}.rs", spec.name.to_lowercase()),
71 });
72
73 let handler_file = format!("apps/api/src/routes/{}.rs", spec.name.to_lowercase());
75 for op in &spec.api.operations {
76 routes.push(RouteInfo {
77 op_id: format!("{}.{}", spec.name, op.op),
78 method: op.method.clone(),
79 path: format!("{}{}", spec.route.trim_end_matches('/'), op.path),
80 file: handler_file.clone(),
81 marker: Some(format!("{}_{}", op.op, spec.name)),
82 });
83 }
84 }
85 }
86 }
87
88 Ok(ProjectMap {
89 routes,
90 models,
91 specs,
92 })
93 }
94}