Summary
tests/tools/tree_sitter_accuracy_audit.py --lang typescript currently measures func_recall=92.1%, extra_functions=309 (precision 85.6%) against the language-crucible/data/typescript corpus (see docs/self_scan/tree_sitter_accuracy_history.csv). Diagnosed the 159 found_functions misses directly (full diff dumped via a one-off script reusing tree_sitter_accuracy_audit.py's own measure() internals, not just the tool's 8-file/3-name sample). This is the single largest contributor: at least 88 of the 159 missing functions (>55%) are brace-less, expression-bodied arrow function definitions — real, func_start-regex-matched function declarations that detector.py's _slice_by_braces (Mode B) silently drops because their body has no { at all.
Root cause
_slice_by_braces (gitgalaxy/core/detector.py:2133) has language-gated special handling for brace-less/expression bodies in csharp (#789, => arrow-bodied members), scala (#1266, bare = expr bodies), rust/zig/solidity (bodyless ;-terminated trait signatures), kotlin, objective-c, and dart — but not typescript (or javascript, which shares the same fallback). Every language not explicitly gated into one of those branches falls through to the generic default:
else:
brace_idx = safe_code.find(opener, start_idx, search_limit)
if brace_idx == -1:
continue
end_idx = self._find_balanced_end(safe_code, brace_idx, opener, closer)
If no { appears within search_limit (min of 2000 chars or the next func_start match), the match is dropped entirely via continue — the function is never recorded, not even with a degraded/zero-magnitude entry.
TypeScript/JavaScript idiomatically use brace-less arrow function bodies extremely often — single-expression arrow functions (const swap = (x) => x + 1) and, especially in functional-style code, curried multi-arrow chains with no { anywhere in the whole definition. This is not a rare style; it's the primary export shape throughout fp-ts (a top-20 npm functional-programming library, part of the pinned corpus).
Evidence
Confirmed with the actual func_start regex (gitgalaxy/standards/language_standards.py) — these DO match at the regex level (proving the drop happens in _slice_by_braces, not the regex):
>>> rule.search("export const swap = <E, A>(ma: Either<E, A>): Either<A, E> => (isLeft(ma) ? right(ma.left) : left(ma.right))")
<re.Match object; span=(13, 17), match='swap'> # matches, but absent from function_data
language-crucible/data/typescript/fp-ts/Either.ts alone accounts for dozens of these, e.g.:
// line 1325 -- matches func_start, never reaches function_data
export const swap = <E, A>(ma: Either<E, A>): Either<A, E> => (isLeft(ma) ? right(ma.left) : left(ma.right))
// line 688 -- curried chain, no `{` anywhere in the whole definition
export const traverse: PipeableTraverse2<URI> =
<F>(F: ApplicativeHKT<F>) =>
<A, B>(f: (a: A) => HKT<F, B>) =>
<E>(ta: Either<E, A>): HKT<F, Either<E, B>> =>
isLeft(ta) ? F.of(left(ta.left)) : F.map<B, Either<E, B>>(f(ta.right), right)
// line 170 -- top-level, unexported, still a real function
const _map: Monad2<URI>['map'] = (fa, f) => pipe(fa, map(f))
Confirmed via galaxyscope --db-only against a single-file scan of fp-ts/Either.ts: function_data has zero rows named traverse, swap, _map, _reduce, _ap, _reduceRight, reduce, foldMap, mapLeft, filter, ap, bimap, altW, concat, equals — all real, tree-sitter-confirmed functions.
Other affected files in the same corpus: fp-ts/TaskEither.ts, fp-ts/pipeable.ts (same style throughout).
Suggested fix direction
Add a typescript/javascript branch to _slice_by_braces mirroring csharp's (#789) or scala's (#1266) approach: if no { is found before search_limit, look for the nearest un-nested => after the parameter list and bound the body by either the next top-level statement terminator or the next func_start match (scala's approach — end_idx = next_match_start — is probably the closer analogy here, since TS/JS arrow bodies have no reliable ; terminator either, same as scala's def).
Scope note
This audit only measures typescript; javascript shares the exact same _slice_by_braces fallback path and near-certainly has the same gap (unverified here — out of scope for this issue, worth a quick follow-up check once this is fixed).
Filed under epic #1261.
Summary
tests/tools/tree_sitter_accuracy_audit.py --lang typescriptcurrently measures func_recall=92.1%, extra_functions=309 (precision 85.6%) against thelanguage-crucible/data/typescriptcorpus (seedocs/self_scan/tree_sitter_accuracy_history.csv). Diagnosed the 159found_functionsmisses directly (full diff dumped via a one-off script reusingtree_sitter_accuracy_audit.py's ownmeasure()internals, not just the tool's 8-file/3-name sample). This is the single largest contributor: at least 88 of the 159 missing functions (>55%) are brace-less, expression-bodied arrow function definitions — real,func_start-regex-matched function declarations thatdetector.py's_slice_by_braces(Mode B) silently drops because their body has no{at all.Root cause
_slice_by_braces(gitgalaxy/core/detector.py:2133) has language-gated special handling for brace-less/expression bodies incsharp(#789,=>arrow-bodied members),scala(#1266, bare= exprbodies),rust/zig/solidity(bodyless;-terminated trait signatures),kotlin,objective-c, anddart— but nottypescript(orjavascript, which shares the same fallback). Every language not explicitly gated into one of those branches falls through to the generic default:If no
{appears withinsearch_limit(min of 2000 chars or the nextfunc_startmatch), the match is dropped entirely viacontinue— the function is never recorded, not even with a degraded/zero-magnitude entry.TypeScript/JavaScript idiomatically use brace-less arrow function bodies extremely often — single-expression arrow functions (
const swap = (x) => x + 1) and, especially in functional-style code, curried multi-arrow chains with no{anywhere in the whole definition. This is not a rare style; it's the primary export shape throughoutfp-ts(a top-20 npm functional-programming library, part of the pinned corpus).Evidence
Confirmed with the actual
func_startregex (gitgalaxy/standards/language_standards.py) — these DO match at the regex level (proving the drop happens in_slice_by_braces, not the regex):>>> rule.search("export const swap = <E, A>(ma: Either<E, A>): Either<A, E> => (isLeft(ma) ? right(ma.left) : left(ma.right))") <re.Match object; span=(13, 17), match='swap'> # matches, but absent from function_datalanguage-crucible/data/typescript/fp-ts/Either.tsalone accounts for dozens of these, e.g.:Confirmed via
galaxyscope --db-onlyagainst a single-file scan offp-ts/Either.ts:function_datahas zero rows namedtraverse,swap,_map,_reduce,_ap,_reduceRight,reduce,foldMap,mapLeft,filter,ap,bimap,altW,concat,equals— all real, tree-sitter-confirmed functions.Other affected files in the same corpus:
fp-ts/TaskEither.ts,fp-ts/pipeable.ts(same style throughout).Suggested fix direction
Add a
typescript/javascriptbranch to_slice_by_bracesmirroring csharp's (#789) or scala's (#1266) approach: if no{is found beforesearch_limit, look for the nearest un-nested=>after the parameter list and bound the body by either the next top-level statement terminator or the nextfunc_startmatch (scala's approach —end_idx = next_match_start— is probably the closer analogy here, since TS/JS arrow bodies have no reliable;terminator either, same as scala'sdef).Scope note
This audit only measures
typescript;javascriptshares the exact same_slice_by_bracesfallback path and near-certainly has the same gap (unverified here — out of scope for this issue, worth a quick follow-up check once this is fixed).Filed under epic #1261.