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 path = path.replace('\\', "/");
27 let is_absolute = path.starts_with('/');
28 let parts: Vec<&str> = path.split('/').filter(|p| !p.is_empty()).collect();
29 let mut out: Vec<&str> = Vec::new();
30 for part in parts {
31 if part == "." {
32 continue;
33 }
34 if part == ".." {
35 out.pop();
36 } else {
37 out.push(part);
38 }
39 }
40 let result = out.join("/");
41 if is_absolute {
42 format!("/{result}")
43 } else {
44 result
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn normalizes_dotdot() {
54 assert_eq!(normalize_path("a/b/../c"), "a/c");
55 }
56
57 #[test]
58 fn strips_dots() {
59 assert_eq!(normalize_path("a/./b"), "a/b");
60 }
61
62 #[test]
63 fn handles_multiple_dotdots() {
64 assert_eq!(normalize_path("a/b/../../c"), "c");
65 }
66
67 #[test]
68 fn preserves_absolute_path() {
69 assert_eq!(normalize_path("/a/b/../c"), "/a/c");
70 }
71}