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.
Files changed (186) hide show
  1. package/README.md +6 -5
  2. package/dist/cli/ai-context.d.ts +4 -1
  3. package/dist/cli/ai-context.js +19 -11
  4. package/dist/cli/analyze.d.ts +6 -0
  5. package/dist/cli/analyze.js +105 -251
  6. package/dist/cli/eval-server.js +20 -11
  7. package/dist/cli/index-repo.js +20 -22
  8. package/dist/cli/index.js +8 -7
  9. package/dist/cli/mcp.js +1 -1
  10. package/dist/cli/serve.js +29 -1
  11. package/dist/cli/setup.js +9 -9
  12. package/dist/cli/skill-gen.js +15 -9
  13. package/dist/cli/wiki.d.ts +2 -0
  14. package/dist/cli/wiki.js +141 -26
  15. package/dist/config/ignore-service.js +102 -22
  16. package/dist/config/supported-languages.d.ts +8 -42
  17. package/dist/config/supported-languages.js +8 -43
  18. package/dist/core/augmentation/engine.js +19 -7
  19. package/dist/core/embeddings/embedder.js +19 -15
  20. package/dist/core/embeddings/embedding-pipeline.js +6 -6
  21. package/dist/core/embeddings/http-client.js +3 -3
  22. package/dist/core/embeddings/text-generator.js +9 -24
  23. package/dist/core/embeddings/types.d.ts +1 -1
  24. package/dist/core/embeddings/types.js +1 -7
  25. package/dist/core/graph/graph.js +6 -2
  26. package/dist/core/graph/types.d.ts +9 -59
  27. package/dist/core/ingestion/ast-cache.js +3 -3
  28. package/dist/core/ingestion/call-processor.d.ts +20 -2
  29. package/dist/core/ingestion/call-processor.js +347 -144
  30. package/dist/core/ingestion/call-routing.js +10 -4
  31. package/dist/core/ingestion/call-sites/extract-language-call-site.d.ts +10 -0
  32. package/dist/core/ingestion/call-sites/extract-language-call-site.js +22 -0
  33. package/dist/core/ingestion/call-sites/java.d.ts +9 -0
  34. package/dist/core/ingestion/call-sites/java.js +30 -0
  35. package/dist/core/ingestion/cluster-enricher.js +6 -8
  36. package/dist/core/ingestion/cobol/cobol-copy-expander.js +10 -3
  37. package/dist/core/ingestion/cobol/cobol-preprocessor.js +287 -81
  38. package/dist/core/ingestion/cobol/jcl-parser.js +1 -1
  39. package/dist/core/ingestion/cobol/jcl-processor.js +1 -1
  40. package/dist/core/ingestion/cobol-processor.js +102 -56
  41. package/dist/core/ingestion/community-processor.js +21 -15
  42. package/dist/core/ingestion/entry-point-scoring.d.ts +1 -1
  43. package/dist/core/ingestion/entry-point-scoring.js +5 -6
  44. package/dist/core/ingestion/export-detection.js +32 -9
  45. package/dist/core/ingestion/field-extractor.d.ts +1 -1
  46. package/dist/core/ingestion/field-extractors/configs/c-cpp.js +8 -12
  47. package/dist/core/ingestion/field-extractors/configs/csharp.js +45 -2
  48. package/dist/core/ingestion/field-extractors/configs/dart.js +5 -3
  49. package/dist/core/ingestion/field-extractors/configs/go.js +3 -7
  50. package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +5 -0
  51. package/dist/core/ingestion/field-extractors/configs/helpers.js +14 -0
  52. package/dist/core/ingestion/field-extractors/configs/jvm.js +7 -7
  53. package/dist/core/ingestion/field-extractors/configs/php.js +9 -11
  54. package/dist/core/ingestion/field-extractors/configs/python.js +1 -1
  55. package/dist/core/ingestion/field-extractors/configs/ruby.js +4 -3
  56. package/dist/core/ingestion/field-extractors/configs/rust.js +2 -5
  57. package/dist/core/ingestion/field-extractors/configs/swift.js +9 -7
  58. package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +2 -6
  59. package/dist/core/ingestion/field-extractors/generic.d.ts +5 -2
  60. package/dist/core/ingestion/field-extractors/generic.js +6 -0
  61. package/dist/core/ingestion/field-extractors/typescript.d.ts +1 -1
  62. package/dist/core/ingestion/field-extractors/typescript.js +1 -1
  63. package/dist/core/ingestion/field-types.d.ts +4 -2
  64. package/dist/core/ingestion/filesystem-walker.js +3 -3
  65. package/dist/core/ingestion/framework-detection.d.ts +1 -1
  66. package/dist/core/ingestion/framework-detection.js +355 -85
  67. package/dist/core/ingestion/heritage-processor.d.ts +24 -0
  68. package/dist/core/ingestion/heritage-processor.js +99 -8
  69. package/dist/core/ingestion/import-processor.js +44 -15
  70. package/dist/core/ingestion/import-resolvers/csharp.js +7 -3
  71. package/dist/core/ingestion/import-resolvers/dart.js +1 -1
  72. package/dist/core/ingestion/import-resolvers/go.js +4 -2
  73. package/dist/core/ingestion/import-resolvers/jvm.js +4 -4
  74. package/dist/core/ingestion/import-resolvers/php.js +4 -4
  75. package/dist/core/ingestion/import-resolvers/python.js +1 -1
  76. package/dist/core/ingestion/import-resolvers/rust.js +9 -3
  77. package/dist/core/ingestion/import-resolvers/standard.d.ts +1 -1
  78. package/dist/core/ingestion/import-resolvers/standard.js +6 -5
  79. package/dist/core/ingestion/import-resolvers/swift.js +2 -1
  80. package/dist/core/ingestion/import-resolvers/utils.js +26 -7
  81. package/dist/core/ingestion/language-config.js +5 -4
  82. package/dist/core/ingestion/language-provider.d.ts +7 -2
  83. package/dist/core/ingestion/languages/c-cpp.js +106 -21
  84. package/dist/core/ingestion/languages/cobol.js +1 -1
  85. package/dist/core/ingestion/languages/csharp.js +96 -19
  86. package/dist/core/ingestion/languages/dart.js +23 -7
  87. package/dist/core/ingestion/languages/go.js +1 -1
  88. package/dist/core/ingestion/languages/index.d.ts +1 -1
  89. package/dist/core/ingestion/languages/index.js +2 -3
  90. package/dist/core/ingestion/languages/java.js +4 -1
  91. package/dist/core/ingestion/languages/kotlin.js +60 -13
  92. package/dist/core/ingestion/languages/php.js +102 -25
  93. package/dist/core/ingestion/languages/python.js +28 -5
  94. package/dist/core/ingestion/languages/ruby.js +56 -14
  95. package/dist/core/ingestion/languages/rust.js +55 -11
  96. package/dist/core/ingestion/languages/swift.js +112 -27
  97. package/dist/core/ingestion/languages/typescript.js +95 -19
  98. package/dist/core/ingestion/markdown-processor.js +5 -5
  99. package/dist/core/ingestion/method-extractors/configs/csharp.d.ts +2 -0
  100. package/dist/core/ingestion/method-extractors/configs/csharp.js +283 -0
  101. package/dist/core/ingestion/method-extractors/configs/jvm.d.ts +3 -0
  102. package/dist/core/ingestion/method-extractors/configs/jvm.js +326 -0
  103. package/dist/core/ingestion/method-extractors/generic.d.ts +5 -0
  104. package/dist/core/ingestion/method-extractors/generic.js +137 -0
  105. package/dist/core/ingestion/method-types.d.ts +61 -0
  106. package/dist/core/ingestion/method-types.js +2 -0
  107. package/dist/core/ingestion/mro-processor.d.ts +1 -1
  108. package/dist/core/ingestion/mro-processor.js +12 -8
  109. package/dist/core/ingestion/named-binding-processor.js +2 -2
  110. package/dist/core/ingestion/named-bindings/rust.js +3 -1
  111. package/dist/core/ingestion/parsing-processor.js +74 -24
  112. package/dist/core/ingestion/pipeline.d.ts +2 -1
  113. package/dist/core/ingestion/pipeline.js +208 -102
  114. package/dist/core/ingestion/process-processor.js +12 -10
  115. package/dist/core/ingestion/resolution-context.js +3 -3
  116. package/dist/core/ingestion/route-extractors/middleware.js +31 -7
  117. package/dist/core/ingestion/route-extractors/php.js +2 -1
  118. package/dist/core/ingestion/route-extractors/response-shapes.js +8 -4
  119. package/dist/core/ingestion/structure-processor.d.ts +1 -1
  120. package/dist/core/ingestion/structure-processor.js +4 -4
  121. package/dist/core/ingestion/symbol-table.d.ts +1 -1
  122. package/dist/core/ingestion/symbol-table.js +22 -6
  123. package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
  124. package/dist/core/ingestion/tree-sitter-queries.js +1 -1
  125. package/dist/core/ingestion/type-env.d.ts +2 -2
  126. package/dist/core/ingestion/type-env.js +75 -50
  127. package/dist/core/ingestion/type-extractors/c-cpp.js +33 -30
  128. package/dist/core/ingestion/type-extractors/csharp.js +24 -14
  129. package/dist/core/ingestion/type-extractors/dart.js +6 -8
  130. package/dist/core/ingestion/type-extractors/go.js +7 -6
  131. package/dist/core/ingestion/type-extractors/jvm.js +10 -21
  132. package/dist/core/ingestion/type-extractors/php.js +26 -13
  133. package/dist/core/ingestion/type-extractors/python.js +11 -15
  134. package/dist/core/ingestion/type-extractors/ruby.js +8 -3
  135. package/dist/core/ingestion/type-extractors/rust.js +6 -8
  136. package/dist/core/ingestion/type-extractors/shared.js +134 -50
  137. package/dist/core/ingestion/type-extractors/swift.js +16 -13
  138. package/dist/core/ingestion/type-extractors/typescript.js +23 -15
  139. package/dist/core/ingestion/utils/ast-helpers.d.ts +8 -8
  140. package/dist/core/ingestion/utils/ast-helpers.js +72 -35
  141. package/dist/core/ingestion/utils/call-analysis.d.ts +2 -0
  142. package/dist/core/ingestion/utils/call-analysis.js +96 -49
  143. package/dist/core/ingestion/utils/event-loop.js +1 -1
  144. package/dist/core/ingestion/workers/parse-worker.d.ts +7 -2
  145. package/dist/core/ingestion/workers/parse-worker.js +364 -84
  146. package/dist/core/ingestion/workers/worker-pool.js +5 -10
  147. package/dist/core/lbug/csv-generator.js +54 -15
  148. package/dist/core/lbug/lbug-adapter.d.ts +5 -0
  149. package/dist/core/lbug/lbug-adapter.js +86 -23
  150. package/dist/core/lbug/schema.d.ts +3 -6
  151. package/dist/core/lbug/schema.js +6 -30
  152. package/dist/core/run-analyze.d.ts +49 -0
  153. package/dist/core/run-analyze.js +257 -0
  154. package/dist/core/tree-sitter/parser-loader.d.ts +1 -1
  155. package/dist/core/tree-sitter/parser-loader.js +1 -1
  156. package/dist/core/wiki/cursor-client.js +2 -7
  157. package/dist/core/wiki/generator.js +38 -23
  158. package/dist/core/wiki/graph-queries.js +10 -10
  159. package/dist/core/wiki/html-viewer.js +7 -3
  160. package/dist/core/wiki/llm-client.d.ts +23 -2
  161. package/dist/core/wiki/llm-client.js +96 -26
  162. package/dist/core/wiki/prompts.js +7 -6
  163. package/dist/mcp/core/embedder.js +1 -1
  164. package/dist/mcp/core/lbug-adapter.d.ts +4 -1
  165. package/dist/mcp/core/lbug-adapter.js +17 -7
  166. package/dist/mcp/local/local-backend.js +247 -95
  167. package/dist/mcp/resources.js +14 -6
  168. package/dist/mcp/server.js +13 -5
  169. package/dist/mcp/staleness.js +5 -1
  170. package/dist/mcp/tools.js +100 -23
  171. package/dist/server/analyze-job.d.ts +53 -0
  172. package/dist/server/analyze-job.js +146 -0
  173. package/dist/server/analyze-worker.d.ts +13 -0
  174. package/dist/server/analyze-worker.js +59 -0
  175. package/dist/server/api.js +795 -44
  176. package/dist/server/git-clone.d.ts +25 -0
  177. package/dist/server/git-clone.js +91 -0
  178. package/dist/storage/git.js +1 -3
  179. package/dist/storage/repo-manager.d.ts +5 -2
  180. package/dist/storage/repo-manager.js +4 -4
  181. package/dist/types/pipeline.d.ts +1 -21
  182. package/dist/types/pipeline.js +1 -18
  183. package/hooks/claude/gitnexus-hook.cjs +52 -22
  184. package/package.json +3 -2
  185. package/dist/core/ingestion/utils/language-detection.d.ts +0 -9
  186. 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 (typeName.indexOf('|') === -1 && typeName.indexOf('?') === -1)
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.lookupFuzzy(name).some(def => def.type === 'Class' || def.type === 'Enum' || def.type === 'Struct');
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', 'string_literal',
345
- 'string_content', 'string_fragment', 'heredoc_body',
343
+ 'string',
344
+ 'string_literal',
345
+ 'string_content',
346
+ 'string_fragment',
347
+ 'heredoc_body',
346
348
  // Comments
347
- 'comment', 'line_comment', 'block_comment',
349
+ 'comment',
350
+ 'line_comment',
351
+ 'block_comment',
348
352
  // Numeric/boolean/null literals
349
- 'number', 'integer_literal', 'float_literal',
350
- 'true', 'false', 'null',
353
+ 'number',
354
+ 'integer_literal',
355
+ 'float_literal',
356
+ 'true',
357
+ 'false',
358
+ 'null',
351
359
  // Regex
352
- 'regex', 'regex_pattern',
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) || CLASS_CONTAINER_TYPES.has(child.type)
406
- || CALL_EXPRESSION_TYPES.has(child.type))
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
- ?? ((name) => symbolTable.lookupFuzzy(name).filter(d => CLASS_LIKE_TYPES.has(d.type)));
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
- ?? ((name) => symbolTable.lookupFuzzy(name).filter(d => CLASS_LIKE_TYPES.has(d.type)));
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.lookupFuzzyCallable(method)
517
- .filter(d => d.ownerId && classNodeIds.has(d.ownerId));
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.lookupFuzzyCallable(method)
525
- .filter(d => d.ownerId === nodeId);
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
- let typeNode = node.childForFieldName('type');
723
+ const typeNode = node.childForFieldName('type');
712
724
  if (typeNode) {
713
- const nameNode = node.childForFieldName('name')
714
- ?? node.childForFieldName('pattern')
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
- ?? (node.firstNamedChild?.type === 'identifier' ? node.firstNamedChild : null);
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 && (child.type === 'simple_identifier' || child.type === 'identifier')) {
744
+ if (!fallbackName &&
745
+ (child.type === 'simple_identifier' || child.type === 'identifier')) {
733
746
  fallbackName = child;
734
747
  }
735
- if (!fallbackType && (child.type === 'user_type' || child.type === 'type_identifier'
736
- || child.type === 'generic_type' || child.type === 'parameterized_type'
737
- || child.type === 'nullable_type')) {
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 = { scopeEnv, declarationTypeNodes, scope, returnTypeLookup };
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
- ?? node.childForFieldName('left')
818
- ?? node.childForFieldName('pattern');
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 = (declTypeNode && config.unwrapDeclaredType)
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 && (!config.patternBindingNodeTypes || config.patternBindingNodeTypes.has(node.type))) {
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, { scopeEnv, declarationTypeNodes, scope, returnTypeLookup });
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
- : (func.type === 'qualified_identifier' || func.type === 'scoped_identifier')
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 = (nameNode.type === 'qualified_identifier' || nameNode.type === 'scoped_identifier')
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 = declarator.type === 'pointer_declarator' || declarator.type === 'reference_declarator'
157
- ? declarator.firstNamedChild
158
- : declarator;
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' && typeText !== 'decltype(auto)' && typeNode.type !== 'placeholder_type_specifier')
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 : nameNode;
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 : nameNode;
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' && typeText !== 'decltype(auto)'
228
- && typeNode.type !== 'placeholder_type_specifier')
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 : nameNode;
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' || typeNode.type === 'pointer_type'
313
- || typeNode.type === 'type_descriptor') {
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' || identNode.type === 'pointer_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
- || typeNode.text === 'auto'
398
- || typeNode.text === 'const auto'
399
- || typeNode.text === 'decltype(auto)';
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
- ?? findChild(declarators[0], 'equals_value_clause')?.firstNamedChild;
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' || child.type === 'object_creation_expression' || child.type === 'await_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' || current.type === 'method_declaration'
332
- || current.type === 'constructor_declaration' || current.type === 'local_function_statement'
333
- || current.type === 'lambda_expression')
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' && (left.type === 'null_literal' || left.text === 'null')) {
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 && valueNode !== nameNode && (valueNode.type === 'identifier' || valueNode.type === 'simple_identifier')) {
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(['is_pattern_expression', 'declaration_pattern', 'recursive_pattern', 'binary_expression']),
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
- ?? findChild(child, 'conditional_assignable_selector');
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
- ?? findChild(child, 'conditional_assignable_selector');
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' && valueNode.firstNamedChild?.type === 'composite_literal') {
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', 'method_declaration', 'func_literal',
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.