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_declaration" => {
if let Some(sym) = extract_function(&child, source) {
symbols.push(sym);
}
}
"method_declaration" => {
if let Some(sym) = extract_method(&child, source) {
symbols.push(sym);
}
}
"type_declaration" => {
extract_type_decl(&child, source, &mut symbols);
}
"import_declaration" => {
let text = node_text(&child, source);
imports.push(Import {
path: text.to_string(),
alias: None,
span: Span::from_node(&child),
});
}
"const_declaration" | "var_declaration" => {
extract_var_const(&child, source, &mut symbols);
}
_ => {}
}
}
(symbols, imports)
}
fn extract_function(node: &tree_sitter::Node, source: &[u8]) -> Option<Symbol> {
let name = field_text(node, "name", source)?;
Some(Symbol {
name: name.to_string(),
kind: SymbolKind::Function,
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_method(node: &tree_sitter::Node, source: &[u8]) -> Option<Symbol> {
let name = field_text(node, "name", source)?;
let receiver = node
.child_by_field_name("receiver")
.map(|r| node_text(&r, source).to_string());
Some(Symbol {
name: name.to_string(),
kind: SymbolKind::Method,
span: Span::from_node(node),
signature: extract_signature(node, "body", source),
doc_comment: extract_doc_comment(node, source),
parent: receiver,
children: Vec::new(),
})
}
fn extract_type_decl(node: &tree_sitter::Node, source: &[u8], symbols: &mut Vec<Symbol>) {
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
if child.kind() == "type_spec" {
if let Some(name) = field_text(&child, "name", source) {
if let Some(type_node) = child.child_by_field_name("type") {
let kind = match type_node.kind() {
"struct_type" => SymbolKind::Struct,
"interface_type" => SymbolKind::Interface,
_ => SymbolKind::TypeAlias,
};
let mut methods = Vec::new();
if kind == SymbolKind::Interface {
let mut inner = type_node.walk();
for field in type_node.children(&mut inner) {
if field.kind() == "method_spec" {
if let Some(mname) = field_text(&field, "name", source) {
methods.push(Symbol {
name: mname.to_string(),
kind: SymbolKind::Method,
span: Span::from_node(&field),
signature: node_text(&field, source).to_string(),
doc_comment: extract_doc_comment(&field, source),
parent: Some(name.to_string()),
children: Vec::new(),
});
}
}
}
}
symbols.push(Symbol {
name: name.to_string(),
kind,
span: Span::from_node(&child),
signature: node_text(&child, source).to_string(),
doc_comment: extract_doc_comment(node, source),
parent: None,
children: methods,
});
}
}
}
}
}
fn extract_var_const(node: &tree_sitter::Node, source: &[u8], symbols: &mut Vec<Symbol>) {
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
if child.kind() == "const_spec" || child.kind() == "var_spec" {
if let Some(name_node) = child.child_by_field_name("name") {
let name = node_text(&name_node, source);
if !name.is_empty() {
symbols.push(Symbol {
name: name.to_string(),
kind: SymbolKind::Const,
span: Span::from_node(&child),
signature: node_text(&child, source).to_string(),
doc_comment: extract_doc_comment(&child, source),
parent: None,
children: Vec::new(),
});
}
}
}
}
}