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
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { FUNCTION_NODE_TYPES, extractFunctionName, CLASS_CONTAINER_TYPES } from './utils/ast-helpers.js';
|
|
1
|
+
import { FUNCTION_NODE_TYPES, extractFunctionName, CLASS_CONTAINER_TYPES, } from './utils/ast-helpers.js';
|
|
2
2
|
import { CALL_EXPRESSION_TYPES } from './utils/call-analysis.js';
|
|
3
3
|
import { TYPED_PARAMETER_TYPES } from './type-extractors/shared.js';
|
|
4
4
|
import { getProvider } from './languages/index.js';
|
|
5
|
-
import { extractSimpleTypeName, extractVarName, stripNullable, extractReturnTypeName } from './type-extractors/shared.js';
|
|
5
|
+
import { extractSimpleTypeName, extractVarName, stripNullable, extractReturnTypeName, } from './type-extractors/shared.js';
|
|
6
6
|
/** File-level scope key */
|
|
7
7
|
const FILE_SCOPE = '';
|
|
8
8
|
/** Shared empty map for files with no file-scope bindings. */
|
|
@@ -48,7 +48,7 @@ const FAST_NULLABLE_KEYWORDS = new Set(['null', 'undefined', 'void', 'None', 'ni
|
|
|
48
48
|
const fastStripNullable = (typeName) => {
|
|
49
49
|
if (FAST_NULLABLE_KEYWORDS.has(typeName))
|
|
50
50
|
return undefined;
|
|
51
|
-
return
|
|
51
|
+
return typeName.indexOf('|') === -1 && typeName.indexOf('?') === -1
|
|
52
52
|
? typeName
|
|
53
53
|
: stripNullable(typeName);
|
|
54
54
|
};
|
|
@@ -107,8 +107,7 @@ const findEnclosingClassName = (node) => {
|
|
|
107
107
|
let current = node.parent;
|
|
108
108
|
while (current) {
|
|
109
109
|
if (CLASS_CONTAINER_TYPES.has(current.type)) {
|
|
110
|
-
const nameNode = current.childForFieldName('name')
|
|
111
|
-
?? findTypeIdentifierChild(current);
|
|
110
|
+
const nameNode = current.childForFieldName('name') ?? findTypeIdentifierChild(current);
|
|
112
111
|
if (nameNode) {
|
|
113
112
|
enclosingClassNameCache.set(node, nameNode.text);
|
|
114
113
|
return nameNode.text;
|
|
@@ -172,9 +171,7 @@ const extractParentClassFromNode = (classNode) => {
|
|
|
172
171
|
const superclassNode = classNode.childForFieldName('superclass');
|
|
173
172
|
if (superclassNode) {
|
|
174
173
|
// Java: superclass > type_identifier or generic_type, Ruby: superclass > constant
|
|
175
|
-
const inner = superclassNode.childForFieldName('type')
|
|
176
|
-
?? superclassNode.firstNamedChild
|
|
177
|
-
?? superclassNode;
|
|
174
|
+
const inner = superclassNode.childForFieldName('type') ?? superclassNode.firstNamedChild ?? superclassNode;
|
|
178
175
|
return extractSimpleTypeName(inner) ?? inner.text;
|
|
179
176
|
}
|
|
180
177
|
const superclassesNode = classNode.childForFieldName('superclasses');
|
|
@@ -316,7 +313,9 @@ const createClassNameLookup = (localNames, symbolTable) => {
|
|
|
316
313
|
const cached = memo.get(name);
|
|
317
314
|
if (cached !== undefined)
|
|
318
315
|
return cached;
|
|
319
|
-
const result = symbolTable
|
|
316
|
+
const result = symbolTable
|
|
317
|
+
.lookupFuzzy(name)
|
|
318
|
+
.some((def) => def.type === 'Class' || def.type === 'Enum' || def.type === 'Struct');
|
|
320
319
|
memo.set(name, result);
|
|
321
320
|
return result;
|
|
322
321
|
},
|
|
@@ -341,15 +340,25 @@ const createClassNameLookup = (localNames, symbolTable) => {
|
|
|
341
340
|
const SKIP_SUBTREE_TYPES = new Set([
|
|
342
341
|
// Plain string literals (NOT template_string — it contains interpolated expressions
|
|
343
342
|
// that can hold arrow functions with typed parameters, e.g. `${(x: T) => x}`)
|
|
344
|
-
'string',
|
|
345
|
-
'
|
|
343
|
+
'string',
|
|
344
|
+
'string_literal',
|
|
345
|
+
'string_content',
|
|
346
|
+
'string_fragment',
|
|
347
|
+
'heredoc_body',
|
|
346
348
|
// Comments
|
|
347
|
-
'comment',
|
|
349
|
+
'comment',
|
|
350
|
+
'line_comment',
|
|
351
|
+
'block_comment',
|
|
348
352
|
// Numeric/boolean/null literals
|
|
349
|
-
'number',
|
|
350
|
-
'
|
|
353
|
+
'number',
|
|
354
|
+
'integer_literal',
|
|
355
|
+
'float_literal',
|
|
356
|
+
'true',
|
|
357
|
+
'false',
|
|
358
|
+
'null',
|
|
351
359
|
// Regex
|
|
352
|
-
'regex',
|
|
360
|
+
'regex',
|
|
361
|
+
'regex_pattern',
|
|
353
362
|
]);
|
|
354
363
|
const CLASS_LIKE_TYPES = new Set(['Class', 'Struct', 'Interface']);
|
|
355
364
|
/** Memoize class definition lookups during fixpoint iteration.
|
|
@@ -361,7 +370,7 @@ const createClassDefCache = (symbolTable) => {
|
|
|
361
370
|
let result = cache.get(typeName);
|
|
362
371
|
if (result === undefined) {
|
|
363
372
|
result = symbolTable
|
|
364
|
-
? symbolTable.lookupFuzzy(typeName).filter(d => CLASS_LIKE_TYPES.has(d.type))
|
|
373
|
+
? symbolTable.lookupFuzzy(typeName).filter((d) => CLASS_LIKE_TYPES.has(d.type))
|
|
365
374
|
: [];
|
|
366
375
|
cache.set(typeName, result);
|
|
367
376
|
}
|
|
@@ -402,8 +411,9 @@ const extractConstructorTypeName = (node, depth = 0) => {
|
|
|
402
411
|
continue;
|
|
403
412
|
// Don't descend into nested functions/classes or call expressions (prevents
|
|
404
413
|
// finding constructor args inside method calls, e.g. processAll(new Dog()))
|
|
405
|
-
if (FUNCTION_NODE_TYPES.has(child.type) ||
|
|
406
|
-
|
|
414
|
+
if (FUNCTION_NODE_TYPES.has(child.type) ||
|
|
415
|
+
CLASS_CONTAINER_TYPES.has(child.type) ||
|
|
416
|
+
CALL_EXPRESSION_TYPES.has(child.type))
|
|
407
417
|
continue;
|
|
408
418
|
const result = extractConstructorTypeName(child, depth + 1);
|
|
409
419
|
if (result)
|
|
@@ -480,8 +490,8 @@ const resolveFieldType = (receiver, field, scopeEnv, symbolTable, getClassDefs,
|
|
|
480
490
|
const receiverType = scopeEnv.get(receiver);
|
|
481
491
|
if (!receiverType)
|
|
482
492
|
return undefined;
|
|
483
|
-
const lookup = getClassDefs
|
|
484
|
-
|
|
493
|
+
const lookup = getClassDefs ??
|
|
494
|
+
((name) => symbolTable.lookupFuzzy(name).filter((d) => CLASS_LIKE_TYPES.has(d.type)));
|
|
485
495
|
const classDefs = lookup(receiverType);
|
|
486
496
|
if (classDefs.length !== 1)
|
|
487
497
|
return undefined;
|
|
@@ -506,23 +516,25 @@ const resolveMethodReturnType = (receiver, method, scopeEnv, symbolTable, getCla
|
|
|
506
516
|
const receiverType = scopeEnv.get(receiver);
|
|
507
517
|
if (!receiverType)
|
|
508
518
|
return undefined;
|
|
509
|
-
const lookup = getClassDefs
|
|
510
|
-
|
|
519
|
+
const lookup = getClassDefs ??
|
|
520
|
+
((name) => symbolTable.lookupFuzzy(name).filter((d) => CLASS_LIKE_TYPES.has(d.type)));
|
|
511
521
|
const classDefs = lookup(receiverType);
|
|
512
522
|
if (classDefs.length === 0)
|
|
513
523
|
return undefined;
|
|
514
524
|
// Direct lookup first
|
|
515
|
-
const classNodeIds = new Set(classDefs.map(d => d.nodeId));
|
|
516
|
-
const methods = symbolTable
|
|
517
|
-
.
|
|
525
|
+
const classNodeIds = new Set(classDefs.map((d) => d.nodeId));
|
|
526
|
+
const methods = symbolTable
|
|
527
|
+
.lookupFuzzyCallable(method)
|
|
528
|
+
.filter((d) => d.ownerId && classNodeIds.has(d.ownerId));
|
|
518
529
|
if (methods.length === 1 && methods[0].returnType) {
|
|
519
530
|
return extractReturnTypeName(methods[0].returnType);
|
|
520
531
|
}
|
|
521
532
|
// MRO parent chain walking on miss
|
|
522
533
|
if (methods.length === 0) {
|
|
523
534
|
const inherited = walkParentChain(receiverType, parentMap, lookup, (nodeId) => {
|
|
524
|
-
const parentMethods = symbolTable
|
|
525
|
-
.
|
|
535
|
+
const parentMethods = symbolTable
|
|
536
|
+
.lookupFuzzyCallable(method)
|
|
537
|
+
.filter((d) => d.ownerId === nodeId);
|
|
526
538
|
if (parentMethods.length !== 1 || !parentMethods[0].returnType)
|
|
527
539
|
return undefined;
|
|
528
540
|
return extractReturnTypeName(parentMethods[0].returnType);
|
|
@@ -667,14 +679,14 @@ export const buildTypeEnv = (tree, language, options) => {
|
|
|
667
679
|
// Cross-file fallback uses importedRawReturnTypes (raw declared types, e.g., 'User[]')
|
|
668
680
|
// NOT importedReturnTypes (which contains processed/simple types via extractReturnTypeName)
|
|
669
681
|
return options?.importedRawReturnTypes?.get(callee);
|
|
670
|
-
}
|
|
682
|
+
},
|
|
671
683
|
};
|
|
672
684
|
// Pre-compute combined set of node types that need extractTypeBinding.
|
|
673
685
|
// Single Set.has() replaces 3 separate checks per node in walk().
|
|
674
686
|
const interestingNodeTypes = new Set();
|
|
675
|
-
TYPED_PARAMETER_TYPES.forEach(t => interestingNodeTypes.add(t));
|
|
676
|
-
config.declarationNodeTypes.forEach(t => interestingNodeTypes.add(t));
|
|
677
|
-
config.forLoopNodeTypes?.forEach(t => interestingNodeTypes.add(t));
|
|
687
|
+
TYPED_PARAMETER_TYPES.forEach((t) => interestingNodeTypes.add(t));
|
|
688
|
+
config.declarationNodeTypes.forEach((t) => interestingNodeTypes.add(t));
|
|
689
|
+
config.forLoopNodeTypes?.forEach((t) => interestingNodeTypes.add(t));
|
|
678
690
|
// Tier 2: unified fixpoint propagation — collects copy, callResult, fieldAccess, and
|
|
679
691
|
// methodCallResult items during walk(), then iterates until no new bindings are produced.
|
|
680
692
|
// Handles arbitrary-depth mixed chains: callResult → fieldAccess → methodCallResult → copy.
|
|
@@ -708,12 +720,12 @@ export const buildTypeEnv = (tree, language, options) => {
|
|
|
708
720
|
// Most languages use 'name' field; Rust uses 'pattern'; TS uses 'pattern' for some param types.
|
|
709
721
|
// Kotlin `parameter` nodes use positional children instead of named fields,
|
|
710
722
|
// so we fall back to scanning children by type when childForFieldName returns null.
|
|
711
|
-
|
|
723
|
+
const typeNode = node.childForFieldName('type');
|
|
712
724
|
if (typeNode) {
|
|
713
|
-
const nameNode = node.childForFieldName('name')
|
|
714
|
-
|
|
725
|
+
const nameNode = node.childForFieldName('name') ??
|
|
726
|
+
node.childForFieldName('pattern') ??
|
|
715
727
|
// Python typed_parameter: name is a positional child (identifier), not a named field
|
|
716
|
-
|
|
728
|
+
(node.firstNamedChild?.type === 'identifier' ? node.firstNamedChild : null);
|
|
717
729
|
if (nameNode) {
|
|
718
730
|
const varName = extractVarName(nameNode);
|
|
719
731
|
if (varName && !declarationTypeNodes.has(`${scope}\0${varName}`)) {
|
|
@@ -729,12 +741,16 @@ export const buildTypeEnv = (tree, language, options) => {
|
|
|
729
741
|
const child = node.namedChild(i);
|
|
730
742
|
if (!child)
|
|
731
743
|
continue;
|
|
732
|
-
if (!fallbackName &&
|
|
744
|
+
if (!fallbackName &&
|
|
745
|
+
(child.type === 'simple_identifier' || child.type === 'identifier')) {
|
|
733
746
|
fallbackName = child;
|
|
734
747
|
}
|
|
735
|
-
if (!fallbackType &&
|
|
736
|
-
|
|
737
|
-
|
|
748
|
+
if (!fallbackType &&
|
|
749
|
+
(child.type === 'user_type' ||
|
|
750
|
+
child.type === 'type_identifier' ||
|
|
751
|
+
child.type === 'generic_type' ||
|
|
752
|
+
child.type === 'parameterized_type' ||
|
|
753
|
+
child.type === 'nullable_type')) {
|
|
738
754
|
fallbackType = child;
|
|
739
755
|
}
|
|
740
756
|
}
|
|
@@ -753,7 +769,12 @@ export const buildTypeEnv = (tree, language, options) => {
|
|
|
753
769
|
if (config.forLoopNodeTypes?.has(node.type)) {
|
|
754
770
|
if (config.extractForLoopBinding) {
|
|
755
771
|
const sizeBefore = scopeEnv.size;
|
|
756
|
-
const forLoopCtx = {
|
|
772
|
+
const forLoopCtx = {
|
|
773
|
+
scopeEnv,
|
|
774
|
+
declarationTypeNodes,
|
|
775
|
+
scope,
|
|
776
|
+
returnTypeLookup,
|
|
777
|
+
};
|
|
757
778
|
config.extractForLoopBinding(node, forLoopCtx);
|
|
758
779
|
// If no new binding was produced, the iterable's type may not yet be resolved.
|
|
759
780
|
// Store for post-fixpoint replay (Phase 10 / ex-9B loop-fixpoint bridge).
|
|
@@ -813,9 +834,9 @@ export const buildTypeEnv = (tree, language, options) => {
|
|
|
813
834
|
}
|
|
814
835
|
}
|
|
815
836
|
if (typeNode) {
|
|
816
|
-
const nameNode = node.childForFieldName('name')
|
|
817
|
-
|
|
818
|
-
|
|
837
|
+
const nameNode = node.childForFieldName('name') ??
|
|
838
|
+
node.childForFieldName('left') ??
|
|
839
|
+
node.childForFieldName('pattern');
|
|
819
840
|
if (nameNode) {
|
|
820
841
|
const varName = extractVarName(nameNode);
|
|
821
842
|
if (varName && !declarationTypeNodes.has(`${scope}\0${varName}`)) {
|
|
@@ -863,14 +884,13 @@ export const buildTypeEnv = (tree, language, options) => {
|
|
|
863
884
|
const declaredType = scopeEnv.get(varName);
|
|
864
885
|
if (!declaredType)
|
|
865
886
|
continue;
|
|
866
|
-
const ctorType = extractConstructorTypeName(node)
|
|
867
|
-
?? config.detectConstructorType?.(node, classNames);
|
|
887
|
+
const ctorType = extractConstructorTypeName(node) ?? config.detectConstructorType?.(node, classNames);
|
|
868
888
|
if (!ctorType || ctorType === declaredType)
|
|
869
889
|
continue;
|
|
870
890
|
// Unwrap wrapper types (e.g., C++ shared_ptr<Animal> → Animal) for an
|
|
871
891
|
// accurate isSubclassOf comparison. Language-specific via config hook.
|
|
872
892
|
const declTypeNode = declarationTypeNodes.get(`${scope}\0${varName}`);
|
|
873
|
-
const effectiveDeclaredType =
|
|
893
|
+
const effectiveDeclaredType = declTypeNode && config.unwrapDeclaredType
|
|
874
894
|
? (config.unwrapDeclaredType(declaredType, declTypeNode) ?? declaredType)
|
|
875
895
|
: declaredType;
|
|
876
896
|
if (ctorType !== effectiveDeclaredType) {
|
|
@@ -889,8 +909,7 @@ export const buildTypeEnv = (tree, language, options) => {
|
|
|
889
909
|
// Currently only C++ uses this locally; other languages rely on the SymbolTable path.
|
|
890
910
|
if (CLASS_CONTAINER_TYPES.has(node.type)) {
|
|
891
911
|
// Most languages use 'name' field; Kotlin uses a type_identifier child instead
|
|
892
|
-
const nameNode = node.childForFieldName('name')
|
|
893
|
-
?? findTypeIdentifierChild(node);
|
|
912
|
+
const nameNode = node.childForFieldName('name') ?? findTypeIdentifierChild(node);
|
|
894
913
|
if (nameNode)
|
|
895
914
|
localClassNames.add(nameNode.text);
|
|
896
915
|
}
|
|
@@ -914,7 +933,8 @@ export const buildTypeEnv = (tree, language, options) => {
|
|
|
914
933
|
// or narrow existing variables within a branch (null-check narrowing).
|
|
915
934
|
// Runs after Tier 0/1 so scopeEnv already contains the source variable's type.
|
|
916
935
|
// Conservative: extractor returns undefined when source type is unknown.
|
|
917
|
-
if (config.extractPatternBinding &&
|
|
936
|
+
if (config.extractPatternBinding &&
|
|
937
|
+
(!config.patternBindingNodeTypes || config.patternBindingNodeTypes.has(node.type))) {
|
|
918
938
|
// Ensure scopeEnv exists for pattern binding reads/writes
|
|
919
939
|
if (!env.has(scope))
|
|
920
940
|
env.set(scope, new Map());
|
|
@@ -1020,7 +1040,12 @@ export const buildTypeEnv = (tree, language, options) => {
|
|
|
1020
1040
|
if (!env.has(scope))
|
|
1021
1041
|
env.set(scope, new Map());
|
|
1022
1042
|
const scopeEnv = env.get(scope);
|
|
1023
|
-
config.extractForLoopBinding(node, {
|
|
1043
|
+
config.extractForLoopBinding(node, {
|
|
1044
|
+
scopeEnv,
|
|
1045
|
+
declarationTypeNodes,
|
|
1046
|
+
scope,
|
|
1047
|
+
returnTypeLookup,
|
|
1048
|
+
});
|
|
1024
1049
|
}
|
|
1025
1050
|
// Re-run the main fixpoint to resolve items that depended on loop variables.
|
|
1026
1051
|
// Only needed if replay actually produced new bindings.
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import { extractSimpleTypeName, extractVarName, resolveIterableElementType, methodToTypeArgPosition } from './shared.js';
|
|
2
|
-
const DECLARATION_NODE_TYPES = new Set([
|
|
3
|
-
'declaration',
|
|
4
|
-
]);
|
|
1
|
+
import { extractSimpleTypeName, extractVarName, resolveIterableElementType, methodToTypeArgPosition, } from './shared.js';
|
|
2
|
+
const DECLARATION_NODE_TYPES = new Set(['declaration']);
|
|
5
3
|
/** Smart pointer factory function names that create a typed object. */
|
|
6
|
-
const SMART_PTR_FACTORIES = new Set([
|
|
7
|
-
'make_shared', 'make_unique', 'make_shared_for_overwrite',
|
|
8
|
-
]);
|
|
4
|
+
const SMART_PTR_FACTORIES = new Set(['make_shared', 'make_unique', 'make_shared_for_overwrite']);
|
|
9
5
|
/** Smart pointer wrapper type names. When the declared type is a smart pointer,
|
|
10
6
|
* the inner template type is extracted for virtual dispatch comparison. */
|
|
11
7
|
const SMART_PTR_WRAPPERS = new Set(['shared_ptr', 'unique_ptr', 'weak_ptr']);
|
|
@@ -36,9 +32,7 @@ const extractDeclaration = (node, env) => {
|
|
|
36
32
|
if (!declarator)
|
|
37
33
|
return;
|
|
38
34
|
// init_declarator: Type x = value
|
|
39
|
-
const nameNode = declarator.type === 'init_declarator'
|
|
40
|
-
? declarator.childForFieldName('declarator')
|
|
41
|
-
: declarator;
|
|
35
|
+
const nameNode = declarator.type === 'init_declarator' ? declarator.childForFieldName('declarator') : declarator;
|
|
42
36
|
if (!nameNode)
|
|
43
37
|
return;
|
|
44
38
|
// Handle pointer/reference declarators
|
|
@@ -117,14 +111,14 @@ const extractInitializer = (node, env, classNames) => {
|
|
|
117
111
|
// or: call_expression > function: template_function (unqualified)
|
|
118
112
|
const templateFunc = func.type === 'template_function'
|
|
119
113
|
? func
|
|
120
|
-
:
|
|
121
|
-
? func.namedChildren.find((c) => c.type === 'template_function') ?? null
|
|
114
|
+
: func.type === 'qualified_identifier' || func.type === 'scoped_identifier'
|
|
115
|
+
? (func.namedChildren.find((c) => c.type === 'template_function') ?? null)
|
|
122
116
|
: null;
|
|
123
117
|
if (templateFunc) {
|
|
124
118
|
const nameNode = templateFunc.firstNamedChild;
|
|
125
119
|
if (nameNode) {
|
|
126
|
-
const funcName =
|
|
127
|
-
? nameNode.lastNamedChild?.text ?? ''
|
|
120
|
+
const funcName = nameNode.type === 'qualified_identifier' || nameNode.type === 'scoped_identifier'
|
|
121
|
+
? (nameNode.lastNamedChild?.text ?? '')
|
|
128
122
|
: nameNode.text;
|
|
129
123
|
if (SMART_PTR_FACTORIES.has(funcName)) {
|
|
130
124
|
const typeName = extractFirstTemplateTypeArg(templateFunc);
|
|
@@ -153,9 +147,10 @@ const extractParameter = (node, env) => {
|
|
|
153
147
|
typeNode = node.childForFieldName('type');
|
|
154
148
|
const declarator = node.childForFieldName('declarator');
|
|
155
149
|
if (declarator) {
|
|
156
|
-
nameNode =
|
|
157
|
-
|
|
158
|
-
|
|
150
|
+
nameNode =
|
|
151
|
+
declarator.type === 'pointer_declarator' || declarator.type === 'reference_declarator'
|
|
152
|
+
? declarator.firstNamedChild
|
|
153
|
+
: declarator;
|
|
159
154
|
}
|
|
160
155
|
}
|
|
161
156
|
else {
|
|
@@ -177,7 +172,9 @@ const scanConstructorBinding = (node) => {
|
|
|
177
172
|
if (!typeNode)
|
|
178
173
|
return undefined;
|
|
179
174
|
const typeText = typeNode.text;
|
|
180
|
-
if (typeText !== 'auto' &&
|
|
175
|
+
if (typeText !== 'auto' &&
|
|
176
|
+
typeText !== 'decltype(auto)' &&
|
|
177
|
+
typeNode.type !== 'placeholder_type_specifier')
|
|
181
178
|
return undefined;
|
|
182
179
|
const declarator = node.childForFieldName('declarator');
|
|
183
180
|
if (!declarator || declarator.type !== 'init_declarator')
|
|
@@ -196,7 +193,8 @@ const scanConstructorBinding = (node) => {
|
|
|
196
193
|
if (!nameNode)
|
|
197
194
|
return undefined;
|
|
198
195
|
const finalName = nameNode.type === 'pointer_declarator' || nameNode.type === 'reference_declarator'
|
|
199
|
-
? nameNode.firstNamedChild
|
|
196
|
+
? nameNode.firstNamedChild
|
|
197
|
+
: nameNode;
|
|
200
198
|
if (!finalName)
|
|
201
199
|
return undefined;
|
|
202
200
|
return { varName: finalName.text, calleeName: last.text };
|
|
@@ -207,7 +205,8 @@ const scanConstructorBinding = (node) => {
|
|
|
207
205
|
if (!nameNode)
|
|
208
206
|
return undefined;
|
|
209
207
|
const finalName = nameNode.type === 'pointer_declarator' || nameNode.type === 'reference_declarator'
|
|
210
|
-
? nameNode.firstNamedChild
|
|
208
|
+
? nameNode.firstNamedChild
|
|
209
|
+
: nameNode;
|
|
211
210
|
if (!finalName)
|
|
212
211
|
return undefined;
|
|
213
212
|
const varName = finalName.text;
|
|
@@ -224,8 +223,9 @@ const extractPendingAssignment = (node, scopeEnv) => {
|
|
|
224
223
|
return undefined;
|
|
225
224
|
// Only handle auto — typed declarations already resolved by extractDeclaration
|
|
226
225
|
const typeText = typeNode.text;
|
|
227
|
-
if (typeText !== 'auto' &&
|
|
228
|
-
|
|
226
|
+
if (typeText !== 'auto' &&
|
|
227
|
+
typeText !== 'decltype(auto)' &&
|
|
228
|
+
typeNode.type !== 'placeholder_type_specifier')
|
|
229
229
|
return undefined;
|
|
230
230
|
const declarator = node.childForFieldName('declarator');
|
|
231
231
|
if (!declarator || declarator.type !== 'init_declarator')
|
|
@@ -237,7 +237,8 @@ const extractPendingAssignment = (node, scopeEnv) => {
|
|
|
237
237
|
if (!nameNode)
|
|
238
238
|
return undefined;
|
|
239
239
|
const finalName = nameNode.type === 'pointer_declarator' || nameNode.type === 'reference_declarator'
|
|
240
|
-
? nameNode.firstNamedChild
|
|
240
|
+
? nameNode.firstNamedChild
|
|
241
|
+
: nameNode;
|
|
241
242
|
if (!finalName)
|
|
242
243
|
return undefined;
|
|
243
244
|
const lhs = extractVarName(finalName);
|
|
@@ -309,8 +310,9 @@ const extractCppElementTypeFromTypeNode = (typeNode, pos = 'last', depth = 0) =>
|
|
|
309
310
|
return pos === 'first' ? args[0] : args[args.length - 1];
|
|
310
311
|
}
|
|
311
312
|
// reference/pointer types: unwrap and recurse (vector<User>& → vector<User>)
|
|
312
|
-
if (typeNode.type === 'reference_type' ||
|
|
313
|
-
|
|
313
|
+
if (typeNode.type === 'reference_type' ||
|
|
314
|
+
typeNode.type === 'pointer_type' ||
|
|
315
|
+
typeNode.type === 'type_descriptor') {
|
|
314
316
|
const inner = typeNode.lastNamedChild;
|
|
315
317
|
if (inner)
|
|
316
318
|
return extractCppElementTypeFromTypeNode(inner, pos, depth + 1);
|
|
@@ -342,7 +344,8 @@ const findCppParamElementType = (iterableName, startNode, pos = 'last') => {
|
|
|
342
344
|
continue;
|
|
343
345
|
// Unwrap reference/pointer declarators: vector<User>& users → &users
|
|
344
346
|
let identNode = paramDeclarator;
|
|
345
|
-
if (identNode.type === 'reference_declarator' ||
|
|
347
|
+
if (identNode.type === 'reference_declarator' ||
|
|
348
|
+
identNode.type === 'pointer_declarator') {
|
|
346
349
|
identNode = identNode.firstNamedChild ?? identNode;
|
|
347
350
|
}
|
|
348
351
|
if (identNode.text !== iterableName)
|
|
@@ -393,10 +396,10 @@ const extractForLoopBinding = (node, { scopeEnv, declarationTypeNodes, scope })
|
|
|
393
396
|
if (!varName)
|
|
394
397
|
return;
|
|
395
398
|
// Check if the type is auto/placeholder — if not, use the explicit type directly
|
|
396
|
-
const isAuto = typeNode.type === 'placeholder_type_specifier'
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
399
|
+
const isAuto = typeNode.type === 'placeholder_type_specifier' ||
|
|
400
|
+
typeNode.text === 'auto' ||
|
|
401
|
+
typeNode.text === 'const auto' ||
|
|
402
|
+
typeNode.text === 'decltype(auto)';
|
|
400
403
|
if (!isAuto) {
|
|
401
404
|
// Explicit type: for (User& user : users) — extract directly
|
|
402
405
|
const typeName = extractSimpleTypeName(typeNode);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { findChild } from '../utils/ast-helpers.js';
|
|
2
|
-
import { extractSimpleTypeName, extractVarName, unwrapAwait, resolveIterableElementType, methodToTypeArgPosition, extractElementTypeFromString } from './shared.js';
|
|
2
|
+
import { extractSimpleTypeName, extractVarName, unwrapAwait, resolveIterableElementType, methodToTypeArgPosition, extractElementTypeFromString, } from './shared.js';
|
|
3
3
|
/** Known container property accessors that operate on the container itself (e.g., dict.Keys, dict.Values) */
|
|
4
4
|
const KNOWN_CONTAINER_PROPS = new Set(['Keys', 'Values']);
|
|
5
5
|
const DECLARATION_NODE_TYPES = new Set([
|
|
@@ -44,8 +44,8 @@ const extractDeclaration = (node, env) => {
|
|
|
44
44
|
// tree-sitter-c-sharp may put object_creation_expression as direct child
|
|
45
45
|
// or inside equals_value_clause depending on grammar version
|
|
46
46
|
if (declarators.length === 1) {
|
|
47
|
-
const initializer = findChild(declarators[0], 'object_creation_expression')
|
|
48
|
-
|
|
47
|
+
const initializer = findChild(declarators[0], 'object_creation_expression') ??
|
|
48
|
+
findChild(declarators[0], 'equals_value_clause')?.firstNamedChild;
|
|
49
49
|
if (initializer?.type === 'object_creation_expression') {
|
|
50
50
|
const ctorType = initializer.childForFieldName('type');
|
|
51
51
|
if (ctorType)
|
|
@@ -124,7 +124,9 @@ const scanConstructorBinding = (node) => {
|
|
|
124
124
|
value = child.firstNamedChild;
|
|
125
125
|
break;
|
|
126
126
|
}
|
|
127
|
-
if (child.type === 'invocation_expression' ||
|
|
127
|
+
if (child.type === 'invocation_expression' ||
|
|
128
|
+
child.type === 'object_creation_expression' ||
|
|
129
|
+
child.type === 'await_expression') {
|
|
128
130
|
value = child;
|
|
129
131
|
break;
|
|
130
132
|
}
|
|
@@ -148,9 +150,7 @@ const scanConstructorBinding = (node) => {
|
|
|
148
150
|
return undefined;
|
|
149
151
|
return { varName: nameNode.text, calleeName };
|
|
150
152
|
};
|
|
151
|
-
const FOR_LOOP_NODE_TYPES = new Set([
|
|
152
|
-
'foreach_statement',
|
|
153
|
-
]);
|
|
153
|
+
const FOR_LOOP_NODE_TYPES = new Set(['foreach_statement']);
|
|
154
154
|
/** Extract element type from a C# type annotation AST node.
|
|
155
155
|
* Handles generic_name (List<User>), array_type (User[]), nullable_type (?).
|
|
156
156
|
* `pos` selects which type arg: 'first' for keys, 'last' for values (default). */
|
|
@@ -328,9 +328,11 @@ const findCSharpIfConsequenceBlock = (expr) => {
|
|
|
328
328
|
}
|
|
329
329
|
return undefined;
|
|
330
330
|
}
|
|
331
|
-
if (current.type === 'block' ||
|
|
332
|
-
|
|
333
|
-
|
|
331
|
+
if (current.type === 'block' ||
|
|
332
|
+
current.type === 'method_declaration' ||
|
|
333
|
+
current.type === 'constructor_declaration' ||
|
|
334
|
+
current.type === 'local_function_statement' ||
|
|
335
|
+
current.type === 'lambda_expression')
|
|
334
336
|
return undefined;
|
|
335
337
|
current = current.parent;
|
|
336
338
|
}
|
|
@@ -408,7 +410,7 @@ const extractPatternBinding = (node, scopeEnv, declarationTypeNodes, scope) => {
|
|
|
408
410
|
}
|
|
409
411
|
// Null-check: `x != null` — binary_expression with != operator
|
|
410
412
|
if (node.type === 'binary_expression') {
|
|
411
|
-
const op = node.children.find(c => !c.isNamed && c.text === '!=');
|
|
413
|
+
const op = node.children.find((c) => !c.isNamed && c.text === '!=');
|
|
412
414
|
if (!op)
|
|
413
415
|
return undefined;
|
|
414
416
|
const left = node.namedChild(0);
|
|
@@ -419,7 +421,8 @@ const extractPatternBinding = (node, scopeEnv, declarationTypeNodes, scope) => {
|
|
|
419
421
|
if (left.type === 'identifier' && (right.type === 'null_literal' || right.text === 'null')) {
|
|
420
422
|
varNode = left;
|
|
421
423
|
}
|
|
422
|
-
else if (right.type === 'identifier' &&
|
|
424
|
+
else if (right.type === 'identifier' &&
|
|
425
|
+
(left.type === 'null_literal' || left.text === 'null')) {
|
|
423
426
|
varNode = right;
|
|
424
427
|
}
|
|
425
428
|
if (!varNode)
|
|
@@ -468,7 +471,9 @@ const extractPendingAssignment = (node, scopeEnv) => {
|
|
|
468
471
|
}
|
|
469
472
|
}
|
|
470
473
|
const valueNode = evc?.firstNamedChild ?? child.namedChild(child.namedChildCount - 1);
|
|
471
|
-
if (valueNode &&
|
|
474
|
+
if (valueNode &&
|
|
475
|
+
valueNode !== nameNode &&
|
|
476
|
+
(valueNode.type === 'identifier' || valueNode.type === 'simple_identifier')) {
|
|
472
477
|
return { kind: 'copy', lhs, rhs: valueNode.text };
|
|
473
478
|
}
|
|
474
479
|
// member_access_expression RHS → fieldAccess (a.Field)
|
|
@@ -545,7 +550,12 @@ const inferLiteralType = (node) => {
|
|
|
545
550
|
export const typeConfig = {
|
|
546
551
|
declarationNodeTypes: DECLARATION_NODE_TYPES,
|
|
547
552
|
forLoopNodeTypes: FOR_LOOP_NODE_TYPES,
|
|
548
|
-
patternBindingNodeTypes: new Set([
|
|
553
|
+
patternBindingNodeTypes: new Set([
|
|
554
|
+
'is_pattern_expression',
|
|
555
|
+
'declaration_pattern',
|
|
556
|
+
'recursive_pattern',
|
|
557
|
+
'binary_expression',
|
|
558
|
+
]),
|
|
549
559
|
extractDeclaration,
|
|
550
560
|
extractParameter,
|
|
551
561
|
scanConstructorBinding,
|
|
@@ -11,16 +11,14 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Credit: Type resolution approach adapted from @xFlaviews' PR #83.
|
|
13
13
|
*/
|
|
14
|
-
import { extractSimpleTypeName, extractVarName, extractElementTypeFromString, resolveIterableElementType } from './shared.js';
|
|
14
|
+
import { extractSimpleTypeName, extractVarName, extractElementTypeFromString, resolveIterableElementType, } from './shared.js';
|
|
15
15
|
import { findChild } from '../utils/ast-helpers.js';
|
|
16
16
|
// ── Node types ──────────────────────────────────────────────────────────
|
|
17
17
|
const DART_DECLARATION_NODE_TYPES = new Set([
|
|
18
18
|
'initialized_variable_definition',
|
|
19
19
|
'initialized_identifier',
|
|
20
20
|
]);
|
|
21
|
-
const DART_FOR_LOOP_NODE_TYPES = new Set([
|
|
22
|
-
'for_statement',
|
|
23
|
-
]);
|
|
21
|
+
const DART_FOR_LOOP_NODE_TYPES = new Set(['for_statement']);
|
|
24
22
|
function parseDartRHSChildren(children) {
|
|
25
23
|
let callee;
|
|
26
24
|
let member;
|
|
@@ -31,8 +29,8 @@ function parseDartRHSChildren(children) {
|
|
|
31
29
|
continue;
|
|
32
30
|
}
|
|
33
31
|
if (child.type === 'selector') {
|
|
34
|
-
const uas = findChild(child, 'unconditional_assignable_selector')
|
|
35
|
-
|
|
32
|
+
const uas = findChild(child, 'unconditional_assignable_selector') ??
|
|
33
|
+
findChild(child, 'conditional_assignable_selector');
|
|
36
34
|
if (uas) {
|
|
37
35
|
const id = findChild(uas, 'identifier');
|
|
38
36
|
if (id && !member)
|
|
@@ -323,8 +321,8 @@ const extractDartForLoopBinding = (node, ctx) => {
|
|
|
323
321
|
if (!foundIterable)
|
|
324
322
|
continue;
|
|
325
323
|
if (child.type === 'selector') {
|
|
326
|
-
const uas = findChild(child, 'unconditional_assignable_selector')
|
|
327
|
-
|
|
324
|
+
const uas = findChild(child, 'unconditional_assignable_selector') ??
|
|
325
|
+
findChild(child, 'conditional_assignable_selector');
|
|
328
326
|
if (uas) {
|
|
329
327
|
const id = findChild(uas, 'identifier');
|
|
330
328
|
if (id)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { extractSimpleTypeName, extractVarName, extractElementTypeFromString, extractGenericTypeArgs, resolveIterableElementType, methodToTypeArgPosition } 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',
|
|
@@ -59,7 +59,8 @@ const extractGoShortVarDeclaration = (node, env) => {
|
|
|
59
59
|
for (let i = 0; i < count; i++) {
|
|
60
60
|
let valueNode = rhsNodes[i];
|
|
61
61
|
// Unwrap &User{} — unary_expression (address-of) wrapping composite_literal
|
|
62
|
-
if (valueNode.type === 'unary_expression' &&
|
|
62
|
+
if (valueNode.type === 'unary_expression' &&
|
|
63
|
+
valueNode.firstNamedChild?.type === 'composite_literal') {
|
|
63
64
|
valueNode = valueNode.firstNamedChild;
|
|
64
65
|
}
|
|
65
66
|
// Go built-in new(User) — call_expression with 'new' callee and type argument
|
|
@@ -194,12 +195,12 @@ const scanConstructorBinding = (node) => {
|
|
|
194
195
|
return undefined;
|
|
195
196
|
return { varName: leftIds[0].text, calleeName };
|
|
196
197
|
};
|
|
197
|
-
const FOR_LOOP_NODE_TYPES = new Set([
|
|
198
|
-
'for_statement',
|
|
199
|
-
]);
|
|
198
|
+
const FOR_LOOP_NODE_TYPES = new Set(['for_statement']);
|
|
200
199
|
/** Go function/method node types that carry a parameter list. */
|
|
201
200
|
const GO_FUNCTION_NODE_TYPES = new Set([
|
|
202
|
-
'function_declaration',
|
|
201
|
+
'function_declaration',
|
|
202
|
+
'method_declaration',
|
|
203
|
+
'func_literal',
|
|
203
204
|
]);
|
|
204
205
|
/**
|
|
205
206
|
* Extract element type from a Go type annotation AST node.
|