the_code_graph_parser/resolver/
mod.rs1pub mod go;
2pub mod python;
3pub mod rust_lang;
4pub mod typescript;
5
6use std::collections::HashMap;
7use std::path::{Path, PathBuf};
8
9use domain::error::CodeGraphError;
10use domain::model::{Edge, Language};
11
12use crate::ParseResult;
13
14pub trait ImportResolver: Send + Sync {
17 fn languages(&self) -> &[Language];
19
20 fn resolve(
22 &self,
23 file_path: &Path,
24 parse_result: &ParseResult,
25 context: &ResolveContext,
26 ) -> domain::error::Result<Vec<Edge>>;
27}
28
29pub struct ResolveContext {
31 pub project_root: PathBuf,
32 pub parsed_files: HashMap<PathBuf, ParseResult>,
33 pub file_tree: Vec<PathBuf>,
34}
35
36pub struct ResolverRegistry {
38 resolvers: Vec<Box<dyn ImportResolver>>,
39}
40
41impl ResolverRegistry {
42 pub fn new(project_root: &Path) -> Self {
44 let mut registry = Self {
45 resolvers: Vec::new(),
46 };
47 registry.register(Box::new(typescript::TypeScriptResolver::new(project_root)));
48 let rust_config = rust_lang::RustConfig::load(project_root);
49 registry.register(Box::new(rust_lang::RustResolver::new(rust_config)));
50 let python_config = python::PythonConfig::load(project_root);
51 registry.register(Box::new(python::PythonResolver::new(python_config)));
52 let go_config = go::GoConfig::load(project_root);
53 registry.register(Box::new(go::GoResolver::new(go_config)));
54 registry
55 }
56
57 fn register(&mut self, resolver: Box<dyn ImportResolver>) {
58 self.resolvers.push(resolver);
59 }
60
61 pub fn resolver_for_language(&self, lang: Language) -> Option<&dyn ImportResolver> {
63 self.resolvers
64 .iter()
65 .find(|r| r.languages().contains(&lang))
66 .map(|r| r.as_ref())
67 }
68
69 pub fn resolve_file(
71 &self,
72 file_path: &Path,
73 lang: Language,
74 parse_result: &ParseResult,
75 context: &ResolveContext,
76 ) -> domain::error::Result<Vec<Edge>> {
77 self.resolver_for_language(lang)
78 .ok_or_else(|| {
79 CodeGraphError::Resolution(format!("no resolver for language {lang:?}"))
80 })?
81 .resolve(file_path, parse_result, context)
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use std::path::Path;
89
90 #[test]
91 fn registry_has_all_four_resolvers() {
92 let registry = ResolverRegistry::new(Path::new("/tmp"));
93 assert!(registry
94 .resolver_for_language(Language::TypeScript)
95 .is_some());
96 assert!(registry
97 .resolver_for_language(Language::JavaScript)
98 .is_some());
99 assert!(registry.resolver_for_language(Language::Rust).is_some());
100 assert!(registry.resolver_for_language(Language::Python).is_some());
101 assert!(registry.resolver_for_language(Language::Go).is_some());
102 }
103
104 #[test]
105 fn resolve_file_returns_error_for_unknown_language_none() {
106 let registry = ResolverRegistry::new(Path::new("/tmp"));
108 let context = ResolveContext {
109 project_root: PathBuf::from("/tmp"),
110 parsed_files: HashMap::new(),
111 file_tree: Vec::new(),
112 };
113 let result = ParseResult::default();
114 let edges = registry.resolve_file(
116 Path::new("test.ts"),
117 Language::TypeScript,
118 &result,
119 &context,
120 );
121 assert!(edges.is_ok());
122 }
123}