gitnexus 1.4.9 → 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.
Files changed (186) hide show
  1. package/README.md +6 -5
  2. package/dist/cli/ai-context.d.ts +4 -1
  3. package/dist/cli/ai-context.js +19 -11
  4. package/dist/cli/analyze.d.ts +6 -0
  5. package/dist/cli/analyze.js +105 -251
  6. package/dist/cli/eval-server.js +20 -11
  7. package/dist/cli/index-repo.js +20 -22
  8. package/dist/cli/index.js +8 -7
  9. package/dist/cli/mcp.js +1 -1
  10. package/dist/cli/serve.js +29 -1
  11. package/dist/cli/setup.js +9 -9
  12. package/dist/cli/skill-gen.js +15 -9
  13. package/dist/cli/wiki.d.ts +2 -0
  14. package/dist/cli/wiki.js +141 -26
  15. package/dist/config/ignore-service.js +102 -22
  16. package/dist/config/supported-languages.d.ts +8 -42
  17. package/dist/config/supported-languages.js +8 -43
  18. package/dist/core/augmentation/engine.js +19 -7
  19. package/dist/core/embeddings/embedder.js +19 -15
  20. package/dist/core/embeddings/embedding-pipeline.js +6 -6
  21. package/dist/core/embeddings/http-client.js +3 -3
  22. package/dist/core/embeddings/text-generator.js +9 -24
  23. package/dist/core/embeddings/types.d.ts +1 -1
  24. package/dist/core/embeddings/types.js +1 -7
  25. package/dist/core/graph/graph.js +6 -2
  26. package/dist/core/graph/types.d.ts +9 -59
  27. package/dist/core/ingestion/ast-cache.js +3 -3
  28. package/dist/core/ingestion/call-processor.d.ts +20 -2
  29. package/dist/core/ingestion/call-processor.js +347 -144
  30. package/dist/core/ingestion/call-routing.js +10 -4
  31. package/dist/core/ingestion/call-sites/extract-language-call-site.d.ts +10 -0
  32. package/dist/core/ingestion/call-sites/extract-language-call-site.js +22 -0
  33. package/dist/core/ingestion/call-sites/java.d.ts +9 -0
  34. package/dist/core/ingestion/call-sites/java.js +30 -0
  35. package/dist/core/ingestion/cluster-enricher.js +6 -8
  36. package/dist/core/ingestion/cobol/cobol-copy-expander.js +10 -3
  37. package/dist/core/ingestion/cobol/cobol-preprocessor.js +287 -81
  38. package/dist/core/ingestion/cobol/jcl-parser.js +1 -1
  39. package/dist/core/ingestion/cobol/jcl-processor.js +1 -1
  40. package/dist/core/ingestion/cobol-processor.js +102 -56
  41. package/dist/core/ingestion/community-processor.js +21 -15
  42. package/dist/core/ingestion/entry-point-scoring.d.ts +1 -1
  43. package/dist/core/ingestion/entry-point-scoring.js +5 -6
  44. package/dist/core/ingestion/export-detection.js +32 -9
  45. package/dist/core/ingestion/field-extractor.d.ts +1 -1
  46. package/dist/core/ingestion/field-extractors/configs/c-cpp.js +8 -12
  47. package/dist/core/ingestion/field-extractors/configs/csharp.js +45 -2
  48. package/dist/core/ingestion/field-extractors/configs/dart.js +5 -3
  49. package/dist/core/ingestion/field-extractors/configs/go.js +3 -7
  50. package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +5 -0
  51. package/dist/core/ingestion/field-extractors/configs/helpers.js +14 -0
  52. package/dist/core/ingestion/field-extractors/configs/jvm.js +7 -7
  53. package/dist/core/ingestion/field-extractors/configs/php.js +9 -11
  54. package/dist/core/ingestion/field-extractors/configs/python.js +1 -1
  55. package/dist/core/ingestion/field-extractors/configs/ruby.js +4 -3
  56. package/dist/core/ingestion/field-extractors/configs/rust.js +2 -5
  57. package/dist/core/ingestion/field-extractors/configs/swift.js +9 -7
  58. package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +2 -6
  59. package/dist/core/ingestion/field-extractors/generic.d.ts +5 -2
  60. package/dist/core/ingestion/field-extractors/generic.js +6 -0
  61. package/dist/core/ingestion/field-extractors/typescript.d.ts +1 -1
  62. package/dist/core/ingestion/field-extractors/typescript.js +1 -1
  63. package/dist/core/ingestion/field-types.d.ts +4 -2
  64. package/dist/core/ingestion/filesystem-walker.js +3 -3
  65. package/dist/core/ingestion/framework-detection.d.ts +1 -1
  66. package/dist/core/ingestion/framework-detection.js +355 -85
  67. package/dist/core/ingestion/heritage-processor.d.ts +24 -0
  68. package/dist/core/ingestion/heritage-processor.js +99 -8
  69. package/dist/core/ingestion/import-processor.js +44 -15
  70. package/dist/core/ingestion/import-resolvers/csharp.js +7 -3
  71. package/dist/core/ingestion/import-resolvers/dart.js +1 -1
  72. package/dist/core/ingestion/import-resolvers/go.js +4 -2
  73. package/dist/core/ingestion/import-resolvers/jvm.js +4 -4
  74. package/dist/core/ingestion/import-resolvers/php.js +4 -4
  75. package/dist/core/ingestion/import-resolvers/python.js +1 -1
  76. package/dist/core/ingestion/import-resolvers/rust.js +9 -3
  77. package/dist/core/ingestion/import-resolvers/standard.d.ts +1 -1
  78. package/dist/core/ingestion/import-resolvers/standard.js +6 -5
  79. package/dist/core/ingestion/import-resolvers/swift.js +2 -1
  80. package/dist/core/ingestion/import-resolvers/utils.js +26 -7
  81. package/dist/core/ingestion/language-config.js +5 -4
  82. package/dist/core/ingestion/language-provider.d.ts +7 -2
  83. package/dist/core/ingestion/languages/c-cpp.js +106 -21
  84. package/dist/core/ingestion/languages/cobol.js +1 -1
  85. package/dist/core/ingestion/languages/csharp.js +96 -19
  86. package/dist/core/ingestion/languages/dart.js +23 -7
  87. package/dist/core/ingestion/languages/go.js +1 -1
  88. package/dist/core/ingestion/languages/index.d.ts +1 -1
  89. package/dist/core/ingestion/languages/index.js +2 -3
  90. package/dist/core/ingestion/languages/java.js +4 -1
  91. package/dist/core/ingestion/languages/kotlin.js +60 -13
  92. package/dist/core/ingestion/languages/php.js +102 -25
  93. package/dist/core/ingestion/languages/python.js +28 -5
  94. package/dist/core/ingestion/languages/ruby.js +56 -14
  95. package/dist/core/ingestion/languages/rust.js +55 -11
  96. package/dist/core/ingestion/languages/swift.js +112 -27
  97. package/dist/core/ingestion/languages/typescript.js +95 -19
  98. package/dist/core/ingestion/markdown-processor.js +5 -5
  99. package/dist/core/ingestion/method-extractors/configs/csharp.d.ts +2 -0
  100. package/dist/core/ingestion/method-extractors/configs/csharp.js +283 -0
  101. package/dist/core/ingestion/method-extractors/configs/jvm.d.ts +3 -0
  102. package/dist/core/ingestion/method-extractors/configs/jvm.js +326 -0
  103. package/dist/core/ingestion/method-extractors/generic.d.ts +5 -0
  104. package/dist/core/ingestion/method-extractors/generic.js +137 -0
  105. package/dist/core/ingestion/method-types.d.ts +61 -0
  106. package/dist/core/ingestion/method-types.js +2 -0
  107. package/dist/core/ingestion/mro-processor.d.ts +1 -1
  108. package/dist/core/ingestion/mro-processor.js +12 -8
  109. package/dist/core/ingestion/named-binding-processor.js +2 -2
  110. package/dist/core/ingestion/named-bindings/rust.js +3 -1
  111. package/dist/core/ingestion/parsing-processor.js +74 -24
  112. package/dist/core/ingestion/pipeline.d.ts +2 -1
  113. package/dist/core/ingestion/pipeline.js +208 -102
  114. package/dist/core/ingestion/process-processor.js +12 -10
  115. package/dist/core/ingestion/resolution-context.js +3 -3
  116. package/dist/core/ingestion/route-extractors/middleware.js +31 -7
  117. package/dist/core/ingestion/route-extractors/php.js +2 -1
  118. package/dist/core/ingestion/route-extractors/response-shapes.js +8 -4
  119. package/dist/core/ingestion/structure-processor.d.ts +1 -1
  120. package/dist/core/ingestion/structure-processor.js +4 -4
  121. package/dist/core/ingestion/symbol-table.d.ts +1 -1
  122. package/dist/core/ingestion/symbol-table.js +22 -6
  123. package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
  124. package/dist/core/ingestion/tree-sitter-queries.js +1 -1
  125. package/dist/core/ingestion/type-env.d.ts +2 -2
  126. package/dist/core/ingestion/type-env.js +75 -50
  127. package/dist/core/ingestion/type-extractors/c-cpp.js +33 -30
  128. package/dist/core/ingestion/type-extractors/csharp.js +24 -14
  129. package/dist/core/ingestion/type-extractors/dart.js +6 -8
  130. package/dist/core/ingestion/type-extractors/go.js +7 -6
  131. package/dist/core/ingestion/type-extractors/jvm.js +10 -21
  132. package/dist/core/ingestion/type-extractors/php.js +26 -13
  133. package/dist/core/ingestion/type-extractors/python.js +11 -15
  134. package/dist/core/ingestion/type-extractors/ruby.js +8 -3
  135. package/dist/core/ingestion/type-extractors/rust.js +6 -8
  136. package/dist/core/ingestion/type-extractors/shared.js +134 -50
  137. package/dist/core/ingestion/type-extractors/swift.js +16 -13
  138. package/dist/core/ingestion/type-extractors/typescript.js +23 -15
  139. package/dist/core/ingestion/utils/ast-helpers.d.ts +8 -8
  140. package/dist/core/ingestion/utils/ast-helpers.js +72 -35
  141. package/dist/core/ingestion/utils/call-analysis.d.ts +2 -0
  142. package/dist/core/ingestion/utils/call-analysis.js +96 -49
  143. package/dist/core/ingestion/utils/event-loop.js +1 -1
  144. package/dist/core/ingestion/workers/parse-worker.d.ts +7 -2
  145. package/dist/core/ingestion/workers/parse-worker.js +364 -84
  146. package/dist/core/ingestion/workers/worker-pool.js +5 -10
  147. package/dist/core/lbug/csv-generator.js +54 -15
  148. package/dist/core/lbug/lbug-adapter.d.ts +5 -0
  149. package/dist/core/lbug/lbug-adapter.js +86 -23
  150. package/dist/core/lbug/schema.d.ts +3 -6
  151. package/dist/core/lbug/schema.js +6 -30
  152. package/dist/core/run-analyze.d.ts +49 -0
  153. package/dist/core/run-analyze.js +257 -0
  154. package/dist/core/tree-sitter/parser-loader.d.ts +1 -1
  155. package/dist/core/tree-sitter/parser-loader.js +1 -1
  156. package/dist/core/wiki/cursor-client.js +2 -7
  157. package/dist/core/wiki/generator.js +38 -23
  158. package/dist/core/wiki/graph-queries.js +10 -10
  159. package/dist/core/wiki/html-viewer.js +7 -3
  160. package/dist/core/wiki/llm-client.d.ts +23 -2
  161. package/dist/core/wiki/llm-client.js +96 -26
  162. package/dist/core/wiki/prompts.js +7 -6
  163. package/dist/mcp/core/embedder.js +1 -1
  164. package/dist/mcp/core/lbug-adapter.d.ts +4 -1
  165. package/dist/mcp/core/lbug-adapter.js +17 -7
  166. package/dist/mcp/local/local-backend.js +247 -95
  167. package/dist/mcp/resources.js +14 -6
  168. package/dist/mcp/server.js +13 -5
  169. package/dist/mcp/staleness.js +5 -1
  170. package/dist/mcp/tools.js +100 -23
  171. package/dist/server/analyze-job.d.ts +53 -0
  172. package/dist/server/analyze-job.js +146 -0
  173. package/dist/server/analyze-worker.d.ts +13 -0
  174. package/dist/server/analyze-worker.js +59 -0
  175. package/dist/server/api.js +795 -44
  176. package/dist/server/git-clone.d.ts +25 -0
  177. package/dist/server/git-clone.js +91 -0
  178. package/dist/storage/git.js +1 -3
  179. package/dist/storage/repo-manager.d.ts +5 -2
  180. package/dist/storage/repo-manager.js +4 -4
  181. package/dist/types/pipeline.d.ts +1 -21
  182. package/dist/types/pipeline.js +1 -18
  183. package/hooks/claude/gitnexus-hook.cjs +52 -22
  184. package/package.json +13 -13
  185. package/dist/core/ingestion/utils/language-detection.d.ts +0 -9
  186. 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,3 @@
1
+ import type { MethodExtractionConfig } from '../../method-types.js';
2
+ export declare const javaMethodConfig: MethodExtractionConfig;
3
+ export declare const kotlinMethodConfig: MethodExtractionConfig;
@@ -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
+ };
@@ -0,0 +1,5 @@
1
+ import type { MethodExtractor, MethodExtractionConfig } from '../method-types.js';
2
+ /**
3
+ * Create a MethodExtractor from a declarative config.
4
+ */
5
+ export declare function createMethodExtractor(config: MethodExtractionConfig): MethodExtractor;