Coverage
What nao can actually read.
Every row below is the behaviour of a parser in src/parser/, not a plan. The
tier is a claim about which edges come out, and the edge list next to each language is the
evidence for it. Where a language is weaker than you would expect from its popularity, it
says so.
Tier 1 of 3
Typed
Entities, call edges, and exact type edges from signatures and fields. This is the tier where impact analysis is type-accurate rather than approximate.
| Language | Files | Edges it emits | Notes |
|---|---|---|---|
| Rust | .rs | CallsImplementsUsesType | The most developed parser, and the only one with an optional exact call-edge path through rust-analyzer (NAO_LSP_EXACT=1). It is also the only language whose accuracy has been measured. |
| Python | .py .pyi | CallsInstantiatesUsesTypeWritesTo | Type edges come from annotations. Unannotated code still yields entities and call edges, so coverage tracks how typed the codebase is. |
| TypeScript | .ts .tsx | CallsInstantiatesUsesType | Full tree-sitter parse. On a real repository this produces roughly fifteen entities per file, with every relationship kind represented. |
| Java | .java | CallsInstantiatesUsesType | Also the language the Educator rules target, so it gets good-practice hovers in the VS Code extension that the others do not. |
| Kotlin | .kt .kts | CallsInstantiatesUsesType | Data classes are recognised as such, which is why the Data Bag smell does not fire on every one of them. |
| Svelte no call edges | .svelte | InstantiatesUsesType | Component-level, and much narrower than the others: it resolves which components use which, and the types in a <script lang="ts"> block. |
nao's own docs count this tier as five languages rather than six: TypeScript and Svelte
share one implementation, so a Svelte file gets its type edges from the TypeScript
machinery reading its <script> block. Svelte is listed separately here
because what it does not emit — call edges — is worth knowing before you rely on
it.
Tier 2 of 3
Structural
Entities and relationships, but no type edges. impact still works — it approximates type usage through "used via members" instead of resolving it.
| Language | Files | Edges it emits | Notes |
|---|---|---|---|
| Groovy | .groovy .gradle | CallsInstantiatesReadsFromWritesTo | Includes Spring bean wiring and embedded scripts. The named gap in the roadmap: it is the one dedicated parser still without type edges. |
| Impex | .impex | CallsReferencesWritesTo | SAP Hybris data-import files. Hand-rolled, because no tree-sitter grammar for the format exists — this is data flow rather than control flow. |
| Ansible / Kubernetes | by path | ContainsIncludesInterpolatesProvidesReferencesRendersFromRequires | Classified by repository layout rather than extension, since .yml belongs to nobody. The richest edge vocabulary of any parser, because deployment topology is what it models. |
| Elevator | .elv | ContainsReferences | The domain-spec language, not source code. It is parsed by the same machinery so that --drift can compare a spec against the code it claims. |
Tier 3 of 3
Fallback
A line-based regex pass, not a grammar. It recognises some declarations and produces no relationships at all, so the graph has nodes but no edges.
| Language | Files | Edges it emits | Notes |
|---|---|---|---|
| JavaScript not wired up | .js .mjs .cjs .jsx | none | Despite the TypeScript parser sitting right next to it, .js files are not routed to it — they fall through to the regex fallback and produce no relationships. Renaming a file to .ts is currently the whole fix. |
| Go no parser | .go | none | No dedicated parser. tree-sitter-go is a declared dependency that nothing calls, so Go gets the same regex pass as everything unrecognised. |
Anything nao does not recognise at all lands here too, alongside these: C, C++, C#, PHP, Ruby, Scala, Swift. Files are still walked, counted and drawn — you get a file tree and entity names, and nothing that depends on relationships.
The gap worth stating twice
JavaScript is not wired to the TypeScript parser.
The parser exists, handles the same grammar family, and sits in the same directory. But
the dispatch table has no arm for JavaScript, so .js, .mjs, .cjs and .jsx fall through to the regex fallback and produce
entities with no edges between them.
This is a routing gap rather than a missing capability, which is what makes it worth calling out: the cost of not knowing is a graph that looks sparse for reasons that have nothing to do with your code.
Until it is wired up, a TypeScript-flavoured project gets full fidelity by extension
alone — a mixed repository will be analyzed unevenly, and the uneven half is the .js one.
Measured on sindresorhus/got
One repository, both languages present, one analysis run.
| .ts | .js | |
|---|---|---|
| Files | 79 | 6 |
| Entities | 1,212 | 9 |
| Relationships | 3,458 | 0 |
Fifteen entities per TypeScript file; one and a half per JavaScript file, joined by nothing.
One more honest note
Only one of these has been measured.
The 93.7% recall and 98.6% precision figures quoted everywhere on this site are Rust, on nao's own source, against a rust-analyzer oracle — the only oracle wired up. Every other parser in the table above is unmeasured. Assume they are worse rather than equal.