* Initial plan
* Add MRO fast path before D2 fuzzy widening in resolveCallTarget
When receiverTypeName is known, try resolveMethodByOwner (owner-scoped
+ MRO lookup) before falling back to the expensive lookupFuzzy in D2.
This short-circuits cross-file member call resolution for the common
non-overloaded case.
The fast path is skipped when overload disambiguation hints are
available (overloadHints or preComputedArgTypes) to avoid picking the
wrong overload for same-return-type overloaded methods.
Passes heritageMap to resolveCallTarget from all 4 call sites:
- Language seed path (processCalls)
- Sequential path (processCalls)
- walkMixedChain fallback
- Worker path (processCallsFromExtracted)
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/9e49521f-2472-47bc-96e9-be4a46b073f0
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
* fix(SM-10): address PR #741 review
Correctness:
- Module-alias guard for D0. When call.receiverName matches an active
entry in ctx.moduleAliasMap for the current file, D0 is now skipped
and resolution falls through to D1-D4 which respects the
alias-narrowed candidate pool. Prevents a homonymous class in a
different file from being picked by ctx.resolve(receiverTypeName)
inside resolveMethodByOwner. New unit test pins the contract.
Unit tests (call-processor.test.ts — 3 new):
- D0 hit: child.parentMethod() resolves via MRO walk when
heritageMap is provided.
- D0 skipped: same scenario still resolves via D1-D4 when heritageMap
is undefined (backward-compat guard).
- Module-alias guard: two files both define class User with a save()
method; 'import auth_mod as auth' in app.py must resolve
auth.user.save() to auth_mod.py, not user_mod.py.
Integration language coverage (+3 fixtures/tests):
- swift-child-extends-parent — first-wins, gated on swiftAvailable.
- ruby-child-extends-parent — first-wins.
- php-child-extends-parent — first-wins (uses ParentClass since
'Parent' is a PHP reserved word).
* test(SM-10): address second PR #741 review round
Unit tests (call-processor.test.ts, +2 new):
- overloadHints guard: Java source with two same-return-type overloads
method(int) and method(String), int added first so lookupMethodByOwner
would return it. processCalls auto-generates overloadHints for Java,
forcing D0 to be skipped. o.method("hello") must resolve to
method(String) via literal-inferred disambiguation.
- preComputedArgTypes guard: worker-path equivalent via
processCallsFromExtracted with ExtractedCall.argTypes=['String'].
Same two overloads, same correctness guarantee.
Integration tests (+2 fixtures + test blocks):
- go-child-extends-parent — struct embedding, first-wins
(Go structs are labeled 'Struct' not 'Class' in GitNexus).
- dart-child-extends-parent — extends, first-wins, gated on
dartAvailable like other Dart tests.
Documentation:
- Expanded the fallthrough comment in resolveMethodByOwner to clarify
that unknown-extension paths land on plain lookupMethodByOwner
without an ancestor walk, and that D1-D4 still runs on D0 miss.
* test(SM-10): D0 miss with heritageMap present falls through to D1-D4
Closes the last remaining gap from PR #741 review round 3. The existing
'D0 skipped' test only covered the heritageMap=undefined case, leaving
the miss-with-heritageMap path implicitly covered by integration tests
only. This adds a focused unit test where:
- Class Obj has a method doWork findable via tiered resolution
(import-scoped) but intentionally NOT registered in methodByOwner
(no ownerId), so lookupMethodByOwner misses.
- heritageMap is provided but built from an empty heritage array, so
getAncestors(class:Obj) returns []. The MRO walk yields no parents.
- lookupMethodByOwnerWithMRO therefore returns undefined → D0 miss.
- D1 resolves the receiver type; D2 widens via lookupFuzzy;
D3 file-filter picks the single matching candidate.
- A CALLS edge must still be emitted — D0 miss must not swallow
the call.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
Co-authored-by: Gergo Magyar <gergomagyar@icloud.com>
* Initial plan
* feat(SM-9): add lookupMethodByOwnerWithMRO with HeritageMap parent chain walking
- Export c3Linearize from mro-processor.ts for reuse
- Add lookupMethodByOwnerWithMRO in call-processor.ts with MRO strategy support
- Update resolveMethodByOwner to fall back to MRO walk when HeritageMap available
- Thread heritageMap through walkMixedChain for chain resolution
- Add 10 unit tests covering all acceptance criteria
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/cc58249b-42f1-45a9-89fb-e3917e4d0171
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
* feat(SM-9): add Java integration test with class Child extends Parent fixture
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/cc58249b-42f1-45a9-89fb-e3917e4d0171
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
* docs: address code review comments on MRO strategy documentation
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/cc58249b-42f1-45a9-89fb-e3917e4d0171
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
* perf(SM-9): address PR #740 review comments
- Eliminate double direct lookup in resolveMethodByOwner: delegate
straight to lookupMethodByOwnerWithMRO when a HeritageMap is
available (the MRO helper already does the direct lookup before
walking ancestors). Fallback path handles the no-HeritageMap case.
- Memoize C3 linearization per HeritageMap via a WeakMap keyed cache.
HeritageMap is immutable after build, so C3 results are stable for
its lifetime; WeakMap lets the cache auto-drain when the HeritageMap
is GC'd. Null sentinel caches linearization failures so cyclic
hierarchies are not reprocessed. Eliminates per-call buildParentMap +
c3Linearize on Python codebases.
- ancestors variable typed as readonly to accept the cached result
without copying.
- Add four missing MRO unit tests: Kotlin implements-split, C#
implements-split, JavaScript first-wins (separate provider from TS),
and C++ leftmost-base diamond (first diamond test for C++).
* fix(SM-9): CI prettier + address PR #740 follow-up review
- Fix CI prettier failure in test/integration/resolvers/java.test.ts
(auto-formatted — was introduced in 37563a31 before my first fix
commit but had not been caught locally).
- Pin caller on the SM-9 Java integration test (parentMethodCall.source
=== 'run') so a regression that misattributes the CALLS edge fails.
- Add two implements-split unit tests:
* Ambiguous default from two interfaces → BFS first-wins. Pins the
contract that lookupMethodByOwnerWithMRO returns a defined result
(full ambiguity detection is deferred to computeMRO graph pass).
* Class method precedence over interface default: Child extends Base
implements IFoo where both define handle() — documents that BFS
visits the extends edge first, matching Java's class-wins rule.
- Add @internal JSDoc on lookupMethodByOwnerWithMRO clarifying it is
exported only for testing; resolveMethodByOwner is the proper entry
point for callers.
* test(SM-9): per-language integration fixtures and tests for inherited method resolution
Extends the SM-9 integration coverage beyond Java with six new
child-extends-parent fixtures, one per MRO strategy:
- python-child-extends-parent → C3 strategy
- typescript-child-extends-parent → first-wins
- javascript-child-extends-parent → first-wins (separate provider)
- kotlin-child-extends-parent → implements-split
- csharp-child-extends-parent → implements-split
- cpp-child-extends-parent → leftmost-base
Each fixture follows the java-child-extends-parent pattern:
- Parent class with a single method
- Child class extending Parent, no override
- App class/function that instantiates Child and calls
the parent method — exercises the full ingestion pipeline,
HeritageMap construction, and lookupMethodByOwnerWithMRO walk.
For every fixture the matching integration test asserts:
- Parent and Child classes are detected
- Child → Parent EXTENDS edge is emitted
- The parent-method call resolves to the correct target file
- The caller is pinned (source === 'run' / 'Run') to catch
edge misattribution regressions
Rust is intentionally omitted — its qualified-syntax strategy
returns undefined from lookupMethodByOwnerWithMRO by design, so
there is no inherited-method resolution to assert against.
All 1739 integration resolver tests pass (+18 new SM-9 tests
across 6 languages).
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
Co-authored-by: Gergo Magyar <gergomagyar@icloud.com>
* Initial plan
* feat(SM-8): add HeritageMap with MRO-aware parent/ancestor lookup
- New heritage-map.ts: HeritageMap interface with getParents() and getAncestors()
- buildHeritageMap() consumes ExtractedHeritage[], resolves names via lookupClassByName
- Cycle protection and bounded depth (MAX_ANCESTOR_DEPTH=32) in getAncestors
- Worker path: HeritageMap built from deferredWorkerHeritage, threaded into processCallsFromExtracted
- Sequential path: Heritage accumulated across chunks, HeritageMap built after all chunks, passed to processCalls
- 18 unit tests covering parent lookup, multi-level, diamond, cycles, missing parent, bounded depth
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/c413e0a3-5d63-4ddb-8ece-02fe6ed99efd
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
* test: rename cycle test for clarity per code review
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/c413e0a3-5d63-4ddb-8ece-02fe6ed99efd
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
* refactor(SM-8): merge implementor map into heritage map
- Add `getImplementorFiles(interfaceName)` to HeritageMap interface
- Build implementor index (interface name → file paths) alongside parent
lookup in `buildHeritageMap`, using same `resolveExtendsType` logic
- Remove `ImplementorMap` type, `buildImplementorMap`, `mergeImplementorMaps`
from call-processor.ts
- Update `findInterfaceDispatchTargets`, `processCalls`, and
`processCallsFromExtracted` to use HeritageMap for both parent
lookup and implementor dispatch
- Pipeline: single `buildHeritageMap` call replaces separate
buildImplementorMap + buildHeritageMap for both worker and
sequential paths
- Migrate implementor tests from call-processor.test.ts to
heritage-map.test.ts (4 new getImplementorFiles tests)
- Update interface dispatch test to use buildHeritageMap instead
of hand-constructed ImplementorMap
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/085dffb4-b31e-4aa5-9aa3-4314bc0010e7
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
* test: rename implementor test for clarity per code review
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/085dffb4-b31e-4aa5-9aa3-4314bc0010e7
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
* fix(SM-8): address PR #739 review comments
- pipeline.ts: cache chunk file contents from Pass 1 to eliminate
double-read of sequential chunks in Pass 2. Peak memory drains
incrementally as Pass 2 processes each chunk.
- heritage-map.ts: document Rust trait-impl omission from implementor
index and the interface-name collision limitation.
- heritage-map.test.ts: add six tests covering the extends->IMPLEMENTS
path across C# (interfaceNamePattern), Swift (heritageDefaultEdge),
Java (symbol-table Interface lookup), Kotlin, PHP, and the Rust
trait-impl omission.
- pipeline.ts: comment why the heritage accumulation uses a manual
push loop instead of spread (ref #650).
* test(SM-8): address second PR #739 review pass
- Add TypeScript implements test to getImplementorFiles (closes
the .ts coverage gap flagged by the bot reviewer).
- Tighten deep-chain boundary assertion from toBeLessThanOrEqual(32)
to toBe(32) so a future regression returning fewer ancestors
fails loudly. Added an ancestors[31] === 'class:Level32' check
to pin the upper boundary.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
Co-authored-by: Gergo Magyar <gergomagyar@icloud.com>
* refactor(call-processor): use class lookup index in phase p
* test(call-processor): cover class lookup fallback
---------
Co-authored-by: 许恩宁 <xuenning@qiyi.com>
* refactor(type-env): use class lookup index for type resolution
* test(type-env): add lookupClassByName regression coverage
* test(type-env): expand class lookup regression coverage
---------
Co-authored-by: 许恩宁 <xuenning@qiyi.com>
Add eagerly-populated methodByOwner index to SymbolTable, keyed by
ownerNodeId\0methodName. Used by walkMixedChain as a fast path for
resolving intermediate method calls in cross-class chains like
user.getAddress().getCity().getZipCode(), avoiding expensive fuzzy
lookups when the owner type is already known.
Handles overloaded methods: returns the first match when all overloads
share the same returnType, undefined when return types differ (ambiguous).
- Add lookupMethodByOwner to SymbolTable interface + implementation
- Add resolveMethodByOwner helper in call-processor.ts
- Add fast path in walkMixedChain before resolveCallTarget fallback
- Add Java cross-class chain fixture + 6 integration tests
- Add 148 unit tests for methodByOwner index behavior
* fix(ignore): respect negation patterns in .gitnexusignore childrenIgnored
childrenIgnored checked `ig.ignores(rel) || ig.ignores(rel + '/')` which
short-circuited on the bare path — directory-only negation patterns like
`!iOS/` were missed because `ig.ignores('iOS')` treats the path as a file.
Now only checks with trailing slash since childrenIgnored is only called
for directories. Bare-name patterns (e.g. `local`) still match per gitignore spec.
Fixes#596
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test(ignore): add edge-case for bare `!dir` negation pattern
Verifies that `!iOS` (without trailing slash) also un-ignores the iOS/
directory — confirms the `ignore` package normalizes both `!dir` and
`!dir/` forms consistently when tested with a trailing-slash path.
Addresses non-blocking review suggestion on #654.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs(ignore): link ignore package docs for bare-name normalization
Adds references to the `ignore` package documentation in both the
childrenIgnored comment and the bare-negation test, explaining why
`!iOS` (without trailing slash) also re-includes the iOS/ directory.
Addresses non-blocking review suggestion on #654.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: replace Array.push(...spread) with loop to prevent stack overflow
On large codebases (78K+ C files), deferred arrays in
runChunkedParseAndResolve accumulate 100K+ entries. The spread
operator in push(...array) puts every element on the call stack
as a function argument, exceeding the maximum call stack size.
Replace all 11 occurrences of `arr.push(...other)` with
`for (const _item of other) arr.push(_item)` which uses
constant stack space regardless of array size.
Fixes#649
* fix: also replace push(...spread) in parsing-processor.ts
* style: format pipeline.ts to match prettier config
---------
Co-authored-by: tian kian tan <tan@example.com>
* feat: same-arity overload disambiguation via type-hash suffix (#651)
Add ~type1,type2 suffix to Method/Constructor node IDs when same-arity
overloads with different parameter types exist in the same class. Also add
$const suffix for C++ const-qualified method overloads via new isConst field.
Key changes:
- typeTagForId() detects same-arity collisions and appends ~typeTag
- constTagForId() detects const/non-const collisions and appends $const
- TS/JS excluded from type-hashing (overload signatures collapse to impl body)
- Sequential findEnclosingFunction fixed: falls through on ambiguous same-class
candidates instead of picking first; fallback path includes typeTag + constTag
- Per-call-site integration tests across Java, C#, Kotlin, C++, TypeScript
- Cross-file + chain resolution tests for all 5 languages
- C++ isConst extraction via tree-sitter type_qualifier in function_declarator
1710 integration + 18 unit tests pass.
* fix: preserve generic/template args in type-hash, perf + type safety fixes
- Add rawType field to ParameterInfo preserving full type text (vector<int>)
while type stays simplified (vector). typeTagForId uses rawType for tags.
- Populate rawType in all 11 language method extractors
- Add buildCollisionGroups() to pre-group methods by name#arity (O(N) once
per class instead of O(N) per method call)
- Cache method extraction in call-processor findEnclosingFunction fallback
- Fix null guards on getLanguageFromFilename in all findEnclosing paths
- Tighten SKIP_TYPE_HASH_LANGUAGES to ReadonlySet<SupportedLanguages>
- Document ID stability invariant on first overload introduction
- C++ integration tests: template overloads (vector<int> vs vector<string>),
cross-file template + chain resolution, out-of-class method definitions
1718 integration + 20 unit tests pass.
* fix: add rawType to method-extraction unit test assertions
All 26 parameter .toEqual() assertions in method-extraction.test.ts
needed the new rawType field added to match ParameterInfo schema change.
* perf: cache tempMap/groups per class, consolidate extractFromNode
- Cache derived method map + collision groups per classNode.id in
parsing-processor (avoids rebuild per method in same class)
- Replace per-call extractFromNode with cached class extraction +
funcName:line lookup in call-processor fallback (avoids AST walk
per call site)
- Remove dead clearEnclosingFunctionCache export, fix JSDoc
* test: add sequential-path integration test for same-arity overloads
Add skipWorkers option to PipelineOptions to force sequential parsing.
New test suite verifies type-hash disambiguation produces identical
results through the sequential path (parsing-processor + call-processor
findEnclosingFunction) as the worker path.
* feat: MethodExtractor configs for Python, PHP, Swift, Dart, Rust, Ruby with exhaustive integration tests
Add per-language MethodExtractionConfig for all remaining tree-sitter languages
(RFC #568 PR 2). Each config follows the established createMethodExtractor()
factory pattern — no new types, no parse-worker changes.
Configs:
- Python: @abstractmethod, @staticmethod/@classmethod, *args/**kwargs, type hints, _/__ visibility
- PHP: abstract/final/static keywords, PHP 8 #[] attributes, __construct/__destruct
- Swift: 5-level visibility, protocol-as-abstract, static/class methods, @ attributes
- Dart: _ convention visibility, abstract (no body), method_signature unwrapping
- Rust: pub visibility, &self receiver, trait_item + impl_item, #[] attributes
- Ruby: positional visibility via sibling-walk, singleton_method as static
Integration fixtures (18 directories) covering 3 resolution patterns:
- Method enrichment: parameterTypes, isAbstract, isFinal, annotations on graph nodes
- Overload dispatch: arity-based CALLS resolution via parameterTypes
- Abstract dispatch: abstract/concrete method distinction (Python, PHP, Rust, Swift)
Go deferred — requires factory changes for receiver-based method extraction.
Closes#571
* fix: address code review findings across 6 MethodExtractor configs
Fix all actionable items from the PR #624 deep-dive review:
Dart (critical — fixes 6 CI failures):
- isDartStatic: check children first, siblings as fallback
- isDartAbstract: handle declaration nodes for abstract methods
- extractSingleParam: detect required keyword as sibling token
- Add declaration to methodNodeTypes, mixin_declaration to typeDeclarationNodes
- Add member call query for variable assignments in tree-sitter-queries
Python:
- hasDecorator now matches dotted paths (e.g. @abc.abstractmethod)
- Fix version comment from ^0.23.6 to 0.23.4
PHP:
- Add enum_declaration to typeDeclarationNodes (PHP 8.1+)
- Add version comment for 0.23.12
Swift:
- Add isOverride using hasKeyword/hasModifier pattern
Rust:
- Fix version comment from ^0.23.2 to 0.23.1
Also: identifier fallback in generic.ts for mixin owner names,
Dart integration test label fix (Method vs Function), version
comment for tree-sitter-dart 1.0.0.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: Dart extension_declaration and Ruby module_function support
Dart:
- Add extension_declaration to typeDeclarationNodes and extension_body
to bodyNodeTypes — extension methods are now extracted into the graph
- Add extension_declaration and mixin_declaration to CLASS_CONTAINER_TYPES
for HAS_METHOD edge resolution
Ruby:
- module_function now maps to visibility 'private' in extractRubyVisibility
- module_function methods marked isStatic via backward-walk in isStatic
- Override semantics: private/public after module_function resets isStatic
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(go): Go MethodExtractor config with receiver-based extraction
Add Go as the 13th language with a per-language MethodExtractor config.
Go methods are top-level (not nested in struct bodies), so this adds
extractFromNode() to the MethodExtractor interface for direct method
node extraction without an enclosing class.
Config extracts:
- Name from field_identifier (methods) / identifier (functions)
- Return type including multi-return (first type from parameter_list)
- Parameters with variadic support
- Visibility via uppercase/lowercase convention
- Receiver type with pointer unwrapping (*User → User)
- isStatic for functions (no receiver)
Infrastructure:
- extractOwnerName optional hook on MethodExtractionConfig
- extractFromNode on MethodExtractor (factory auto-implements)
- Parse-worker uses extractFromNode when no enclosing class found
- method_declaration added to CLASS_CONTAINER_TYPES
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: method enrichment integration tests for 7 languages + TS abstract class fix
Add method-enrichment integration test fixtures and test blocks for
Go, C++, Java, Kotlin, TypeScript, JavaScript, and C#. Each fixture
tests: class detection, HAS_METHOD edges, EXTENDS edges, isAbstract,
isStatic, annotations, parameterTypes, and CALLS edge resolution.
Fixes found during testing:
- Remove method_declaration from CLASS_CONTAINER_TYPES (added for Go
but broke Java/C# HAS_METHOD edge resolution — method_declaration
is also Java's method node type)
- Add abstract_class_declaration query to TypeScript tree-sitter
queries (was missing, so abstract classes were invisible to pipeline)
1699 integration tests pass across 20 test files, 0 regressions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: format typeDeclarationNodes array for better readability in PHP config
* fix: Go interface methods + Rust impl-for-Struct owner resolution
Go:
- Add method_elem to methodNodeTypes so interface method signatures
are extractable as abstract methods
- Integration test: Animal interface detected, Speak isAbstract,
CALLS edges from app.go
Rust:
- Add extractOwnerName to resolve impl Trait for Struct to the
concrete Struct (not the Trait) — fixes method misattribution
- Fix findEnclosingClassId to generate Struct: label (not Impl:)
for impl blocks so HAS_METHOD edges resolve to struct nodes
- Tighten abstract-dispatch test: assert SqlRepo owns find/save
generic.ts:
- Fix extractOwnerName fallback: when hook returns a value, skip
both name-field and type_identifier scan (was overwriting result)
1703 integration tests pass, 0 regressions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: code review response — Rust impl label, Swift params, Dart async, sequential methodExtractor
Address code review findings from PR #624:
- ast-helpers: Rust `impl Trait for Struct` uses Struct label (matches existing
graph node), plain `impl Struct` uses Impl label (matches definition.impl)
- swift: fix parameter type extraction (user_type not type_annotation), detect
default values as function_declaration siblings, add version comment
- dart: isDartAsync now detects async*/sync* generators, add clarifying comment
for declaration nodes in extension bodies
- python: correct isFinal comment (PEP 591 @typing.final exists, just not modeled)
- parsing-processor: port methodExtractor enrichment to sequential path so
isAbstract/isStatic/visibility/annotations/isFinal populate on <15-file repos
- tests: remove silent `if (prop !== undefined)` guards, assert properties
directly, fix label queries (Dart Method vs Function, Swift Method for protocol
methods), add Rust HAS_METHOD sourceLabel tests, Swift parameterTypes tests,
and Dart async/sync* integration tests with fixture
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: Rust grammar gap + qualified method IDs to resolve same-file collisions
Phase 1 — Rust grammar:
- Add function_signature_item query to RUST_QUERIES so abstract trait methods
(fn speak(&self) -> String;) become graph nodes with isAbstract=true
Phase 2 — Qualified method IDs:
- findEnclosingClassInfo returns {classId, className} for AST-based class lookup
- Both parsing paths (sequential + worker) qualify method/property IDs with
enclosing class: Method:file:ClassName.method instead of Method:file:method
- extractFuncNameFromSourceId handles ClassName.method format
- Fixes silent data loss when same-name methods in different classes shared a
file (e.g., Animal.speak and Dog.speak both now exist as distinct graph nodes)
Test updates:
- Rust: abstract+concrete trait methods both verified, function count adjusted
- Python: static method disambiguation now emits 2 CALLS edges (correct — no
more ID collision masking the second call)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: owner-aware resolution for qualified method IDs
Address Codex adversarial review findings after qualified ID change:
- findEnclosingFunction: disambiguate candidates by ownerId when multiple
same-name methods exist in file; qualify fallback-generated IDs
- findEnclosingFunctionId (worker): qualify sourceIds with enclosing class
name so CALLS source attribution matches definition-phase node IDs
- buildExportedTypeMapFromGraph: use lookupExactAll + nodeId match instead
of lookupExactFull which returns first definition for bare name
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: methodExtractor variadic arity, return type preservation, PHP abstract dispatch
Three bugs in the methodExtractor enrichment path broke 17 integration tests:
1. Variadic parameterCount: buildMethodProps and parse-worker set
parameterCount = info.parameters.length even for variadic functions,
causing arity filtering to reject valid calls. Now checks isVariadic
and sets parameterCount = undefined (matching extractMethodSignature).
2. C++ bare `...` token: extractCppParameters only iterated named
children, missing the unnamed `...` token in C-style variadics like
log_entry(const char* fmt, ...). Added fallback scan of all children.
3. Return type stripping: All 11 language extractReturnType functions
used extractSimpleTypeName() which strips generic parameters
(List<User> → "List", Task<User> → "Task"). Changed to .text?.trim()
to preserve full generic types needed for for-loop iterable resolution,
async-await binding, and return-type inference.
Also fixes PHP abstract dispatch test that matched SqlRepository instead
of the interface due to ambiguous filePath.includes('Repository') filter,
and adds parent-walk fallback in PHP isAbstract for extractFromNode path.
* chore: remove plan and review artifacts from PR
* fix: address Round 4 review findings + infrastructure improvements
- Ruby: add singleton_class support for class << self methods (4 new tests)
- PHP: add enum_declaration to CLASS_CONTAINER_TYPES
- Dart: add mixin/extension labels to CONTAINER_TYPE_TO_LABEL
- Swift: add TODO for unverifiable struct/enum node types on Node 22
- C#: add grammar version comment (0.23.1)
- Ruby: fix version comment range to pin (0.23.1)
- Rust/ast-helpers: add cross-reference comments for impl_item duplication
- ast-helpers: document CLASS_CONTAINER_TYPES ↔ typeDeclarationNodes invariant
- generic.ts: replace Array.includes with Set for O(1) dedup in addNestedBodies
- Go/Python/Ruby: align isAbstract signature with 2-param interface contract
- CLAUDE.md: fix malformed backtick around gitnexus:start HTML comment
- parsing-processor: add per-class method extraction cache (eliminates O(N*M))
- ast-helpers: add scoped_type_identifier to impl_item resolution
- call-processor: add dev-mode warnings at silent candidates[0] fallbacks
- MCP context(): surface methodMetadata for Method/Function/Constructor nodes
- resources.ts: update schema to list all stored Method properties
* fix: singleton_class HAS_METHOD edge regression in findEnclosingClassInfo
singleton_class (class << self) was added to CLASS_CONTAINER_TYPES but
has no name field — its receiver `self` has node type 'self', not
'identifier'. findEnclosingClassInfo now walks up to the enclosing
class/module to inherit its name, matching ruby.ts:extractOwnerName.
Also fixes findEnclosingClassNode in parse-worker.ts to skip
singleton_class and return the actual class/module node.
Adds integration test assertions for from_habitat (class << self method):
HAS_METHOD edge from Animal, isStatic=true, parameterCount=1.
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(vue): add Vue SFC (.vue) support for indexing
Vue Single File Components are now fully supported in the indexing pipeline.
The implementation extracts <script> / <script setup> blocks from .vue files
and parses them using the existing TypeScript tree-sitter grammar — no new
npm dependencies required.
Key changes:
- SFC script extractor: regex-based extraction of <script setup lang="ts">
blocks with correct line offset mapping back to the .vue file
- Vue language provider: reuses TypeScript queries, type config, field
extractors, and named binding extraction
- Import resolution: .vue added to EXTENSIONS so `import Foo from './Foo'`
resolves to Foo.vue; Vue import resolver delegates to TS resolver for
tsconfig path alias support
- Export detection: <script setup> top-level bindings are implicitly exported
- Template component detection: PascalCase tags in <template> emit CALLS edges
- Line offsets applied to all emitted positions (startLine, endLine, route
lineNumbers, decorator positions) in both worker and sequential paths
Validated on a 3,553-file Vue project:
Before: 24,693 nodes | 73,614 edges | 0 symbols from .vue
After: 30,495 nodes | 112,324 edges | 5,213 symbols from .vue
18,682 imports from .vue | 5,826 vue-to-vue imports
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(typescript): track destructured call results in TypeEnv
Extend `extractPendingAssignment` to handle object destructuring from
function calls and await expressions:
const { isMaker } = useUserRole()
const { data } = await fetchData()
const { name } = repo.getProfile()
Previously, only `const { x } = someVariable` (identifier RHS) produced
TypeEnv bindings. Call-expression RHS was silently skipped, leaving
destructured properties untracked.
The fix emits a synthetic `callResult` item plus N `fieldAccess` items
per destructured property, which the existing fixpoint resolver processes
in 2 iterations. No changes needed to type-env.ts, PendingAssignment
types, or call-processor — the existing infrastructure handles it.
Also extracts a `collectDestructuredFields` helper to share the
object_pattern property iteration logic between the identifier and
call-expression branches.
Note: Full property-type resolution requires the callee to have a
declared returnType in the SymbolTable. Arrow-function composables
without type annotations (common in Vue/React) won't resolve property
types until return-type inference is added in a future change.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(vue): address PR review issues for Vue SFC support
- Extract duplicated isVueSetupTopLevel to vue-sfc-extractor.ts shared
utility, removing identical copies from parse-worker.ts and
parsing-processor.ts
- Fix VUE_BUILT_INS to be a superset of TS BUILT_INS by importing and
spreading the TypeScript set, preventing spurious unresolved calls for
standard built-ins (Symbol, BigInt, WeakMap, array methods, etc.)
- Add Vue template component CALLS edge resolution in both sequential
and worker paths (call-processor.ts), matching PascalCase template
tags against imported .vue file basenames via the import map
- Add integration test for template PascalCase CALLS edges
(App.vue → Button.vue)
- Add integration test for isExported: false on non-setup <script>
blocks (OldStyle.vue options API)
- Add comment explaining TEMPLATE_RE greedy regex behavior for nested
template tags
- Fix stale language count comment (14 → 15) and remove dead code
branch in test
Made-with: Cursor
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Spec covers 4 HIGH-priority issues from review: path traversal via
group name, gRPC proto regex nested braces, service boundary detector
directory exclusions, double-close of LadybugDB pools.
Plan: 6 tasks with TDD, ordered by complexity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire extractors into the sync pipeline with service boundary detection.
GroupService provides high-level API for all group operations.
- Sync pipeline: orchestrates extraction (HTTP, gRPC, topics) with
service boundary assignment and exact matching
- GroupService: groupList, groupSync, groupContracts, groupQuery,
groupStatus (groupImpact deferred to cross-repo follow-up PR)
- CLI: group create/add/remove/list/sync/contracts/query/status
- MCP tools: group_list, group_sync, group_contracts, group_query,
group_status
- Monorepo fixture: 3 services (auth/orders/gateway) connected via
gRPC + Kafka + HTTP — all intra-repo cross-links discovered
- Documentation: CLI commands and MCP tools added to both READMEs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Core foundation for repository group analysis:
- Type system: ContractType, ExtractedContract, StoredContract, CrossLink
with optional `service` field for intra-repo matching
- Config parser for group.yaml (repos, detection flags, matching thresholds)
- Contract registry storage with atomic writes
- Exact matching engine with per-type normalization (HTTP, gRPC, topic)
and intra-repo support (different services within same repo can match)
- Extract LadybugDB pool-adapter from MCP backend for reuse by sync pipeline
- Git staleness checker for group status reporting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cpp): C/C++ MethodExtractor config with pure virtual detection (#572)
- Pure virtual (= 0) detected as isAbstract via token scanning
- virtual/final/override via hasKeyword and virtual_specifier children
- Access specifier visibility via backward sibling walk (public:/private:/protected:)
- Pointer/reference parameter types extracted correctly
- Constructor and destructor support via declaration node type
- Static detection via storage_class_specifier
- 16 new tests covering all acceptance criteria
* fix(cpp): isVirtual infers from override/final + out-of-class resolution
- isVirtual returns true for override/final methods (C++ mandates these
are virtual)
- Add findClassNodeByQualifiedName to parse-worker: resolves Foo::bar()
back to the Foo class declaration for method extractor enrichment
- Handles pointer/ref return types, constructors, destructors
- Integration test for virtual/static/constructor inline methods
- 233 unit+integration tests pass, 97 C++ resolver tests pass
* fix(cpp): address review — deep pointers, templates, unions, trailing returns
- Fix extractParamName: recursive unwrap for int** ptr → "ptr" (not "**ptr")
- Fix findFunctionDeclarator: recursive unwrap for multi-level pointer chains
- Template methods: generic extractor unwraps template_declaration to inner node
- union_specifier: added to typeDeclarationNodes, visibility defaults to public
- Trailing return type: auto foo() -> T now extracts T instead of "auto"
- Fix version comment: ^0.22.4 → ^0.23.4 to match package.json
- 4 new tests: double pointer params, template methods, union methods, trailing returns
* fix(cpp): template method visibility + union isTypeDeclaration test
extractCppVisibility now walks from the template_declaration parent
when the node is wrapped by a template, restoring correct access-
specifier resolution for templated class methods.
Also adds missing isTypeDeclaration assertion for union_specifier and
expands the template method test with explicit visibility checks.
* fix(cpp): address deep gap analysis review findings
- findClassNodeByQualifiedName: recursive pointer/reference
declarator unwrap, fixing out-of-class linking for deep pointer
return types (e.g. int** Foo::bar())
- findClassNodeByQualifiedName: recurse into namespace_definition
blocks so namespace-wrapped classes resolve correctly
- Suppress = delete / = default special members from extraction
via delete_method_clause / default_method_clause node detection
- Update known-gaps: namespace-wrapped classes, const-overload collapse
- Add tree-sitter-c version comment for consistency
- toBeFalsy() → toBe(undefined) for precise isVirtual assertion
- Tests: = delete, = default, = 0 non-regression, operator overloads,
deep pointer return types, default visibility (class vs struct),
multiple access specifier sections
* fix(wiki): Azure OpenAI compat and HTML viewer script injection
- Use max_completion_tokens instead of deprecated max_tokens for all models
- Skip sending temperature for Azure provider (some models reject non-default values)
- Simplify Azure interactive setup: endpoint + deployment + key (3 prompts instead of 7)
- Escape </script> in embedded JSON to prevent premature script tag closure
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(test): align wiki-llm-client test with max_completion_tokens change
The test expected max_tokens for non-reasoning models, but the source
now uses max_completion_tokens for all models since max_tokens is
deprecated by newer OpenAI models.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Abhigyan Patwari <abhigyan@Abhigyans-MacBook-Air.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(ts,js): MethodExtractor config for TypeScript and JavaScript (#570)
Add per-language method extraction config following the established
JVM and C# patterns. Shared config base mirrors the field extractor's
typescript-javascript.ts pattern — TS-only node types are harmless
no-ops for JS.
Key features:
- isAbstract for abstract class methods and interface methods
- Parameter extraction with isOptional (?:, defaults) and isVariadic (...)
- Decorator extraction from preceding body-level siblings
- isAsync and isOverride detection
- Visibility via accessibility_modifier two-pass pattern
- Return type extraction unwrapping type_annotation
* test(ts,js): add override, getter/setter, destructured param tests
Address code review findings:
- Add override method detection test
- Add getter/setter extraction test
- Add destructured parameter with type annotation test
- Tighten constructor and private method assertions
* refactor(ts,js): address code review findings
- Replace O(M*N) decorator index scan with previousNamedSibling walk
- Remove dead findVisibility 'modifiers' fallback (TS uses
accessibility_modifier, not a modifiers wrapper)
- Document call_signature/construct_signature as known gaps
- Document that TS constructors are method_definition nodes
- Remove unused findVisibility import
* fix(ts,js): type guard before cast, add generator/computed/overload tests
- Use type guard pattern (Set.has check before as-cast) in visibility
extraction to ensure string is validated before narrowing
- Add generator method test (*items()) — confirms extraction works
- Add computed property name test ([Symbol.iterator]) — documents
bracket-in-name behavior as intentional
- Add class-level method overload test — verifies overload signatures
+ implementation are all extracted
* fix(ts,js): detect #private methods as visibility 'private'
ES2022 private class methods (#name) use private_property_identifier
as their name node type. Detect this and return 'private' visibility
instead of the default 'public'.
* fix(ts,js): address review findings + close ingestion gaps
- hasKeyword/findVisibility: skip name field child to prevent false
positives on soft-keyword method names (e.g. `abstract()`, `static()`)
- extractTsJsParameters: filter TS `this` parameter (compile-time only)
- extractMethodSignature: mirror `this`-param skip in fallback path
- tree-sitter queries: capture abstract_method_signature,
method_signature, and private_property_identifier for TS; add
private_property_identifier for JS
- Remove dead childForFieldName('name') fallbacks and typeFromAnnotation
fallback
- Add 10+ unit tests, 4 integration tests through query pipeline
* test(ts): update HAS_METHOD count for interface method_signature capture
The new method_signature query now captures ILogger.log() as a Method
node with a HAS_METHOD edge, increasing the expected count from 4 to 5.
* fix(ts,js): address second review — async generator test, declare module gap
- Add async generator method test (async *values() → isAsync: true)
- Document declare module/global augmentation as known gap
npm runs `prepare` after `prepack` during publish, so the previous
`prepare: tsc` overwrote the rewritten imports before packing.
Both `prepare` and `prepack` now run the full build script so the
tarball always contains rewritten relative imports.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(ci): build gitnexus-shared before publish, use CHANGELOG for release notes
The publish workflow was missing the gitnexus-shared build step that
the setup-gitnexus composite action provides. Since PR #536 unified
the ingestion pipeline, gitnexus imports types from gitnexus-shared,
so it must be built first.
Also replaces generate_release_notes with CHANGELOG.md extraction so
GitHub Releases use the reviewed changelog entry instead of a flat
PR title list.
Made-with: Cursor
* fix: bundle gitnexus-shared into CLI dist to fix module resolution
gitnexus-shared was declared as a file: dependency but never published
to npm, causing ERR_MODULE_NOT_FOUND for users installing gitnexus
globally. The build script now copies gitnexus-shared/dist into
dist/_shared/ and rewrites bare specifiers to relative paths.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: move gitnexus-shared to devDependencies, use tsc for prepare
gitnexus-shared must remain available for tsc to resolve imports during
development/CI, but is not needed at runtime since it's bundled into
dist/_shared/. Moving it to devDependencies keeps it out of production
installs while allowing compilation. The prepare script now runs plain
tsc (no shared bundling needed for local dev).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Abhigyan Patwari <abhigyan@Abhigyans-MacBook-Air.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The publish job failed because npm ci triggers the prepare script (tsc)
before gitnexus-shared types are available. Add the same build step
that the setup-gitnexus composite action uses in CI.
* feat(web): add repo landing screen with selectable repo cards
Instead of auto-loading the first indexed repo when the backend is
detected, show a landing screen that lets users choose which repo
to explore or analyze a new one. This addresses the UX gap where
users with multiple indexed repos had no way to pick—they were
always sent to the first one found.
- New RepoLanding component with clickable repo cards (name, stats,
indexed date) and an embedded RepoAnalyzer for new repos
- DropZone gains a 'landing' phase between server detection and
graph loading
- Shared connectToRepo handler replaces the old handleAnalyzeComplete
for both repo selection and post-analysis connection
Made-with: Cursor
* fix(web): update e2e flow for repo landing screen
The new landing screen intentionally stops auto-loading the first indexed
repo, so the existing Playwright tests were still waiting for the explorer
to appear automatically. Update the specs to select a repo from the landing
screen before asserting on the graph, and add a stable test id for repo cards.
Also format DropZone to satisfy the Prettier CI check.
Made-with: Cursor
* fix(e2e): use waitFor instead of instant isVisible for landing card
locator.isVisible() is a non-retrying instant check — the landing card
hadn't rendered yet when it was called, causing the click to be silently
skipped. Switch to waitFor which properly polls until the element appears.
Made-with: Cursor
---------
Co-authored-by: Abhigyan Patwari <abhigyan@Abhigyans-MacBook-Air.local>
* feat(csharp): add C# MethodExtractor config (#573)
Add C# method extraction config mirroring the JVM pattern from PR #576.
Wire csharpMethodConfig into the C# language provider and add 18 tests
covering classes, interfaces, abstract classes, structs, records,
constructors, params/out/ref/optional parameters, sealed methods,
attributes, and visibility modifiers.
* fix(csharp): add destructor, operator, conversion operator, and in-param support
- Add destructor_declaration, operator_declaration, and
conversion_operator_declaration to methodNodeTypes
- Custom extractName for operators (e.g., "operator +", "implicit operator double")
- Fix extractReturnType for operator declarations (use type field, not returns)
- Add in modifier to parameter extraction (alongside out/ref)
- Add 4 new tests: destructor, operator+, implicit conversion, in parameter
* fix(csharp): add ref param test and document compound visibility limitation
- Add test for ref parameter modifier (was only testing out)
- Document that protected internal / private protected resolve to first modifier
* feat(csharp): support compound visibilities (protected internal, private protected)
- Add 'protected internal' and 'private protected' to FieldVisibility union
- Detect compound modifiers in both C# method and field extractors via
collectModifierTexts helper scanning adjacent modifier nodes
- Add 2 tests for compound visibility detection
* feat(csharp): primary constructors, virtual/override/async, primary fields
Address all known limitations from review:
- Primary constructor support (C# 12): add extractPrimaryConstructor to
MethodExtractionConfig and extractPrimaryFields to FieldExtractionConfig.
Record params become public readonly properties; class params become
private captured fields.
- Add isVirtual, isOverride, isAsync optional fields to MethodInfo,
MethodExtractionConfig, NodeProperties, and parse-worker propagation.
- Detect virtual/override/async modifiers in C# method config.
- Move collectModifierTexts to shared helpers.ts (deduplicate).
- Fix destructor name to ~ClassName (disambiguates from constructor).
- Add expression-bodied method test.
- 118 tests total across method + field extraction suites, all passing.
* fix(csharp): review round 2 — annotations, record_struct, grammar pin
- Fix primary constructor annotations: use [] instead of extracting
class-level attributes (C# has no syntax for ctor-specific attributes)
- Add record_struct_declaration to typeDeclarationNodes in both method
and field extractors, CLASS_CONTAINER_TYPES, and isRecord visibility check
- Pin tree-sitter-c-sharp version (^0.23.1) in params comment
* fix(csharp): complete record_struct query + label mapping, sealed override test
- Add record_struct_declaration capture patterns to tree-sitter-queries.ts
(type definition + primary constructor)
- Add record_struct_declaration → 'Struct' in CONTAINER_TYPE_TO_LABEL
- Assert isOverride: true alongside isFinal in sealed override test
* fix(csharp): record_struct label mismatch, add record struct + documented limitation tests
- Fix record_struct_declaration query tag: @definition.struct (not @definition.record)
to match CONTAINER_TYPE_TO_LABEL and prevent broken HAS_METHOD edges
- Add 3 record struct tests: isTypeDeclaration, method extraction, primary constructor
- Add documented limitation tests: partial method (isAbstract: false), generic type
parameter stripping (name excludes <T>)
* fix(csharp): remove record_struct_declaration — not a real tree-sitter node type
tree-sitter-c-sharp 0.23.1 parses 'record struct' as record_declaration
(absorbs the 'struct' keyword as an unnamed child token). The non-existent
record_struct_declaration in queries caused TSQueryErrorNodeType, breaking
ALL C# file processing.
Remove from: tree-sitter-queries.ts, typeDeclarationNodes in both
extractors, CLASS_CONTAINER_TYPES, and CONTAINER_TYPE_TO_LABEL.
Record struct types are already handled via record_declaration.
* feat(csharp): add isPartial support, filter targeted attributes, static ctor test
- Add isPartial optional field to MethodInfo, MethodExtractionConfig,
NodeProperties, and parse-worker propagation pipeline
- Detect partial modifier in C# config — marks both declaration-only
and implemented partial methods
- Filter targeted attribute lists (e.g. [return: MarshalAs(...)]) in
extractCSharpAnnotations — only untargeted attributes collected
- Add static constructor test (isStatic: true, same name as class)
- Add 3 partial method tests: declaration-only, with body, coexisting pair
- Document record_struct/record_class as defensive dead code in
export-detection.ts (grammar absorbs keywords into record_declaration)
* fix(csharp): this param for extension methods, dedup visibility, test fixes
- Handle this modifier on extension method parameters (type prefixed
as 'this string', consistent with out/ref/in handling)
- Deduplicate visibility logic in extractPrimaryConstructor — reuse
csharpMethodConfig.extractVisibility instead of inline compound check
- Fix record struct test title to reflect actual grammar behavior
- Add conversion operator returnType assertion
- Add extension method this parameter test
* fix(csharp): primary constructor line points to param list, empty name guard
- Use paramList.startPosition instead of ownerNode.startPosition for
primary constructor line number (avoids methodInfoCache key collision)
- Guard against empty param names from tree-sitter error recovery nodes
gitnexus-web imports from gitnexus-shared, which requires npm run build
to generate dist/. Without this step, npm run dev fails with module
resolution errors.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>