gitnexus 1.4.6 → 1.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -1
- package/dist/cli/ai-context.d.ts +1 -1
- package/dist/cli/ai-context.js +1 -1
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +54 -21
- package/dist/cli/index.js +2 -1
- package/dist/cli/setup.js +78 -1
- package/dist/config/supported-languages.d.ts +30 -0
- package/dist/config/supported-languages.js +30 -0
- package/dist/core/embeddings/embedder.d.ts +6 -1
- package/dist/core/embeddings/embedder.js +65 -5
- package/dist/core/embeddings/embedding-pipeline.js +11 -9
- package/dist/core/embeddings/http-client.d.ts +31 -0
- package/dist/core/embeddings/http-client.js +179 -0
- package/dist/core/embeddings/index.d.ts +1 -0
- package/dist/core/embeddings/index.js +1 -0
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/graph/types.d.ts +4 -3
- package/dist/core/ingestion/ast-helpers.d.ts +80 -0
- package/dist/core/ingestion/ast-helpers.js +738 -0
- package/dist/core/ingestion/call-analysis.d.ts +73 -0
- package/dist/core/ingestion/call-analysis.js +490 -0
- package/dist/core/ingestion/call-processor.d.ts +55 -2
- package/dist/core/ingestion/call-processor.js +673 -108
- package/dist/core/ingestion/call-routing.d.ts +23 -2
- package/dist/core/ingestion/call-routing.js +21 -0
- package/dist/core/ingestion/entry-point-scoring.js +36 -26
- package/dist/core/ingestion/framework-detection.d.ts +10 -2
- package/dist/core/ingestion/framework-detection.js +49 -12
- package/dist/core/ingestion/heritage-processor.js +47 -49
- package/dist/core/ingestion/import-processor.d.ts +1 -1
- package/dist/core/ingestion/import-processor.js +103 -194
- package/dist/core/ingestion/import-resolution.d.ts +101 -0
- package/dist/core/ingestion/import-resolution.js +251 -0
- package/dist/core/ingestion/language-config.d.ts +3 -0
- package/dist/core/ingestion/language-config.js +13 -0
- package/dist/core/ingestion/markdown-processor.d.ts +17 -0
- package/dist/core/ingestion/markdown-processor.js +124 -0
- package/dist/core/ingestion/mro-processor.js +8 -3
- package/dist/core/ingestion/named-binding-extraction.d.ts +9 -43
- package/dist/core/ingestion/named-binding-extraction.js +89 -79
- package/dist/core/ingestion/parsing-processor.d.ts +3 -2
- package/dist/core/ingestion/parsing-processor.js +27 -60
- package/dist/core/ingestion/pipeline.d.ts +10 -0
- package/dist/core/ingestion/pipeline.js +425 -4
- package/dist/core/ingestion/resolution-context.d.ts +5 -0
- package/dist/core/ingestion/resolution-context.js +7 -4
- package/dist/core/ingestion/resolvers/index.d.ts +1 -1
- package/dist/core/ingestion/resolvers/index.js +1 -1
- package/dist/core/ingestion/resolvers/jvm.d.ts +2 -1
- package/dist/core/ingestion/resolvers/jvm.js +25 -9
- package/dist/core/ingestion/resolvers/php.d.ts +14 -0
- package/dist/core/ingestion/resolvers/php.js +43 -3
- package/dist/core/ingestion/resolvers/utils.d.ts +5 -0
- package/dist/core/ingestion/resolvers/utils.js +16 -0
- package/dist/core/ingestion/symbol-table.d.ts +29 -3
- package/dist/core/ingestion/symbol-table.js +42 -9
- package/dist/core/ingestion/tree-sitter-queries.d.ts +12 -12
- package/dist/core/ingestion/tree-sitter-queries.js +243 -2
- package/dist/core/ingestion/type-env.d.ts +28 -1
- package/dist/core/ingestion/type-env.js +451 -72
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +5 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +146 -2
- package/dist/core/ingestion/type-extractors/csharp.js +189 -16
- package/dist/core/ingestion/type-extractors/go.js +45 -0
- package/dist/core/ingestion/type-extractors/index.d.ts +1 -1
- package/dist/core/ingestion/type-extractors/index.js +1 -1
- package/dist/core/ingestion/type-extractors/jvm.js +244 -69
- package/dist/core/ingestion/type-extractors/php.js +31 -4
- package/dist/core/ingestion/type-extractors/python.js +89 -17
- package/dist/core/ingestion/type-extractors/ruby.js +17 -2
- package/dist/core/ingestion/type-extractors/rust.js +72 -4
- package/dist/core/ingestion/type-extractors/shared.d.ts +12 -2
- package/dist/core/ingestion/type-extractors/shared.js +115 -13
- package/dist/core/ingestion/type-extractors/swift.js +7 -6
- package/dist/core/ingestion/type-extractors/types.d.ts +54 -11
- package/dist/core/ingestion/type-extractors/typescript.js +171 -9
- package/dist/core/ingestion/utils.d.ts +2 -95
- package/dist/core/ingestion/utils.js +3 -892
- package/dist/core/ingestion/workers/parse-worker.d.ts +36 -11
- package/dist/core/ingestion/workers/parse-worker.js +116 -95
- package/dist/core/lbug/csv-generator.js +18 -1
- package/dist/core/lbug/lbug-adapter.d.ts +12 -0
- package/dist/core/lbug/lbug-adapter.js +71 -4
- package/dist/core/lbug/schema.d.ts +6 -4
- package/dist/core/lbug/schema.js +27 -3
- package/dist/mcp/core/embedder.js +11 -3
- package/dist/mcp/core/lbug-adapter.d.ts +22 -0
- package/dist/mcp/core/lbug-adapter.js +178 -23
- package/dist/mcp/local/local-backend.d.ts +22 -0
- package/dist/mcp/local/local-backend.js +136 -32
- package/dist/mcp/resources.js +13 -0
- package/dist/mcp/server.js +26 -4
- package/dist/mcp/tools.js +17 -7
- package/dist/server/api.d.ts +19 -1
- package/dist/server/api.js +66 -6
- package/dist/storage/git.d.ts +12 -0
- package/dist/storage/git.js +21 -0
- package/package.json +12 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { findChild } from './resolvers/utils.js';
|
|
2
2
|
/**
|
|
3
3
|
* Walk a named-binding re-export chain through NamedImportMap.
|
|
4
4
|
*
|
|
@@ -41,40 +41,6 @@ export function walkBindingChain(name, currentFilePath, symbolTable, namedImport
|
|
|
41
41
|
}
|
|
42
42
|
return null;
|
|
43
43
|
}
|
|
44
|
-
/**
|
|
45
|
-
* Extract named bindings from an import AST node.
|
|
46
|
-
* Returns undefined if the import is not a named import (e.g., import * or default).
|
|
47
|
-
*
|
|
48
|
-
* TS: import { User, Repo as R } from './models'
|
|
49
|
-
* → [{local:'User', exported:'User'}, {local:'R', exported:'Repo'}]
|
|
50
|
-
*
|
|
51
|
-
* Python: from models import User, Repo as R
|
|
52
|
-
* → [{local:'User', exported:'User'}, {local:'R', exported:'Repo'}]
|
|
53
|
-
*/
|
|
54
|
-
export function extractNamedBindings(importNode, language) {
|
|
55
|
-
if (language === SupportedLanguages.TypeScript || language === SupportedLanguages.JavaScript) {
|
|
56
|
-
return extractTsNamedBindings(importNode);
|
|
57
|
-
}
|
|
58
|
-
if (language === SupportedLanguages.Python) {
|
|
59
|
-
return extractPythonNamedBindings(importNode);
|
|
60
|
-
}
|
|
61
|
-
if (language === SupportedLanguages.Kotlin) {
|
|
62
|
-
return extractKotlinNamedBindings(importNode);
|
|
63
|
-
}
|
|
64
|
-
if (language === SupportedLanguages.Rust) {
|
|
65
|
-
return extractRustNamedBindings(importNode);
|
|
66
|
-
}
|
|
67
|
-
if (language === SupportedLanguages.PHP) {
|
|
68
|
-
return extractPhpNamedBindings(importNode);
|
|
69
|
-
}
|
|
70
|
-
if (language === SupportedLanguages.CSharp) {
|
|
71
|
-
return extractCsharpNamedBindings(importNode);
|
|
72
|
-
}
|
|
73
|
-
if (language === SupportedLanguages.Java) {
|
|
74
|
-
return extractJavaNamedBindings(importNode);
|
|
75
|
-
}
|
|
76
|
-
return undefined;
|
|
77
|
-
}
|
|
78
44
|
export function extractTsNamedBindings(importNode) {
|
|
79
45
|
// import_statement > import_clause > named_imports > import_specifier*
|
|
80
46
|
const importClause = findChild(importNode, 'import_clause');
|
|
@@ -133,34 +99,52 @@ export function extractTsNamedBindings(importNode) {
|
|
|
133
99
|
return undefined;
|
|
134
100
|
}
|
|
135
101
|
export function extractPythonNamedBindings(importNode) {
|
|
136
|
-
//
|
|
137
|
-
if (importNode.type
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (!child)
|
|
143
|
-
continue;
|
|
144
|
-
if (child.type === 'dotted_name') {
|
|
145
|
-
// Skip the module_name (first dotted_name is the source module)
|
|
146
|
-
const fieldName = importNode.childForFieldName?.('module_name');
|
|
147
|
-
if (fieldName && child.startIndex === fieldName.startIndex)
|
|
102
|
+
// Handle: from x import User, Repo as R
|
|
103
|
+
if (importNode.type === 'import_from_statement') {
|
|
104
|
+
const bindings = [];
|
|
105
|
+
for (let i = 0; i < importNode.namedChildCount; i++) {
|
|
106
|
+
const child = importNode.namedChild(i);
|
|
107
|
+
if (!child)
|
|
148
108
|
continue;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
109
|
+
if (child.type === 'dotted_name') {
|
|
110
|
+
// Skip the module_name (first dotted_name is the source module)
|
|
111
|
+
const fieldName = importNode.childForFieldName?.('module_name');
|
|
112
|
+
if (fieldName && child.startIndex === fieldName.startIndex)
|
|
113
|
+
continue;
|
|
114
|
+
// This is an imported name: from x import User
|
|
115
|
+
const name = child.text;
|
|
116
|
+
if (name)
|
|
117
|
+
bindings.push({ local: name, exported: name });
|
|
118
|
+
}
|
|
119
|
+
if (child.type === 'aliased_import') {
|
|
120
|
+
// from x import Repo as R
|
|
121
|
+
const dottedName = findChild(child, 'dotted_name');
|
|
122
|
+
const aliasIdent = findChild(child, 'identifier');
|
|
123
|
+
if (dottedName && aliasIdent) {
|
|
124
|
+
bindings.push({ local: aliasIdent.text, exported: dottedName.text });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
153
127
|
}
|
|
154
|
-
|
|
155
|
-
|
|
128
|
+
return bindings.length > 0 ? bindings : undefined;
|
|
129
|
+
}
|
|
130
|
+
// Handle: import numpy as np (import_statement with aliased_import child)
|
|
131
|
+
// Tagged with isModuleAlias so applyImportResult routes these directly to
|
|
132
|
+
// moduleAliasMap (e.g. "np" → "numpy.py") instead of namedImportMap.
|
|
133
|
+
if (importNode.type === 'import_statement') {
|
|
134
|
+
const bindings = [];
|
|
135
|
+
for (let i = 0; i < importNode.namedChildCount; i++) {
|
|
136
|
+
const child = importNode.namedChild(i);
|
|
137
|
+
if (!child || child.type !== 'aliased_import')
|
|
138
|
+
continue;
|
|
156
139
|
const dottedName = findChild(child, 'dotted_name');
|
|
157
140
|
const aliasIdent = findChild(child, 'identifier');
|
|
158
141
|
if (dottedName && aliasIdent) {
|
|
159
|
-
bindings.push({ local: aliasIdent.text, exported: dottedName.text });
|
|
142
|
+
bindings.push({ local: aliasIdent.text, exported: dottedName.text, isModuleAlias: true });
|
|
160
143
|
}
|
|
161
144
|
}
|
|
145
|
+
return bindings.length > 0 ? bindings : undefined;
|
|
162
146
|
}
|
|
163
|
-
return
|
|
147
|
+
return undefined;
|
|
164
148
|
}
|
|
165
149
|
export function extractKotlinNamedBindings(importNode) {
|
|
166
150
|
// import_header > identifier + import_alias > simple_identifier
|
|
@@ -180,15 +164,21 @@ export function extractKotlinNamedBindings(importNode) {
|
|
|
180
164
|
return [{ local: aliasIdent.text, exported: exportedName }];
|
|
181
165
|
}
|
|
182
166
|
// Non-aliased: import com.example.User → local="User", exported="User"
|
|
167
|
+
// Also handles top-level function imports: import models.getUser → local="getUser"
|
|
183
168
|
// Skip wildcard imports (ending in *)
|
|
184
169
|
if (fullText.endsWith('.*') || fullText.endsWith('*'))
|
|
185
170
|
return undefined;
|
|
186
|
-
// Skip
|
|
187
|
-
//
|
|
171
|
+
// Skip class-member imports (e.g., import util.OneArg.writeAudit) where the
|
|
172
|
+
// second-to-last segment is PascalCase (a class name). Multiple member imports
|
|
188
173
|
// with the same function name would collide in NamedImportMap, breaking
|
|
189
|
-
// arity-based disambiguation.
|
|
190
|
-
|
|
191
|
-
|
|
174
|
+
// arity-based disambiguation. Top-level function imports (import models.getUser)
|
|
175
|
+
// and class imports (import models.User) have package-only prefixes.
|
|
176
|
+
const segments = fullText.split('.');
|
|
177
|
+
if (segments.length >= 3) {
|
|
178
|
+
const parentSegment = segments[segments.length - 2];
|
|
179
|
+
if (parentSegment[0] && parentSegment[0] === parentSegment[0].toUpperCase())
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
192
182
|
return [{ local: exportedName, exported: exportedName }];
|
|
193
183
|
}
|
|
194
184
|
export function extractRustNamedBindings(importNode) {
|
|
@@ -260,6 +250,12 @@ export function extractPhpNamedBindings(importNode) {
|
|
|
260
250
|
// namespace_use_declaration > namespace_use_group > namespace_use_clause* (grouped)
|
|
261
251
|
if (importNode.type !== 'namespace_use_declaration')
|
|
262
252
|
return undefined;
|
|
253
|
+
// Skip 'use function' and 'use const' declarations — these import callables/constants,
|
|
254
|
+
// not class types, and should not be added to namedImportMap as type bindings.
|
|
255
|
+
const useTypeNode = importNode.childForFieldName?.('type');
|
|
256
|
+
if (useTypeNode && (useTypeNode.text === 'function' || useTypeNode.text === 'const')) {
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
263
259
|
const bindings = [];
|
|
264
260
|
// Collect all clauses — from direct children AND from namespace_use_group
|
|
265
261
|
const clauses = [];
|
|
@@ -311,11 +307,20 @@ export function extractPhpNamedBindings(importNode) {
|
|
|
311
307
|
return bindings.length > 0 ? bindings : undefined;
|
|
312
308
|
}
|
|
313
309
|
export function extractCsharpNamedBindings(importNode) {
|
|
314
|
-
// using_directive
|
|
310
|
+
// using_directive — three forms:
|
|
311
|
+
// using Alias = NS.Type; → aliasIdent + qualifiedName
|
|
312
|
+
// using static NS.Type; → static + qualifiedName (no alias)
|
|
313
|
+
// using NS; → qualifiedName only (namespace, not capturable)
|
|
315
314
|
if (importNode.type !== 'using_directive')
|
|
316
315
|
return undefined;
|
|
317
316
|
let aliasIdent = null;
|
|
318
317
|
let qualifiedName = null;
|
|
318
|
+
let isStatic = false;
|
|
319
|
+
for (let i = 0; i < importNode.childCount; i++) {
|
|
320
|
+
const child = importNode.child(i);
|
|
321
|
+
if (child?.text === 'static')
|
|
322
|
+
isStatic = true;
|
|
323
|
+
}
|
|
319
324
|
for (let i = 0; i < importNode.namedChildCount; i++) {
|
|
320
325
|
const child = importNode.namedChild(i);
|
|
321
326
|
if (child?.type === 'identifier' && !aliasIdent)
|
|
@@ -323,22 +328,34 @@ export function extractCsharpNamedBindings(importNode) {
|
|
|
323
328
|
else if (child?.type === 'qualified_name')
|
|
324
329
|
qualifiedName = child;
|
|
325
330
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
+
// Form 1: using Alias = NS.Type;
|
|
332
|
+
if (aliasIdent && qualifiedName) {
|
|
333
|
+
const fullText = qualifiedName.text;
|
|
334
|
+
const exportedName = fullText.includes('.') ? fullText.split('.').pop() : fullText;
|
|
335
|
+
return [{ local: aliasIdent.text, exported: exportedName }];
|
|
336
|
+
}
|
|
337
|
+
// Form 2: using static NS.Type; — last segment is the class name
|
|
338
|
+
if (isStatic && qualifiedName) {
|
|
339
|
+
const fullText = qualifiedName.text;
|
|
340
|
+
const lastSegment = fullText.includes('.') ? fullText.split('.').pop() : fullText;
|
|
341
|
+
return [{ local: lastSegment, exported: lastSegment }];
|
|
342
|
+
}
|
|
343
|
+
// Form 3: using NS; — namespace import, can't resolve to per-symbol bindings
|
|
344
|
+
return undefined;
|
|
331
345
|
}
|
|
332
346
|
export function extractJavaNamedBindings(importNode) {
|
|
333
347
|
// import_declaration > scoped_identifier "com.example.models.User"
|
|
334
348
|
// Wildcard imports (.*) don't produce named bindings
|
|
335
349
|
if (importNode.type !== 'import_declaration')
|
|
336
350
|
return undefined;
|
|
337
|
-
// Check for asterisk (wildcard import)
|
|
351
|
+
// Check for asterisk (wildcard import) and static modifier
|
|
352
|
+
let isStatic = false;
|
|
338
353
|
for (let i = 0; i < importNode.childCount; i++) {
|
|
339
354
|
const child = importNode.child(i);
|
|
340
355
|
if (child?.type === 'asterisk')
|
|
341
356
|
return undefined;
|
|
357
|
+
if (child?.text === 'static')
|
|
358
|
+
isStatic = true;
|
|
342
359
|
}
|
|
343
360
|
const scopedId = findChild(importNode, 'scoped_identifier');
|
|
344
361
|
if (!scopedId)
|
|
@@ -347,17 +364,10 @@ export function extractJavaNamedBindings(importNode) {
|
|
|
347
364
|
const lastDot = fullText.lastIndexOf('.');
|
|
348
365
|
if (lastDot === -1)
|
|
349
366
|
return undefined;
|
|
350
|
-
const
|
|
351
|
-
//
|
|
352
|
-
|
|
367
|
+
const name = fullText.slice(lastDot + 1);
|
|
368
|
+
// Non-static: skip lowercase names — those are package imports, not class imports.
|
|
369
|
+
// Static: allow lowercase — `import static models.UserFactory.getUser` imports a method.
|
|
370
|
+
if (!isStatic && name[0] && name[0] === name[0].toLowerCase())
|
|
353
371
|
return undefined;
|
|
354
|
-
return [{ local:
|
|
355
|
-
}
|
|
356
|
-
function findChild(node, type) {
|
|
357
|
-
for (let i = 0; i < node.namedChildCount; i++) {
|
|
358
|
-
const child = node.namedChild(i);
|
|
359
|
-
if (child?.type === type)
|
|
360
|
-
return child;
|
|
361
|
-
}
|
|
362
|
-
return null;
|
|
372
|
+
return [{ local: name, exported: name }];
|
|
363
373
|
}
|
|
@@ -2,16 +2,17 @@ import { KnowledgeGraph } from '../graph/types.js';
|
|
|
2
2
|
import { SymbolTable } from './symbol-table.js';
|
|
3
3
|
import { ASTCache } from './ast-cache.js';
|
|
4
4
|
import { WorkerPool } from './workers/worker-pool.js';
|
|
5
|
-
import type { ExtractedImport, ExtractedCall, ExtractedHeritage, ExtractedRoute, FileConstructorBindings } from './workers/parse-worker.js';
|
|
5
|
+
import type { ExtractedImport, ExtractedCall, ExtractedAssignment, ExtractedHeritage, ExtractedRoute, FileConstructorBindings, FileTypeEnvBindings } from './workers/parse-worker.js';
|
|
6
6
|
export type FileProgressCallback = (current: number, total: number, filePath: string) => void;
|
|
7
7
|
export interface WorkerExtractedData {
|
|
8
8
|
imports: ExtractedImport[];
|
|
9
9
|
calls: ExtractedCall[];
|
|
10
|
+
assignments: ExtractedAssignment[];
|
|
10
11
|
heritage: ExtractedHeritage[];
|
|
11
12
|
routes: ExtractedRoute[];
|
|
12
13
|
constructorBindings: FileConstructorBindings[];
|
|
14
|
+
typeEnvBindings: FileTypeEnvBindings[];
|
|
13
15
|
}
|
|
14
|
-
export { isNodeExported } from './export-detection.js';
|
|
15
16
|
export declare const processParsing: (graph: KnowledgeGraph, files: {
|
|
16
17
|
path: string;
|
|
17
18
|
content: string;
|
|
@@ -2,14 +2,12 @@ import Parser from 'tree-sitter';
|
|
|
2
2
|
import { loadParser, loadLanguage, isLanguageAvailable } from '../tree-sitter/parser-loader.js';
|
|
3
3
|
import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
|
|
4
4
|
import { generateId } from '../../lib/utils.js';
|
|
5
|
-
import { getLanguageFromFilename, yieldToEventLoop, getDefinitionNodeFromCaptures, findEnclosingClassId, extractMethodSignature } from './utils.js';
|
|
5
|
+
import { getLanguageFromFilename, yieldToEventLoop, getDefinitionNodeFromCaptures, findEnclosingClassId, extractMethodSignature, getLabelFromCaptures } from './utils.js';
|
|
6
|
+
import { extractPropertyDeclaredType } from './type-extractors/shared.js';
|
|
6
7
|
import { isNodeExported } from './export-detection.js';
|
|
7
8
|
import { detectFrameworkFromAST } from './framework-detection.js';
|
|
8
9
|
import { typeConfigs } from './type-extractors/index.js';
|
|
9
10
|
import { getTreeSitterBufferSize, TREE_SITTER_MAX_BUFFER } from './constants.js';
|
|
10
|
-
// isNodeExported imported from ./export-detection.js (shared module)
|
|
11
|
-
// Re-export for backward compatibility with any external consumers
|
|
12
|
-
export { isNodeExported } from './export-detection.js';
|
|
13
11
|
// ============================================================================
|
|
14
12
|
// Worker-based parallel parsing
|
|
15
13
|
// ============================================================================
|
|
@@ -22,7 +20,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
22
20
|
parseableFiles.push({ path: file.path, content: file.content });
|
|
23
21
|
}
|
|
24
22
|
if (parseableFiles.length === 0)
|
|
25
|
-
return { imports: [], calls: [], heritage: [], routes: [], constructorBindings: [] };
|
|
23
|
+
return { imports: [], calls: [], assignments: [], heritage: [], routes: [], constructorBindings: [], typeEnvBindings: [] };
|
|
26
24
|
const total = files.length;
|
|
27
25
|
// Dispatch to worker pool — pool handles splitting into chunks and sub-batching
|
|
28
26
|
const chunkResults = await workerPool.dispatch(parseableFiles, (filesProcessed) => {
|
|
@@ -31,9 +29,11 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
31
29
|
// Merge results from all workers into graph and symbol table
|
|
32
30
|
const allImports = [];
|
|
33
31
|
const allCalls = [];
|
|
32
|
+
const allAssignments = [];
|
|
34
33
|
const allHeritage = [];
|
|
35
34
|
const allRoutes = [];
|
|
36
35
|
const allConstructorBindings = [];
|
|
36
|
+
const allTypeEnvBindings = [];
|
|
37
37
|
for (const result of chunkResults) {
|
|
38
38
|
for (const node of result.nodes) {
|
|
39
39
|
graph.addNode({
|
|
@@ -48,15 +48,20 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
48
48
|
for (const sym of result.symbols) {
|
|
49
49
|
symbolTable.add(sym.filePath, sym.name, sym.nodeId, sym.type, {
|
|
50
50
|
parameterCount: sym.parameterCount,
|
|
51
|
+
requiredParameterCount: sym.requiredParameterCount,
|
|
52
|
+
parameterTypes: sym.parameterTypes,
|
|
51
53
|
returnType: sym.returnType,
|
|
54
|
+
declaredType: sym.declaredType,
|
|
52
55
|
ownerId: sym.ownerId,
|
|
53
56
|
});
|
|
54
57
|
}
|
|
55
58
|
allImports.push(...result.imports);
|
|
56
59
|
allCalls.push(...result.calls);
|
|
60
|
+
allAssignments.push(...result.assignments);
|
|
57
61
|
allHeritage.push(...result.heritage);
|
|
58
62
|
allRoutes.push(...result.routes);
|
|
59
63
|
allConstructorBindings.push(...result.constructorBindings);
|
|
64
|
+
allTypeEnvBindings.push(...result.typeEnvBindings);
|
|
60
65
|
}
|
|
61
66
|
// Merge and log skipped languages from workers
|
|
62
67
|
const skippedLanguages = new Map();
|
|
@@ -73,7 +78,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
73
78
|
}
|
|
74
79
|
// Final progress
|
|
75
80
|
onFileProgress?.(total, total, 'done');
|
|
76
|
-
return { imports: allImports, calls: allCalls, heritage: allHeritage, routes: allRoutes, constructorBindings: allConstructorBindings };
|
|
81
|
+
return { imports: allImports, calls: allCalls, assignments: allAssignments, heritage: allHeritage, routes: allRoutes, constructorBindings: allConstructorBindings, typeEnvBindings: allTypeEnvBindings };
|
|
77
82
|
};
|
|
78
83
|
// ============================================================================
|
|
79
84
|
// Sequential fallback (original implementation)
|
|
@@ -133,62 +138,14 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
133
138
|
match.captures.forEach(c => {
|
|
134
139
|
captureMap[c.name] = c.node;
|
|
135
140
|
});
|
|
136
|
-
|
|
141
|
+
const nodeLabel = getLabelFromCaptures(captureMap, language);
|
|
142
|
+
if (!nodeLabel)
|
|
137
143
|
return;
|
|
138
|
-
}
|
|
139
|
-
if (captureMap['call']) {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
144
|
const nameNode = captureMap['name'];
|
|
143
145
|
// Synthesize name for constructors without explicit @name capture (e.g. Swift init)
|
|
144
|
-
if (!nameNode &&
|
|
146
|
+
if (!nameNode && nodeLabel !== 'Constructor')
|
|
145
147
|
return;
|
|
146
148
|
const nodeName = nameNode ? nameNode.text : 'init';
|
|
147
|
-
let nodeLabel = 'CodeElement';
|
|
148
|
-
if (captureMap['definition.function'])
|
|
149
|
-
nodeLabel = 'Function';
|
|
150
|
-
else if (captureMap['definition.class'])
|
|
151
|
-
nodeLabel = 'Class';
|
|
152
|
-
else if (captureMap['definition.interface'])
|
|
153
|
-
nodeLabel = 'Interface';
|
|
154
|
-
else if (captureMap['definition.method'])
|
|
155
|
-
nodeLabel = 'Method';
|
|
156
|
-
else if (captureMap['definition.struct'])
|
|
157
|
-
nodeLabel = 'Struct';
|
|
158
|
-
else if (captureMap['definition.enum'])
|
|
159
|
-
nodeLabel = 'Enum';
|
|
160
|
-
else if (captureMap['definition.namespace'])
|
|
161
|
-
nodeLabel = 'Namespace';
|
|
162
|
-
else if (captureMap['definition.module'])
|
|
163
|
-
nodeLabel = 'Module';
|
|
164
|
-
else if (captureMap['definition.trait'])
|
|
165
|
-
nodeLabel = 'Trait';
|
|
166
|
-
else if (captureMap['definition.impl'])
|
|
167
|
-
nodeLabel = 'Impl';
|
|
168
|
-
else if (captureMap['definition.type'])
|
|
169
|
-
nodeLabel = 'TypeAlias';
|
|
170
|
-
else if (captureMap['definition.const'])
|
|
171
|
-
nodeLabel = 'Const';
|
|
172
|
-
else if (captureMap['definition.static'])
|
|
173
|
-
nodeLabel = 'Static';
|
|
174
|
-
else if (captureMap['definition.typedef'])
|
|
175
|
-
nodeLabel = 'Typedef';
|
|
176
|
-
else if (captureMap['definition.macro'])
|
|
177
|
-
nodeLabel = 'Macro';
|
|
178
|
-
else if (captureMap['definition.union'])
|
|
179
|
-
nodeLabel = 'Union';
|
|
180
|
-
else if (captureMap['definition.property'])
|
|
181
|
-
nodeLabel = 'Property';
|
|
182
|
-
else if (captureMap['definition.record'])
|
|
183
|
-
nodeLabel = 'Record';
|
|
184
|
-
else if (captureMap['definition.delegate'])
|
|
185
|
-
nodeLabel = 'Delegate';
|
|
186
|
-
else if (captureMap['definition.annotation'])
|
|
187
|
-
nodeLabel = 'Annotation';
|
|
188
|
-
else if (captureMap['definition.constructor'])
|
|
189
|
-
nodeLabel = 'Constructor';
|
|
190
|
-
else if (captureMap['definition.template'])
|
|
191
|
-
nodeLabel = 'Template';
|
|
192
149
|
const definitionNodeForRange = getDefinitionNodeFromCaptures(captureMap);
|
|
193
150
|
const startLine = definitionNodeForRange ? definitionNodeForRange.startPosition.row : (nameNode ? nameNode.startPosition.row : 0);
|
|
194
151
|
const nodeId = generateId(nodeLabel, `${file.path}:${nodeName}`);
|
|
@@ -226,6 +183,8 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
226
183
|
} : {}),
|
|
227
184
|
...(methodSig ? {
|
|
228
185
|
parameterCount: methodSig.parameterCount,
|
|
186
|
+
...(methodSig.requiredParameterCount !== undefined ? { requiredParameterCount: methodSig.requiredParameterCount } : {}),
|
|
187
|
+
...(methodSig.parameterTypes ? { parameterTypes: methodSig.parameterTypes } : {}),
|
|
229
188
|
returnType: methodSig.returnType,
|
|
230
189
|
} : {}),
|
|
231
190
|
},
|
|
@@ -235,9 +194,16 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
235
194
|
// Function is included because Kotlin/Rust/Python capture class methods as Function nodes
|
|
236
195
|
const needsOwner = nodeLabel === 'Method' || nodeLabel === 'Constructor' || nodeLabel === 'Property' || nodeLabel === 'Function';
|
|
237
196
|
const enclosingClassId = needsOwner ? findEnclosingClassId(nameNode || definitionNodeForRange, file.path) : null;
|
|
197
|
+
// Extract declared type for Property nodes (field/property type annotations)
|
|
198
|
+
const declaredType = (nodeLabel === 'Property' && definitionNode)
|
|
199
|
+
? extractPropertyDeclaredType(definitionNode)
|
|
200
|
+
: undefined;
|
|
238
201
|
symbolTable.add(file.path, nodeName, nodeId, nodeLabel, {
|
|
239
202
|
parameterCount: methodSig?.parameterCount,
|
|
203
|
+
requiredParameterCount: methodSig?.requiredParameterCount,
|
|
204
|
+
parameterTypes: methodSig?.parameterTypes,
|
|
240
205
|
returnType: methodSig?.returnType,
|
|
206
|
+
declaredType,
|
|
241
207
|
ownerId: enclosingClassId ?? undefined,
|
|
242
208
|
});
|
|
243
209
|
const fileId = generateId('File', file.path);
|
|
@@ -251,13 +217,14 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
251
217
|
reason: '',
|
|
252
218
|
};
|
|
253
219
|
graph.addRelationship(relationship);
|
|
254
|
-
// ── HAS_METHOD: link
|
|
220
|
+
// ── HAS_METHOD / HAS_PROPERTY: link member to enclosing class ──
|
|
255
221
|
if (enclosingClassId) {
|
|
222
|
+
const memberEdgeType = nodeLabel === 'Property' ? 'HAS_PROPERTY' : 'HAS_METHOD';
|
|
256
223
|
graph.addRelationship({
|
|
257
|
-
id: generateId(
|
|
224
|
+
id: generateId(memberEdgeType, `${enclosingClassId}->${nodeId}`),
|
|
258
225
|
sourceId: enclosingClassId,
|
|
259
226
|
targetId: nodeId,
|
|
260
|
-
type:
|
|
227
|
+
type: memberEdgeType,
|
|
261
228
|
confidence: 1.0,
|
|
262
229
|
reason: '',
|
|
263
230
|
});
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { PipelineProgress, PipelineResult } from '../../types/pipeline.js';
|
|
2
|
+
/** A group of files with no mutual dependencies, safe to process in parallel. */
|
|
3
|
+
type IndependentFileGroup = readonly string[];
|
|
4
|
+
/** Kahn's algorithm: returns files grouped by topological level.
|
|
5
|
+
* Files in the same level have no mutual dependencies — safe to process in parallel.
|
|
6
|
+
* Files in cycles are returned as a final group (no cross-cycle propagation). */
|
|
7
|
+
export declare function topologicalLevelSort(importMap: ReadonlyMap<string, ReadonlySet<string>>): {
|
|
8
|
+
levels: readonly IndependentFileGroup[];
|
|
9
|
+
cycleCount: number;
|
|
10
|
+
};
|
|
2
11
|
export interface PipelineOptions {
|
|
3
12
|
/** Skip MRO, community detection, and process extraction for faster test runs. */
|
|
4
13
|
skipGraphPhases?: boolean;
|
|
5
14
|
}
|
|
6
15
|
export declare const runPipelineFromRepo: (repoPath: string, onProgress: (progress: PipelineProgress) => void, options?: PipelineOptions) => Promise<PipelineResult>;
|
|
16
|
+
export {};
|