gitnexus 1.4.0 → 1.4.5
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 +19 -18
- package/dist/cli/analyze.js +37 -28
- package/dist/cli/augment.js +1 -1
- package/dist/cli/eval-server.d.ts +1 -1
- package/dist/cli/eval-server.js +1 -1
- package/dist/cli/index.js +1 -0
- package/dist/cli/mcp.js +1 -1
- package/dist/cli/setup.js +25 -13
- package/dist/cli/status.js +13 -4
- package/dist/cli/tool.d.ts +1 -1
- package/dist/cli/tool.js +2 -2
- package/dist/cli/wiki.js +2 -2
- package/dist/config/ignore-service.d.ts +25 -0
- package/dist/config/ignore-service.js +76 -0
- package/dist/config/supported-languages.d.ts +1 -0
- package/dist/config/supported-languages.js +1 -1
- package/dist/core/augmentation/engine.js +94 -67
- package/dist/core/embeddings/embedder.d.ts +1 -1
- package/dist/core/embeddings/embedder.js +1 -1
- package/dist/core/embeddings/embedding-pipeline.d.ts +3 -3
- package/dist/core/embeddings/embedding-pipeline.js +52 -25
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/ingestion/call-processor.d.ts +6 -7
- package/dist/core/ingestion/call-processor.js +490 -127
- package/dist/core/ingestion/call-routing.d.ts +53 -0
- package/dist/core/ingestion/call-routing.js +108 -0
- package/dist/core/ingestion/entry-point-scoring.js +13 -2
- package/dist/core/ingestion/export-detection.js +1 -0
- package/dist/core/ingestion/filesystem-walker.js +4 -3
- package/dist/core/ingestion/framework-detection.js +9 -0
- package/dist/core/ingestion/heritage-processor.d.ts +3 -4
- package/dist/core/ingestion/heritage-processor.js +40 -50
- package/dist/core/ingestion/import-processor.d.ts +3 -5
- package/dist/core/ingestion/import-processor.js +41 -10
- package/dist/core/ingestion/parsing-processor.d.ts +2 -1
- package/dist/core/ingestion/parsing-processor.js +41 -4
- package/dist/core/ingestion/pipeline.d.ts +5 -1
- package/dist/core/ingestion/pipeline.js +174 -121
- package/dist/core/ingestion/resolution-context.d.ts +53 -0
- package/dist/core/ingestion/resolution-context.js +132 -0
- package/dist/core/ingestion/resolvers/index.d.ts +2 -0
- package/dist/core/ingestion/resolvers/index.js +2 -0
- package/dist/core/ingestion/resolvers/python.d.ts +19 -0
- package/dist/core/ingestion/resolvers/python.js +52 -0
- package/dist/core/ingestion/resolvers/ruby.d.ts +12 -0
- package/dist/core/ingestion/resolvers/ruby.js +15 -0
- package/dist/core/ingestion/resolvers/standard.js +0 -22
- package/dist/core/ingestion/resolvers/utils.js +2 -0
- package/dist/core/ingestion/symbol-table.d.ts +3 -0
- package/dist/core/ingestion/symbol-table.js +1 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +3 -2
- package/dist/core/ingestion/tree-sitter-queries.js +53 -1
- package/dist/core/ingestion/type-env.d.ts +32 -10
- package/dist/core/ingestion/type-env.js +520 -47
- package/dist/core/ingestion/type-extractors/c-cpp.js +326 -1
- package/dist/core/ingestion/type-extractors/csharp.js +282 -2
- package/dist/core/ingestion/type-extractors/go.js +333 -2
- package/dist/core/ingestion/type-extractors/index.d.ts +3 -2
- package/dist/core/ingestion/type-extractors/index.js +3 -1
- package/dist/core/ingestion/type-extractors/jvm.js +537 -4
- package/dist/core/ingestion/type-extractors/php.js +387 -7
- package/dist/core/ingestion/type-extractors/python.js +356 -5
- package/dist/core/ingestion/type-extractors/ruby.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/ruby.js +389 -0
- package/dist/core/ingestion/type-extractors/rust.js +399 -2
- package/dist/core/ingestion/type-extractors/shared.d.ts +116 -1
- package/dist/core/ingestion/type-extractors/shared.js +488 -14
- package/dist/core/ingestion/type-extractors/swift.js +95 -1
- package/dist/core/ingestion/type-extractors/types.d.ts +81 -0
- package/dist/core/ingestion/type-extractors/typescript.js +436 -2
- package/dist/core/ingestion/utils.d.ts +33 -2
- package/dist/core/ingestion/utils.js +399 -27
- package/dist/core/ingestion/workers/parse-worker.d.ts +18 -1
- package/dist/core/ingestion/workers/parse-worker.js +169 -19
- package/dist/core/{kuzu → lbug}/csv-generator.d.ts +1 -1
- package/dist/core/{kuzu → lbug}/csv-generator.js +1 -1
- package/dist/core/{kuzu/kuzu-adapter.d.ts → lbug/lbug-adapter.d.ts} +19 -19
- package/dist/core/{kuzu/kuzu-adapter.js → lbug/lbug-adapter.js} +70 -65
- package/dist/core/{kuzu → lbug}/schema.d.ts +1 -1
- package/dist/core/{kuzu → lbug}/schema.js +1 -1
- package/dist/core/search/bm25-index.d.ts +4 -4
- package/dist/core/search/bm25-index.js +10 -10
- package/dist/core/search/hybrid-search.d.ts +2 -2
- package/dist/core/search/hybrid-search.js +6 -6
- package/dist/core/tree-sitter/parser-loader.js +9 -2
- package/dist/core/wiki/generator.d.ts +2 -2
- package/dist/core/wiki/generator.js +4 -4
- package/dist/core/wiki/graph-queries.d.ts +4 -4
- package/dist/core/wiki/graph-queries.js +7 -7
- package/dist/mcp/core/{kuzu-adapter.d.ts → lbug-adapter.d.ts} +7 -7
- package/dist/mcp/core/{kuzu-adapter.js → lbug-adapter.js} +72 -43
- package/dist/mcp/local/local-backend.d.ts +6 -6
- package/dist/mcp/local/local-backend.js +25 -18
- package/dist/server/api.js +12 -12
- package/dist/server/mcp-http.d.ts +1 -1
- package/dist/server/mcp-http.js +1 -1
- package/dist/storage/repo-manager.d.ts +20 -2
- package/dist/storage/repo-manager.js +55 -1
- package/dist/types/pipeline.d.ts +1 -1
- package/package.json +5 -3
- package/dist/core/ingestion/symbol-resolver.d.ts +0 -32
- package/dist/core/ingestion/symbol-resolver.js +0 -83
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { extractSimpleTypeName, extractVarName } from './shared.js';
|
|
1
|
+
import { extractSimpleTypeName, extractVarName, extractElementTypeFromString, extractGenericTypeArgs, resolveIterableElementType, methodToTypeArgPosition } from './shared.js';
|
|
2
2
|
const DECLARATION_NODE_TYPES = new Set([
|
|
3
3
|
'var_declaration',
|
|
4
4
|
'var_spec',
|
|
@@ -57,7 +57,56 @@ const extractGoShortVarDeclaration = (node, env) => {
|
|
|
57
57
|
// Pair each LHS name with its corresponding RHS value
|
|
58
58
|
const count = Math.min(lhsNodes.length, rhsNodes.length);
|
|
59
59
|
for (let i = 0; i < count; i++) {
|
|
60
|
-
|
|
60
|
+
let valueNode = rhsNodes[i];
|
|
61
|
+
// Unwrap &User{} — unary_expression (address-of) wrapping composite_literal
|
|
62
|
+
if (valueNode.type === 'unary_expression' && valueNode.firstNamedChild?.type === 'composite_literal') {
|
|
63
|
+
valueNode = valueNode.firstNamedChild;
|
|
64
|
+
}
|
|
65
|
+
// Go built-in new(User) — call_expression with 'new' callee and type argument
|
|
66
|
+
// Go built-in make([]User, 0) / make(map[string]User) — extract element/value type
|
|
67
|
+
if (valueNode.type === 'call_expression') {
|
|
68
|
+
const funcNode = valueNode.childForFieldName('function');
|
|
69
|
+
if (funcNode?.text === 'new') {
|
|
70
|
+
const args = valueNode.childForFieldName('arguments');
|
|
71
|
+
if (args?.firstNamedChild) {
|
|
72
|
+
const typeName = extractSimpleTypeName(args.firstNamedChild);
|
|
73
|
+
const varName = extractVarName(lhsNodes[i]);
|
|
74
|
+
if (varName && typeName)
|
|
75
|
+
env.set(varName, typeName);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (funcNode?.text === 'make') {
|
|
79
|
+
const args = valueNode.childForFieldName('arguments');
|
|
80
|
+
const firstArg = args?.firstNamedChild;
|
|
81
|
+
if (firstArg) {
|
|
82
|
+
let innerType = null;
|
|
83
|
+
if (firstArg.type === 'slice_type') {
|
|
84
|
+
innerType = firstArg.childForFieldName('element');
|
|
85
|
+
}
|
|
86
|
+
else if (firstArg.type === 'map_type') {
|
|
87
|
+
innerType = firstArg.childForFieldName('value');
|
|
88
|
+
}
|
|
89
|
+
if (innerType) {
|
|
90
|
+
const typeName = extractSimpleTypeName(innerType);
|
|
91
|
+
const varName = extractVarName(lhsNodes[i]);
|
|
92
|
+
if (varName && typeName)
|
|
93
|
+
env.set(varName, typeName);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
// Go type assertion: user := iface.(User) — type_assertion_expression with 'type' field
|
|
100
|
+
if (valueNode.type === 'type_assertion_expression') {
|
|
101
|
+
const typeNode = valueNode.childForFieldName('type');
|
|
102
|
+
if (typeNode) {
|
|
103
|
+
const typeName = extractSimpleTypeName(typeNode);
|
|
104
|
+
const varName = extractVarName(lhsNodes[i]);
|
|
105
|
+
if (varName && typeName)
|
|
106
|
+
env.set(varName, typeName);
|
|
107
|
+
}
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
61
110
|
if (valueNode.type !== 'composite_literal')
|
|
62
111
|
continue;
|
|
63
112
|
const typeNode = valueNode.childForFieldName('type');
|
|
@@ -98,8 +147,290 @@ const extractParameter = (node, env) => {
|
|
|
98
147
|
if (varName && typeName)
|
|
99
148
|
env.set(varName, typeName);
|
|
100
149
|
};
|
|
150
|
+
/** Go: user := NewUser(...) — infer type from single-assignment call expression */
|
|
151
|
+
const scanConstructorBinding = (node) => {
|
|
152
|
+
if (node.type !== 'short_var_declaration')
|
|
153
|
+
return undefined;
|
|
154
|
+
const left = node.childForFieldName('left');
|
|
155
|
+
const right = node.childForFieldName('right');
|
|
156
|
+
if (!left || !right)
|
|
157
|
+
return undefined;
|
|
158
|
+
const leftIds = left.type === 'expression_list' ? left.namedChildren : [left];
|
|
159
|
+
const rightExprs = right.type === 'expression_list' ? right.namedChildren : [right];
|
|
160
|
+
// Multi-return: user, err := NewUser() — bind first var when second is err/ok/_
|
|
161
|
+
if (leftIds.length === 2 && rightExprs.length === 1) {
|
|
162
|
+
const secondVar = leftIds[1];
|
|
163
|
+
const isErrorOrDiscard = secondVar.text === '_' ||
|
|
164
|
+
secondVar.text === 'err' ||
|
|
165
|
+
secondVar.text === 'ok' ||
|
|
166
|
+
secondVar.text === 'error';
|
|
167
|
+
if (isErrorOrDiscard && leftIds[0].type === 'identifier') {
|
|
168
|
+
if (rightExprs[0].type !== 'call_expression')
|
|
169
|
+
return undefined;
|
|
170
|
+
const func = rightExprs[0].childForFieldName('function');
|
|
171
|
+
if (!func)
|
|
172
|
+
return undefined;
|
|
173
|
+
if (func.text === 'new' || func.text === 'make')
|
|
174
|
+
return undefined;
|
|
175
|
+
const calleeName = extractSimpleTypeName(func);
|
|
176
|
+
if (!calleeName)
|
|
177
|
+
return undefined;
|
|
178
|
+
return { varName: leftIds[0].text, calleeName };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Single assignment only
|
|
182
|
+
if (leftIds.length !== 1 || leftIds[0].type !== 'identifier')
|
|
183
|
+
return undefined;
|
|
184
|
+
if (rightExprs.length !== 1 || rightExprs[0].type !== 'call_expression')
|
|
185
|
+
return undefined;
|
|
186
|
+
const func = rightExprs[0].childForFieldName('function');
|
|
187
|
+
if (!func)
|
|
188
|
+
return undefined;
|
|
189
|
+
// Skip new() and make() — already handled by extractDeclaration
|
|
190
|
+
if (func.text === 'new' || func.text === 'make')
|
|
191
|
+
return undefined;
|
|
192
|
+
const calleeName = extractSimpleTypeName(func);
|
|
193
|
+
if (!calleeName)
|
|
194
|
+
return undefined;
|
|
195
|
+
return { varName: leftIds[0].text, calleeName };
|
|
196
|
+
};
|
|
197
|
+
const FOR_LOOP_NODE_TYPES = new Set([
|
|
198
|
+
'for_statement',
|
|
199
|
+
]);
|
|
200
|
+
/** Go function/method node types that carry a parameter list. */
|
|
201
|
+
const GO_FUNCTION_NODE_TYPES = new Set([
|
|
202
|
+
'function_declaration', 'method_declaration', 'func_literal',
|
|
203
|
+
]);
|
|
204
|
+
/**
|
|
205
|
+
* Extract element type from a Go type annotation AST node.
|
|
206
|
+
* Handles:
|
|
207
|
+
* slice_type "[]User" → element field → type_identifier "User"
|
|
208
|
+
* array_type "[10]User" → element field → type_identifier "User"
|
|
209
|
+
* Falls back to text-based extraction via extractElementTypeFromString.
|
|
210
|
+
*/
|
|
211
|
+
const extractGoElementTypeFromTypeNode = (typeNode, pos = 'last') => {
|
|
212
|
+
// slice_type: []User — element field is the element type
|
|
213
|
+
if (typeNode.type === 'slice_type' || typeNode.type === 'array_type') {
|
|
214
|
+
const elemNode = typeNode.childForFieldName('element');
|
|
215
|
+
if (elemNode)
|
|
216
|
+
return extractSimpleTypeName(elemNode);
|
|
217
|
+
}
|
|
218
|
+
// map_type: map[string]User — value field is the element type (for range, second var gets value)
|
|
219
|
+
if (typeNode.type === 'map_type') {
|
|
220
|
+
const valueNode = typeNode.childForFieldName('value');
|
|
221
|
+
if (valueNode)
|
|
222
|
+
return extractSimpleTypeName(valueNode);
|
|
223
|
+
}
|
|
224
|
+
// channel_type: chan User — the type argument is the element type
|
|
225
|
+
if (typeNode.type === 'channel_type') {
|
|
226
|
+
const valueNode = typeNode.childForFieldName('value') ?? typeNode.lastNamedChild;
|
|
227
|
+
if (valueNode)
|
|
228
|
+
return extractSimpleTypeName(valueNode);
|
|
229
|
+
}
|
|
230
|
+
// generic_type: Go 1.18+ generics (e.g., MySlice[User], Cache[string, User])
|
|
231
|
+
// Use position-aware arg selection: 'first' for keys, 'last' for values.
|
|
232
|
+
if (typeNode.type === 'generic_type') {
|
|
233
|
+
const args = extractGenericTypeArgs(typeNode);
|
|
234
|
+
if (args.length >= 1)
|
|
235
|
+
return pos === 'first' ? args[0] : args[args.length - 1];
|
|
236
|
+
}
|
|
237
|
+
// Fallback: text-based extraction ([]User → User, User[] → User)
|
|
238
|
+
return extractElementTypeFromString(typeNode.text, pos);
|
|
239
|
+
};
|
|
240
|
+
/** Check if a Go type node represents a channel type. Used to determine
|
|
241
|
+
* whether single-var range yields the element (channels) vs index (slices/maps). */
|
|
242
|
+
const isChannelType = (iterableName, scopeEnv, declarationTypeNodes, scope) => {
|
|
243
|
+
if (declarationTypeNodes && scope) {
|
|
244
|
+
const typeNode = declarationTypeNodes.get(`${scope}\0${iterableName}`);
|
|
245
|
+
if (typeNode)
|
|
246
|
+
return typeNode.type === 'channel_type';
|
|
247
|
+
}
|
|
248
|
+
const t = scopeEnv.get(iterableName);
|
|
249
|
+
return !!t && t.startsWith('chan ');
|
|
250
|
+
};
|
|
251
|
+
/**
|
|
252
|
+
* Walk up the AST from a for-statement to find the enclosing function declaration,
|
|
253
|
+
* then search its parameters for one named `iterableName`.
|
|
254
|
+
* Returns the element type extracted from its type annotation, or undefined.
|
|
255
|
+
*
|
|
256
|
+
* Go parameter_declaration has:
|
|
257
|
+
* name field: identifier (the parameter name)
|
|
258
|
+
* type field: the type node (slice_type for []User)
|
|
259
|
+
*/
|
|
260
|
+
const findGoParamElementType = (iterableName, startNode, pos = 'last') => {
|
|
261
|
+
let current = startNode.parent;
|
|
262
|
+
while (current) {
|
|
263
|
+
if (GO_FUNCTION_NODE_TYPES.has(current.type)) {
|
|
264
|
+
const paramsNode = current.childForFieldName('parameters');
|
|
265
|
+
if (paramsNode) {
|
|
266
|
+
for (let i = 0; i < paramsNode.namedChildCount; i++) {
|
|
267
|
+
const paramDecl = paramsNode.namedChild(i);
|
|
268
|
+
if (!paramDecl || paramDecl.type !== 'parameter_declaration')
|
|
269
|
+
continue;
|
|
270
|
+
// parameter_declaration: name type — name field is the identifier
|
|
271
|
+
const nameNode = paramDecl.childForFieldName('name');
|
|
272
|
+
if (nameNode?.text === iterableName) {
|
|
273
|
+
const typeNode = paramDecl.childForFieldName('type');
|
|
274
|
+
if (typeNode)
|
|
275
|
+
return extractGoElementTypeFromTypeNode(typeNode, pos);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
current = current.parent;
|
|
282
|
+
}
|
|
283
|
+
return undefined;
|
|
284
|
+
};
|
|
285
|
+
/**
|
|
286
|
+
* Go: for _, user := range users where users has a known slice type.
|
|
287
|
+
*
|
|
288
|
+
* Go uses a single `for_statement` node for all for-loop forms. We detect
|
|
289
|
+
* range-based loops by looking for a `range_clause` child node. C-style for
|
|
290
|
+
* loops (with `for_clause`) and infinite loops (no clause) are ignored.
|
|
291
|
+
*
|
|
292
|
+
* Tier 1c: resolves the element type via three strategies in priority order:
|
|
293
|
+
* 1. declarationTypeNodes — raw type annotation AST node
|
|
294
|
+
* 2. scopeEnv string — extractElementTypeFromString on the stored type
|
|
295
|
+
* 3. AST walk — walks up to the enclosing function's parameters to read []User directly
|
|
296
|
+
* For `_, user := range users`, the loop variable is the second identifier in
|
|
297
|
+
* the `left` expression_list (index is discarded, value is the element).
|
|
298
|
+
*/
|
|
299
|
+
const extractForLoopBinding = (node, scopeEnv, declarationTypeNodes, scope) => {
|
|
300
|
+
if (node.type !== 'for_statement')
|
|
301
|
+
return;
|
|
302
|
+
// Find the range_clause child — this distinguishes range loops from other for forms.
|
|
303
|
+
let rangeClause = null;
|
|
304
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
305
|
+
const child = node.namedChild(i);
|
|
306
|
+
if (child?.type === 'range_clause') {
|
|
307
|
+
rangeClause = child;
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (!rangeClause)
|
|
312
|
+
return;
|
|
313
|
+
// The iterable is the `right` field of the range_clause.
|
|
314
|
+
const rightNode = rangeClause.childForFieldName('right');
|
|
315
|
+
let iterableName;
|
|
316
|
+
if (rightNode?.type === 'identifier') {
|
|
317
|
+
iterableName = rightNode.text;
|
|
318
|
+
}
|
|
319
|
+
else if (rightNode?.type === 'selector_expression') {
|
|
320
|
+
const field = rightNode.childForFieldName('field');
|
|
321
|
+
if (field)
|
|
322
|
+
iterableName = field.text;
|
|
323
|
+
}
|
|
324
|
+
if (!iterableName)
|
|
325
|
+
return;
|
|
326
|
+
const containerTypeName = scopeEnv.get(iterableName);
|
|
327
|
+
const typeArgPos = methodToTypeArgPosition(undefined, containerTypeName);
|
|
328
|
+
const elementType = resolveIterableElementType(iterableName, node, scopeEnv, declarationTypeNodes, scope, extractGoElementTypeFromTypeNode, findGoParamElementType, typeArgPos);
|
|
329
|
+
if (!elementType)
|
|
330
|
+
return;
|
|
331
|
+
// The loop variable(s) are in the `left` field.
|
|
332
|
+
// Go range semantics:
|
|
333
|
+
// Slice/Array/String: single-var → INDEX (int); two-var → (index, element)
|
|
334
|
+
// Map: single-var → KEY; two-var → (key, value)
|
|
335
|
+
// Channel: single-var → ELEMENT (channels have no index)
|
|
336
|
+
const leftNode = rangeClause.childForFieldName('left');
|
|
337
|
+
if (!leftNode)
|
|
338
|
+
return;
|
|
339
|
+
let loopVarNode = null;
|
|
340
|
+
if (leftNode.type === 'expression_list') {
|
|
341
|
+
if (leftNode.namedChildCount >= 2) {
|
|
342
|
+
// Two-var form: `_, user` or `i, user` — second variable gets element/value type
|
|
343
|
+
loopVarNode = leftNode.namedChild(1);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
// Single-var in expression_list — yields INDEX for slices/maps, ELEMENT for channels
|
|
347
|
+
if (isChannelType(iterableName, scopeEnv, declarationTypeNodes, scope)) {
|
|
348
|
+
loopVarNode = leftNode.namedChild(0);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
return; // index-only range on slice/map — skip
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
// Plain identifier (single-var form without expression_list)
|
|
357
|
+
if (isChannelType(iterableName, scopeEnv, declarationTypeNodes, scope)) {
|
|
358
|
+
loopVarNode = leftNode;
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
return; // index-only range on slice/map — skip
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (!loopVarNode)
|
|
365
|
+
return;
|
|
366
|
+
// Skip the blank identifier `_`
|
|
367
|
+
if (loopVarNode.text === '_')
|
|
368
|
+
return;
|
|
369
|
+
const loopVarName = extractVarName(loopVarNode);
|
|
370
|
+
if (loopVarName)
|
|
371
|
+
scopeEnv.set(loopVarName, elementType);
|
|
372
|
+
};
|
|
373
|
+
/** Go: alias := u (short_var_declaration) or var b = u (var_spec) */
|
|
374
|
+
const extractPendingAssignment = (node, scopeEnv) => {
|
|
375
|
+
if (node.type === 'short_var_declaration') {
|
|
376
|
+
const left = node.childForFieldName('left');
|
|
377
|
+
const right = node.childForFieldName('right');
|
|
378
|
+
if (!left || !right)
|
|
379
|
+
return undefined;
|
|
380
|
+
const lhsNode = left.type === 'expression_list' ? left.firstNamedChild : left;
|
|
381
|
+
const rhsNode = right.type === 'expression_list' ? right.firstNamedChild : right;
|
|
382
|
+
if (!lhsNode || !rhsNode)
|
|
383
|
+
return undefined;
|
|
384
|
+
if (lhsNode.type !== 'identifier')
|
|
385
|
+
return undefined;
|
|
386
|
+
const lhs = lhsNode.text;
|
|
387
|
+
if (scopeEnv.has(lhs))
|
|
388
|
+
return undefined;
|
|
389
|
+
if (rhsNode.type === 'identifier')
|
|
390
|
+
return { lhs, rhs: rhsNode.text };
|
|
391
|
+
return undefined;
|
|
392
|
+
}
|
|
393
|
+
if (node.type === 'var_spec' || node.type === 'var_declaration') {
|
|
394
|
+
// var_declaration contains var_spec children; var_spec has name + expression_list value
|
|
395
|
+
const specs = [];
|
|
396
|
+
if (node.type === 'var_declaration') {
|
|
397
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
398
|
+
const c = node.namedChild(i);
|
|
399
|
+
if (c?.type === 'var_spec')
|
|
400
|
+
specs.push(c);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
specs.push(node);
|
|
405
|
+
}
|
|
406
|
+
for (const spec of specs) {
|
|
407
|
+
const nameNode = spec.childForFieldName('name');
|
|
408
|
+
if (!nameNode || nameNode.type !== 'identifier')
|
|
409
|
+
continue;
|
|
410
|
+
const lhs = nameNode.text;
|
|
411
|
+
if (scopeEnv.has(lhs))
|
|
412
|
+
continue;
|
|
413
|
+
// Check if the last named child is a bare identifier (no type annotation between name and value)
|
|
414
|
+
let exprList = null;
|
|
415
|
+
for (let i = 0; i < spec.childCount; i++) {
|
|
416
|
+
if (spec.child(i)?.type === 'expression_list') {
|
|
417
|
+
exprList = spec.child(i);
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
const rhsNode = exprList?.firstNamedChild;
|
|
422
|
+
if (rhsNode?.type === 'identifier')
|
|
423
|
+
return { lhs, rhs: rhsNode.text };
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return undefined;
|
|
427
|
+
};
|
|
101
428
|
export const typeConfig = {
|
|
102
429
|
declarationNodeTypes: DECLARATION_NODE_TYPES,
|
|
430
|
+
forLoopNodeTypes: FOR_LOOP_NODE_TYPES,
|
|
103
431
|
extractDeclaration,
|
|
104
432
|
extractParameter,
|
|
433
|
+
scanConstructorBinding,
|
|
434
|
+
extractForLoopBinding,
|
|
435
|
+
extractPendingAssignment,
|
|
105
436
|
};
|
|
@@ -16,6 +16,7 @@ export declare const typeConfigs: {
|
|
|
16
16
|
c: LanguageTypeConfig;
|
|
17
17
|
cpp: LanguageTypeConfig;
|
|
18
18
|
php: LanguageTypeConfig;
|
|
19
|
+
ruby: LanguageTypeConfig;
|
|
19
20
|
};
|
|
20
|
-
export type { LanguageTypeConfig, TypeBindingExtractor, ParameterExtractor } from './types.js';
|
|
21
|
-
export { TYPED_PARAMETER_TYPES, extractSimpleTypeName, extractVarName, findChildByType } from './shared.js';
|
|
21
|
+
export type { LanguageTypeConfig, TypeBindingExtractor, ParameterExtractor, ConstructorBindingScanner, ForLoopExtractor, PendingAssignmentExtractor, PatternBindingExtractor, } from './types.js';
|
|
22
|
+
export { TYPED_PARAMETER_TYPES, extractSimpleTypeName, extractGenericTypeArgs, extractVarName, findChildByType, extractRubyConstructorAssignment } from './shared.js';
|
|
@@ -12,6 +12,7 @@ import { typeConfig as pythonConfig } from './python.js';
|
|
|
12
12
|
import { typeConfig as swiftConfig } from './swift.js';
|
|
13
13
|
import { typeConfig as cCppConfig } from './c-cpp.js';
|
|
14
14
|
import { typeConfig as phpConfig } from './php.js';
|
|
15
|
+
import { typeConfig as rubyConfig } from './ruby.js';
|
|
15
16
|
export const typeConfigs = {
|
|
16
17
|
[SupportedLanguages.JavaScript]: typescriptConfig,
|
|
17
18
|
[SupportedLanguages.TypeScript]: typescriptConfig,
|
|
@@ -25,5 +26,6 @@ export const typeConfigs = {
|
|
|
25
26
|
[SupportedLanguages.C]: cCppConfig,
|
|
26
27
|
[SupportedLanguages.CPlusPlus]: cCppConfig,
|
|
27
28
|
[SupportedLanguages.PHP]: phpConfig,
|
|
29
|
+
[SupportedLanguages.Ruby]: rubyConfig,
|
|
28
30
|
};
|
|
29
|
-
export { TYPED_PARAMETER_TYPES, extractSimpleTypeName, extractVarName, findChildByType } from './shared.js';
|
|
31
|
+
export { TYPED_PARAMETER_TYPES, extractSimpleTypeName, extractGenericTypeArgs, extractVarName, findChildByType, extractRubyConstructorAssignment } from './shared.js';
|