1use crate::types::{Symbol, SymbolKind, Visibility};
55use std::collections::{HashMap, HashSet};
56use thiserror::Error;
57use tree_sitter::{Node, Parser as TSParser, Query, QueryCursor, StreamingIterator, Tree};
58
59#[derive(Debug, Error)]
61pub enum ParserError {
62 #[error("Unsupported language: {0}")]
63 UnsupportedLanguage(String),
64
65 #[error("Parse error: {0}")]
66 ParseError(String),
67
68 #[error("Query error: {0}")]
69 QueryError(String),
70
71 #[error("Invalid UTF-8 in source code")]
72 InvalidUtf8,
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
77pub enum Language {
78 Python,
79 JavaScript,
80 TypeScript,
81 Rust,
82 Go,
83 Java,
84 C,
85 Cpp,
86 CSharp,
87 Ruby,
88 Bash,
89 Php,
90 Kotlin,
91 Swift,
92 Scala,
93 Haskell,
94 Elixir,
95 Clojure,
96 OCaml,
97 FSharp,
98 Lua,
99 R,
100}
101
102impl Language {
103 pub fn from_extension(ext: &str) -> Option<Self> {
105 match ext.to_lowercase().as_str() {
106 "py" | "pyw" => Some(Self::Python),
107 "js" | "jsx" | "mjs" | "cjs" => Some(Self::JavaScript),
108 "ts" | "tsx" => Some(Self::TypeScript),
109 "rs" => Some(Self::Rust),
110 "go" => Some(Self::Go),
111 "java" => Some(Self::Java),
112 "c" | "h" => Some(Self::C),
113 "cpp" | "cc" | "cxx" | "hpp" | "hxx" | "hh" => Some(Self::Cpp),
114 "cs" => Some(Self::CSharp),
115 "rb" | "rake" | "gemspec" => Some(Self::Ruby),
116 "sh" | "bash" | "zsh" | "fish" => Some(Self::Bash),
117 "php" | "phtml" | "php3" | "php4" | "php5" | "phps" => Some(Self::Php),
118 "kt" | "kts" => Some(Self::Kotlin),
119 "swift" => Some(Self::Swift),
120 "scala" | "sc" => Some(Self::Scala),
121 "hs" | "lhs" => Some(Self::Haskell),
122 "ex" | "exs" | "eex" | "heex" | "leex" => Some(Self::Elixir),
123 "clj" | "cljs" | "cljc" | "edn" => Some(Self::Clojure),
124 "ml" | "mli" => Some(Self::OCaml),
125 "fs" | "fsi" | "fsx" | "fsscript" => Some(Self::FSharp),
126 "lua" => Some(Self::Lua),
127 "r" | "rmd" => Some(Self::R),
128 _ => None,
129 }
130 }
131
132 pub fn name(&self) -> &'static str {
134 match self {
135 Self::Python => "python",
136 Self::JavaScript => "javascript",
137 Self::TypeScript => "typescript",
138 Self::Rust => "rust",
139 Self::Go => "go",
140 Self::Java => "java",
141 Self::C => "c",
142 Self::Cpp => "cpp",
143 Self::CSharp => "csharp",
144 Self::Ruby => "ruby",
145 Self::Bash => "bash",
146 Self::Php => "php",
147 Self::Kotlin => "kotlin",
148 Self::Swift => "swift",
149 Self::Scala => "scala",
150 Self::Haskell => "haskell",
151 Self::Elixir => "elixir",
152 Self::Clojure => "clojure",
153 Self::OCaml => "ocaml",
154 Self::FSharp => "fsharp",
155 Self::Lua => "lua",
156 Self::R => "r",
157 }
158 }
159}
160
161pub struct Parser {
170 parsers: HashMap<Language, TSParser>,
171 queries: HashMap<Language, Query>,
172 super_queries: HashMap<Language, Query>,
174}
175
176impl Parser {
177 pub fn new() -> Self {
180 Self { parsers: HashMap::new(), queries: HashMap::new(), super_queries: HashMap::new() }
181 }
182
183 fn ensure_initialized(&mut self, language: Language) -> Result<(), ParserError> {
185 use std::collections::hash_map::Entry;
186 if let Entry::Vacant(parser_entry) = self.parsers.entry(language) {
187 let (parser, query, super_query) = match language {
188 Language::Python => (
189 Self::init_python_parser()?,
190 Self::python_query()?,
191 Self::python_super_query()?,
192 ),
193 Language::JavaScript => (
194 Self::init_javascript_parser()?,
195 Self::javascript_query()?,
196 Self::javascript_super_query()?,
197 ),
198 Language::TypeScript => (
199 Self::init_typescript_parser()?,
200 Self::typescript_query()?,
201 Self::typescript_super_query()?,
202 ),
203 Language::Rust => {
204 (Self::init_rust_parser()?, Self::rust_query()?, Self::rust_super_query()?)
205 },
206 Language::Go => {
207 (Self::init_go_parser()?, Self::go_query()?, Self::go_super_query()?)
208 },
209 Language::Java => {
210 (Self::init_java_parser()?, Self::java_query()?, Self::java_super_query()?)
211 },
212 Language::C => (Self::init_c_parser()?, Self::c_query()?, Self::c_super_query()?),
213 Language::Cpp => {
214 (Self::init_cpp_parser()?, Self::cpp_query()?, Self::cpp_super_query()?)
215 },
216 Language::CSharp => (
217 Self::init_csharp_parser()?,
218 Self::csharp_query()?,
219 Self::csharp_super_query()?,
220 ),
221 Language::Ruby => {
222 (Self::init_ruby_parser()?, Self::ruby_query()?, Self::ruby_super_query()?)
223 },
224 Language::Bash => {
225 (Self::init_bash_parser()?, Self::bash_query()?, Self::bash_super_query()?)
226 },
227 Language::Php => {
228 (Self::init_php_parser()?, Self::php_query()?, Self::php_super_query()?)
229 },
230 Language::Kotlin => (
231 Self::init_kotlin_parser()?,
232 Self::kotlin_query()?,
233 Self::kotlin_super_query()?,
234 ),
235 Language::Swift => {
236 (Self::init_swift_parser()?, Self::swift_query()?, Self::swift_super_query()?)
237 },
238 Language::Scala => {
239 (Self::init_scala_parser()?, Self::scala_query()?, Self::scala_super_query()?)
240 },
241 Language::Haskell => (
242 Self::init_haskell_parser()?,
243 Self::haskell_query()?,
244 Self::haskell_super_query()?,
245 ),
246 Language::Elixir => (
247 Self::init_elixir_parser()?,
248 Self::elixir_query()?,
249 Self::elixir_super_query()?,
250 ),
251 Language::Clojure => (
252 Self::init_clojure_parser()?,
253 Self::clojure_query()?,
254 Self::clojure_super_query()?,
255 ),
256 Language::OCaml => {
257 (Self::init_ocaml_parser()?, Self::ocaml_query()?, Self::ocaml_super_query()?)
258 },
259 Language::FSharp => {
260 return Err(ParserError::UnsupportedLanguage(
261 "F# not yet supported (no tree-sitter grammar available)".to_owned(),
262 ));
263 },
264 Language::Lua => {
265 (Self::init_lua_parser()?, Self::lua_query()?, Self::lua_super_query()?)
266 },
267 Language::R => (Self::init_r_parser()?, Self::r_query()?, Self::r_super_query()?),
268 };
269 parser_entry.insert(parser);
270 self.queries.insert(language, query);
271 self.super_queries.insert(language, super_query);
272 }
273 Ok(())
274 }
275
276 pub fn parse(
281 &mut self,
282 source_code: &str,
283 language: Language,
284 ) -> Result<Vec<Symbol>, ParserError> {
285 self.ensure_initialized(language)?;
287
288 let parser = self
289 .parsers
290 .get_mut(&language)
291 .ok_or_else(|| ParserError::UnsupportedLanguage(language.name().to_owned()))?;
292
293 let tree = parser
294 .parse(source_code, None)
295 .ok_or_else(|| ParserError::ParseError("Failed to parse source code".to_owned()))?;
296
297 let super_query = self
299 .super_queries
300 .get(&language)
301 .ok_or_else(|| ParserError::QueryError("No super-query available".to_owned()))?;
302
303 self.extract_symbols_single_pass(&tree, source_code, super_query, language)
304 }
305
306 fn extract_symbols_single_pass(
308 &self,
309 tree: &Tree,
310 source_code: &str,
311 query: &Query,
312 language: Language,
313 ) -> Result<Vec<Symbol>, ParserError> {
314 let mut symbols = Vec::new();
315 let mut cursor = QueryCursor::new();
316 let root_node = tree.root_node();
317
318 let mut matches = cursor.matches(query, root_node, source_code.as_bytes());
319 let capture_names: Vec<&str> = query.capture_names().to_vec();
320
321 while let Some(m) = matches.next() {
322 if let Some(import_symbol) = self.process_import_match(m, source_code, &capture_names) {
324 symbols.push(import_symbol);
325 continue;
326 }
327
328 if let Some(symbol) =
330 self.process_match_single_pass(m, source_code, &capture_names, language)
331 {
332 symbols.push(symbol);
333 }
334 }
335
336 Ok(symbols)
337 }
338
339 fn process_import_match(
341 &self,
342 m: &tree_sitter::QueryMatch<'_, '_>,
343 source_code: &str,
344 capture_names: &[&str],
345 ) -> Option<Symbol> {
346 let captures = &m.captures;
347
348 let import_capture = captures.iter().find(|c| {
350 capture_names
351 .get(c.index as usize)
352 .map(|n| *n == "import")
353 .unwrap_or(false)
354 })?;
355
356 let node = import_capture.node;
357 let text = node.utf8_text(source_code.as_bytes()).ok()?;
358
359 let mut symbol = Symbol::new(text.trim(), SymbolKind::Import);
360 symbol.start_line = node.start_position().row as u32 + 1;
361 symbol.end_line = node.end_position().row as u32 + 1;
362
363 Some(symbol)
364 }
365
366 fn process_match_single_pass(
368 &self,
369 m: &tree_sitter::QueryMatch<'_, '_>,
370 source_code: &str,
371 capture_names: &[&str],
372 language: Language,
373 ) -> Option<Symbol> {
374 let captures = &m.captures;
375
376 let name_node = captures
378 .iter()
379 .find(|c| {
380 capture_names
381 .get(c.index as usize)
382 .map(|n| *n == "name")
383 .unwrap_or(false)
384 })?
385 .node;
386
387 let kind_capture = captures.iter().find(|c| {
389 capture_names
390 .get(c.index as usize)
391 .map(|n| {
392 ["function", "class", "method", "struct", "enum", "interface", "trait"]
393 .contains(n)
394 })
395 .unwrap_or(false)
396 })?;
397
398 let kind_name = capture_names.get(kind_capture.index as usize)?;
399 let mut symbol_kind = self.map_symbol_kind(kind_name);
400
401 let name = name_node.utf8_text(source_code.as_bytes()).ok()?;
402
403 let def_node = captures
405 .iter()
406 .max_by_key(|c| c.node.byte_range().len())
407 .map(|c| c.node)
408 .unwrap_or(name_node);
409
410 if language == Language::Kotlin && def_node.kind() == "class_declaration" {
411 let mut cursor = def_node.walk();
412 for child in def_node.children(&mut cursor) {
413 if child.kind() == "interface" {
414 symbol_kind = SymbolKind::Interface;
415 break;
416 }
417 }
418 }
419
420 let start_line = def_node.start_position().row as u32 + 1;
421 let end_line = def_node.end_position().row as u32 + 1;
422
423 let signature = self.extract_signature(def_node, source_code, language);
425 let docstring = self.extract_docstring(def_node, source_code, language);
426 let parent = if symbol_kind == SymbolKind::Method {
427 self.extract_parent(def_node, source_code)
428 } else {
429 None
430 };
431 let visibility = self.extract_visibility(def_node, source_code, language);
432 let calls = if matches!(symbol_kind, SymbolKind::Function | SymbolKind::Method) {
433 self.extract_calls(def_node, source_code, language)
434 } else {
435 Vec::new()
436 };
437
438 let (extends, implements) = if matches!(
440 symbol_kind,
441 SymbolKind::Class | SymbolKind::Struct | SymbolKind::Interface
442 ) {
443 self.extract_inheritance(def_node, source_code, language)
444 } else {
445 (None, Vec::new())
446 };
447
448 let mut symbol = Symbol::new(name, symbol_kind);
449 symbol.start_line = start_line;
450 symbol.end_line = end_line;
451 symbol.signature = signature;
452 symbol.docstring = docstring;
453 symbol.parent = parent;
454 symbol.visibility = visibility;
455 symbol.calls = calls;
456 symbol.extends = extends;
457 symbol.implements = implements;
458
459 Some(symbol)
460 }
461
462 fn map_symbol_kind(&self, capture_name: &str) -> SymbolKind {
464 match capture_name {
465 "function" => SymbolKind::Function,
466 "class" => SymbolKind::Class,
467 "method" => SymbolKind::Method,
468 "struct" => SymbolKind::Struct,
469 "enum" => SymbolKind::Enum,
470 "interface" => SymbolKind::Interface,
471 "trait" => SymbolKind::Trait,
472 _ => SymbolKind::Function,
473 }
474 }
475
476 fn extract_signature(
478 &self,
479 node: Node<'_>,
480 source_code: &str,
481 language: Language,
482 ) -> Option<String> {
483 let sig_node = match language {
485 Language::Python => {
486 if node.kind() == "function_definition" {
488 let start = node.start_byte();
490 let mut end = start;
491 for byte in &source_code.as_bytes()[start..] {
492 end += 1;
493 if *byte == b':' {
494 break;
495 }
496 if *byte == b'\n' {
497 break;
498 }
499 }
500 return Some(source_code[start..end].trim().to_owned().replace('\n', " "));
501 }
502 None
503 },
504 Language::JavaScript | Language::TypeScript => {
505 if node.kind().contains("function") || node.kind().contains("method") {
507 let start = node.start_byte();
509 let mut end = start;
510 let mut brace_count = 0;
511 for byte in &source_code.as_bytes()[start..] {
512 if *byte == b'{' {
513 brace_count += 1;
514 if brace_count == 1 {
515 break;
516 }
517 }
518 end += 1;
519 }
520 return Some(source_code[start..end].trim().to_owned().replace('\n', " "));
521 }
522 None
523 },
524 Language::Rust => {
525 if node.kind() == "function_item" {
527 for child in node.children(&mut node.walk()) {
529 if child.kind() == "block" {
530 let start = node.start_byte();
531 let end = child.start_byte();
532 return Some(
533 source_code[start..end].trim().to_owned().replace('\n', " "),
534 );
535 }
536 }
537 }
538 None
539 },
540 Language::Go => {
541 if node.kind() == "function_declaration" || node.kind() == "method_declaration" {
543 for child in node.children(&mut node.walk()) {
544 if child.kind() == "block" {
545 let start = node.start_byte();
546 let end = child.start_byte();
547 return Some(
548 source_code[start..end].trim().to_owned().replace('\n', " "),
549 );
550 }
551 }
552 }
553 None
554 },
555 Language::Java => {
556 if node.kind() == "method_declaration" {
558 for child in node.children(&mut node.walk()) {
559 if child.kind() == "block" {
560 let start = node.start_byte();
561 let end = child.start_byte();
562 return Some(
563 source_code[start..end].trim().to_owned().replace('\n', " "),
564 );
565 }
566 }
567 }
568 None
569 },
570 Language::C
572 | Language::Cpp
573 | Language::CSharp
574 | Language::Php
575 | Language::Kotlin
576 | Language::Swift
577 | Language::Scala => {
578 for child in node.children(&mut node.walk()) {
580 if child.kind() == "block"
581 || child.kind() == "compound_statement"
582 || child.kind() == "function_body"
583 {
584 let start = node.start_byte();
585 let end = child.start_byte();
586 return Some(source_code[start..end].trim().to_owned().replace('\n', " "));
587 }
588 }
589 None
590 },
591 Language::Ruby | Language::Lua => {
593 let start = node.start_byte();
594 let mut end = start;
595 for byte in &source_code.as_bytes()[start..] {
596 end += 1;
597 if *byte == b'\n' {
598 break;
599 }
600 }
601 Some(source_code[start..end].trim().to_owned())
602 },
603 Language::Bash => {
605 let start = node.start_byte();
606 let mut end = start;
607 for byte in &source_code.as_bytes()[start..] {
608 if *byte == b'{' {
609 break;
610 }
611 end += 1;
612 }
613 Some(source_code[start..end].trim().to_owned())
614 },
615 Language::Haskell
617 | Language::OCaml
618 | Language::FSharp
619 | Language::Elixir
620 | Language::Clojure
621 | Language::R => {
622 let start = node.start_byte();
623 let mut end = start;
624 for byte in &source_code.as_bytes()[start..] {
625 end += 1;
626 if *byte == b'\n' || *byte == b'=' {
627 break;
628 }
629 }
630 Some(source_code[start..end].trim().to_owned())
631 },
632 };
633
634 sig_node.or_else(|| {
635 let start = node.start_byte();
637 let end = std::cmp::min(start + 200, source_code.len());
638 let text = &source_code[start..end];
639 text.lines().next().map(|s| s.trim().to_owned())
640 })
641 }
642
643 fn extract_docstring(
645 &self,
646 node: Node<'_>,
647 source_code: &str,
648 language: Language,
649 ) -> Option<String> {
650 match language {
651 Language::Python => {
652 let mut cursor = node.walk();
654 for child in node.children(&mut cursor) {
655 if child.kind() == "block" {
656 for stmt in child.children(&mut child.walk()) {
658 if stmt.kind() == "expression_statement" {
659 for expr in stmt.children(&mut stmt.walk()) {
660 if expr.kind() == "string" {
661 if let Ok(text) = expr.utf8_text(source_code.as_bytes()) {
662 return Some(
664 text.trim_matches(|c| c == '"' || c == '\'')
665 .trim()
666 .to_owned(),
667 );
668 }
669 }
670 }
671 }
672 }
673 }
674 }
675 None
676 },
677 Language::JavaScript | Language::TypeScript => {
678 if let Some(prev_sibling) = node.prev_sibling() {
680 if prev_sibling.kind() == "comment" {
681 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
682 if text.starts_with("/**") {
683 return Some(self.clean_jsdoc(text));
684 }
685 }
686 }
687 }
688 None
689 },
690 Language::Rust => {
691 let start_byte = node.start_byte();
693 let lines_before: Vec<_> = source_code[..start_byte]
694 .lines()
695 .rev()
696 .take_while(|line| line.trim().starts_with("///") || line.trim().is_empty())
697 .collect();
698
699 if !lines_before.is_empty() {
700 let doc: Vec<String> = lines_before
701 .into_iter()
702 .rev()
703 .filter_map(|line| {
704 let trimmed = line.trim();
705 trimmed.strip_prefix("///").map(|s| s.trim().to_owned())
706 })
707 .collect();
708
709 if !doc.is_empty() {
710 return Some(doc.join(" "));
711 }
712 }
713 None
714 },
715 Language::Go => {
716 if let Some(prev_sibling) = node.prev_sibling() {
718 if prev_sibling.kind() == "comment" {
719 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
720 return Some(text.trim_start_matches("//").trim().to_owned());
721 }
722 }
723 }
724 None
725 },
726 Language::Java => {
727 if let Some(prev_sibling) = node.prev_sibling() {
729 if prev_sibling.kind() == "block_comment" {
730 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
731 if text.starts_with("/**") {
732 return Some(self.clean_javadoc(text));
733 }
734 }
735 }
736 }
737 None
738 },
739 Language::C | Language::Cpp => {
741 if let Some(prev_sibling) = node.prev_sibling() {
742 if prev_sibling.kind() == "comment" {
743 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
744 if text.starts_with("/**") || text.starts_with("/*") {
745 return Some(self.clean_jsdoc(text));
746 }
747 return Some(text.trim_start_matches("//").trim().to_owned());
748 }
749 }
750 }
751 None
752 },
753 Language::CSharp => {
755 let start_byte = node.start_byte();
756 let lines_before: Vec<_> = source_code[..start_byte]
757 .lines()
758 .rev()
759 .take_while(|line| line.trim().starts_with("///") || line.trim().is_empty())
760 .collect();
761
762 if !lines_before.is_empty() {
763 let doc: Vec<String> = lines_before
764 .into_iter()
765 .rev()
766 .filter_map(|line| {
767 let trimmed = line.trim();
768 trimmed.strip_prefix("///").map(|s| s.trim().to_owned())
769 })
770 .collect();
771
772 if !doc.is_empty() {
773 return Some(doc.join(" "));
774 }
775 }
776 None
777 },
778 Language::Ruby => {
780 if let Some(prev_sibling) = node.prev_sibling() {
781 if prev_sibling.kind() == "comment" {
782 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
783 return Some(text.trim_start_matches('#').trim().to_owned());
784 }
785 }
786 }
787 None
788 },
789 Language::Php | Language::Kotlin | Language::Swift | Language::Scala => {
791 if let Some(prev_sibling) = node.prev_sibling() {
792 let kind = prev_sibling.kind();
793 if kind == "comment" || kind == "multiline_comment" || kind == "block_comment" {
794 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
795 if text.starts_with("/**") {
796 return Some(self.clean_jsdoc(text));
797 }
798 }
799 }
800 }
801 None
802 },
803 Language::Bash => {
805 if let Some(prev_sibling) = node.prev_sibling() {
806 if prev_sibling.kind() == "comment" {
807 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
808 return Some(text.trim_start_matches('#').trim().to_owned());
809 }
810 }
811 }
812 None
813 },
814 Language::Haskell => {
816 if let Some(prev_sibling) = node.prev_sibling() {
817 if prev_sibling.kind() == "comment" {
818 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
819 let cleaned = text
820 .trim_start_matches("{-")
821 .trim_end_matches("-}")
822 .trim_start_matches("--")
823 .trim();
824 return Some(cleaned.to_owned());
825 }
826 }
827 }
828 None
829 },
830 Language::Elixir => {
832 if let Some(prev_sibling) = node.prev_sibling() {
834 if prev_sibling.kind() == "comment" {
835 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
836 return Some(text.trim_start_matches('#').trim().to_owned());
837 }
838 }
839 }
840 None
841 },
842 Language::Clojure => {
844 None
846 },
847 Language::OCaml | Language::FSharp => {
849 if let Some(prev_sibling) = node.prev_sibling() {
850 if prev_sibling.kind() == "comment" {
851 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
852 let cleaned = text
853 .trim_start_matches("(**")
854 .trim_start_matches("(*")
855 .trim_end_matches("*)")
856 .trim();
857 return Some(cleaned.to_owned());
858 }
859 }
860 }
861 None
862 },
863 Language::Lua => {
865 if let Some(prev_sibling) = node.prev_sibling() {
866 if prev_sibling.kind() == "comment" {
867 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
868 let cleaned = text
869 .trim_start_matches("--[[")
870 .trim_end_matches("]]")
871 .trim_start_matches("--")
872 .trim();
873 return Some(cleaned.to_owned());
874 }
875 }
876 }
877 None
878 },
879 Language::R => {
881 if let Some(prev_sibling) = node.prev_sibling() {
882 if prev_sibling.kind() == "comment" {
883 if let Ok(text) = prev_sibling.utf8_text(source_code.as_bytes()) {
884 return Some(text.trim_start_matches('#').trim().to_owned());
885 }
886 }
887 }
888 None
889 },
890 }
891 }
892
893 fn extract_parent(&self, node: Node<'_>, source_code: &str) -> Option<String> {
895 let mut current = node.parent()?;
896
897 while let Some(parent) = current.parent() {
898 if ["class_definition", "class_declaration", "struct_item", "impl_item"]
899 .contains(&parent.kind())
900 {
901 for child in parent.children(&mut parent.walk()) {
903 if child.kind() == "identifier" || child.kind() == "type_identifier" {
904 if let Ok(name) = child.utf8_text(source_code.as_bytes()) {
905 return Some(name.to_owned());
906 }
907 }
908 }
909 }
910 current = parent;
911 }
912
913 None
914 }
915
916 fn extract_visibility(
918 &self,
919 node: Node<'_>,
920 source_code: &str,
921 language: Language,
922 ) -> Visibility {
923 match language {
924 Language::Python => {
925 if let Some(name_node) = node.child_by_field_name("name") {
927 if let Ok(name) = name_node.utf8_text(source_code.as_bytes()) {
928 if name.starts_with("__") && !name.ends_with("__") {
929 return Visibility::Private;
930 } else if name.starts_with('_') {
931 return Visibility::Protected; }
933 }
934 }
935 Visibility::Public
936 },
937 Language::Rust => {
938 for child in node.children(&mut node.walk()) {
940 if child.kind() == "visibility_modifier" {
941 if let Ok(text) = child.utf8_text(source_code.as_bytes()) {
942 if text.contains("pub(crate)") || text.contains("pub(super)") {
943 return Visibility::Internal;
944 } else if text.starts_with("pub") {
945 return Visibility::Public;
946 }
947 }
948 }
949 }
950 Visibility::Private },
952 Language::JavaScript | Language::TypeScript => {
953 for child in node.children(&mut node.walk()) {
955 let kind = child.kind();
956 if kind == "private" || kind == "accessibility_modifier" {
957 if let Ok(text) = child.utf8_text(source_code.as_bytes()) {
958 return match text {
959 "private" => Visibility::Private,
960 "protected" => Visibility::Protected,
961 _ => Visibility::Public,
962 };
963 }
964 }
965 }
966 if let Some(name_node) = node.child_by_field_name("name") {
968 if let Ok(name) = name_node.utf8_text(source_code.as_bytes()) {
969 if name.starts_with('#') {
970 return Visibility::Private;
971 }
972 }
973 }
974 Visibility::Public
975 },
976 Language::Go => {
977 if let Some(name_node) = node.child_by_field_name("name") {
979 if let Ok(name) = name_node.utf8_text(source_code.as_bytes()) {
980 if let Some(first_char) = name.chars().next() {
981 if first_char.is_lowercase() {
982 return Visibility::Private;
983 }
984 }
985 }
986 }
987 Visibility::Public
988 },
989 Language::Java => {
990 for child in node.children(&mut node.walk()) {
992 if child.kind() == "modifiers" {
993 if let Ok(text) = child.utf8_text(source_code.as_bytes()) {
994 if text.contains("private") {
995 return Visibility::Private;
996 } else if text.contains("protected") {
997 return Visibility::Protected;
998 } else if text.contains("public") {
999 return Visibility::Public;
1000 }
1001 }
1002 }
1003 }
1004 Visibility::Internal },
1006 Language::C | Language::Cpp => {
1008 for child in node.children(&mut node.walk()) {
1009 if child.kind() == "storage_class_specifier" {
1010 if let Ok(text) = child.utf8_text(source_code.as_bytes()) {
1011 if text == "static" {
1012 return Visibility::Private;
1013 }
1014 }
1015 }
1016 }
1017 Visibility::Public
1018 },
1019 Language::CSharp | Language::Kotlin | Language::Swift | Language::Scala => {
1021 for child in node.children(&mut node.walk()) {
1022 let kind = child.kind();
1023 if kind == "modifier" || kind == "modifiers" || kind == "visibility_modifier" {
1024 if let Ok(text) = child.utf8_text(source_code.as_bytes()) {
1025 if text.contains("private") {
1026 return Visibility::Private;
1027 } else if text.contains("protected") {
1028 return Visibility::Protected;
1029 } else if text.contains("internal") {
1030 return Visibility::Internal;
1031 } else if text.contains("public") {
1032 return Visibility::Public;
1033 }
1034 }
1035 }
1036 }
1037 Visibility::Internal
1038 },
1039 Language::Ruby => {
1041 if let Some(name_node) = node.child_by_field_name("name") {
1042 if let Ok(name) = name_node.utf8_text(source_code.as_bytes()) {
1043 if name.starts_with("_") {
1044 return Visibility::Private;
1045 }
1046 }
1047 }
1048 Visibility::Public
1049 },
1050 Language::Php => {
1052 for child in node.children(&mut node.walk()) {
1053 if child.kind() == "visibility_modifier" {
1054 if let Ok(text) = child.utf8_text(source_code.as_bytes()) {
1055 return match text {
1056 "private" => Visibility::Private,
1057 "protected" => Visibility::Protected,
1058 "public" => Visibility::Public,
1059 _ => Visibility::Public,
1060 };
1061 }
1062 }
1063 }
1064 Visibility::Public
1065 },
1066 Language::Bash => Visibility::Public,
1068 Language::Haskell
1070 | Language::Elixir
1071 | Language::Clojure
1072 | Language::OCaml
1073 | Language::FSharp
1074 | Language::Lua
1075 | Language::R => Visibility::Public,
1076 }
1077 }
1078
1079 fn extract_calls(&self, node: Node<'_>, source_code: &str, language: Language) -> Vec<String> {
1081 let mut calls = HashSet::new();
1082
1083 let body_node = self.find_body_node(node, language);
1085 if let Some(body) = body_node {
1086 self.collect_calls_recursive(body, source_code, language, &mut calls);
1087 }
1088
1089 if calls.is_empty() {
1092 self.collect_calls_recursive(node, source_code, language, &mut calls);
1093 }
1094
1095 calls.into_iter().collect()
1096 }
1097
1098 fn find_body_node<'a>(&self, node: Node<'a>, language: Language) -> Option<Node<'a>> {
1100 match language {
1101 Language::Python => {
1102 for child in node.children(&mut node.walk()) {
1104 if child.kind() == "block" {
1105 return Some(child);
1106 }
1107 }
1108 },
1109 Language::Rust => {
1110 for child in node.children(&mut node.walk()) {
1112 if child.kind() == "block" {
1113 return Some(child);
1114 }
1115 }
1116 },
1117 Language::JavaScript | Language::TypeScript => {
1118 for child in node.children(&mut node.walk()) {
1120 let kind = child.kind();
1121 if kind == "statement_block" {
1122 return Some(child);
1123 }
1124 if kind == "arrow_function" {
1126 if let Some(body) = self.find_body_node(child, language) {
1128 return Some(body);
1129 }
1130 return Some(child);
1132 }
1133 }
1134 if node.kind() == "arrow_function" {
1137 for child in node.children(&mut node.walk()) {
1138 let kind = child.kind();
1140 if kind != "formal_parameters"
1141 && kind != "identifier"
1142 && kind != "=>"
1143 && kind != "("
1144 && kind != ")"
1145 && kind != ","
1146 {
1147 return Some(child);
1148 }
1149 }
1150 return Some(node);
1151 }
1152 },
1153 Language::Go => {
1154 for child in node.children(&mut node.walk()) {
1156 if child.kind() == "block" {
1157 return Some(child);
1158 }
1159 }
1160 },
1161 Language::Java => {
1162 for child in node.children(&mut node.walk()) {
1164 if child.kind() == "block" {
1165 return Some(child);
1166 }
1167 }
1168 },
1169 Language::C | Language::Cpp => {
1171 for child in node.children(&mut node.walk()) {
1172 if child.kind() == "compound_statement" {
1173 return Some(child);
1174 }
1175 }
1176 },
1177 Language::CSharp
1179 | Language::Php
1180 | Language::Kotlin
1181 | Language::Swift
1182 | Language::Scala => {
1183 for child in node.children(&mut node.walk()) {
1184 let kind = child.kind();
1185 if kind == "block" || kind == "compound_statement" || kind == "function_body" {
1186 return Some(child);
1187 }
1188 }
1189 },
1190 Language::Ruby => {
1192 for child in node.children(&mut node.walk()) {
1193 if child.kind() == "body_statement" || child.kind() == "do_block" {
1194 return Some(child);
1195 }
1196 }
1197 },
1198 Language::Bash => {
1200 for child in node.children(&mut node.walk()) {
1201 if child.kind() == "compound_statement" {
1202 return Some(child);
1203 }
1204 }
1205 },
1206 Language::Haskell
1208 | Language::Elixir
1209 | Language::Clojure
1210 | Language::OCaml
1211 | Language::FSharp
1212 | Language::R => {
1213 return Some(node);
1215 },
1216 Language::Lua => {
1218 for child in node.children(&mut node.walk()) {
1219 if child.kind() == "block" {
1220 return Some(child);
1221 }
1222 }
1223 },
1224 }
1225 None
1226 }
1227
1228 #[allow(clippy::only_used_in_recursion)]
1230 fn collect_calls_recursive(
1231 &self,
1232 node: Node<'_>,
1233 source_code: &str,
1234 language: Language,
1235 calls: &mut HashSet<String>,
1236 ) {
1237 let kind = node.kind();
1238
1239 let call_name = match language {
1241 Language::Python => {
1242 if kind == "call" {
1243 node.child_by_field_name("function").and_then(|f| {
1245 if f.kind() == "identifier" {
1246 f.utf8_text(source_code.as_bytes()).ok().map(String::from)
1247 } else if f.kind() == "attribute" {
1248 f.child_by_field_name("attribute")
1250 .and_then(|a| a.utf8_text(source_code.as_bytes()).ok())
1251 .map(String::from)
1252 } else {
1253 None
1254 }
1255 })
1256 } else {
1257 None
1258 }
1259 },
1260 Language::Rust => {
1261 if kind == "call_expression" {
1262 node.child_by_field_name("function").and_then(|f| {
1264 if f.kind() == "identifier" {
1265 f.utf8_text(source_code.as_bytes()).ok().map(String::from)
1266 } else if f.kind() == "field_expression" {
1267 f.child_by_field_name("field")
1269 .and_then(|a| a.utf8_text(source_code.as_bytes()).ok())
1270 .map(String::from)
1271 } else if f.kind() == "scoped_identifier" {
1272 f.utf8_text(source_code.as_bytes()).ok().map(String::from)
1274 } else {
1275 None
1276 }
1277 })
1278 } else if kind == "macro_invocation" {
1279 node.child_by_field_name("macro")
1281 .and_then(|m| m.utf8_text(source_code.as_bytes()).ok())
1282 .map(|s| format!("{}!", s))
1283 } else {
1284 None
1285 }
1286 },
1287 Language::JavaScript | Language::TypeScript => {
1288 if kind == "call_expression" {
1289 node.child_by_field_name("function").and_then(|f| {
1291 if f.kind() == "identifier" {
1292 f.utf8_text(source_code.as_bytes()).ok().map(String::from)
1293 } else if f.kind() == "member_expression" {
1294 f.child_by_field_name("property")
1296 .and_then(|p| p.utf8_text(source_code.as_bytes()).ok())
1297 .map(String::from)
1298 } else {
1299 None
1300 }
1301 })
1302 } else {
1303 None
1304 }
1305 },
1306 Language::Go => {
1307 if kind == "call_expression" {
1308 node.child_by_field_name("function").and_then(|f| {
1310 if f.kind() == "identifier" {
1311 f.utf8_text(source_code.as_bytes()).ok().map(String::from)
1312 } else if f.kind() == "selector_expression" {
1313 f.child_by_field_name("field")
1315 .and_then(|a| a.utf8_text(source_code.as_bytes()).ok())
1316 .map(String::from)
1317 } else {
1318 None
1319 }
1320 })
1321 } else {
1322 None
1323 }
1324 },
1325 Language::Java => {
1326 if kind == "method_invocation" {
1327 node.child_by_field_name("name")
1329 .and_then(|n| n.utf8_text(source_code.as_bytes()).ok())
1330 .map(String::from)
1331 } else {
1332 None
1333 }
1334 },
1335 Language::C | Language::Cpp => {
1337 if kind == "call_expression" {
1338 node.child_by_field_name("function").and_then(|f| {
1339 if f.kind() == "identifier" {
1340 f.utf8_text(source_code.as_bytes()).ok().map(String::from)
1341 } else if f.kind() == "field_expression" {
1342 f.child_by_field_name("field")
1343 .and_then(|a| a.utf8_text(source_code.as_bytes()).ok())
1344 .map(String::from)
1345 } else {
1346 None
1347 }
1348 })
1349 } else {
1350 None
1351 }
1352 },
1353 Language::CSharp | Language::Kotlin | Language::Swift | Language::Scala => {
1355 if kind == "invocation_expression"
1356 || kind == "call_expression"
1357 || kind == "method_invocation"
1358 {
1359 node.child_by_field_name("function")
1360 .or_else(|| node.child_by_field_name("name"))
1361 .and_then(|f| {
1362 if f.kind() == "identifier" || f.kind() == "simple_identifier" {
1363 f.utf8_text(source_code.as_bytes()).ok().map(String::from)
1364 } else if f.kind() == "member_access_expression"
1365 || f.kind() == "member_expression"
1366 {
1367 f.child_by_field_name("name")
1368 .and_then(|n| n.utf8_text(source_code.as_bytes()).ok())
1369 .map(String::from)
1370 } else {
1371 None
1372 }
1373 })
1374 } else {
1375 None
1376 }
1377 },
1378 Language::Ruby => {
1380 if kind == "call" || kind == "method_call" {
1381 node.child_by_field_name("method")
1382 .and_then(|m| m.utf8_text(source_code.as_bytes()).ok())
1383 .map(String::from)
1384 } else {
1385 None
1386 }
1387 },
1388 Language::Php => {
1390 if kind == "function_call_expression" || kind == "method_call_expression" {
1391 node.child_by_field_name("function")
1392 .or_else(|| node.child_by_field_name("name"))
1393 .and_then(|f| f.utf8_text(source_code.as_bytes()).ok())
1394 .map(String::from)
1395 } else {
1396 None
1397 }
1398 },
1399 Language::Bash => {
1401 if kind == "command" {
1402 node.child_by_field_name("name")
1403 .and_then(|n| n.utf8_text(source_code.as_bytes()).ok())
1404 .map(String::from)
1405 } else {
1406 None
1407 }
1408 },
1409 Language::Haskell
1411 | Language::Elixir
1412 | Language::Clojure
1413 | Language::OCaml
1414 | Language::FSharp
1415 | Language::Lua
1416 | Language::R => {
1417 if kind == "application" || kind == "call" || kind == "function_call" {
1418 node.child(0).and_then(|c| {
1420 if c.kind() == "identifier" || c.kind() == "variable" {
1421 c.utf8_text(source_code.as_bytes()).ok().map(String::from)
1422 } else {
1423 None
1424 }
1425 })
1426 } else {
1427 None
1428 }
1429 },
1430 };
1431
1432 if let Some(name) = call_name {
1433 if name.len() > 1 && !Self::is_builtin(&name, language) {
1435 calls.insert(name);
1436 }
1437 }
1438
1439 for child in node.children(&mut node.walk()) {
1441 self.collect_calls_recursive(child, source_code, language, calls);
1442 }
1443 }
1444
1445 fn is_builtin(name: &str, language: Language) -> bool {
1447 match language {
1448 Language::Python => {
1449 matches!(
1450 name,
1451 "print"
1452 | "len"
1453 | "range"
1454 | "str"
1455 | "int"
1456 | "float"
1457 | "list"
1458 | "dict"
1459 | "set"
1460 | "tuple"
1461 | "bool"
1462 | "type"
1463 | "isinstance"
1464 | "hasattr"
1465 | "getattr"
1466 | "setattr"
1467 | "super"
1468 | "iter"
1469 | "next"
1470 | "open"
1471 | "input"
1472 | "format"
1473 | "enumerate"
1474 | "zip"
1475 | "map"
1476 | "filter"
1477 | "sorted"
1478 | "reversed"
1479 | "sum"
1480 | "min"
1481 | "max"
1482 | "abs"
1483 | "round"
1484 | "ord"
1485 | "chr"
1486 | "hex"
1487 | "bin"
1488 | "oct"
1489 )
1490 },
1491 Language::JavaScript | Language::TypeScript => {
1492 matches!(
1493 name,
1494 "console"
1495 | "log"
1496 | "error"
1497 | "warn"
1498 | "parseInt"
1499 | "parseFloat"
1500 | "setTimeout"
1501 | "setInterval"
1502 | "clearTimeout"
1503 | "clearInterval"
1504 | "JSON"
1505 | "stringify"
1506 | "parse"
1507 | "toString"
1508 | "valueOf"
1509 | "push"
1510 | "pop"
1511 | "shift"
1512 | "unshift"
1513 | "slice"
1514 | "splice"
1515 | "map"
1516 | "filter"
1517 | "reduce"
1518 | "forEach"
1519 | "find"
1520 | "findIndex"
1521 | "includes"
1522 | "indexOf"
1523 | "join"
1524 | "split"
1525 | "replace"
1526 )
1527 },
1528 Language::Rust => {
1529 matches!(
1530 name,
1531 "println!"
1532 | "print!"
1533 | "eprintln!"
1534 | "eprint!"
1535 | "format!"
1536 | "vec!"
1537 | "panic!"
1538 | "assert!"
1539 | "assert_eq!"
1540 | "assert_ne!"
1541 | "debug!"
1542 | "info!"
1543 | "warn!"
1544 | "error!"
1545 | "trace!"
1546 | "unwrap"
1547 | "expect"
1548 | "ok"
1549 | "err"
1550 | "some"
1551 | "none"
1552 | "clone"
1553 | "to_string"
1554 | "into"
1555 | "from"
1556 | "default"
1557 | "iter"
1558 | "into_iter"
1559 | "collect"
1560 | "map"
1561 | "filter"
1562 )
1563 },
1564 Language::Go => {
1565 matches!(
1566 name,
1567 "fmt"
1568 | "Println"
1569 | "Printf"
1570 | "Sprintf"
1571 | "Errorf"
1572 | "make"
1573 | "new"
1574 | "len"
1575 | "cap"
1576 | "append"
1577 | "copy"
1578 | "delete"
1579 | "close"
1580 | "panic"
1581 | "recover"
1582 | "print"
1583 )
1584 },
1585 Language::Java => {
1586 matches!(
1587 name,
1588 "println"
1589 | "print"
1590 | "printf"
1591 | "toString"
1592 | "equals"
1593 | "hashCode"
1594 | "getClass"
1595 | "clone"
1596 | "notify"
1597 | "wait"
1598 | "get"
1599 | "set"
1600 | "add"
1601 | "remove"
1602 | "size"
1603 | "isEmpty"
1604 | "contains"
1605 | "iterator"
1606 | "valueOf"
1607 | "parseInt"
1608 )
1609 },
1610 Language::C | Language::Cpp => {
1611 matches!(
1612 name,
1613 "printf"
1614 | "scanf"
1615 | "malloc"
1616 | "free"
1617 | "memcpy"
1618 | "memset"
1619 | "strlen"
1620 | "strcpy"
1621 | "strcmp"
1622 | "strcat"
1623 | "sizeof"
1624 | "cout"
1625 | "cin"
1626 | "endl"
1627 | "cerr"
1628 | "clog"
1629 )
1630 },
1631 Language::CSharp => {
1632 matches!(
1633 name,
1634 "WriteLine"
1635 | "Write"
1636 | "ReadLine"
1637 | "ToString"
1638 | "Equals"
1639 | "GetHashCode"
1640 | "GetType"
1641 | "Add"
1642 | "Remove"
1643 | "Contains"
1644 | "Count"
1645 | "Clear"
1646 | "ToList"
1647 | "ToArray"
1648 )
1649 },
1650 Language::Ruby => {
1651 matches!(
1652 name,
1653 "puts"
1654 | "print"
1655 | "p"
1656 | "gets"
1657 | "each"
1658 | "map"
1659 | "select"
1660 | "reject"
1661 | "reduce"
1662 | "inject"
1663 | "find"
1664 | "any?"
1665 | "all?"
1666 | "include?"
1667 | "empty?"
1668 | "nil?"
1669 | "length"
1670 | "size"
1671 )
1672 },
1673 Language::Php => {
1674 matches!(
1675 name,
1676 "echo"
1677 | "print"
1678 | "var_dump"
1679 | "print_r"
1680 | "isset"
1681 | "empty"
1682 | "array"
1683 | "count"
1684 | "strlen"
1685 | "strpos"
1686 | "substr"
1687 | "explode"
1688 | "implode"
1689 | "json_encode"
1690 | "json_decode"
1691 )
1692 },
1693 Language::Kotlin => {
1694 matches!(
1695 name,
1696 "println"
1697 | "print"
1698 | "readLine"
1699 | "toString"
1700 | "equals"
1701 | "hashCode"
1702 | "map"
1703 | "filter"
1704 | "forEach"
1705 | "let"
1706 | "also"
1707 | "apply"
1708 | "run"
1709 | "with"
1710 | "listOf"
1711 | "mapOf"
1712 | "setOf"
1713 )
1714 },
1715 Language::Swift => {
1716 matches!(
1717 name,
1718 "print"
1719 | "debugPrint"
1720 | "dump"
1721 | "map"
1722 | "filter"
1723 | "reduce"
1724 | "forEach"
1725 | "contains"
1726 | "count"
1727 | "isEmpty"
1728 | "append"
1729 )
1730 },
1731 Language::Scala => {
1732 matches!(
1733 name,
1734 "println"
1735 | "print"
1736 | "map"
1737 | "filter"
1738 | "flatMap"
1739 | "foreach"
1740 | "reduce"
1741 | "fold"
1742 | "foldLeft"
1743 | "foldRight"
1744 | "collect"
1745 )
1746 },
1747 Language::Bash
1749 | Language::Haskell
1750 | Language::Elixir
1751 | Language::Clojure
1752 | Language::OCaml
1753 | Language::FSharp
1754 | Language::Lua
1755 | Language::R => false,
1756 }
1757 }
1758
1759 fn clean_jsdoc(&self, text: &str) -> String {
1761 text.lines()
1762 .map(|line| {
1763 line.trim()
1764 .trim_start_matches("/**")
1765 .trim_start_matches("/*")
1766 .trim_start_matches('*')
1767 .trim_end_matches("*/")
1768 .trim()
1769 })
1770 .filter(|line| !line.is_empty())
1771 .collect::<Vec<_>>()
1772 .join(" ")
1773 }
1774
1775 fn clean_javadoc(&self, text: &str) -> String {
1777 self.clean_jsdoc(text) }
1779
1780 fn extract_inheritance(
1783 &self,
1784 node: Node<'_>,
1785 source_code: &str,
1786 language: Language,
1787 ) -> (Option<String>, Vec<String>) {
1788 let mut extends = None;
1789 let mut implements = Vec::new();
1790
1791 match language {
1792 Language::Python => {
1793 if node.kind() == "class_definition" {
1795 if let Some(args) = node.child_by_field_name("superclasses") {
1796 let mut first = true;
1797 for child in args.children(&mut args.walk()) {
1798 if child.kind() == "identifier" || child.kind() == "attribute" {
1799 if let Ok(name) = child.utf8_text(source_code.as_bytes()) {
1800 if first {
1801 extends = Some(name.to_owned());
1802 first = false;
1803 } else {
1804 implements.push(name.to_owned());
1805 }
1806 }
1807 }
1808 }
1809 }
1810 }
1811 },
1812 Language::JavaScript | Language::TypeScript => {
1813 if node.kind() == "class_declaration" {
1815 for child in node.children(&mut node.walk()) {
1817 if child.kind() == "class_heritage" {
1818 for heritage in child.children(&mut child.walk()) {
1819 if heritage.kind() == "extends_clause" {
1820 for ext_child in heritage.children(&mut heritage.walk()) {
1822 if ext_child.kind() == "identifier"
1823 || ext_child.kind() == "type_identifier"
1824 {
1825 if let Ok(name) =
1826 ext_child.utf8_text(source_code.as_bytes())
1827 {
1828 extends = Some(name.to_owned());
1829 }
1830 }
1831 }
1832 } else if heritage.kind() == "implements_clause" {
1833 for impl_child in heritage.children(&mut heritage.walk()) {
1835 if impl_child.kind() == "type_identifier"
1836 || impl_child.kind() == "identifier"
1837 {
1838 if let Ok(name) =
1839 impl_child.utf8_text(source_code.as_bytes())
1840 {
1841 implements.push(name.to_owned());
1842 }
1843 }
1844 }
1845 }
1846 }
1847 }
1848 }
1849 }
1850 },
1851 Language::Java => {
1852 if node.kind() == "class_declaration" {
1854 if let Some(superclass) = node.child_by_field_name("superclass") {
1855 if let Ok(name) = superclass.utf8_text(source_code.as_bytes()) {
1856 extends = Some(name.trim_start_matches("extends ").trim().to_owned());
1857 }
1858 }
1859 if let Some(interfaces) = node.child_by_field_name("interfaces") {
1860 for child in interfaces.children(&mut interfaces.walk()) {
1861 if child.kind() == "type_identifier" {
1862 if let Ok(name) = child.utf8_text(source_code.as_bytes()) {
1863 implements.push(name.to_owned());
1864 }
1865 }
1866 }
1867 }
1868 }
1869 },
1870 Language::Rust => {
1871 },
1875 Language::Go => {
1876 if node.kind() == "type_declaration" {
1879 for child in node.children(&mut node.walk()) {
1880 if child.kind() == "type_spec" {
1881 for spec_child in child.children(&mut child.walk()) {
1883 if spec_child.kind() == "struct_type" {
1884 for field in spec_child.children(&mut spec_child.walk()) {
1885 if field.kind() == "field_declaration" {
1886 let has_name =
1888 field.child_by_field_name("name").is_some();
1889 if !has_name {
1890 if let Some(type_node) =
1891 field.child_by_field_name("type")
1892 {
1893 if let Ok(name) =
1894 type_node.utf8_text(source_code.as_bytes())
1895 {
1896 implements.push(name.to_owned());
1897 }
1898 }
1899 }
1900 }
1901 }
1902 }
1903 }
1904 }
1905 }
1906 }
1907 },
1908 Language::Cpp => {
1909 if node.kind() == "class_specifier" {
1911 for child in node.children(&mut node.walk()) {
1912 if child.kind() == "base_class_clause" {
1913 let mut first = true;
1914 for base in child.children(&mut child.walk()) {
1915 if base.kind() == "type_identifier" {
1916 if let Ok(name) = base.utf8_text(source_code.as_bytes()) {
1917 if first {
1918 extends = Some(name.to_owned());
1919 first = false;
1920 } else {
1921 implements.push(name.to_owned());
1922 }
1923 }
1924 }
1925 }
1926 }
1927 }
1928 }
1929 },
1930 Language::CSharp => {
1931 if node.kind() == "class_declaration" {
1933 if let Some(base_list) = node.child_by_field_name("bases") {
1934 let mut first = true;
1935 for child in base_list.children(&mut base_list.walk()) {
1936 if child.kind() == "identifier" || child.kind() == "generic_name" {
1937 if let Ok(name) = child.utf8_text(source_code.as_bytes()) {
1938 if first && !name.starts_with('I') {
1940 extends = Some(name.to_owned());
1941 first = false;
1942 } else {
1943 implements.push(name.to_owned());
1944 }
1945 }
1946 }
1947 }
1948 }
1949 }
1950 },
1951 Language::Ruby => {
1952 if node.kind() == "class" {
1954 if let Some(superclass) = node.child_by_field_name("superclass") {
1955 if let Ok(name) = superclass.utf8_text(source_code.as_bytes()) {
1956 extends = Some(name.to_owned());
1957 }
1958 }
1959 }
1960 },
1961 Language::Kotlin => {
1962 if node.kind() == "class_declaration" {
1964 for child in node.children(&mut node.walk()) {
1965 if child.kind() == "delegation_specifiers" {
1966 let mut first = true;
1967 for spec in child.children(&mut child.walk()) {
1968 if spec.kind() == "delegation_specifier" {
1969 if let Ok(name) = spec.utf8_text(source_code.as_bytes()) {
1970 let clean_name =
1972 name.split('(').next().unwrap_or(name).trim();
1973 if first {
1974 extends = Some(clean_name.to_owned());
1975 first = false;
1976 } else {
1977 implements.push(clean_name.to_owned());
1978 }
1979 }
1980 }
1981 }
1982 }
1983 }
1984 }
1985 },
1986 Language::Swift => {
1987 if node.kind() == "class_declaration" {
1989 for child in node.children(&mut node.walk()) {
1990 if child.kind() == "type_inheritance_clause" {
1991 let mut first = true;
1992 for type_child in child.children(&mut child.walk()) {
1993 if type_child.kind() == "type_identifier" {
1994 if let Ok(name) = type_child.utf8_text(source_code.as_bytes()) {
1995 if first {
1996 extends = Some(name.to_owned());
1997 first = false;
1998 } else {
1999 implements.push(name.to_owned());
2000 }
2001 }
2002 }
2003 }
2004 }
2005 }
2006 }
2007 },
2008 Language::Scala => {
2009 if node.kind() == "class_definition" {
2011 for child in node.children(&mut node.walk()) {
2012 if child.kind() == "extends_clause" {
2013 if let Ok(name) = child.utf8_text(source_code.as_bytes()) {
2014 let text = name.trim_start_matches("extends").trim();
2016 let parts: Vec<&str> = text.split(" with ").collect();
2017 if let Some(base) = parts.first() {
2018 extends = Some(base.trim().to_owned());
2019 }
2020 for trait_name in parts.iter().skip(1) {
2021 implements.push(trait_name.trim().to_owned());
2022 }
2023 }
2024 }
2025 }
2026 }
2027 },
2028 Language::C
2030 | Language::Bash
2031 | Language::Php
2032 | Language::Haskell
2033 | Language::Elixir
2034 | Language::Clojure
2035 | Language::OCaml
2036 | Language::FSharp
2037 | Language::Lua
2038 | Language::R => {},
2039 }
2040
2041 (extends, implements)
2042 }
2043
2044 fn init_python_parser() -> Result<TSParser, ParserError> {
2047 let mut parser = TSParser::new();
2048 parser
2049 .set_language(&tree_sitter_python::LANGUAGE.into())
2050 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2051 Ok(parser)
2052 }
2053
2054 fn init_javascript_parser() -> Result<TSParser, ParserError> {
2055 let mut parser = TSParser::new();
2056 parser
2057 .set_language(&tree_sitter_javascript::LANGUAGE.into())
2058 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2059 Ok(parser)
2060 }
2061
2062 fn init_typescript_parser() -> Result<TSParser, ParserError> {
2063 let mut parser = TSParser::new();
2064 parser
2065 .set_language(&tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into())
2066 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2067 Ok(parser)
2068 }
2069
2070 fn init_rust_parser() -> Result<TSParser, ParserError> {
2071 let mut parser = TSParser::new();
2072 parser
2073 .set_language(&tree_sitter_rust::LANGUAGE.into())
2074 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2075 Ok(parser)
2076 }
2077
2078 fn init_go_parser() -> Result<TSParser, ParserError> {
2079 let mut parser = TSParser::new();
2080 parser
2081 .set_language(&tree_sitter_go::LANGUAGE.into())
2082 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2083 Ok(parser)
2084 }
2085
2086 fn init_java_parser() -> Result<TSParser, ParserError> {
2087 let mut parser = TSParser::new();
2088 parser
2089 .set_language(&tree_sitter_java::LANGUAGE.into())
2090 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2091 Ok(parser)
2092 }
2093
2094 fn init_c_parser() -> Result<TSParser, ParserError> {
2095 let mut parser = TSParser::new();
2096 parser
2097 .set_language(&tree_sitter_c::LANGUAGE.into())
2098 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2099 Ok(parser)
2100 }
2101
2102 fn init_cpp_parser() -> Result<TSParser, ParserError> {
2103 let mut parser = TSParser::new();
2104 parser
2105 .set_language(&tree_sitter_cpp::LANGUAGE.into())
2106 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2107 Ok(parser)
2108 }
2109
2110 fn init_csharp_parser() -> Result<TSParser, ParserError> {
2111 let mut parser = TSParser::new();
2112 parser
2113 .set_language(&tree_sitter_c_sharp::LANGUAGE.into())
2114 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2115 Ok(parser)
2116 }
2117
2118 fn init_ruby_parser() -> Result<TSParser, ParserError> {
2119 let mut parser = TSParser::new();
2120 parser
2121 .set_language(&tree_sitter_ruby::LANGUAGE.into())
2122 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2123 Ok(parser)
2124 }
2125
2126 fn init_bash_parser() -> Result<TSParser, ParserError> {
2127 let mut parser = TSParser::new();
2128 parser
2129 .set_language(&tree_sitter_bash::LANGUAGE.into())
2130 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2131 Ok(parser)
2132 }
2133
2134 fn init_php_parser() -> Result<TSParser, ParserError> {
2135 let mut parser = TSParser::new();
2136 parser
2137 .set_language(&tree_sitter_php::LANGUAGE_PHP.into())
2138 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2139 Ok(parser)
2140 }
2141
2142 fn init_kotlin_parser() -> Result<TSParser, ParserError> {
2143 let mut parser = TSParser::new();
2144 parser
2145 .set_language(&tree_sitter_kotlin_ng::LANGUAGE.into())
2146 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2147 Ok(parser)
2148 }
2149
2150 fn init_swift_parser() -> Result<TSParser, ParserError> {
2151 let mut parser = TSParser::new();
2152 parser
2153 .set_language(&tree_sitter_swift::LANGUAGE.into())
2154 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2155 Ok(parser)
2156 }
2157
2158 fn init_scala_parser() -> Result<TSParser, ParserError> {
2159 let mut parser = TSParser::new();
2160 parser
2161 .set_language(&tree_sitter_scala::LANGUAGE.into())
2162 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2163 Ok(parser)
2164 }
2165
2166 fn init_haskell_parser() -> Result<TSParser, ParserError> {
2167 let mut parser = TSParser::new();
2168 parser
2169 .set_language(&tree_sitter_haskell::LANGUAGE.into())
2170 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2171 Ok(parser)
2172 }
2173
2174 fn init_elixir_parser() -> Result<TSParser, ParserError> {
2175 let mut parser = TSParser::new();
2176 parser
2177 .set_language(&tree_sitter_elixir::LANGUAGE.into())
2178 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2179 Ok(parser)
2180 }
2181
2182 fn init_clojure_parser() -> Result<TSParser, ParserError> {
2183 let mut parser = TSParser::new();
2184 parser
2185 .set_language(&tree_sitter_clojure::LANGUAGE.into())
2186 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2187 Ok(parser)
2188 }
2189
2190 fn init_ocaml_parser() -> Result<TSParser, ParserError> {
2191 let mut parser = TSParser::new();
2192 parser
2193 .set_language(&tree_sitter_ocaml::LANGUAGE_OCAML.into())
2194 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2195 Ok(parser)
2196 }
2197
2198 fn init_lua_parser() -> Result<TSParser, ParserError> {
2199 let mut parser = TSParser::new();
2200 parser
2201 .set_language(&tree_sitter_lua::LANGUAGE.into())
2202 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2203 Ok(parser)
2204 }
2205
2206 fn init_r_parser() -> Result<TSParser, ParserError> {
2207 let mut parser = TSParser::new();
2208 parser
2209 .set_language(&tree_sitter_r::LANGUAGE.into())
2210 .map_err(|e| ParserError::ParseError(e.to_string()))?;
2211 Ok(parser)
2212 }
2213
2214 fn python_query() -> Result<Query, ParserError> {
2217 let query_string = r#"
2218 (function_definition
2219 name: (identifier) @name) @function
2220
2221 (class_definition
2222 name: (identifier) @name) @class
2223
2224 (class_definition
2225 body: (block
2226 (function_definition
2227 name: (identifier) @name))) @method
2228 "#;
2229
2230 Query::new(&tree_sitter_python::LANGUAGE.into(), query_string)
2231 .map_err(|e| ParserError::QueryError(e.to_string()))
2232 }
2233
2234 fn javascript_query() -> Result<Query, ParserError> {
2235 let query_string = r#"
2236 (function_declaration
2237 name: (_) @name) @function
2238
2239 (class_declaration
2240 name: (_) @name) @class
2241
2242 (method_definition
2243 name: (property_identifier) @name) @method
2244
2245 (arrow_function) @function
2246
2247 (function_expression) @function
2248 "#;
2249
2250 Query::new(&tree_sitter_javascript::LANGUAGE.into(), query_string)
2251 .map_err(|e| ParserError::QueryError(e.to_string()))
2252 }
2253
2254 fn typescript_query() -> Result<Query, ParserError> {
2255 let query_string = r#"
2256 (function_declaration
2257 name: (identifier) @name) @function
2258
2259 (class_declaration
2260 name: (type_identifier) @name) @class
2261
2262 (interface_declaration
2263 name: (type_identifier) @name) @interface
2264
2265 (method_definition
2266 name: (property_identifier) @name) @method
2267
2268 (enum_declaration
2269 name: (identifier) @name) @enum
2270
2271 ; Arrow functions (named via variable) - Bug #1 fix
2272 (lexical_declaration
2273 (variable_declarator
2274 name: (identifier) @name
2275 value: (arrow_function))) @function
2276 "#;
2277
2278 Query::new(&tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into(), query_string)
2279 .map_err(|e| ParserError::QueryError(e.to_string()))
2280 }
2281
2282 fn rust_query() -> Result<Query, ParserError> {
2283 let query_string = r#"
2284 (function_item
2285 name: (identifier) @name) @function
2286
2287 (struct_item
2288 name: (type_identifier) @name) @struct
2289
2290 (enum_item
2291 name: (type_identifier) @name) @enum
2292
2293 (trait_item
2294 name: (type_identifier) @name) @trait
2295 "#;
2296
2297 Query::new(&tree_sitter_rust::LANGUAGE.into(), query_string)
2298 .map_err(|e| ParserError::QueryError(e.to_string()))
2299 }
2300
2301 fn go_query() -> Result<Query, ParserError> {
2302 let query_string = r#"
2303 (function_declaration
2304 name: (identifier) @name) @function
2305
2306 (method_declaration
2307 name: (field_identifier) @name) @method
2308
2309 (type_declaration
2310 (type_spec
2311 name: (type_identifier) @name
2312 type: (struct_type))) @struct
2313
2314 (type_declaration
2315 (type_spec
2316 name: (type_identifier) @name
2317 type: (interface_type))) @interface
2318 "#;
2319
2320 Query::new(&tree_sitter_go::LANGUAGE.into(), query_string)
2321 .map_err(|e| ParserError::QueryError(e.to_string()))
2322 }
2323
2324 fn java_query() -> Result<Query, ParserError> {
2325 let query_string = r#"
2326 (method_declaration
2327 name: (identifier) @name) @method
2328
2329 (class_declaration
2330 name: (identifier) @name) @class
2331
2332 (interface_declaration
2333 name: (identifier) @name) @interface
2334
2335 (enum_declaration
2336 name: (identifier) @name) @enum
2337 "#;
2338
2339 Query::new(&tree_sitter_java::LANGUAGE.into(), query_string)
2340 .map_err(|e| ParserError::QueryError(e.to_string()))
2341 }
2342
2343 fn python_super_query() -> Result<Query, ParserError> {
2348 let query_string = r#"
2349 ; Functions
2350 (function_definition
2351 name: (identifier) @name) @function
2352
2353 ; Classes
2354 (class_definition
2355 name: (identifier) @name) @class
2356
2357 ; Methods inside classes
2358 (class_definition
2359 body: (block
2360 (function_definition
2361 name: (identifier) @name))) @method
2362
2363 ; Imports
2364 (import_statement) @import
2365 (import_from_statement) @import
2366 "#;
2367
2368 Query::new(&tree_sitter_python::LANGUAGE.into(), query_string)
2369 .map_err(|e| ParserError::QueryError(e.to_string()))
2370 }
2371
2372 fn javascript_super_query() -> Result<Query, ParserError> {
2373 let query_string = r#"
2374 ; Functions
2375 (function_declaration
2376 name: (identifier) @name) @function
2377
2378 ; Classes
2379 (class_declaration
2380 name: (identifier) @name) @class
2381
2382 ; Methods
2383 (method_definition
2384 name: (property_identifier) @name) @method
2385
2386 ; Arrow functions (named via variable)
2387 (lexical_declaration
2388 (variable_declarator
2389 name: (identifier) @name
2390 value: (arrow_function))) @function
2391
2392 ; Imports
2393 (import_statement) @import
2394 "#;
2395
2396 Query::new(&tree_sitter_javascript::LANGUAGE.into(), query_string)
2397 .map_err(|e| ParserError::QueryError(e.to_string()))
2398 }
2399
2400 fn typescript_super_query() -> Result<Query, ParserError> {
2401 let query_string = r#"
2402 ; Functions
2403 (function_declaration
2404 name: (identifier) @name) @function
2405
2406 ; Classes
2407 (class_declaration
2408 name: (type_identifier) @name) @class
2409
2410 ; Interfaces
2411 (interface_declaration
2412 name: (type_identifier) @name) @interface
2413
2414 ; Methods
2415 (method_definition
2416 name: (property_identifier) @name) @method
2417
2418 ; Enums
2419 (enum_declaration
2420 name: (identifier) @name) @enum
2421
2422 ; Arrow functions (named via variable) - Bug #1 fix
2423 (lexical_declaration
2424 (variable_declarator
2425 name: (identifier) @name
2426 value: (arrow_function))) @function
2427
2428 ; Arrow functions (exported)
2429 (export_statement
2430 declaration: (lexical_declaration
2431 (variable_declarator
2432 name: (identifier) @name
2433 value: (arrow_function)))) @function
2434
2435 ; Type aliases
2436 (type_alias_declaration
2437 name: (type_identifier) @name) @struct
2438
2439 ; Imports
2440 (import_statement) @import
2441
2442 ; Exports (re-exports)
2443 (export_statement) @export
2444 "#;
2445
2446 Query::new(&tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into(), query_string)
2447 .map_err(|e| ParserError::QueryError(e.to_string()))
2448 }
2449
2450 fn rust_super_query() -> Result<Query, ParserError> {
2451 let query_string = r#"
2452 ; Functions
2453 (function_item
2454 name: (identifier) @name) @function
2455
2456 ; Structs
2457 (struct_item
2458 name: (type_identifier) @name) @struct
2459
2460 ; Enums
2461 (enum_item
2462 name: (type_identifier) @name) @enum
2463
2464 ; Traits
2465 (trait_item
2466 name: (type_identifier) @name) @trait
2467
2468 ; Use statements (imports)
2469 (use_declaration) @import
2470 "#;
2471
2472 Query::new(&tree_sitter_rust::LANGUAGE.into(), query_string)
2473 .map_err(|e| ParserError::QueryError(e.to_string()))
2474 }
2475
2476 fn go_super_query() -> Result<Query, ParserError> {
2477 let query_string = r#"
2478 ; Functions
2479 (function_declaration
2480 name: (identifier) @name) @function
2481
2482 ; Methods
2483 (method_declaration
2484 name: (field_identifier) @name) @method
2485
2486 ; Structs
2487 (type_declaration
2488 (type_spec
2489 name: (type_identifier) @name
2490 type: (struct_type))) @struct
2491
2492 ; Interfaces
2493 (type_declaration
2494 (type_spec
2495 name: (type_identifier) @name
2496 type: (interface_type))) @interface
2497
2498 ; Imports
2499 (import_declaration) @import
2500 "#;
2501
2502 Query::new(&tree_sitter_go::LANGUAGE.into(), query_string)
2503 .map_err(|e| ParserError::QueryError(e.to_string()))
2504 }
2505
2506 fn java_super_query() -> Result<Query, ParserError> {
2507 let query_string = r#"
2508 ; Methods
2509 (method_declaration
2510 name: (identifier) @name) @method
2511
2512 ; Classes
2513 (class_declaration
2514 name: (identifier) @name) @class
2515
2516 ; Interfaces
2517 (interface_declaration
2518 name: (identifier) @name) @interface
2519
2520 ; Enums
2521 (enum_declaration
2522 name: (identifier) @name) @enum
2523
2524 ; Imports
2525 (import_declaration) @import
2526 "#;
2527
2528 Query::new(&tree_sitter_java::LANGUAGE.into(), query_string)
2529 .map_err(|e| ParserError::QueryError(e.to_string()))
2530 }
2531
2532 fn c_query() -> Result<Query, ParserError> {
2537 let query_string = r#"
2538 (function_definition
2539 declarator: (function_declarator
2540 declarator: (identifier) @name)) @function
2541
2542 (struct_specifier
2543 name: (type_identifier) @name) @struct
2544
2545 (enum_specifier
2546 name: (type_identifier) @name) @enum
2547 "#;
2548
2549 Query::new(&tree_sitter_c::LANGUAGE.into(), query_string)
2550 .map_err(|e| ParserError::QueryError(e.to_string()))
2551 }
2552
2553 fn c_super_query() -> Result<Query, ParserError> {
2554 let query_string = r#"
2555 ; Functions
2556 (function_definition
2557 declarator: (function_declarator
2558 declarator: (identifier) @name)) @function
2559
2560 ; Structs
2561 (struct_specifier
2562 name: (type_identifier) @name) @struct
2563
2564 ; Enums
2565 (enum_specifier
2566 name: (type_identifier) @name) @enum
2567
2568 ; Includes (imports)
2569 (preproc_include) @import
2570 "#;
2571
2572 Query::new(&tree_sitter_c::LANGUAGE.into(), query_string)
2573 .map_err(|e| ParserError::QueryError(e.to_string()))
2574 }
2575
2576 fn cpp_query() -> Result<Query, ParserError> {
2581 let query_string = r#"
2582 (function_definition
2583 declarator: (function_declarator
2584 declarator: (identifier) @name)) @function
2585
2586 (class_specifier
2587 name: (type_identifier) @name) @class
2588
2589 (struct_specifier
2590 name: (type_identifier) @name) @struct
2591
2592 (enum_specifier
2593 name: (type_identifier) @name) @enum
2594 "#;
2595
2596 Query::new(&tree_sitter_cpp::LANGUAGE.into(), query_string)
2597 .map_err(|e| ParserError::QueryError(e.to_string()))
2598 }
2599
2600 fn cpp_super_query() -> Result<Query, ParserError> {
2601 let query_string = r#"
2602 ; Functions
2603 (function_definition
2604 declarator: (function_declarator
2605 declarator: (identifier) @name)) @function
2606
2607 ; Classes
2608 (class_specifier
2609 name: (type_identifier) @name) @class
2610
2611 ; Structs
2612 (struct_specifier
2613 name: (type_identifier) @name) @struct
2614
2615 ; Enums
2616 (enum_specifier
2617 name: (type_identifier) @name) @enum
2618
2619 ; Includes (imports)
2620 (preproc_include) @import
2621 "#;
2622
2623 Query::new(&tree_sitter_cpp::LANGUAGE.into(), query_string)
2624 .map_err(|e| ParserError::QueryError(e.to_string()))
2625 }
2626
2627 fn csharp_query() -> Result<Query, ParserError> {
2632 let query_string = r#"
2633 (method_declaration
2634 name: (identifier) @name) @method
2635
2636 (class_declaration
2637 name: (identifier) @name) @class
2638
2639 (interface_declaration
2640 name: (identifier) @name) @interface
2641
2642 (struct_declaration
2643 name: (identifier) @name) @struct
2644
2645 (enum_declaration
2646 name: (identifier) @name) @enum
2647 "#;
2648
2649 Query::new(&tree_sitter_c_sharp::LANGUAGE.into(), query_string)
2650 .map_err(|e| ParserError::QueryError(e.to_string()))
2651 }
2652
2653 fn csharp_super_query() -> Result<Query, ParserError> {
2654 let query_string = r#"
2655 ; Methods
2656 (method_declaration
2657 name: (identifier) @name) @method
2658
2659 ; Classes
2660 (class_declaration
2661 name: (identifier) @name) @class
2662
2663 ; Interfaces
2664 (interface_declaration
2665 name: (identifier) @name) @interface
2666
2667 ; Structs
2668 (struct_declaration
2669 name: (identifier) @name) @struct
2670
2671 ; Enums
2672 (enum_declaration
2673 name: (identifier) @name) @enum
2674
2675 ; Imports (using directives)
2676 (using_directive) @import
2677 "#;
2678
2679 Query::new(&tree_sitter_c_sharp::LANGUAGE.into(), query_string)
2680 .map_err(|e| ParserError::QueryError(e.to_string()))
2681 }
2682
2683 fn ruby_query() -> Result<Query, ParserError> {
2688 let query_string = r#"
2689 (method
2690 name: (identifier) @name) @function
2691
2692 (class
2693 name: (constant) @name) @class
2694
2695 (module
2696 name: (constant) @name) @class
2697 "#;
2698
2699 Query::new(&tree_sitter_ruby::LANGUAGE.into(), query_string)
2700 .map_err(|e| ParserError::QueryError(e.to_string()))
2701 }
2702
2703 fn ruby_super_query() -> Result<Query, ParserError> {
2704 let query_string = r#"
2705 ; Methods
2706 (method
2707 name: (identifier) @name) @function
2708
2709 ; Classes
2710 (class
2711 name: (constant) @name) @class
2712
2713 ; Modules
2714 (module
2715 name: (constant) @name) @class
2716
2717 ; Requires (imports)
2718 (call
2719 method: (identifier) @_method
2720 (#match? @_method "^require")
2721 arguments: (argument_list)) @import
2722 "#;
2723
2724 Query::new(&tree_sitter_ruby::LANGUAGE.into(), query_string)
2725 .map_err(|e| ParserError::QueryError(e.to_string()))
2726 }
2727
2728 fn bash_query() -> Result<Query, ParserError> {
2733 let query_string = r#"
2734 (function_definition
2735 name: (word) @name) @function
2736 "#;
2737
2738 Query::new(&tree_sitter_bash::LANGUAGE.into(), query_string)
2739 .map_err(|e| ParserError::QueryError(e.to_string()))
2740 }
2741
2742 fn bash_super_query() -> Result<Query, ParserError> {
2743 let query_string = r#"
2744 ; Functions
2745 (function_definition
2746 name: (word) @name) @function
2747
2748 ; Source commands (imports)
2749 (command
2750 name: (command_name) @_cmd
2751 (#match? @_cmd "^(source|\\.)$")
2752 argument: (word)) @import
2753 "#;
2754
2755 Query::new(&tree_sitter_bash::LANGUAGE.into(), query_string)
2756 .map_err(|e| ParserError::QueryError(e.to_string()))
2757 }
2758
2759 fn php_query() -> Result<Query, ParserError> {
2764 let query_string = r#"
2765 (function_definition
2766 name: (name) @name) @function
2767
2768 (method_declaration
2769 name: (name) @name) @method
2770
2771 (class_declaration
2772 name: (name) @name) @class
2773
2774 (interface_declaration
2775 name: (name) @name) @interface
2776
2777 (trait_declaration
2778 name: (name) @name) @trait
2779 "#;
2780
2781 Query::new(&tree_sitter_php::LANGUAGE_PHP.into(), query_string)
2782 .map_err(|e| ParserError::QueryError(e.to_string()))
2783 }
2784
2785 fn php_super_query() -> Result<Query, ParserError> {
2786 let query_string = r#"
2787 ; Functions
2788 (function_definition
2789 name: (name) @name) @function
2790
2791 ; Methods
2792 (method_declaration
2793 name: (name) @name) @method
2794
2795 ; Classes
2796 (class_declaration
2797 name: (name) @name) @class
2798
2799 ; Interfaces
2800 (interface_declaration
2801 name: (name) @name) @interface
2802
2803 ; Traits
2804 (trait_declaration
2805 name: (name) @name) @trait
2806
2807 ; Use statements (imports)
2808 (namespace_use_declaration) @import
2809 "#;
2810
2811 Query::new(&tree_sitter_php::LANGUAGE_PHP.into(), query_string)
2812 .map_err(|e| ParserError::QueryError(e.to_string()))
2813 }
2814
2815 fn kotlin_query() -> Result<Query, ParserError> {
2820 let query_string = r#"
2821 (function_declaration
2822 name: (_) @name) @function
2823
2824 (class_declaration
2825 name: (_) @name) @class
2826
2827 (object_declaration
2828 name: (_) @name) @class
2829 "#;
2830
2831 Query::new(&tree_sitter_kotlin_ng::LANGUAGE.into(), query_string)
2832 .map_err(|e| ParserError::QueryError(e.to_string()))
2833 }
2834
2835 fn kotlin_super_query() -> Result<Query, ParserError> {
2836 let query_string = r#"
2837 ; Functions
2838 (function_declaration
2839 name: (_) @name) @function
2840
2841 ; Classes
2842 (class_declaration
2843 name: (_) @name) @class
2844
2845 ; Objects
2846 (object_declaration
2847 name: (_) @name) @class
2848
2849 ; Imports
2850 (import) @import
2851 "#;
2852
2853 Query::new(&tree_sitter_kotlin_ng::LANGUAGE.into(), query_string)
2854 .map_err(|e| ParserError::QueryError(e.to_string()))
2855 }
2856
2857 fn swift_query() -> Result<Query, ParserError> {
2862 let query_string = r#"
2863 (function_declaration
2864 name: (simple_identifier) @name) @function
2865
2866 (class_declaration
2867 declaration_kind: "class"
2868 name: (type_identifier) @name) @class
2869
2870 (protocol_declaration
2871 name: (type_identifier) @name) @interface
2872
2873 (class_declaration
2874 declaration_kind: "struct"
2875 name: (type_identifier) @name) @struct
2876
2877 (class_declaration
2878 declaration_kind: "enum"
2879 name: (type_identifier) @name) @enum
2880 "#;
2881
2882 Query::new(&tree_sitter_swift::LANGUAGE.into(), query_string)
2883 .map_err(|e| ParserError::QueryError(e.to_string()))
2884 }
2885
2886 fn swift_super_query() -> Result<Query, ParserError> {
2887 let query_string = r#"
2888 ; Functions
2889 (function_declaration
2890 name: (simple_identifier) @name) @function
2891
2892 ; Classes
2893 (class_declaration
2894 declaration_kind: "class"
2895 name: (type_identifier) @name) @class
2896
2897 ; Protocols (interfaces)
2898 (protocol_declaration
2899 name: (type_identifier) @name) @interface
2900
2901 ; Structs
2902 (class_declaration
2903 declaration_kind: "struct"
2904 name: (type_identifier) @name) @struct
2905
2906 ; Enums
2907 (class_declaration
2908 declaration_kind: "enum"
2909 name: (type_identifier) @name) @enum
2910
2911 ; Imports
2912 (import_declaration) @import
2913 "#;
2914
2915 Query::new(&tree_sitter_swift::LANGUAGE.into(), query_string)
2916 .map_err(|e| ParserError::QueryError(e.to_string()))
2917 }
2918
2919 fn scala_query() -> Result<Query, ParserError> {
2924 let query_string = r#"
2925 (function_definition
2926 name: (identifier) @name) @function
2927
2928 (class_definition
2929 name: (identifier) @name) @class
2930
2931 (object_definition
2932 name: (identifier) @name) @class
2933
2934 (trait_definition
2935 name: (identifier) @name) @trait
2936 "#;
2937
2938 Query::new(&tree_sitter_scala::LANGUAGE.into(), query_string)
2939 .map_err(|e| ParserError::QueryError(e.to_string()))
2940 }
2941
2942 fn scala_super_query() -> Result<Query, ParserError> {
2943 let query_string = r#"
2944 ; Functions
2945 (function_definition
2946 name: (identifier) @name) @function
2947
2948 ; Classes
2949 (class_definition
2950 name: (identifier) @name) @class
2951
2952 ; Objects
2953 (object_definition
2954 name: (identifier) @name) @class
2955
2956 ; Traits
2957 (trait_definition
2958 name: (identifier) @name) @trait
2959
2960 ; Imports
2961 (import_declaration) @import
2962 "#;
2963
2964 Query::new(&tree_sitter_scala::LANGUAGE.into(), query_string)
2965 .map_err(|e| ParserError::QueryError(e.to_string()))
2966 }
2967
2968 fn haskell_query() -> Result<Query, ParserError> {
2973 let query_string = r#"
2974 (function
2975 name: (variable) @name) @function
2976
2977 (signature
2978 name: (variable) @name) @function
2979
2980 (function
2981 name: (prefix_id) @name) @function
2982
2983 (signature
2984 name: (prefix_id) @name) @function
2985
2986 (newtype
2987 name: (name) @name) @struct
2988
2989 (type_synomym
2990 name: (name) @name) @struct
2991
2992 (data_type
2993 name: (name) @name) @enum
2994 "#;
2995
2996 Query::new(&tree_sitter_haskell::LANGUAGE.into(), query_string)
2997 .map_err(|e| ParserError::QueryError(e.to_string()))
2998 }
2999
3000 fn haskell_super_query() -> Result<Query, ParserError> {
3001 let query_string = r#"
3002 ; Functions
3003 (function
3004 name: (variable) @name) @function
3005
3006 ; Type signatures
3007 (signature
3008 name: (variable) @name) @function
3009
3010 ; Type aliases
3011 (function
3012 name: (prefix_id) @name) @function
3013
3014 (signature
3015 name: (prefix_id) @name) @function
3016
3017 ; Newtypes
3018 (newtype
3019 name: (name) @name) @struct
3020
3021 ; ADTs (data declarations)
3022 (type_synomym
3023 name: (name) @name) @struct
3024
3025 (data_type
3026 name: (name) @name) @enum
3027
3028 ; Imports
3029 (import) @import
3030 "#;
3031
3032 Query::new(&tree_sitter_haskell::LANGUAGE.into(), query_string)
3033 .map_err(|e| ParserError::QueryError(e.to_string()))
3034 }
3035
3036 fn elixir_query() -> Result<Query, ParserError> {
3041 let query_string = r#"
3042 (call
3043 target: (identifier) @_type
3044 (#match? @_type "^(def|defp|defmacro|defmacrop)$")
3045 (arguments
3046 (call
3047 target: (identifier) @name))) @function
3048
3049 (call
3050 target: (identifier) @_type
3051 (#match? @_type "^defmodule$")
3052 (arguments
3053 (alias) @name)) @class
3054 "#;
3055
3056 Query::new(&tree_sitter_elixir::LANGUAGE.into(), query_string)
3057 .map_err(|e| ParserError::QueryError(e.to_string()))
3058 }
3059
3060 fn elixir_super_query() -> Result<Query, ParserError> {
3061 let query_string = r#"
3062 ; Functions (def, defp, defmacro)
3063 (call
3064 target: (identifier) @_type
3065 (#match? @_type "^(def|defp|defmacro|defmacrop)$")
3066 (arguments
3067 (call
3068 target: (identifier) @name))) @function
3069
3070 ; Modules
3071 (call
3072 target: (identifier) @_type
3073 (#match? @_type "^defmodule$")
3074 (arguments
3075 (alias) @name)) @class
3076
3077 ; Imports (alias, import, use, require)
3078 (call
3079 target: (identifier) @_type
3080 (#match? @_type "^(alias|import|use|require)$")) @import
3081 "#;
3082
3083 Query::new(&tree_sitter_elixir::LANGUAGE.into(), query_string)
3084 .map_err(|e| ParserError::QueryError(e.to_string()))
3085 }
3086
3087 fn clojure_query() -> Result<Query, ParserError> {
3092 let query_string = r#"
3093 (list_lit
3094 (sym_lit) @_type
3095 (#match? @_type "^(defn|defn-|defmacro)$")
3096 (sym_lit) @name) @function
3097
3098 (list_lit
3099 (sym_lit) @_type
3100 (#match? @_type "^(defrecord|deftype|defprotocol)$")
3101 (sym_lit) @name) @class
3102 "#;
3103
3104 Query::new(&tree_sitter_clojure::LANGUAGE.into(), query_string)
3105 .map_err(|e| ParserError::QueryError(e.to_string()))
3106 }
3107
3108 fn clojure_super_query() -> Result<Query, ParserError> {
3109 let query_string = r#"
3110 ; Functions
3111 (list_lit
3112 (sym_lit) @_type
3113 (#match? @_type "^(defn|defn-|defmacro)$")
3114 (sym_lit) @name) @function
3115
3116 ; Records/Types/Protocols
3117 (list_lit
3118 (sym_lit) @_type
3119 (#match? @_type "^(defrecord|deftype|defprotocol)$")
3120 (sym_lit) @name) @class
3121
3122 ; Namespace (imports)
3123 (list_lit
3124 (sym_lit) @_type
3125 (#match? @_type "^(ns|require|use|import)$")) @import
3126 "#;
3127
3128 Query::new(&tree_sitter_clojure::LANGUAGE.into(), query_string)
3129 .map_err(|e| ParserError::QueryError(e.to_string()))
3130 }
3131
3132 fn ocaml_query() -> Result<Query, ParserError> {
3137 let query_string = r#"
3138 (value_definition
3139 (let_binding
3140 pattern: (value_name) @name)) @function
3141
3142 (type_definition
3143 (type_binding
3144 name: (type_constructor) @name)) @struct
3145
3146 (module_definition
3147 (module_binding
3148 name: (module_name) @name)) @class
3149 "#;
3150
3151 Query::new(&tree_sitter_ocaml::LANGUAGE_OCAML.into(), query_string)
3152 .map_err(|e| ParserError::QueryError(e.to_string()))
3153 }
3154
3155 fn ocaml_super_query() -> Result<Query, ParserError> {
3156 let query_string = r#"
3157 ; Functions (let bindings)
3158 (value_definition
3159 (let_binding
3160 pattern: (value_name) @name)) @function
3161
3162 ; Types
3163 (type_definition
3164 (type_binding
3165 name: (type_constructor) @name)) @struct
3166
3167 ; Modules
3168 (module_definition
3169 (module_binding
3170 name: (module_name) @name)) @class
3171
3172 ; Opens (imports)
3173 (open_module) @import
3174 "#;
3175
3176 Query::new(&tree_sitter_ocaml::LANGUAGE_OCAML.into(), query_string)
3177 .map_err(|e| ParserError::QueryError(e.to_string()))
3178 }
3179
3180 fn lua_query() -> Result<Query, ParserError> {
3185 let query_string = r#"
3186 (function_declaration
3187 name: (identifier) @name) @function
3188
3189 (function_declaration
3190 name: (dot_index_expression) @name) @method
3191
3192 (function_declaration
3193 name: (method_index_expression) @name) @method
3194 "#;
3195
3196 Query::new(&tree_sitter_lua::LANGUAGE.into(), query_string)
3197 .map_err(|e| ParserError::QueryError(e.to_string()))
3198 }
3199
3200 fn lua_super_query() -> Result<Query, ParserError> {
3201 let query_string = r#"
3202 ; Global functions
3203 (function_declaration
3204 name: (identifier) @name) @function
3205
3206 ; Method-like functions
3207 (function_declaration
3208 name: (dot_index_expression) @name) @method
3209
3210 (function_declaration
3211 name: (method_index_expression) @name) @method
3212
3213 ; Requires (imports)
3214 (function_call
3215 name: (variable
3216 (identifier) @_func)
3217 (#eq? @_func "require")
3218 arguments: (arguments)) @import
3219 "#;
3220
3221 Query::new(&tree_sitter_lua::LANGUAGE.into(), query_string)
3222 .map_err(|e| ParserError::QueryError(e.to_string()))
3223 }
3224
3225 fn r_query() -> Result<Query, ParserError> {
3230 let query_string = r#"
3231 (binary_operator
3232 lhs: (identifier) @name
3233 operator: "<-"
3234 rhs: (function_definition)) @function
3235
3236 (binary_operator
3237 lhs: (identifier) @name
3238 operator: "="
3239 rhs: (function_definition)) @function
3240 "#;
3241
3242 Query::new(&tree_sitter_r::LANGUAGE.into(), query_string)
3243 .map_err(|e| ParserError::QueryError(e.to_string()))
3244 }
3245
3246 fn r_super_query() -> Result<Query, ParserError> {
3247 let query_string = r#"
3248 ; Functions (left assignment)
3249 (binary_operator
3250 lhs: (identifier) @name
3251 operator: "<-"
3252 rhs: (function_definition)) @function
3253
3254 ; Functions (equals assignment)
3255 (binary_operator
3256 lhs: (identifier) @name
3257 operator: "="
3258 rhs: (function_definition)) @function
3259
3260 ; Library/require calls (imports)
3261 (call
3262 function: (identifier) @_func
3263 (#match? @_func "^(library|require|source)$")) @import
3264 "#;
3265
3266 Query::new(&tree_sitter_r::LANGUAGE.into(), query_string)
3267 .map_err(|e| ParserError::QueryError(e.to_string()))
3268 }
3269}
3270
3271impl Default for Parser {
3272 fn default() -> Self {
3273 Self::new()
3274 }
3275}
3276
3277#[cfg(test)]
3278mod tests {
3279 use super::*;
3280
3281 #[test]
3282 fn test_language_from_extension() {
3283 assert_eq!(Language::from_extension("py"), Some(Language::Python));
3284 assert_eq!(Language::from_extension("js"), Some(Language::JavaScript));
3285 assert_eq!(Language::from_extension("ts"), Some(Language::TypeScript));
3286 assert_eq!(Language::from_extension("rs"), Some(Language::Rust));
3287 assert_eq!(Language::from_extension("go"), Some(Language::Go));
3288 assert_eq!(Language::from_extension("java"), Some(Language::Java));
3289 assert_eq!(Language::from_extension("unknown"), None);
3290 }
3291
3292 #[test]
3293 fn test_parse_python() {
3294 let mut parser = Parser::new();
3295 let source = r#"
3296def hello_world():
3297 """This is a docstring"""
3298 print("Hello, World!")
3299
3300class MyClass:
3301 def method(self, x):
3302 return x * 2
3303"#;
3304
3305 let symbols = parser.parse(source, Language::Python).unwrap();
3306 assert!(!symbols.is_empty());
3307
3308 let func = symbols
3310 .iter()
3311 .find(|s| s.name == "hello_world" && s.kind == SymbolKind::Function);
3312 assert!(func.is_some());
3313
3314 let class = symbols
3316 .iter()
3317 .find(|s| s.name == "MyClass" && s.kind == SymbolKind::Class);
3318 assert!(class.is_some());
3319
3320 let method = symbols
3322 .iter()
3323 .find(|s| s.name == "method" && s.kind == SymbolKind::Method);
3324 assert!(method.is_some());
3325 }
3326
3327 #[test]
3328 fn test_parse_rust() {
3329 let mut parser = Parser::new();
3330 let source = r#"
3331/// A test function
3332fn test_function() -> i32 {
3333 42
3334}
3335
3336struct MyStruct {
3337 field: i32,
3338}
3339
3340enum MyEnum {
3341 Variant1,
3342 Variant2,
3343}
3344"#;
3345
3346 let symbols = parser.parse(source, Language::Rust).unwrap();
3347 assert!(!symbols.is_empty());
3348
3349 let func = symbols
3351 .iter()
3352 .find(|s| s.name == "test_function" && s.kind == SymbolKind::Function);
3353 assert!(func.is_some());
3354
3355 let struct_sym = symbols
3357 .iter()
3358 .find(|s| s.name == "MyStruct" && s.kind == SymbolKind::Struct);
3359 assert!(struct_sym.is_some());
3360
3361 let enum_sym = symbols
3363 .iter()
3364 .find(|s| s.name == "MyEnum" && s.kind == SymbolKind::Enum);
3365 assert!(enum_sym.is_some());
3366 }
3367
3368 #[test]
3369 fn test_parse_javascript() {
3370 let mut parser = Parser::new();
3371 let source = r#"
3372function testFunction() {
3373 return 42;
3374}
3375
3376class TestClass {
3377 testMethod() {
3378 return "test";
3379 }
3380}
3381
3382const arrowFunc = () => {
3383 console.log("arrow");
3384};
3385"#;
3386
3387 let symbols = parser.parse(source, Language::JavaScript).unwrap();
3388 assert!(!symbols.is_empty());
3389
3390 let func = symbols
3392 .iter()
3393 .find(|s| s.name == "testFunction" && s.kind == SymbolKind::Function);
3394 assert!(func.is_some());
3395
3396 let class = symbols
3398 .iter()
3399 .find(|s| s.name == "TestClass" && s.kind == SymbolKind::Class);
3400 assert!(class.is_some());
3401 }
3402
3403 #[test]
3404 fn test_parse_typescript() {
3405 let mut parser = Parser::new();
3406 let source = r#"
3407interface TestInterface {
3408 method(): void;
3409}
3410
3411enum TestEnum {
3412 Value1,
3413 Value2
3414}
3415
3416class TestClass implements TestInterface {
3417 method(): void {
3418 console.log("test");
3419 }
3420}
3421"#;
3422
3423 let symbols = parser.parse(source, Language::TypeScript).unwrap();
3424 assert!(!symbols.is_empty());
3425
3426 let interface = symbols
3428 .iter()
3429 .find(|s| s.name == "TestInterface" && s.kind == SymbolKind::Interface);
3430 assert!(interface.is_some());
3431
3432 let enum_sym = symbols
3434 .iter()
3435 .find(|s| s.name == "TestEnum" && s.kind == SymbolKind::Enum);
3436 assert!(enum_sym.is_some());
3437 }
3438
3439 #[test]
3440 fn test_symbol_metadata() {
3441 let mut parser = Parser::new();
3442 let source = r#"
3443def test_func(x, y):
3444 """A test function with params"""
3445 return x + y
3446"#;
3447
3448 let symbols = parser.parse(source, Language::Python).unwrap();
3449 let func = symbols
3450 .iter()
3451 .find(|s| s.name == "test_func")
3452 .expect("Function not found");
3453
3454 assert!(func.start_line > 0);
3455 assert!(func.end_line >= func.start_line);
3456 assert!(func.signature.is_some());
3457 assert!(func.docstring.is_some());
3458 }
3459}