# Community Tree-Sitter Query Analysis

Analyzed: July 3, 2026
Source: nvim-treesitter (master branch) tag queries + highlight queries

## Key Finding

**Community TAGS queries are for code navigation (Go to Definition), NOT for Dervish.**

Dervish needs **behavioral sequences**: what operations happen in what order.
Tags queries only capture declaration sites and reference locations.

## Language-by-Language Gap Analysis

### JAVA

**Tags captures:**
- `@definition.class` — class declaration sites
- `@definition.method` — method declaration sites
- `@definition.interface` — interface declaration sites
- `@reference.call` — method invocations (ONLY with `argument_list`)
- `@reference.implementation` — implements clauses
- `@reference.class` — `new Type()` expressions + superclass refs

**What is MISSING for Dervish:**
- `@annotation` / `@decorator` — annotations only exist in highlights as `@attribute`, not in tags
- `@reference.call` excludes parameterless calls like `foo()` — requires `argument_list`
- No `throw_statement`, `try_statement`, `catch_clause` in tags
- No `if_statement`, `return_statement` captures
- No mechanism to extract ORDERED sequences
- Highlights collapse all control-flow keywords into `@keyword`

### KOTLIN (from highlights.scm since no tags.scm exists at that path)

**Available captures (highlights only):**
- `@function.call` — `call_expression` with `simple_identifier`
- `@constructor` — `constructor_invocation`, `primary_constructor`, secondary
- `@attribute` — `annotation` with `user_type`
- `@keyword.conditional` — `if`/`else`/`when`
- `@keyword.repeat` — `for`/`do`/`while`
- `@keyword.exception` — `try`/`catch`/`throw`/`finally`
- `@keyword.return` — `return`
- `@function` — `function_declaration`

**What is MISSING for Dervish:**
- No tags.scm available on nvim-treesitter master for Kotlin
- Call expressions captured as `@function.call` in highlights, not structured for sequence extraction
- Navigation expressions (`obj.method()`) captured but as `@function.call` on the suffix
- No `when_structure` / `when_condition` structural capture
- No `navigation_expression` itself as a token — only the method name inside
- No sequencing mechanism

### PYTHON

**Tags captures:**
- `@definition.constant` — module-level assignments
- `@definition.class` — class definitions
- `@definition.function` — function definitions
- `@reference.call` — direct function calls + method calls via attribute

**What is MISSING for Dervish:**
- No `decorator` capture in tags (only in highlights as `@function`)
- `call` only captured as reference, not as behavioral sequence token
- No `raise_statement`, `try_statement`, `except_clause` in tags
- No `if_statement`, `return_statement`, `with_statement` in tags
- Highlights `@function` conflates decorators, definitions, and calls

### GO

**Tags captures:**
- `@definition.function` — function declarations (with doc comments)
- `@definition.method` — method declarations
- `@definition.type` — type specs
- `@reference.call` — direct calls + selector calls (`obj.Method()`)
- `@reference.type` — type identifier references
- Plus: var/const/import/struct/interface tracking

**What is MISSING for Dervish:**
- No `defer_statement` capture (only `defer` keyword in highlights)
- No `go` (goroutine launch) as structural capture
- No `if_statement`, `return_statement`, `for_statement`, `switch_statement` in tags
- `call_expression` well captured but only function name as `@name`, not whole expression
- Highlights distinguish builtins (`append`, `len`, `make`, `panic`, etc.) but not structured

### RUST

**Tags captures:**
- `@definition.class` — struct/enum/union/type alias
- `@definition.method` — methods in impl blocks
- `@definition.function` — free functions
- `@definition.interface` — trait definitions
- `@definition.module` — module definitions
- `@definition.macro` — macro definitions
- `@reference.call` — direct calls + method calls + macro invocations
- `@reference.implementation` — trait/inherent impl tracking

**What is MISSING for Dervish:**
- Best coverage of any language — captures calls, macros, implementations
- Still: no `if_expression` / `match_expression` / `return` in tags
- No `unsafe` block capture
- `@attribute` (`#[derive]`) only in highlights, not tags
- No sequencing mechanism

### TYPESCRIPT / JAVASCRIPT

**Tags captures:**
- `@definition.function` — function signatures only (definitions)
- `@definition.method` — method signatures
- `@definition.class` — class + abstract class declarations
- `@definition.module` — module declarations
- `@definition.interface` — interface declarations
- `@reference.type` — type annotations
- `@reference.class` — `new Foo()` constructor calls

**What is MISSING for Dervish:**
- **NO `call_expression` capture at all** — neither in tags nor highlights
- **NO `@reference.call`** — critical gap
- No function/method call tracking
- Highlight query is extremely minimal (35 lines)
- Missing: `arrow_function`, `call_expression`, `method_invocation`
- Query file seems designed for `.d.ts` type definitions, not implementation code

### C++

**Tags captures:**
- `@definition.class` — struct/union/class specifiers
- `@definition.function` — function declarators
- `@definition.method` — qualified methods (with namespace scope)
- `@definition.type` — typedef/enum

**What is MISSING for Dervish:**
- **NO `call_expression` capture in tags** — call tracking only in highlights as `@function`
- **NO `@reference.call`** in tags at all
- No `template_function`, `template_method` in tags
- No `new_expression`, `delete_expression` in tags
- No `throw_statement`, `try_statement`, `catch_clause` in tags
- No sequencing mechanism

### YAML

**What is MISSING for Dervish:**
- No tags query exists at all
- YAML is data-oriented, not code-oriented
- Highlights only capture data types (strings, numbers, booleans) and key names
- YAML sequence extraction (for Ansible/Helm) needs a different approach entirely

## Cross-Cutting Findings

### What community tags DO capture (for Dervish, partially useful):

| Capture | Languages | Dervish Value |
|---------|-----------|--------------|
| `@reference.call` | Java, Python, Go, Rust | **Partial** — identifies call sites but per-language inconsistencies |
| `@reference.class` / `new` | Java, TypeScript | **Partial** — constructor calls |
| `@reference.implementation` | Java, Rust | Low — inheritance tracking |
| macro invocations (as `@reference.call`) | Rust | **Useful** — Rust macros ARE behavioral tokens |

### What community tags do NOT capture (GAPS):

| Dervish Need | In Tags? | In Highlights? |
|-------------|----------|---------------|
| `@annotation` / `@decorator` / `@attribute` | **0 languages** | Java `@attribute`, Python `@function` (decorator), Rust `@attribute`, Kotlin `@attribute` |
| Control flow (`if`/`else`/`when`) | **0 languages** | All: collapsed in `@keyword` |
| Error handling (`try`/`catch`/`throw`) | **0 languages** | All: collapsed in `@keyword` |
| `@return` | **0 languages** | All: collapsed in `@keyword` |
| Call expressions | Java, Python, Go, Rust | All except TS |
| Ordered sequences | **0 languages** | **0 languages** |
| Variable declarations | Go only | Not structural |
| Resource management (`defer`/`with`) | **0 languages** | Go: `defer` in keyword; Python: `with` in keyword |
| Goroutines / async / coroutines | **0 languages** | Go `go` in keyword; Python async/await in keyword; Kotlin `suspend` as `@keyword.coroutine` |

### The Naming Inconsistency Problem

Same tree-sitter node types have DIFFERENT capture names across languages:

| Node | Java | Python | Go | Rust | C++ | TS |
|------|------|--------|----|------|-----|----|
| call expr | `@reference.call` | `@reference.call` | `@reference.call` | `@reference.call` | NONE | NONE |
| class def | `@definition.class` | `@definition.class` | -- | `@definition.class` | `@definition.class` | `@definition.class` |
| function def | -- | `@definition.function` | `@definition.function` | `@definition.function` | `@definition.function` | `@definition.function` |

Dervish cannot rely on capture names alone. Must either:
1. Use universal query with Dervish-specific capture names, OR
2. Map language-specific capture names to canonical Dervish vocabulary

### Community tags.scm availability on nvim-treesitter master

Checked July 3, 2026 via `raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/master/queries/<lang>/tags.scm`:

| Language | tags.scm exists? | highlights.scm? |
|----------|-----------------|-----------------|
| Java | 404 | yes (in refs) |
| Kotlin | 404 | yes (newly downloaded) |
| Python | 404 | yes (in refs) |
| Go | 404 | yes (in refs) |
| Rust | 404 | yes (in refs) |
| TypeScript | 404 | yes (in refs) |
| C++ | 404 | yes (in refs) |
| YAML | never | yes (in refs) |

All tags.scm returned 404 — nvim-treesitter may have restructured or moved to a different branch/tag.

## Resolution

This analysis was performed against community **tags.scm** queries. The actual implementation uses **nvim-treesitter `highlights.scm`** instead, which resolves the critical gaps:

| Gap in tags.scm | highlights.scm outcome |
|---|---|
| Missing control flow (`if`/`else`/`when`) | `@keyword.conditional` — all languages |
| Missing error handling (`try`/`catch`/`throw`) | `@keyword.exception` — all languages |
| Missing `@return` | `@keyword.return` — all languages |
| Missing annotations/decorators | Java/Kotlin `@attribute`, Rust `@attribute`, Python `@function` (decorator) |
| Naming inconsistency across langs | Mitigated by **prefix-based filter** (`definition.*`, `keyword.*`, `reference.*`, etc.) — exact capture names don't need to match, only prefixes |

Highlights.scm proved richer than tags.scm for behavioral sequence extraction, because highlight queries deliberately distinguish keywords, functions, calls, and attributes — exactly what Dervish needs.

### Special Cases

Two languages required deviations from the plain nvim-treesitter approach:

**Kotlin** — nvim-treesitter `queries/kotlin/highlights.scm` fails at row 296 due to a conflict between the grammar's duplicate `annotation` node type (id 92 named=False, id 304 named=True). Resolution: use `ts-kotlin`'s bundled `queries/highlights.scm` instead (`pip install ts-kotlin`). This is the fwcd grammar fork, which also includes the `simple_identifier` node needed by highlight queries.

**JavaScript/TypeScript** — JS query uses `; inherits: ecma, jsx` and TS uses `; inherits: ecma`. The `code.py` preprocessor resolves inheritance by concatenating parent query content before child content. Additionally, `jsx.scm` contains two `#set!` predicates with 3 arguments (`#set! @_capture property value`) which py-tree-sitter 0.26 rejects (expects 1-2 args). Resolution: those two `bo.commentstring` patterns were stripped from `jsx.scm`.

## Verdict

**Community tags.scm alone are insufficient. But nvim-treesitter highlights.scm — used as-is with two caveats — covers 4/5 gaps.** The remaining gap (no sequencing/traversal mechanism) is handled by tree-sitter's built-in ordered cursor iteration over captures, which naturally preserves source order.

A universal query file is no longer needed. The `code.py` preprocessor loads highlights.scm per-language, resolves `; inherits:` directives, handles the two known deviations (Kotlin bundled query, jsx `#set!` stripping), and filters by behavioral capture prefix — zero adapters, zero per-language branches.

## Method-Level Sequencing

### The Problem

Flat per-file sequences are too diverse for k-ORE to produce ordered grammars. Each file mixes multiple function bodies into one flat token list — the ordering across methods is meaningless.

### The Solution: `child_by_field_name("body")`

Research across all 10 grammar `node-types.json` files revealed that every tree-sitter grammar stores function/method bodies in a field called **`body`**:

| Language | Function node type | `body` field type |
|----------|-------------------|-------------------|
| Python | `function_definition` | `block` |
| Go | `function_declaration`, `method_declaration` | `block` |
| Rust | `function_item` | `block` |
| JavaScript | `function_declaration`, `method_definition`, `arrow_function` | `statement_block` |
| TypeScript | `function_declaration`, `method_signature` | `statement_block` |
| Ruby | `method` | `body_statement` |
| Java | `method_declaration` | `block` |
| C/C++ | `function_definition` | `compound_statement` |
| Kotlin (fwcd) | `function_declaration` *(no field — positional child)* | `function_body` |

**9/10 grammars** expose the body via `node.child_by_field_name("body")` in the tree-sitter API. Kotlin (fwcd grammar) is the exception — its `function_declaration` doesn't use a named `body` field. For Kotlin, we scan children and match by type name (`function_body`).

The parent filter `"function" in node.type or "method" in node.type` ensures we don't capture class bodies, loop bodies, or other block-like constructs.

This gives us **per-method sequences**: each function/method body becomes its own token list. k-ORE can then find actual call-order conventions (e.g. `validate → process → respond`).
