gitnexus 1.4.8 → 1.4.9

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 (211) hide show
  1. package/README.md +7 -0
  2. package/dist/cli/index-repo.d.ts +15 -0
  3. package/dist/cli/index-repo.js +115 -0
  4. package/dist/cli/index.js +11 -2
  5. package/dist/cli/setup.js +12 -9
  6. package/dist/cli/wiki.d.ts +4 -0
  7. package/dist/cli/wiki.js +174 -53
  8. package/dist/config/supported-languages.d.ts +7 -5
  9. package/dist/config/supported-languages.js +6 -4
  10. package/dist/core/graph/graph.js +9 -1
  11. package/dist/core/graph/types.d.ts +10 -2
  12. package/dist/core/ingestion/call-processor.d.ts +18 -1
  13. package/dist/core/ingestion/call-processor.js +297 -38
  14. package/dist/core/ingestion/call-routing.d.ts +3 -18
  15. package/dist/core/ingestion/call-routing.js +0 -19
  16. package/dist/core/ingestion/cobol/cobol-copy-expander.d.ts +57 -0
  17. package/dist/core/ingestion/cobol/cobol-copy-expander.js +385 -0
  18. package/dist/core/ingestion/cobol/cobol-preprocessor.d.ts +210 -0
  19. package/dist/core/ingestion/cobol/cobol-preprocessor.js +1509 -0
  20. package/dist/core/ingestion/cobol/jcl-parser.d.ts +68 -0
  21. package/dist/core/ingestion/cobol/jcl-parser.js +217 -0
  22. package/dist/core/ingestion/cobol/jcl-processor.d.ts +33 -0
  23. package/dist/core/ingestion/cobol/jcl-processor.js +229 -0
  24. package/dist/core/ingestion/cobol-processor.d.ts +54 -0
  25. package/dist/core/ingestion/cobol-processor.js +1186 -0
  26. package/dist/core/ingestion/entry-point-scoring.d.ts +17 -0
  27. package/dist/core/ingestion/entry-point-scoring.js +18 -4
  28. package/dist/core/ingestion/export-detection.d.ts +47 -8
  29. package/dist/core/ingestion/export-detection.js +29 -50
  30. package/dist/core/ingestion/field-extractor.d.ts +29 -0
  31. package/dist/core/ingestion/field-extractor.js +25 -0
  32. package/dist/core/ingestion/field-extractors/configs/c-cpp.d.ts +3 -0
  33. package/dist/core/ingestion/field-extractors/configs/c-cpp.js +108 -0
  34. package/dist/core/ingestion/field-extractors/configs/csharp.d.ts +8 -0
  35. package/dist/core/ingestion/field-extractors/configs/csharp.js +73 -0
  36. package/dist/core/ingestion/field-extractors/configs/dart.d.ts +8 -0
  37. package/dist/core/ingestion/field-extractors/configs/dart.js +76 -0
  38. package/dist/core/ingestion/field-extractors/configs/go.d.ts +11 -0
  39. package/dist/core/ingestion/field-extractors/configs/go.js +64 -0
  40. package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +44 -0
  41. package/dist/core/ingestion/field-extractors/configs/helpers.js +134 -0
  42. package/dist/core/ingestion/field-extractors/configs/jvm.d.ts +3 -0
  43. package/dist/core/ingestion/field-extractors/configs/jvm.js +118 -0
  44. package/dist/core/ingestion/field-extractors/configs/php.d.ts +8 -0
  45. package/dist/core/ingestion/field-extractors/configs/php.js +67 -0
  46. package/dist/core/ingestion/field-extractors/configs/python.d.ts +12 -0
  47. package/dist/core/ingestion/field-extractors/configs/python.js +91 -0
  48. package/dist/core/ingestion/field-extractors/configs/ruby.d.ts +16 -0
  49. package/dist/core/ingestion/field-extractors/configs/ruby.js +75 -0
  50. package/dist/core/ingestion/field-extractors/configs/rust.d.ts +9 -0
  51. package/dist/core/ingestion/field-extractors/configs/rust.js +55 -0
  52. package/dist/core/ingestion/field-extractors/configs/swift.d.ts +8 -0
  53. package/dist/core/ingestion/field-extractors/configs/swift.js +63 -0
  54. package/dist/core/ingestion/field-extractors/configs/typescript-javascript.d.ts +3 -0
  55. package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +60 -0
  56. package/dist/core/ingestion/field-extractors/generic.d.ts +46 -0
  57. package/dist/core/ingestion/field-extractors/generic.js +111 -0
  58. package/dist/core/ingestion/field-extractors/typescript.d.ts +77 -0
  59. package/dist/core/ingestion/field-extractors/typescript.js +291 -0
  60. package/dist/core/ingestion/field-types.d.ts +59 -0
  61. package/dist/core/ingestion/field-types.js +2 -0
  62. package/dist/core/ingestion/framework-detection.d.ts +87 -0
  63. package/dist/core/ingestion/framework-detection.js +65 -2
  64. package/dist/core/ingestion/heritage-processor.js +15 -17
  65. package/dist/core/ingestion/import-processor.d.ts +9 -10
  66. package/dist/core/ingestion/import-processor.js +59 -14
  67. package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.d.ts +6 -9
  68. package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.js +20 -2
  69. package/dist/core/ingestion/import-resolvers/dart.d.ts +7 -0
  70. package/dist/core/ingestion/import-resolvers/dart.js +44 -0
  71. package/dist/core/ingestion/{resolvers → import-resolvers}/go.d.ts +4 -5
  72. package/dist/core/ingestion/{resolvers → import-resolvers}/go.js +17 -0
  73. package/dist/core/ingestion/{resolvers → import-resolvers}/jvm.d.ts +9 -1
  74. package/dist/core/ingestion/{resolvers → import-resolvers}/jvm.js +56 -0
  75. package/dist/core/ingestion/{resolvers → import-resolvers}/php.d.ts +6 -10
  76. package/dist/core/ingestion/{resolvers → import-resolvers}/php.js +7 -2
  77. package/dist/core/ingestion/{resolvers → import-resolvers}/python.d.ts +9 -3
  78. package/dist/core/ingestion/{resolvers → import-resolvers}/python.js +35 -3
  79. package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.d.ts +5 -2
  80. package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.js +7 -2
  81. package/dist/core/ingestion/{resolvers → import-resolvers}/rust.d.ts +5 -2
  82. package/dist/core/ingestion/{resolvers → import-resolvers}/rust.js +41 -2
  83. package/dist/core/ingestion/{resolvers → import-resolvers}/standard.d.ts +15 -7
  84. package/dist/core/ingestion/{resolvers → import-resolvers}/standard.js +22 -3
  85. package/dist/core/ingestion/import-resolvers/swift.d.ts +7 -0
  86. package/dist/core/ingestion/import-resolvers/swift.js +23 -0
  87. package/dist/core/ingestion/import-resolvers/types.d.ts +44 -0
  88. package/dist/core/ingestion/import-resolvers/types.js +6 -0
  89. package/dist/core/ingestion/{resolvers → import-resolvers}/utils.d.ts +0 -3
  90. package/dist/core/ingestion/{resolvers → import-resolvers}/utils.js +0 -9
  91. package/dist/core/ingestion/language-config.d.ts +4 -1
  92. package/dist/core/ingestion/language-provider.d.ts +121 -0
  93. package/dist/core/ingestion/language-provider.js +24 -0
  94. package/dist/core/ingestion/languages/c-cpp.d.ts +12 -0
  95. package/dist/core/ingestion/languages/c-cpp.js +71 -0
  96. package/dist/core/ingestion/languages/cobol.d.ts +1 -0
  97. package/dist/core/ingestion/languages/cobol.js +26 -0
  98. package/dist/core/ingestion/languages/csharp.d.ts +8 -0
  99. package/dist/core/ingestion/languages/csharp.js +49 -0
  100. package/dist/core/ingestion/languages/dart.d.ts +12 -0
  101. package/dist/core/ingestion/languages/dart.js +58 -0
  102. package/dist/core/ingestion/languages/go.d.ts +11 -0
  103. package/dist/core/ingestion/languages/go.js +28 -0
  104. package/dist/core/ingestion/languages/index.d.ts +38 -0
  105. package/dist/core/ingestion/languages/index.js +63 -0
  106. package/dist/core/ingestion/languages/java.d.ts +9 -0
  107. package/dist/core/ingestion/languages/java.js +29 -0
  108. package/dist/core/ingestion/languages/kotlin.d.ts +9 -0
  109. package/dist/core/ingestion/languages/kotlin.js +53 -0
  110. package/dist/core/ingestion/languages/php.d.ts +8 -0
  111. package/dist/core/ingestion/languages/php.js +145 -0
  112. package/dist/core/ingestion/languages/python.d.ts +12 -0
  113. package/dist/core/ingestion/languages/python.js +39 -0
  114. package/dist/core/ingestion/languages/ruby.d.ts +9 -0
  115. package/dist/core/ingestion/languages/ruby.js +44 -0
  116. package/dist/core/ingestion/languages/rust.d.ts +12 -0
  117. package/dist/core/ingestion/languages/rust.js +44 -0
  118. package/dist/core/ingestion/languages/swift.d.ts +12 -0
  119. package/dist/core/ingestion/languages/swift.js +133 -0
  120. package/dist/core/ingestion/languages/typescript.d.ts +10 -0
  121. package/dist/core/ingestion/languages/typescript.js +60 -0
  122. package/dist/core/ingestion/mro-processor.js +14 -15
  123. package/dist/core/ingestion/{named-binding-extraction.d.ts → named-binding-processor.d.ts} +0 -9
  124. package/dist/core/ingestion/named-binding-processor.js +42 -0
  125. package/dist/core/ingestion/named-bindings/csharp.d.ts +3 -0
  126. package/dist/core/ingestion/named-bindings/csharp.js +37 -0
  127. package/dist/core/ingestion/named-bindings/java.d.ts +3 -0
  128. package/dist/core/ingestion/named-bindings/java.js +29 -0
  129. package/dist/core/ingestion/named-bindings/kotlin.d.ts +3 -0
  130. package/dist/core/ingestion/named-bindings/kotlin.js +36 -0
  131. package/dist/core/ingestion/named-bindings/php.d.ts +3 -0
  132. package/dist/core/ingestion/named-bindings/php.js +61 -0
  133. package/dist/core/ingestion/named-bindings/python.d.ts +3 -0
  134. package/dist/core/ingestion/named-bindings/python.js +49 -0
  135. package/dist/core/ingestion/named-bindings/rust.d.ts +3 -0
  136. package/dist/core/ingestion/named-bindings/rust.js +64 -0
  137. package/dist/core/ingestion/named-bindings/types.d.ts +16 -0
  138. package/dist/core/ingestion/named-bindings/types.js +6 -0
  139. package/dist/core/ingestion/named-bindings/typescript.d.ts +3 -0
  140. package/dist/core/ingestion/named-bindings/typescript.js +58 -0
  141. package/dist/core/ingestion/parsing-processor.d.ts +5 -1
  142. package/dist/core/ingestion/parsing-processor.js +115 -16
  143. package/dist/core/ingestion/pipeline.js +925 -424
  144. package/dist/core/ingestion/resolution-context.js +1 -1
  145. package/dist/core/ingestion/route-extractors/expo.d.ts +1 -0
  146. package/dist/core/ingestion/route-extractors/expo.js +36 -0
  147. package/dist/core/ingestion/route-extractors/middleware.d.ts +47 -0
  148. package/dist/core/ingestion/route-extractors/middleware.js +143 -0
  149. package/dist/core/ingestion/route-extractors/nextjs.d.ts +3 -0
  150. package/dist/core/ingestion/route-extractors/nextjs.js +76 -0
  151. package/dist/core/ingestion/route-extractors/php.d.ts +7 -0
  152. package/dist/core/ingestion/route-extractors/php.js +21 -0
  153. package/dist/core/ingestion/route-extractors/response-shapes.d.ts +20 -0
  154. package/dist/core/ingestion/route-extractors/response-shapes.js +290 -0
  155. package/dist/core/ingestion/tree-sitter-queries.d.ts +8 -7
  156. package/dist/core/ingestion/tree-sitter-queries.js +231 -9
  157. package/dist/core/ingestion/type-env.d.ts +14 -17
  158. package/dist/core/ingestion/type-env.js +66 -14
  159. package/dist/core/ingestion/type-extractors/c-cpp.d.ts +1 -1
  160. package/dist/core/ingestion/type-extractors/csharp.js +1 -1
  161. package/dist/core/ingestion/type-extractors/dart.d.ts +15 -0
  162. package/dist/core/ingestion/type-extractors/dart.js +371 -0
  163. package/dist/core/ingestion/type-extractors/jvm.js +1 -1
  164. package/dist/core/ingestion/type-extractors/shared.d.ts +1 -13
  165. package/dist/core/ingestion/type-extractors/shared.js +9 -102
  166. package/dist/core/ingestion/type-extractors/swift.js +334 -4
  167. package/dist/core/ingestion/type-extractors/types.d.ts +3 -1
  168. package/dist/core/ingestion/{ast-helpers.d.ts → utils/ast-helpers.d.ts} +16 -13
  169. package/dist/core/ingestion/{ast-helpers.js → utils/ast-helpers.js} +111 -32
  170. package/dist/core/ingestion/{call-analysis.js → utils/call-analysis.js} +37 -0
  171. package/dist/core/ingestion/utils/event-loop.d.ts +5 -0
  172. package/dist/core/ingestion/utils/event-loop.js +5 -0
  173. package/dist/core/ingestion/utils/language-detection.d.ts +9 -0
  174. package/dist/core/ingestion/utils/language-detection.js +70 -0
  175. package/dist/core/ingestion/utils/verbose.d.ts +1 -0
  176. package/dist/core/ingestion/utils/verbose.js +7 -0
  177. package/dist/core/ingestion/workers/parse-worker.d.ts +43 -2
  178. package/dist/core/ingestion/workers/parse-worker.js +361 -150
  179. package/dist/core/lbug/csv-generator.js +34 -1
  180. package/dist/core/lbug/lbug-adapter.js +6 -0
  181. package/dist/core/lbug/schema.d.ts +5 -3
  182. package/dist/core/lbug/schema.js +39 -2
  183. package/dist/core/tree-sitter/parser-loader.js +7 -1
  184. package/dist/core/wiki/cursor-client.d.ts +31 -0
  185. package/dist/core/wiki/cursor-client.js +127 -0
  186. package/dist/core/wiki/generator.d.ts +28 -9
  187. package/dist/core/wiki/generator.js +115 -18
  188. package/dist/core/wiki/graph-queries.d.ts +4 -0
  189. package/dist/core/wiki/graph-queries.js +7 -1
  190. package/dist/core/wiki/llm-client.d.ts +2 -0
  191. package/dist/core/wiki/llm-client.js +8 -4
  192. package/dist/core/wiki/prompts.d.ts +3 -3
  193. package/dist/core/wiki/prompts.js +6 -0
  194. package/dist/mcp/core/lbug-adapter.d.ts +5 -0
  195. package/dist/mcp/core/lbug-adapter.js +11 -1
  196. package/dist/mcp/local/local-backend.d.ts +16 -5
  197. package/dist/mcp/local/local-backend.js +711 -74
  198. package/dist/mcp/tools.js +71 -2
  199. package/dist/storage/repo-manager.d.ts +3 -0
  200. package/package.json +17 -16
  201. package/dist/core/ingestion/import-resolution.d.ts +0 -101
  202. package/dist/core/ingestion/import-resolution.js +0 -251
  203. package/dist/core/ingestion/named-binding-extraction.js +0 -373
  204. package/dist/core/ingestion/resolvers/index.d.ts +0 -18
  205. package/dist/core/ingestion/resolvers/index.js +0 -13
  206. package/dist/core/ingestion/type-extractors/index.d.ts +0 -22
  207. package/dist/core/ingestion/type-extractors/index.js +0 -31
  208. package/dist/core/ingestion/utils.d.ts +0 -20
  209. package/dist/core/ingestion/utils.js +0 -242
  210. package/scripts/patch-tree-sitter-swift.cjs +0 -74
  211. /package/dist/core/ingestion/{call-analysis.d.ts → utils/call-analysis.d.ts} +0 -0
@@ -1,8 +1,12 @@
1
- import { FUNCTION_NODE_TYPES, extractFunctionName, CLASS_CONTAINER_TYPES, CALL_EXPRESSION_TYPES, isBuiltInOrNoise } from './utils.js';
2
- import { typeConfigs, TYPED_PARAMETER_TYPES } from './type-extractors/index.js';
1
+ import { FUNCTION_NODE_TYPES, extractFunctionName, CLASS_CONTAINER_TYPES } from './utils/ast-helpers.js';
2
+ import { CALL_EXPRESSION_TYPES } from './utils/call-analysis.js';
3
+ import { TYPED_PARAMETER_TYPES } from './type-extractors/shared.js';
4
+ import { getProvider } from './languages/index.js';
3
5
  import { extractSimpleTypeName, extractVarName, stripNullable, extractReturnTypeName } from './type-extractors/shared.js';
4
6
  /** File-level scope key */
5
7
  const FILE_SCOPE = '';
8
+ /** Shared empty map for files with no file-scope bindings. */
9
+ const EMPTY_FILE_SCOPE = new Map();
6
10
  /** Fallback for languages where class names aren't in a 'name' field (e.g. Kotlin uses type_identifier). */
7
11
  const findTypeIdentifierChild = (node) => {
8
12
  for (let i = 0; i < node.childCount; i++) {
@@ -49,7 +53,7 @@ const fastStripNullable = (typeName) => {
49
53
  : stripNullable(typeName);
50
54
  };
51
55
  /** Implementation of the lookup logic — shared between TypeEnvironment and the legacy export. */
52
- const lookupInEnv = (env, varName, callNode, patternOverrides) => {
56
+ const lookupInEnv = (env, varName, callNode, patternOverrides, enclosingFunctionFinder) => {
53
57
  // Self/this receiver: resolve to enclosing class name via AST walk
54
58
  if (varName === 'self' || varName === 'this' || varName === '$this') {
55
59
  return findEnclosingClassName(callNode);
@@ -60,7 +64,7 @@ const lookupInEnv = (env, varName, callNode, patternOverrides) => {
60
64
  return findEnclosingParentClassName(callNode);
61
65
  }
62
66
  // Determine the enclosing function scope for the call
63
- const scopeKey = findEnclosingScopeKey(callNode);
67
+ const scopeKey = findEnclosingScopeKey(callNode, enclosingFunctionFinder);
64
68
  // Check position-indexed pattern overrides first (e.g., Kotlin when/is smart casts).
65
69
  // These take priority over flat scopeEnv because they represent per-branch narrowing.
66
70
  if (scopeKey && patternOverrides) {
@@ -88,21 +92,31 @@ const lookupInEnv = (env, varName, callNode, patternOverrides) => {
88
92
  const raw = fileEnv?.get(varName);
89
93
  return raw ? fastStripNullable(raw) : undefined;
90
94
  };
95
+ /** Per-file memoization caches for expensive parent-walk functions.
96
+ * Cleared at the start of each buildTypeEnv call (one call per file). */
97
+ const enclosingClassNameCache = new Map();
98
+ const enclosingParentClassNameCache = new Map();
91
99
  /**
92
100
  * Walk up the AST from a node to find the enclosing class/module name.
93
101
  * Used to resolve `self`/`this` receivers to their containing type.
102
+ * Memoized per-file: cache is cleared at buildTypeEnv entry.
94
103
  */
95
104
  const findEnclosingClassName = (node) => {
105
+ if (enclosingClassNameCache.has(node))
106
+ return enclosingClassNameCache.get(node);
96
107
  let current = node.parent;
97
108
  while (current) {
98
109
  if (CLASS_CONTAINER_TYPES.has(current.type)) {
99
110
  const nameNode = current.childForFieldName('name')
100
111
  ?? findTypeIdentifierChild(current);
101
- if (nameNode)
112
+ if (nameNode) {
113
+ enclosingClassNameCache.set(node, nameNode.text);
102
114
  return nameNode.text;
115
+ }
103
116
  }
104
117
  current = current.parent;
105
118
  }
119
+ enclosingClassNameCache.set(node, undefined);
106
120
  return undefined;
107
121
  };
108
122
  /** Keywords that refer to the current instance across languages. */
@@ -138,13 +152,18 @@ const substituteThisReceiver = (item, node) => {
138
152
  * - Swift: unnamed `inheritance_specifier` child → user_type → type_identifier
139
153
  */
140
154
  const findEnclosingParentClassName = (node) => {
155
+ if (enclosingParentClassNameCache.has(node))
156
+ return enclosingParentClassNameCache.get(node);
141
157
  let current = node.parent;
142
158
  while (current) {
143
159
  if (CLASS_CONTAINER_TYPES.has(current.type)) {
144
- return extractParentClassFromNode(current);
160
+ const result = extractParentClassFromNode(current);
161
+ enclosingParentClassNameCache.set(node, result);
162
+ return result;
145
163
  }
146
164
  current = current.parent;
147
165
  }
166
+ enclosingParentClassNameCache.set(node, undefined);
148
167
  return undefined;
149
168
  };
150
169
  /** Extract the parent/superclass name from a class declaration AST node. */
@@ -251,8 +270,12 @@ const extractParentClassFromNode = (classNode) => {
251
270
  }
252
271
  return undefined;
253
272
  };
254
- /** Find the enclosing function name for scope lookup. */
255
- const findEnclosingScopeKey = (node) => {
273
+ /** Find the enclosing function name for scope lookup.
274
+ * When an `enclosingFunctionFinder` hook is provided (from the language provider),
275
+ * it is consulted for each ancestor before the default FUNCTION_NODE_TYPES check.
276
+ * This handles languages like Dart where the function body is a sibling of the
277
+ * signature instead of a child. */
278
+ const findEnclosingScopeKey = (node, enclosingFunctionFinder) => {
256
279
  let current = node.parent;
257
280
  while (current) {
258
281
  if (FUNCTION_NODE_TYPES.has(current.type)) {
@@ -260,6 +283,15 @@ const findEnclosingScopeKey = (node) => {
260
283
  if (funcName)
261
284
  return `${funcName}@${current.startIndex}`;
262
285
  }
286
+ // Language-specific hook (e.g., Dart function_body → sibling function_signature)
287
+ if (enclosingFunctionFinder) {
288
+ const result = enclosingFunctionFinder(current);
289
+ if (result) {
290
+ const sigNode = current.previousSibling;
291
+ const startIdx = sigNode?.startIndex ?? current.startIndex;
292
+ return `${result.funcName}@${startIdx}`;
293
+ }
294
+ }
263
295
  current = current.parent;
264
296
  }
265
297
  return undefined;
@@ -530,7 +562,10 @@ const resolveFixpointBindings = (pendingItems, env, returnTypeLookup, symbolTabl
530
562
  let typeName;
531
563
  switch (item.kind) {
532
564
  case 'callResult':
533
- typeName = returnTypeLookup.lookupReturnType(item.callee);
565
+ // Phase 9: Prefer FQN lookup when available for higher precision
566
+ typeName = item.calleeFqn
567
+ ? returnTypeLookup.lookupReturnType(item.calleeFqn)
568
+ : returnTypeLookup.lookupReturnType(item.callee);
534
569
  break;
535
570
  case 'copy':
536
571
  typeName = scopeEnv.get(item.rhs) ?? env.get(FILE_SCOPE)?.get(item.rhs);
@@ -580,6 +615,9 @@ function seedImportedBindings(env, importedBindings) {
580
615
  }
581
616
  }
582
617
  export const buildTypeEnv = (tree, language, options) => {
618
+ // Clear per-file memoization caches from the previous file.
619
+ enclosingClassNameCache.clear();
620
+ enclosingParentClassNameCache.clear();
583
621
  const symbolTable = options?.symbolTable;
584
622
  const parentMap = options?.parentMap;
585
623
  const env = new Map();
@@ -590,7 +628,8 @@ export const buildTypeEnv = (tree, language, options) => {
590
628
  const constructorTypeMap = new Map();
591
629
  const localClassNames = new Set();
592
630
  const classNames = createClassNameLookup(localClassNames, symbolTable);
593
- const config = typeConfigs[language];
631
+ const provider = getProvider(language);
632
+ const config = provider.typeConfig;
594
633
  const bindings = [];
595
634
  // Build ReturnTypeLookup: SymbolTable is authoritative when it has an unambiguous match.
596
635
  // Cross-file importedReturnTypes are consulted ONLY when SymbolTable has 0 matches.
@@ -599,7 +638,7 @@ export const buildTypeEnv = (tree, language, options) => {
599
638
  lookupReturnType(callee) {
600
639
  // SymbolTable is authoritative when it has an unambiguous match
601
640
  if (symbolTable) {
602
- if (isBuiltInOrNoise(callee))
641
+ if (provider.isBuiltInName(callee))
603
642
  return undefined;
604
643
  const callables = symbolTable.lookupFuzzyCallable(callee);
605
644
  if (callables.length === 1) {
@@ -616,7 +655,7 @@ export const buildTypeEnv = (tree, language, options) => {
616
655
  },
617
656
  lookupRawReturnType(callee) {
618
657
  if (symbolTable) {
619
- if (isBuiltInOrNoise(callee))
658
+ if (provider.isBuiltInName(callee))
620
659
  return undefined;
621
660
  const callables = symbolTable.lookupFuzzyCallable(callee);
622
661
  if (callables.length === 1)
@@ -760,6 +799,18 @@ export const buildTypeEnv = (tree, language, options) => {
760
799
  }
761
800
  }
762
801
  }
802
+ // Swift: property_declaration has type_annotation as a direct child (not a 'type' field).
803
+ // Extract the inner type node (array_type, user_type, etc.) for declarationTypeNodes.
804
+ if (!typeNode) {
805
+ for (let i = 0; i < node.namedChildCount; i++) {
806
+ const c = node.namedChild(i);
807
+ if (c?.type === 'type_annotation') {
808
+ // Use the inner type (array_type, user_type) rather than the annotation wrapper
809
+ typeNode = c.firstNamedChild ?? c;
810
+ break;
811
+ }
812
+ }
813
+ }
763
814
  }
764
815
  if (typeNode) {
765
816
  const nameNode = node.childForFieldName('name')
@@ -982,9 +1033,10 @@ export const buildTypeEnv = (tree, language, options) => {
982
1033
  }
983
1034
  }
984
1035
  return {
985
- lookup: (varName, callNode) => lookupInEnv(env, varName, callNode, patternOverrides),
1036
+ lookup: (varName, callNode) => lookupInEnv(env, varName, callNode, patternOverrides, options?.enclosingFunctionFinder),
986
1037
  constructorBindings: bindings,
987
- env,
1038
+ fileScope: () => env.get(FILE_SCOPE) ?? EMPTY_FILE_SCOPE,
1039
+ allScopes: () => env,
988
1040
  constructorTypeMap,
989
1041
  };
990
1042
  };
@@ -1,4 +1,4 @@
1
- import type { SyntaxNode } from '../utils.js';
1
+ import type { SyntaxNode } from '../utils/ast-helpers.js';
2
2
  import type { LanguageTypeConfig } from './types.js';
3
3
  /** Extract the first type name from a template_argument_list child.
4
4
  * Unwraps type_descriptor wrappers common in tree-sitter-cpp ASTs.
@@ -1,5 +1,5 @@
1
+ import { findChild } from '../utils/ast-helpers.js';
1
2
  import { extractSimpleTypeName, extractVarName, unwrapAwait, resolveIterableElementType, methodToTypeArgPosition, extractElementTypeFromString } from './shared.js';
2
- import { findChild } from '../resolvers/utils.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([
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Dart type extractor — full implementation following type-resolution-system.md.
3
+ *
4
+ * Tier 0: Explicit type annotations (User user = ...)
5
+ * Tier 0b: For-loop element types (for (var u in users))
6
+ * Tier 1: Constructor/initializer inference (var user = User())
7
+ * Tier 2: Assignment chain propagation (copy, fieldAccess, callResult, methodCallResult)
8
+ *
9
+ * Handles tree-sitter-dart's flat sibling AST structure:
10
+ * identifier + selector + selector (not nested call_expression).
11
+ *
12
+ * Credit: Type resolution approach adapted from @xFlaviews' PR #83.
13
+ */
14
+ import type { LanguageTypeConfig } from './types.js';
15
+ export declare const typeConfig: LanguageTypeConfig;
@@ -0,0 +1,371 @@
1
+ /**
2
+ * Dart type extractor — full implementation following type-resolution-system.md.
3
+ *
4
+ * Tier 0: Explicit type annotations (User user = ...)
5
+ * Tier 0b: For-loop element types (for (var u in users))
6
+ * Tier 1: Constructor/initializer inference (var user = User())
7
+ * Tier 2: Assignment chain propagation (copy, fieldAccess, callResult, methodCallResult)
8
+ *
9
+ * Handles tree-sitter-dart's flat sibling AST structure:
10
+ * identifier + selector + selector (not nested call_expression).
11
+ *
12
+ * Credit: Type resolution approach adapted from @xFlaviews' PR #83.
13
+ */
14
+ import { extractSimpleTypeName, extractVarName, extractElementTypeFromString, resolveIterableElementType } from './shared.js';
15
+ import { findChild } from '../utils/ast-helpers.js';
16
+ // ── Node types ──────────────────────────────────────────────────────────
17
+ const DART_DECLARATION_NODE_TYPES = new Set([
18
+ 'initialized_variable_definition',
19
+ 'initialized_identifier',
20
+ ]);
21
+ const DART_FOR_LOOP_NODE_TYPES = new Set([
22
+ 'for_statement',
23
+ ]);
24
+ function parseDartRHSChildren(children) {
25
+ let callee;
26
+ let member;
27
+ let hasCall = false;
28
+ for (const child of children) {
29
+ if (child.type === 'identifier' && !callee) {
30
+ callee = child.text;
31
+ continue;
32
+ }
33
+ if (child.type === 'selector') {
34
+ const uas = findChild(child, 'unconditional_assignable_selector')
35
+ ?? findChild(child, 'conditional_assignable_selector');
36
+ if (uas) {
37
+ const id = findChild(uas, 'identifier');
38
+ if (id && !member)
39
+ member = id.text;
40
+ continue;
41
+ }
42
+ if (findChild(child, 'argument_part')) {
43
+ hasCall = true;
44
+ continue;
45
+ }
46
+ }
47
+ }
48
+ return { callee, member, hasCall };
49
+ }
50
+ function parseDartRHS(node) {
51
+ const rhsChildren = [];
52
+ let foundEquals = false;
53
+ for (let i = 0; i < node.childCount; i++) {
54
+ const child = node.child(i);
55
+ if (!child)
56
+ continue;
57
+ if (!child.isNamed && child.text === '=') {
58
+ foundEquals = true;
59
+ continue;
60
+ }
61
+ if (foundEquals)
62
+ rhsChildren.push(child);
63
+ }
64
+ if (rhsChildren.length === 0)
65
+ return { hasCall: false, isAwait: false };
66
+ const first = rhsChildren[0];
67
+ if (first.type === 'unary_expression') {
68
+ const awaitExpr = findChild(first, 'await_expression');
69
+ if (awaitExpr) {
70
+ const innerChildren = [];
71
+ for (let i = 0; i < awaitExpr.namedChildCount; i++) {
72
+ const c = awaitExpr.namedChild(i);
73
+ if (c && c.type !== 'await')
74
+ innerChildren.push(c);
75
+ }
76
+ return { ...parseDartRHSChildren(innerChildren), isAwait: true };
77
+ }
78
+ }
79
+ return { ...parseDartRHSChildren(rhsChildren), isAwait: false };
80
+ }
81
+ function hasDartTypeAnnotation(node) {
82
+ return !!(findChild(node, 'type_identifier') || findChild(node, 'nullable_type'));
83
+ }
84
+ // ── Tier 0: Explicit Type Annotations ───────────────────────────────────
85
+ const extractDartDeclaration = (node, env) => {
86
+ // initialized_identifier: comma-separated variable (String a, b, c) — type is on parent
87
+ if (node.type === 'initialized_identifier') {
88
+ const parent = node.parent;
89
+ if (!parent)
90
+ return;
91
+ let typeNode = findChild(parent, 'type_identifier');
92
+ if (!typeNode) {
93
+ const nullable = findChild(parent, 'nullable_type');
94
+ if (nullable)
95
+ typeNode = findChild(nullable, 'type_identifier');
96
+ }
97
+ if (!typeNode)
98
+ return;
99
+ const typeName = extractSimpleTypeName(typeNode);
100
+ if (!typeName || typeName === 'dynamic')
101
+ return;
102
+ const nameNode = findChild(node, 'identifier');
103
+ if (!nameNode)
104
+ return;
105
+ const varName = extractVarName(nameNode);
106
+ if (varName)
107
+ env.set(varName, typeName);
108
+ return;
109
+ }
110
+ let typeNode = findChild(node, 'type_identifier');
111
+ if (!typeNode) {
112
+ const nullable = findChild(node, 'nullable_type');
113
+ if (nullable)
114
+ typeNode = findChild(nullable, 'type_identifier');
115
+ }
116
+ if (!typeNode)
117
+ return;
118
+ const typeName = extractSimpleTypeName(typeNode);
119
+ if (!typeName || typeName === 'dynamic')
120
+ return;
121
+ const nameNode = node.childForFieldName('name');
122
+ if (!nameNode)
123
+ return;
124
+ const varName = extractVarName(nameNode);
125
+ if (varName)
126
+ env.set(varName, typeName);
127
+ };
128
+ const extractDartParameter = (node, env) => {
129
+ let typeNode = findChild(node, 'type_identifier');
130
+ if (!typeNode) {
131
+ const nullable = findChild(node, 'nullable_type');
132
+ if (nullable)
133
+ typeNode = findChild(nullable, 'type_identifier');
134
+ }
135
+ if (!typeNode)
136
+ return;
137
+ const typeName = extractSimpleTypeName(typeNode);
138
+ if (!typeName || typeName === 'dynamic')
139
+ return;
140
+ const nameNode = node.childForFieldName('name');
141
+ if (!nameNode)
142
+ return;
143
+ const varName = extractVarName(nameNode);
144
+ if (varName)
145
+ env.set(varName, typeName);
146
+ };
147
+ // ── Tier 1: Constructor / Initializer Inference ─────────────────────────
148
+ const extractDartInitializer = (node, env, classNames) => {
149
+ if (node.type !== 'initialized_variable_definition')
150
+ return;
151
+ if (hasDartTypeAnnotation(node))
152
+ return;
153
+ const nameNode = node.childForFieldName('name');
154
+ if (!nameNode)
155
+ return;
156
+ const varName = extractVarName(nameNode);
157
+ if (!varName || env.has(varName))
158
+ return;
159
+ const rhs = parseDartRHS(node);
160
+ if (!rhs.callee || !rhs.hasCall)
161
+ return;
162
+ if (!rhs.member && classNames.has(rhs.callee)) {
163
+ env.set(varName, rhs.callee);
164
+ return;
165
+ }
166
+ if (rhs.member && classNames.has(rhs.callee)) {
167
+ env.set(varName, rhs.callee);
168
+ }
169
+ };
170
+ // ── Constructor Binding Scan ────────────────────────────────────────────
171
+ const scanDartConstructorBinding = (node) => {
172
+ if (node.type !== 'initialized_variable_definition')
173
+ return undefined;
174
+ if (hasDartTypeAnnotation(node))
175
+ return undefined;
176
+ const nameNode = node.childForFieldName('name');
177
+ if (!nameNode)
178
+ return undefined;
179
+ const varName = nameNode.text;
180
+ if (!varName)
181
+ return undefined;
182
+ const rhs = parseDartRHS(node);
183
+ if (!rhs.callee)
184
+ return undefined;
185
+ if (rhs.hasCall && !rhs.member)
186
+ return { varName, calleeName: rhs.callee };
187
+ if (rhs.hasCall && rhs.member)
188
+ return { varName, calleeName: rhs.member };
189
+ return undefined;
190
+ };
191
+ // ── Virtual Dispatch ────────────────────────────────────────────────────
192
+ const detectDartConstructorType = (node, classNames) => {
193
+ if (node.type !== 'initialized_variable_definition')
194
+ return undefined;
195
+ const rhs = parseDartRHS(node);
196
+ if (!rhs.callee || !rhs.hasCall)
197
+ return undefined;
198
+ if (!rhs.member && classNames.has(rhs.callee))
199
+ return rhs.callee;
200
+ if (rhs.member && classNames.has(rhs.callee))
201
+ return rhs.callee;
202
+ return undefined;
203
+ };
204
+ // ── Literal Type Inference ──────────────────────────────────────────────
205
+ const inferDartLiteralType = (node) => {
206
+ switch (node.type) {
207
+ case 'decimal_integer_literal':
208
+ case 'hex_integer_literal':
209
+ return 'int';
210
+ case 'decimal_floating_point_literal':
211
+ return 'double';
212
+ case 'string_literal':
213
+ return 'String';
214
+ case 'true':
215
+ case 'false':
216
+ return 'bool';
217
+ case 'null_literal':
218
+ return 'null';
219
+ default:
220
+ return undefined;
221
+ }
222
+ };
223
+ // ── Tier 2: Assignment Chain Propagation ─────────────────────────────────
224
+ const extractDartPendingAssignment = (node, scopeEnv) => {
225
+ if (node.type !== 'initialized_variable_definition')
226
+ return undefined;
227
+ if (hasDartTypeAnnotation(node))
228
+ return undefined;
229
+ const nameNode = node.childForFieldName('name');
230
+ if (!nameNode)
231
+ return undefined;
232
+ const lhs = nameNode.text;
233
+ if (!lhs || scopeEnv.has(lhs))
234
+ return undefined;
235
+ const rhs = parseDartRHS(node);
236
+ if (!rhs.callee)
237
+ return undefined;
238
+ if (!rhs.hasCall && !rhs.member)
239
+ return { kind: 'copy', lhs, rhs: rhs.callee };
240
+ if (!rhs.hasCall && rhs.member)
241
+ return { kind: 'fieldAccess', lhs, receiver: rhs.callee, field: rhs.member };
242
+ if (rhs.hasCall && !rhs.member)
243
+ return { kind: 'callResult', lhs, callee: rhs.callee };
244
+ if (rhs.hasCall && rhs.member)
245
+ return { kind: 'methodCallResult', lhs, receiver: rhs.callee, method: rhs.member };
246
+ return undefined;
247
+ };
248
+ // ── For-Loop Element Type Resolution ────────────────────────────────────
249
+ function extractDartElementTypeFromTypeNode(typeNode) {
250
+ if (typeNode.type === 'type_identifier') {
251
+ const parent = typeNode.parent;
252
+ if (parent) {
253
+ const args = findChild(parent, 'type_arguments');
254
+ if (args && args.namedChildCount >= 1) {
255
+ const lastArg = args.namedChild(args.namedChildCount - 1);
256
+ if (lastArg)
257
+ return extractSimpleTypeName(lastArg);
258
+ }
259
+ }
260
+ }
261
+ return undefined;
262
+ }
263
+ const extractDartForLoopBinding = (node, ctx) => {
264
+ if (node.type !== 'for_statement')
265
+ return;
266
+ const { scopeEnv, declarationTypeNodes, scope, returnTypeLookup } = ctx;
267
+ const loopParts = findChild(node, 'for_loop_parts');
268
+ if (!loopParts)
269
+ return;
270
+ const nameNode = loopParts.childForFieldName('name');
271
+ if (!nameNode)
272
+ return;
273
+ const loopVarName = nameNode.text;
274
+ if (!loopVarName)
275
+ return;
276
+ const typeNode = findChild(loopParts, 'type_identifier');
277
+ if (typeNode) {
278
+ const typeName = extractSimpleTypeName(typeNode);
279
+ if (typeName && !scopeEnv.has(loopVarName)) {
280
+ scopeEnv.set(loopVarName, typeName);
281
+ }
282
+ return;
283
+ }
284
+ const iterableNode = loopParts.childForFieldName('value');
285
+ if (!iterableNode)
286
+ return;
287
+ let iterableName;
288
+ let callExprElementType;
289
+ if (iterableNode.type === 'identifier') {
290
+ iterableName = iterableNode.text;
291
+ }
292
+ else if (iterableNode.type === 'unary_expression') {
293
+ const awaitExpr = findChild(iterableNode, 'await_expression');
294
+ if (awaitExpr) {
295
+ const innerIdent = findChild(awaitExpr, 'identifier');
296
+ if (innerIdent)
297
+ iterableName = innerIdent.text;
298
+ }
299
+ if (!iterableName)
300
+ return;
301
+ }
302
+ if (iterableName) {
303
+ let hasCallSelector = false;
304
+ let memberName;
305
+ const selectorParent = iterableNode.type === 'unary_expression'
306
+ ? findChild(iterableNode, 'await_expression')
307
+ : loopParts;
308
+ if (!selectorParent)
309
+ return;
310
+ let foundIterable = false;
311
+ for (let i = 0; i < selectorParent.childCount; i++) {
312
+ const child = selectorParent.child(i);
313
+ if (!child)
314
+ continue;
315
+ if (child.type === 'identifier' && child.text === iterableName) {
316
+ foundIterable = true;
317
+ continue;
318
+ }
319
+ if (child === iterableNode) {
320
+ foundIterable = true;
321
+ continue;
322
+ }
323
+ if (!foundIterable)
324
+ continue;
325
+ if (child.type === 'selector') {
326
+ const uas = findChild(child, 'unconditional_assignable_selector')
327
+ ?? findChild(child, 'conditional_assignable_selector');
328
+ if (uas) {
329
+ const id = findChild(uas, 'identifier');
330
+ if (id)
331
+ memberName = id.text;
332
+ continue;
333
+ }
334
+ if (findChild(child, 'argument_part')) {
335
+ hasCallSelector = true;
336
+ }
337
+ }
338
+ }
339
+ if (hasCallSelector) {
340
+ const callee = memberName ?? iterableName;
341
+ const rawReturn = returnTypeLookup.lookupRawReturnType(callee);
342
+ if (rawReturn)
343
+ callExprElementType = extractElementTypeFromString(rawReturn);
344
+ }
345
+ }
346
+ if (!iterableName && !callExprElementType)
347
+ return;
348
+ let elementType;
349
+ if (callExprElementType) {
350
+ elementType = callExprElementType;
351
+ }
352
+ else if (iterableName) {
353
+ elementType = resolveIterableElementType(iterableName, node, scopeEnv, declarationTypeNodes, scope, extractDartElementTypeFromTypeNode);
354
+ }
355
+ if (elementType && !scopeEnv.has(loopVarName)) {
356
+ scopeEnv.set(loopVarName, elementType);
357
+ }
358
+ };
359
+ // ── Export ───────────────────────────────────────────────────────────────
360
+ export const typeConfig = {
361
+ declarationNodeTypes: DART_DECLARATION_NODE_TYPES,
362
+ forLoopNodeTypes: DART_FOR_LOOP_NODE_TYPES,
363
+ extractDeclaration: extractDartDeclaration,
364
+ extractParameter: extractDartParameter,
365
+ extractInitializer: extractDartInitializer,
366
+ scanConstructorBinding: scanDartConstructorBinding,
367
+ extractForLoopBinding: extractDartForLoopBinding,
368
+ extractPendingAssignment: extractDartPendingAssignment,
369
+ inferLiteralType: inferDartLiteralType,
370
+ detectConstructorType: detectDartConstructorType,
371
+ };
@@ -1,5 +1,5 @@
1
+ import { findChild } from '../utils/ast-helpers.js';
1
2
  import { extractSimpleTypeName, extractVarName, extractGenericTypeArgs, resolveIterableElementType, methodToTypeArgPosition, extractElementTypeFromString } from './shared.js';
2
- import { findChild } from '../resolvers/utils.js';
3
3
  // ── Java ──────────────────────────────────────────────────────────────────
4
4
  const JAVA_DECLARATION_NODE_TYPES = new Set([
5
5
  'local_variable_declaration',
@@ -1,4 +1,4 @@
1
- import type { SyntaxNode } from '../utils.js';
1
+ import type { SyntaxNode } from '../utils/ast-helpers.js';
2
2
  /** Which type argument to extract from a multi-arg generic container.
3
3
  * - 'first': key type (e.g., K from Map<K,V>) — used for .keys(), .keySet()
4
4
  * - 'last': value type (e.g., V from Map<K,V>) — used for .values(), .items(), .iter() */
@@ -128,16 +128,4 @@ export declare const extractCalleeName: (callNode: SyntaxNode) => string | undef
128
128
  */
129
129
  export declare function extractElementTypeFromString(typeStr: string, pos?: TypeArgPosition): string | undefined;
130
130
  export declare const extractReturnTypeName: (raw: string, depth?: number) => string | undefined;
131
- /**
132
- * Extract the declared type of a property/field from its AST definition node.
133
- * Handles cross-language patterns:
134
- * - TypeScript: `name: Type` → type_annotation child
135
- * - Java: `Type name` → type child on field_declaration
136
- * - C#: `Type Name { get; set; }` → type child on property_declaration
137
- * - Go: `Name Type` → type child on field_declaration
138
- * - Kotlin: `var name: Type` → variable_declaration child with type field
139
- *
140
- * Returns the normalized type name, or undefined if no type can be extracted.
141
- */
142
- export declare const extractPropertyDeclaredType: (definitionNode: SyntaxNode | null) => string | undefined;
143
131
  export {};