gitnexus 1.4.10 → 1.5.0
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/README.md +6 -5
- package/dist/cli/ai-context.d.ts +4 -1
- package/dist/cli/ai-context.js +19 -11
- package/dist/cli/analyze.d.ts +6 -0
- package/dist/cli/analyze.js +105 -251
- package/dist/cli/eval-server.js +20 -11
- package/dist/cli/index-repo.js +20 -22
- package/dist/cli/index.js +8 -7
- package/dist/cli/mcp.js +1 -1
- package/dist/cli/serve.js +29 -1
- package/dist/cli/setup.js +9 -9
- package/dist/cli/skill-gen.js +15 -9
- package/dist/cli/wiki.d.ts +2 -0
- package/dist/cli/wiki.js +141 -26
- package/dist/config/ignore-service.js +102 -22
- package/dist/config/supported-languages.d.ts +8 -42
- package/dist/config/supported-languages.js +8 -43
- package/dist/core/augmentation/engine.js +19 -7
- package/dist/core/embeddings/embedder.js +19 -15
- package/dist/core/embeddings/embedding-pipeline.js +6 -6
- package/dist/core/embeddings/http-client.js +3 -3
- package/dist/core/embeddings/text-generator.js +9 -24
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/embeddings/types.js +1 -7
- package/dist/core/graph/graph.js +6 -2
- package/dist/core/graph/types.d.ts +9 -59
- package/dist/core/ingestion/ast-cache.js +3 -3
- package/dist/core/ingestion/call-processor.d.ts +20 -2
- package/dist/core/ingestion/call-processor.js +347 -144
- package/dist/core/ingestion/call-routing.js +10 -4
- package/dist/core/ingestion/call-sites/extract-language-call-site.d.ts +10 -0
- package/dist/core/ingestion/call-sites/extract-language-call-site.js +22 -0
- package/dist/core/ingestion/call-sites/java.d.ts +9 -0
- package/dist/core/ingestion/call-sites/java.js +30 -0
- package/dist/core/ingestion/cluster-enricher.js +6 -8
- package/dist/core/ingestion/cobol/cobol-copy-expander.js +10 -3
- package/dist/core/ingestion/cobol/cobol-preprocessor.js +287 -81
- package/dist/core/ingestion/cobol/jcl-parser.js +1 -1
- package/dist/core/ingestion/cobol/jcl-processor.js +1 -1
- package/dist/core/ingestion/cobol-processor.js +102 -56
- package/dist/core/ingestion/community-processor.js +21 -15
- package/dist/core/ingestion/entry-point-scoring.d.ts +1 -1
- package/dist/core/ingestion/entry-point-scoring.js +5 -6
- package/dist/core/ingestion/export-detection.js +32 -9
- package/dist/core/ingestion/field-extractor.d.ts +1 -1
- package/dist/core/ingestion/field-extractors/configs/c-cpp.js +8 -12
- package/dist/core/ingestion/field-extractors/configs/csharp.js +45 -2
- package/dist/core/ingestion/field-extractors/configs/dart.js +5 -3
- package/dist/core/ingestion/field-extractors/configs/go.js +3 -7
- package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +5 -0
- package/dist/core/ingestion/field-extractors/configs/helpers.js +14 -0
- package/dist/core/ingestion/field-extractors/configs/jvm.js +7 -7
- package/dist/core/ingestion/field-extractors/configs/php.js +9 -11
- package/dist/core/ingestion/field-extractors/configs/python.js +1 -1
- package/dist/core/ingestion/field-extractors/configs/ruby.js +4 -3
- package/dist/core/ingestion/field-extractors/configs/rust.js +2 -5
- package/dist/core/ingestion/field-extractors/configs/swift.js +9 -7
- package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +2 -6
- package/dist/core/ingestion/field-extractors/generic.d.ts +5 -2
- package/dist/core/ingestion/field-extractors/generic.js +6 -0
- package/dist/core/ingestion/field-extractors/typescript.d.ts +1 -1
- package/dist/core/ingestion/field-extractors/typescript.js +1 -1
- package/dist/core/ingestion/field-types.d.ts +4 -2
- package/dist/core/ingestion/filesystem-walker.js +3 -3
- package/dist/core/ingestion/framework-detection.d.ts +1 -1
- package/dist/core/ingestion/framework-detection.js +355 -85
- package/dist/core/ingestion/heritage-processor.d.ts +24 -0
- package/dist/core/ingestion/heritage-processor.js +99 -8
- package/dist/core/ingestion/import-processor.js +44 -15
- package/dist/core/ingestion/import-resolvers/csharp.js +7 -3
- package/dist/core/ingestion/import-resolvers/dart.js +1 -1
- package/dist/core/ingestion/import-resolvers/go.js +4 -2
- package/dist/core/ingestion/import-resolvers/jvm.js +4 -4
- package/dist/core/ingestion/import-resolvers/php.js +4 -4
- package/dist/core/ingestion/import-resolvers/python.js +1 -1
- package/dist/core/ingestion/import-resolvers/rust.js +9 -3
- package/dist/core/ingestion/import-resolvers/standard.d.ts +1 -1
- package/dist/core/ingestion/import-resolvers/standard.js +6 -5
- package/dist/core/ingestion/import-resolvers/swift.js +2 -1
- package/dist/core/ingestion/import-resolvers/utils.js +26 -7
- package/dist/core/ingestion/language-config.js +5 -4
- package/dist/core/ingestion/language-provider.d.ts +7 -2
- package/dist/core/ingestion/languages/c-cpp.js +106 -21
- package/dist/core/ingestion/languages/cobol.js +1 -1
- package/dist/core/ingestion/languages/csharp.js +96 -19
- package/dist/core/ingestion/languages/dart.js +23 -7
- package/dist/core/ingestion/languages/go.js +1 -1
- package/dist/core/ingestion/languages/index.d.ts +1 -1
- package/dist/core/ingestion/languages/index.js +2 -3
- package/dist/core/ingestion/languages/java.js +4 -1
- package/dist/core/ingestion/languages/kotlin.js +60 -13
- package/dist/core/ingestion/languages/php.js +102 -25
- package/dist/core/ingestion/languages/python.js +28 -5
- package/dist/core/ingestion/languages/ruby.js +56 -14
- package/dist/core/ingestion/languages/rust.js +55 -11
- package/dist/core/ingestion/languages/swift.js +112 -27
- package/dist/core/ingestion/languages/typescript.js +95 -19
- package/dist/core/ingestion/markdown-processor.js +5 -5
- package/dist/core/ingestion/method-extractors/configs/csharp.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/csharp.js +283 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.js +326 -0
- package/dist/core/ingestion/method-extractors/generic.d.ts +5 -0
- package/dist/core/ingestion/method-extractors/generic.js +137 -0
- package/dist/core/ingestion/method-types.d.ts +61 -0
- package/dist/core/ingestion/method-types.js +2 -0
- package/dist/core/ingestion/mro-processor.d.ts +1 -1
- package/dist/core/ingestion/mro-processor.js +12 -8
- package/dist/core/ingestion/named-binding-processor.js +2 -2
- package/dist/core/ingestion/named-bindings/rust.js +3 -1
- package/dist/core/ingestion/parsing-processor.js +74 -24
- package/dist/core/ingestion/pipeline.d.ts +2 -1
- package/dist/core/ingestion/pipeline.js +208 -102
- package/dist/core/ingestion/process-processor.js +12 -10
- package/dist/core/ingestion/resolution-context.js +3 -3
- package/dist/core/ingestion/route-extractors/middleware.js +31 -7
- package/dist/core/ingestion/route-extractors/php.js +2 -1
- package/dist/core/ingestion/route-extractors/response-shapes.js +8 -4
- package/dist/core/ingestion/structure-processor.d.ts +1 -1
- package/dist/core/ingestion/structure-processor.js +4 -4
- package/dist/core/ingestion/symbol-table.d.ts +1 -1
- package/dist/core/ingestion/symbol-table.js +22 -6
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +1 -1
- package/dist/core/ingestion/type-env.d.ts +2 -2
- package/dist/core/ingestion/type-env.js +75 -50
- package/dist/core/ingestion/type-extractors/c-cpp.js +33 -30
- package/dist/core/ingestion/type-extractors/csharp.js +24 -14
- package/dist/core/ingestion/type-extractors/dart.js +6 -8
- package/dist/core/ingestion/type-extractors/go.js +7 -6
- package/dist/core/ingestion/type-extractors/jvm.js +10 -21
- package/dist/core/ingestion/type-extractors/php.js +26 -13
- package/dist/core/ingestion/type-extractors/python.js +11 -15
- package/dist/core/ingestion/type-extractors/ruby.js +8 -3
- package/dist/core/ingestion/type-extractors/rust.js +6 -8
- package/dist/core/ingestion/type-extractors/shared.js +134 -50
- package/dist/core/ingestion/type-extractors/swift.js +16 -13
- package/dist/core/ingestion/type-extractors/typescript.js +23 -15
- package/dist/core/ingestion/utils/ast-helpers.d.ts +8 -8
- package/dist/core/ingestion/utils/ast-helpers.js +72 -35
- package/dist/core/ingestion/utils/call-analysis.d.ts +2 -0
- package/dist/core/ingestion/utils/call-analysis.js +96 -49
- package/dist/core/ingestion/utils/event-loop.js +1 -1
- package/dist/core/ingestion/workers/parse-worker.d.ts +7 -2
- package/dist/core/ingestion/workers/parse-worker.js +364 -84
- package/dist/core/ingestion/workers/worker-pool.js +5 -10
- package/dist/core/lbug/csv-generator.js +54 -15
- package/dist/core/lbug/lbug-adapter.d.ts +5 -0
- package/dist/core/lbug/lbug-adapter.js +86 -23
- package/dist/core/lbug/schema.d.ts +3 -6
- package/dist/core/lbug/schema.js +6 -30
- package/dist/core/run-analyze.d.ts +49 -0
- package/dist/core/run-analyze.js +257 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +1 -1
- package/dist/core/tree-sitter/parser-loader.js +1 -1
- package/dist/core/wiki/cursor-client.js +2 -7
- package/dist/core/wiki/generator.js +38 -23
- package/dist/core/wiki/graph-queries.js +10 -10
- package/dist/core/wiki/html-viewer.js +7 -3
- package/dist/core/wiki/llm-client.d.ts +23 -2
- package/dist/core/wiki/llm-client.js +96 -26
- package/dist/core/wiki/prompts.js +7 -6
- package/dist/mcp/core/embedder.js +1 -1
- package/dist/mcp/core/lbug-adapter.d.ts +4 -1
- package/dist/mcp/core/lbug-adapter.js +17 -7
- package/dist/mcp/local/local-backend.js +247 -95
- package/dist/mcp/resources.js +14 -6
- package/dist/mcp/server.js +13 -5
- package/dist/mcp/staleness.js +5 -1
- package/dist/mcp/tools.js +100 -23
- package/dist/server/analyze-job.d.ts +53 -0
- package/dist/server/analyze-job.js +146 -0
- package/dist/server/analyze-worker.d.ts +13 -0
- package/dist/server/analyze-worker.js +59 -0
- package/dist/server/api.js +795 -44
- package/dist/server/git-clone.d.ts +25 -0
- package/dist/server/git-clone.js +91 -0
- package/dist/storage/git.js +1 -3
- package/dist/storage/repo-manager.d.ts +5 -2
- package/dist/storage/repo-manager.js +4 -4
- package/dist/types/pipeline.d.ts +1 -21
- package/dist/types/pipeline.js +1 -18
- package/hooks/claude/gitnexus-hook.cjs +52 -22
- package/package.json +3 -2
- package/dist/core/ingestion/utils/language-detection.d.ts +0 -9
- package/dist/core/ingestion/utils/language-detection.js +0 -70
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
// gitnexus/src/core/ingestion/method-extractors/configs/csharp.ts
|
|
2
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
3
|
+
import { findVisibility, hasModifier, hasKeyword, collectModifierTexts, } from '../../field-extractors/configs/helpers.js';
|
|
4
|
+
import { extractSimpleTypeName } from '../../type-extractors/shared.js';
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// C# helpers
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
const CSHARP_VIS = new Set(['public', 'private', 'protected', 'internal']);
|
|
9
|
+
/**
|
|
10
|
+
* Walk the parameter_list of a method or constructor and return typed ParameterInfo
|
|
11
|
+
* entries.
|
|
12
|
+
*
|
|
13
|
+
* In tree-sitter-c-sharp (verified against ^0.23.1), the `params` variadic keyword
|
|
14
|
+
* is NOT wrapped inside a `parameter` node. It appears as a bare unnamed `params`
|
|
15
|
+
* token at the `parameter_list` level, followed by a type node and an identifier
|
|
16
|
+
* node that are also direct children of `parameter_list` (not of a `parameter` node).
|
|
17
|
+
*
|
|
18
|
+
* All other parameters are normal `parameter` named children of `parameter_list`:
|
|
19
|
+
* - name comes from field 'name'
|
|
20
|
+
* - type comes from field 'type'
|
|
21
|
+
* - ref / out: modifier children inside the parameter node prefix the type string
|
|
22
|
+
* - isOptional: an '=' token appears among the children (indicates a default value)
|
|
23
|
+
*/
|
|
24
|
+
function extractCSharpParameters(node) {
|
|
25
|
+
const paramList = node.childForFieldName('parameters');
|
|
26
|
+
if (!paramList)
|
|
27
|
+
return [];
|
|
28
|
+
return extractParametersFromList(paramList);
|
|
29
|
+
}
|
|
30
|
+
/** Extract parameters from a parameter_list node directly. */
|
|
31
|
+
function extractParametersFromList(paramList) {
|
|
32
|
+
const params = [];
|
|
33
|
+
let i = 0;
|
|
34
|
+
while (i < paramList.childCount) {
|
|
35
|
+
const child = paramList.child(i);
|
|
36
|
+
if (!child) {
|
|
37
|
+
i++;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
// `params` variadic: bare unnamed `params` keyword followed by type + identifier
|
|
41
|
+
// siblings at the parameter_list level (not wrapped in a `parameter` node).
|
|
42
|
+
if (!child.isNamed && child.type === 'params') {
|
|
43
|
+
let typeNode = null;
|
|
44
|
+
let nameText;
|
|
45
|
+
let j = i + 1;
|
|
46
|
+
while (j < paramList.childCount) {
|
|
47
|
+
const sibling = paramList.child(j);
|
|
48
|
+
if (!sibling) {
|
|
49
|
+
j++;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (sibling.isNamed && sibling.type !== 'parameter') {
|
|
53
|
+
if (!typeNode) {
|
|
54
|
+
typeNode = sibling;
|
|
55
|
+
}
|
|
56
|
+
else if (sibling.type === 'identifier') {
|
|
57
|
+
nameText = sibling.text;
|
|
58
|
+
i = j;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
j++;
|
|
63
|
+
}
|
|
64
|
+
if (nameText) {
|
|
65
|
+
params.push({
|
|
66
|
+
name: nameText,
|
|
67
|
+
type: typeNode
|
|
68
|
+
? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim() ?? null)
|
|
69
|
+
: null,
|
|
70
|
+
isOptional: false,
|
|
71
|
+
isVariadic: true,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
i++;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
// Regular named `parameter` node
|
|
78
|
+
if (child.isNamed && child.type === 'parameter') {
|
|
79
|
+
const nameNode = child.childForFieldName('name');
|
|
80
|
+
if (nameNode && nameNode.text.trim()) {
|
|
81
|
+
const typeNode = child.childForFieldName('type');
|
|
82
|
+
let typeName = typeNode
|
|
83
|
+
? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim() ?? null)
|
|
84
|
+
: null;
|
|
85
|
+
// Detect ref / out modifiers inside the parameter node — prefix the type string
|
|
86
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
87
|
+
const c = child.namedChild(j);
|
|
88
|
+
if (!c || c.type !== 'modifier')
|
|
89
|
+
continue;
|
|
90
|
+
const modText = c.text.trim();
|
|
91
|
+
if (modText === 'out' || modText === 'ref' || modText === 'in' || modText === 'this') {
|
|
92
|
+
typeName = typeName ? `${modText} ${typeName}` : modText;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Detect optional (default value) — an '=' token among direct children
|
|
97
|
+
let isOptional = false;
|
|
98
|
+
for (let j = 0; j < child.childCount; j++) {
|
|
99
|
+
const c = child.child(j);
|
|
100
|
+
if (c && c.text.trim() === '=') {
|
|
101
|
+
isOptional = true;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
params.push({
|
|
106
|
+
name: nameNode.text,
|
|
107
|
+
type: typeName,
|
|
108
|
+
isOptional,
|
|
109
|
+
isVariadic: false,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
i++;
|
|
114
|
+
}
|
|
115
|
+
return params;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Collect C# attributes from attribute_list nodes on a method or constructor.
|
|
119
|
+
* Skips attribute lists with a target specifier (e.g. [return: NotNull],
|
|
120
|
+
* [param: Required]) — those target a different declaration element.
|
|
121
|
+
* Names are prefixed with '@' to mirror the JVM convention.
|
|
122
|
+
*/
|
|
123
|
+
function extractCSharpAnnotations(node) {
|
|
124
|
+
const annotations = [];
|
|
125
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
126
|
+
const child = node.namedChild(i);
|
|
127
|
+
if (!child || child.type !== 'attribute_list')
|
|
128
|
+
continue;
|
|
129
|
+
// Skip targeted attribute lists (e.g. [return: ...], [method: ...])
|
|
130
|
+
let hasTarget = false;
|
|
131
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
132
|
+
if (child.namedChild(j)?.type === 'attribute_target_specifier') {
|
|
133
|
+
hasTarget = true;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (hasTarget)
|
|
138
|
+
continue;
|
|
139
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
140
|
+
const attr = child.namedChild(j);
|
|
141
|
+
if (!attr || attr.type !== 'attribute')
|
|
142
|
+
continue;
|
|
143
|
+
const nameNode = attr.childForFieldName('name');
|
|
144
|
+
if (nameNode)
|
|
145
|
+
annotations.push('@' + nameNode.text);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return annotations;
|
|
149
|
+
}
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
// C# config
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
export const csharpMethodConfig = {
|
|
154
|
+
language: SupportedLanguages.CSharp,
|
|
155
|
+
typeDeclarationNodes: [
|
|
156
|
+
'class_declaration',
|
|
157
|
+
'struct_declaration',
|
|
158
|
+
'interface_declaration',
|
|
159
|
+
'record_declaration',
|
|
160
|
+
],
|
|
161
|
+
methodNodeTypes: [
|
|
162
|
+
'method_declaration',
|
|
163
|
+
'constructor_declaration',
|
|
164
|
+
'destructor_declaration',
|
|
165
|
+
'operator_declaration',
|
|
166
|
+
'conversion_operator_declaration',
|
|
167
|
+
],
|
|
168
|
+
bodyNodeTypes: ['declaration_list'],
|
|
169
|
+
extractName(node) {
|
|
170
|
+
// destructor_declaration: prefix with ~ to distinguish from constructor
|
|
171
|
+
if (node.type === 'destructor_declaration') {
|
|
172
|
+
const name = node.childForFieldName('name')?.text;
|
|
173
|
+
return name ? `~${name}` : undefined;
|
|
174
|
+
}
|
|
175
|
+
// operator_declaration: no 'name' field — use 'operator' field (e.g., +, ==)
|
|
176
|
+
if (node.type === 'operator_declaration') {
|
|
177
|
+
const op = node.childForFieldName('operator');
|
|
178
|
+
return op ? `operator ${op.text.trim()}` : undefined;
|
|
179
|
+
}
|
|
180
|
+
// conversion_operator_declaration: no 'name' field — implicit/explicit + target type
|
|
181
|
+
if (node.type === 'conversion_operator_declaration') {
|
|
182
|
+
const typeNode = node.childForFieldName('type');
|
|
183
|
+
const typeName = typeNode
|
|
184
|
+
? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim())
|
|
185
|
+
: undefined;
|
|
186
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
187
|
+
const c = node.child(i);
|
|
188
|
+
if (c && !c.isNamed && (c.text === 'implicit' || c.text === 'explicit')) {
|
|
189
|
+
return typeName ? `${c.text} operator ${typeName}` : undefined;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return typeName ? `operator ${typeName}` : undefined;
|
|
193
|
+
}
|
|
194
|
+
return node.childForFieldName('name')?.text;
|
|
195
|
+
},
|
|
196
|
+
extractReturnType(node) {
|
|
197
|
+
// Constructors and destructors have no return type
|
|
198
|
+
// operator_declaration and conversion_operator_declaration use 'type' field, not 'returns'
|
|
199
|
+
const returnsNode = node.childForFieldName('returns');
|
|
200
|
+
if (returnsNode)
|
|
201
|
+
return extractSimpleTypeName(returnsNode) ?? returnsNode.text?.trim();
|
|
202
|
+
// Fallback for operator/conversion declarations that use 'type' as return type field
|
|
203
|
+
if (node.type === 'operator_declaration' || node.type === 'conversion_operator_declaration') {
|
|
204
|
+
const typeNode = node.childForFieldName('type');
|
|
205
|
+
if (typeNode)
|
|
206
|
+
return extractSimpleTypeName(typeNode) ?? typeNode.text?.trim();
|
|
207
|
+
}
|
|
208
|
+
return undefined;
|
|
209
|
+
},
|
|
210
|
+
extractParameters: extractCSharpParameters,
|
|
211
|
+
extractVisibility(node) {
|
|
212
|
+
// Detect compound C# visibilities: protected internal, private protected
|
|
213
|
+
const mods = collectModifierTexts(node);
|
|
214
|
+
if (mods.has('protected') && mods.has('internal'))
|
|
215
|
+
return 'protected internal';
|
|
216
|
+
if (mods.has('private') && mods.has('protected'))
|
|
217
|
+
return 'private protected';
|
|
218
|
+
return findVisibility(node, CSHARP_VIS, 'private', 'modifier');
|
|
219
|
+
},
|
|
220
|
+
isStatic(node) {
|
|
221
|
+
return hasKeyword(node, 'static') || hasModifier(node, 'modifier', 'static');
|
|
222
|
+
},
|
|
223
|
+
isAbstract(node, ownerNode) {
|
|
224
|
+
if (hasKeyword(node, 'abstract') || hasModifier(node, 'modifier', 'abstract'))
|
|
225
|
+
return true;
|
|
226
|
+
// Interface methods are implicitly abstract when they have no body
|
|
227
|
+
if (ownerNode.type === 'interface_declaration') {
|
|
228
|
+
const body = node.childForFieldName('body');
|
|
229
|
+
return !body;
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
},
|
|
233
|
+
isFinal(node) {
|
|
234
|
+
// C# uses 'sealed' instead of 'final'
|
|
235
|
+
return hasKeyword(node, 'sealed') || hasModifier(node, 'modifier', 'sealed');
|
|
236
|
+
},
|
|
237
|
+
extractAnnotations: extractCSharpAnnotations,
|
|
238
|
+
isVirtual(node) {
|
|
239
|
+
return hasKeyword(node, 'virtual') || hasModifier(node, 'modifier', 'virtual');
|
|
240
|
+
},
|
|
241
|
+
isOverride(node) {
|
|
242
|
+
return hasKeyword(node, 'override') || hasModifier(node, 'modifier', 'override');
|
|
243
|
+
},
|
|
244
|
+
isAsync(node) {
|
|
245
|
+
return hasKeyword(node, 'async') || hasModifier(node, 'modifier', 'async');
|
|
246
|
+
},
|
|
247
|
+
isPartial(node) {
|
|
248
|
+
return hasKeyword(node, 'partial') || hasModifier(node, 'modifier', 'partial');
|
|
249
|
+
},
|
|
250
|
+
extractPrimaryConstructor(ownerNode, context) {
|
|
251
|
+
// C# 12 primary constructors: class Point(int x, int y) { }
|
|
252
|
+
// The parameter_list is a direct named child of class_declaration/record_declaration
|
|
253
|
+
// but has NO field name — it must be found by iterating named children.
|
|
254
|
+
let paramList = null;
|
|
255
|
+
for (let i = 0; i < ownerNode.namedChildCount; i++) {
|
|
256
|
+
const child = ownerNode.namedChild(i);
|
|
257
|
+
if (child?.type === 'parameter_list') {
|
|
258
|
+
paramList = child;
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (!paramList)
|
|
263
|
+
return null;
|
|
264
|
+
const name = ownerNode.childForFieldName('name')?.text;
|
|
265
|
+
if (!name)
|
|
266
|
+
return null;
|
|
267
|
+
const parameters = extractParametersFromList(paramList);
|
|
268
|
+
return {
|
|
269
|
+
name,
|
|
270
|
+
receiverType: null,
|
|
271
|
+
returnType: null,
|
|
272
|
+
parameters,
|
|
273
|
+
// Reuse the config's extractVisibility on the owner declaration node
|
|
274
|
+
visibility: csharpMethodConfig.extractVisibility(ownerNode),
|
|
275
|
+
isStatic: false,
|
|
276
|
+
isAbstract: false,
|
|
277
|
+
isFinal: false,
|
|
278
|
+
annotations: [], // C# has no syntax for attributes on primary constructors
|
|
279
|
+
sourceFile: context.filePath,
|
|
280
|
+
line: paramList.startPosition.row + 1,
|
|
281
|
+
};
|
|
282
|
+
},
|
|
283
|
+
};
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
// gitnexus/src/core/ingestion/method-extractors/configs/jvm.ts
|
|
2
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
3
|
+
import { findVisibility, hasModifier } from '../../field-extractors/configs/helpers.js';
|
|
4
|
+
import { extractSimpleTypeName } from '../../type-extractors/shared.js';
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Shared JVM helpers
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
const INTERFACE_OWNER_TYPES = new Set(['interface_declaration', 'annotation_type_declaration']);
|
|
9
|
+
function extractReturnTypeFromField(node) {
|
|
10
|
+
const typeNode = node.childForFieldName('type');
|
|
11
|
+
if (!typeNode)
|
|
12
|
+
return undefined;
|
|
13
|
+
return extractSimpleTypeName(typeNode) ?? typeNode.text?.trim();
|
|
14
|
+
}
|
|
15
|
+
function extractAnnotations(node, modifierType) {
|
|
16
|
+
const annotations = [];
|
|
17
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
18
|
+
const child = node.namedChild(i);
|
|
19
|
+
if (child && child.type === modifierType) {
|
|
20
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
21
|
+
const mod = child.namedChild(j);
|
|
22
|
+
if (mod && (mod.type === 'marker_annotation' || mod.type === 'annotation')) {
|
|
23
|
+
const nameNode = mod.childForFieldName('name') ?? mod.firstNamedChild;
|
|
24
|
+
if (nameNode)
|
|
25
|
+
annotations.push('@' + nameNode.text);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return annotations;
|
|
31
|
+
}
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Java
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
const JAVA_VIS = new Set(['public', 'private', 'protected']);
|
|
36
|
+
function extractJavaParameters(node) {
|
|
37
|
+
const params = [];
|
|
38
|
+
let paramList = node.childForFieldName('parameters');
|
|
39
|
+
// Compact constructors have no parameter list — inherit from parent record_declaration
|
|
40
|
+
if (!paramList && node.type === 'compact_constructor_declaration') {
|
|
41
|
+
const recordNode = node.parent?.parent; // compact_ctor → class_body → record_declaration
|
|
42
|
+
if (recordNode?.type === 'record_declaration') {
|
|
43
|
+
paramList = recordNode.childForFieldName('parameters');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (!paramList)
|
|
47
|
+
return params;
|
|
48
|
+
for (let i = 0; i < paramList.namedChildCount; i++) {
|
|
49
|
+
const param = paramList.namedChild(i);
|
|
50
|
+
if (!param)
|
|
51
|
+
continue;
|
|
52
|
+
if (param.type === 'formal_parameter') {
|
|
53
|
+
const nameNode = param.childForFieldName('name');
|
|
54
|
+
const typeNode = param.childForFieldName('type');
|
|
55
|
+
if (nameNode) {
|
|
56
|
+
params.push({
|
|
57
|
+
name: nameNode.text,
|
|
58
|
+
type: typeNode ? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim()) : null,
|
|
59
|
+
isOptional: false,
|
|
60
|
+
isVariadic: false,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else if (param.type === 'spread_parameter') {
|
|
65
|
+
// Varargs: type_identifier + "..." + variable_declarator
|
|
66
|
+
let paramName;
|
|
67
|
+
let paramType = null;
|
|
68
|
+
for (let j = 0; j < param.namedChildCount; j++) {
|
|
69
|
+
const c = param.namedChild(j);
|
|
70
|
+
if (!c)
|
|
71
|
+
continue;
|
|
72
|
+
if (c.type === 'variable_declarator') {
|
|
73
|
+
const nameChild = c.childForFieldName('name');
|
|
74
|
+
paramName = nameChild?.text ?? c.text;
|
|
75
|
+
}
|
|
76
|
+
else if (c.type === 'type_identifier' ||
|
|
77
|
+
c.type === 'generic_type' ||
|
|
78
|
+
c.type === 'scoped_type_identifier' ||
|
|
79
|
+
c.type === 'integral_type' ||
|
|
80
|
+
c.type === 'floating_point_type' ||
|
|
81
|
+
c.type === 'boolean_type') {
|
|
82
|
+
paramType = extractSimpleTypeName(c) ?? c.text?.trim();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (paramName) {
|
|
86
|
+
params.push({
|
|
87
|
+
name: paramName,
|
|
88
|
+
type: paramType,
|
|
89
|
+
isOptional: false,
|
|
90
|
+
isVariadic: true,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return params;
|
|
96
|
+
}
|
|
97
|
+
export const javaMethodConfig = {
|
|
98
|
+
language: SupportedLanguages.Java,
|
|
99
|
+
typeDeclarationNodes: [
|
|
100
|
+
'class_declaration',
|
|
101
|
+
'interface_declaration',
|
|
102
|
+
'enum_declaration',
|
|
103
|
+
'record_declaration',
|
|
104
|
+
'annotation_type_declaration',
|
|
105
|
+
],
|
|
106
|
+
methodNodeTypes: [
|
|
107
|
+
'method_declaration',
|
|
108
|
+
'constructor_declaration',
|
|
109
|
+
'compact_constructor_declaration',
|
|
110
|
+
'annotation_type_element_declaration',
|
|
111
|
+
],
|
|
112
|
+
bodyNodeTypes: [
|
|
113
|
+
'class_body',
|
|
114
|
+
'interface_body',
|
|
115
|
+
'enum_body',
|
|
116
|
+
'enum_body_declarations',
|
|
117
|
+
'annotation_type_body',
|
|
118
|
+
],
|
|
119
|
+
extractName(node) {
|
|
120
|
+
const nameNode = node.childForFieldName('name');
|
|
121
|
+
return nameNode?.text;
|
|
122
|
+
},
|
|
123
|
+
extractReturnType: extractReturnTypeFromField,
|
|
124
|
+
extractParameters: extractJavaParameters,
|
|
125
|
+
extractVisibility(node) {
|
|
126
|
+
return findVisibility(node, JAVA_VIS, 'package', 'modifiers');
|
|
127
|
+
},
|
|
128
|
+
isStatic(node) {
|
|
129
|
+
return hasModifier(node, 'modifiers', 'static');
|
|
130
|
+
},
|
|
131
|
+
isAbstract(node, ownerNode) {
|
|
132
|
+
if (hasModifier(node, 'modifiers', 'abstract'))
|
|
133
|
+
return true;
|
|
134
|
+
// Interface methods are implicitly abstract unless they have a body (default methods)
|
|
135
|
+
if (INTERFACE_OWNER_TYPES.has(ownerNode.type)) {
|
|
136
|
+
const body = node.childForFieldName('body');
|
|
137
|
+
return !body;
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
},
|
|
141
|
+
isFinal(node) {
|
|
142
|
+
return hasModifier(node, 'modifiers', 'final');
|
|
143
|
+
},
|
|
144
|
+
extractAnnotations(node) {
|
|
145
|
+
return extractAnnotations(node, 'modifiers');
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// Kotlin
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
const KOTLIN_VIS = new Set(['public', 'private', 'protected', 'internal']);
|
|
152
|
+
function extractKotlinParameters(node) {
|
|
153
|
+
const params = [];
|
|
154
|
+
// Kotlin: function_declaration > function_value_parameters > parameter
|
|
155
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
156
|
+
const child = node.namedChild(i);
|
|
157
|
+
if (child && child.type === 'function_value_parameters') {
|
|
158
|
+
let nextIsVariadic = false;
|
|
159
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
160
|
+
const param = child.namedChild(j);
|
|
161
|
+
if (!param)
|
|
162
|
+
continue;
|
|
163
|
+
// parameter_modifiers containing vararg precedes the parameter node
|
|
164
|
+
if (param.type === 'parameter_modifiers') {
|
|
165
|
+
for (let m = 0; m < param.namedChildCount; m++) {
|
|
166
|
+
const mod = param.namedChild(m);
|
|
167
|
+
if (mod && mod.text === 'vararg')
|
|
168
|
+
nextIsVariadic = true;
|
|
169
|
+
}
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (param.type !== 'parameter')
|
|
173
|
+
continue;
|
|
174
|
+
let paramName;
|
|
175
|
+
let paramType = null;
|
|
176
|
+
let hasDefault = false;
|
|
177
|
+
const isVariadic = nextIsVariadic;
|
|
178
|
+
nextIsVariadic = false;
|
|
179
|
+
for (let k = 0; k < param.namedChildCount; k++) {
|
|
180
|
+
const part = param.namedChild(k);
|
|
181
|
+
if (!part)
|
|
182
|
+
continue;
|
|
183
|
+
if (part.type === 'simple_identifier') {
|
|
184
|
+
paramName = part.text;
|
|
185
|
+
}
|
|
186
|
+
else if (part.type === 'user_type' ||
|
|
187
|
+
part.type === 'nullable_type' ||
|
|
188
|
+
part.type === 'function_type') {
|
|
189
|
+
paramType = extractSimpleTypeName(part) ?? part.text?.trim();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Check for default value: `= expr`
|
|
193
|
+
for (let k = 0; k < param.childCount; k++) {
|
|
194
|
+
const c = param.child(k);
|
|
195
|
+
if (c && c.text === '=') {
|
|
196
|
+
hasDefault = true;
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (paramName) {
|
|
201
|
+
params.push({
|
|
202
|
+
name: paramName,
|
|
203
|
+
type: paramType,
|
|
204
|
+
isOptional: hasDefault,
|
|
205
|
+
isVariadic: isVariadic,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return params;
|
|
213
|
+
}
|
|
214
|
+
function extractKotlinReturnType(node) {
|
|
215
|
+
// Kotlin: return type appears after `:` following the parameter list
|
|
216
|
+
// In tree-sitter-kotlin, it's a user_type/nullable_type child after function_value_parameters
|
|
217
|
+
let seenParams = false;
|
|
218
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
219
|
+
const child = node.namedChild(i);
|
|
220
|
+
if (!child)
|
|
221
|
+
continue;
|
|
222
|
+
if (child.type === 'function_value_parameters') {
|
|
223
|
+
seenParams = true;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (seenParams &&
|
|
227
|
+
(child.type === 'user_type' ||
|
|
228
|
+
child.type === 'nullable_type' ||
|
|
229
|
+
child.type === 'function_type')) {
|
|
230
|
+
return extractSimpleTypeName(child) ?? child.text?.trim();
|
|
231
|
+
}
|
|
232
|
+
if (child.type === 'function_body')
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
return undefined;
|
|
236
|
+
}
|
|
237
|
+
export const kotlinMethodConfig = {
|
|
238
|
+
language: SupportedLanguages.Kotlin,
|
|
239
|
+
typeDeclarationNodes: ['class_declaration', 'object_declaration', 'companion_object'],
|
|
240
|
+
methodNodeTypes: ['function_declaration'],
|
|
241
|
+
bodyNodeTypes: ['class_body'],
|
|
242
|
+
extractName(node) {
|
|
243
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
244
|
+
const child = node.namedChild(i);
|
|
245
|
+
if (child?.type === 'simple_identifier')
|
|
246
|
+
return child.text;
|
|
247
|
+
}
|
|
248
|
+
return undefined;
|
|
249
|
+
},
|
|
250
|
+
extractReturnType: extractKotlinReturnType,
|
|
251
|
+
extractParameters: extractKotlinParameters,
|
|
252
|
+
extractVisibility(node) {
|
|
253
|
+
return findVisibility(node, KOTLIN_VIS, 'public', 'modifiers');
|
|
254
|
+
},
|
|
255
|
+
isStatic(_node) {
|
|
256
|
+
// Kotlin has no static — companion object members are separate
|
|
257
|
+
return false;
|
|
258
|
+
},
|
|
259
|
+
isAbstract(node, ownerNode) {
|
|
260
|
+
if (hasModifier(node, 'modifiers', 'abstract'))
|
|
261
|
+
return true;
|
|
262
|
+
// Interface methods without a body are abstract
|
|
263
|
+
// Kotlin interfaces: class_declaration with "interface" keyword child
|
|
264
|
+
for (let i = 0; i < ownerNode.childCount; i++) {
|
|
265
|
+
const child = ownerNode.child(i);
|
|
266
|
+
if (child && child.text === 'interface') {
|
|
267
|
+
const body = node.childForFieldName('body');
|
|
268
|
+
// function_declaration > function_body
|
|
269
|
+
let hasBody = !!body;
|
|
270
|
+
if (!hasBody) {
|
|
271
|
+
for (let j = 0; j < node.namedChildCount; j++) {
|
|
272
|
+
const c = node.namedChild(j);
|
|
273
|
+
if (c && c.type === 'function_body') {
|
|
274
|
+
hasBody = true;
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return !hasBody;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return false;
|
|
283
|
+
},
|
|
284
|
+
isFinal(node) {
|
|
285
|
+
// Kotlin functions are closed (final) by default — only open/abstract/override makes them overridable
|
|
286
|
+
if (hasModifier(node, 'modifiers', 'open'))
|
|
287
|
+
return false;
|
|
288
|
+
if (hasModifier(node, 'modifiers', 'abstract'))
|
|
289
|
+
return false;
|
|
290
|
+
if (hasModifier(node, 'modifiers', 'override'))
|
|
291
|
+
return false;
|
|
292
|
+
return true;
|
|
293
|
+
},
|
|
294
|
+
extractAnnotations(node) {
|
|
295
|
+
const annotations = [];
|
|
296
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
297
|
+
const child = node.namedChild(i);
|
|
298
|
+
if (child && child.type === 'modifiers') {
|
|
299
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
300
|
+
const mod = child.namedChild(j);
|
|
301
|
+
if (mod && mod.type === 'annotation') {
|
|
302
|
+
// Kotlin annotation text includes the @ prefix
|
|
303
|
+
const text = mod.text.trim();
|
|
304
|
+
annotations.push(text.startsWith('@') ? text : '@' + text);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return annotations;
|
|
310
|
+
},
|
|
311
|
+
extractReceiverType(node) {
|
|
312
|
+
// Extension function: user_type appears before the simple_identifier (name)
|
|
313
|
+
// e.g., fun String.format(template: String) → receiver is "String"
|
|
314
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
315
|
+
const child = node.namedChild(i);
|
|
316
|
+
if (!child)
|
|
317
|
+
continue;
|
|
318
|
+
if (child.type === 'simple_identifier')
|
|
319
|
+
break; // past the name — no receiver
|
|
320
|
+
if (child.type === 'user_type' || child.type === 'nullable_type') {
|
|
321
|
+
return extractSimpleTypeName(child) ?? child.text?.trim();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return undefined;
|
|
325
|
+
},
|
|
326
|
+
};
|