Skip to main content

codesynapse_core/ts_extract/
haskell.rs

1use super::{add_contains_edge, add_node_if_missing, make_file_node, run_query_named};
2use crate::error::Result;
3use crate::extract::{make_id, ImportNode, LanguageExtractor};
4use crate::types::{Edge, ExtractionFragment, Node};
5use std::collections::HashMap;
6use std::path::Path;
7
8pub struct TsHaskellExtractor;
9
10impl TsHaskellExtractor {
11    pub fn extract(source: &[u8], path: &Path) -> Result<ExtractionFragment> {
12        let (file_id, _, file_node) = make_file_node(path);
13        let mut fragment = ExtractionFragment {
14            nodes: vec![file_node],
15            edges: vec![],
16        };
17
18        let lang = tree_sitter_haskell::LANGUAGE.into();
19
20        let module_query = r#"
21            (module
22                (module_id) @module.name
23            )
24        "#;
25        if let Ok(mut captures) = run_query_named(source, &lang, module_query) {
26            for name in captures.remove("module.name").unwrap_or_default() {
27                let id = make_id(&[&file_id, &name]);
28                fragment.nodes.push(Node {
29                    id: id.clone(),
30                    label: name,
31                    file_type: "module".to_string(),
32                    source_file: path.to_string_lossy().to_string(),
33                    source_location: None,
34                    community: None,
35                    rationale: None,
36                    docstring: None,
37                    metadata: HashMap::new(),
38                });
39                add_contains_edge(&mut fragment, &file_id, id, path);
40            }
41        }
42
43        let func_query = r#"
44            [
45                (function
46                    name: (variable) @func.name
47                )
48                (bind
49                    name: (variable) @func.name
50                )
51            ]
52        "#;
53        if let Ok(mut captures) = run_query_named(source, &lang, func_query) {
54            for name in captures.remove("func.name").unwrap_or_default() {
55                let label = format!("{}()", name);
56                let id = make_id(&[&file_id, &name]);
57                fragment.nodes.push(Node {
58                    id: id.clone(),
59                    label,
60                    file_type: "function".to_string(),
61                    source_file: path.to_string_lossy().to_string(),
62                    source_location: None,
63                    community: None,
64                    rationale: None,
65                    docstring: None,
66                    metadata: HashMap::new(),
67                });
68                add_contains_edge(&mut fragment, &file_id, id, path);
69            }
70        }
71
72        let import_query = r#"
73            (import
74                module: (module) @import.name
75            )
76        "#;
77        if let Ok(mut captures) = run_query_named(source, &lang, import_query) {
78            for name in captures.remove("import.name").unwrap_or_default() {
79                let mod_id = make_id(&[&file_id, &name]);
80                let mod_node = Node {
81                    id: mod_id.clone(),
82                    label: name,
83                    file_type: "module".to_string(),
84                    source_file: path.to_string_lossy().to_string(),
85                    source_location: None,
86                    community: None,
87                    rationale: None,
88                    docstring: None,
89                    metadata: HashMap::new(),
90                };
91                add_node_if_missing(&mut fragment, mod_node);
92                fragment.edges.push(Edge {
93                    source: file_id.clone(),
94                    target: mod_id,
95                    relation: "imports".to_string(),
96                    confidence: "EXTRACTED".to_string(),
97                    source_file: Some(path.to_string_lossy().to_string()),
98                    weight: 1.0,
99                    context: None,
100                });
101            }
102        }
103
104        Ok(fragment)
105    }
106}
107
108impl LanguageExtractor for TsHaskellExtractor {
109    fn file_extensions(&self) -> Vec<&'static str> {
110        vec!["hs", "lhs"]
111    }
112    fn extract(&self, source: &[u8], path: &Path) -> Result<ExtractionFragment> {
113        Self::extract(source, path)
114    }
115    fn resolve_imports(&self, _imports: &[ImportNode]) -> Vec<Edge> {
116        vec![]
117    }
118    fn collect_type_refs(&self, _fragment: &mut ExtractionFragment) {}
119}