context_builder/tree_sitter/
mod.rs1#[cfg(feature = "tree-sitter-base")]
11pub mod language_support;
12
13#[cfg(feature = "tree-sitter-base")]
14pub mod signatures;
15
16#[cfg(feature = "tree-sitter-base")]
17pub mod structure;
18
19#[cfg(feature = "tree-sitter-base")]
20pub mod truncation;
21
22#[cfg(feature = "tree-sitter-base")]
23pub mod languages;
24
25#[cfg(feature = "tree-sitter-base")]
26use std::path::Path;
27
28#[cfg(feature = "tree-sitter-base")]
29pub use language_support::{CodeStructure, LanguageSupport, Signature, SignatureKind, Visibility};
30
31#[cfg(feature = "tree-sitter-base")]
32pub use signatures::extract_signatures;
33
34#[cfg(feature = "tree-sitter-base")]
35pub use structure::extract_structure;
36
37#[cfg(feature = "tree-sitter-base")]
38pub use truncation::find_truncation_point;
39
40#[cfg(feature = "tree-sitter-base")]
42pub fn is_supported_extension(ext: &str) -> bool {
43 languages::get_language_support(ext).is_some()
44}
45
46#[cfg(not(feature = "tree-sitter-base"))]
47pub fn is_supported_extension(_ext: &str) -> bool {
48 false
49}
50
51#[cfg(feature = "tree-sitter-base")]
53fn get_extension(path: &Path) -> Option<String> {
54 path.extension()
55 .and_then(|e| e.to_str())
56 .map(|s| s.to_lowercase())
57}
58
59#[cfg(feature = "tree-sitter-base")]
61pub fn get_language_for_path(path: &Path) -> Option<&'static dyn LanguageSupport> {
62 let ext = get_extension(path)?;
63 languages::get_language_support(&ext)
64}
65
66#[cfg(feature = "tree-sitter-base")]
68pub fn extract_signatures_for_file(
69 source: &str,
70 ext: &str,
71 visibility_filter: Visibility,
72) -> Option<Vec<Signature>> {
73 let support = languages::get_language_support(ext)?;
74 Some(extract_signatures(source, support, visibility_filter))
75}
76
77#[cfg(feature = "tree-sitter-base")]
79pub fn extract_structure_for_file(source: &str, ext: &str) -> Option<CodeStructure> {
80 let support = languages::get_language_support(ext)?;
81 Some(extract_structure(source, support))
82}
83
84#[cfg(feature = "tree-sitter-base")]
86pub fn find_smart_truncation_point(source: &str, max_bytes: usize, ext: &str) -> Option<usize> {
87 let support = languages::get_language_support(ext)?;
88 Some(find_truncation_point(source, max_bytes, support))
89}
90
91#[cfg(not(feature = "tree-sitter-base"))]
92pub fn extract_signatures_for_file(
93 _source: &str,
94 _ext: &str,
95 _visibility_filter: (),
96) -> Option<()> {
97 None
98}
99
100#[cfg(not(feature = "tree-sitter-base"))]
101pub fn extract_structure_for_file(_source: &str, _ext: &str) -> Option<()> {
102 None
103}
104
105#[cfg(not(feature = "tree-sitter-base"))]
106pub fn find_smart_truncation_point(_source: &str, _max_bytes: usize, _ext: &str) -> Option<usize> {
107 None
108}
109
110#[cfg(not(feature = "tree-sitter-base"))]
111pub fn get_language_for_path(_path: &std::path::Path) -> Option<()> {
112 None
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 #[cfg(feature = "tree-sitter-base")]
121 fn test_is_supported_extension() {
122 #[cfg(feature = "tree-sitter-rust")]
123 assert!(is_supported_extension("rs"));
124 #[cfg(feature = "tree-sitter-python")]
125 assert!(is_supported_extension("py"));
126 #[cfg(feature = "tree-sitter-js")]
127 assert!(is_supported_extension("js"));
128 assert!(!is_supported_extension("xyz"));
129 }
130
131 #[test]
132 #[cfg(not(feature = "tree-sitter-base"))]
133 fn test_no_tree_sitter_support() {
134 assert!(!is_supported_extension("rs"));
135 assert!(!is_supported_extension("py"));
136 }
137
138 #[test]
139 #[cfg(feature = "tree-sitter-base")]
140 fn test_get_extension() {
141 assert_eq!(get_extension(Path::new("foo.rs")), Some("rs".to_string()));
142 assert_eq!(get_extension(Path::new("foo.RS")), Some("rs".to_string()));
143 assert_eq!(get_extension(Path::new("foo.PY")), Some("py".to_string()));
144 assert_eq!(get_extension(Path::new("foo")), None);
145 assert_eq!(get_extension(Path::new(".gitignore")), None);
146 }
147
148 #[test]
149 #[cfg(feature = "tree-sitter-rust")]
150 fn test_extract_signatures_for_file_rust() {
151 let source = "pub fn hello() { }\nfn world() { }";
152 let sigs = extract_signatures_for_file(source, "rs", Visibility::All);
153 assert!(sigs.is_some());
154 let sigs = sigs.unwrap();
155 assert!(sigs.len() >= 2);
156 }
157
158 #[test]
159 #[cfg(feature = "tree-sitter-base")]
160 fn test_extract_signatures_for_file_unsupported() {
161 let sigs = extract_signatures_for_file("anything", "xyz", Visibility::All);
162 assert!(sigs.is_none());
163 }
164
165 #[test]
166 #[cfg(feature = "tree-sitter-rust")]
167 fn test_extract_structure_for_file_rust() {
168 let source = "use std::io;\nfn foo() { }\nstruct Bar { }\nenum Baz { A, B }";
169 let structure = extract_structure_for_file(source, "rs");
170 assert!(structure.is_some());
171 let s = structure.unwrap();
172 assert!(s.functions >= 1);
173 assert!(s.structs >= 1);
174 assert!(s.enums >= 1);
175 }
176
177 #[test]
178 #[cfg(feature = "tree-sitter-base")]
179 fn test_extract_structure_for_file_unsupported() {
180 let structure = extract_structure_for_file("anything", "xyz");
181 assert!(structure.is_none());
182 }
183
184 #[test]
185 #[cfg(feature = "tree-sitter-rust")]
186 fn test_find_smart_truncation_point_within_bounds() {
187 let source = "fn foo() { }\nfn bar() { }\nfn baz() { }";
188 let point = find_smart_truncation_point(source, 1000, "rs");
190 assert!(point.is_some());
191 assert_eq!(point.unwrap(), source.len());
192 }
193
194 #[test]
195 #[cfg(feature = "tree-sitter-rust")]
196 fn test_find_smart_truncation_point_truncated() {
197 let source = "fn foo() {\n let x = 1;\n}\nfn bar() {\n let y = 2;\n}";
198 let point = find_smart_truncation_point(source, 15, "rs");
199 assert!(point.is_some());
200 assert!(point.unwrap() <= source.len());
202 }
203
204 #[test]
205 #[cfg(feature = "tree-sitter-base")]
206 fn test_find_smart_truncation_point_unsupported() {
207 let point = find_smart_truncation_point("anything", 100, "xyz");
208 assert!(point.is_none());
209 }
210
211 #[test]
212 #[cfg(feature = "tree-sitter-rust")]
213 fn test_get_language_for_path_known() {
214 let support = get_language_for_path(Path::new("src/main.rs"));
215 assert!(support.is_some());
216 }
217
218 #[test]
219 #[cfg(feature = "tree-sitter-base")]
220 fn test_get_language_for_path_unknown() {
221 let support = get_language_for_path(Path::new("README.md"));
222 assert!(support.is_none());
223 }
224
225 #[test]
226 #[cfg(feature = "tree-sitter-base")]
227 fn test_get_language_for_path_no_extension() {
228 let support = get_language_for_path(Path::new("Makefile"));
229 assert!(support.is_none());
230 }
231}