@colbymchenry/codegraph-darwin-x64 0.9.5 → 0.9.6
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/db/queries.d.ts +1 -0
- package/lib/dist/db/queries.d.ts.map +1 -1
- package/lib/dist/db/queries.js +31 -3
- package/lib/dist/db/queries.js.map +1 -1
- 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/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/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.d.ts +33 -0
- package/lib/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.js +269 -9
- package/lib/dist/extraction/tree-sitter.js.map +1 -1
- package/lib/dist/index.d.ts +1 -1
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +20 -1
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/installer/index.d.ts +1 -1
- package/lib/dist/installer/index.js +3 -3
- package/lib/dist/installer/index.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 +307 -0
- package/lib/dist/installer/targets/antigravity.js.map +1 -0
- 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 +165 -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 +196 -0
- package/lib/dist/installer/targets/kiro.js.map +1 -0
- 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 -1
- package/lib/dist/installer/targets/types.d.ts.map +1 -1
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +14 -3
- 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 +79 -2
- 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 +18 -0
- package/lib/dist/resolution/import-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/import-resolver.js +537 -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 +102 -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/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/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
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MyBatisExtractor = void 0;
|
|
4
|
+
const tree_sitter_helpers_1 = require("./tree-sitter-helpers");
|
|
5
|
+
/**
|
|
6
|
+
* MyBatisExtractor — parses MyBatis mapper XML files.
|
|
7
|
+
*
|
|
8
|
+
* MyBatis splits a DAO interface across two files: a Java interface (parsed by
|
|
9
|
+
* tree-sitter) declares the method, and an XML mapper file holds the SQL keyed
|
|
10
|
+
* by `<namespace>` (the fully-qualified Java type name) and `id` (the method
|
|
11
|
+
* name). Without the XML side in the graph, `trace(Controller, ...DAO.method)`
|
|
12
|
+
* dead-ends at the interface method — the SQL it actually runs is invisible,
|
|
13
|
+
* and "what does this query touch" / "where is this column written" can't be
|
|
14
|
+
* answered.
|
|
15
|
+
*
|
|
16
|
+
* This extractor emits one method-shaped node per `<select|insert|update|
|
|
17
|
+
* delete>` and per `<sql>` fragment, qualified as `<namespace>::<id>` so the
|
|
18
|
+
* MyBatis framework synthesizer (`src/resolution/frameworks/mybatis.ts`) can
|
|
19
|
+
* link the matching Java method → XML statement by suffix-matching qualified
|
|
20
|
+
* names. `<include refid="...">` inside a statement yields an unresolved
|
|
21
|
+
* reference to the SQL fragment, also keyed by `<namespace>::<refid>`.
|
|
22
|
+
*
|
|
23
|
+
* Non-mapper XML (Maven `pom.xml`, Spring beans XML, `web.xml`, log4j config,
|
|
24
|
+
* etc.) is detected by the absence of a `<mapper namespace="...">` root and
|
|
25
|
+
* returns just a file node — we still need the file row so the watcher can
|
|
26
|
+
* track it, but we emit no symbols.
|
|
27
|
+
*/
|
|
28
|
+
class MyBatisExtractor {
|
|
29
|
+
filePath;
|
|
30
|
+
source;
|
|
31
|
+
nodes = [];
|
|
32
|
+
edges = [];
|
|
33
|
+
unresolvedReferences = [];
|
|
34
|
+
errors = [];
|
|
35
|
+
lineStarts = [];
|
|
36
|
+
constructor(filePath, source) {
|
|
37
|
+
this.filePath = filePath;
|
|
38
|
+
this.source = source;
|
|
39
|
+
this.computeLineStarts();
|
|
40
|
+
}
|
|
41
|
+
extract() {
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
const fileNode = this.createFileNode();
|
|
44
|
+
try {
|
|
45
|
+
const mapperMatch = this.findMapperRoot();
|
|
46
|
+
if (mapperMatch) {
|
|
47
|
+
this.extractMapper(fileNode.id, mapperMatch.namespace, mapperMatch.bodyStart, mapperMatch.bodyEnd);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
this.errors.push({
|
|
52
|
+
message: `MyBatis extraction error: ${error instanceof Error ? error.message : String(error)}`,
|
|
53
|
+
severity: 'error',
|
|
54
|
+
code: 'parse_error',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
nodes: this.nodes,
|
|
59
|
+
edges: this.edges,
|
|
60
|
+
unresolvedReferences: this.unresolvedReferences,
|
|
61
|
+
errors: this.errors,
|
|
62
|
+
durationMs: Date.now() - startTime,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
createFileNode() {
|
|
66
|
+
const lines = this.source.split('\n');
|
|
67
|
+
const id = (0, tree_sitter_helpers_1.generateNodeId)(this.filePath, 'file', this.filePath, 1);
|
|
68
|
+
const node = {
|
|
69
|
+
id,
|
|
70
|
+
kind: 'file',
|
|
71
|
+
name: this.filePath.split('/').pop() || this.filePath,
|
|
72
|
+
qualifiedName: this.filePath,
|
|
73
|
+
filePath: this.filePath,
|
|
74
|
+
language: 'xml',
|
|
75
|
+
startLine: 1,
|
|
76
|
+
endLine: lines.length || 1,
|
|
77
|
+
startColumn: 0,
|
|
78
|
+
endColumn: lines[lines.length - 1]?.length ?? 0,
|
|
79
|
+
updatedAt: Date.now(),
|
|
80
|
+
};
|
|
81
|
+
this.nodes.push(node);
|
|
82
|
+
return node;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Find the `<mapper namespace="X">` opening tag. Returns the namespace and
|
|
86
|
+
* the byte offsets of the body (between the opening and closing tag) so
|
|
87
|
+
* statement extraction can be scoped to mapper contents.
|
|
88
|
+
*/
|
|
89
|
+
findMapperRoot() {
|
|
90
|
+
const open = /<mapper\b([^>]*)>/.exec(this.source);
|
|
91
|
+
if (!open)
|
|
92
|
+
return null;
|
|
93
|
+
const attrs = open[1] ?? '';
|
|
94
|
+
const nsMatch = /\bnamespace\s*=\s*"([^"]+)"/.exec(attrs);
|
|
95
|
+
if (!nsMatch)
|
|
96
|
+
return null;
|
|
97
|
+
const bodyStart = open.index + open[0].length;
|
|
98
|
+
const closeIdx = this.source.indexOf('</mapper>', bodyStart);
|
|
99
|
+
const bodyEnd = closeIdx >= 0 ? closeIdx : this.source.length;
|
|
100
|
+
return { namespace: nsMatch[1], bodyStart, bodyEnd };
|
|
101
|
+
}
|
|
102
|
+
extractMapper(fileNodeId, namespace, bodyStart, bodyEnd) {
|
|
103
|
+
const body = this.source.slice(bodyStart, bodyEnd);
|
|
104
|
+
// Match each top-level statement-shaped element. The body may have nested
|
|
105
|
+
// tags (`<if>`, `<foreach>`, `<include>`), so we scan with a regex that
|
|
106
|
+
// pairs an opening tag to its matching close — the simple form below works
|
|
107
|
+
// because MyBatis statement elements are not themselves nested.
|
|
108
|
+
const stmtRegex = /<(select|insert|update|delete|sql)\b([^>]*)>([\s\S]*?)<\/\1>/g;
|
|
109
|
+
let m;
|
|
110
|
+
while ((m = stmtRegex.exec(body)) !== null) {
|
|
111
|
+
const elemType = m[1];
|
|
112
|
+
const attrs = m[2] ?? '';
|
|
113
|
+
const elemBody = m[3] ?? '';
|
|
114
|
+
const idMatch = /\bid\s*=\s*"([^"]+)"/.exec(attrs);
|
|
115
|
+
if (!idMatch)
|
|
116
|
+
continue;
|
|
117
|
+
const id = idMatch[1];
|
|
118
|
+
const absoluteIndex = bodyStart + m.index;
|
|
119
|
+
const startLine = this.getLineNumber(absoluteIndex);
|
|
120
|
+
const endLine = this.getLineNumber(absoluteIndex + m[0].length);
|
|
121
|
+
const qualified = `${namespace}::${id}`;
|
|
122
|
+
const isSqlFragment = elemType === 'sql';
|
|
123
|
+
const nodeId = (0, tree_sitter_helpers_1.generateNodeId)(this.filePath, 'method', qualified, startLine);
|
|
124
|
+
const node = {
|
|
125
|
+
id: nodeId,
|
|
126
|
+
kind: 'method',
|
|
127
|
+
name: id,
|
|
128
|
+
qualifiedName: qualified,
|
|
129
|
+
filePath: this.filePath,
|
|
130
|
+
language: 'xml',
|
|
131
|
+
signature: this.buildSignature(elemType, attrs, isSqlFragment),
|
|
132
|
+
startLine,
|
|
133
|
+
endLine,
|
|
134
|
+
startColumn: 0,
|
|
135
|
+
endColumn: 0,
|
|
136
|
+
docstring: this.previewSql(elemBody),
|
|
137
|
+
updatedAt: Date.now(),
|
|
138
|
+
};
|
|
139
|
+
this.nodes.push(node);
|
|
140
|
+
this.edges.push({ source: fileNodeId, target: nodeId, kind: 'contains' });
|
|
141
|
+
// <include refid="X"/> → reference to the SQL fragment in this mapper
|
|
142
|
+
// (or in another mapper, when the refid is qualified — `ns.X`).
|
|
143
|
+
const includeRegex = /<include\b[^>]*\brefid\s*=\s*"([^"]+)"/g;
|
|
144
|
+
let inc;
|
|
145
|
+
while ((inc = includeRegex.exec(elemBody)) !== null) {
|
|
146
|
+
const refid = inc[1];
|
|
147
|
+
const refQualified = refid.includes('.') ? refid.replace(/\./g, '::') : `${namespace}::${refid}`;
|
|
148
|
+
const includeOffset = absoluteIndex + (m[0].length - m[3].length - `</${elemType}>`.length) + inc.index;
|
|
149
|
+
const line = this.getLineNumber(includeOffset);
|
|
150
|
+
this.unresolvedReferences.push({
|
|
151
|
+
fromNodeId: nodeId,
|
|
152
|
+
referenceName: refQualified,
|
|
153
|
+
referenceKind: 'references',
|
|
154
|
+
line,
|
|
155
|
+
column: 0,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
buildSignature(elemType, attrs, isSqlFragment) {
|
|
161
|
+
if (isSqlFragment)
|
|
162
|
+
return '<sql>';
|
|
163
|
+
const verb = elemType.toUpperCase();
|
|
164
|
+
const result = /\bresultType\s*=\s*"([^"]+)"/.exec(attrs)?.[1];
|
|
165
|
+
const param = /\bparameterType\s*=\s*"([^"]+)"/.exec(attrs)?.[1];
|
|
166
|
+
const parts = [verb];
|
|
167
|
+
if (param)
|
|
168
|
+
parts.push(`param=${param}`);
|
|
169
|
+
if (result)
|
|
170
|
+
parts.push(`result=${result}`);
|
|
171
|
+
return parts.join(' ');
|
|
172
|
+
}
|
|
173
|
+
previewSql(body) {
|
|
174
|
+
return body.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 200);
|
|
175
|
+
}
|
|
176
|
+
computeLineStarts() {
|
|
177
|
+
this.lineStarts = [0];
|
|
178
|
+
for (let i = 0; i < this.source.length; i++) {
|
|
179
|
+
if (this.source.charCodeAt(i) === 10)
|
|
180
|
+
this.lineStarts.push(i + 1);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
getLineNumber(offset) {
|
|
184
|
+
// Binary search
|
|
185
|
+
let lo = 0;
|
|
186
|
+
let hi = this.lineStarts.length - 1;
|
|
187
|
+
while (lo < hi) {
|
|
188
|
+
const mid = (lo + hi + 1) >>> 1;
|
|
189
|
+
if (this.lineStarts[mid] <= offset)
|
|
190
|
+
lo = mid;
|
|
191
|
+
else
|
|
192
|
+
hi = mid - 1;
|
|
193
|
+
}
|
|
194
|
+
return lo + 1;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
exports.MyBatisExtractor = MyBatisExtractor;
|
|
198
|
+
//# sourceMappingURL=mybatis-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mybatis-extractor.js","sourceRoot":"","sources":["../../src/extraction/mybatis-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -104,6 +104,20 @@ export declare class TreeSitterExtractor {
|
|
|
104
104
|
* Returns true if children should be skipped (struct/interface handled body visiting).
|
|
105
105
|
*/
|
|
106
106
|
private extractTypeAlias;
|
|
107
|
+
/**
|
|
108
|
+
* Surface the members of a TypeScript `type X = { ... }` (or intersection
|
|
109
|
+
* thereof) as `property` / `method` nodes under the type-alias node. Only
|
|
110
|
+
* walks the immediate object_type / intersection operands so anonymous
|
|
111
|
+
* nested object types inside generic arguments (`Promise<{ ok: true }>`)
|
|
112
|
+
* don't produce phantom members.
|
|
113
|
+
*/
|
|
114
|
+
private extractTsTypeAliasMembers;
|
|
115
|
+
/**
|
|
116
|
+
* `foo: () => T` → property_signature whose type_annotation contains a
|
|
117
|
+
* `function_type`. Treat that as a method-shaped contract member, since
|
|
118
|
+
* the call site `obj.foo()` has identical semantics to `bar(): T`.
|
|
119
|
+
*/
|
|
120
|
+
private isTsFunctionTypedProperty;
|
|
107
121
|
/**
|
|
108
122
|
* Extract an import
|
|
109
123
|
*
|
|
@@ -178,6 +192,25 @@ export declare class TreeSitterExtractor {
|
|
|
178
192
|
* Creates 'references' edges for parameter types, return types, and field types.
|
|
179
193
|
*/
|
|
180
194
|
private extractTypeAnnotations;
|
|
195
|
+
/**
|
|
196
|
+
* Extract C# type references from a node that owns a type position —
|
|
197
|
+
* a method/constructor declaration, a property declaration, or a
|
|
198
|
+
* field declaration (which wraps `variable_declaration → type`).
|
|
199
|
+
*
|
|
200
|
+
* Walks ONLY into known type fields, so parameter names like
|
|
201
|
+
* `request` in `Build(UserDto request)` are never mis-emitted as
|
|
202
|
+
* type references. Once inside a type subtree, `walkCsharpTypePosition`
|
|
203
|
+
* recognizes C#'s actual type-leaf node kinds (`identifier`,
|
|
204
|
+
* `qualified_name`, `generic_name`, `array_type`, `nullable_type`,
|
|
205
|
+
* `tuple_type`, …) — none of which are `type_identifier`. Closes #381.
|
|
206
|
+
*/
|
|
207
|
+
private extractCsharpTypeRefs;
|
|
208
|
+
/**
|
|
209
|
+
* Walk a C# subtree that is KNOWN to be in a type position
|
|
210
|
+
* (return type, parameter type, property type, field type, generic
|
|
211
|
+
* argument). Identifiers here are type names, not parameter names.
|
|
212
|
+
*/
|
|
213
|
+
private walkCsharpTypePosition;
|
|
181
214
|
/**
|
|
182
215
|
* Extract type references from a variable's type annotation.
|
|
183
216
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree-sitter.d.ts","sourceRoot":"","sources":["../../src/extraction/tree-sitter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EACL,QAAQ,EAIR,gBAAgB,EAGjB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"tree-sitter.d.ts","sourceRoot":"","sources":["../../src/extraction/tree-sitter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EACL,QAAQ,EAIR,gBAAgB,EAGjB,MAAM,UAAU,CAAC;AAgBlB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAgGvD;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,WAAW,CAAoC;gBAE3C,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ;IAOjE;;OAEG;IACH,OAAO,IAAI,gBAAgB;IAqG3B;;OAEG;IACH,OAAO,CAAC,SAAS;IA+JjB;;OAEG;IACH,OAAO,CAAC,UAAU;IA4DlB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAQxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAc1B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAiB5B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;OAEG;IACH,OAAO,CAAC,eAAe;IAgFvB;;OAEG;IACH,OAAO,CAAC,YAAY;IAqCpB;;OAEG;IACH,OAAO,CAAC,aAAa;IA4FrB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAgCxB;;OAEG;IACH,OAAO,CAAC,aAAa;IAiCrB;;OAEG;IACH,OAAO,CAAC,WAAW;IAwCnB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAwB1B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAyCvB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAoGpB;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAmLvB;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IA8FxB;;;;;;OAMG;IACH,OAAO,CAAC,yBAAyB;IAiDjC;;;;OAIG;IACH,OAAO,CAAC,yBAAyB;IAgBjC;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IA+HrB;;OAEG;IACH,OAAO,CAAC,WAAW;IA8InB;;;;;;;;OAQG;IACH,OAAO,CAAC,oBAAoB;IA0C5B;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,oBAAoB;IA0F5B;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB;IAgFzB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAyR1B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA+C3B;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAEvC;IAEH;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAW3B;IAEH;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAoC9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,qBAAqB;IA+B7B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IA2D9B;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAYrC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAwBlC;;;OAGG;IACH,OAAO,CAAC,eAAe;IAuIvB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAuE7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA0BzB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAW1B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAiBhC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA0D5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAyCzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAmBzB;AAGD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,QAAQ,EACnB,cAAc,CAAC,EAAE,MAAM,EAAE,GACxB,gBAAgB,CAmElB"}
|
|
@@ -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");
|
|
@@ -395,6 +396,20 @@ class TreeSitterExtractor {
|
|
|
395
396
|
else if (nodeType === 'impl_item') {
|
|
396
397
|
this.extractRustImplItem(node);
|
|
397
398
|
}
|
|
399
|
+
// TypeScript interface members: property_signature (`foo: T`, `foo?: T`)
|
|
400
|
+
// and method_signature (`foo(arg: A): R`) both carry type annotations the
|
|
401
|
+
// interface walker would otherwise drop. Extract them as `references`
|
|
402
|
+
// edges from the interface so resolvers can wire callers/impact for
|
|
403
|
+
// types that only appear in interface members.
|
|
404
|
+
else if ((nodeType === 'property_signature' || nodeType === 'method_signature') &&
|
|
405
|
+
this.isInsideClassLikeNode() &&
|
|
406
|
+
this.TYPE_ANNOTATION_LANGUAGES.has(this.language)) {
|
|
407
|
+
const parentId = this.nodeStack[this.nodeStack.length - 1];
|
|
408
|
+
if (parentId) {
|
|
409
|
+
this.extractTypeAnnotations(node, parentId);
|
|
410
|
+
}
|
|
411
|
+
// don't skipChildren — nested signatures still need traversal
|
|
412
|
+
}
|
|
398
413
|
// Visit children (unless the extract method already visited them)
|
|
399
414
|
if (!skipChildren) {
|
|
400
415
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
@@ -651,6 +666,11 @@ class TreeSitterExtractor {
|
|
|
651
666
|
// in inline objects). These are ephemeral and create noise (e.g., Svelte context
|
|
652
667
|
// objects: `ctx.set({ get view() { ... } })`).
|
|
653
668
|
if (node.parent?.type === 'object' || node.parent?.type === 'object_expression') {
|
|
669
|
+
const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
|
|
670
|
+
?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
|
|
671
|
+
if (body) {
|
|
672
|
+
this.visitFunctionBody(body, '');
|
|
673
|
+
}
|
|
654
674
|
return;
|
|
655
675
|
}
|
|
656
676
|
// Not inside a class-like node and no receiver type, treat as function
|
|
@@ -875,6 +895,10 @@ class TreeSitterExtractor {
|
|
|
875
895
|
// decorator->target relationship for class properties too.
|
|
876
896
|
if (propNode) {
|
|
877
897
|
this.extractDecoratorsFor(node, propNode.id);
|
|
898
|
+
// Emit `references` edges from the property to types named in its
|
|
899
|
+
// type annotation (#381). The generic walker handles TS-style
|
|
900
|
+
// `type_annotation` children; the C# branch walks the `type` field.
|
|
901
|
+
this.extractTypeAnnotations(node, propNode.id);
|
|
878
902
|
}
|
|
879
903
|
}
|
|
880
904
|
/**
|
|
@@ -947,8 +971,15 @@ class TreeSitterExtractor {
|
|
|
947
971
|
});
|
|
948
972
|
// Java/Kotlin annotations / TS field decorators sit on the
|
|
949
973
|
// outer field_declaration, not on the individual declarator.
|
|
950
|
-
if (fieldNode)
|
|
974
|
+
if (fieldNode) {
|
|
951
975
|
this.extractDecoratorsFor(node, fieldNode.id);
|
|
976
|
+
// Same as properties: emit `references` to the field's annotated
|
|
977
|
+
// type. The outer `field_declaration` is the right scope to
|
|
978
|
+
// search from — C# carries the `type` inside `variable_declaration`
|
|
979
|
+
// and the language-aware path in `extractTypeAnnotations` descends
|
|
980
|
+
// into that wrapper (#381).
|
|
981
|
+
this.extractTypeAnnotations(node, fieldNode.id);
|
|
982
|
+
}
|
|
952
983
|
}
|
|
953
984
|
}
|
|
954
985
|
else {
|
|
@@ -1016,6 +1047,11 @@ class TreeSitterExtractor {
|
|
|
1016
1047
|
if (varNode) {
|
|
1017
1048
|
this.extractVariableTypeAnnotation(child, varNode.id);
|
|
1018
1049
|
}
|
|
1050
|
+
if (valueNode &&
|
|
1051
|
+
valueNode.type !== 'object' &&
|
|
1052
|
+
valueNode.type !== 'object_expression') {
|
|
1053
|
+
this.visitFunctionBody(valueNode, '');
|
|
1054
|
+
}
|
|
1019
1055
|
// Exported const object-of-functions: `export const actions =
|
|
1020
1056
|
// { default: async () => {} }` (SvelteKit form actions / handler maps
|
|
1021
1057
|
// / route tables). Extract each function-valued property as a function
|
|
@@ -1221,10 +1257,89 @@ class TreeSitterExtractor {
|
|
|
1221
1257
|
const value = (0, tree_sitter_helpers_1.getChildByField)(node, 'value');
|
|
1222
1258
|
if (value) {
|
|
1223
1259
|
this.extractTypeRefsFromSubtree(value, typeAliasNode.id);
|
|
1260
|
+
// `type X = { foo: T; bar(): T }` — make the members first-class
|
|
1261
|
+
// property/method nodes under the type alias so `recorder.stop()`
|
|
1262
|
+
// can attach the call edge to `RecorderHandle.stop` instead of
|
|
1263
|
+
// an unrelated class method picked by path-proximity (#359).
|
|
1264
|
+
if (this.language === 'typescript' || this.language === 'tsx') {
|
|
1265
|
+
this.extractTsTypeAliasMembers(value, typeAliasNode);
|
|
1266
|
+
}
|
|
1224
1267
|
}
|
|
1225
1268
|
}
|
|
1226
1269
|
return false;
|
|
1227
1270
|
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Surface the members of a TypeScript `type X = { ... }` (or intersection
|
|
1273
|
+
* thereof) as `property` / `method` nodes under the type-alias node. Only
|
|
1274
|
+
* walks the immediate object_type / intersection operands so anonymous
|
|
1275
|
+
* nested object types inside generic arguments (`Promise<{ ok: true }>`)
|
|
1276
|
+
* don't produce phantom members.
|
|
1277
|
+
*/
|
|
1278
|
+
extractTsTypeAliasMembers(value, typeAliasNode) {
|
|
1279
|
+
const objectTypes = [];
|
|
1280
|
+
if (value.type === 'object_type') {
|
|
1281
|
+
objectTypes.push(value);
|
|
1282
|
+
}
|
|
1283
|
+
else if (value.type === 'intersection_type') {
|
|
1284
|
+
for (let i = 0; i < value.namedChildCount; i++) {
|
|
1285
|
+
const op = value.namedChild(i);
|
|
1286
|
+
if (op && op.type === 'object_type')
|
|
1287
|
+
objectTypes.push(op);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
else {
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
this.nodeStack.push(typeAliasNode.id);
|
|
1294
|
+
for (const objType of objectTypes) {
|
|
1295
|
+
for (let i = 0; i < objType.namedChildCount; i++) {
|
|
1296
|
+
const child = objType.namedChild(i);
|
|
1297
|
+
if (!child)
|
|
1298
|
+
continue;
|
|
1299
|
+
if (child.type !== 'property_signature' && child.type !== 'method_signature')
|
|
1300
|
+
continue;
|
|
1301
|
+
const nameNode = (0, tree_sitter_helpers_1.getChildByField)(child, 'name');
|
|
1302
|
+
const memberName = nameNode ? (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source) : '';
|
|
1303
|
+
if (!memberName)
|
|
1304
|
+
continue;
|
|
1305
|
+
// `foo: () => T` and `foo(): T` are functionally a method on the
|
|
1306
|
+
// type contract. Treat the property_signature with a function-typed
|
|
1307
|
+
// annotation as a method too so call sites can resolve to it.
|
|
1308
|
+
const memberKind = child.type === 'method_signature'
|
|
1309
|
+
? 'method'
|
|
1310
|
+
: this.isTsFunctionTypedProperty(child) ? 'method' : 'property';
|
|
1311
|
+
const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(child, this.source);
|
|
1312
|
+
const signature = (0, tree_sitter_helpers_1.getNodeText)(child, this.source);
|
|
1313
|
+
this.createNode(memberKind, memberName, child, {
|
|
1314
|
+
docstring,
|
|
1315
|
+
signature,
|
|
1316
|
+
qualifiedName: `${typeAliasNode.name}::${memberName}`,
|
|
1317
|
+
});
|
|
1318
|
+
// Emit `references` edges from the type alias to types named in the
|
|
1319
|
+
// member's signature, matching the interface-member behavior added in
|
|
1320
|
+
// #432. We attach refs to the type-alias parent (consistent with
|
|
1321
|
+
// interface property_signature treatment).
|
|
1322
|
+
this.extractTypeAnnotations(child, typeAliasNode.id);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
this.nodeStack.pop();
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* `foo: () => T` → property_signature whose type_annotation contains a
|
|
1329
|
+
* `function_type`. Treat that as a method-shaped contract member, since
|
|
1330
|
+
* the call site `obj.foo()` has identical semantics to `bar(): T`.
|
|
1331
|
+
*/
|
|
1332
|
+
isTsFunctionTypedProperty(propertySignature) {
|
|
1333
|
+
const typeAnno = (0, tree_sitter_helpers_1.getChildByField)(propertySignature, 'type');
|
|
1334
|
+
if (!typeAnno)
|
|
1335
|
+
return false;
|
|
1336
|
+
for (let i = 0; i < typeAnno.namedChildCount; i++) {
|
|
1337
|
+
const inner = typeAnno.namedChild(i);
|
|
1338
|
+
if (inner && inner.type === 'function_type')
|
|
1339
|
+
return true;
|
|
1340
|
+
}
|
|
1341
|
+
return false;
|
|
1342
|
+
}
|
|
1228
1343
|
// extractExportedVariables removed — the walker now descends into
|
|
1229
1344
|
// export_statement children and the inner declaration's dedicated
|
|
1230
1345
|
// extractor (extractVariable, extractFunction, extractClass, etc.)
|
|
@@ -1373,7 +1488,25 @@ class TreeSitterExtractor {
|
|
|
1373
1488
|
if (nameField && objectField && (node.type === 'method_invocation' || node.type === 'member_call_expression' || node.type === 'scoped_call_expression')) {
|
|
1374
1489
|
// Method call with explicit receiver: receiver.method() / $receiver->method() / ClassName::method()
|
|
1375
1490
|
const methodName = (0, tree_sitter_helpers_1.getNodeText)(nameField, this.source);
|
|
1376
|
-
|
|
1491
|
+
// Java `this.userbo.toLogin2()` parses as method_invocation(object=field_access(this, userbo)).
|
|
1492
|
+
// Without unwrapping, receiverName is `this.userbo` and the name-matcher's
|
|
1493
|
+
// single-dot receiver regex fails. Pull out the immediate field after `this.`
|
|
1494
|
+
// so the receiver is the field name (`userbo`), which the resolver can then
|
|
1495
|
+
// look up in the enclosing class's field declarations.
|
|
1496
|
+
let receiverName;
|
|
1497
|
+
if (objectField.type === 'field_access') {
|
|
1498
|
+
const inner = (0, tree_sitter_helpers_1.getChildByField)(objectField, 'object');
|
|
1499
|
+
const fld = (0, tree_sitter_helpers_1.getChildByField)(objectField, 'field');
|
|
1500
|
+
if (inner && fld && (inner.type === 'this' || inner.type === 'this_expression')) {
|
|
1501
|
+
receiverName = (0, tree_sitter_helpers_1.getNodeText)(fld, this.source);
|
|
1502
|
+
}
|
|
1503
|
+
else {
|
|
1504
|
+
receiverName = (0, tree_sitter_helpers_1.getNodeText)(objectField, this.source);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
else {
|
|
1508
|
+
receiverName = (0, tree_sitter_helpers_1.getNodeText)(objectField, this.source);
|
|
1509
|
+
}
|
|
1377
1510
|
// Strip PHP $ prefix from variable names
|
|
1378
1511
|
receiverName = receiverName.replace(/^\$/, '');
|
|
1379
1512
|
if (methodName) {
|
|
@@ -1427,10 +1560,11 @@ class TreeSitterExtractor {
|
|
|
1427
1560
|
else {
|
|
1428
1561
|
const func = (0, tree_sitter_helpers_1.getChildByField)(node, 'function') || node.namedChild(0);
|
|
1429
1562
|
if (func) {
|
|
1430
|
-
if (func.type === 'member_expression' || func.type === 'attribute' || func.type === 'selector_expression' || func.type === 'navigation_expression') {
|
|
1563
|
+
if (func.type === 'member_expression' || func.type === 'attribute' || func.type === 'selector_expression' || func.type === 'navigation_expression' || func.type === 'field_expression') {
|
|
1431
1564
|
// Method call: obj.method() or obj.field.method()
|
|
1432
1565
|
// Go uses selector_expression with 'field', JS/TS uses member_expression with 'property'
|
|
1433
1566
|
// Kotlin uses navigation_expression with navigation_suffix > simple_identifier
|
|
1567
|
+
// C/C++ use field_expression for both `obj.method()` and `ptr->method()`
|
|
1434
1568
|
let property = (0, tree_sitter_helpers_1.getChildByField)(func, 'property') || (0, tree_sitter_helpers_1.getChildByField)(func, 'field');
|
|
1435
1569
|
if (!property) {
|
|
1436
1570
|
const child1 = func.namedChild(1);
|
|
@@ -1448,9 +1582,12 @@ class TreeSitterExtractor {
|
|
|
1448
1582
|
// This helps the resolver distinguish method calls from bare function calls
|
|
1449
1583
|
// (e.g., Python's console.print() vs builtin print())
|
|
1450
1584
|
// Skip self/this/cls as they don't aid resolution
|
|
1451
|
-
const receiver = (0, tree_sitter_helpers_1.getChildByField)(func, 'object') ||
|
|
1585
|
+
const receiver = (0, tree_sitter_helpers_1.getChildByField)(func, 'object') ||
|
|
1586
|
+
(0, tree_sitter_helpers_1.getChildByField)(func, 'operand') ||
|
|
1587
|
+
(0, tree_sitter_helpers_1.getChildByField)(func, 'argument') ||
|
|
1588
|
+
func.namedChild(0);
|
|
1452
1589
|
const SKIP_RECEIVERS = new Set(['self', 'this', 'cls', 'super']);
|
|
1453
|
-
if (receiver && (receiver.type === 'identifier' || receiver.type === 'simple_identifier')) {
|
|
1590
|
+
if (receiver && (receiver.type === 'identifier' || receiver.type === 'simple_identifier' || receiver.type === 'field_identifier')) {
|
|
1454
1591
|
const receiverName = (0, tree_sitter_helpers_1.getNodeText)(receiver, this.source);
|
|
1455
1592
|
if (!SKIP_RECEIVERS.has(receiverName)) {
|
|
1456
1593
|
calleeName = `${receiverName}.${methodName}`;
|
|
@@ -2083,6 +2220,16 @@ class TreeSitterExtractor {
|
|
|
2083
2220
|
return;
|
|
2084
2221
|
if (!this.TYPE_ANNOTATION_LANGUAGES.has(this.language))
|
|
2085
2222
|
return;
|
|
2223
|
+
// C# tree-sitter doesn't produce `type_identifier` leaves — it uses
|
|
2224
|
+
// `identifier`, `predefined_type`, `qualified_name`, `generic_name`,
|
|
2225
|
+
// etc. — so the generic walker below emits zero references for it.
|
|
2226
|
+
// Dispatch to a C#-aware path that only walks type-position subtrees
|
|
2227
|
+
// (the `type` field of a parameter/method/property/field), so
|
|
2228
|
+
// parameter NAMES never accidentally surface as type refs (#381).
|
|
2229
|
+
if (this.language === 'csharp') {
|
|
2230
|
+
this.extractCsharpTypeRefs(node, nodeId);
|
|
2231
|
+
return;
|
|
2232
|
+
}
|
|
2086
2233
|
// Extract parameter type annotations
|
|
2087
2234
|
const params = (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.paramsField || 'parameters');
|
|
2088
2235
|
if (params) {
|
|
@@ -2099,6 +2246,112 @@ class TreeSitterExtractor {
|
|
|
2099
2246
|
this.extractTypeRefsFromSubtree(typeAnnotation, nodeId);
|
|
2100
2247
|
}
|
|
2101
2248
|
}
|
|
2249
|
+
/**
|
|
2250
|
+
* Extract C# type references from a node that owns a type position —
|
|
2251
|
+
* a method/constructor declaration, a property declaration, or a
|
|
2252
|
+
* field declaration (which wraps `variable_declaration → type`).
|
|
2253
|
+
*
|
|
2254
|
+
* Walks ONLY into known type fields, so parameter names like
|
|
2255
|
+
* `request` in `Build(UserDto request)` are never mis-emitted as
|
|
2256
|
+
* type references. Once inside a type subtree, `walkCsharpTypePosition`
|
|
2257
|
+
* recognizes C#'s actual type-leaf node kinds (`identifier`,
|
|
2258
|
+
* `qualified_name`, `generic_name`, `array_type`, `nullable_type`,
|
|
2259
|
+
* `tuple_type`, …) — none of which are `type_identifier`. Closes #381.
|
|
2260
|
+
*/
|
|
2261
|
+
extractCsharpTypeRefs(node, nodeId) {
|
|
2262
|
+
// Return type / property type — the field is named `type`.
|
|
2263
|
+
const directType = (0, tree_sitter_helpers_1.getChildByField)(node, 'type');
|
|
2264
|
+
if (directType)
|
|
2265
|
+
this.walkCsharpTypePosition(directType, nodeId);
|
|
2266
|
+
// Field declarations wrap declarators in a `variable_declaration`
|
|
2267
|
+
// whose `type` field carries the type. The outer `field_declaration`
|
|
2268
|
+
// has no `type` field of its own, so the call above is a no-op here
|
|
2269
|
+
// and we descend one level.
|
|
2270
|
+
const varDecl = node.namedChildren.find((c) => c.type === 'variable_declaration');
|
|
2271
|
+
if (varDecl) {
|
|
2272
|
+
const vdType = (0, tree_sitter_helpers_1.getChildByField)(varDecl, 'type');
|
|
2273
|
+
if (vdType)
|
|
2274
|
+
this.walkCsharpTypePosition(vdType, nodeId);
|
|
2275
|
+
}
|
|
2276
|
+
// Method / constructor parameters. The field name on
|
|
2277
|
+
// `method_declaration` is `parameters`; it points at a
|
|
2278
|
+
// `parameter_list` whose `parameter` children each have their own
|
|
2279
|
+
// `type` field. Walking ONLY the type field skips parameter NAMES,
|
|
2280
|
+
// which would otherwise mis-emit as type references.
|
|
2281
|
+
const params = (0, tree_sitter_helpers_1.getChildByField)(node, 'parameters');
|
|
2282
|
+
if (params) {
|
|
2283
|
+
for (let i = 0; i < params.namedChildCount; i++) {
|
|
2284
|
+
const child = params.namedChild(i);
|
|
2285
|
+
if (!child || child.type !== 'parameter')
|
|
2286
|
+
continue;
|
|
2287
|
+
const paramType = (0, tree_sitter_helpers_1.getChildByField)(child, 'type');
|
|
2288
|
+
if (paramType)
|
|
2289
|
+
this.walkCsharpTypePosition(paramType, nodeId);
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
/**
|
|
2294
|
+
* Walk a C# subtree that is KNOWN to be in a type position
|
|
2295
|
+
* (return type, parameter type, property type, field type, generic
|
|
2296
|
+
* argument). Identifiers here are type names, not parameter names.
|
|
2297
|
+
*/
|
|
2298
|
+
walkCsharpTypePosition(node, fromNodeId) {
|
|
2299
|
+
// `predefined_type` is int/string/bool/etc. — never a project ref.
|
|
2300
|
+
if (node.type === 'predefined_type')
|
|
2301
|
+
return;
|
|
2302
|
+
// Bare type name: `Foo` in `Foo bar`, or the `Foo` inside `List<Foo>`.
|
|
2303
|
+
if (node.type === 'identifier') {
|
|
2304
|
+
const name = (0, tree_sitter_helpers_1.getNodeText)(node, this.source);
|
|
2305
|
+
if (name && !this.BUILTIN_TYPES.has(name)) {
|
|
2306
|
+
this.unresolvedReferences.push({
|
|
2307
|
+
fromNodeId,
|
|
2308
|
+
referenceName: name,
|
|
2309
|
+
referenceKind: 'references',
|
|
2310
|
+
line: node.startPosition.row + 1,
|
|
2311
|
+
column: node.startPosition.column,
|
|
2312
|
+
});
|
|
2313
|
+
}
|
|
2314
|
+
return;
|
|
2315
|
+
}
|
|
2316
|
+
// `Namespace.Foo` → the rightmost identifier is the type. Emit the
|
|
2317
|
+
// full qualified name as the reference; the resolver can still match
|
|
2318
|
+
// on the trailing simple name when needed.
|
|
2319
|
+
if (node.type === 'qualified_name') {
|
|
2320
|
+
const text = (0, tree_sitter_helpers_1.getNodeText)(node, this.source);
|
|
2321
|
+
const last = text.split('.').pop() ?? text;
|
|
2322
|
+
if (last && !this.BUILTIN_TYPES.has(last)) {
|
|
2323
|
+
this.unresolvedReferences.push({
|
|
2324
|
+
fromNodeId,
|
|
2325
|
+
referenceName: last,
|
|
2326
|
+
referenceKind: 'references',
|
|
2327
|
+
line: node.startPosition.row + 1,
|
|
2328
|
+
column: node.startPosition.column,
|
|
2329
|
+
});
|
|
2330
|
+
}
|
|
2331
|
+
return;
|
|
2332
|
+
}
|
|
2333
|
+
// `(int Code, Foo Payload)` — tuple element has BOTH a `type` and a
|
|
2334
|
+
// `name` field; descending into all named children would mis-emit
|
|
2335
|
+
// the element name (`Code`, `Payload`) as a type ref. Walk only the
|
|
2336
|
+
// type field.
|
|
2337
|
+
if (node.type === 'tuple_element') {
|
|
2338
|
+
const t = (0, tree_sitter_helpers_1.getChildByField)(node, 'type');
|
|
2339
|
+
if (t)
|
|
2340
|
+
this.walkCsharpTypePosition(t, fromNodeId);
|
|
2341
|
+
return;
|
|
2342
|
+
}
|
|
2343
|
+
// Composite type nodes — recurse into named children. Covers
|
|
2344
|
+
// `generic_name` (head identifier + `type_argument_list`),
|
|
2345
|
+
// `nullable_type`, `array_type`, `pointer_type`, `tuple_type`,
|
|
2346
|
+
// `ref_type`, and any newer wrapping shapes the grammar adds.
|
|
2347
|
+
// Identifiers reached here are all type-positional (parameter/field
|
|
2348
|
+
// names are gated out before we descend).
|
|
2349
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
2350
|
+
const child = node.namedChild(i);
|
|
2351
|
+
if (child)
|
|
2352
|
+
this.walkCsharpTypePosition(child, fromNodeId);
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2102
2355
|
/**
|
|
2103
2356
|
* Extract type references from a variable's type annotation.
|
|
2104
2357
|
*/
|
|
@@ -2535,10 +2788,17 @@ function extractFromSource(filePath, source, language, frameworkNames) {
|
|
|
2535
2788
|
const extractor = new liquid_extractor_1.LiquidExtractor(filePath, source);
|
|
2536
2789
|
result = extractor.extract();
|
|
2537
2790
|
}
|
|
2538
|
-
else if (detectedLanguage === '
|
|
2539
|
-
//
|
|
2540
|
-
//
|
|
2541
|
-
|
|
2791
|
+
else if (detectedLanguage === 'xml') {
|
|
2792
|
+
// Custom extractor for MyBatis mapper XML. Non-mapper XML returns just a
|
|
2793
|
+
// file node so the watcher tracks it without emitting symbols.
|
|
2794
|
+
const extractor = new mybatis_extractor_1.MyBatisExtractor(filePath, source);
|
|
2795
|
+
result = extractor.extract();
|
|
2796
|
+
}
|
|
2797
|
+
else if (detectedLanguage === 'yaml' || detectedLanguage === 'twig' || detectedLanguage === 'properties') {
|
|
2798
|
+
// No symbol extraction at this stage — files are tracked at the file-record
|
|
2799
|
+
// level only. Framework extractors (Drupal routing yml, Spring `@Value`
|
|
2800
|
+
// resolution against application.yml/application.properties) run later and
|
|
2801
|
+
// add per-file nodes/references when they apply.
|
|
2542
2802
|
result = { nodes: [], edges: [], unresolvedReferences: [], errors: [], durationMs: 0 };
|
|
2543
2803
|
}
|
|
2544
2804
|
else if (detectedLanguage === 'pascal' &&
|