use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum LanguageTier {
SemanticDeep,
Structural,
IndexSearch,
DataConfig,
}
impl LanguageTier {
pub fn as_str(self) -> &'static str {
match self {
LanguageTier::SemanticDeep => "A",
LanguageTier::Structural => "B",
LanguageTier::IndexSearch => "C",
LanguageTier::DataConfig => "D",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub struct LanguageCapability {
pub id: &'static str,
pub display: &'static str,
pub tier: LanguageTier,
pub extensions: &'static [&'static str],
pub filenames: &'static [&'static str],
pub extractor: bool,
pub definitions: bool,
pub methods: bool,
pub classes: bool,
pub fields: bool,
pub calls: bool,
pub reads_writes: bool,
pub imports: bool,
pub inheritance: bool,
pub type_refs: bool,
pub macros: bool,
pub routes: bool,
pub state: bool,
pub contracts: bool,
pub tests: bool,
pub notes: &'static str,
}
pub const LANGUAGE_REGISTRY: &[LanguageCapability] = &[
cap("python", "Python", LanguageTier::SemanticDeep, &["py", "pyi"], &[], true, true, true, true, true, true, true, true, false, false, false, true, true, true, true, "procedural tree-sitter; store R/W not SSA"),
cap("typescript", "TypeScript", LanguageTier::SemanticDeep, &["ts", "tsx", "mts", "cts"], &[], true, true, true, true, true, true, true, true, false, true, false, true, true, true, true, "TS/TSX; implements→REGISTERS not INHERITS"),
cap("javascript", "JavaScript", LanguageTier::SemanticDeep, &["js", "jsx", "mjs", "cjs"], &[], true, true, true, true, true, true, true, true, false, false, false, true, true, true, true, "shares TypeScript extractor"),
cap("go", "Go", LanguageTier::SemanticDeep, &["go"], &[], true, true, true, true, true, true, true, true, false, false, false, true, true, false, false, "framework-gated routes; tests via path heuristics"),
cap("rust", "Rust", LanguageTier::SemanticDeep, &["rs"], &[], true, true, true, true, true, true, true, true, false, false, true, true, true, true, true, "macros as invocations; no INHERITS edges"),
cap("java", "Java", LanguageTier::SemanticDeep, &["java"], &[], true, true, true, true, true, true, true, true, false, true, false, true, true, true, true, "Spring routes import-gated; extends→schema composition"),
cap("json", "JSON", LanguageTier::DataConfig, &["json", "jsonc"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "named config files only (package.json)"),
cap("yaml", "YAML", LanguageTier::DataConfig, &["yaml", "yml"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "compose/helm/github workflows"),
cap("toml", "TOML", LanguageTier::DataConfig, &["toml"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "classified; Cargo.toml not a code extractor"),
cap("env", "Env", LanguageTier::DataConfig, &["env"], &[".env"], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "secret redaction"),
cap("dockerfile", "Dockerfile", LanguageTier::DataConfig, &[], &["dockerfile", "Dockerfile"], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "infra extractor"),
cap("compose", "Compose", LanguageTier::DataConfig, &[], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "detected via filename, not extension"),
cap("terraform", "Terraform", LanguageTier::DataConfig, &["tf"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "infra extractor"),
cap("markdown", "Markdown", LanguageTier::DataConfig, &["md", "mdx", "rst"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "docs; DECLARED_AS mention index"),
cap("shell", "Shell", LanguageTier::IndexSearch, &["sh", "bash", "zsh"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "classified; no AST extractor"),
cap("sql", "SQL", LanguageTier::IndexSearch, &["sql"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "classified; no AST extractor"),
cap("c", "C", LanguageTier::SemanticDeep, &["c", "h"], &[], true, true, false, false, false, true, false, true, false, false, false, false, false, false, false, "procedural tree-sitter; quote-include Step-A; no CHA/fn-ptr/ObjC"),
cap("cpp", "C++", LanguageTier::SemanticDeep, &["cc", "cpp", "cxx", "hpp", "hh", "hxx"], &[], true, true, true, true, false, true, false, true, false, false, false, false, false, false, false, "procedural tree-sitter; quote-include Step-A; class methods; no CHA/fn-ptr"),
cap("objc", "Objective-C", LanguageTier::IndexSearch, &["m", "mm"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "classified; no AST extractor"),
cap("csharp", "C#", LanguageTier::IndexSearch, &["cs"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "classified; no AST extractor"),
cap("ruby", "Ruby", LanguageTier::IndexSearch, &["rb"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "classified; no AST extractor"),
cap("php", "PHP", LanguageTier::IndexSearch, &["php"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "classified; no AST extractor"),
cap("lua", "Lua", LanguageTier::IndexSearch, &["lua"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "classified; no AST extractor"),
cap("swift", "Swift", LanguageTier::IndexSearch, &["swift"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "classified; no AST extractor"),
cap("kotlin", "Kotlin", LanguageTier::IndexSearch, &["kt", "kts"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "classified; no AST extractor"),
cap("protobuf", "Protocol Buffers", LanguageTier::DataConfig, &["proto"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, "service/rpc → CONTRACT; no AST extractor"),
];
pub fn language_registry() -> &'static [LanguageCapability] {
LANGUAGE_REGISTRY
}
#[allow(clippy::too_many_arguments)]
const fn cap(
id: &'static str,
display: &'static str,
tier: LanguageTier,
extensions: &'static [&'static str],
filenames: &'static [&'static str],
extractor: bool,
definitions: bool,
methods: bool,
classes: bool,
fields: bool,
calls: bool,
reads_writes: bool,
imports: bool,
inheritance: bool,
type_refs: bool,
macros: bool,
routes: bool,
state: bool,
contracts: bool,
tests: bool,
notes: &'static str,
) -> LanguageCapability {
LanguageCapability {
id,
display,
tier,
extensions,
filenames,
extractor,
definitions,
methods,
classes,
fields,
calls,
reads_writes,
imports,
inheritance,
type_refs,
macros,
routes,
state,
contracts,
tests,
notes,
}
}
pub fn language_by_id(id: &str) -> Option<&'static LanguageCapability> {
language_registry().iter().find(|c| c.id == id)
}
pub fn extracted_language_ids() -> Vec<&'static str> {
language_registry()
.iter()
.filter(|c| c.extractor)
.map(|c| c.id)
.collect()
}
pub fn support_matrix_markdown() -> String {
let mut out = String::from(
"| Language | Tier | Extractor | Defs | Calls | Fields | Imports | Routes | Tests | Notes |\n|---|---|---|---|---|---|---|---|---|---|\n",
);
for c in language_registry() {
out.push_str(&format!(
"| {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |\n",
c.display,
c.tier.as_str(),
yn(c.extractor),
yn(c.definitions),
yn(c.calls),
yn(c.fields),
yn(c.imports),
yn(c.routes),
yn(c.tests),
c.notes
));
}
out
}
fn yn(v: bool) -> &'static str {
if v {
"yes"
} else {
"no"
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeSet;
#[test]
fn registry_ids_are_unique_and_extracted_are_tier_a() {
let mut ids = BTreeSet::new();
for c in language_registry() {
assert!(ids.insert(c.id), "duplicate language id {}", c.id);
if c.extractor {
assert_eq!(
c.tier,
LanguageTier::SemanticDeep,
"{} claims an extractor but is not tier A",
c.id
);
assert!(c.definitions && c.calls, "{} extractor without defs/calls", c.id);
}
}
assert!(extracted_language_ids().contains(&"python"));
assert!(extracted_language_ids().contains(&"rust"));
assert!(extracted_language_ids().contains(&"c"));
assert!(extracted_language_ids().contains(&"cpp"));
assert!(!extracted_language_ids().contains(&"objc"));
}
#[test]
fn matrix_is_generated_not_empty() {
let md = support_matrix_markdown();
assert!(md.contains("| Python |"));
assert!(md.contains("| C | A | yes |"));
assert!(md.contains("| Objective-C | C | no |"));
}
}