gitnexus 1.5.2 → 1.6.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 (207) hide show
  1. package/README.md +10 -0
  2. package/dist/_shared/graph/types.d.ts +1 -1
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/index.d.ts +1 -0
  5. package/dist/_shared/index.d.ts.map +1 -1
  6. package/dist/_shared/language-detection.d.ts.map +1 -1
  7. package/dist/_shared/language-detection.js +2 -0
  8. package/dist/_shared/language-detection.js.map +1 -1
  9. package/dist/_shared/languages.d.ts +1 -0
  10. package/dist/_shared/languages.d.ts.map +1 -1
  11. package/dist/_shared/languages.js +1 -0
  12. package/dist/_shared/languages.js.map +1 -1
  13. package/dist/_shared/lbug/schema-constants.d.ts +1 -1
  14. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  15. package/dist/_shared/lbug/schema-constants.js +3 -1
  16. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  17. package/dist/_shared/mro-strategy.d.ts +19 -0
  18. package/dist/_shared/mro-strategy.d.ts.map +1 -0
  19. package/dist/_shared/mro-strategy.js +2 -0
  20. package/dist/_shared/mro-strategy.js.map +1 -0
  21. package/dist/cli/ai-context.d.ts +1 -0
  22. package/dist/cli/ai-context.js +28 -4
  23. package/dist/cli/analyze.d.ts +2 -0
  24. package/dist/cli/analyze.js +2 -1
  25. package/dist/cli/group.d.ts +2 -0
  26. package/dist/cli/group.js +233 -0
  27. package/dist/cli/index.js +3 -0
  28. package/dist/cli/serve.js +4 -1
  29. package/dist/cli/setup.js +34 -3
  30. package/dist/cli/wiki.js +15 -44
  31. package/dist/config/ignore-service.js +8 -3
  32. package/dist/core/augmentation/engine.js +1 -1
  33. package/dist/core/git-staleness.d.ts +13 -0
  34. package/dist/core/git-staleness.js +29 -0
  35. package/dist/core/group/bridge-db.d.ts +82 -0
  36. package/dist/core/group/bridge-db.js +460 -0
  37. package/dist/core/group/bridge-schema.d.ts +27 -0
  38. package/dist/core/group/bridge-schema.js +55 -0
  39. package/dist/core/group/config-parser.d.ts +3 -0
  40. package/dist/core/group/config-parser.js +83 -0
  41. package/dist/core/group/contract-extractor.d.ts +7 -0
  42. package/dist/core/group/contract-extractor.js +1 -0
  43. package/dist/core/group/extractors/grpc-extractor.d.ts +16 -0
  44. package/dist/core/group/extractors/grpc-extractor.js +264 -0
  45. package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
  46. package/dist/core/group/extractors/http-route-extractor.js +428 -0
  47. package/dist/core/group/extractors/topic-extractor.d.ts +9 -0
  48. package/dist/core/group/extractors/topic-extractor.js +234 -0
  49. package/dist/core/group/matching.d.ts +13 -0
  50. package/dist/core/group/matching.js +198 -0
  51. package/dist/core/group/normalization.d.ts +3 -0
  52. package/dist/core/group/normalization.js +115 -0
  53. package/dist/core/group/service-boundary-detector.d.ts +8 -0
  54. package/dist/core/group/service-boundary-detector.js +155 -0
  55. package/dist/core/group/service.d.ts +46 -0
  56. package/dist/core/group/service.js +160 -0
  57. package/dist/core/group/storage.d.ts +9 -0
  58. package/dist/core/group/storage.js +91 -0
  59. package/dist/core/group/sync.d.ts +21 -0
  60. package/dist/core/group/sync.js +148 -0
  61. package/dist/core/group/types.d.ts +130 -0
  62. package/dist/core/group/types.js +1 -0
  63. package/dist/core/ingestion/binding-accumulator.d.ts +207 -0
  64. package/dist/core/ingestion/binding-accumulator.js +332 -0
  65. package/dist/core/ingestion/call-processor.d.ts +155 -24
  66. package/dist/core/ingestion/call-processor.js +1129 -247
  67. package/dist/core/ingestion/class-extractors/generic.d.ts +2 -0
  68. package/dist/core/ingestion/class-extractors/generic.js +135 -0
  69. package/dist/core/ingestion/class-types.d.ts +34 -0
  70. package/dist/core/ingestion/class-types.js +1 -0
  71. package/dist/core/ingestion/entry-point-scoring.d.ts +1 -0
  72. package/dist/core/ingestion/entry-point-scoring.js +1 -0
  73. package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +5 -1
  74. package/dist/core/ingestion/field-extractors/configs/helpers.js +13 -3
  75. package/dist/core/ingestion/field-types.d.ts +2 -2
  76. package/dist/core/ingestion/filesystem-walker.js +8 -0
  77. package/dist/core/ingestion/framework-detection.d.ts +1 -0
  78. package/dist/core/ingestion/framework-detection.js +1 -0
  79. package/dist/core/ingestion/heritage-processor.d.ts +8 -15
  80. package/dist/core/ingestion/heritage-processor.js +15 -28
  81. package/dist/core/ingestion/import-processor.d.ts +1 -11
  82. package/dist/core/ingestion/import-processor.js +0 -12
  83. package/dist/core/ingestion/import-resolvers/utils.js +1 -0
  84. package/dist/core/ingestion/import-resolvers/vue.d.ts +8 -0
  85. package/dist/core/ingestion/import-resolvers/vue.js +9 -0
  86. package/dist/core/ingestion/language-provider.d.ts +6 -3
  87. package/dist/core/ingestion/languages/c-cpp.js +168 -1
  88. package/dist/core/ingestion/languages/csharp.js +20 -0
  89. package/dist/core/ingestion/languages/dart.js +26 -4
  90. package/dist/core/ingestion/languages/go.js +22 -0
  91. package/dist/core/ingestion/languages/index.d.ts +1 -0
  92. package/dist/core/ingestion/languages/index.js +2 -0
  93. package/dist/core/ingestion/languages/java.js +17 -0
  94. package/dist/core/ingestion/languages/kotlin.js +24 -1
  95. package/dist/core/ingestion/languages/php.js +23 -11
  96. package/dist/core/ingestion/languages/python.js +9 -0
  97. package/dist/core/ingestion/languages/ruby.js +28 -0
  98. package/dist/core/ingestion/languages/rust.js +38 -0
  99. package/dist/core/ingestion/languages/swift.js +31 -0
  100. package/dist/core/ingestion/languages/typescript.d.ts +1 -0
  101. package/dist/core/ingestion/languages/typescript.js +54 -1
  102. package/dist/core/ingestion/languages/vue.d.ts +13 -0
  103. package/dist/core/ingestion/languages/vue.js +81 -0
  104. package/dist/core/ingestion/method-extractors/configs/c-cpp.d.ts +3 -0
  105. package/dist/core/ingestion/method-extractors/configs/c-cpp.js +387 -0
  106. package/dist/core/ingestion/method-extractors/configs/csharp.js +5 -1
  107. package/dist/core/ingestion/method-extractors/configs/dart.d.ts +2 -0
  108. package/dist/core/ingestion/method-extractors/configs/dart.js +376 -0
  109. package/dist/core/ingestion/method-extractors/configs/go.d.ts +2 -0
  110. package/dist/core/ingestion/method-extractors/configs/go.js +176 -0
  111. package/dist/core/ingestion/method-extractors/configs/jvm.js +13 -4
  112. package/dist/core/ingestion/method-extractors/configs/php.d.ts +2 -0
  113. package/dist/core/ingestion/method-extractors/configs/php.js +304 -0
  114. package/dist/core/ingestion/method-extractors/configs/python.d.ts +2 -0
  115. package/dist/core/ingestion/method-extractors/configs/python.js +309 -0
  116. package/dist/core/ingestion/method-extractors/configs/ruby.d.ts +2 -0
  117. package/dist/core/ingestion/method-extractors/configs/ruby.js +285 -0
  118. package/dist/core/ingestion/method-extractors/configs/rust.d.ts +2 -0
  119. package/dist/core/ingestion/method-extractors/configs/rust.js +195 -0
  120. package/dist/core/ingestion/method-extractors/configs/swift.d.ts +2 -0
  121. package/dist/core/ingestion/method-extractors/configs/swift.js +277 -0
  122. package/dist/core/ingestion/method-extractors/configs/typescript-javascript.d.ts +3 -0
  123. package/dist/core/ingestion/method-extractors/configs/typescript-javascript.js +338 -0
  124. package/dist/core/ingestion/method-extractors/generic.js +38 -15
  125. package/dist/core/ingestion/method-types.d.ts +25 -0
  126. package/dist/core/ingestion/model/field-registry.d.ts +18 -0
  127. package/dist/core/ingestion/model/field-registry.js +22 -0
  128. package/dist/core/ingestion/model/heritage-map.d.ts +70 -0
  129. package/dist/core/ingestion/model/heritage-map.js +159 -0
  130. package/dist/core/ingestion/model/index.d.ts +20 -0
  131. package/dist/core/ingestion/model/index.js +41 -0
  132. package/dist/core/ingestion/model/method-registry.d.ts +62 -0
  133. package/dist/core/ingestion/model/method-registry.js +130 -0
  134. package/dist/core/ingestion/model/registration-table.d.ts +139 -0
  135. package/dist/core/ingestion/model/registration-table.js +224 -0
  136. package/dist/core/ingestion/model/resolution-context.d.ts +93 -0
  137. package/dist/core/ingestion/model/resolution-context.js +337 -0
  138. package/dist/core/ingestion/model/resolve.d.ts +56 -0
  139. package/dist/core/ingestion/model/resolve.js +242 -0
  140. package/dist/core/ingestion/model/semantic-model.d.ts +86 -0
  141. package/dist/core/ingestion/model/semantic-model.js +120 -0
  142. package/dist/core/ingestion/model/symbol-table.d.ts +222 -0
  143. package/dist/core/ingestion/model/symbol-table.js +206 -0
  144. package/dist/core/ingestion/model/type-registry.d.ts +39 -0
  145. package/dist/core/ingestion/model/type-registry.js +62 -0
  146. package/dist/core/ingestion/mro-processor.d.ts +4 -3
  147. package/dist/core/ingestion/mro-processor.js +310 -106
  148. package/dist/core/ingestion/parsing-processor.d.ts +5 -4
  149. package/dist/core/ingestion/parsing-processor.js +210 -85
  150. package/dist/core/ingestion/pipeline.d.ts +2 -0
  151. package/dist/core/ingestion/pipeline.js +192 -68
  152. package/dist/core/ingestion/tree-sitter-queries.d.ts +6 -6
  153. package/dist/core/ingestion/tree-sitter-queries.js +37 -0
  154. package/dist/core/ingestion/type-env.d.ts +15 -2
  155. package/dist/core/ingestion/type-env.js +163 -102
  156. package/dist/core/ingestion/type-extractors/csharp.js +17 -0
  157. package/dist/core/ingestion/type-extractors/jvm.js +11 -0
  158. package/dist/core/ingestion/type-extractors/php.js +0 -55
  159. package/dist/core/ingestion/type-extractors/ruby.js +0 -32
  160. package/dist/core/ingestion/type-extractors/swift.js +13 -0
  161. package/dist/core/ingestion/type-extractors/types.d.ts +8 -8
  162. package/dist/core/ingestion/type-extractors/typescript.js +66 -69
  163. package/dist/core/ingestion/utils/ast-helpers.d.ts +33 -43
  164. package/dist/core/ingestion/utils/ast-helpers.js +129 -565
  165. package/dist/core/ingestion/utils/method-props.d.ts +32 -0
  166. package/dist/core/ingestion/utils/method-props.js +147 -0
  167. package/dist/core/ingestion/vue-sfc-extractor.d.ts +44 -0
  168. package/dist/core/ingestion/vue-sfc-extractor.js +94 -0
  169. package/dist/core/ingestion/workers/parse-worker.d.ts +31 -19
  170. package/dist/core/ingestion/workers/parse-worker.js +463 -198
  171. package/dist/core/lbug/lbug-adapter.d.ts +6 -0
  172. package/dist/core/lbug/lbug-adapter.js +68 -3
  173. package/dist/core/lbug/pool-adapter.d.ts +76 -0
  174. package/dist/core/lbug/pool-adapter.js +522 -0
  175. package/dist/core/run-analyze.d.ts +2 -0
  176. package/dist/core/run-analyze.js +1 -1
  177. package/dist/core/search/bm25-index.js +1 -1
  178. package/dist/core/tree-sitter/parser-loader.js +1 -0
  179. package/dist/core/wiki/graph-queries.js +1 -1
  180. package/dist/core/wiki/html-viewer.js +6 -4
  181. package/dist/core/wiki/llm-client.js +4 -6
  182. package/dist/mcp/core/embedder.js +6 -5
  183. package/dist/mcp/core/lbug-adapter.d.ts +3 -63
  184. package/dist/mcp/core/lbug-adapter.js +3 -484
  185. package/dist/mcp/local/local-backend.d.ts +31 -2
  186. package/dist/mcp/local/local-backend.js +255 -46
  187. package/dist/mcp/resources.js +5 -4
  188. package/dist/mcp/staleness.d.ts +3 -13
  189. package/dist/mcp/staleness.js +2 -31
  190. package/dist/mcp/tools.js +80 -4
  191. package/dist/server/analyze-job.d.ts +2 -0
  192. package/dist/server/analyze-job.js +4 -0
  193. package/dist/server/api.d.ts +20 -1
  194. package/dist/server/api.js +306 -71
  195. package/dist/server/git-clone.d.ts +2 -1
  196. package/dist/server/git-clone.js +98 -5
  197. package/dist/storage/git.d.ts +13 -0
  198. package/dist/storage/git.js +25 -0
  199. package/dist/storage/repo-manager.js +1 -1
  200. package/package.json +8 -2
  201. package/scripts/patch-tree-sitter-swift.cjs +78 -0
  202. package/dist/core/ingestion/named-binding-processor.d.ts +0 -18
  203. package/dist/core/ingestion/named-binding-processor.js +0 -42
  204. package/dist/core/ingestion/resolution-context.d.ts +0 -58
  205. package/dist/core/ingestion/resolution-context.js +0 -135
  206. package/dist/core/ingestion/symbol-table.d.ts +0 -79
  207. package/dist/core/ingestion/symbol-table.js +0 -115
@@ -0,0 +1,285 @@
1
+ // gitnexus/src/core/ingestion/method-extractors/configs/ruby.ts
2
+ // Verified against tree-sitter-ruby 0.23.1
3
+ import { SupportedLanguages } from '../../../../_shared/index.js';
4
+ // ---------------------------------------------------------------------------
5
+ // Ruby helpers
6
+ // ---------------------------------------------------------------------------
7
+ const VISIBILITY_MODIFIERS = new Set(['private', 'protected', 'public']);
8
+ /** Regex to extract YARD `@return [Type]` annotations from comments. */
9
+ const YARD_RETURN_RE = /@return\s+\[([^\]]+)\]/;
10
+ /**
11
+ * Extract the simple type name from a YARD type string.
12
+ * Handles qualified types ("Models::User" -> "User"), generics ("Array<User>"
13
+ * -> "Array"), nullable ("String, nil" -> "String"), and rejects ambiguous
14
+ * unions ("String, Integer" -> undefined).
15
+ */
16
+ function extractYardTypeName(yardType) {
17
+ const trimmed = yardType.trim();
18
+ // Bracket-balanced split on commas to handle generics like Hash<Symbol, User>
19
+ const parts = [];
20
+ let depth = 0, start = 0;
21
+ for (let i = 0; i < trimmed.length; i++) {
22
+ if (trimmed[i] === '<')
23
+ depth++;
24
+ else if (trimmed[i] === '>')
25
+ depth--;
26
+ else if (trimmed[i] === ',' && depth === 0) {
27
+ parts.push(trimmed.slice(start, i).trim());
28
+ start = i + 1;
29
+ }
30
+ }
31
+ parts.push(trimmed.slice(start).trim());
32
+ const filtered = parts.filter((p) => p !== '' && p !== 'nil');
33
+ if (filtered.length !== 1)
34
+ return undefined; // ambiguous union
35
+ const typePart = filtered[0];
36
+ // Qualified: "Models::User" -> "User"
37
+ const segments = typePart.split('::');
38
+ const last = segments[segments.length - 1];
39
+ // Generic: "Array<User>" -> "Array"
40
+ const genericMatch = last.match(/^(\w+)\s*[<{(]/);
41
+ if (genericMatch)
42
+ return genericMatch[1];
43
+ // Simple identifier
44
+ if (/^\w+$/.test(last))
45
+ return last;
46
+ return undefined;
47
+ }
48
+ /**
49
+ * Extract visibility for a Ruby method by walking backwards through the
50
+ * parent body_statement's named children from the method node's position.
51
+ *
52
+ * Ruby visibility modifiers (private, protected, public) appear as bare
53
+ * `identifier` nodes in the body_statement. The most recent modifier
54
+ * before the method determines its visibility. Default is public.
55
+ *
56
+ * Example AST for:
57
+ * class Foo
58
+ * private
59
+ * def secret; end
60
+ * end
61
+ *
62
+ * body_statement
63
+ * identifier "private" ← index 0
64
+ * method "def secret" ← index 1
65
+ */
66
+ function extractRubyVisibility(node) {
67
+ const parent = node.parent;
68
+ if (!parent)
69
+ return 'public';
70
+ // Find the index of this method node in the parent's named children
71
+ let methodIndex = -1;
72
+ for (let i = 0; i < parent.namedChildCount; i++) {
73
+ if (parent.namedChild(i) === node) {
74
+ methodIndex = i;
75
+ break;
76
+ }
77
+ }
78
+ if (methodIndex < 0)
79
+ return 'public';
80
+ // Walk backwards from the method node looking for a visibility modifier
81
+ for (let i = methodIndex - 1; i >= 0; i--) {
82
+ const sibling = parent.namedChild(i);
83
+ if (!sibling)
84
+ continue;
85
+ if (sibling.type === 'identifier' && VISIBILITY_MODIFIERS.has(sibling.text)) {
86
+ return sibling.text;
87
+ }
88
+ // module_function makes instance methods private
89
+ if (sibling.type === 'identifier' && sibling.text === 'module_function') {
90
+ return 'private';
91
+ }
92
+ }
93
+ return 'public';
94
+ }
95
+ /**
96
+ * Extract parameters from a Ruby method's method_parameters node.
97
+ *
98
+ * Handles: identifier, optional_parameter (default), splat_parameter (*args),
99
+ * hash_splat_parameter (**kwargs), block_parameter (&block), keyword_parameter.
100
+ */
101
+ function extractRubyParameters(node) {
102
+ const paramList = node.childForFieldName('parameters');
103
+ if (!paramList)
104
+ return [];
105
+ const params = [];
106
+ for (let i = 0; i < paramList.namedChildCount; i++) {
107
+ const param = paramList.namedChild(i);
108
+ if (!param)
109
+ continue;
110
+ switch (param.type) {
111
+ case 'identifier': {
112
+ // Plain parameter: def foo(x)
113
+ params.push({
114
+ name: param.text,
115
+ type: null,
116
+ rawType: null,
117
+ isOptional: false,
118
+ isVariadic: false,
119
+ });
120
+ break;
121
+ }
122
+ case 'optional_parameter': {
123
+ // Default parameter: def foo(x = 10)
124
+ const nameNode = param.childForFieldName('name');
125
+ if (nameNode) {
126
+ params.push({
127
+ name: nameNode.text,
128
+ type: null,
129
+ rawType: null,
130
+ isOptional: true,
131
+ isVariadic: false,
132
+ });
133
+ }
134
+ break;
135
+ }
136
+ case 'splat_parameter': {
137
+ // Splat: def foo(*args)
138
+ const nameNode = param.childForFieldName('name');
139
+ if (nameNode) {
140
+ params.push({
141
+ name: nameNode.text,
142
+ type: null,
143
+ rawType: null,
144
+ isOptional: false,
145
+ isVariadic: true,
146
+ });
147
+ }
148
+ break;
149
+ }
150
+ case 'hash_splat_parameter': {
151
+ // Double splat: def foo(**kwargs)
152
+ const nameNode = param.childForFieldName('name');
153
+ if (nameNode) {
154
+ params.push({
155
+ name: nameNode.text,
156
+ type: null,
157
+ rawType: null,
158
+ isOptional: false,
159
+ isVariadic: true,
160
+ });
161
+ }
162
+ break;
163
+ }
164
+ case 'block_parameter': {
165
+ // Block: def foo(&block)
166
+ const nameNode = param.childForFieldName('name');
167
+ if (nameNode) {
168
+ params.push({
169
+ name: nameNode.text,
170
+ type: null,
171
+ rawType: null,
172
+ isOptional: false,
173
+ isVariadic: false,
174
+ });
175
+ }
176
+ break;
177
+ }
178
+ case 'keyword_parameter': {
179
+ // Keyword: def foo(name:) or def foo(name: "default")
180
+ const nameNode = param.childForFieldName('name');
181
+ const valueNode = param.childForFieldName('value');
182
+ if (nameNode) {
183
+ params.push({
184
+ name: nameNode.text,
185
+ type: null,
186
+ rawType: null,
187
+ isOptional: !!valueNode,
188
+ isVariadic: false,
189
+ });
190
+ }
191
+ break;
192
+ }
193
+ }
194
+ }
195
+ return params;
196
+ }
197
+ // ---------------------------------------------------------------------------
198
+ // Config
199
+ // ---------------------------------------------------------------------------
200
+ export const rubyMethodConfig = {
201
+ language: SupportedLanguages.Ruby,
202
+ typeDeclarationNodes: ['class', 'module', 'singleton_class'],
203
+ methodNodeTypes: ['method', 'singleton_method'],
204
+ bodyNodeTypes: ['body_statement'],
205
+ extractOwnerName(node) {
206
+ // singleton_class (class << self) inherits the enclosing class/module name
207
+ if (node.type === 'singleton_class') {
208
+ let ancestor = node.parent;
209
+ while (ancestor) {
210
+ if (ancestor.type === 'class' || ancestor.type === 'module') {
211
+ const nameNode = ancestor.childForFieldName('name');
212
+ return nameNode?.text;
213
+ }
214
+ ancestor = ancestor.parent;
215
+ }
216
+ return undefined;
217
+ }
218
+ return undefined; // use default resolution for class/module
219
+ },
220
+ extractName(node) {
221
+ const nameNode = node.childForFieldName('name');
222
+ return nameNode?.text;
223
+ },
224
+ extractReturnType(node) {
225
+ // Walk backwards through preceding siblings looking for YARD @return [Type].
226
+ // Try direct siblings first, then fall back to parent (body_statement) siblings
227
+ // for class methods where the comment may be a sibling of the body_statement.
228
+ const search = (startNode) => {
229
+ let sibling = startNode.previousSibling;
230
+ while (sibling) {
231
+ if (sibling.type === 'comment') {
232
+ const match = YARD_RETURN_RE.exec(sibling.text);
233
+ if (match)
234
+ return extractYardTypeName(match[1]);
235
+ }
236
+ else if (sibling.isNamed) {
237
+ break;
238
+ }
239
+ sibling = sibling.previousSibling;
240
+ }
241
+ return undefined;
242
+ };
243
+ const result = search(node);
244
+ if (result)
245
+ return result;
246
+ if (node.parent?.type === 'body_statement') {
247
+ return search(node.parent);
248
+ }
249
+ return undefined;
250
+ },
251
+ extractParameters: extractRubyParameters,
252
+ extractVisibility: extractRubyVisibility,
253
+ isStatic(node) {
254
+ if (node.type === 'singleton_method')
255
+ return true;
256
+ // module_function makes following methods callable at module level (static)
257
+ const parent = node.parent;
258
+ if (!parent)
259
+ return false;
260
+ let methodIndex = -1;
261
+ for (let i = 0; i < parent.namedChildCount; i++) {
262
+ if (parent.namedChild(i) === node) {
263
+ methodIndex = i;
264
+ break;
265
+ }
266
+ }
267
+ for (let i = methodIndex - 1; i >= 0; i--) {
268
+ const sibling = parent.namedChild(i);
269
+ if (!sibling)
270
+ continue;
271
+ if (sibling.type === 'identifier' && sibling.text === 'module_function')
272
+ return true;
273
+ // Other visibility modifiers override module_function
274
+ if (sibling.type === 'identifier' && VISIBILITY_MODIFIERS.has(sibling.text))
275
+ return false;
276
+ }
277
+ return false;
278
+ },
279
+ isAbstract(_node, _ownerNode) {
280
+ return false; // Ruby has no abstract methods
281
+ },
282
+ isFinal(_node) {
283
+ return false; // Ruby has no final methods
284
+ },
285
+ };
@@ -0,0 +1,2 @@
1
+ import type { MethodExtractionConfig } from '../../method-types.js';
2
+ export declare const rustMethodConfig: MethodExtractionConfig;
@@ -0,0 +1,195 @@
1
+ // gitnexus/src/core/ingestion/method-extractors/configs/rust.ts
2
+ // Verified against tree-sitter-rust 0.23.1
3
+ import { SupportedLanguages } from '../../../../_shared/index.js';
4
+ import { extractSimpleTypeName } from '../../type-extractors/shared.js';
5
+ // ---------------------------------------------------------------------------
6
+ // Rust helpers
7
+ // ---------------------------------------------------------------------------
8
+ /**
9
+ * Extract method name from function_item or function_signature_item.
10
+ * Both use a `name` field containing an identifier.
11
+ */
12
+ function extractRustMethodName(node) {
13
+ const nameNode = node.childForFieldName('name');
14
+ return nameNode?.text;
15
+ }
16
+ /**
17
+ * Extract return type from the `return_type` field.
18
+ * tree-sitter-rust puts the return type (after `->`) as the `return_type` field.
19
+ */
20
+ function extractRustReturnType(node) {
21
+ const typeNode = node.childForFieldName('return_type');
22
+ if (!typeNode)
23
+ return undefined;
24
+ return typeNode.text?.trim();
25
+ }
26
+ /**
27
+ * Extract parameters, skipping the self_parameter (handled by extractReceiverType).
28
+ *
29
+ * Rust parameters use `pattern` and `type` fields:
30
+ * parameter { pattern: identifier, type: primitive_type }
31
+ */
32
+ function extractRustParameters(node) {
33
+ const paramList = node.childForFieldName('parameters');
34
+ if (!paramList)
35
+ return [];
36
+ const params = [];
37
+ for (let i = 0; i < paramList.namedChildCount; i++) {
38
+ const param = paramList.namedChild(i);
39
+ if (!param)
40
+ continue;
41
+ // Skip self_parameter — it is the receiver, not a regular parameter
42
+ if (param.type === 'self_parameter')
43
+ continue;
44
+ if (param.type === 'parameter') {
45
+ const patternNode = param.childForFieldName('pattern');
46
+ const typeNode = param.childForFieldName('type');
47
+ params.push({
48
+ name: patternNode?.text ?? '?',
49
+ type: typeNode ? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim() ?? null) : null,
50
+ rawType: typeNode?.text?.trim() ?? null,
51
+ isOptional: false,
52
+ isVariadic: false,
53
+ });
54
+ }
55
+ }
56
+ return params;
57
+ }
58
+ /**
59
+ * Detect visibility from visibility_modifier named child.
60
+ * `pub`, `pub(crate)`, `pub(super)`, `pub(in path)` → public.
61
+ * Absence → private (Rust default).
62
+ */
63
+ function extractRustVisibility(node) {
64
+ for (let i = 0; i < node.namedChildCount; i++) {
65
+ const child = node.namedChild(i);
66
+ if (child?.type === 'visibility_modifier')
67
+ return 'public';
68
+ }
69
+ return 'private';
70
+ }
71
+ /**
72
+ * Detect receiver type from the first parameter if it is a self_parameter.
73
+ *
74
+ * Variants:
75
+ * - `self` → "self"
76
+ * - `&self` → "&self"
77
+ * - `&mut self` → "&mut self"
78
+ * - `mut self` → "mut self"
79
+ * - `self: Box<Self>` → "Box<Self>" (explicit self type)
80
+ */
81
+ function extractRustReceiverType(node) {
82
+ const paramList = node.childForFieldName('parameters');
83
+ if (!paramList)
84
+ return undefined;
85
+ const first = paramList.namedChild(0);
86
+ if (!first || first.type !== 'self_parameter')
87
+ return undefined;
88
+ return first.text;
89
+ }
90
+ /**
91
+ * Check whether a function_item has the `async` keyword.
92
+ * tree-sitter-rust wraps it in a `function_modifiers` named child.
93
+ */
94
+ function isRustAsync(node) {
95
+ for (let i = 0; i < node.namedChildCount; i++) {
96
+ const child = node.namedChild(i);
97
+ if (child?.type === 'function_modifiers' && child.text.includes('async'))
98
+ return true;
99
+ }
100
+ return false;
101
+ }
102
+ /**
103
+ * Extract attributes from preceding sibling attribute_item nodes.
104
+ *
105
+ * In tree-sitter-rust, `#[inline]` is an `attribute_item` sibling that precedes
106
+ * the function_item in the declaration_list, not a child of the function_item.
107
+ */
108
+ function extractRustAnnotations(node) {
109
+ const annotations = [];
110
+ let sibling = node.previousNamedSibling;
111
+ while (sibling) {
112
+ if (sibling.type === 'attribute_item') {
113
+ annotations.unshift(sibling.text);
114
+ }
115
+ else {
116
+ // Stop at the first non-attribute sibling — attributes are contiguous
117
+ break;
118
+ }
119
+ sibling = sibling.previousNamedSibling;
120
+ }
121
+ return annotations;
122
+ }
123
+ // ---------------------------------------------------------------------------
124
+ // Rust config
125
+ // ---------------------------------------------------------------------------
126
+ // Rust methods live inside `impl` blocks (concrete implementations) or
127
+ // `trait` blocks (trait definitions with required/default methods).
128
+ //
129
+ // `impl_item` body contains `function_item` nodes for concrete methods.
130
+ // `trait_item` body contains `function_item` (default methods) and
131
+ // `function_signature_item` (required/abstract methods without a body).
132
+ //
133
+ // ownerName resolution: `impl_item` has no `name` field — the generic
134
+ // extractor falls back to the first `type_identifier` child, which is the
135
+ // implementing type (e.g. `impl MyStruct { ... }` → "MyStruct").
136
+ // `trait_item` uses the standard `name` field.
137
+ //
138
+ // Known gaps:
139
+ // - Macro-generated methods (e.g. derive) are not visible in the AST.
140
+ // - Unsafe methods are not distinguished (no isUnsafe field in schema).
141
+ export const rustMethodConfig = {
142
+ language: SupportedLanguages.Rust,
143
+ typeDeclarationNodes: ['impl_item', 'trait_item'],
144
+ methodNodeTypes: ['function_item', 'function_signature_item'],
145
+ bodyNodeTypes: ['declaration_list'],
146
+ // For `impl Trait for Struct`, resolve owner to the concrete Struct (after `for`).
147
+ // For plain `impl Struct`, resolve to Struct (first type_identifier).
148
+ // For `trait Foo`, let the default name-field resolution handle it.
149
+ extractOwnerName(node) {
150
+ if (node.type !== 'impl_item')
151
+ return undefined;
152
+ const children = node.children ?? [];
153
+ const forIdx = children.findIndex((c) => c.text === 'for');
154
+ if (forIdx !== -1) {
155
+ // impl Trait for Struct — pick the type after `for`
156
+ const typeNode = children
157
+ .slice(forIdx + 1)
158
+ .find((c) => c.type === 'type_identifier' || c.type === 'scoped_type_identifier');
159
+ if (typeNode)
160
+ return typeNode.text;
161
+ }
162
+ // Plain `impl Struct` — pick the first type_identifier
163
+ const first = children.find((c) => c.type === 'type_identifier');
164
+ return first?.text;
165
+ },
166
+ extractName: extractRustMethodName,
167
+ extractReturnType: extractRustReturnType,
168
+ extractParameters: extractRustParameters,
169
+ extractVisibility: extractRustVisibility,
170
+ isStatic(node) {
171
+ // A Rust method is an "associated function" (static) if it lacks a
172
+ // self_parameter as first parameter.
173
+ const paramList = node.childForFieldName('parameters');
174
+ if (!paramList)
175
+ return true;
176
+ const first = paramList.namedChild(0);
177
+ return !first || first.type !== 'self_parameter';
178
+ },
179
+ isAbstract(node, ownerNode) {
180
+ // Only trait methods without a body (function_signature_item) are abstract.
181
+ // function_signature_item never has a body field.
182
+ if (ownerNode.type === 'trait_item' && node.type === 'function_signature_item') {
183
+ return true;
184
+ }
185
+ return false;
186
+ },
187
+ isFinal() {
188
+ // Rust has no `final` concept — all methods are effectively sealed
189
+ // (traits cannot be "overridden" the way Java methods can).
190
+ return false;
191
+ },
192
+ extractAnnotations: extractRustAnnotations,
193
+ extractReceiverType: extractRustReceiverType,
194
+ isAsync: isRustAsync,
195
+ };
@@ -0,0 +1,2 @@
1
+ import type { MethodExtractionConfig } from '../../method-types.js';
2
+ export declare const swiftMethodConfig: MethodExtractionConfig;