use super::{extract_doc_comment, extract_signature, field_text, node_text};
use crate::types::*;
pub fn extract(tree: &tree_sitter::Tree, source: &[u8]) -> (Vec<Symbol>, Vec<Import>) {
let root = tree.root_node();
let mut symbols = Vec::new();
let mut imports = Vec::new();
let mut cursor = root.walk();
for child in root.children(&mut cursor) {
match child.kind() {
"function_item" => {
if let Some(sym) = extract_function(&child, source, None) {
symbols.push(sym);
}
}
"struct_item" => {
if let Some(sym) = extract_struct(&child, source) {
symbols.push(sym);
}
}
"enum_item" => {
if let Some(sym) = extract_enum(&child, source) {
symbols.push(sym);
}
}
"trait_item" => {
if let Some(sym) = extract_trait(&child, source) {
symbols.push(sym);
}
}
"impl_item" => {
symbols.push(extract_impl(&child, source));
}
"use_declaration" => {
imports.push(Import {
path: node_text(&child, source)
.trim_start_matches("use ")
.trim_end_matches(';')
.to_string(),
alias: None,
span: Span::from_node(&child),
});
}
"const_item" | "static_item" => {
if let Some(name) = field_text(&child, "name", source) {
symbols.push(Symbol {
name: name.to_string(),
kind: SymbolKind::Const,
span: Span::from_node(&child),
signature: extract_signature(&child, "value", source),
doc_comment: extract_doc_comment(&child, source),
parent: None,
children: Vec::new(),
});
}
}
"type_item" => {
if let Some(name) = field_text(&child, "name", source) {
symbols.push(Symbol {
name: name.to_string(),
kind: SymbolKind::TypeAlias,
span: Span::from_node(&child),
signature: node_text(&child, source).to_string(),
doc_comment: extract_doc_comment(&child, source),
parent: None,
children: Vec::new(),
});
}
}
"mod_item" => {
if let Some(name) = field_text(&child, "name", source) {
symbols.push(Symbol {
name: name.to_string(),
kind: SymbolKind::Module,
span: Span::from_node(&child),
signature: format!("mod {}", name),
doc_comment: extract_doc_comment(&child, source),
parent: None,
children: Vec::new(),
});
}
}
_ => {}
}
}
(symbols, imports)
}
fn extract_function(
node: &tree_sitter::Node,
source: &[u8],
parent: Option<&str>,
) -> Option<Symbol> {
let name = field_text(node, "name", source)?;
Some(Symbol {
name: name.to_string(),
kind: if parent.is_some() {
SymbolKind::Method
} else {
SymbolKind::Function
},
span: Span::from_node(node),
signature: extract_signature(node, "body", source),
doc_comment: extract_doc_comment(node, source),
parent: parent.map(|s| s.to_string()),
children: Vec::new(),
})
}
fn extract_struct(node: &tree_sitter::Node, source: &[u8]) -> Option<Symbol> {
let name = field_text(node, "name", source)?;
Some(Symbol {
name: name.to_string(),
kind: SymbolKind::Struct,
span: Span::from_node(node),
signature: extract_signature(node, "body", source),
doc_comment: extract_doc_comment(node, source),
parent: None,
children: Vec::new(),
})
}
fn extract_enum(node: &tree_sitter::Node, source: &[u8]) -> Option<Symbol> {
let name = field_text(node, "name", source)?;
Some(Symbol {
name: name.to_string(),
kind: SymbolKind::Enum,
span: Span::from_node(node),
signature: extract_signature(node, "body", source),
doc_comment: extract_doc_comment(node, source),
parent: None,
children: Vec::new(),
})
}
fn extract_trait(node: &tree_sitter::Node, source: &[u8]) -> Option<Symbol> {
let name = field_text(node, "name", source)?;
Some(Symbol {
name: name.to_string(),
kind: SymbolKind::Trait,
span: Span::from_node(node),
signature: extract_signature(node, "body", source),
doc_comment: extract_doc_comment(node, source),
parent: None,
children: Vec::new(),
})
}
fn extract_impl(node: &tree_sitter::Node, source: &[u8]) -> Symbol {
let type_name = field_text(node, "type", source)
.or_else(|| {
node.child_by_field_name("type")
.map(|n| n.utf8_text(source).unwrap_or(""))
})
.unwrap_or("Unknown")
.to_string();
let mut methods = Vec::new();
if let Some(body) = node.child_by_field_name("body") {
let mut cursor = body.walk();
for child in body.children(&mut cursor) {
if child.kind() == "function_item" {
if let Some(m) = extract_function(&child, source, Some(&type_name)) {
methods.push(m);
}
}
}
}
Symbol {
name: type_name,
kind: SymbolKind::Impl,
span: Span::from_node(node),
signature: extract_signature(node, "body", source),
doc_comment: extract_doc_comment(node, source),
parent: None,
children: methods,
}
}