mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-26 04:19:33 +08:00
main
24
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3a93f57ae1 |
fix(java): a record is indexed as a class, with its components' fields and accessors
Neither engine treated record_declaration as a class type, so a Java record
left no node of its own. Its methods and explicit constructor became
package-level functions (p::norm, p::Point), a nested record's methods were
filed under the class around it, compact constructors, static fields and
records nested in a record were dropped, and calls on a record-typed value
resolved to nothing or to a same-named member of another type.
The Java extractor and the kernel now treat record_declaration as a class
and a compact constructor as a method. Each component becomes a private
field ("<Type> <name>") and a public accessor name() with the component's
type as its return type, unless the body declares it; they are synthesized
before Lombok's members, the same way.
An implicit accessor is reached only through what types its receiver: a
typed receiver, a method reference, a qualified call, or a call from inside
the record. The name-only strategies (the receiver-word guesses, exact-name
and fuzzy matching) no longer settle on one, so result.content() on a
library type stops linking to whichever record has a content component.
Records usually sit in sealed hierarchies, and that exposed a resolver gap:
the member-type reader took the head "sealed interface Blocks permits Block"
for a member named Block of type "permits", typed the receiver of
Block.fromKey(...) inside the record as a built-in and dropped the call.
"permits" and "throws" are now among the words that are not a type there.
Validation:
- java-records.test.ts, 5 cases on both engines (10 tests), all red on
main; the sealed-permits and name-only-guess cases are each red without
their resolver line.
- Kernel parity: TortureRecord.java in the torture and CRLF runs; real-repo
sweeps at full parity with deferrals unchanged (jextract 218/218,
spring-modulith 682/682, playframework 801/801, kestra 2997/2997,
spring-ai 2491/2492, Minestom 1859/1894).
- A/B against main
|
||
|
|
0d46dba08f |
fix(js,ts): a call on a new C() receiver resolves through C
A TypeScript or JavaScript call on a constructed object, new C(args).m(),
reached the resolver as the bare method name in both engines, so exact
matching bound it to any project method called m: new RegExp(p).exec(s)
to a database wrapper's exec, new Array(n).fill(0) to a text class's
fill, new TextEncoder().encode(s) to a project encode function.
Both engines now emit new C().m (new ns.C().m for a namespaced class, and
nothing for a constructor that is not a plain name or member chain). The
resolver looks m up on C with resolveMethodOnType, inherited methods on
the conformance pass once extends edges exist, an aliased named import
mapped back to its class, and a JS built-in (RegExp, Map, Date...) never
a project class unless the file imports or declares one. An ES5
constructor function keeps its prototype method.
Our changes: the lookup passes the file the call's file imports the class
from (tsImportedTypeFile), so of two classes sharing a name the imported
one is the one constructed (the PR as written took the first indexed copy,
at 0.9); new this.constructor() and a static new this() keep the bare
method name, as a call on this does (the PR dropped three.js's clone
idiom, 29 links to a class's own copy); rebased onto PR #2852, which
edits the same keepsBareTsJsReceiver and test lists; resolved the import
list conflict with rustChainedCallByName from PR #2846; CHANGELOG bullet
moved next to the JS/TS receiver bullets.
Validation: the new tests fail 4 of 6 on main
|
||
|
|
449eefa7da |
fix(js,ts): a call on an element of a class field reaches the element's type
A TypeScript or JavaScript method called on an element of a class field, like this.handlers[type].handle() or this.items[0].save(), kept the bare method name: a member chain rooted at this collapses to it so the resolver can read the owner off the enclosing class. A subscript in the chain leaves the resolver nothing to read, so the bare name exact-matched any project method of that name, often another class's (this.listeners[type].push(h) reached an unrelated UndoStack.push). Both engines now emit this.<field>[k].<m>() as this.<field>[].<m>, and this['svc'].m() as this.svc.m; any other subscript in a this-rooted chain, or under window, emits nothing, as arr[0].run() already did. The resolver reads the element type the field's declaration writes (X[], Array<X>, ReadonlyArray<X>, Record<K, X>), on the calling class or a base, and resolves the method on it or leaves the call unresolved: a type parameter of the declaring class, a union with another type, an array of arrays or a non-plain element hold no one type. The class type-parameter reader now reads from the keyword to the list's own >, over several lines and through braces in constraints. Our changes: kept escapeRegExp from PR #2769 in the conflict; the type-parameter reader also accepts the type keyword, since the T['p'] path passes type-alias owners and the PR as written read State<Item>['current'] as the project class Item (new case in ts-array-annotated-receivers); CHANGELOG covers JavaScript and asks for a re-index. Validation: the element tests fail 10 of 11 on main with both engines; the type-alias case fails on the PR as written and its brace half on main. A/B against main, kernel built per arm: flask and gin byte-identical. TS: pixijs 7 links added, 5 retargeted and 5 typed, all right, 15 removed (9 wrong, 6 right only by name: a cast, a mixin's this, a T[] parameter, a merged mixin member, an index-signature type, an any field); typeorm 3 wrong removed, 1 right lost, 2 retargeted to the declared interface; excalidraw 1 wrong removed; vscode's base and editor 19 added, 24 retargeted and 35 typed, all right, 45 removed (37 wrong, 8 right only by name: a getter, an index-signature field, deep chains, a T[] parameter, a union alias). JS: three.js, playcanvas and pdf.js lose 288 bare-name guesses, about 230 of them wrong (array, Map and DOM calls on project classes). Kernel parity holds on every repo with deferrals unchanged. Index CPU time within noise (pixijs 32.4 s to 33.3 s, three.js 64.7 s to 67.9 s, medians of 3 interleaved). Original PR #2766 by @inth3shadows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
8afb970a23 |
fix(ts): an awaited call with type arguments links to its callee (#2595)
tree-sitter-typescript parses `await f<T>(x)` as a call whose callee is `await f`, so the reference was named `await f` and matched nothing. Both engines now peel the await, skipping a comment after it, and the reference sits where the callee starts, as for `await f(x)`: on the call node, which starts at await, the checks that read the source at a call's position missed the callee, and a package-imported `await get<T>()` linked to a project class's static get. A/B: excalidraw +2 (compressData, decompressData), vben +6, zod and bulletproof-react unchanged. Fixes issue 2586. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3f714bcc48 |
fix(jsx): a .jsx component links to the file-scope values it reads, as in .js and .tsx (#2561)
Value-reference edges (a reader symbol -> the file-scope const/var it reads, which impact follows) ran for typescript, tsx and javascript but not jsx. A .jsx file is its own language, parsed with the JavaScript grammar, so the same component had no edge to the lazy page it renders (`<LoginPage />` under `const LoginPage = Loadable(lazy(...))`), the route table or the config it maps over as .jsx, and all of them as .js or .tsx. Every other JS-family gate in the extractor lists jsx, and nothing in the history says this one was left out on purpose: the kernel mirrored the gap with an explicit "NOT jsx" check for parity. Add jsx to VALUE_REF_LANGS and drop the kernel's jsx exclusion. On mantis, matx, berry, mastodon and bigbluebutton-html5 the index only gains edges (35, 56, 15, 28 and 266): no node, ref or file changes and no edge removed. Every added edge is a same-file read of a file-scope value that is the only binding of its name in the file. A repo with no .jsx files indexes byte-identically, and kernel-parity.mjs shows 0 diffs over those repos with the same deferrals as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
78f5c8893a |
fix(react): a typed styled component is a component, not a constant (#2429)
`const Wrapper = styled.div<WrapperProps>` + a template literal came out as a
`constant`, so the JSX-render synthesizer skipped it: `<Wrapper>` got no
render edge, or bound to a same-named component in another file.
tree-sitter's tagged-template call takes no type arguments, so when the type
argument also reads as an expression the initializer parses as comparisons,
`(styled.div < WrapperProps) > template`, not as a call. (A type argument
that can't be an expression, `<{ open: boolean }>`, error-recovers into a
call on the tag, which #841 already took.)
reactComponentHoc now also takes that comparison chain: the leftmost operand
is the `styled` tag against a `<`, the rightmost is the template against a
`>` (`>>` when the type argument ends in its own `<...>`), and operators in
between belong to the type argument (`<A & B>`). Mirrored in the kernel's
TS/JS walker.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
5ace306b7c |
fix(kernel): a Go value like wm.new or raft.None keeps its function ref (#2401)
* fix(kernel): a Go value like `wm.new` or `raft.None` keeps its function ref
The kernel's Go fn-ref capture checked a selector value's field name
against the name stoplist, so `raft.None`, `compression.None`, cgo's
`C.NULL` and a method value like `sync.Pool{New: wm.new}` were dropped.
The wasm extractor, the reference, applies NAME_STOPLIST to the
normalized name (`raft.None`), which the stoplist never matches. It also
builds that name from the operand and the field, so a line break or
comment beside the dot keeps the candidate; the kernel validated the
selector's whole source text and dropped it.
Build the name from operand and field as normalizeSpecial does, and drop
the field-name check. No other walker has the pattern: each applies the
stoplist to the same name as its TS spec.
kernel-parity.mjs --lang go: prometheus 202 -> 0 function_ref diffs,
etcd 6 -> 0, golang/go 35 -> 0, kapacitor 2 -> 0, plus 0 on gin, grpc-go,
hugo, caddy and go-ethereum. Indexed with both kernels, edges are
unchanged on prometheus, etcd, gin and hugo; kapacitor gains the one
missing edge, NewExecutor -> workerMaker::new.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(kernel): note that a comment before the dot keeps a Go selector value too
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
5f5b8db620 |
fix(js,ts): find a store exported by an export { } list when its name starts or ends with $ (#2384)
TreeSitterExtractor.isExportedLater and its kernel mirror is_exported_later
bounded the name in the `export { ... }` branch with `\b`, which takes a `$`
for a separator. It never fires beside a leading or trailing `$`, so
`const items$ = create(...)` + `export { items$ };` (or `export { $items as
default };` for a `$items` store) never matched, and the store's actions
were not extracted on either engine. It also matched inside a longer name:
`export { useStore$ }` or `export { $useStore }` counted as exporting a
store named `useStore`.
The clause branch now bounds the name with a character that can't continue
an identifier. The regex crate has no look-around, so the bounds consume,
and both sides spell the class in ASCII, since the crate's `\w` is Unicode
while JS's is ASCII. Plain names decide as before apart from the two false
positives. A non-ASCII letter written against the name (`export {
éuseStore }`) used to split the engines (the kernel's Unicode `\b` said not
exported, the wasm path exported); both now give the wasm answer.
Adds kernel/wasm parity cases (ts/tsx/js/jsx) inside 'a store exported by a
later statement', and the same cases in store-exported-later.test.ts, for
`items$`, `$items as default` and both false-positive shapes. They fail with
the unfixed kernel and with the unfixed TS on the wasm path, and pass with
both fixes.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
5b73d0fd46 |
fix(js,ts): find a store exported on a later line when its name contains $ (#2366)
TreeSitterExtractor.isExportedLater put the binding name into its regex
unescaped. A `$` in the name (`items$`, `$store`, `a$b`) became an
end-of-line anchor, so `const items$ = create(...)` + `export default
items$;` never matched and the store's actions (e.g. `function inc`) were
not extracted, while the kernel mirror escapes the name with regex::escape
and extracts them. The same anchor also matched where it should not: a
store named `items$` read as exported when a multi-line `export { ... }`
ended a line with `items`.
The kernel routes TS/TSX/JS/JSX by default, so the wasm path is what files
with parse errors (deferred to wasm), Svelte/Vue/Astro script blocks and
runs without the kernel get. Escape the name the way regex::escape does;
the guard limits names to [A-Za-z0-9_$], so only `$` changes. `\b` stays
as is on both sides: next to a leading or trailing `$` it never matches
(`export { items$ }`), the same in both engines.
Adds a kernel/wasm parity case (ts/tsx/js/jsx) for `items$`, `$store` and
`a$b` plus the false-positive shape; all 16 fail with the name unescaped
and pass with the fix.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
aeb8f95581 |
fix(kernel): find a store exported on a later line in CRLF TS/JS files (#2364)
The kernel's is_exported_later mirrors TreeSitterExtractor.isExportedLater's multiline regex, but JS's `m` flag treats `\r` as a line end while the regex crate's `(?m)` sees only `\n`. On a CRLF checkout (Windows, autocrlf) a line like `export default useStore;\r\n` matched in wasm but not in the kernel, so `const useStore = create(...)` + `export default useStore;` lost its actions (e.g. `function inc`) on the default kernel route for TS/TSX/JS/JSX. Compile it in CRLF mode, `(?mR)`: `^`/`$` then treat `\r` as a line end too, and the pattern body stays byte-identical to the TS regex. It agrees with the JS regex on CRLF, trailing whitespace and lone `\r` line ends, where an optional `\r?$` would still miss a lone `\r`. This was the only `(?m)` regex in the kernel. The other tsjs regexes are whole-string anchors, and the minified-bundle check splits lines on `\n` exactly as the TS does. Adds a kernel/wasm parity case (ts/tsx/js/jsx, LF and CRLF) that fails on the unfixed kernel for all four CRLF variants and passes with the fix. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f40db4b9cc |
fix(js,ts): index the functions in every named object literal, not only exported ones (#2300) (#2363)
Issue #2300: a function written inside an object literal became a symbol
only when the object was an `export const`. A plain `const api = {...}`,
an object declared inside an IIFE or a function, and a namespace hung on
the page (`window.WS = {...}`, `ns.mod = {...}`) produced no member nodes,
and no node for `WS` either. Calls made inside those members were credited
to the enclosing constant or lost, and calls into them resolved to
nothing. Script-tag JavaScript, written almost entirely this way, was
mostly missing from callers and impact.
Cause: the TS/JS extractor, and the kernel's tsjs mirror of it, minted
members only for exported object-of-functions; any other literal was
walked as one opaque initializer, and an assignment to a member path was
never a declaration. Resolution had no way to reach a member through
`App.init()`, `window.App.init()` or `App.utils.pad()`.
Fix (extraction, TS and kernel byte-identical): a named object literal
owns its function members (method shorthand, `key: function`, `key: () =>`,
generators; static keys only), whether it is declared at module scope,
in a function body or IIFE, assigned to a path (`window.App = {...}`,
`App.utils = {...}`) or assigned to a plain name at module level
(`dw_page = {...}`). Members are `function` nodes qualified under the owner
(`api::load`, `window.App::init`, `App.utils::pad`), the exported case
included; a path owner is named by its last link and qualified by the
path. Calls in a member are the member's; other values are walked where
they were before. CommonJS exports, prototypes, `this.x = {...}`,
call-argument literals, a name reassigned inside a function, and
generated or minified files keep the old shape. Minified files are now
also recognised by content, in both extractors, and the kernel's
`.min.js` pattern matches the TS one.
Fix (resolution): a member is reached through its object only:
`App.init()`, `window.App.init()`, `App.utils.pad()`, a sibling's
`this.render()`, a `const { init } = App` binding; never a bare `init()`.
A same-file holder is chosen by lexical block (an IIFE's own `App` first);
otherwise a global one (`window.App = {...}`, or a classic script's
top-level `App`) when the caller neither imports nor binds the name.
Arrow members keep the `this` of the method around the literal, in the
`this.x` resolvers too. A dotted-path holder is never reached by its last
name alone, and Svelte's `$store` rule now applies only in `.svelte`
components, so the new local holders are not taken for `$n` in plain
scripts. The lookups read each file once (destructuring patterns only
when the raw text has a `} =`) and keep only the last 32 files' scans.
Contributor PR #2310 (@danusha2345): adopted its model (owner-qualified
members exported or not, path owners, IIFE/local owners, static keys,
no bare-name reach, `<script setup>` contains edges, SFC languages, test
scenarios), re-implemented on current main. Not taken: the
EXTRACTION_VERSION bump (already 28), the extraction-time binding oracle
with its ref/edge metadata and kernel ref patching (replaced by
resolution-time lookups), naming the owner `window.WS`, rewriting
`window.X.m()` ref names, flipping exported members' isExported, and
unrelated bare-call changes.
Verification: new js-object-literal-members suite (native + wasm, 18
tests); the issue's shapes fail on main and the guard test fails without
the guards. kernel-tsjs-parity passes with CODEGRAPH_KERNEL_EXPECT=1
(object-literal owners LF/CRLF, minified bundles); kernel parity sweeps
show 0 diffs on DokuWiki, vue-realworld, TodoMVC, excalidraw and this repo.
Validation (kernel loaded, before = origin/main
|
||
|
|
8998697f1d |
fix(vue,ts): link calls in Vue templates and in top-level destructuring (#2340) (#2357)
`codegraph callers <composable>` missed most of the components using it in a Nuxt app (Issue #2340), through two extraction gaps: - A destructuring declaration at module or `<script setup>` scope (`const { a } = useFoo(1)`, `const [b] = useFoo(1)`) mints no symbol, and extractVariable skipped its declarator with `continue` before walking the initializer, so the call was never recorded (inside a function the body walker reached it). The declarator is now walked the way a function body walks it, with the enclosing scope on the stack: the file for module code, which a `<script setup>` block folds into its component. Defaults in the pattern and calls inside callbacks in the initializer count too. Mirrored in the native kernel (tsjs/extractors.rs), which extracts TS/JS in released builds. - The Vue extractor parsed only `<script>`, so calls in the template (`{{ useBar(link) }}`, `:to="useBar(link.location)"`, `v-if`, `v-for` sources, `@click="save(item)"`) made no reference. The new vue-template-calls scanner reads the root `<template>` quote-aware, collects interpolations and directive values, and names each callee the way a script call is named (`useBar`, `store.fetchUsers`). It skips `v-for` aliases and slot props in their element's subtree, arrow and function parameters, `$`-helpers, Vue's template globals, strings, regex literals, `new X()`, object-method shorthand, `v-pre` subtrees, custom blocks and non-HTML templates. Each call is a `calls` reference from the component at its own line and column; a bare call to the component's own Options API method is linked at extraction, since resolution only binds those through `this.`. Two resolution follow-ons, found validating on elk: - The vue-handler synthesizer resolved the leading identifier of every `@event` value, so `@click="save(item)"` got a second, line-1 edge, and `@click="query = ''"`, a slot prop's `hide()` or a `refresh()` destructured from useAsyncData were bound to any same-named function in another file. It now resolves only a bare handler name (`@click="save"`) and keeps its composable-destructure mapping. - The Nuxt auto-import rule answered a call to a file's own `clearError` or `navigateTo` with an edge from the caller to itself. A same-file declaration of that name now shadows the auto-import. Verification: new tests in vue-template-calls.test.ts (scanner shapes and four indexed projects, incl. the issue's repro), extraction.test.ts (module-scope destructuring in ts/tsx/js/jsx; script-setup + template refs, LF and CRLF) and kernel-tsjs-parity.test.ts (destructuring, kernel vs wasm). On main (src + kernel reverted) the 10 indexed/extraction tests fail and the 4 parity cases fail with the main kernel; all pass with the fix (CODEGRAPH_KERNEL_EXPECT=1). Issue repro on the built CLI with the kernel: callers useFoo 2 -> 5 (A.vue, B.vue, F.vue, G.ts, D.ts), callers useBar 0 -> 2 (H.vue, I.vue). kernel-parity.mjs over elk, nuxt/movies and fastify: 467/471 files byte-identical, 0 diffs, 4 deferred. Validation (kernel loaded, main vs branch, edges by natural key): elk 6282 -> 6633 (+443 / -92), vue-element-admin 2337 -> 2372 (+60 / -25), nuxt/movies 939 -> 959 (+26 / -6), fastify (plain JS control) no edge change. Every removed edge is a line-1 vue-handler edge whose pair is now linked at the handler's line (101), a name-collision guess (8), or an auto-import self-loop now resolved to the local function or route (14). Self-loops: elk 44 -> 30, others unchanged. Builds on #2341 by @drakeo338 (walk the destructuring initializer) and the template scan in #2073 by @L0garithmic. Co-authored-by: drakeo338 <paranoyouz@gmail.com> Co-authored-by: L0garithmic <L0garithmic@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
5eaa6fedd5 |
fix(extraction): preserve receivers for method values (#1820) (#2034)
* 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> |
||
|
|
9649ce1bd6 |
fix(resolution): reject unrelated cross-language matches (#1986) (#2032)
* 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> |
||
|
|
86708bf519 |
fix(extraction): preserve symbols with colliding same-line IDs (#1349) (#2030)
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> |
||
|
|
b65e05b98f |
fix(resolution): require receiver evidence for built-in method calls (#1987) (#2028)
* 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> |
||
|
|
bd993b12fa |
fix(extraction): index Python body docstrings across backends (#1905) (#2004)
* 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> |
||
|
|
cabe319939 | test: cover audited call and extraction regressions | ||
|
|
de5adba7ea |
fix(resolution): leave built-in Map calls unresolved (#1566) (#1790)
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com> |
||
|
|
5e329adc28 |
fix(kernel): CRLF docstring parity — JS multiline ^ anchors after \r, regex crate's (?m)^ is \n-only (#1329)
On CRLF checkouts (every Windows autocrlf clone) the JS reference's block-continuation strip /^\s*\*\s?/gm finds a line start after the \r and its greedy \s* consumes the \n, leaving a bare \r in the docstring; the kernel's (?m)^ pass matched after \n only and kept \r\n. Caught by the O2 Windows VM leg (6 kernel-tsjs-parity failures), reproduced on macOS by CRLF-converting the fixtures. js_multiline_strip now replicates the JS anchor set (\n, \r, U+2028, U+2029) for all five line-marker passes; CRLF variants of every torture fixture are pinned in kernel-tsjs-parity, derived in-memory so nothing can normalize them away. Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c2503e2bee |
feat(kernel): R5 — Python and Go ports, gates passed, default-on
Python (codegraph-kernel/src/python.rs) and Go (src/go.rs) join the native kernel, mirroring the wasm extractors bug-for-bug. Python: decorated_definition docstrings/decorators (decorates refs only for bare-identifier decorators — the call-kind quirk), function-in-class → method, module-level assignments always extract as variable, from-import per-name binding refs, self.x fn-ref candidates as bare names. Go: receiver methods with Recv::name qualified names + contains edges to the first earlier struct of that name, type_spec struct/interface classification with embedding→extends and interface method nodes, composite-literal instantiates keeping the package qualifier, top-level var/const initializer walks attributed to the declared symbol (#693), 2-hop field chains (#1276), New().Method() re-encode (#645/#608), and the GO_SPEC fn-ref layers. Grammars: tree-sitter-python 0.23.6 + tree-sitter-go 0.23.4 crates, with wasm vendored from the same tags (parser.c sha-matched) — both were 2023-era in tree-sitter-wasms. Gates: extraction sweeps 100% (flask 83/83, django 3,035/3,038 +3 error-file deferrals, gin 99/99, prometheus 978/979 +1); full-init dump-diffs byte-identical on flask (10,833 rows), gin (17,540), django (360,794), and prometheus (213,758); torture fixtures enforced in npm test. DEFAULT_ROUTED now covers typescript/tsx/javascript/jsx/java/ python/go. Full suite: 2,471 tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
03d54e47a1 |
feat(kernel): R4 — Java port with Lombok synthesis, gate passed, default-on
Java joins the native kernel (codegraph-kernel/src/java.rs), mirroring the wasm extractor's Java paths bug-for-bug: package namespaces, imports, javadoc, annotations→decorates, type_list inheritance, static-final constants, enum constants, anonymous classes (including the TS side's 0-based-line quirk on the extends ref), method_invocation calls with the this.field unwrap and the Foo.getInstance().bar() chain encoding (#645/#608), static-member value reads, method-reference fn-refs (#756), value-reference edges, and the full Lombok member synthesizer (#912: Getter/Setter/Data/Value/Builder/ToString/ EqualsAndHashCode/Slf4j-family with taken-member dedup). The shared docstring/textutil modules moved to crate level. Grammar: tree-sitter-java 0.23.5, with the wasm grammar vendored from the same tag (parser.c sha-matched) replacing tree-sitter-wasms' 2023-era build. Gate (plan §4c): extraction sweeps 100% — gson 262/262, retrofit 341/341, dubbo 4,048/4,048 — plus a Java torture fixture in npm test; full-init dump-diffs byte-identical on gson (49,766 rows), retrofit (62,735), and dubbo (441,266 rows); all R2/R3 repos re-verified; Linux container runs all 23 kernel tests green under CODEGRAPH_KERNEL_EXPECT=1. The gate caught a real cross-language bug: fn-ref dedupe and value-ref self-target checks must compare node ID STRINGS, not node-table rows — ids collide for same-(kind, name, line) nodes, which minified one-line bundles hit routinely (retrofit's website JS exposed it; latent in the TS/JS walker since R2, never released). Fixed in both walkers. Benchmark honesty: dubbo fresh-init on an 11-core Mac is ~flat (parse-loop wall 5,020→4,394ms; total ~11.3s both arms) because that wall is main-thread-bound (reads + store), not worker-CPU-bound — the §6 expectation assumed otherwise. Where worker CPU binds the kernel delivers: dubbo on a 2-CPU/6GB container drops 27.8-28.6s → 22.3-22.8s (~1.25×). The identified lever for the many-core headline is decoding kernel buffers directly into store rows (skipping per-node JS object materialization); the buffer contract already carries everything. DEFAULT_ROUTED now includes java. Full suite: 2,467 tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c8cca9a601 |
feat(kernel): R3 — TS/JS equivalence gate passed, kernel default-on
Gate evidence (docs/design/rust-kernel-migration-plan.md §4b):
- Graph parity, byte-identical (stronger than the §5 ≤0.5% bar): full
codegraph-init dump-diffs kernel-vs-wasm on express (13,712 rows),
excalidraw (89,898), and vscode (2,378,238 rows) — identical bytes.
Python control repo (flask) identical + timing unchanged. The parity
harness is now ORDER-sensitive (emission order drives rowids, which
drive resolution order) and dumps come from the new
scripts/dump-graph.mjs (natural keys, no rowids/timestamps).
- The one real find, caught by the vscode tier: tree-sitter error
RECOVERY is encoding-dependent — byte-identical grammar sources and
the same core (0.25.10) recover erroring files differently under
UTF-8 (native) vs UTF-16 (web-tree-sitter) parsing; proven by
reproducing the wasm tree with a native UTF-16 parse. Policy: the
kernel defers any file whose tree has_error() to the wasm extractor
(silent 'defer:' signal, per file) — parity by construction on
erroring files (incidence 0-0.42% across the gate repos), and the
harness fails if deferrals exceed 10% so a broken kernel can't hide
behind the fallback.
- Retrieval invariants: canonical excalidraw flow (mutateElement →
renderStaticScene) connects end-to-end on the kernel-indexed graph;
synthesized-edge families present. Agent A/B is vacuous under
byte-identical DBs (same justification as #1320-#1322).
- Perf: vscode init 105.4s → 82.1s (1.28×) on an 11-core Mac;
excalidraw on a 2-CPU/6GB Linux container (the CI-runner envelope)
6.2-7.1s → 4.3-4.8s (~1.5×). Linux arm64 in-container build: all 22
kernel tests green under CODEGRAPH_KERNEL_EXPECT=1. Windows VM leg
deferred (VM stopped; prlctl start needs Parallels Pro) — benign: a
missing .node falls back to wasm, and the release matrix builds and
gates the win32 prebuilds.
- Full suite: 2,465 tests pass WITH default-on routing, so the entire
extraction corpus now exercises the kernel for TS/JS wherever a
.node is staged.
DEFAULT_ROUTED = {typescript, tsx, javascript, jsx}. Override:
CODEGRAPH_KERNEL_LANGS (replaces the set) / CODEGRAPH_KERNEL=0 (kill).
Changelog entry added under [Unreleased].
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
9ad5cd7ba2 |
feat(kernel): R2 — full TypeScript/JavaScript extraction port, byte-parity with the wasm path
Replaces the R1 seed .scm emitter with a bespoke Rust walker (codegraph-kernel/src/tsjs/) that mirrors TreeSitterExtractor's TS/JS paths function-for-function: declarations (incl. #808 field/property classification), qualified names, docstrings (#780 wrapper climbs), signatures, imports/re-exports + per-binding refs, calls with receiver-qualified callees (#1230 literal-receiver skip), instantiations, decorators, inheritance, type annotations (#381), type-alias members + tuple contracts (#359/#634), React component recognition (#841 forwardRef/memo/styled), object-of-functions / zustand-through-middleware / RTK Query endpoints + generated hooks / vuex + pinia store shapes, function-as-value capture with the flush gate (#756), and value-reference edges with the shadow prune (#895/#897). The generic query emitter is deleted — extraction parity needs logic .scm can't express; future languages get walkers too (migration plan §4a). Positions and JS string-slice semantics are emitted in UTF-16 code units natively, so kernel output is byte-identical to web-tree-sitter's — no column diff class exists. Parity evidence (macOS): scripts/kernel-parity.mjs (full-object multiset diff per file) — this repo 353/353 files, excalidraw 643/643 (10,650 nodes / 10,726 edges / 68,307 refs), plus torture fixtures checked into __tests__/fixtures/kernel-parity/ and enforced in npm test by kernel-tsjs-parity.test.ts. The strict compare caught one real decoder bug the loose harness missed: refs must NOT carry denormalized filePath/language at the extractFromSource seam (the store fills them). Perf: extraction 2.6× single-thread on excalidraw (487ms vs 1,255ms, identical outputs). Routing stays opt-in (CODEGRAPH_KERNEL_LANGS) until the R3 equivalence gate (large repo, DB dump-diff, retrieval invariants, agent A/B, Linux/Windows) passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |