codeprism_core/linkers/
mod.rs1use crate::ast::{Edge, Node};
4use crate::error::Result;
5
6pub mod symbol_resolver;
7
8pub use symbol_resolver::SymbolResolver;
9
10pub trait Linker: Send + Sync {
12 fn name(&self) -> &str;
14
15 fn find_edges(&self, nodes: &[Node]) -> Result<Vec<Edge>>;
17}
18
19pub struct RestLinker;
21
22impl Linker for RestLinker {
23 fn name(&self) -> &str {
24 "REST"
25 }
26
27 fn find_edges(&self, nodes: &[Node]) -> Result<Vec<Edge>> {
28 let mut edges = Vec::new();
29
30 let mut routes = Vec::new();
32 let mut functions = Vec::new();
33
34 for node in nodes {
35 match node.kind {
36 crate::ast::NodeKind::Route => routes.push(node),
37 crate::ast::NodeKind::Function | crate::ast::NodeKind::Method => {
38 functions.push(node)
39 }
40 _ => {}
41 }
42 }
43
44 for route in routes {
46 for function in &functions {
47 if self.simple_name_match(&route.name, &function.name) {
48 edges.push(Edge::new(
49 route.id,
50 function.id,
51 crate::ast::EdgeKind::RoutesTo,
52 ));
53 break; }
55 }
56 }
57
58 Ok(edges)
59 }
60}
61
62impl RestLinker {
63 fn simple_name_match(&self, route_name: &str, func_name: &str) -> bool {
65 let route_lower = route_name.to_lowercase();
66 let func_lower = func_name.to_lowercase();
67
68 route_lower.contains(&func_lower) || func_lower.contains(&route_lower)
70 }
71}
72
73pub struct SqlLinker;
75
76impl Linker for SqlLinker {
77 fn name(&self) -> &str {
78 "SQL"
79 }
80
81 fn find_edges(&self, nodes: &[Node]) -> Result<Vec<Edge>> {
82 let mut edges = Vec::new();
83
84 let mut sql_queries = Vec::new();
86 let mut table_candidates = Vec::new();
87
88 for node in nodes {
89 match node.kind {
90 crate::ast::NodeKind::SqlQuery => sql_queries.push(node),
91 crate::ast::NodeKind::Class | crate::ast::NodeKind::Variable => {
92 table_candidates.push(node)
93 }
94 _ => {}
95 }
96 }
97
98 for query in sql_queries {
100 for candidate in &table_candidates {
101 if self.simple_table_match(&query.name, &candidate.name) {
102 edges.push(Edge::new(
103 query.id,
104 candidate.id,
105 crate::ast::EdgeKind::Reads,
106 ));
107 }
108 }
109 }
110
111 Ok(edges)
112 }
113}
114
115impl SqlLinker {
116 fn simple_table_match(&self, query_text: &str, table_name: &str) -> bool {
118 let query_lower = query_text.to_lowercase();
119 let table_lower = table_name.to_lowercase();
120
121 query_lower.contains(&table_lower)
123 }
124}