gitnexus 1.5.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/README.md +10 -0
  2. package/dist/_shared/graph/types.d.ts +1 -1
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/index.d.ts +1 -0
  5. package/dist/_shared/index.d.ts.map +1 -1
  6. package/dist/_shared/language-detection.d.ts.map +1 -1
  7. package/dist/_shared/language-detection.js +2 -0
  8. package/dist/_shared/language-detection.js.map +1 -1
  9. package/dist/_shared/languages.d.ts +1 -0
  10. package/dist/_shared/languages.d.ts.map +1 -1
  11. package/dist/_shared/languages.js +1 -0
  12. package/dist/_shared/languages.js.map +1 -1
  13. package/dist/_shared/lbug/schema-constants.d.ts +1 -1
  14. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  15. package/dist/_shared/lbug/schema-constants.js +3 -1
  16. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  17. package/dist/_shared/mro-strategy.d.ts +19 -0
  18. package/dist/_shared/mro-strategy.d.ts.map +1 -0
  19. package/dist/_shared/mro-strategy.js +2 -0
  20. package/dist/_shared/mro-strategy.js.map +1 -0
  21. package/dist/cli/ai-context.d.ts +1 -0
  22. package/dist/cli/ai-context.js +28 -4
  23. package/dist/cli/analyze.d.ts +2 -0
  24. package/dist/cli/analyze.js +2 -1
  25. package/dist/cli/group.d.ts +2 -0
  26. package/dist/cli/group.js +233 -0
  27. package/dist/cli/index.js +3 -0
  28. package/dist/cli/serve.js +4 -1
  29. package/dist/cli/setup.js +34 -3
  30. package/dist/config/ignore-service.js +8 -3
  31. package/dist/core/augmentation/engine.js +1 -1
  32. package/dist/core/git-staleness.d.ts +13 -0
  33. package/dist/core/git-staleness.js +29 -0
  34. package/dist/core/group/bridge-db.d.ts +82 -0
  35. package/dist/core/group/bridge-db.js +460 -0
  36. package/dist/core/group/bridge-schema.d.ts +27 -0
  37. package/dist/core/group/bridge-schema.js +55 -0
  38. package/dist/core/group/config-parser.d.ts +3 -0
  39. package/dist/core/group/config-parser.js +83 -0
  40. package/dist/core/group/contract-extractor.d.ts +7 -0
  41. package/dist/core/group/contract-extractor.js +1 -0
  42. package/dist/core/group/extractors/grpc-extractor.d.ts +16 -0
  43. package/dist/core/group/extractors/grpc-extractor.js +264 -0
  44. package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
  45. package/dist/core/group/extractors/http-route-extractor.js +428 -0
  46. package/dist/core/group/extractors/topic-extractor.d.ts +9 -0
  47. package/dist/core/group/extractors/topic-extractor.js +234 -0
  48. package/dist/core/group/matching.d.ts +13 -0
  49. package/dist/core/group/matching.js +198 -0
  50. package/dist/core/group/normalization.d.ts +3 -0
  51. package/dist/core/group/normalization.js +115 -0
  52. package/dist/core/group/service-boundary-detector.d.ts +8 -0
  53. package/dist/core/group/service-boundary-detector.js +155 -0
  54. package/dist/core/group/service.d.ts +46 -0
  55. package/dist/core/group/service.js +160 -0
  56. package/dist/core/group/storage.d.ts +9 -0
  57. package/dist/core/group/storage.js +91 -0
  58. package/dist/core/group/sync.d.ts +21 -0
  59. package/dist/core/group/sync.js +148 -0
  60. package/dist/core/group/types.d.ts +130 -0
  61. package/dist/core/group/types.js +1 -0
  62. package/dist/core/ingestion/binding-accumulator.d.ts +207 -0
  63. package/dist/core/ingestion/binding-accumulator.js +332 -0
  64. package/dist/core/ingestion/call-processor.d.ts +155 -24
  65. package/dist/core/ingestion/call-processor.js +1129 -247
  66. package/dist/core/ingestion/class-extractors/generic.d.ts +2 -0
  67. package/dist/core/ingestion/class-extractors/generic.js +135 -0
  68. package/dist/core/ingestion/class-types.d.ts +34 -0
  69. package/dist/core/ingestion/class-types.js +1 -0
  70. package/dist/core/ingestion/entry-point-scoring.d.ts +1 -0
  71. package/dist/core/ingestion/entry-point-scoring.js +1 -0
  72. package/dist/core/ingestion/field-types.d.ts +2 -2
  73. package/dist/core/ingestion/filesystem-walker.js +8 -0
  74. package/dist/core/ingestion/framework-detection.d.ts +1 -0
  75. package/dist/core/ingestion/framework-detection.js +1 -0
  76. package/dist/core/ingestion/heritage-processor.d.ts +8 -15
  77. package/dist/core/ingestion/heritage-processor.js +15 -28
  78. package/dist/core/ingestion/import-processor.d.ts +1 -11
  79. package/dist/core/ingestion/import-processor.js +0 -12
  80. package/dist/core/ingestion/import-resolvers/utils.js +1 -0
  81. package/dist/core/ingestion/import-resolvers/vue.d.ts +8 -0
  82. package/dist/core/ingestion/import-resolvers/vue.js +9 -0
  83. package/dist/core/ingestion/language-provider.d.ts +6 -3
  84. package/dist/core/ingestion/languages/c-cpp.js +168 -1
  85. package/dist/core/ingestion/languages/csharp.js +20 -0
  86. package/dist/core/ingestion/languages/dart.js +26 -4
  87. package/dist/core/ingestion/languages/go.js +22 -0
  88. package/dist/core/ingestion/languages/index.d.ts +1 -0
  89. package/dist/core/ingestion/languages/index.js +2 -0
  90. package/dist/core/ingestion/languages/java.js +17 -0
  91. package/dist/core/ingestion/languages/kotlin.js +24 -1
  92. package/dist/core/ingestion/languages/php.js +23 -11
  93. package/dist/core/ingestion/languages/python.js +9 -0
  94. package/dist/core/ingestion/languages/ruby.js +28 -0
  95. package/dist/core/ingestion/languages/rust.js +38 -0
  96. package/dist/core/ingestion/languages/swift.js +31 -0
  97. package/dist/core/ingestion/languages/typescript.d.ts +1 -0
  98. package/dist/core/ingestion/languages/typescript.js +52 -3
  99. package/dist/core/ingestion/languages/vue.d.ts +13 -0
  100. package/dist/core/ingestion/languages/vue.js +81 -0
  101. package/dist/core/ingestion/method-extractors/configs/c-cpp.d.ts +3 -0
  102. package/dist/core/ingestion/method-extractors/configs/c-cpp.js +387 -0
  103. package/dist/core/ingestion/method-extractors/configs/csharp.js +5 -1
  104. package/dist/core/ingestion/method-extractors/configs/dart.d.ts +2 -0
  105. package/dist/core/ingestion/method-extractors/configs/dart.js +376 -0
  106. package/dist/core/ingestion/method-extractors/configs/go.d.ts +2 -0
  107. package/dist/core/ingestion/method-extractors/configs/go.js +176 -0
  108. package/dist/core/ingestion/method-extractors/configs/jvm.js +13 -4
  109. package/dist/core/ingestion/method-extractors/configs/php.d.ts +2 -0
  110. package/dist/core/ingestion/method-extractors/configs/php.js +304 -0
  111. package/dist/core/ingestion/method-extractors/configs/python.d.ts +2 -0
  112. package/dist/core/ingestion/method-extractors/configs/python.js +309 -0
  113. package/dist/core/ingestion/method-extractors/configs/ruby.d.ts +2 -0
  114. package/dist/core/ingestion/method-extractors/configs/ruby.js +285 -0
  115. package/dist/core/ingestion/method-extractors/configs/rust.d.ts +2 -0
  116. package/dist/core/ingestion/method-extractors/configs/rust.js +195 -0
  117. package/dist/core/ingestion/method-extractors/configs/swift.d.ts +2 -0
  118. package/dist/core/ingestion/method-extractors/configs/swift.js +277 -0
  119. package/dist/core/ingestion/method-extractors/configs/typescript-javascript.js +85 -8
  120. package/dist/core/ingestion/method-extractors/generic.js +38 -15
  121. package/dist/core/ingestion/method-types.d.ts +25 -0
  122. package/dist/core/ingestion/model/field-registry.d.ts +18 -0
  123. package/dist/core/ingestion/model/field-registry.js +22 -0
  124. package/dist/core/ingestion/model/heritage-map.d.ts +70 -0
  125. package/dist/core/ingestion/model/heritage-map.js +159 -0
  126. package/dist/core/ingestion/model/index.d.ts +20 -0
  127. package/dist/core/ingestion/model/index.js +41 -0
  128. package/dist/core/ingestion/model/method-registry.d.ts +62 -0
  129. package/dist/core/ingestion/model/method-registry.js +130 -0
  130. package/dist/core/ingestion/model/registration-table.d.ts +139 -0
  131. package/dist/core/ingestion/model/registration-table.js +224 -0
  132. package/dist/core/ingestion/model/resolution-context.d.ts +93 -0
  133. package/dist/core/ingestion/model/resolution-context.js +337 -0
  134. package/dist/core/ingestion/model/resolve.d.ts +56 -0
  135. package/dist/core/ingestion/model/resolve.js +242 -0
  136. package/dist/core/ingestion/model/semantic-model.d.ts +86 -0
  137. package/dist/core/ingestion/model/semantic-model.js +120 -0
  138. package/dist/core/ingestion/model/symbol-table.d.ts +222 -0
  139. package/dist/core/ingestion/model/symbol-table.js +206 -0
  140. package/dist/core/ingestion/model/type-registry.d.ts +39 -0
  141. package/dist/core/ingestion/model/type-registry.js +62 -0
  142. package/dist/core/ingestion/mro-processor.d.ts +4 -3
  143. package/dist/core/ingestion/mro-processor.js +310 -106
  144. package/dist/core/ingestion/parsing-processor.d.ts +5 -4
  145. package/dist/core/ingestion/parsing-processor.js +210 -85
  146. package/dist/core/ingestion/pipeline.d.ts +2 -0
  147. package/dist/core/ingestion/pipeline.js +192 -68
  148. package/dist/core/ingestion/tree-sitter-queries.d.ts +5 -5
  149. package/dist/core/ingestion/tree-sitter-queries.js +21 -0
  150. package/dist/core/ingestion/type-env.d.ts +15 -2
  151. package/dist/core/ingestion/type-env.js +163 -102
  152. package/dist/core/ingestion/type-extractors/csharp.js +17 -0
  153. package/dist/core/ingestion/type-extractors/jvm.js +11 -0
  154. package/dist/core/ingestion/type-extractors/php.js +0 -55
  155. package/dist/core/ingestion/type-extractors/ruby.js +0 -32
  156. package/dist/core/ingestion/type-extractors/swift.js +13 -0
  157. package/dist/core/ingestion/type-extractors/types.d.ts +8 -8
  158. package/dist/core/ingestion/type-extractors/typescript.js +66 -69
  159. package/dist/core/ingestion/utils/ast-helpers.d.ts +33 -43
  160. package/dist/core/ingestion/utils/ast-helpers.js +129 -572
  161. package/dist/core/ingestion/utils/method-props.d.ts +32 -0
  162. package/dist/core/ingestion/utils/method-props.js +147 -0
  163. package/dist/core/ingestion/vue-sfc-extractor.d.ts +44 -0
  164. package/dist/core/ingestion/vue-sfc-extractor.js +94 -0
  165. package/dist/core/ingestion/workers/parse-worker.d.ts +31 -19
  166. package/dist/core/ingestion/workers/parse-worker.js +463 -198
  167. package/dist/core/lbug/lbug-adapter.d.ts +6 -0
  168. package/dist/core/lbug/lbug-adapter.js +68 -3
  169. package/dist/core/lbug/pool-adapter.d.ts +76 -0
  170. package/dist/core/lbug/pool-adapter.js +522 -0
  171. package/dist/core/run-analyze.d.ts +2 -0
  172. package/dist/core/run-analyze.js +1 -1
  173. package/dist/core/search/bm25-index.js +1 -1
  174. package/dist/core/tree-sitter/parser-loader.js +1 -0
  175. package/dist/core/wiki/graph-queries.js +1 -1
  176. package/dist/mcp/core/embedder.js +6 -5
  177. package/dist/mcp/core/lbug-adapter.d.ts +3 -63
  178. package/dist/mcp/core/lbug-adapter.js +3 -484
  179. package/dist/mcp/local/local-backend.d.ts +31 -2
  180. package/dist/mcp/local/local-backend.js +255 -46
  181. package/dist/mcp/resources.js +5 -4
  182. package/dist/mcp/staleness.d.ts +3 -13
  183. package/dist/mcp/staleness.js +2 -31
  184. package/dist/mcp/tools.js +80 -4
  185. package/dist/server/analyze-job.d.ts +2 -0
  186. package/dist/server/analyze-job.js +4 -0
  187. package/dist/server/api.d.ts +20 -1
  188. package/dist/server/api.js +306 -71
  189. package/dist/server/git-clone.d.ts +2 -1
  190. package/dist/server/git-clone.js +98 -5
  191. package/dist/storage/git.d.ts +13 -0
  192. package/dist/storage/git.js +25 -0
  193. package/dist/storage/repo-manager.js +1 -1
  194. package/package.json +8 -2
  195. package/scripts/patch-tree-sitter-swift.cjs +78 -0
  196. package/dist/core/ingestion/named-binding-processor.d.ts +0 -18
  197. package/dist/core/ingestion/named-binding-processor.js +0 -42
  198. package/dist/core/ingestion/resolution-context.d.ts +0 -58
  199. package/dist/core/ingestion/resolution-context.js +0 -135
  200. package/dist/core/ingestion/symbol-table.d.ts +0 -79
  201. package/dist/core/ingestion/symbol-table.js +0 -115
@@ -2,11 +2,13 @@ import Parser from 'tree-sitter';
2
2
  import { loadParser, loadLanguage, isLanguageAvailable } from '../tree-sitter/parser-loader.js';
3
3
  import { getProvider } from './languages/index.js';
4
4
  import { generateId } from '../../lib/utils.js';
5
- import { getLanguageFromFilename } from '../../_shared/index.js';
5
+ import { getLanguageFromFilename, SupportedLanguages } from '../../_shared/index.js';
6
+ import { extractVueScript, isVueSetupTopLevel } from './vue-sfc-extractor.js';
6
7
  import { yieldToEventLoop } from './utils/event-loop.js';
7
- import { getDefinitionNodeFromCaptures, findEnclosingClassId, extractMethodSignature, getLabelFromCaptures, CLASS_CONTAINER_TYPES, } from './utils/ast-helpers.js';
8
+ import { getDefinitionNodeFromCaptures, findEnclosingClassInfo, getLabelFromCaptures, CLASS_CONTAINER_TYPES, } from './utils/ast-helpers.js';
8
9
  import { detectFrameworkFromAST } from './framework-detection.js';
9
10
  import { buildTypeEnv } from './type-env.js';
11
+ import { buildMethodProps, arityForIdFromInfo, typeTagForId, constTagForId, buildCollisionGroups, } from './utils/method-props.js';
10
12
  import { getTreeSitterBufferSize, TREE_SITTER_MAX_BUFFER } from './constants.js';
11
13
  // ============================================================================
12
14
  // Worker-based parallel parsing
@@ -31,7 +33,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
31
33
  toolDefs: [],
32
34
  ormQueries: [],
33
35
  constructorBindings: [],
34
- typeEnvBindings: [],
36
+ fileScopeBindings: [],
35
37
  };
36
38
  const total = files.length;
37
39
  // Dispatch to worker pool — pool handles splitting into chunks and sub-batching
@@ -49,7 +51,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
49
51
  const allToolDefs = [];
50
52
  const allORMQueries = [];
51
53
  const allConstructorBindings = [];
52
- const allTypeEnvBindings = [];
54
+ const fileScopeBindingsByFile = [];
53
55
  for (const result of chunkResults) {
54
56
  for (const node of result.nodes) {
55
57
  graph.addNode({
@@ -69,20 +71,33 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
69
71
  returnType: sym.returnType,
70
72
  declaredType: sym.declaredType,
71
73
  ownerId: sym.ownerId,
74
+ qualifiedName: sym.qualifiedName,
72
75
  });
73
76
  }
74
- allImports.push(...result.imports);
75
- allCalls.push(...result.calls);
76
- allAssignments.push(...result.assignments);
77
- allHeritage.push(...result.heritage);
78
- allRoutes.push(...result.routes);
79
- allFetchCalls.push(...result.fetchCalls);
80
- allDecoratorRoutes.push(...result.decoratorRoutes);
81
- allToolDefs.push(...result.toolDefs);
77
+ for (const _item of result.imports)
78
+ allImports.push(_item);
79
+ for (const _item of result.calls)
80
+ allCalls.push(_item);
81
+ for (const _item of result.assignments)
82
+ allAssignments.push(_item);
83
+ for (const _item of result.heritage)
84
+ allHeritage.push(_item);
85
+ for (const _item of result.routes)
86
+ allRoutes.push(_item);
87
+ for (const _item of result.fetchCalls)
88
+ allFetchCalls.push(_item);
89
+ for (const _item of result.decoratorRoutes)
90
+ allDecoratorRoutes.push(_item);
91
+ for (const _item of result.toolDefs)
92
+ allToolDefs.push(_item);
82
93
  if (result.ormQueries)
83
- allORMQueries.push(...result.ormQueries);
84
- allConstructorBindings.push(...result.constructorBindings);
85
- allTypeEnvBindings.push(...result.typeEnvBindings);
94
+ for (const _item of result.ormQueries)
95
+ allORMQueries.push(_item);
96
+ for (const _item of result.constructorBindings)
97
+ allConstructorBindings.push(_item);
98
+ if (result.fileScopeBindings)
99
+ for (const _item of result.fileScopeBindings)
100
+ fileScopeBindingsByFile.push(_item);
86
101
  }
87
102
  // Merge and log skipped languages from workers
88
103
  const skippedLanguages = new Map();
@@ -110,7 +125,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
110
125
  toolDefs: allToolDefs,
111
126
  ormQueries: allORMQueries,
112
127
  constructorBindings: allConstructorBindings,
113
- typeEnvBindings: allTypeEnvBindings,
128
+ fileScopeBindings: fileScopeBindingsByFile,
114
129
  };
115
130
  };
116
131
  // ============================================================================
@@ -118,14 +133,14 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
118
133
  // ============================================================================
119
134
  // Inline caches to avoid repeated parent-walks per node (same pattern as parse-worker.ts).
120
135
  // Keyed by tree-sitter node reference — cleared at the start of each file.
121
- const classIdCache = new Map();
136
+ const classInfoCache = new Map();
122
137
  const exportCache = new Map();
123
- const cachedFindEnclosingClassId = (node, filePath) => {
124
- const cached = classIdCache.get(node);
138
+ const cachedFindEnclosingClassInfo = (node, filePath) => {
139
+ const cached = classInfoCache.get(node);
125
140
  if (cached !== undefined)
126
141
  return cached;
127
- const result = findEnclosingClassId(node, filePath);
128
- classIdCache.set(node, result);
142
+ const result = findEnclosingClassInfo(node, filePath);
143
+ classInfoCache.set(node, result);
129
144
  return result;
130
145
  };
131
146
  const cachedExportCheck = (checker, node, name) => {
@@ -138,21 +153,36 @@ const cachedExportCheck = (checker, node, name) => {
138
153
  };
139
154
  // FieldExtractor cache for sequential path — same pattern as parse-worker.ts
140
155
  const seqFieldInfoCache = new Map();
156
+ // MethodExtractor cache for sequential path — avoids re-traversing the same class
157
+ // body once per method. Keyed on classNode.id (tree-sitter node identity number).
158
+ const seqMethodExtractCache = new Map();
159
+ // Derived method map + collision groups cache — avoids rebuilding per method.
160
+ const seqMethodMapCache = new Map();
141
161
  function seqFindEnclosingClassNode(node) {
142
162
  let current = node.parent;
143
163
  while (current) {
144
- if (CLASS_CONTAINER_TYPES.has(current.type))
164
+ if (CLASS_CONTAINER_TYPES.has(current.type)) {
165
+ // Return singleton_class directly so the method extractor sees it as
166
+ // the owner node and correctly marks methods as static. Name resolution
167
+ // for qualified names is handled separately by findEnclosingClassInfo.
145
168
  return current;
169
+ }
146
170
  current = current.parent;
147
171
  }
148
172
  return null;
149
173
  }
150
- /** Minimal no-op SymbolTable stub for FieldExtractorContext (sequential path has a real
151
- * SymbolTable, but it's incomplete at this stage — use the stub for safety). */
174
+ /** Minimal no-op SymbolTable stub for FieldExtractorContext (sequential
175
+ * path has a real SymbolTable, but it's incomplete at this stage — use
176
+ * the stub for safety). Implements the full {@link SymbolTableReader}
177
+ * surface so future extractor additions don't silently fall off an
178
+ * `as unknown as` cast. */
152
179
  const NOOP_SYMBOL_TABLE_SEQ = {
153
- lookupExactAll: () => [],
154
180
  lookupExact: () => undefined,
155
181
  lookupExactFull: () => undefined,
182
+ lookupExactAll: () => [],
183
+ lookupCallableByName: () => [],
184
+ getFiles: () => [][Symbol.iterator](),
185
+ getStats: () => ({ fileCount: 0 }),
156
186
  };
157
187
  function seqGetFieldInfo(classNode, provider, context) {
158
188
  if (!provider.fieldExtractor)
@@ -177,9 +207,11 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
177
207
  for (let i = 0; i < files.length; i++) {
178
208
  const file = files[i];
179
209
  // Reset memoization before each new file (node refs are per-tree)
180
- classIdCache.clear();
210
+ classInfoCache.clear();
181
211
  exportCache.clear();
182
212
  seqFieldInfoCache.clear();
213
+ seqMethodExtractCache.clear();
214
+ seqMethodMapCache.clear();
183
215
  onFileProgress?.(i + 1, total, file.path);
184
216
  if (i % 20 === 0)
185
217
  await yieldToEventLoop();
@@ -194,6 +226,18 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
194
226
  // Skip files larger than the max tree-sitter buffer (32 MB)
195
227
  if (file.content.length > TREE_SITTER_MAX_BUFFER)
196
228
  continue;
229
+ // Vue SFC preprocessing: extract <script> block content
230
+ let parseContent = file.content;
231
+ let lineOffset = 0;
232
+ let isVueSetup = false;
233
+ if (language === SupportedLanguages.Vue) {
234
+ const extracted = extractVueScript(file.content);
235
+ if (!extracted)
236
+ continue; // skip .vue files with no script block
237
+ parseContent = extracted.scriptContent;
238
+ lineOffset = extracted.lineOffset;
239
+ isVueSetup = extracted.isSetup;
240
+ }
197
241
  try {
198
242
  await loadLanguage(language, file.path);
199
243
  }
@@ -202,8 +246,8 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
202
246
  }
203
247
  let tree;
204
248
  try {
205
- tree = parser.parse(file.content, undefined, {
206
- bufferSize: getTreeSitterBufferSize(file.content.length),
249
+ tree = parser.parse(parseContent, undefined, {
250
+ bufferSize: getTreeSitterBufferSize(parseContent.length),
207
251
  });
208
252
  }
209
253
  catch (parseError) {
@@ -227,90 +271,170 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
227
271
  console.warn(`Query error for ${file.path}:`, queryError);
228
272
  continue;
229
273
  }
230
- // Build per-file type environment for FieldExtractor context (lightweight — skipped if no fieldExtractor)
274
+ // Build per-file type environment for FieldExtractor context (lightweight — skipped if no fieldExtractor).
275
+ //
276
+ // Note: this TypeEnv is intentionally NOT flushed into the BindingAccumulator.
277
+ // The accumulator feed happens later in `call-processor.ts` via its own
278
+ // `typeEnv.flush(accumulator)` call. Flushing here would double-count
279
+ // file-scope bindings and break the single-use invariant of `flush()`.
280
+ // See the BindingAccumulator class JSDoc for the full accumulator
281
+ // lifecycle and flush-site ownership rules.
231
282
  const typeEnv = provider.fieldExtractor
232
- ? buildTypeEnv(tree, language, { enclosingFunctionFinder: provider.enclosingFunctionFinder })
283
+ ? buildTypeEnv(tree, language, {
284
+ enclosingFunctionFinder: provider.enclosingFunctionFinder,
285
+ extractFunctionName: provider.methodExtractor?.extractFunctionName,
286
+ })
233
287
  : null;
234
288
  matches.forEach((match) => {
235
289
  const captureMap = {};
236
290
  match.captures.forEach((c) => {
237
291
  captureMap[c.name] = c.node;
238
292
  });
239
- const nodeLabel = getLabelFromCaptures(captureMap, provider);
240
- if (!nodeLabel)
293
+ const definitionNodeForRange = getDefinitionNodeFromCaptures(captureMap);
294
+ const definitionNode = getDefinitionNodeFromCaptures(captureMap);
295
+ const defaultNodeLabel = getLabelFromCaptures(captureMap, provider);
296
+ if (!defaultNodeLabel)
241
297
  return;
242
298
  const nameNode = captureMap['name'];
299
+ const extractedClassSymbol = definitionNode && provider.classExtractor?.isTypeDeclaration(definitionNode)
300
+ ? provider.classExtractor.extract(definitionNode, {
301
+ name: nameNode?.text,
302
+ type: defaultNodeLabel,
303
+ })
304
+ : null;
305
+ const nodeLabel = extractedClassSymbol?.type ?? defaultNodeLabel;
243
306
  // Synthesize name for constructors without explicit @name capture (e.g. Swift init)
244
- if (!nameNode && nodeLabel !== 'Constructor')
307
+ if (!nameNode && nodeLabel !== 'Constructor' && !extractedClassSymbol)
245
308
  return;
246
- const nodeName = nameNode ? nameNode.text : 'init';
247
- const definitionNodeForRange = getDefinitionNodeFromCaptures(captureMap);
309
+ const nodeName = extractedClassSymbol?.name ?? (nameNode ? nameNode.text : 'init');
248
310
  const startLine = definitionNodeForRange
249
- ? definitionNodeForRange.startPosition.row
311
+ ? definitionNodeForRange.startPosition.row + lineOffset
250
312
  : nameNode
251
- ? nameNode.startPosition.row
252
- : 0;
253
- const nodeId = generateId(nodeLabel, `${file.path}:${nodeName}`);
254
- const definitionNode = getDefinitionNodeFromCaptures(captureMap);
255
- const frameworkHint = definitionNode
256
- ? detectFrameworkFromAST(language, (definitionNode.text || '').slice(0, 300))
313
+ ? nameNode.startPosition.row + lineOffset
314
+ : lineOffset;
315
+ // Compute enclosing class BEFORE node ID — needed to qualify method IDs
316
+ const needsOwner = nodeLabel === 'Method' ||
317
+ nodeLabel === 'Constructor' ||
318
+ nodeLabel === 'Property' ||
319
+ nodeLabel === 'Function';
320
+ const enclosingClassInfo = needsOwner
321
+ ? cachedFindEnclosingClassInfo(nameNode || definitionNodeForRange, file.path)
257
322
  : null;
258
- // Extract method signature for Method/Constructor nodes
259
- const methodSig = nodeLabel === 'Function' || nodeLabel === 'Method' || nodeLabel === 'Constructor'
260
- ? extractMethodSignature(definitionNode)
261
- : undefined;
262
- // Language-specific return type fallback (e.g. Ruby YARD @return [Type])
263
- // Also upgrades uninformative AST types like PHP `array` with PHPDoc `@return User[]`
264
- if (methodSig &&
265
- (!methodSig.returnType ||
266
- methodSig.returnType === 'array' ||
267
- methodSig.returnType === 'iterable') &&
268
- definitionNode) {
269
- const tc = provider.typeConfig;
270
- if (tc?.extractReturnType) {
271
- const docReturn = tc.extractReturnType(definitionNode);
272
- if (docReturn)
273
- methodSig.returnType = docReturn;
323
+ const enclosingClassId = enclosingClassInfo?.classId ?? null;
324
+ // Qualify method/property IDs with enclosing class name to avoid collisions
325
+ // e.g. "Method:animal.dart:Animal.speak" vs "Method:animal.dart:Dog.speak"
326
+ const qualifiedName = enclosingClassInfo
327
+ ? `${enclosingClassInfo.className}.${nodeName}`
328
+ : nodeName;
329
+ // Extract method metadata for Function/Method/Constructor nodes BEFORE generating
330
+ // the node ID — parameterCount is needed to disambiguate overloaded methods.
331
+ // Use the per-language MethodExtractor for method metadata (isAbstract, isStatic,
332
+ // visibility, annotations, parameterCount, parameterTypes, returnType, etc.).
333
+ const isMethodLike = nodeLabel === 'Function' || nodeLabel === 'Method' || nodeLabel === 'Constructor';
334
+ let methodProps = {};
335
+ let arityForId; // raw param count for ID, even for variadic
336
+ let seqDefMethodInfo;
337
+ let seqDefMethods;
338
+ let seqClassNodeId;
339
+ if (isMethodLike && definitionNode) {
340
+ let enriched = false;
341
+ if (provider.methodExtractor) {
342
+ // Try class-based extraction (method inside a class/struct/trait body)
343
+ const classNode = seqFindEnclosingClassNode(definitionNode);
344
+ if (classNode) {
345
+ // Cache extract() results per class node to avoid re-traversing the
346
+ // same class body for every method it contains (O(N) -> O(1) per hit).
347
+ let result = seqMethodExtractCache.get(classNode.id);
348
+ if (result === undefined) {
349
+ result =
350
+ provider.methodExtractor.extract(classNode, {
351
+ filePath: file.path,
352
+ language,
353
+ }) ?? null;
354
+ seqMethodExtractCache.set(classNode.id, result);
355
+ }
356
+ if (result?.methods?.length) {
357
+ const defLine = definitionNode.startPosition.row + 1;
358
+ const info = result.methods.find((m) => m.name === nodeName && m.line === defLine);
359
+ if (info) {
360
+ enriched = true;
361
+ arityForId = arityForIdFromInfo(info);
362
+ methodProps = buildMethodProps(info);
363
+ seqDefMethodInfo = info;
364
+ seqDefMethods = result.methods;
365
+ seqClassNodeId = classNode.id;
366
+ }
367
+ }
368
+ }
369
+ // For top-level methods (e.g. Go method_declaration), try extractFromNode
370
+ if (!enriched && provider.methodExtractor.extractFromNode) {
371
+ const info = provider.methodExtractor.extractFromNode(definitionNode, {
372
+ filePath: file.path,
373
+ language,
374
+ });
375
+ if (info) {
376
+ enriched = true;
377
+ arityForId = arityForIdFromInfo(info);
378
+ methodProps = buildMethodProps(info);
379
+ }
380
+ }
381
+ }
382
+ }
383
+ // Append #<paramCount> to Method/Constructor IDs to disambiguate overloads.
384
+ // Functions are not suffixed — they don't overload by name in the same scope.
385
+ // When same-arity collisions exist, append ~type1,type2 for further disambiguation.
386
+ const needsAritySuffix = nodeLabel === 'Method' || nodeLabel === 'Constructor';
387
+ let arityTag = needsAritySuffix && arityForId !== undefined ? `#${arityForId}` : '';
388
+ if (arityTag && seqDefMethods && seqDefMethodInfo && seqClassNodeId !== undefined) {
389
+ // Use cached method map + collision groups (built once per class, not per method)
390
+ let cached = seqMethodMapCache.get(seqClassNodeId);
391
+ if (!cached) {
392
+ const tempMap = new Map();
393
+ for (const m of seqDefMethods)
394
+ tempMap.set(`${m.name}:${m.line}`, m);
395
+ cached = { map: tempMap, groups: buildCollisionGroups(tempMap) };
396
+ seqMethodMapCache.set(seqClassNodeId, cached);
274
397
  }
398
+ arityTag += typeTagForId(cached.map, nodeName, arityForId, seqDefMethodInfo, language, cached.groups);
399
+ arityTag += constTagForId(cached.map, nodeName, arityForId, seqDefMethodInfo, cached.groups);
275
400
  }
401
+ const nodeId = generateId(nodeLabel, `${file.path}:${qualifiedName}${arityTag}`);
402
+ const classNodeForSymbol = definitionNodeForRange || definitionNode || nameNode;
403
+ const qualifiedTypeName = extractedClassSymbol?.qualifiedName ??
404
+ (classNodeForSymbol && provider.classExtractor?.isTypeDeclaration(classNodeForSymbol)
405
+ ? (provider.classExtractor.extractQualifiedName(classNodeForSymbol, nodeName) ?? nodeName)
406
+ : undefined);
407
+ const frameworkHint = definitionNode
408
+ ? detectFrameworkFromAST(language, (definitionNode.text || '').slice(0, 300))
409
+ : null;
276
410
  const node = {
277
411
  id: nodeId,
278
412
  label: nodeLabel,
279
413
  properties: {
280
414
  name: nodeName,
281
415
  filePath: file.path,
282
- startLine: definitionNodeForRange ? definitionNodeForRange.startPosition.row : startLine,
283
- endLine: definitionNodeForRange ? definitionNodeForRange.endPosition.row : startLine,
416
+ startLine: definitionNodeForRange
417
+ ? definitionNodeForRange.startPosition.row + lineOffset
418
+ : startLine,
419
+ endLine: definitionNodeForRange
420
+ ? definitionNodeForRange.endPosition.row + lineOffset
421
+ : startLine,
284
422
  language: language,
285
- isExported: cachedExportCheck(provider.exportChecker, nameNode || definitionNodeForRange, nodeName),
423
+ isExported: language === SupportedLanguages.Vue && isVueSetup
424
+ ? isVueSetupTopLevel(nameNode || definitionNodeForRange)
425
+ : cachedExportCheck(provider.exportChecker, nameNode || definitionNodeForRange, nodeName),
426
+ ...(qualifiedTypeName !== undefined ? { qualifiedName: qualifiedTypeName } : {}),
286
427
  ...(frameworkHint
287
428
  ? {
288
429
  astFrameworkMultiplier: frameworkHint.entryPointMultiplier,
289
430
  astFrameworkReason: frameworkHint.reason,
290
431
  }
291
432
  : {}),
292
- ...(methodSig
293
- ? {
294
- parameterCount: methodSig.parameterCount,
295
- ...(methodSig.requiredParameterCount !== undefined
296
- ? { requiredParameterCount: methodSig.requiredParameterCount }
297
- : {}),
298
- ...(methodSig.parameterTypes ? { parameterTypes: methodSig.parameterTypes } : {}),
299
- returnType: methodSig.returnType,
300
- }
301
- : {}),
433
+ ...methodProps,
302
434
  },
303
435
  };
304
436
  graph.addNode(node);
305
- // Compute enclosing class for Method/Constructor/Property/Function used for both ownerId and HAS_METHOD
306
- // Function is included because Kotlin/Rust/Python capture class methods as Function nodes
307
- const needsOwner = nodeLabel === 'Method' ||
308
- nodeLabel === 'Constructor' ||
309
- nodeLabel === 'Property' ||
310
- nodeLabel === 'Function';
311
- const enclosingClassId = needsOwner
312
- ? cachedFindEnclosingClassId(nameNode || definitionNodeForRange, file.path)
313
- : null;
437
+ // enclosingClassId already computed above (before nodeId generation)
314
438
  // Extract declared type and field metadata for Property nodes
315
439
  let declaredType;
316
440
  let seqVisibility;
@@ -336,7 +460,7 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
336
460
  }
337
461
  }
338
462
  }
339
- // All 14 languages register a FieldExtractor — no fallback needed.
463
+ // All 15 tree-sitter languages register a FieldExtractor — no fallback needed.
340
464
  }
341
465
  // Apply field metadata to the graph node retroactively
342
466
  if (seqVisibility !== undefined)
@@ -348,12 +472,13 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
348
472
  if (declaredType !== undefined)
349
473
  node.properties.declaredType = declaredType;
350
474
  symbolTable.add(file.path, nodeName, nodeId, nodeLabel, {
351
- parameterCount: methodSig?.parameterCount,
352
- requiredParameterCount: methodSig?.requiredParameterCount,
353
- parameterTypes: methodSig?.parameterTypes,
354
- returnType: methodSig?.returnType,
475
+ parameterCount: methodProps.parameterCount,
476
+ requiredParameterCount: methodProps.requiredParameterCount,
477
+ parameterTypes: methodProps.parameterTypes,
478
+ returnType: methodProps.returnType,
355
479
  declaredType,
356
480
  ownerId: enclosingClassId ?? undefined,
481
+ qualifiedName: qualifiedTypeName,
357
482
  });
358
483
  const fileId = generateId('File', file.path);
359
484
  const relId = generateId('DEFINES', `${fileId}->${nodeId}`);
@@ -12,6 +12,8 @@ export declare function topologicalLevelSort(importMap: ReadonlyMap<string, Read
12
12
  export interface PipelineOptions {
13
13
  /** Skip MRO, community detection, and process extraction for faster test runs. */
14
14
  skipGraphPhases?: boolean;
15
+ /** Force sequential parsing (no worker pool). Useful for testing the sequential path. */
16
+ skipWorkers?: boolean;
15
17
  }
16
18
  export declare const runPipelineFromRepo: (repoPath: string, onProgress: (progress: PipelineProgress) => void, options?: PipelineOptions) => Promise<PipelineResult>;
17
19
  export {};