@colbymchenry/codegraph-darwin-x64 0.9.5 → 0.9.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/dist/bin/codegraph.js +10 -25
- package/lib/dist/bin/codegraph.js.map +1 -1
- package/lib/dist/context/formatter.d.ts.map +1 -1
- package/lib/dist/context/formatter.js +25 -6
- package/lib/dist/context/formatter.js.map +1 -1
- package/lib/dist/context/index.d.ts.map +1 -1
- package/lib/dist/context/index.js +31 -0
- package/lib/dist/context/index.js.map +1 -1
- package/lib/dist/db/queries.d.ts +75 -0
- package/lib/dist/db/queries.d.ts.map +1 -1
- package/lib/dist/db/queries.js +213 -3
- package/lib/dist/db/queries.js.map +1 -1
- package/lib/dist/extraction/generated-detection.d.ts +30 -0
- package/lib/dist/extraction/generated-detection.d.ts.map +1 -0
- package/lib/dist/extraction/generated-detection.js +80 -0
- package/lib/dist/extraction/generated-detection.js.map +1 -0
- package/lib/dist/extraction/grammars.d.ts +1 -1
- package/lib/dist/extraction/grammars.d.ts.map +1 -1
- package/lib/dist/extraction/grammars.js +15 -0
- package/lib/dist/extraction/grammars.js.map +1 -1
- package/lib/dist/extraction/index.js +4 -4
- package/lib/dist/extraction/index.js.map +1 -1
- package/lib/dist/extraction/languages/c-cpp.d.ts.map +1 -1
- package/lib/dist/extraction/languages/c-cpp.js +45 -0
- package/lib/dist/extraction/languages/c-cpp.js.map +1 -1
- package/lib/dist/extraction/languages/csharp.d.ts.map +1 -1
- package/lib/dist/extraction/languages/csharp.js +2 -1
- package/lib/dist/extraction/languages/csharp.js.map +1 -1
- package/lib/dist/extraction/languages/go.d.ts.map +1 -1
- package/lib/dist/extraction/languages/go.js +12 -0
- package/lib/dist/extraction/languages/go.js.map +1 -1
- package/lib/dist/extraction/languages/java.d.ts.map +1 -1
- package/lib/dist/extraction/languages/java.js +6 -0
- package/lib/dist/extraction/languages/java.js.map +1 -1
- package/lib/dist/extraction/languages/kotlin.d.ts.map +1 -1
- package/lib/dist/extraction/languages/kotlin.js +6 -0
- package/lib/dist/extraction/languages/kotlin.js.map +1 -1
- package/lib/dist/extraction/mybatis-extractor.d.ts +48 -0
- package/lib/dist/extraction/mybatis-extractor.d.ts.map +1 -0
- package/lib/dist/extraction/mybatis-extractor.js +198 -0
- package/lib/dist/extraction/mybatis-extractor.js.map +1 -0
- package/lib/dist/extraction/tree-sitter-types.d.ts +10 -0
- package/lib/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.d.ts +58 -0
- package/lib/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.js +393 -9
- package/lib/dist/extraction/tree-sitter.js.map +1 -1
- package/lib/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
- package/lib/dist/extraction/wasm-runtime-flags.js +1 -0
- package/lib/dist/extraction/wasm-runtime-flags.js.map +1 -1
- package/lib/dist/index.d.ts +32 -1
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +49 -1
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/installer/config-writer.d.ts +7 -8
- package/lib/dist/installer/config-writer.d.ts.map +1 -1
- package/lib/dist/installer/config-writer.js +7 -27
- package/lib/dist/installer/config-writer.js.map +1 -1
- package/lib/dist/installer/index.d.ts +3 -20
- package/lib/dist/installer/index.d.ts.map +1 -1
- package/lib/dist/installer/index.js +8 -39
- package/lib/dist/installer/index.js.map +1 -1
- package/lib/dist/installer/instructions-template.d.ts +11 -21
- package/lib/dist/installer/instructions-template.d.ts.map +1 -1
- package/lib/dist/installer/instructions-template.js +12 -56
- package/lib/dist/installer/instructions-template.js.map +1 -1
- package/lib/dist/installer/targets/antigravity.d.ts +57 -0
- package/lib/dist/installer/targets/antigravity.d.ts.map +1 -0
- package/lib/dist/installer/targets/antigravity.js +308 -0
- package/lib/dist/installer/targets/antigravity.js.map +1 -0
- package/lib/dist/installer/targets/claude.d.ts +10 -1
- package/lib/dist/installer/targets/claude.d.ts.map +1 -1
- package/lib/dist/installer/targets/claude.js +25 -40
- package/lib/dist/installer/targets/claude.js.map +1 -1
- package/lib/dist/installer/targets/codex.d.ts.map +1 -1
- package/lib/dist/installer/targets/codex.js +15 -13
- package/lib/dist/installer/targets/codex.js.map +1 -1
- package/lib/dist/installer/targets/cursor.d.ts.map +1 -1
- package/lib/dist/installer/targets/cursor.js +9 -38
- package/lib/dist/installer/targets/cursor.js.map +1 -1
- package/lib/dist/installer/targets/gemini.d.ts +26 -0
- package/lib/dist/installer/targets/gemini.d.ts.map +1 -0
- package/lib/dist/installer/targets/gemini.js +167 -0
- package/lib/dist/installer/targets/gemini.js.map +1 -0
- package/lib/dist/installer/targets/hermes.d.ts.map +1 -1
- package/lib/dist/installer/targets/hermes.js +57 -3
- package/lib/dist/installer/targets/hermes.js.map +1 -1
- package/lib/dist/installer/targets/kiro.d.ts +27 -0
- package/lib/dist/installer/targets/kiro.d.ts.map +1 -0
- package/lib/dist/installer/targets/kiro.js +178 -0
- package/lib/dist/installer/targets/kiro.js.map +1 -0
- package/lib/dist/installer/targets/opencode.d.ts.map +1 -1
- package/lib/dist/installer/targets/opencode.js +15 -13
- package/lib/dist/installer/targets/opencode.js.map +1 -1
- package/lib/dist/installer/targets/registry.d.ts.map +1 -1
- package/lib/dist/installer/targets/registry.js +6 -0
- package/lib/dist/installer/targets/registry.js.map +1 -1
- package/lib/dist/installer/targets/types.d.ts +1 -16
- package/lib/dist/installer/targets/types.d.ts.map +1 -1
- package/lib/dist/mcp/engine.d.ts +6 -1
- package/lib/dist/mcp/engine.d.ts.map +1 -1
- package/lib/dist/mcp/engine.js +9 -4
- package/lib/dist/mcp/engine.js.map +1 -1
- package/lib/dist/mcp/server-instructions.d.ts +1 -1
- package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
- package/lib/dist/mcp/server-instructions.js +2 -0
- package/lib/dist/mcp/server-instructions.js.map +1 -1
- package/lib/dist/mcp/tools.d.ts +31 -0
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +556 -55
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/resolution/callback-synthesizer.d.ts +2 -2
- package/lib/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/lib/dist/resolution/callback-synthesizer.js +235 -29
- package/lib/dist/resolution/callback-synthesizer.js.map +1 -1
- package/lib/dist/resolution/frameworks/java.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/java.js +270 -1
- package/lib/dist/resolution/frameworks/java.js.map +1 -1
- package/lib/dist/resolution/frameworks/nestjs.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/nestjs.js +324 -0
- package/lib/dist/resolution/frameworks/nestjs.js.map +1 -1
- package/lib/dist/resolution/go-module.d.ts +26 -0
- package/lib/dist/resolution/go-module.d.ts.map +1 -0
- package/lib/dist/resolution/go-module.js +78 -0
- package/lib/dist/resolution/go-module.js.map +1 -0
- package/lib/dist/resolution/import-resolver.d.ts +28 -0
- package/lib/dist/resolution/import-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/import-resolver.js +571 -4
- package/lib/dist/resolution/import-resolver.js.map +1 -1
- package/lib/dist/resolution/index.d.ts +10 -0
- package/lib/dist/resolution/index.d.ts.map +1 -1
- package/lib/dist/resolution/index.js +117 -0
- package/lib/dist/resolution/index.js.map +1 -1
- package/lib/dist/resolution/name-matcher.d.ts.map +1 -1
- package/lib/dist/resolution/name-matcher.js +212 -0
- package/lib/dist/resolution/name-matcher.js.map +1 -1
- package/lib/dist/resolution/types.d.ts +29 -0
- package/lib/dist/resolution/types.d.ts.map +1 -1
- package/lib/dist/sync/git-hooks.d.ts.map +1 -1
- package/lib/dist/sync/git-hooks.js +2 -0
- package/lib/dist/sync/git-hooks.js.map +1 -1
- package/lib/dist/sync/index.d.ts +1 -1
- package/lib/dist/sync/index.d.ts.map +1 -1
- package/lib/dist/sync/index.js +2 -1
- package/lib/dist/sync/index.js.map +1 -1
- package/lib/dist/sync/watcher.d.ts +10 -0
- package/lib/dist/sync/watcher.d.ts.map +1 -1
- package/lib/dist/sync/watcher.js +28 -4
- package/lib/dist/sync/watcher.js.map +1 -1
- package/lib/dist/sync/worktree.d.ts.map +1 -1
- package/lib/dist/sync/worktree.js +1 -0
- package/lib/dist/sync/worktree.js.map +1 -1
- package/lib/dist/types.d.ts +1 -1
- package/lib/dist/types.d.ts.map +1 -1
- package/lib/dist/types.js +2 -0
- package/lib/dist/types.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -1
- package/lib/package.json +1 -1
- package/package.json +1 -1
- package/lib/dist/installer/claude-md-template.d.ts +0 -14
- package/lib/dist/installer/claude-md-template.d.ts.map +0 -1
- package/lib/dist/installer/claude-md-template.js +0 -21
- package/lib/dist/installer/claude-md-template.js.map +0 -1
|
@@ -48,6 +48,7 @@ const liquid_extractor_1 = require("./liquid-extractor");
|
|
|
48
48
|
const svelte_extractor_1 = require("./svelte-extractor");
|
|
49
49
|
const dfm_extractor_1 = require("./dfm-extractor");
|
|
50
50
|
const vue_extractor_1 = require("./vue-extractor");
|
|
51
|
+
const mybatis_extractor_1 = require("./mybatis-extractor");
|
|
51
52
|
const frameworks_1 = require("../resolution/frameworks");
|
|
52
53
|
// Re-export for backward compatibility
|
|
53
54
|
var tree_sitter_helpers_2 = require("./tree-sitter-helpers");
|
|
@@ -221,7 +222,16 @@ class TreeSitterExtractor {
|
|
|
221
222
|
this.nodes.push(fileNode);
|
|
222
223
|
// Push file node onto stack so top-level declarations get contains edges
|
|
223
224
|
this.nodeStack.push(fileNode.id);
|
|
225
|
+
// File-level package declaration (Kotlin/Java). Creates an implicit
|
|
226
|
+
// `namespace` node wrapping every top-level declaration so their
|
|
227
|
+
// qualifiedName carries the FQN — required for cross-file import
|
|
228
|
+
// resolution on JVM languages where filename ≠ class name.
|
|
229
|
+
const packageNodeId = this.extractFilePackage(this.tree.rootNode);
|
|
230
|
+
if (packageNodeId)
|
|
231
|
+
this.nodeStack.push(packageNodeId);
|
|
224
232
|
this.visitNode(this.tree.rootNode);
|
|
233
|
+
if (packageNodeId)
|
|
234
|
+
this.nodeStack.pop();
|
|
225
235
|
this.nodeStack.pop();
|
|
226
236
|
}
|
|
227
237
|
catch (error) {
|
|
@@ -386,6 +396,17 @@ class TreeSitterExtractor {
|
|
|
386
396
|
// their own `calls` refs.
|
|
387
397
|
else if (INSTANTIATION_KINDS.has(nodeType)) {
|
|
388
398
|
this.extractInstantiation(node);
|
|
399
|
+
// Java/C# `new T(...) { ... }` — anonymous class with body. Without
|
|
400
|
+
// extracting it as a class node + its methods, the interface→impl
|
|
401
|
+
// synthesizer (Phase 5.5) can't bridge T's abstract methods to the
|
|
402
|
+
// anonymous overrides, and an agent investigating a call through T
|
|
403
|
+
// (`strategy.iterator(...)` where strategy is a Strategy lambda body)
|
|
404
|
+
// has to Read the file to find the actual implementation.
|
|
405
|
+
const anonBody = this.findAnonymousClassBody(node);
|
|
406
|
+
if (anonBody) {
|
|
407
|
+
this.extractAnonymousClass(node, anonBody);
|
|
408
|
+
skipChildren = true;
|
|
409
|
+
}
|
|
389
410
|
}
|
|
390
411
|
// (Decorator handling lives inside the symbol-creating extractors
|
|
391
412
|
// — extractClass / extractFunction / extractProperty — because the
|
|
@@ -395,6 +416,20 @@ class TreeSitterExtractor {
|
|
|
395
416
|
else if (nodeType === 'impl_item') {
|
|
396
417
|
this.extractRustImplItem(node);
|
|
397
418
|
}
|
|
419
|
+
// TypeScript interface members: property_signature (`foo: T`, `foo?: T`)
|
|
420
|
+
// and method_signature (`foo(arg: A): R`) both carry type annotations the
|
|
421
|
+
// interface walker would otherwise drop. Extract them as `references`
|
|
422
|
+
// edges from the interface so resolvers can wire callers/impact for
|
|
423
|
+
// types that only appear in interface members.
|
|
424
|
+
else if ((nodeType === 'property_signature' || nodeType === 'method_signature') &&
|
|
425
|
+
this.isInsideClassLikeNode() &&
|
|
426
|
+
this.TYPE_ANNOTATION_LANGUAGES.has(this.language)) {
|
|
427
|
+
const parentId = this.nodeStack[this.nodeStack.length - 1];
|
|
428
|
+
if (parentId) {
|
|
429
|
+
this.extractTypeAnnotations(node, parentId);
|
|
430
|
+
}
|
|
431
|
+
// don't skipChildren — nested signatures still need traversal
|
|
432
|
+
}
|
|
398
433
|
// Visit children (unless the extract method already visited them)
|
|
399
434
|
if (!skipChildren) {
|
|
400
435
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
@@ -468,6 +503,32 @@ class TreeSitterExtractor {
|
|
|
468
503
|
}
|
|
469
504
|
return null;
|
|
470
505
|
}
|
|
506
|
+
/**
|
|
507
|
+
* Find a `packageTypes` child under the root, create a `namespace` node
|
|
508
|
+
* for it, and return its id so the caller can scope top-level
|
|
509
|
+
* declarations underneath. Returns null when no package header is
|
|
510
|
+
* present (script files, .kts without a package).
|
|
511
|
+
*/
|
|
512
|
+
extractFilePackage(rootNode) {
|
|
513
|
+
const types = this.extractor?.packageTypes;
|
|
514
|
+
if (!types || types.length === 0 || !this.extractor?.extractPackage)
|
|
515
|
+
return null;
|
|
516
|
+
let pkgNode = null;
|
|
517
|
+
for (let i = 0; i < rootNode.namedChildCount; i++) {
|
|
518
|
+
const child = rootNode.namedChild(i);
|
|
519
|
+
if (child && types.includes(child.type)) {
|
|
520
|
+
pkgNode = child;
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (!pkgNode)
|
|
525
|
+
return null;
|
|
526
|
+
const pkgName = this.extractor.extractPackage(pkgNode, this.source);
|
|
527
|
+
if (!pkgName)
|
|
528
|
+
return null;
|
|
529
|
+
const ns = this.createNode('namespace', pkgName, pkgNode);
|
|
530
|
+
return ns?.id ?? null;
|
|
531
|
+
}
|
|
471
532
|
/**
|
|
472
533
|
* Build qualified name from node stack
|
|
473
534
|
*/
|
|
@@ -651,6 +712,11 @@ class TreeSitterExtractor {
|
|
|
651
712
|
// in inline objects). These are ephemeral and create noise (e.g., Svelte context
|
|
652
713
|
// objects: `ctx.set({ get view() { ... } })`).
|
|
653
714
|
if (node.parent?.type === 'object' || node.parent?.type === 'object_expression') {
|
|
715
|
+
const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
|
|
716
|
+
?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
|
|
717
|
+
if (body) {
|
|
718
|
+
this.visitFunctionBody(body, '');
|
|
719
|
+
}
|
|
654
720
|
return;
|
|
655
721
|
}
|
|
656
722
|
// Not inside a class-like node and no receiver type, treat as function
|
|
@@ -875,6 +941,10 @@ class TreeSitterExtractor {
|
|
|
875
941
|
// decorator->target relationship for class properties too.
|
|
876
942
|
if (propNode) {
|
|
877
943
|
this.extractDecoratorsFor(node, propNode.id);
|
|
944
|
+
// Emit `references` edges from the property to types named in its
|
|
945
|
+
// type annotation (#381). The generic walker handles TS-style
|
|
946
|
+
// `type_annotation` children; the C# branch walks the `type` field.
|
|
947
|
+
this.extractTypeAnnotations(node, propNode.id);
|
|
878
948
|
}
|
|
879
949
|
}
|
|
880
950
|
/**
|
|
@@ -947,8 +1017,15 @@ class TreeSitterExtractor {
|
|
|
947
1017
|
});
|
|
948
1018
|
// Java/Kotlin annotations / TS field decorators sit on the
|
|
949
1019
|
// outer field_declaration, not on the individual declarator.
|
|
950
|
-
if (fieldNode)
|
|
1020
|
+
if (fieldNode) {
|
|
951
1021
|
this.extractDecoratorsFor(node, fieldNode.id);
|
|
1022
|
+
// Same as properties: emit `references` to the field's annotated
|
|
1023
|
+
// type. The outer `field_declaration` is the right scope to
|
|
1024
|
+
// search from — C# carries the `type` inside `variable_declaration`
|
|
1025
|
+
// and the language-aware path in `extractTypeAnnotations` descends
|
|
1026
|
+
// into that wrapper (#381).
|
|
1027
|
+
this.extractTypeAnnotations(node, fieldNode.id);
|
|
1028
|
+
}
|
|
952
1029
|
}
|
|
953
1030
|
}
|
|
954
1031
|
else {
|
|
@@ -1016,6 +1093,11 @@ class TreeSitterExtractor {
|
|
|
1016
1093
|
if (varNode) {
|
|
1017
1094
|
this.extractVariableTypeAnnotation(child, varNode.id);
|
|
1018
1095
|
}
|
|
1096
|
+
if (valueNode &&
|
|
1097
|
+
valueNode.type !== 'object' &&
|
|
1098
|
+
valueNode.type !== 'object_expression') {
|
|
1099
|
+
this.visitFunctionBody(valueNode, '');
|
|
1100
|
+
}
|
|
1019
1101
|
// Exported const object-of-functions: `export const actions =
|
|
1020
1102
|
// { default: async () => {} }` (SvelteKit form actions / handler maps
|
|
1021
1103
|
// / route tables). Extract each function-valued property as a function
|
|
@@ -1221,8 +1303,87 @@ class TreeSitterExtractor {
|
|
|
1221
1303
|
const value = (0, tree_sitter_helpers_1.getChildByField)(node, 'value');
|
|
1222
1304
|
if (value) {
|
|
1223
1305
|
this.extractTypeRefsFromSubtree(value, typeAliasNode.id);
|
|
1306
|
+
// `type X = { foo: T; bar(): T }` — make the members first-class
|
|
1307
|
+
// property/method nodes under the type alias so `recorder.stop()`
|
|
1308
|
+
// can attach the call edge to `RecorderHandle.stop` instead of
|
|
1309
|
+
// an unrelated class method picked by path-proximity (#359).
|
|
1310
|
+
if (this.language === 'typescript' || this.language === 'tsx') {
|
|
1311
|
+
this.extractTsTypeAliasMembers(value, typeAliasNode);
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
return false;
|
|
1316
|
+
}
|
|
1317
|
+
/**
|
|
1318
|
+
* Surface the members of a TypeScript `type X = { ... }` (or intersection
|
|
1319
|
+
* thereof) as `property` / `method` nodes under the type-alias node. Only
|
|
1320
|
+
* walks the immediate object_type / intersection operands so anonymous
|
|
1321
|
+
* nested object types inside generic arguments (`Promise<{ ok: true }>`)
|
|
1322
|
+
* don't produce phantom members.
|
|
1323
|
+
*/
|
|
1324
|
+
extractTsTypeAliasMembers(value, typeAliasNode) {
|
|
1325
|
+
const objectTypes = [];
|
|
1326
|
+
if (value.type === 'object_type') {
|
|
1327
|
+
objectTypes.push(value);
|
|
1328
|
+
}
|
|
1329
|
+
else if (value.type === 'intersection_type') {
|
|
1330
|
+
for (let i = 0; i < value.namedChildCount; i++) {
|
|
1331
|
+
const op = value.namedChild(i);
|
|
1332
|
+
if (op && op.type === 'object_type')
|
|
1333
|
+
objectTypes.push(op);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
else {
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
this.nodeStack.push(typeAliasNode.id);
|
|
1340
|
+
for (const objType of objectTypes) {
|
|
1341
|
+
for (let i = 0; i < objType.namedChildCount; i++) {
|
|
1342
|
+
const child = objType.namedChild(i);
|
|
1343
|
+
if (!child)
|
|
1344
|
+
continue;
|
|
1345
|
+
if (child.type !== 'property_signature' && child.type !== 'method_signature')
|
|
1346
|
+
continue;
|
|
1347
|
+
const nameNode = (0, tree_sitter_helpers_1.getChildByField)(child, 'name');
|
|
1348
|
+
const memberName = nameNode ? (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source) : '';
|
|
1349
|
+
if (!memberName)
|
|
1350
|
+
continue;
|
|
1351
|
+
// `foo: () => T` and `foo(): T` are functionally a method on the
|
|
1352
|
+
// type contract. Treat the property_signature with a function-typed
|
|
1353
|
+
// annotation as a method too so call sites can resolve to it.
|
|
1354
|
+
const memberKind = child.type === 'method_signature'
|
|
1355
|
+
? 'method'
|
|
1356
|
+
: this.isTsFunctionTypedProperty(child) ? 'method' : 'property';
|
|
1357
|
+
const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(child, this.source);
|
|
1358
|
+
const signature = (0, tree_sitter_helpers_1.getNodeText)(child, this.source);
|
|
1359
|
+
this.createNode(memberKind, memberName, child, {
|
|
1360
|
+
docstring,
|
|
1361
|
+
signature,
|
|
1362
|
+
qualifiedName: `${typeAliasNode.name}::${memberName}`,
|
|
1363
|
+
});
|
|
1364
|
+
// Emit `references` edges from the type alias to types named in the
|
|
1365
|
+
// member's signature, matching the interface-member behavior added in
|
|
1366
|
+
// #432. We attach refs to the type-alias parent (consistent with
|
|
1367
|
+
// interface property_signature treatment).
|
|
1368
|
+
this.extractTypeAnnotations(child, typeAliasNode.id);
|
|
1224
1369
|
}
|
|
1225
1370
|
}
|
|
1371
|
+
this.nodeStack.pop();
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* `foo: () => T` → property_signature whose type_annotation contains a
|
|
1375
|
+
* `function_type`. Treat that as a method-shaped contract member, since
|
|
1376
|
+
* the call site `obj.foo()` has identical semantics to `bar(): T`.
|
|
1377
|
+
*/
|
|
1378
|
+
isTsFunctionTypedProperty(propertySignature) {
|
|
1379
|
+
const typeAnno = (0, tree_sitter_helpers_1.getChildByField)(propertySignature, 'type');
|
|
1380
|
+
if (!typeAnno)
|
|
1381
|
+
return false;
|
|
1382
|
+
for (let i = 0; i < typeAnno.namedChildCount; i++) {
|
|
1383
|
+
const inner = typeAnno.namedChild(i);
|
|
1384
|
+
if (inner && inner.type === 'function_type')
|
|
1385
|
+
return true;
|
|
1386
|
+
}
|
|
1226
1387
|
return false;
|
|
1227
1388
|
}
|
|
1228
1389
|
// extractExportedVariables removed — the walker now descends into
|
|
@@ -1373,7 +1534,25 @@ class TreeSitterExtractor {
|
|
|
1373
1534
|
if (nameField && objectField && (node.type === 'method_invocation' || node.type === 'member_call_expression' || node.type === 'scoped_call_expression')) {
|
|
1374
1535
|
// Method call with explicit receiver: receiver.method() / $receiver->method() / ClassName::method()
|
|
1375
1536
|
const methodName = (0, tree_sitter_helpers_1.getNodeText)(nameField, this.source);
|
|
1376
|
-
|
|
1537
|
+
// Java `this.userbo.toLogin2()` parses as method_invocation(object=field_access(this, userbo)).
|
|
1538
|
+
// Without unwrapping, receiverName is `this.userbo` and the name-matcher's
|
|
1539
|
+
// single-dot receiver regex fails. Pull out the immediate field after `this.`
|
|
1540
|
+
// so the receiver is the field name (`userbo`), which the resolver can then
|
|
1541
|
+
// look up in the enclosing class's field declarations.
|
|
1542
|
+
let receiverName;
|
|
1543
|
+
if (objectField.type === 'field_access') {
|
|
1544
|
+
const inner = (0, tree_sitter_helpers_1.getChildByField)(objectField, 'object');
|
|
1545
|
+
const fld = (0, tree_sitter_helpers_1.getChildByField)(objectField, 'field');
|
|
1546
|
+
if (inner && fld && (inner.type === 'this' || inner.type === 'this_expression')) {
|
|
1547
|
+
receiverName = (0, tree_sitter_helpers_1.getNodeText)(fld, this.source);
|
|
1548
|
+
}
|
|
1549
|
+
else {
|
|
1550
|
+
receiverName = (0, tree_sitter_helpers_1.getNodeText)(objectField, this.source);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
else {
|
|
1554
|
+
receiverName = (0, tree_sitter_helpers_1.getNodeText)(objectField, this.source);
|
|
1555
|
+
}
|
|
1377
1556
|
// Strip PHP $ prefix from variable names
|
|
1378
1557
|
receiverName = receiverName.replace(/^\$/, '');
|
|
1379
1558
|
if (methodName) {
|
|
@@ -1427,10 +1606,11 @@ class TreeSitterExtractor {
|
|
|
1427
1606
|
else {
|
|
1428
1607
|
const func = (0, tree_sitter_helpers_1.getChildByField)(node, 'function') || node.namedChild(0);
|
|
1429
1608
|
if (func) {
|
|
1430
|
-
if (func.type === 'member_expression' || func.type === 'attribute' || func.type === 'selector_expression' || func.type === 'navigation_expression') {
|
|
1609
|
+
if (func.type === 'member_expression' || func.type === 'attribute' || func.type === 'selector_expression' || func.type === 'navigation_expression' || func.type === 'field_expression') {
|
|
1431
1610
|
// Method call: obj.method() or obj.field.method()
|
|
1432
1611
|
// Go uses selector_expression with 'field', JS/TS uses member_expression with 'property'
|
|
1433
1612
|
// Kotlin uses navigation_expression with navigation_suffix > simple_identifier
|
|
1613
|
+
// C/C++ use field_expression for both `obj.method()` and `ptr->method()`
|
|
1434
1614
|
let property = (0, tree_sitter_helpers_1.getChildByField)(func, 'property') || (0, tree_sitter_helpers_1.getChildByField)(func, 'field');
|
|
1435
1615
|
if (!property) {
|
|
1436
1616
|
const child1 = func.namedChild(1);
|
|
@@ -1448,9 +1628,12 @@ class TreeSitterExtractor {
|
|
|
1448
1628
|
// This helps the resolver distinguish method calls from bare function calls
|
|
1449
1629
|
// (e.g., Python's console.print() vs builtin print())
|
|
1450
1630
|
// Skip self/this/cls as they don't aid resolution
|
|
1451
|
-
const receiver = (0, tree_sitter_helpers_1.getChildByField)(func, 'object') ||
|
|
1631
|
+
const receiver = (0, tree_sitter_helpers_1.getChildByField)(func, 'object') ||
|
|
1632
|
+
(0, tree_sitter_helpers_1.getChildByField)(func, 'operand') ||
|
|
1633
|
+
(0, tree_sitter_helpers_1.getChildByField)(func, 'argument') ||
|
|
1634
|
+
func.namedChild(0);
|
|
1452
1635
|
const SKIP_RECEIVERS = new Set(['self', 'this', 'cls', 'super']);
|
|
1453
|
-
if (receiver && (receiver.type === 'identifier' || receiver.type === 'simple_identifier')) {
|
|
1636
|
+
if (receiver && (receiver.type === 'identifier' || receiver.type === 'simple_identifier' || receiver.type === 'field_identifier')) {
|
|
1454
1637
|
const receiverName = (0, tree_sitter_helpers_1.getNodeText)(receiver, this.source);
|
|
1455
1638
|
if (!SKIP_RECEIVERS.has(receiverName)) {
|
|
1456
1639
|
calleeName = `${receiverName}.${methodName}`;
|
|
@@ -1531,6 +1714,76 @@ class TreeSitterExtractor {
|
|
|
1531
1714
|
});
|
|
1532
1715
|
}
|
|
1533
1716
|
}
|
|
1717
|
+
/**
|
|
1718
|
+
* Find a `class_body` child of an `object_creation_expression` — the
|
|
1719
|
+
* marker for an anonymous class (`new T() { ... }`). Returns the body
|
|
1720
|
+
* node so the caller can walk it as the anon class's members.
|
|
1721
|
+
*/
|
|
1722
|
+
findAnonymousClassBody(node) {
|
|
1723
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
1724
|
+
const child = node.namedChild(i);
|
|
1725
|
+
// Java: `class_body`. C# uses the same node kind.
|
|
1726
|
+
if (child && (child.type === 'class_body' || child.type === 'declaration_list')) {
|
|
1727
|
+
return child;
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
return null;
|
|
1731
|
+
}
|
|
1732
|
+
/**
|
|
1733
|
+
* Extract a Java/C# anonymous class — `new T() { ...members }`. Emits a
|
|
1734
|
+
* `class` node named `<T$anon@line>`, an `extends` reference to T (so
|
|
1735
|
+
* Phase 5.5 interface-impl can bridge), and walks the body so its
|
|
1736
|
+
* `method_declaration` members become method nodes under the anon class.
|
|
1737
|
+
*
|
|
1738
|
+
* Why this matters: without anon-class extraction, the overrides inside
|
|
1739
|
+
* a lambda-returned `new T() { @Override int foo(){...} }` are not nodes,
|
|
1740
|
+
* so a call through T.foo (the abstract parent method) has no static
|
|
1741
|
+
* target — the agent has to Read the file to find the implementation.
|
|
1742
|
+
*/
|
|
1743
|
+
extractAnonymousClass(node, body) {
|
|
1744
|
+
if (!this.extractor)
|
|
1745
|
+
return;
|
|
1746
|
+
// The instantiated type sits in the same field/position that
|
|
1747
|
+
// extractInstantiation reads from. Use the same lookup so the anon
|
|
1748
|
+
// class's `extends` target matches the `instantiates` edge.
|
|
1749
|
+
const typeNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'constructor') ||
|
|
1750
|
+
(0, tree_sitter_helpers_1.getChildByField)(node, 'type') ||
|
|
1751
|
+
(0, tree_sitter_helpers_1.getChildByField)(node, 'name') ||
|
|
1752
|
+
node.namedChild(0);
|
|
1753
|
+
let typeName = typeNode ? (0, tree_sitter_helpers_1.getNodeText)(typeNode, this.source) : 'Object';
|
|
1754
|
+
const ltIdx = typeName.indexOf('<');
|
|
1755
|
+
if (ltIdx > 0)
|
|
1756
|
+
typeName = typeName.slice(0, ltIdx);
|
|
1757
|
+
const lastDot = Math.max(typeName.lastIndexOf('.'), typeName.lastIndexOf('::'));
|
|
1758
|
+
if (lastDot >= 0)
|
|
1759
|
+
typeName = typeName.slice(lastDot + 1).replace(/^[:.]/, '');
|
|
1760
|
+
typeName = typeName.trim() || 'Object';
|
|
1761
|
+
const anonName = `<${typeName}$anon@${node.startPosition.row + 1}>`;
|
|
1762
|
+
const classNode = this.createNode('class', anonName, node, {});
|
|
1763
|
+
if (!classNode)
|
|
1764
|
+
return;
|
|
1765
|
+
// The anonymous class implicitly extends/implements the named type.
|
|
1766
|
+
// We can't tell at extraction time whether T is a class or an interface,
|
|
1767
|
+
// so emit `extends`. Resolution will still bind T to whatever it is, and
|
|
1768
|
+
// Phase 5.5 (which already handles both `extends` and `implements`) will
|
|
1769
|
+
// bridge T's methods to the override names found in the anon body.
|
|
1770
|
+
this.unresolvedReferences.push({
|
|
1771
|
+
fromNodeId: classNode.id,
|
|
1772
|
+
referenceName: typeName,
|
|
1773
|
+
referenceKind: 'extends',
|
|
1774
|
+
line: typeNode?.startPosition.row ?? node.startPosition.row,
|
|
1775
|
+
column: typeNode?.startPosition.column ?? node.startPosition.column,
|
|
1776
|
+
});
|
|
1777
|
+
// Walk the body's children so method_declaration nodes inside become
|
|
1778
|
+
// method nodes scoped to the anon class.
|
|
1779
|
+
this.nodeStack.push(classNode.id);
|
|
1780
|
+
for (let i = 0; i < body.namedChildCount; i++) {
|
|
1781
|
+
const child = body.namedChild(i);
|
|
1782
|
+
if (child)
|
|
1783
|
+
this.visitNode(child);
|
|
1784
|
+
}
|
|
1785
|
+
this.nodeStack.pop();
|
|
1786
|
+
}
|
|
1534
1787
|
/**
|
|
1535
1788
|
* Scan `declNode` and its preceding siblings (within the parent's
|
|
1536
1789
|
* named children) for decorator nodes, emitting a `decorates`
|
|
@@ -1661,6 +1914,14 @@ class TreeSitterExtractor {
|
|
|
1661
1914
|
// about `call_expression`, so constructor invocations
|
|
1662
1915
|
// produced no graph edges at all.
|
|
1663
1916
|
this.extractInstantiation(node);
|
|
1917
|
+
// Anonymous class with body: `new T() { ... }` (Java/C#). Extract as
|
|
1918
|
+
// a class so interface-impl synthesis (Phase 5.5) can bridge T's
|
|
1919
|
+
// methods to the overrides — same rationale as in visitNode.
|
|
1920
|
+
const anonBody = this.findAnonymousClassBody(node);
|
|
1921
|
+
if (anonBody) {
|
|
1922
|
+
this.extractAnonymousClass(node, anonBody);
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1664
1925
|
}
|
|
1665
1926
|
else if (this.extractor.extractBareCall) {
|
|
1666
1927
|
const calleeName = this.extractor.extractBareCall(node, this.source);
|
|
@@ -2083,6 +2344,16 @@ class TreeSitterExtractor {
|
|
|
2083
2344
|
return;
|
|
2084
2345
|
if (!this.TYPE_ANNOTATION_LANGUAGES.has(this.language))
|
|
2085
2346
|
return;
|
|
2347
|
+
// C# tree-sitter doesn't produce `type_identifier` leaves — it uses
|
|
2348
|
+
// `identifier`, `predefined_type`, `qualified_name`, `generic_name`,
|
|
2349
|
+
// etc. — so the generic walker below emits zero references for it.
|
|
2350
|
+
// Dispatch to a C#-aware path that only walks type-position subtrees
|
|
2351
|
+
// (the `type` field of a parameter/method/property/field), so
|
|
2352
|
+
// parameter NAMES never accidentally surface as type refs (#381).
|
|
2353
|
+
if (this.language === 'csharp') {
|
|
2354
|
+
this.extractCsharpTypeRefs(node, nodeId);
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2086
2357
|
// Extract parameter type annotations
|
|
2087
2358
|
const params = (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.paramsField || 'parameters');
|
|
2088
2359
|
if (params) {
|
|
@@ -2099,6 +2370,112 @@ class TreeSitterExtractor {
|
|
|
2099
2370
|
this.extractTypeRefsFromSubtree(typeAnnotation, nodeId);
|
|
2100
2371
|
}
|
|
2101
2372
|
}
|
|
2373
|
+
/**
|
|
2374
|
+
* Extract C# type references from a node that owns a type position —
|
|
2375
|
+
* a method/constructor declaration, a property declaration, or a
|
|
2376
|
+
* field declaration (which wraps `variable_declaration → type`).
|
|
2377
|
+
*
|
|
2378
|
+
* Walks ONLY into known type fields, so parameter names like
|
|
2379
|
+
* `request` in `Build(UserDto request)` are never mis-emitted as
|
|
2380
|
+
* type references. Once inside a type subtree, `walkCsharpTypePosition`
|
|
2381
|
+
* recognizes C#'s actual type-leaf node kinds (`identifier`,
|
|
2382
|
+
* `qualified_name`, `generic_name`, `array_type`, `nullable_type`,
|
|
2383
|
+
* `tuple_type`, …) — none of which are `type_identifier`. Closes #381.
|
|
2384
|
+
*/
|
|
2385
|
+
extractCsharpTypeRefs(node, nodeId) {
|
|
2386
|
+
// Return type / property type — the field is named `type`.
|
|
2387
|
+
const directType = (0, tree_sitter_helpers_1.getChildByField)(node, 'type');
|
|
2388
|
+
if (directType)
|
|
2389
|
+
this.walkCsharpTypePosition(directType, nodeId);
|
|
2390
|
+
// Field declarations wrap declarators in a `variable_declaration`
|
|
2391
|
+
// whose `type` field carries the type. The outer `field_declaration`
|
|
2392
|
+
// has no `type` field of its own, so the call above is a no-op here
|
|
2393
|
+
// and we descend one level.
|
|
2394
|
+
const varDecl = node.namedChildren.find((c) => c.type === 'variable_declaration');
|
|
2395
|
+
if (varDecl) {
|
|
2396
|
+
const vdType = (0, tree_sitter_helpers_1.getChildByField)(varDecl, 'type');
|
|
2397
|
+
if (vdType)
|
|
2398
|
+
this.walkCsharpTypePosition(vdType, nodeId);
|
|
2399
|
+
}
|
|
2400
|
+
// Method / constructor parameters. The field name on
|
|
2401
|
+
// `method_declaration` is `parameters`; it points at a
|
|
2402
|
+
// `parameter_list` whose `parameter` children each have their own
|
|
2403
|
+
// `type` field. Walking ONLY the type field skips parameter NAMES,
|
|
2404
|
+
// which would otherwise mis-emit as type references.
|
|
2405
|
+
const params = (0, tree_sitter_helpers_1.getChildByField)(node, 'parameters');
|
|
2406
|
+
if (params) {
|
|
2407
|
+
for (let i = 0; i < params.namedChildCount; i++) {
|
|
2408
|
+
const child = params.namedChild(i);
|
|
2409
|
+
if (!child || child.type !== 'parameter')
|
|
2410
|
+
continue;
|
|
2411
|
+
const paramType = (0, tree_sitter_helpers_1.getChildByField)(child, 'type');
|
|
2412
|
+
if (paramType)
|
|
2413
|
+
this.walkCsharpTypePosition(paramType, nodeId);
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
/**
|
|
2418
|
+
* Walk a C# subtree that is KNOWN to be in a type position
|
|
2419
|
+
* (return type, parameter type, property type, field type, generic
|
|
2420
|
+
* argument). Identifiers here are type names, not parameter names.
|
|
2421
|
+
*/
|
|
2422
|
+
walkCsharpTypePosition(node, fromNodeId) {
|
|
2423
|
+
// `predefined_type` is int/string/bool/etc. — never a project ref.
|
|
2424
|
+
if (node.type === 'predefined_type')
|
|
2425
|
+
return;
|
|
2426
|
+
// Bare type name: `Foo` in `Foo bar`, or the `Foo` inside `List<Foo>`.
|
|
2427
|
+
if (node.type === 'identifier') {
|
|
2428
|
+
const name = (0, tree_sitter_helpers_1.getNodeText)(node, this.source);
|
|
2429
|
+
if (name && !this.BUILTIN_TYPES.has(name)) {
|
|
2430
|
+
this.unresolvedReferences.push({
|
|
2431
|
+
fromNodeId,
|
|
2432
|
+
referenceName: name,
|
|
2433
|
+
referenceKind: 'references',
|
|
2434
|
+
line: node.startPosition.row + 1,
|
|
2435
|
+
column: node.startPosition.column,
|
|
2436
|
+
});
|
|
2437
|
+
}
|
|
2438
|
+
return;
|
|
2439
|
+
}
|
|
2440
|
+
// `Namespace.Foo` → the rightmost identifier is the type. Emit the
|
|
2441
|
+
// full qualified name as the reference; the resolver can still match
|
|
2442
|
+
// on the trailing simple name when needed.
|
|
2443
|
+
if (node.type === 'qualified_name') {
|
|
2444
|
+
const text = (0, tree_sitter_helpers_1.getNodeText)(node, this.source);
|
|
2445
|
+
const last = text.split('.').pop() ?? text;
|
|
2446
|
+
if (last && !this.BUILTIN_TYPES.has(last)) {
|
|
2447
|
+
this.unresolvedReferences.push({
|
|
2448
|
+
fromNodeId,
|
|
2449
|
+
referenceName: last,
|
|
2450
|
+
referenceKind: 'references',
|
|
2451
|
+
line: node.startPosition.row + 1,
|
|
2452
|
+
column: node.startPosition.column,
|
|
2453
|
+
});
|
|
2454
|
+
}
|
|
2455
|
+
return;
|
|
2456
|
+
}
|
|
2457
|
+
// `(int Code, Foo Payload)` — tuple element has BOTH a `type` and a
|
|
2458
|
+
// `name` field; descending into all named children would mis-emit
|
|
2459
|
+
// the element name (`Code`, `Payload`) as a type ref. Walk only the
|
|
2460
|
+
// type field.
|
|
2461
|
+
if (node.type === 'tuple_element') {
|
|
2462
|
+
const t = (0, tree_sitter_helpers_1.getChildByField)(node, 'type');
|
|
2463
|
+
if (t)
|
|
2464
|
+
this.walkCsharpTypePosition(t, fromNodeId);
|
|
2465
|
+
return;
|
|
2466
|
+
}
|
|
2467
|
+
// Composite type nodes — recurse into named children. Covers
|
|
2468
|
+
// `generic_name` (head identifier + `type_argument_list`),
|
|
2469
|
+
// `nullable_type`, `array_type`, `pointer_type`, `tuple_type`,
|
|
2470
|
+
// `ref_type`, and any newer wrapping shapes the grammar adds.
|
|
2471
|
+
// Identifiers reached here are all type-positional (parameter/field
|
|
2472
|
+
// names are gated out before we descend).
|
|
2473
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
2474
|
+
const child = node.namedChild(i);
|
|
2475
|
+
if (child)
|
|
2476
|
+
this.walkCsharpTypePosition(child, fromNodeId);
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2102
2479
|
/**
|
|
2103
2480
|
* Extract type references from a variable's type annotation.
|
|
2104
2481
|
*/
|
|
@@ -2535,10 +2912,17 @@ function extractFromSource(filePath, source, language, frameworkNames) {
|
|
|
2535
2912
|
const extractor = new liquid_extractor_1.LiquidExtractor(filePath, source);
|
|
2536
2913
|
result = extractor.extract();
|
|
2537
2914
|
}
|
|
2538
|
-
else if (detectedLanguage === '
|
|
2539
|
-
//
|
|
2540
|
-
//
|
|
2541
|
-
|
|
2915
|
+
else if (detectedLanguage === 'xml') {
|
|
2916
|
+
// Custom extractor for MyBatis mapper XML. Non-mapper XML returns just a
|
|
2917
|
+
// file node so the watcher tracks it without emitting symbols.
|
|
2918
|
+
const extractor = new mybatis_extractor_1.MyBatisExtractor(filePath, source);
|
|
2919
|
+
result = extractor.extract();
|
|
2920
|
+
}
|
|
2921
|
+
else if (detectedLanguage === 'yaml' || detectedLanguage === 'twig' || detectedLanguage === 'properties') {
|
|
2922
|
+
// No symbol extraction at this stage — files are tracked at the file-record
|
|
2923
|
+
// level only. Framework extractors (Drupal routing yml, Spring `@Value`
|
|
2924
|
+
// resolution against application.yml/application.properties) run later and
|
|
2925
|
+
// add per-file nodes/references when they apply.
|
|
2542
2926
|
result = { nodes: [], edges: [], unresolvedReferences: [], errors: [], durationMs: 0 };
|
|
2543
2927
|
}
|
|
2544
2928
|
else if (detectedLanguage === 'pascal' &&
|