use std::collections::BTreeSet;
use super::intelligence::{
apply_comment_lines, comment_at, diagnostic_at, doc_comment_at, docstring_at, export_at, import_at,
is_comment_node, mark_comment_rows, resolve_structure_name, span_from_node, structure_kind_at, structure_signature,
symbol_at,
};
use super::types::*;
pub(super) fn extract_intelligence(source: &str, language: &str, tree: &tree_sitter::Tree) -> ProcessResult {
let root = tree.root_node();
let mut node_count = 0;
let mut error_count = 0;
let mut max_depth = 0;
count_nodes(&root, 0, &mut node_count, &mut error_count, &mut max_depth);
let mut comment_rows = BTreeSet::new();
collect_comment_rows(&root, source, &mut comment_rows);
let mut metrics = super::intelligence::compute_line_metrics(source);
metrics.node_count = node_count;
metrics.error_count = error_count;
metrics.max_depth = max_depth;
apply_comment_lines(&mut metrics, source, &comment_rows);
let mut structure = Vec::new();
collect_structure(&root, source, language, &mut structure);
let mut imports = Vec::new();
collect_imports(&root, source, language, &mut imports);
let mut exports = Vec::new();
collect_exports(&root, source, language, &mut exports);
let mut comments = Vec::new();
collect_comments(&root, source, &mut comments);
let mut docstrings = Vec::new();
collect_docstrings(&root, source, language, &mut docstrings);
let mut symbols = Vec::new();
collect_symbols(&root, source, &mut symbols);
let mut diagnostics = Vec::new();
collect_diagnostics(&root, source, &mut diagnostics);
ProcessResult {
language: language.to_string(),
metrics,
structure,
imports,
exports,
comments,
docstrings,
symbols,
diagnostics,
chunks: Vec::new(),
data: None,
}
}
fn count_nodes(node: &tree_sitter::Node, depth: usize, count: &mut usize, errors: &mut usize, max_depth: &mut usize) {
*count += 1;
if depth > *max_depth {
*max_depth = depth;
}
if node.is_error() || node.is_missing() {
*errors += 1;
}
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
count_nodes(&child, depth + 1, count, errors, max_depth);
}
}
fn collect_comment_rows(node: &tree_sitter::Node, source: &str, rows: &mut BTreeSet<usize>) {
if is_comment_node(node) {
mark_comment_rows(node, source, rows);
}
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
collect_comment_rows(&child, source, rows);
}
}
fn collect_comments(node: &tree_sitter::Node, source: &str, comments: &mut Vec<CommentInfo>) {
if let Some(comment) = comment_at(node, source) {
comments.push(comment);
}
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
collect_comments(&child, source, comments);
}
}
fn collect_docstrings(node: &tree_sitter::Node, source: &str, language: &str, docstrings: &mut Vec<DocstringInfo>) {
if let Some(docstring) = docstring_at(node, source, language) {
docstrings.push(docstring);
}
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
collect_docstrings(&child, source, language, docstrings);
}
}
fn collect_imports(node: &tree_sitter::Node, source: &str, language: &str, imports: &mut Vec<ImportInfo>) {
if language == "elixir" && node.kind() == "call" {
if super::elixir::is_quote_call(node, source) {
return;
}
if let Some(import) = super::elixir::import_directive(node, source) {
imports.push(import);
}
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
collect_imports(&child, source, language, imports);
}
return;
}
if let Some(import) = import_at(node, source, language) {
imports.push(import);
}
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
collect_imports(&child, source, language, imports);
}
}
fn collect_exports(node: &tree_sitter::Node, source: &str, language: &str, exports: &mut Vec<ExportInfo>) {
if let Some(export) = export_at(node, source, language) {
exports.push(export);
}
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
collect_exports(&child, source, language, exports);
}
}
fn collect_structure(node: &tree_sitter::Node, source: &str, language: &str, items: &mut Vec<StructureItem>) {
if language == "elixir" && collect_structure_call(node, source, language, items) {
return;
}
if let Some(kind) = structure_kind_at(node, language) {
let name = resolve_structure_name(node, source);
let body = node.child_by_field_name("body");
let body_span = body.as_ref().map(span_from_node);
let mut children = Vec::new();
if let Some(body) = body {
collect_structure(&body, source, language, &mut children);
}
items.push(StructureItem {
kind,
name,
visibility: None,
span: span_from_node(node),
children,
decorators: Vec::new(),
doc_comment: doc_comment_at(node, source),
signature: structure_signature(node, source, body.as_ref()),
body_span,
});
} else {
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
collect_structure(&child, source, language, items);
}
}
}
fn collect_structure_call(
node: &tree_sitter::Node,
source: &str,
language: &str,
items: &mut Vec<StructureItem>,
) -> bool {
if super::elixir::is_quote_call(node, source) {
return true;
}
let Some(definition) = super::elixir::definition(node, source) else {
return false;
};
let body_span = definition.body.as_ref().map(span_from_node);
let mut children = Vec::new();
if let Some(body) = definition.body {
collect_structure(&body, source, language, &mut children);
}
let signature = structure_signature(node, source, definition.body.as_ref());
items.push(StructureItem {
kind: definition.kind,
name: definition.name,
visibility: definition.visibility,
span: span_from_node(node),
children,
decorators: Vec::new(),
doc_comment: doc_comment_at(node, source),
signature,
body_span,
});
true
}
fn collect_symbols(node: &tree_sitter::Node, source: &str, symbols: &mut Vec<SymbolInfo>) {
if let Some(symbol) = symbol_at(node, source) {
symbols.push(symbol);
}
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
collect_symbols(&child, source, symbols);
}
}
fn collect_diagnostics(node: &tree_sitter::Node, source: &str, diagnostics: &mut Vec<Diagnostic>) {
if let Some(diagnostic) = diagnostic_at(node, source) {
diagnostics.push(diagnostic);
}
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
collect_diagnostics(&child, source, diagnostics);
}
}
pub(super) fn collect_chunk_metadata(
node: &tree_sitter::Node,
source: &str,
language: &str,
chunk_start: usize,
chunk_end: usize,
collector: &mut super::chunking::MetadataCollector<'_>,
depth: usize,
) {
if node.end_byte() <= chunk_start || node.start_byte() >= chunk_end {
return;
}
super::chunking::record_chunk_node(node, source, language, chunk_start, chunk_end, collector, depth);
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
collect_chunk_metadata(&child, source, language, chunk_start, chunk_end, collector, depth + 1);
}
}