code-moniker-core 0.4.0

Core symbol-graph types and per-language extractors for code-moniker.
Documentation
use tree_sitter::Node;

use crate::lang::tree_util::node_slice;

pub(super) fn named_children(node: Node<'_>) -> impl Iterator<Item = Node<'_>> {
	let mut cursor = node.walk();
	node.named_children(&mut cursor)
		.collect::<Vec<_>>()
		.into_iter()
}

pub(super) fn path_pieces(node: Node<'_>, source: &[u8]) -> Vec<Vec<u8>> {
	let mut out = Vec::new();
	collect_path_pieces(node, source, &mut out);
	out
}

fn collect_path_pieces(node: Node<'_>, source: &[u8], out: &mut Vec<Vec<u8>>) {
	match node.kind() {
		"identifier" | "type_identifier" => out.push(node_slice(node, source).to_vec()),
		_ => {
			for child in named_children(node) {
				collect_path_pieces(child, source, out);
			}
		}
	}
}

pub(super) fn last_identifier(node: Node<'_>, source: &[u8]) -> Vec<u8> {
	node.child_by_field_name("name")
		.map(|name| node_slice(name, source).to_vec())
		.unwrap_or_else(|| path_pieces(node, source).pop().unwrap_or_default())
}

pub(super) fn type_name(node: Node<'_>, source: &[u8]) -> Option<Vec<u8>> {
	type_path(node, source).map(|mut pieces| pieces.pop().unwrap_or_default())
}

pub(super) fn type_path(node: Node<'_>, source: &[u8]) -> Option<Vec<Vec<u8>>> {
	match node.kind() {
		"type_identifier" => Some(vec![node_slice(node, source).to_vec()]),
		"scoped_type_identifier" => Some(path_pieces(node, source)),
		"generic_type" => node
			.child_by_field_name("type")
			.or_else(|| {
				named_children(node).find(|child| {
					matches!(child.kind(), "type_identifier" | "scoped_type_identifier")
				})
			})
			.and_then(|ty| type_path(ty, source)),
		"array_type" => node
			.child_by_field_name("element")
			.and_then(|element| type_path(element, source)),
		_ => None,
	}
}

pub(super) fn type_parameters(node: Node<'_>, source: &[u8]) -> Vec<Vec<u8>> {
	let Some(params) = node
		.child_by_field_name("type_parameters")
		.or_else(|| named_children(node).find(|child| child.kind() == "type_parameters"))
	else {
		return Vec::new();
	};
	named_children(params)
		.filter(|child| child.kind() == "type_parameter")
		.filter_map(|child| {
			child
				.child_by_field_name("name")
				.or_else(|| named_children(child).find(|inner| inner.kind() == "type_identifier"))
		})
		.map(|name| node_slice(name, source).to_vec())
		.collect()
}