argyph_graph/resolve/
mod.rs1use camino::Utf8Path;
2
3pub mod python;
4pub mod rust;
5pub mod typescript;
6
7pub trait ImportResolver {
8 fn resolve_import(
9 &self,
10 source_file: &Utf8Path,
11 module_path: &[String],
12 raw: &str,
13 ) -> Option<ModuleTarget>;
14}
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct ModuleTarget {
18 pub file_path: String,
19 pub confidence: super::edge::Confidence,
20}
21
22pub(crate) fn normalize_path(path: &str) -> String {
23 let is_absolute = path.starts_with('/');
24 let parts: Vec<&str> = path.split('/').filter(|p| !p.is_empty()).collect();
25 let mut out: Vec<&str> = Vec::new();
26 for part in parts {
27 if part == "." {
28 continue;
29 }
30 if part == ".." {
31 out.pop();
32 } else {
33 out.push(part);
34 }
35 }
36 let result = out.join("/");
37 if is_absolute {
38 format!("/{result}")
39 } else {
40 result
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
49 fn normalizes_dotdot() {
50 assert_eq!(normalize_path("a/b/../c"), "a/c");
51 }
52
53 #[test]
54 fn strips_dots() {
55 assert_eq!(normalize_path("a/./b"), "a/b");
56 }
57
58 #[test]
59 fn handles_multiple_dotdots() {
60 assert_eq!(normalize_path("a/b/../../c"), "c");
61 }
62
63 #[test]
64 fn preserves_absolute_path() {
65 assert_eq!(normalize_path("/a/b/../c"), "/a/c");
66 }
67}