1use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
11#[serde(rename_all = "snake_case")]
12pub enum LanguageTier {
14 SemanticDeep,
16 Structural,
18 IndexSearch,
20 DataConfig,
22}
23
24impl LanguageTier {
25 pub fn as_str(self) -> &'static str {
26 match self {
27 LanguageTier::SemanticDeep => "A",
28 LanguageTier::Structural => "B",
29 LanguageTier::IndexSearch => "C",
30 LanguageTier::DataConfig => "D",
31 }
32 }
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
39pub struct LanguageCapability {
40 pub id: &'static str,
41 pub display: &'static str,
42 pub tier: LanguageTier,
43 pub extensions: &'static [&'static str],
44 pub filenames: &'static [&'static str],
45 pub extractor: bool,
46 pub definitions: bool,
47 pub methods: bool,
48 pub classes: bool,
49 pub fields: bool,
50 pub calls: bool,
51 pub reads_writes: bool,
52 pub imports: bool,
53 pub inheritance: bool,
54 pub type_refs: bool,
55 pub macros: bool,
56 pub routes: bool,
57 pub state: bool,
58 pub contracts: bool,
59 pub tests: bool,
60 pub notes: &'static str,
61}
62
63pub const LANGUAGE_REGISTRY: &[LanguageCapability] = &[
69 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"),
70 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"),
71 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"),
72 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"),
73 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"),
74 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"),
75 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)"),
76 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"),
77 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"),
78 cap("env", "Env", LanguageTier::DataConfig, &["env"], &[".env"], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "secret redaction"),
79 cap("dockerfile", "Dockerfile", LanguageTier::DataConfig, &[], &["dockerfile", "Dockerfile"], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "infra extractor"),
80 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"),
81 cap("terraform", "Terraform", LanguageTier::DataConfig, &["tf"], &[], false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, "infra extractor"),
82 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"),
83 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"),
84 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"),
85 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"),
86 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"),
87 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"),
88 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"),
89 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"),
90 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"),
91 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"),
92 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"),
93 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"),
94 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"),
95];
96
97pub fn language_registry() -> &'static [LanguageCapability] {
101 LANGUAGE_REGISTRY
102}
103
104#[allow(clippy::too_many_arguments)]
105const fn cap(
107 id: &'static str,
108 display: &'static str,
109 tier: LanguageTier,
110 extensions: &'static [&'static str],
111 filenames: &'static [&'static str],
112 extractor: bool,
113 definitions: bool,
114 methods: bool,
115 classes: bool,
116 fields: bool,
117 calls: bool,
118 reads_writes: bool,
119 imports: bool,
120 inheritance: bool,
121 type_refs: bool,
122 macros: bool,
123 routes: bool,
124 state: bool,
125 contracts: bool,
126 tests: bool,
127 notes: &'static str,
128) -> LanguageCapability {
129 LanguageCapability {
130 id,
131 display,
132 tier,
133 extensions,
134 filenames,
135 extractor,
136 definitions,
137 methods,
138 classes,
139 fields,
140 calls,
141 reads_writes,
142 imports,
143 inheritance,
144 type_refs,
145 macros,
146 routes,
147 state,
148 contracts,
149 tests,
150 notes,
151 }
152}
153
154pub fn language_by_id(id: &str) -> Option<&'static LanguageCapability> {
156 language_registry().iter().find(|c| c.id == id)
157}
158
159pub fn extracted_language_ids() -> Vec<&'static str> {
161 language_registry()
162 .iter()
163 .filter(|c| c.extractor)
164 .map(|c| c.id)
165 .collect()
166}
167
168pub fn support_matrix_markdown() -> String {
171 let mut out = String::from(
172 "| Language | Tier | Extractor | Defs | Calls | Fields | Imports | Routes | Tests | Notes |\n|---|---|---|---|---|---|---|---|---|---|\n",
173 );
174 for c in language_registry() {
175 out.push_str(&format!(
176 "| {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |\n",
177 c.display,
178 c.tier.as_str(),
179 yn(c.extractor),
180 yn(c.definitions),
181 yn(c.calls),
182 yn(c.fields),
183 yn(c.imports),
184 yn(c.routes),
185 yn(c.tests),
186 c.notes
187 ));
188 }
189 out
190}
191
192fn yn(v: bool) -> &'static str {
193 if v {
194 "yes"
195 } else {
196 "no"
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203 use std::collections::BTreeSet;
204
205 #[test]
206 fn registry_ids_are_unique_and_extracted_are_tier_a() {
208 let mut ids = BTreeSet::new();
209 for c in language_registry() {
210 assert!(ids.insert(c.id), "duplicate language id {}", c.id);
211 if c.extractor {
212 assert_eq!(
213 c.tier,
214 LanguageTier::SemanticDeep,
215 "{} claims an extractor but is not tier A",
216 c.id
217 );
218 assert!(c.definitions && c.calls, "{} extractor without defs/calls", c.id);
219 }
220 }
221 assert!(extracted_language_ids().contains(&"python"));
222 assert!(extracted_language_ids().contains(&"rust"));
223 assert!(extracted_language_ids().contains(&"c"));
224 assert!(extracted_language_ids().contains(&"cpp"));
225 assert!(!extracted_language_ids().contains(&"objc"));
226 }
227
228 #[test]
229 fn matrix_is_generated_not_empty() {
231 let md = support_matrix_markdown();
232 assert!(md.contains("| Python |"));
233 assert!(md.contains("| C | A | yes |"));
234 assert!(md.contains("| Objective-C | C | no |"));
235 }
236}