daipendency_extractor_rust/
extractor.rs

1use super::{api, dependencies, metadata};
2use daipendency_extractor::{
3    DependencyResolutionError, ExtractionError, Extractor, LibraryMetadata, LibraryMetadataError,
4    Namespace,
5};
6use std::path::Path;
7use tree_sitter::{Language, Parser};
8
9pub struct RustExtractor;
10
11impl Default for RustExtractor {
12    fn default() -> Self {
13        Self::new()
14    }
15}
16
17impl RustExtractor {
18    pub fn new() -> Self {
19        Self
20    }
21}
22
23impl Extractor for RustExtractor {
24    fn get_parser_language(&self) -> Language {
25        tree_sitter_rust::LANGUAGE.into()
26    }
27
28    fn get_library_metadata(&self, path: &Path) -> Result<LibraryMetadata, LibraryMetadataError> {
29        metadata::extract_metadata(path)
30    }
31
32    fn extract_public_api(
33        &self,
34        metadata: &LibraryMetadata,
35        parser: &mut Parser,
36    ) -> Result<Vec<Namespace>, ExtractionError> {
37        api::build_public_api(&metadata.entry_point, &metadata.name, parser)
38    }
39
40    fn resolve_dependency_path(
41        &self,
42        dependency_name: &str,
43        dependant_path: &Path,
44    ) -> Result<std::path::PathBuf, DependencyResolutionError> {
45        dependencies::resolve_dependency_path(dependency_name, dependant_path)
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use assertables::{assert_contains, assert_ok};
52
53    use super::*;
54    use crate::test_helpers::{create_temp_dir, setup_parser};
55
56    #[test]
57    fn get_package_metadata() {
58        let temp_dir = create_temp_dir();
59        let cargo_toml = temp_dir.path().join("Cargo.toml");
60        std::fs::write(
61            &cargo_toml,
62            r#"[package]
63name = "test_crate"
64version = "0.1.0"
65"#,
66        )
67        .unwrap();
68
69        let analyser = RustExtractor::new();
70        let metadata = analyser.get_library_metadata(temp_dir.path()).unwrap();
71
72        assert_eq!(metadata.name, "test_crate");
73    }
74
75    #[test]
76    fn extract_public_api() {
77        let temp_dir = create_temp_dir();
78        let src_dir = temp_dir.path().join("src");
79        std::fs::create_dir(&src_dir).unwrap();
80        let lib_rs = src_dir.join("lib.rs");
81        std::fs::write(
82            &lib_rs,
83            r#"
84pub fn test_function() -> i32 {
85    42
86}
87"#,
88        )
89        .unwrap();
90
91        let analyser = RustExtractor::new();
92        let metadata = LibraryMetadata {
93            name: "test_crate".to_string(),
94            version: Some("0.1.0".to_string()),
95            documentation: String::new(),
96            entry_point: lib_rs,
97        };
98        let mut parser = setup_parser();
99
100        let namespaces = analyser.extract_public_api(&metadata, &mut parser).unwrap();
101
102        assert_eq!(namespaces.len(), 1);
103        let root = namespaces.iter().find(|n| n.name == "test_crate").unwrap();
104        assert_eq!(root.symbols.len(), 1);
105        assert_eq!(root.symbols[0].name, "test_function");
106    }
107
108    #[test]
109    fn resolve_dependency_path_success() {
110        let cargo_toml = Path::new(env!("CARGO_MANIFEST_DIR"));
111        let analyser = RustExtractor::new();
112        let dependency_name = "tree-sitter";
113
114        let result = analyser.resolve_dependency_path(dependency_name, &cargo_toml);
115
116        assert_ok!(&result);
117        assert_contains!(result.unwrap().to_str().unwrap(), dependency_name);
118    }
119}