Dart: `extension type` members stopped being indexed in #1780 — the `method_signature` gate has no language check
Dart: extension type members stopped being indexed in #1780 — the method_signature gate has no language check
ee83636 (#1780, fixing #1638) gates a bodiless method_signature behind isInsideClassLikeNode(). That is correct for TypeScript, but Dart spells ordinary implemented methods method_signature too (src/extraction/languages/dart.ts → methodTypes: ['method_signature', 'constructor_signature']), and a Dart 3 extension type body is not class-like. Its members now miss the method branch and are dropped entirely.
Reproduction
extension type MetersT(double value) {
double get km => value / 1000;
}
const r = await extractFromSource('probe.dart', src, 'dart');
r.nodes.filter(n => n.kind !== 'file').map(n => `${n.kind}:${n.qualifiedName}`)
| commit | result |
|---|---|
8c04734 (parent) |
["function:km"] |
ee83636 (#1780) |
[] |
e720f6c (current main) |
[] |
Same working tree, same node_modules, same probe; only the checkout changed. km goes from indexed to invisible.
Scope — what is and isn't affected
Ran the same probe across the neighbouring constructs on both commits:
| case | 8c04734 |
e720f6c |
|---|---|---|
Dart extension type |
function:km |
[] |
Dart extension |
class:StringHelpers, method:StringHelpers::shout |
unchanged |
Dart mixin |
class:Logger, method:Logger::log |
unchanged |
Dart class |
class:Widget, method:Widget::build |
unchanged |
TS interface |
interface:Iface |
interface:Iface, method:Iface::go |
| TS type literal | method:Handle::stop, type_alias:Handle |
unchanged |
So #1780 does what it set out to do — the TS interface-member row is the fix working, and the type-literal row confirms it did not reintroduce the phantom free function from #359. extension, mixin and class are unaffected because their bodies satisfy isInsideClassLikeNode(). extension type is the only construct that regressed.
Cause
extension_type_declaration is a node type in the bundled src/extraction/wasm/tree-sitter-dart.wasm, but it appears nowhere in src/extraction/languages/dart.ts — not in classTypes (only class_definition), not in extraClassNodeTypes (only mixin_declaration, extension_declaration), not in enumTypes. Nothing mints a class-like parent for its body, so isInsideClassLikeNode() is false for double get km.
Note the pre-#1780 result was already imperfect — km was minted as a top-level function rather than a member of MetersT, since no class-like node exists for the extension type. The regression is that it went from mis-kinded to absent.
Two possible fixes
Narrow the gate by language, which is what we carry downstream:
const SIGNATURE_METHOD_LANGUAGES = new Set(['typescript', 'tsx', 'arkts']); // ... && (!SIGNATURE_METHOD_NODE_TYPES.has(nodeType) || !SIGNATURE_METHOD_LANGUAGES.has(this.language) || this.isInsideClassLikeNode())Restores
function:kmand keeps every TS row above green.Teach Dart about extension types — add
extension_type_declarationtoextraClassNodeTypes. Strictly better, because it also fixes the pre-existing mis-kinding:kmwould becomemethod:MetersT::kmrather than a top-level function. I have not measured this one, so treat it as a suggestion rather than a tested patch.
They are not exclusive; (2) alone would fix this case, but (1) is the general guard for any other language that reuses method_signature for implemented methods.
Why CI didn't catch it
There appears to be no Dart extraction fixture exercising extension type (or, as far as I can see, a Dart parity fixture at all). We caught this only because our downstream fork runs a Rust-kernel-vs-TypeScript parity suite over a Dart torture fixture, where it surfaced as a node-count mismatch (91 vs 90) across torture.dart and TortureCtors.dart including their CRLF variants. A extension type case in the Dart extraction tests would pin it.
Environment: Windows 11, Node v26.8.1, vitest 2.1.9, bundled tree-sitter-dart.wasm.
Source: colbymchenry/codegraph