code-moniker-core 0.4.0

Core symbol-graph types and per-language extractors for code-moniker.
Documentation
use crate::core::code_graph::CodeGraph;
use crate::core::moniker::{Moniker, MonikerBuilder};
use crate::lang::sdk::{DiscoveredFile, GraphEmitter, ImportTable, ScopeTree};

mod defs;
mod discover;
mod imports;
mod refs;
mod syntax;

use discover::RustDiscover;

use super::kinds;
use super::{Presets, parse};

pub fn extract(
	uri: &str,
	source: &str,
	anchor: &Moniker,
	deep: bool,
	_presets: &Presets,
) -> CodeGraph {
	let module = compute_module_moniker(anchor, uri);
	let tree = parse(source);
	let discovered_parts =
		RustDiscover::run(module.clone(), source.as_bytes(), deep, tree.root_node());
	let discovered = DiscoveredFile::new(
		module,
		kinds::MODULE,
		discovered_parts.defs,
		ScopeTree::new(discovered_parts.root),
		ImportTable::default(),
	);
	GraphEmitter::emit(&discovered, &discovered_parts.refs)
		.unwrap_or_else(|err| panic!("Rust SDK graph emission failed: {err}"))
}

fn compute_module_moniker(anchor: &Moniker, uri: &str) -> Moniker {
	let stem = uri.strip_suffix(".rs").unwrap_or(uri);
	let mut builder = MonikerBuilder::from_view(anchor.as_view());
	builder.segment(crate::lang::kinds::LANG, b"rs");
	append_rust_module_path(&mut builder, stem);
	builder.build()
}

fn append_rust_module_path(builder: &mut MonikerBuilder, path: &str) {
	let pieces = path
		.split('/')
		.filter(|piece| !piece.is_empty() && *piece != ".")
		.collect::<Vec<_>>();
	let Some(src_idx) = pieces.iter().rposition(|piece| *piece == "src") else {
		crate::lang::callable::append_dir_module_segments(builder, path, kinds::DIR, kinds::MODULE);
		return;
	};
	for piece in &pieces[..=src_idx] {
		builder.segment(kinds::DIR, piece.as_bytes());
	}
	let mut modules = &pieces[src_idx + 1..];
	if modules.last().copied() == Some("mod") {
		modules = &modules[..modules.len().saturating_sub(1)];
	}
	for piece in modules {
		builder.segment(kinds::MODULE, piece.as_bytes());
	}
}