fix(extraction): extract type refs from TS interface property and method signatures (#432)
Types that appeared only in TypeScript interface members — property signatures like `value?: Partial<IPage>` and method signatures like `fetchPage(arg: IPage): IOrderField` — were not being captured at extraction time, so the resolver never built `references` edges for them. `codegraph_impact`/`codegraph_callers` on the named type missed every consumer that imported it solely to use it in an interface shape. Add a `property_signature` / `method_signature` branch in `visitNode`: when inside a class-like node (which covers interfaces) and the language supports type annotations, call `extractTypeAnnotations` with the parent (interface) node ID as the edge source. No property/method node is created — only unresolved references that the resolver wires the same way it wires field and parameter type references elsewhere.
This commit is contained in:
@@ -196,6 +196,16 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
`docs/design/mixed-ios-and-react-native-bridging.md`.
|
||||
|
||||
### Fixed
|
||||
- **TypeScript interface members now produce `references` edges to their
|
||||
annotated types (#432).** Types that appeared only in an interface's
|
||||
property or method signatures — e.g. `value?: Partial<IPage>` or
|
||||
`fetchPage(arg: IPage): IOrderField` — were being silently dropped at
|
||||
extraction time, so `codegraph_impact`/`codegraph_callers` on the named
|
||||
type missed every consumer that imported it just to use it in an
|
||||
interface shape. The walker now extracts type annotations from both
|
||||
`property_signature` and `method_signature` nodes inside class-like
|
||||
parents (interfaces, classes), and the resolver wires the resulting
|
||||
references the same way it wires field and parameter types elsewhere.
|
||||
- **Git worktrees no longer silently borrow another tree's index (#155).**
|
||||
When a worktree is nested inside the main checkout — exactly what agent
|
||||
tools that place worktrees under gitignored paths like
|
||||
|
||||
@@ -205,6 +205,38 @@ export interface User {
|
||||
});
|
||||
});
|
||||
|
||||
it('should extract type references from interface property signatures', () => {
|
||||
const code = `
|
||||
import type { IPage } from '../PromoterList';
|
||||
import type { IOrderField } from '../types';
|
||||
|
||||
interface Hprops {
|
||||
value?: Partial<IPage> & Partial<IOrderField>;
|
||||
}
|
||||
`;
|
||||
const result = extractFromSource('HeaderFilter.ts', code);
|
||||
|
||||
const refs = result.unresolvedReferences.filter((r) => r.referenceKind === 'references');
|
||||
expect(refs.some((r) => r.referenceName === 'IPage')).toBe(true);
|
||||
expect(refs.some((r) => r.referenceName === 'IOrderField')).toBe(true);
|
||||
});
|
||||
|
||||
it('should extract type references from interface method signatures', () => {
|
||||
const code = `
|
||||
import type { IPage } from '../PromoterList';
|
||||
import type { IOrderField } from '../types';
|
||||
|
||||
interface MethodForm {
|
||||
fetchPage(arg: IPage): IOrderField;
|
||||
}
|
||||
`;
|
||||
const result = extractFromSource('MethodForm.ts', code);
|
||||
|
||||
const refs = result.unresolvedReferences.filter((r) => r.referenceKind === 'references');
|
||||
expect(refs.some((r) => r.referenceName === 'IPage')).toBe(true);
|
||||
expect(refs.some((r) => r.referenceName === 'IOrderField')).toBe(true);
|
||||
});
|
||||
|
||||
it('should track function calls', () => {
|
||||
const code = `
|
||||
function main() {
|
||||
|
||||
@@ -387,6 +387,22 @@ export class TreeSitterExtractor {
|
||||
else if (nodeType === 'impl_item') {
|
||||
this.extractRustImplItem(node);
|
||||
}
|
||||
// TypeScript interface members: property_signature (`foo: T`, `foo?: T`)
|
||||
// and method_signature (`foo(arg: A): R`) both carry type annotations the
|
||||
// interface walker would otherwise drop. Extract them as `references`
|
||||
// edges from the interface so resolvers can wire callers/impact for
|
||||
// types that only appear in interface members.
|
||||
else if (
|
||||
(nodeType === 'property_signature' || nodeType === 'method_signature') &&
|
||||
this.isInsideClassLikeNode() &&
|
||||
this.TYPE_ANNOTATION_LANGUAGES.has(this.language)
|
||||
) {
|
||||
const parentId = this.nodeStack[this.nodeStack.length - 1];
|
||||
if (parentId) {
|
||||
this.extractTypeAnnotations(node, parentId);
|
||||
}
|
||||
// don't skipChildren — nested signatures still need traversal
|
||||
}
|
||||
|
||||
// Visit children (unless the extract method already visited them)
|
||||
if (!skipChildren) {
|
||||
|
||||
Reference in New Issue
Block a user