* fix(cfml): tag-based calls, wrapped functions and <cfinterface> are indexed (#2091)
Tag-based CFML lost almost all of its call edges. The tag walk sent only
<cfscript> and <cfquery> bodies through call extraction, although the cfml
grammar parses the expressions in <cfset>, <cfif>/<cfelseif>, <cfreturn>
and #hash# (output, strings, attributes) with the same rules as cfscript.
The walk now records each such expression with the scope that owns it
(the enclosing <cffunction>, else the component, else the file) and reads
them all through the existing cfscript extraction in one parse per file:
the expressions are copied out on their original lines, each ended with a
`;`, and every reference is handed back to its expression's scope with its
column restored. <cfloop condition="..."> is read the same way.
A <cffunction> nested in a generic container tag at component or template
scope (<cfprocessingdirective> in Application.cfc, <cfsilent>) was skipped
because only direct children were examined; it is now extracted (never
through an ERROR node, where a lost <cfcomponent> would misfile methods as
top-level functions). <cfinterface>, a generic tag to the grammar, now
yields an interface node with its functions as methods and an `extends`
ref per comma-separated parent, so `implements` resolves to it.
The tag-based parse tree is now freed after the walk.
Resolution: the CFML/Ruby/C# bare-call scope filters evaluated the
receiver-on-line check once per same-named candidate though only the ref
decides it. With tag calls extracted, that made Mach-II's resolution ~8x
slower; the check is now memoized per ref (edges byte-identical).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(changelog): tag-based CFML calls (#2091)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pascal): Delphi .inc include files are indexed as Pascal, not PHP (#2279)
`.inc` maps to PHP (Drupal), so a Delphi/Free Pascal include — a
`{$IFDEF}`/`{$DEFINE}` block or a declaration fragment pulled in with
`{$I defs.inc}` — was parsed as PHP (untagged text = inline HTML) and
contributed nothing.
detectLanguage now decides `.inc` by content: a PHP open tag (`<?php`,
`<?=`) anywhere keeps it PHP; otherwise a Pascal-only line shape (a
compiler directive, a `;`-closed routine header, `unit`/`uses`, a
const/var/type section, a begin/end; pair, Lazarus `{%MainUnit}`) makes
it Pascal; anything else keeps the PHP routing so C / asm / POV-Ray /
SourcePawn / Makefile includes are not handed to the Pascal grammar. A
leading BOM is skipped. An explicit codegraph.json `.inc` mapping wins.
The rule is per file, so a full index and a sync always agree.
The grammar preload set adds Pascal whenever an `.inc` is present (an
include-only tree otherwise had no Pascal parser), and the kernel-parity
script re-detects `.inc` like the indexer does.
Checked on 875 real `.inc` files: 0 of 436 non-Pascal ones (Drupal 7,
php-src, LLVM, FreeBSD mk, POV-Ray, SourceMod, edk2) flip; 433 of 439
Pascal ones (FPC, Lazarus, Castle, mORMot2, JCL) are detected — the rest
are statement-only or bare-literal fragments with nothing to extract.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(changelog): Pascal include files (#2279)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(sync): same-named symbols keep their own cross-file callers across a re-index (#2276)
Re-storing a file re-attaches the edges other files had into it by moving
each edge to the re-indexed node that replaces its target. That pairing
keyed new nodes by (kind, name) with the last one winning, so in a file
defining a name twice — the same method on two classes, a method's
overloads — any edit, even a body-only one, moved every incoming caller
of those symbols onto one of them. A body-only edit leaves the sync's
definition delta empty, so nothing re-resolved them afterwards.
The re-store now reads the file's old node identities alongside the edge
snapshot and pairs old nodes with new ones by (kind, name), then
qualified name, then signature, then position within a same-sized group
of otherwise identical nodes. A target no tier can pair one-to-one is
resurrected as its original unresolved reference, so resolution rebinds
it instead of the store guessing.
The common in-memory re-store path also now deletes the old rows, stores
the new ones and re-attaches incoming edges in one transaction. Committed
separately, a failure between the steps left the file looking new or
already current, and other files' edges into it were lost until a full
re-index.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(changelog): same-named symbols keep their callers across a sync (#2276)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(windows): hide the git calls that flash console windows (#2094)
The two git calls added for exclude-standard scope parity (#1728),
`git config --get core.excludesFile` and
`git ls-files -o -i --exclude-standard --directory`, ran without
windowsHide. Inside the detached, console-less MCP daemon each one got a
fresh visible console, so a window flashed several times on daemon start
and again on every auto-sync. With Windows Terminal as the default
terminal each flash is a full Windows Terminal window. `git config
user.name` in the viewer's trails API had the same gap.
Add windowsHide: true to all three, and replace the per-file regex guards
with an AST guard over every child_process spawn in src/: options passed
through a variable or a function parameter are traced back to the object
literal that defines them, through every call site.
Supersedes #2095 (same fix, rebased on current main). Closes#2094,
closes#2096.
(cherry picked from commit dd2db41f1b)
* docs(changelog): credit the Windows console-window fix
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit cf93d497fd1b38fd9214945eeb55b6b0be9e2007)
---------
Co-authored-by: Suharaz <minesuhara@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cobol): a file ending inside the sequence area no longer hangs the parser
The vendored COBOL grammar's external scanner skips the fixed-format
sequence area (columns 1-6) with `while (get_column() <= 5) advance()`.
At end of input advance() is a no-op, so a file whose last line stops in
that area (` .`, `X\n .`, a sentence closed by a short ` .` line)
never reached column 7 and the scanner spun forever inside wasm. Indexing
hit the parse worker's hard timeout three times (~93 s) and stored the
file with zero symbols; the viewer's highlighter froze on the same text.
The loop now also stops at eof(). It is upstream code (present at
e99dbdc3), so the change is a standalone upstreamable fix; inputs that
parsed before are unaffected (412 NIST + ocesql test sources give
byte-identical trees with the old and new wasm, and the upstream corpus
keeps its single pre-existing failure).
Regenerates docs/grammars/tree-sitter-cobol.patch, rebuilds the wasm per
docs/grammars/tree-sitter-cobol.md, and adds an out-of-process regression
test under a hard deadline (a regression is an uninterruptible wasm loop).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(viewer): force the highlight deadline instead of relying on a grammar bug
The bounded-highlight test used the COBOL ` .` slice as its slice that
never finishes; the grammar fix makes it parse, so the deadline is now
forced through tokenizeBounded's deadline parameter.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The viewer's server classifies a code slice with the engine's tree-sitter
grammars on its one thread. The COBOL grammar's scanner loops forever on a
line like ` .`, which a cobolcraft Flow card's window ends with, so the
whole server froze — /api/stats included — and a parse inside WebAssembly
cannot be interrupted from JavaScript. Slices are now classified in a
worker that is terminated past a 2 s deadline; the slice is served plain
and the next one gets a fresh worker. Request-time parses also carry a
progress-callback budget.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The single-file-component extractors kept the delegated script's file node
and made the component contain it and every node, so the hierarchy ran
file-inside-component, members had two parents, and a file with no script
had no file node. And a per-instance script's top-level calls stayed on the
file, so a walk from the component found nothing. Now: one file node (the
whole file) holds the component; the component holds what the script holds
at top level, nested symbols keep their parent; <script setup>, a Svelte
instance script and Astro frontmatter give their top-level calls — a
top-level constant's initializer's included — to the component, while
imports and module-level scripts stay with the file. Svelte 5's
`<script module>` is a module script too.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(js): a CommonJS require and a module path import the file they name
A `require('./application')` was only a call, so a CommonJS file depended
on nothing at file level: Express's lib/express.js showed no imports and
impact missed the files it loads. Local require specifiers are now read
after extraction (both the wasm extractor and the kernel, including its
deferred-decode transport) as `imports` refs from the file, and a JS/TS
module path resolves to its file the way the runtime finds it —
extensions, index files, aliases — which also lands an extensionless
`import './polyfills'` on its file instead of its own import node.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(js): read require imports inside each extractor, so kernel parity holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A block namespace qualifies only its own body (a nested one is Outer.Inner),
mirrored in the kernel; a using names the project's namespace, never another
file's using; a global using is its own project's; a nested type is reached
by bare name only from inside its owner or a type deriving from it, through
any partial part; visible C# types are filtered before ranking.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A Java enum constant or Kotlin enum entry with a class body -
`PLUS { int apply(...) { ... } }`, `NewBuffer { override fun pipe() ... }` - was
recorded as a bare enum_member: its body was never visited, so its methods
were missing and every call in them was dropped. jsoup's tokenizer
(`TokeniserState`, one `read` per state) and tree builder
(`HtmlTreeBuilderState`) are written this way.
The body is now visited under the member (QN `Op::PLUS::apply`), which
counts as class-like so its functions are methods and its properties fields.
Only a `class_body` child is visited, so Rust's struct-like variants (a
`body` field of field declarations) are untouched. Mirrored in the kernel's
Java and Kotlin walkers; kernel parity is byte-identical on the fixtures
(Torture.java gains a constant-with-body enum; torture.kt already had one)
and on gson/koin/okio.
jsoup +2156 edges, okio +138 -23, okhttp +106 -11, gson +97, halo +29,
commons-lang +16; koin, Exposed, mall unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
nlohmann/json's basic_json was lost whole. Offset-preserving preParse
fixes (the kernel parses the same text):
- an access specifier spelled as a macro (JSON_PRIVATE_UNLESS_TESTED:,
Q_SIGNALS:) becomes the keyword it stands for, padded
- a lone attribute macro is blanked after a comment line (/// @sa
https://…/meta/ ends in '/') and after a template head (ends in '>'),
which read as operator continuations; a line's continuation is judged
on its code, so 'CURLE_X, /* 100 */' still continues (curl's enums)
- a preprocessor conditional where the code before it hasn't ended a
statement/declaration (in an initializer list, between a template head
and its function, in an argument list) keeps its first branch:
directives and later branches blanked; #define continuation lines and
statement macros without ';' (RAPIDJSON_DIAG_OFF(x)) are not code
Parse-error files: redis 192->186, curl 210->203, pybind11 98->95,
spdlog 111->110, leveldb 21->20, none newly broken across json, rapidjson,
fmt, jq; kernel parity 0 diffs; basic_json 0 -> 393 members.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
tree-sitter-kotlin 0.3.8 predates `when` guards (2.1), `..<` (1.9),
multi-dollar strings (2.1) and nullable function-type receivers; each
made error recovery drop the class around it (Exposed's dialect and
query classes came out as loose functions).
Offset-preserving preParse rewrites (so the kernel parses the same text):
`is X if cond ->` -> `is X, cond ->` (the condition stops short of
`->`, so `is X -> if (…)` bodies are untouched), `..<` -> `.. `, the
`94189` prefix blanked, `T?.() ->` -> `T.( ) ->`. Parse-error files:
Exposed 65 -> 43, kotlinx.coroutines 50 -> 46; koin/okhttp/moshi/
nowinandroid/okio unchanged, none newly broken; kernel parity 0 diffs.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
`Users.id eq id1`, `single { … } bind I::class`: an infix_expression was
never extracted, so a project's infix DSL had no callers (Exposed's
`eq` > 1,000). Extract it as a call of the middle simple_identifier —
`lhs.fn` when the left operand is a plain name, else bare — in the TS
walker and the kernel (kernel-parity 0 diffs on okio/okhttp/Exposed).
A standard infix name on an expression receiver is gated like a chain
link (`alias(x) apply false` in a build script); a project's bitwise
extension on a number type (okio's `Byte.and`) is never chosen, typed or
guessed, since the stdlib's Int/Long members take `x and 0xff`.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
tree-sitter-kotlin 0.3.8's external scanner inserted an automatic
semicolon on the same line before any word starting with `e` other than
`else`, so Exposed's `Users.id eq id1` ended its statement early and
error recovery could swallow the class around it (r2dbc UpsertTests
became one loose function nesting every test).
Patch scanner.c (same line: never a semicolon before an e-word) in both
the vendored kernel C and the wasm build; provenance, shas and rebuild
recipe in docs/grammars/tree-sitter-kotlin.md. Exposed files with a parse
error 229 -> 71 of 1,004; koin, nowinandroid, moshi, okio, okhttp and
kotlinx.coroutines unchanged (one okhttp file fixed, none broken);
kernel-parity 0 diffs.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
C# / Java / Kotlin receivers that are fields, properties or parameters were
typed only when declared in the calling method without generics, so a call
through a field fell to the receiver-word guess: Newtonsoft's
_innerWriter.WriteValue() landed on the wrapper's own WriteValue, a
TextWriter's Write() on a test writer's, commons-lang's DateFormat field's
parse() on DateParser 284 times.
- read class-level member declarations (brace depth 1, comments skipped),
walking base classes with their type arguments substituted, C# using
aliases, type-parameter bounds, generic and for-each declarations
- C# interface members default public and namespace-level types internal
(TS extractor + kernel, parity 0 diffs); interface calls resolve at all
- the receiver-word guess weighs the owner type's name only, the receiver's
last link (a constant's type), and its head noun; .NET std names need a
receiver named after the owner; production code never lands in a test
suite's mock
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- tree-sitter-kotlin can't read `class Name` / (comments) / `internal
constructor(…) : Super {` on separate lines — the class is dropped and its
members become loose top-level functions (okio's ByteString, Kotlin
Multiplatform's `expect` classes). The Kotlin preParse now blanks that
constructor's modifiers / annotations / keyword to spaces, so `(…) :
Super {` parses as the primary constructor; offsets and lines survive, and
preParse runs before the kernel, so both paths parse the same bytes.
- With members back on their classes, a Kotlin standard-library name on an
untyped chain link (scope functions, collection / string / conversion
methods — not names project types commonly carry) needs a receiver named
after its owner, in the exact / fuzzy filters and the unique-name guess.
A/B (edges removed / added): okio -1028/+1127, okhttp -979/+1145,
kotlinx-datetime -426/+515 (mostly re-keyed onto recovered classes),
koin -60/+4 (`msg.contains(…)` → a dependency map's `contains`).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
tree-sitter-javascript can't parse Flow annotations; `render(): React.Node`
ended a class early (segmented-control's component had no methods). A
`.js` / `.jsx` whose leading comments carry `@flow` (not `@noflow`) now
detects as `tsx`, and the TS extractor's offset-preserving preParse blanks
Flow-only syntax for those files: exact object `{| |}`, a maybe type's `?`,
an inexact object's bare `...`, `import typeof`, `opaque type`. preParse is
hoisted before the kernel, so both paths parse the same bytes;
kernel-parity now routes .js/.jsx through detectLanguage too (RN core
Libraries: 0 diffs over 641 files). Grammar preload adds tsx whenever
JavaScript is present.
Parse errors over 400 RN-core Flow files: 10,626 (JS grammar) → 391 (TSX).
A/B edges: RN core Libraries 29,649 → 38,194 (+12,639 / −4,094, the
removals mostly `root.render(…)` → the one DrawerLayoutAndroid::render the
old parse left, and edges re-keyed onto recovered methods);
segmented-control +35/−5; express and react-native-netinfo byte-identical.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A Kotlin call's top-level candidate (a function, an extension function, a
property) must be in the caller's package, imported by name, or in a
star-imported package. Class members aren't judged: a lambda's receiver can
put any type's members in scope.
A function type with a qualified receiver (`(A.Builder.() -> Unit)?`) broke
the tree-sitter-kotlin parse badly enough to drop the enclosing class;
an offset-preserving preParse blanks the qualifier (hoisted, so the kernel
parses the same bytes — parity 0 diffs on Exposed, okhttp, nowinandroid).
A/B (edges removed / added): Exposed -5370/+4256 (1,318 R2DBC assertEquals
misroutes; DatabaseTestsBase's members and 250 extends/imports edges back),
koin -965/+960, okhttp -690/+675 (567 MockResponse to the imported
mockwebserver3 class), okio -98/+44, nowinandroid -14.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A receiver-less Dart call now reaches only a method of the enclosing class,
something it extends / mixes in / implements, or an extension on one of those
types, and the nearest one wins. The hierarchy is read from each declaration's
head (comments and type arguments dropped), since supertype edges don't exist
on the first pass. Body-less abstract members (extracted as owned functions)
are scoped too.
Mixin-application classes (`class A = B with C;`) were extracted as
`<anonymous>` with no supertypes; both the wasm extractor and the Rust kernel
now name them and emit their extends/implements refs (kernel parity verified
on bloc, riverpod, shelf, dio, getx).
A/B (edges removed / added): riverpod -1945/+517, shelf -785, getx -855/+18,
bloc -178/+95, dio -78.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A `<script>` block goes through the TS/JS extractor, which extracts no
symbol for a method in an object literal — so every Vue 2 component, and
every Vue 3 one not on `<script setup>`, had no `handleLogin`, no
`mounted`: their calls, their `this.$router.push`, and the template's
`@click="handleLogin"` all belonged to the file.
`vue-options-api.ts` reads the options object the default export is
(directly, or via defineComponent / Vue.extend / Vue.component) and names
each function in it — `methods`, `computed` (incl. get/set objects),
`watch` (incl. `{ handler }`), `data`, `setup`, lifecycle hooks, Nuxt 2's
asyncData/fetch — as `method` nodes owned by the component; the Vue
extractor re-attributes the references and edges written inside each.
A component's own method is only reached as `this.m()` in that component:
the member-call and exact-name strategies no longer hand it
`e.preventDefault()` (ImageCropper's `preventDefault` method took every
event's call), `this.editor.setValue()`, or `this.$refs['input'].click()`.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- `app/blog/og-image/[post]+api.ts` was a screen named
`/blog/og-image/[post]+api` (evanbacon.dev). An Expo API route is now one
endpoint per exported HTTP method (`GET /blog/og-image/:post`), bound to
its handler, the way Next.js `route.ts` files are.
- The per-app framework gate (#2129) took ANY enclosing manifest's
declaration: react-native-true-sheet's root declares expo-router for its
example app, so its `docs/` Next.js app got 16 Expo screens (`/layout`,
`/page`, `/api/search/route`, …). Walking up from a file, the first
manifest that names any gated framework now decides.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
create-t3-turbo, tamagui's starter and react-native-reusables keep an Expo
app beside a Next.js app. Expo Router read the Next app's `app/` folder as
its own, so `layout.tsx` became a `/layout` screen, `page.tsx` a `/page`
one, `_components/posts.tsx` and `api/auth/[...all]/route.ts` screens too,
and a shared `packages/app/` library's files became screens as well.
A resolver can now name `appDependencies`; its extractor runs on a file
only when that file's package.json or an enclosing one declares one of
them. When no manifest in the project declares any, detection found the
framework by other evidence and it runs everywhere, as before. Expo Router
names `expo-router`, Next.js `next`.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Found by the README-wide sweep: vendored bundles topped "most depended on"
across many repos — delphimvcframework's bundled `Buffer` (6,162) and four
`n`s (2,386 each), retrofit's docs `main.js` `t`/`e`/`i`, TestBox's
`__webpack_require__` — because only `*.min.js` was recognized as generated.
- detectGeneratedFile (index time, persisted as files.generated) now also
flags a .js/.mjs/.cjs file whose text is mostly lines of 1,000+ chars AND
whose long lines are code (≥3% `;{}(),`) — not an ordinary file carrying
one long base64 string — and any file that defines webpack's
`__webpack_require__` loader, however readable its lines. The path rule
also matches `-min.js` (underscore-min.js).
- Entry points' hubs skip nodes in generated files, as they skip tests.
Scanned every .js file of express, axios, lodash, excalidraw, typeorm, zod,
trpc, hono, bulletproof-react: zero new flags on hand-written code; newly
caught: lodash vendor/underscore/underscore-min.js, retrofit website
main.js (754 KB) + prism.js, TestBox syntaxhighlighter.js (webpack).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
`API.PackageController.GetRoute.query(on:)` kept only `query` — the
receiver was a navigation_expression, not an identifier — and the bare
name exact-matched whichever type's `query` came first. On
SwiftPackageIndex-Server every route type has one, so health checks and
package-controller tests "called" the dependency controller (or a test's
own `query`).
Extraction (TS and the kernel's swift walker, byte-parity): a receiver that
is a path of capitalized type names, two segments or more, not led by
`Self.`, is kept: `API.PackageController.GetRoute.query`. Instance chains
(`self.store.load()`) and mixed paths (`URLSession.shared.data`) are
unchanged.
Resolution (swift-type-visibility.ts, called decisively from
matchReferenceInner so nothing falls through to name guessing): the member
on the type the path names — a method, an enum case with associated values,
or a nested type's initializer. A member's owner path is its qualified name
with the outermost extension's written path read back from its line
(`extension API.PackageController { enum ShowRoute … }` →
`API::PackageController::ShowRoute`), so twin `Feature::State`s declared in
`extension BasicsView.Feature` and `extension ObservableBasicsView.Feature`
are told apart. A path shortened inside its namespace or behind a module
qualifier fits; two owners, or none, leave the call unresolved. TCA's
`@Reducer enum Path { case detail }` generates `Path.State`/`Path.Action`,
so `Path.State.detail(…)` lands on the written case.
A/B vs main (edge diffs, every change classified): SPI 76 retargeted, all to
the type the line names, 7 dropped (Fluent `App.Version.query`, `Plot.Node.*`
— SDK members main pinned on project methods); TCA 61 retargeted, 1 dropped
(`State.StateReducer.scope` → an unrelated `Store::scope`); mastodon-ios 177
retargeted (`Mastodon.API.V2.Instance.instance`, `L10n.Plural.Count.vote`),
11 SDK drops; swift-nio 6 calls into a deprecated alias became instantiates
of `ChannelOptions.Types.*`; IceCubes 1/1, Alamofire 2 SDK drops.
Kernel/wasm parity 0 diffs over 2,752 files on six repos.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
typealias EditorClient = AutocompleteService.Client
& MediaUploadService.Client
is valid Swift, but in a type's body tree-sitter-swift ends the member at
the newline and the `&` line is an ERROR that swallows the enclosing
type. IceCubesApp's 980-line `EditorStore` came out as loose variables
and functions — no class, no init, no methods — so a call in its init
counted as file-level code ("a file that runs something"), and calls
into its methods from the views landed on same-named methods of other
services.
A Swift preParse moves a line-leading `&` onto the line before, for an
indented `typealias`/`let`/`var` statement's continuation lines only.
Same length and line count; the continuation line's tokens sit one
column left (the Swift type gate reads the site's qualifier at that one
column over). Measured shapes: the failure is type bodies only — a
top-level declaration, a function body and a parenthesized type parse as
written, and are left alone; `&&`, `&+` and inout `&x` are never
touched. The preParse is hoisted before the kernel call like the C/C#
ones, so both arms parse the same bytes, and the file no longer defers
to wasm.
Across IceCubesApp, SwiftPackageIndex-Server, swift-nio, Alamofire, TCA
and mastodon-ios (3,000 Swift files) it rewrites exactly the one failing
file, which now parses clean; none newly erroring. EditorStore is a class
again with 38 methods; views now reference it and call its
insertStatusText / runAssistant (62 edges into it), and
`urlSession.upload` no longer lands on MediaUploadService.upload.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(extraction): an MPEG-TS video named .ts is not TypeScript (#1910)
`.ts` mapped to TypeScript by extension alone, so MPEG transport-stream
fixtures (`testdata/*.ts`) were parsed by tree-sitter: ~28 s of CPU for a
900 KB clip, minutes for a directory of them, for zero symbols.
Recognise the stream from the head of the file — the 0x47 sync byte at
offsets 0, 188, 376 and 564 plus a NUL byte, which every stream carries in
its first packets and UTF-8 source never does — and drop it at discovery:
not indexed, not parsed, not counted, not tallied as an unsupported
language. The check reads under 1 KB and only for `.ts` files; the batch
reader sniffs the bytes it already read, and the single-file path (sync,
watcher) does the same head read, so a clip handed in by name is skipped
too. The skip happens before parse dispatch, so no kernel mirror is needed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix(extraction): a video .ts is never pending on the git path or a scoped sync
Review found two places that decide "is this a source file" without the
MPEG-TS check the scan applies: the git fast path's candidate loop in
getChangedFiles and the scoped-sync path filter (watcher events). An
untracked clip in a git repo was reported as `added`, skipped by sync
without a record, and reported as `added` again on every status; a tracked
.ts that became a clip stayed `modified` with its stale nodes. Both now
treat the clip as non-source: removed when tracked, ignored otherwise.
Regression tests fail without this change and pass with it, on both arms.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(extraction): require a binary head before calling a .ts file video (#1910)
Review on #1915: the sniff took four aligned 0x47 sync bytes plus any NUL
as proof of a transport stream, so TypeScript with a `G` at four 188-byte
strides and one raw NUL in a comment was dropped unindexed. The sniff now
needs the sync byte on sixteen consecutive packets (3 KB of head) and at
least 1/64 of the head to be control bytes. Compressed payload carries
8-20% of them (checked on ffmpeg-made H.264/AAC, MPEG-2 and MP2 streams);
source text carries none. A shorter clip is cheap to parse anyway.
Also drops the benchmark figures from the changelog entry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(extraction): a file over the size limit is never read (#1910)
The size gate ran after `readFile`, so a committed video or blob fixture was
decoded in full — 3.4 GB of RSS for a 400 MB file, `Invalid string length`
past ~512 MB — only to be stored as skipped. It was then read again by every
pass that scans files by name: the framework detectors' `readFile` and the
resolver's cached reader, three full passes on the reporter's fixtures.
Stat first, everywhere a source file is read by path: the batch reader and
`extractFile` store an oversize file with a size stamp in place of its
content, change detection hashes the same stamp (so a same-size rewrite of a
file nothing is indexed from is not a change, while crossing the limit in
either direction is), and both by-name readers return null above the limit.
The limit moves to `src/file-limits.ts` so the three sites share one number.
strace on a sparse 400 MB `.ts`: 153 603 reads before, 0 after; indexing it
next to a real file costs no measurable RSS. Stacked on #1914, which shares
the batch-reader hunk.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* refactor(extraction): one-purpose size-stamp reader, comments in operation order
`readSourceOrStamp` took a `stats` argument no caller passed and returned
stats no caller read; it now returns the text or stamp change detection
hashes. The batch reader's two comments are back in the order its code runs:
the size gate, then the MPEG-TS head check. No behaviour change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(extraction): bound the read itself, not only the stat before it (#1910)
A file can grow between the stat that gates the size limit and the read
that follows (a log, a download, a build output being written). Every
source read now goes through readBoundedSource/readBoundedSourceSync: the
open descriptor is re-checked, and the read stops one byte past the limit,
so an oversize file is still stamped rather than decoded. The extraction
batch reader, single-file extraction, framework detectors and the resolver's
file cache all use it. Ported from the maintainer's hardening of this fix
in #1919.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(extraction): bound the parse-retry reads too (#1910)
The retry passes for files whose worker crashed or timed out re-read the
source with an unbounded fsp.readFile. The file can have grown since the
first, bounded read; an oversize file is now skipped by the retry instead
of being decoded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(extraction): check an oversize file against its size stamp everywhere (#1910)
Review on #1915:
- The viewer (readFileShape, hasDriftedOnDisk, the source endpoint) and
MCP's drift gate hashed a file's real bytes, but the index stores the
size stamp for a file over the limit, so every unchanged 1-8 MB file read
as "changed on disk". oversizeStamp moves to file-limits.ts with an
indexedHashInput helper, and all four checks hash what the index stored.
An oversize file is now compared without being read.
- git-index-currency's "keeps a committed path pending when sync cannot
read it" injected its failure only into readFileSync, which the bounded
reader no longer calls, so it failed. The failure now reaches openSync
too.
- The changelog entry drops its benchmark figures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(mcp): check an oversize answer file against its size stamp (#1910)
#2043's answer-freshness check hashes each contributing file whole and
compares it with the stored contentHash. For a file over the index's size
limit the stored hash is the size stamp, so an unchanged oversize file
would read as stale. Compare it by its stamp, without reading it, like
the viewer and the MCP drift gate do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* perf(extraction): judge a .ts clip from the bytes it is read for, not at discovery (#1910)
Discovery sniffed the head of every `.ts` file on every full scan — an
open + 3 KB read + close per file, before anything asked for its content.
On a 10k-file TypeScript tree that took a warm-cache scan from ~105 ms to
~243 ms; on a slow disk or a network share it is a random read per file
per scan, the access pattern #1231 and the SMB reports (#1014, #448) are
about.
The bytes are now judged where they are read anyway, so the check costs no
I/O and runs only for a file that is new or changed: the batch reader (as
before), `indexFile`, the sync reconcile (an untracked clip is skipped, a
tracked file that became one is removed through the same removal path as
a deletion), and both `getChangedFiles` paths. The scan lists `.ts` files
by name again; a test pins that discovery opens none of them on the walk
or the git path. Scan time is back to main's (~98 ms), and a full index is
unchanged within noise.
Also collapses the four #1910 changelog bullets (#1914 and #1915 each added
both) to two, without the benchmark figures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: danusha2345 <danusha2345@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
The in-order commit window waits for the commit cursor to advance before
dispatching more parses. After a store fails, flushOrdered returns at once and
the cursor never moves, so the backpressure loop spun on microtasks forever:
indexAll never settled, a core stayed pinned, and no timer in the process
could fire. It reproduces whenever a store error (a closed database, disk
full, an I/O error) arrives with more files left than the window holds.
In the test suite, which runs from source with a window of one, a test that
timed out mid-index and closed its graph in afterEach wedged the whole worker,
so a loaded Windows run never produced a report.
Stop waiting once a store has failed or the run was aborted, and destroy the
parse pool on that error path so its worker threads do not outlive the index.
The regression test runs the scenario in a child process under a hard timeout.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cpp): macro invocations are not calls; local objects call their constructor
A function-like macro invocation (`TRACE_POINT(1)`) parses as a call, and
the resolver bound it to a same-named free function in another translation
unit — a caller and a callee that never existed (#1838). And local object
initialization (`Widget w;` / `Widget w(1);` / `Widget w{1};`) reached the
class node instead of a constructor, or nothing at all for the default
form (#1839).
Extraction (wasm walker and the Rust kernel, in parity):
- every `preproc_function_def` becomes a `constant` node whose signature
is the directive, so the index knows which names are macros;
- a C++ declaration emits one `calls` ref per constructed object, shaped
`ns::T::T/<arity>`; pointer, reference and function declarators,
`extern`, and array element braces construct nothing; the #1035
`instantiates` ref is unchanged;
- constructors carry their parameter list as the signature.
Resolution:
- `cpp-macro-visibility.ts` walks the translation unit (root file plus
in-repo includes, each file once) over per-file summaries of
function-like defines, undefs and includes, evaluating what each file
can decide itself (literals, its own defines, the include-guard idiom).
A call whose name is definitely a macro at that point, or a name that
only macros bear, resolves to nothing. A macro that exists in one build
configuration only (CMSIS's `__DSB()` under the ARM compilers, a
target's HAL compat header) keeps the call to the function the other
configuration compiles; a wrapper macro that calls its own name is how
that function gets called and hides nothing.
- `cpp-constructor.ts` resolves the constructor refs: the type in the
lexical namespaces of the call site, then the single overload whose
parameter count admits the arguments; two admitting overloads, an
initializer_list overload, or an aggregate yield no edge.
- a `#define` constant is never a `calls` target and does not count
toward the same-name ceiling.
Measured on a betaflight tree (4,017 files, wasm arm): 153 `calls` edges
lost — all fabricated (`MIN`/`MAX` bound to a CLI enum member, macros
misparsed as functions, a cross-vendor `SWAPBYTE`) — and 34 constructor
edges gained; indexing 34s vs 30s.
Fixes#1838Fixes#1839
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix(cpp): resolve local constructors and macro visibility (#1839)
Local construction lacked constructor calls, while macro invocations could bind unrelated functions.
Resolve constructors using lexical types and overload signatures, preserving separately declared defaults and array element construction.
Evaluate macro directives in translation-unit order, respecting reinclusion, guards and pragma once.
Mirror extraction in Rust and WASM, preserve type dependencies, and distinguish them in CLI output.
Co-authored-by: danusha2345 <danusha2345@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: danusha2345 <danusha2345@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* fix(extraction): record callers for methods passed as values (#1820)
pool.submit(obj.method), thread_pool_exec(self.store.fetch), and Go
Submit(c.store.Fetch) produced no callers/impact edge because only
obj.method(...) call expressions were captured. Member values are now
emitted as *.method function-refs and resolve unique-or-drop
(same-file first). Two methods of the same name still produce no edge.
Go go c.store.Fetch(ids) remains a calls edge (it is a call expression).
EXTRACTION_VERSION 27: MCP daemon catch-up rebuilds a stale index on
start so the watcher does not keep serving the hole after upgrade.
* fix(resolution): do not let test mocks veto #1820 method-value callers
A unique production method plus a unit-test double of the same name
was treated as ambiguous, so retrieve_vision_vectors still looked
callback-invisible on a real repo. Prefer the non-test file when
exactly one production target remains.
* fix(resolution): prefer a real override over a NotImplementedError base
#1820 unique-or-drop treated DocStoreConnection.delete_payload_fields
(the ABC stub) and QdrantConnection.delete_payload_fields as ambiguous,
so gc_stale_member_stamps stayed invisible. Skip short not-implemented
stubs when exactly one real implementation remains.
* fix(extraction): preserve receivers for method values (#1820)
Python attributes and Go selectors used as callback values were dropped or reduced to bare method names.
Preserve receiver paths in native and WASM extraction, resolve through type/import scope, and reject ambiguous or noncallable targets.
Cover callback, assignment, collection, and query behavior, with extraction version 27 signaling the required reindex.
Co-authored-by: Josh66 <info@aska-systems.de>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Josh66 <info@aska-systems.de>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(sync): refresh synthesized edges after incremental changes (#1988)
Scoped sync skipped synthesis and retained obsolete dispatch edges.
Refresh all synthesis passes after base resolution when dependencies or source patterns change.
Stage and atomically replace owned edges, preserve ordinary edges, and retry interrupted refreshes.
Stabilize traversal order and migrate existing indexes for rebuild convergence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: preserve structural Go containment during synthesis refresh
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(resolution): stop expression-receiver calls from binding to unrelated methods
A method called on an expression receiver reached the resolver as the bare
method name, and exact-match bound it to any project method of that name:
`(await list()).map(...)` in TypeScript onto a UI adapter class's `map`
(0.9), and `v.iter().map(...)` in Rust onto the same TypeScript method
across languages (0.5).
TS/JS extraction (mirrored in the kernel): look through receiver wrappers
that keep the same object — parentheses, `!`, `as`/`satisfies`, `<T>x`,
`await` (including the grammar's `(a && b)!` parse of `a && b!`) — so
`x!.m()` is `x.m` and `(await f()).m()` is `f().m`; any other receiver with
no static type (`(a ?? b).m()`, `f().list.m()`, `arr[0].m()`) emits nothing
instead of the bare name. `this`/`super` (and chains rooted at them),
`window.*` chains and `new C().m()` keep their existing bare form.
Resolution: a bare-named call may cross a language family only through the
C ABI (a C/C++ symbol, or a free function a C/Objective-C/Swift caller
reaches, e.g. a cgo `//export`). A class member of another family, or a
function/class/variable outside that pair, is rejected as the candidate a
strategy commits to (exact-match single/best and fuzzy), never filtered out
of the pool, so no lone survivor is manufactured.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(resolution): reject unrelated cross-language matches (#1986)
Name-based calls, constructors, and inheritance could select unrelated foreign-language symbols.
Apply a shared interoperability policy to selected results without manufacturing replacement matches, including JSX/Vue synthesis.
Preserve framework exports and ABI-backed calls, building on PR #1944's TS/Rust expression-receiver fixes.
Validate with both repro scripts, 529 targeted tests, kernel/wasm parity, and clean TypeScript checks.
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Same-kind, same-name declarations on one line shared an ID and silently overwrote each other in SQLite.
Use per-extraction collision tracking to append a UTF-16 column only to later distinct declarations.
Apply the same rule across wasm, Rust language walkers, Liquid, and CFML while preserving file IDs and edge endpoints.
Add persistence, call-edge, identity-vector, and Unicode parity regressions.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(scala): resolve extends/with to the trait, not its companion object
The Scala trait + companion object idiom puts two same-named symbols in
one file. Both were indexed as kind 'class', so an 'extends X' reference
tied between the trait and its companion and the winner was arbitrary.
When the companion won, every subtype was detached from the trait's
inheritance chain, and impact analysis on a widely-used trait stopped at
depth 1.
- classify Scala object_definition as 'module' (a singleton value, not a
type - 'extends' can never target it)
- add 'module' to the classifyClassNode contract and handle it in the
extractor dispatch
- in name matching, bias extends/implements references toward actual
type definitions and penalize 'module' candidates, so the trait wins
the tie deterministically
Regression test: trait + companion in one file, subclass in another -
the extends edge must land on the trait and impact must reach the
subtype through it.
* fix(scala): resolve companion inheritance to type definitions (#1824)
Scala objects and their companion types could tie during inheritance resolution, disconnecting subtype impact paths.
Classify objects as modules in both extraction engines and reject Scala singleton inheritance targets across resolution strategies.
Preserve object method lookup and inherited receiver methods, with declaration-order, impact, and native/WASM parity regressions.
Co-authored-by: Hubert Tarnacki <hubert.tarnacki@comarch.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Hubert Tarnacki <hubert.tarnacki@comarch.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(resolution): resolve this.#field.method() on the field's type (#1987)
A call through an ES private field fell outside the `this.<field>` shape
(#1496): the extractor accepted only a property_identifier, so
`this.#items.add(x)` was emitted as the bare `add` and exact-matched
whichever project method shared the name, often the calling method itself.
The extractor and its kernel mirror now keep `this.#items.add`, and the
resolver matches that shape and reads the field's type off the class
declaration. The field regexes open with a lookbehind instead of `\b`,
which never matches before `#`. A builtin or external field type
(`new Set()`, a `Map`, an array) now yields no edge.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(resolution): require receiver evidence for built-in method calls (#1987)
Unknown JavaScript receivers could match unrelated methods by name or class-name similarity.
Require validated receiver evidence for built-in method names while retaining typed, imported, object-literal and class resolution.
Preserve private-field receivers in TypeScript and Rust extraction and keep public/private field declarations distinct.
Build on PR #1990 with regression coverage across all four JS/TS variants and kernel/WASM parity.
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The orphan sweep discarded resolver statistics, so unchanged files caused the CLI to report a no-op after recovery.
Carry processed, resolved, and unresolved sweep counts into SyncResult and report recovery without changing quiet mode.
Cover successful recovery, unresolved attempts, and genuine no-ops with real SQLite regression tests.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
MSVC COM interface declarations were parsed as functions, losing their owners and methods.
Normalize declaration-position interface keywords to padded struct keywords when alias or declaration evidence is present.
Preserve source offsets and protected text through the shared native/WASM preprocessing hook.
Cover real-file indexing, inheritance, source retrieval, and parser parity.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Rust command attributes were not retained as decorators, so runtime entry points could appear as dead code.
Preserve tauri::command metadata in both native and fallback extraction and reuse the existing decorated exclusion.
Add SQLite regression coverage and native/fallback parity checks, including negative cases.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Single-argument function macros were indexed under parentheses in C or the macro name in C++, breaking caller resolution.
Recover both parser shapes only when a preceding local macro definition establishes the function name, and mirror the recovery in the Rust kernel.
Preserve existing multi-argument recovery and ordinary declarations; add extraction, resolution, explore-flow, and parity regressions.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
DFM/FMX component ranges stayed pinned to their declaration lines because closing blocks only popped IDs.
Store nodes in the component stack and update their ending positions at the matching end.
Cover persisted ranges and MCP source retrieval while preserving containment and event references.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Workspace imports could follow excluded dependency archives and decode them without a size guard.
Reuse extraction's 1 MiB limit, reject non-files before reading, and cache null results.
Add sparse-HAR and real ohpm indexing coverage while preserving legitimate import edges.
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(extraction): index Python docstrings, not just preceding comments (#1905)
getPrecedingDocstring only walks preceding comment siblings, so a Python
docstring — a bare string literal first in the body — never reached the
docstring column, never entered nodes_fts, and was never shown by
`codegraph node`. The identical sentence written as a leading `#` comment was
both. For a Python codebase that is most of the prose there is. (#1905)
Adds an optional getBodyDocstring() to LanguageExtractor, in the same shape as
getSignature(), and routes every docstring call site through one docstringFor()
helper that consults both sources. A node carrying a comment AND a docstring
keeps both, joined: they are two things the author wrote about the same symbol
and the column is free text.
The Python implementation reads the grammar`s string_content rather than
slicing quotes off the raw text, so r/u/b prefixes and both triple-quote forms
work without a regex per case; f-strings are skipped because an interpolated
string is code, not prose. Dedent follows PEP 257 (first line exempt).
Scoped to Python deliberately. Julia (a string sibling before the def) and
Elixir (@doc) fit the same hook and are left as follow-ups.
* fix(extraction): index Python body docstrings across backends (#1905)
Python extraction only consulted preceding comments, leaving body docstrings absent from search and rendered prose.
Extend the contributor's hook to module and definition docstrings, and mirror it in the native kernel.
Handle comments, concatenated literals, and indentation consistently while rejecting bytes, f-strings, and tuples.
Verify persistence, exact-name ranking, MCP/CLI rendering, and native/WASM parity.
Co-authored-by: Max Hsu <maxmilian@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Max Hsu <maxmilian@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The vendored grammar (master@0aca5d0a6f, in both the wasm and the kernel's C
sources) parsed `class A(x: X)(implicit y: Y) extends B(x)(y) with C with D`
with an ERROR and cut the extends clause after `B(x)(y)`, so `C` and `D` never
became inheritance edges. Both copies now come from the v0.26.2 release: the
wasm is the release asset, parser.c/scanner.c are the tag's generated sources.
The grammar change is additive over the old pin: no node type or field was
removed.
On two real repos the share of Scala files that fail to parse drops to zero
(lila 85/1565, playframework 83/846), with no file newly failing. Edges from
those files were built from error-recovered trees; playframework, for
example, nested top-level classes inside their neighbours and drew an
`extends` self-loop.
The kernel defer pins used inputs that the new grammar reads cleanly; they
now use inputs that still fail, and the old inputs pin that both paths
extract them in parity.
(cherry picked from commit 199bc8d8a0)
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(extraction): name a function bound through a curried wrapper (#1747)
reactHookBoundName already names an anonymous function after the
variable_declarator that binds it. The shape is general, but the method
is bounded to three React hooks, so `const run =
Effect.fn("Session.run")(function* () {…})` produced no function node at
all -- and its body's calls were attributed to the enclosing container,
so a file gained an outgoing edge belonging to a function and the
callee's caller list named the file instead.
Bound the new path by a different, equally decidable test: the callee is
itself a call, i.e. a factory returning the wrapper. That admits
Effect.fn(...)(fn), connect(mapState)(fn) and a project's own
wrap("n")(fn), and excludes the single-call forms whose argument is a
computation -- useMemo(() => …, []), arr.map(…) -- which stay anonymous
exactly as before. Widening to "any callee" would have given useMemo a
function node and reddened react-hook-handlers.test.ts.
Generators are admitted here and not in reactHookBoundName: a React
handler is never a generator, while function* is the common form in the
ecosystem this shape comes from, and it is what the report opens with --
broadening the callee test alone would not have fixed that repro.
Mirrored in the Rust kernel; kernel-parity.mjs reports byte-parity on
the new shape.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgtWMywGTyu6twnk1Bu9nP
(cherry picked from commit 4f2b40080d)
* fix(extraction): name a curried-wrapper function that is an object member (#1747)
The curried-wrapper bound stopped at a variable_declarator parent, so
`return { getMode: Effect.fn("ACP.Session.getMode")(function* () {…}) }`
still produced no function node. An Effect service is usually an object a
factory returns, and on sst/opencode (df23b7f) these member positions were
the bulk of what the branch missed.
The member already has a name in the source: its property key. This repo
names `key: () => {}` pairs by that key (extractObjectLiteralFunctions /
objectKeyName), so a `pair` parent is now named the same way. The
callee-is-a-call rule is unchanged, so `key: useMemo(() => …, [])` and
`key: arr.map(…)` stay anonymous.
extractObjectLiteralFunctions also reaches such a member, because an
exported object with an inline function member is extracted member by member
and its initializer is never walked.
A wrapper passed as an argument to another call has no binding at all and is
left as it was.
Mirrored in the Rust kernel; kernel-parity.mjs reports byte-parity on the
new shapes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dfb3aazPY1ccmp5vam4k3L
(cherry picked from commit bbdef20542)
* chore: drop CHANGELOG entry (collected separately)
---------
Co-authored-by: Max Hsu <maxmilian@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
`extension_type_declaration` appears in none of the three places Dart's other
type-like declarations do. `extension_declaration` — the older `extension` — is
in all three, and the two names are near neighbours.
That is why #1780's `isInsideClassLikeNode()` gate dropped these members and no
others: the gate asks whether a class-like node is on the stack, and an
`extension type` never put one there, while `extension`, `mixin` and `class`
all did. The gate surfaced the omission rather than causing it. Before it, the
members were still reached — but as top-level `function:km` rather than
`method:MetersT::km`, indexed and attributed to nothing.
The kernel omits the same node type, so it walks the members through its own
fallback and mints them as top-level functions with no `MetersT` to belong to.
`kernel-dart-parity.test.ts` fails four cases on `main` because of it; fixing
only the wasm side would leave those red.
Listing it alongside the others is the whole fix — `extraClassNodeTypes` and
`dartEnclosingTypeName` on the wasm side, the two `matches!` arms on the
kernel's. Both paths now give:
class:MetersT · method:MetersT::km · method:MetersT::report
with `report`'s span running to its closing brace rather than stopping at the
signature line, and an ordinary class untouched.
Two bugs in the MyBatis mapper extractor:
1. A close tag with trailing whitespace (`</select >`, legal XML) was not
matched by the statement regex, causing the non-greedy body to overshoot
to the next close tag — silently swallowing the statement in between.
Fix: add `\s*` before `>` in the close-tag pattern.
2. A fully-qualified `<include refid="com.example.M.base">` had every dot
replaced with `::`, producing `com::example::M::base` — which never
matched the fragment node's `qualifiedName` (`com.example.M::base`).
Fix: split on the last dot only, matching `qualifyStatement`'s logic.
Also fixes the include-offset calculation to derive from the opening tag
length rather than subtracting the close tag, so it stays correct when the
close tag carries trailing whitespace.
Closes#1209
* fix: index Java packages named build (#1642)
* fix(extraction): preserve Java packages named build (#1642)
The default build-directory exclusion hid legal Java package paths before extraction.
Retain the contributor's main/test Java source-root exceptions, restricted to directories so other default exclusions survive.
Cover filesystem and git enumeration, explicit ignores, indexed retrieval, and incremental sync.
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(extraction): preserve Java packages named build (#1642)
The default build-directory exclusion hid legal Java package paths before extraction.
Retain the contributor's main/test Java source-root exceptions, restricted to directories so other default exclusions survive.
Cover filesystem and git enumeration, explicit ignores, indexed retrieval, and incremental sync.
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Fixes#1861. Reuses L4XB's receiver retention and owner resolution from #1866, with duplicate-owner and edit/sync guards.
Co-authored-by: L4XB <lukas.buck@e-mail.de>
Preserve the indexed-commit approach and regression cases from #1848, with dirty-path retention, commit-race guards, NUL Git paths, and failed-I/O recovery.
Fixes#1829.
Co-authored-by: Eric Minish <eric.minish@gmail.com>