codeprism_core/linkers/
mod.rs

1//! Cross-language linkers for detecting relationships between different languages
2
3use crate::ast::{Edge, Node};
4use crate::error::Result;
5
6pub mod symbol_resolver;
7
8pub use symbol_resolver::SymbolResolver;
9
10/// Trait for cross-language linkers
11pub trait Linker: Send + Sync {
12    /// Name of the linker
13    fn name(&self) -> &str;
14
15    /// Find cross-language edges
16    fn find_edges(&self, nodes: &[Node]) -> Result<Vec<Edge>>;
17}
18
19/// REST API linker - simplified implementation to avoid memory issues
20pub 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        // Find routes and functions
31        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        // Simple matching - just check if route name contains function name or vice versa
45        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; // Only link to first match
54                }
55            }
56        }
57
58        Ok(edges)
59    }
60}
61
62impl RestLinker {
63    /// Simple name matching to avoid complex string operations
64    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        // Basic containment check
69        route_lower.contains(&func_lower) || func_lower.contains(&route_lower)
70    }
71}
72
73/// SQL query linker - simplified implementation
74pub 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        // Find SQL queries and potential tables
85        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        // Simple matching - check if query contains table/model names
99        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    /// Simple table name matching
117    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        // Basic containment check
122        query_lower.contains(&table_lower)
123    }
124}