code-moniker 0.4.0

Standalone CLI / linter for the code-moniker symbol graph: file and directory probes, project-wide architecture rules.
Documentation
use code_moniker_core::core::moniker::Moniker;
use code_moniker_core::core::shape::{Shape, shape_of};
use code_moniker_core::lang::Lang;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct TreeStrategy {
	lang: Option<Lang>,
}

impl TreeStrategy {
	#[cfg(feature = "tui")]
	pub(crate) fn for_lang(lang: Lang) -> Self {
		Self { lang: Some(lang) }
	}

	pub(crate) fn from_moniker(moniker: &Moniker) -> Self {
		Self {
			lang: lang_from_moniker(moniker),
		}
	}

	pub(crate) fn unknown() -> Self {
		Self { lang: None }
	}

	pub(crate) fn definition_order(self, kind: &str) -> u16 {
		self.lang
			.and_then(|lang| lang.kind_spec(kind))
			.map(|spec| spec.order)
			.or_else(|| structural_kind_order(kind))
			.or_else(|| shape_of(kind.as_bytes()).map(fallback_order_for_shape))
			.unwrap_or(u16::MAX)
	}

	pub(crate) fn definition_shape(self, kind: &str) -> Option<Shape> {
		self.lang
			.and_then(|lang| lang.kind_spec(kind))
			.map(|spec| spec.shape)
			.or_else(|| structural_kind_shape(kind))
			.or_else(|| shape_of(kind.as_bytes()))
	}

	pub(crate) fn collapse_separator(self, kind: &str) -> Option<&'static str> {
		match kind {
			"package" => Some("."),
			"dir" => Some("/"),
			_ => None,
		}
	}
}

fn lang_from_moniker(moniker: &Moniker) -> Option<Lang> {
	moniker.as_view().segments().find_map(|segment| {
		if segment.kind == b"lang" {
			std::str::from_utf8(segment.name)
				.ok()
				.and_then(Lang::from_tag)
		} else {
			None
		}
	})
}

fn structural_kind_order(kind: &str) -> Option<u16> {
	structural_kind_shape(kind).map(fallback_order_for_shape)
}

fn structural_kind_shape(kind: &str) -> Option<Shape> {
	match kind {
		"lang" | "dir" | "package" => Some(Shape::Namespace),
		_ => None,
	}
}

fn fallback_order_for_shape(shape: Shape) -> u16 {
	match shape {
		Shape::Namespace => 10,
		Shape::Type => 20,
		Shape::Callable => 40,
		Shape::Value => 60,
		Shape::Ref => 80,
		Shape::Annotation => 90,
	}
}