gitnexus 1.4.10 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/cli/ai-context.d.ts +4 -1
- package/dist/cli/ai-context.js +19 -11
- package/dist/cli/analyze.d.ts +6 -0
- package/dist/cli/analyze.js +105 -251
- package/dist/cli/eval-server.js +20 -11
- package/dist/cli/index-repo.js +20 -22
- package/dist/cli/index.js +8 -7
- package/dist/cli/mcp.js +1 -1
- package/dist/cli/serve.js +29 -1
- package/dist/cli/setup.js +9 -9
- package/dist/cli/skill-gen.js +15 -9
- package/dist/cli/wiki.d.ts +2 -0
- package/dist/cli/wiki.js +141 -26
- package/dist/config/ignore-service.js +102 -22
- package/dist/config/supported-languages.d.ts +8 -42
- package/dist/config/supported-languages.js +8 -43
- package/dist/core/augmentation/engine.js +19 -7
- package/dist/core/embeddings/embedder.js +19 -15
- package/dist/core/embeddings/embedding-pipeline.js +6 -6
- package/dist/core/embeddings/http-client.js +3 -3
- package/dist/core/embeddings/text-generator.js +9 -24
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/embeddings/types.js +1 -7
- package/dist/core/graph/graph.js +6 -2
- package/dist/core/graph/types.d.ts +9 -59
- package/dist/core/ingestion/ast-cache.js +3 -3
- package/dist/core/ingestion/call-processor.d.ts +20 -2
- package/dist/core/ingestion/call-processor.js +347 -144
- package/dist/core/ingestion/call-routing.js +10 -4
- package/dist/core/ingestion/call-sites/extract-language-call-site.d.ts +10 -0
- package/dist/core/ingestion/call-sites/extract-language-call-site.js +22 -0
- package/dist/core/ingestion/call-sites/java.d.ts +9 -0
- package/dist/core/ingestion/call-sites/java.js +30 -0
- package/dist/core/ingestion/cluster-enricher.js +6 -8
- package/dist/core/ingestion/cobol/cobol-copy-expander.js +10 -3
- package/dist/core/ingestion/cobol/cobol-preprocessor.js +287 -81
- package/dist/core/ingestion/cobol/jcl-parser.js +1 -1
- package/dist/core/ingestion/cobol/jcl-processor.js +1 -1
- package/dist/core/ingestion/cobol-processor.js +102 -56
- package/dist/core/ingestion/community-processor.js +21 -15
- package/dist/core/ingestion/entry-point-scoring.d.ts +1 -1
- package/dist/core/ingestion/entry-point-scoring.js +5 -6
- package/dist/core/ingestion/export-detection.js +32 -9
- package/dist/core/ingestion/field-extractor.d.ts +1 -1
- package/dist/core/ingestion/field-extractors/configs/c-cpp.js +8 -12
- package/dist/core/ingestion/field-extractors/configs/csharp.js +45 -2
- package/dist/core/ingestion/field-extractors/configs/dart.js +5 -3
- package/dist/core/ingestion/field-extractors/configs/go.js +3 -7
- package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +5 -0
- package/dist/core/ingestion/field-extractors/configs/helpers.js +14 -0
- package/dist/core/ingestion/field-extractors/configs/jvm.js +7 -7
- package/dist/core/ingestion/field-extractors/configs/php.js +9 -11
- package/dist/core/ingestion/field-extractors/configs/python.js +1 -1
- package/dist/core/ingestion/field-extractors/configs/ruby.js +4 -3
- package/dist/core/ingestion/field-extractors/configs/rust.js +2 -5
- package/dist/core/ingestion/field-extractors/configs/swift.js +9 -7
- package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +2 -6
- package/dist/core/ingestion/field-extractors/generic.d.ts +5 -2
- package/dist/core/ingestion/field-extractors/generic.js +6 -0
- package/dist/core/ingestion/field-extractors/typescript.d.ts +1 -1
- package/dist/core/ingestion/field-extractors/typescript.js +1 -1
- package/dist/core/ingestion/field-types.d.ts +4 -2
- package/dist/core/ingestion/filesystem-walker.js +3 -3
- package/dist/core/ingestion/framework-detection.d.ts +1 -1
- package/dist/core/ingestion/framework-detection.js +355 -85
- package/dist/core/ingestion/heritage-processor.d.ts +24 -0
- package/dist/core/ingestion/heritage-processor.js +99 -8
- package/dist/core/ingestion/import-processor.js +44 -15
- package/dist/core/ingestion/import-resolvers/csharp.js +7 -3
- package/dist/core/ingestion/import-resolvers/dart.js +1 -1
- package/dist/core/ingestion/import-resolvers/go.js +4 -2
- package/dist/core/ingestion/import-resolvers/jvm.js +4 -4
- package/dist/core/ingestion/import-resolvers/php.js +4 -4
- package/dist/core/ingestion/import-resolvers/python.js +1 -1
- package/dist/core/ingestion/import-resolvers/rust.js +9 -3
- package/dist/core/ingestion/import-resolvers/standard.d.ts +1 -1
- package/dist/core/ingestion/import-resolvers/standard.js +6 -5
- package/dist/core/ingestion/import-resolvers/swift.js +2 -1
- package/dist/core/ingestion/import-resolvers/utils.js +26 -7
- package/dist/core/ingestion/language-config.js +5 -4
- package/dist/core/ingestion/language-provider.d.ts +7 -2
- package/dist/core/ingestion/languages/c-cpp.js +106 -21
- package/dist/core/ingestion/languages/cobol.js +1 -1
- package/dist/core/ingestion/languages/csharp.js +96 -19
- package/dist/core/ingestion/languages/dart.js +23 -7
- package/dist/core/ingestion/languages/go.js +1 -1
- package/dist/core/ingestion/languages/index.d.ts +1 -1
- package/dist/core/ingestion/languages/index.js +2 -3
- package/dist/core/ingestion/languages/java.js +4 -1
- package/dist/core/ingestion/languages/kotlin.js +60 -13
- package/dist/core/ingestion/languages/php.js +102 -25
- package/dist/core/ingestion/languages/python.js +28 -5
- package/dist/core/ingestion/languages/ruby.js +56 -14
- package/dist/core/ingestion/languages/rust.js +55 -11
- package/dist/core/ingestion/languages/swift.js +112 -27
- package/dist/core/ingestion/languages/typescript.js +95 -19
- package/dist/core/ingestion/markdown-processor.js +5 -5
- package/dist/core/ingestion/method-extractors/configs/csharp.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/csharp.js +283 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.js +326 -0
- package/dist/core/ingestion/method-extractors/generic.d.ts +5 -0
- package/dist/core/ingestion/method-extractors/generic.js +137 -0
- package/dist/core/ingestion/method-types.d.ts +61 -0
- package/dist/core/ingestion/method-types.js +2 -0
- package/dist/core/ingestion/mro-processor.d.ts +1 -1
- package/dist/core/ingestion/mro-processor.js +12 -8
- package/dist/core/ingestion/named-binding-processor.js +2 -2
- package/dist/core/ingestion/named-bindings/rust.js +3 -1
- package/dist/core/ingestion/parsing-processor.js +74 -24
- package/dist/core/ingestion/pipeline.d.ts +2 -1
- package/dist/core/ingestion/pipeline.js +208 -102
- package/dist/core/ingestion/process-processor.js +12 -10
- package/dist/core/ingestion/resolution-context.js +3 -3
- package/dist/core/ingestion/route-extractors/middleware.js +31 -7
- package/dist/core/ingestion/route-extractors/php.js +2 -1
- package/dist/core/ingestion/route-extractors/response-shapes.js +8 -4
- package/dist/core/ingestion/structure-processor.d.ts +1 -1
- package/dist/core/ingestion/structure-processor.js +4 -4
- package/dist/core/ingestion/symbol-table.d.ts +1 -1
- package/dist/core/ingestion/symbol-table.js +22 -6
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +1 -1
- package/dist/core/ingestion/type-env.d.ts +2 -2
- package/dist/core/ingestion/type-env.js +75 -50
- package/dist/core/ingestion/type-extractors/c-cpp.js +33 -30
- package/dist/core/ingestion/type-extractors/csharp.js +24 -14
- package/dist/core/ingestion/type-extractors/dart.js +6 -8
- package/dist/core/ingestion/type-extractors/go.js +7 -6
- package/dist/core/ingestion/type-extractors/jvm.js +10 -21
- package/dist/core/ingestion/type-extractors/php.js +26 -13
- package/dist/core/ingestion/type-extractors/python.js +11 -15
- package/dist/core/ingestion/type-extractors/ruby.js +8 -3
- package/dist/core/ingestion/type-extractors/rust.js +6 -8
- package/dist/core/ingestion/type-extractors/shared.js +134 -50
- package/dist/core/ingestion/type-extractors/swift.js +16 -13
- package/dist/core/ingestion/type-extractors/typescript.js +23 -15
- package/dist/core/ingestion/utils/ast-helpers.d.ts +8 -8
- package/dist/core/ingestion/utils/ast-helpers.js +72 -35
- package/dist/core/ingestion/utils/call-analysis.d.ts +2 -0
- package/dist/core/ingestion/utils/call-analysis.js +96 -49
- package/dist/core/ingestion/utils/event-loop.js +1 -1
- package/dist/core/ingestion/workers/parse-worker.d.ts +7 -2
- package/dist/core/ingestion/workers/parse-worker.js +364 -84
- package/dist/core/ingestion/workers/worker-pool.js +5 -10
- package/dist/core/lbug/csv-generator.js +54 -15
- package/dist/core/lbug/lbug-adapter.d.ts +5 -0
- package/dist/core/lbug/lbug-adapter.js +86 -23
- package/dist/core/lbug/schema.d.ts +3 -6
- package/dist/core/lbug/schema.js +6 -30
- package/dist/core/run-analyze.d.ts +49 -0
- package/dist/core/run-analyze.js +257 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +1 -1
- package/dist/core/tree-sitter/parser-loader.js +1 -1
- package/dist/core/wiki/cursor-client.js +2 -7
- package/dist/core/wiki/generator.js +38 -23
- package/dist/core/wiki/graph-queries.js +10 -10
- package/dist/core/wiki/html-viewer.js +7 -3
- package/dist/core/wiki/llm-client.d.ts +23 -2
- package/dist/core/wiki/llm-client.js +96 -26
- package/dist/core/wiki/prompts.js +7 -6
- package/dist/mcp/core/embedder.js +1 -1
- package/dist/mcp/core/lbug-adapter.d.ts +4 -1
- package/dist/mcp/core/lbug-adapter.js +17 -7
- package/dist/mcp/local/local-backend.js +247 -95
- package/dist/mcp/resources.js +14 -6
- package/dist/mcp/server.js +13 -5
- package/dist/mcp/staleness.js +5 -1
- package/dist/mcp/tools.js +100 -23
- package/dist/server/analyze-job.d.ts +53 -0
- package/dist/server/analyze-job.js +146 -0
- package/dist/server/analyze-worker.d.ts +13 -0
- package/dist/server/analyze-worker.js +59 -0
- package/dist/server/api.js +795 -44
- package/dist/server/git-clone.d.ts +25 -0
- package/dist/server/git-clone.js +91 -0
- package/dist/storage/git.js +1 -3
- package/dist/storage/repo-manager.d.ts +5 -2
- package/dist/storage/repo-manager.js +4 -4
- package/dist/types/pipeline.d.ts +1 -21
- package/dist/types/pipeline.js +1 -18
- package/hooks/claude/gitnexus-hook.cjs +52 -22
- package/package.json +3 -2
- package/dist/core/ingestion/utils/language-detection.d.ts +0 -9
- package/dist/core/ingestion/utils/language-detection.js +0 -70
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import Parser from 'tree-sitter';
|
|
17
17
|
import { isLanguageAvailable, loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
|
|
18
18
|
import { generateId } from '../../lib/utils.js';
|
|
19
|
-
import { getLanguageFromFilename } from '
|
|
19
|
+
import { getLanguageFromFilename } from 'gitnexus-shared';
|
|
20
20
|
import { isVerboseIngestionEnabled } from './utils/verbose.js';
|
|
21
21
|
import { yieldToEventLoop } from './utils/event-loop.js';
|
|
22
22
|
import { getProvider } from './languages/index.js';
|
|
@@ -30,7 +30,8 @@ import { TIER_CONFIDENCE } from './resolution-context.js';
|
|
|
30
30
|
* - heritageDefaultEdge: 'IMPLEMENTS' causes all unresolved parents to map to IMPLEMENTS
|
|
31
31
|
* - All others: default EXTENDS
|
|
32
32
|
*/
|
|
33
|
-
|
|
33
|
+
/** Exported for implementor-map construction (C#/Java: `extends` rows in base_list may be interfaces). */
|
|
34
|
+
export const resolveExtendsType = (parentName, currentFilePath, ctx, language) => {
|
|
34
35
|
const resolved = ctx.resolve(parentName, currentFilePath);
|
|
35
36
|
if (resolved && resolved.candidates.length > 0) {
|
|
36
37
|
const isInterface = resolved.candidates[0].type === 'Interface';
|
|
@@ -53,12 +54,18 @@ const resolveHeritageId = (name, filePath, ctx, fallbackLabel, fallbackKey) => {
|
|
|
53
54
|
if (resolved && resolved.candidates.length > 0) {
|
|
54
55
|
// For global with multiple candidates, refuse (a wrong edge is worse than no edge)
|
|
55
56
|
if (resolved.tier === 'global' && resolved.candidates.length > 1) {
|
|
56
|
-
return {
|
|
57
|
+
return {
|
|
58
|
+
id: generateId(fallbackLabel, fallbackKey ?? name),
|
|
59
|
+
confidence: TIER_CONFIDENCE['global'],
|
|
60
|
+
};
|
|
57
61
|
}
|
|
58
62
|
return { id: resolved.candidates[0].nodeId, confidence: TIER_CONFIDENCE[resolved.tier] };
|
|
59
63
|
}
|
|
60
64
|
// Unresolved: use global-tier confidence as fallback
|
|
61
|
-
return {
|
|
65
|
+
return {
|
|
66
|
+
id: generateId(fallbackLabel, fallbackKey ?? name),
|
|
67
|
+
confidence: TIER_CONFIDENCE['global'],
|
|
68
|
+
};
|
|
62
69
|
};
|
|
63
70
|
export const processHeritage = async (graph, files, astCache, ctx, onProgress) => {
|
|
64
71
|
const parser = await loadParser();
|
|
@@ -90,7 +97,9 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
|
|
|
90
97
|
if (!tree) {
|
|
91
98
|
// Use larger bufferSize for files > 32KB
|
|
92
99
|
try {
|
|
93
|
-
tree = parser.parse(file.content, undefined, {
|
|
100
|
+
tree = parser.parse(file.content, undefined, {
|
|
101
|
+
bufferSize: getTreeSitterBufferSize(file.content.length),
|
|
102
|
+
});
|
|
94
103
|
}
|
|
95
104
|
catch (parseError) {
|
|
96
105
|
// Skip files that can't be parsed
|
|
@@ -111,9 +120,9 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
|
|
|
111
120
|
continue;
|
|
112
121
|
}
|
|
113
122
|
// 4. Process heritage matches
|
|
114
|
-
matches.forEach(match => {
|
|
123
|
+
matches.forEach((match) => {
|
|
115
124
|
const captureMap = {};
|
|
116
|
-
match.captures.forEach(c => {
|
|
125
|
+
match.captures.forEach((c) => {
|
|
117
126
|
captureMap[c.name] = c.node;
|
|
118
127
|
});
|
|
119
128
|
// EXTENDS or IMPLEMENTS: resolve via symbol table for languages where
|
|
@@ -228,7 +237,10 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, ctx
|
|
|
228
237
|
});
|
|
229
238
|
}
|
|
230
239
|
}
|
|
231
|
-
else if (h.kind === 'trait-impl' ||
|
|
240
|
+
else if (h.kind === 'trait-impl' ||
|
|
241
|
+
h.kind === 'include' ||
|
|
242
|
+
h.kind === 'extend' ||
|
|
243
|
+
h.kind === 'prepend') {
|
|
232
244
|
const strct = resolveHeritageId(h.className, h.filePath, ctx, 'Struct', `${h.filePath}:${h.className}`);
|
|
233
245
|
const trait = resolveHeritageId(h.parentName, h.filePath, ctx, 'Trait');
|
|
234
246
|
if (strct.id && trait.id) {
|
|
@@ -245,3 +257,82 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, ctx
|
|
|
245
257
|
}
|
|
246
258
|
onProgress?.(total, total);
|
|
247
259
|
};
|
|
260
|
+
/**
|
|
261
|
+
* Walk source files with the same heritage captures as parse-worker, producing
|
|
262
|
+
* {@link ExtractedHeritage} rows without mutating the graph. Used on the
|
|
263
|
+
* sequential pipeline path so `buildImplementorMap(..., ctx)` can run before
|
|
264
|
+
* `processCalls` (worker path defers calls until heritage from all chunks exists).
|
|
265
|
+
*/
|
|
266
|
+
export async function extractExtractedHeritageFromFiles(files, astCache) {
|
|
267
|
+
const parser = await loadParser();
|
|
268
|
+
const out = [];
|
|
269
|
+
for (const file of files) {
|
|
270
|
+
const language = getLanguageFromFilename(file.path);
|
|
271
|
+
if (!language || !isLanguageAvailable(language))
|
|
272
|
+
continue;
|
|
273
|
+
const provider = getProvider(language);
|
|
274
|
+
const queryStr = provider.treeSitterQueries;
|
|
275
|
+
if (!queryStr)
|
|
276
|
+
continue;
|
|
277
|
+
await loadLanguage(language, file.path);
|
|
278
|
+
let tree = astCache.get(file.path);
|
|
279
|
+
if (!tree) {
|
|
280
|
+
try {
|
|
281
|
+
tree = parser.parse(file.content, undefined, {
|
|
282
|
+
bufferSize: getTreeSitterBufferSize(file.content.length),
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
astCache.set(file.path, tree);
|
|
289
|
+
}
|
|
290
|
+
let matches;
|
|
291
|
+
try {
|
|
292
|
+
const lang = parser.getLanguage();
|
|
293
|
+
const query = new Parser.Query(lang, queryStr);
|
|
294
|
+
matches = query.matches(tree.rootNode);
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
for (const match of matches) {
|
|
300
|
+
const captureMap = {};
|
|
301
|
+
match.captures.forEach((c) => {
|
|
302
|
+
captureMap[c.name] = c.node;
|
|
303
|
+
});
|
|
304
|
+
if (captureMap['heritage.class']) {
|
|
305
|
+
if (captureMap['heritage.extends']) {
|
|
306
|
+
const extendsNode = captureMap['heritage.extends'];
|
|
307
|
+
const fieldDecl = extendsNode.parent;
|
|
308
|
+
const isNamedField = fieldDecl?.type === 'field_declaration' && fieldDecl.childForFieldName('name');
|
|
309
|
+
if (!isNamedField) {
|
|
310
|
+
out.push({
|
|
311
|
+
filePath: file.path,
|
|
312
|
+
className: captureMap['heritage.class'].text,
|
|
313
|
+
parentName: captureMap['heritage.extends'].text,
|
|
314
|
+
kind: 'extends',
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (captureMap['heritage.implements']) {
|
|
319
|
+
out.push({
|
|
320
|
+
filePath: file.path,
|
|
321
|
+
className: captureMap['heritage.class'].text,
|
|
322
|
+
parentName: captureMap['heritage.implements'].text,
|
|
323
|
+
kind: 'implements',
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
if (captureMap['heritage.trait']) {
|
|
327
|
+
out.push({
|
|
328
|
+
filePath: file.path,
|
|
329
|
+
className: captureMap['heritage.class'].text,
|
|
330
|
+
parentName: captureMap['heritage.trait'].text,
|
|
331
|
+
kind: 'trait-impl',
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return out;
|
|
338
|
+
}
|
|
@@ -2,7 +2,7 @@ import Parser from 'tree-sitter';
|
|
|
2
2
|
import { isLanguageAvailable, loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
|
|
3
3
|
import { getProvider, getProviderForFile, providersWithImplicitWiring } from './languages/index.js';
|
|
4
4
|
import { generateId } from '../../lib/utils.js';
|
|
5
|
-
import { getLanguageFromFilename } from '
|
|
5
|
+
import { getLanguageFromFilename } from 'gitnexus-shared';
|
|
6
6
|
import { isVerboseIngestionEnabled } from './utils/verbose.js';
|
|
7
7
|
import { yieldToEventLoop } from './utils/event-loop.js';
|
|
8
8
|
import { getTreeSitterBufferSize } from './constants.js';
|
|
@@ -47,7 +47,7 @@ export function isFileInPackageDir(filePath, dirSuffix) {
|
|
|
47
47
|
// ImportResolutionContext is defined in ./import-resolvers/types.ts — re-exported here for consumers.
|
|
48
48
|
export function buildImportResolutionContext(allPaths) {
|
|
49
49
|
const allFileList = allPaths;
|
|
50
|
-
const normalizedFileList = allFileList.map(p => p.replace(/\\/g, '/'));
|
|
50
|
+
const normalizedFileList = allFileList.map((p) => p.replace(/\\/g, '/'));
|
|
51
51
|
const allFilePaths = new Set(allFileList);
|
|
52
52
|
const index = buildSuffixIndex(normalizedFileList, allFileList);
|
|
53
53
|
return { allFilePaths, allFileList, normalizedFileList, index, resolveCache: new Map() };
|
|
@@ -80,7 +80,14 @@ function createImportEdgeHelpers(graph, importMap) {
|
|
|
80
80
|
const targetId = generateId('File', resolvedPath);
|
|
81
81
|
const relId = generateId('IMPORTS', `${filePath}->${resolvedPath}`);
|
|
82
82
|
totalImportsResolved++;
|
|
83
|
-
graph.addRelationship({
|
|
83
|
+
graph.addRelationship({
|
|
84
|
+
id: relId,
|
|
85
|
+
sourceId,
|
|
86
|
+
targetId,
|
|
87
|
+
type: 'IMPORTS',
|
|
88
|
+
confidence: 1.0,
|
|
89
|
+
reason: '',
|
|
90
|
+
});
|
|
84
91
|
};
|
|
85
92
|
const addImportEdge = (filePath, resolvedPath) => {
|
|
86
93
|
addImportGraphEdge(filePath, resolvedPath);
|
|
@@ -147,7 +154,10 @@ function applyImportResult(result, filePath, importMap, packageMap, addImportEdg
|
|
|
147
154
|
fileBindings.delete(binding.local);
|
|
148
155
|
}
|
|
149
156
|
else {
|
|
150
|
-
fileBindings.set(binding.local, {
|
|
157
|
+
fileBindings.set(binding.local, {
|
|
158
|
+
sourcePath: resolvedFile,
|
|
159
|
+
exportedName: binding.exported,
|
|
160
|
+
});
|
|
151
161
|
}
|
|
152
162
|
}
|
|
153
163
|
}
|
|
@@ -159,7 +169,7 @@ function applyImportResult(result, filePath, importMap, packageMap, addImportEdg
|
|
|
159
169
|
if (binding.isModuleAlias)
|
|
160
170
|
continue;
|
|
161
171
|
const lowerName = binding.exported.toLowerCase();
|
|
162
|
-
const matchedFile = files.find(f => {
|
|
172
|
+
const matchedFile = files.find((f) => {
|
|
163
173
|
const base = f.replace(/\\/g, '/').split('/').pop() ?? '';
|
|
164
174
|
const nameWithoutExt = base.substring(0, base.lastIndexOf('.')).toLowerCase();
|
|
165
175
|
return nameWithoutExt === lowerName;
|
|
@@ -170,7 +180,10 @@ function applyImportResult(result, filePath, importMap, packageMap, addImportEdg
|
|
|
170
180
|
fileBindings.delete(binding.local);
|
|
171
181
|
}
|
|
172
182
|
else {
|
|
173
|
-
fileBindings.set(binding.local, {
|
|
183
|
+
fileBindings.set(binding.local, {
|
|
184
|
+
sourcePath: matchedFile,
|
|
185
|
+
exportedName: binding.exported,
|
|
186
|
+
});
|
|
174
187
|
}
|
|
175
188
|
}
|
|
176
189
|
}
|
|
@@ -187,21 +200,28 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
|
|
|
187
200
|
const namedImportMap = ctx.namedImportMap;
|
|
188
201
|
const moduleAliasMap = ctx.moduleAliasMap;
|
|
189
202
|
// Use allPaths (full repo) when available for cross-chunk resolution, else fall back to chunk files
|
|
190
|
-
const allFileList = allPaths ?? files.map(f => f.path);
|
|
203
|
+
const allFileList = allPaths ?? files.map((f) => f.path);
|
|
191
204
|
const allFilePaths = new Set(allFileList);
|
|
192
205
|
const parser = await loadParser();
|
|
193
206
|
const logSkipped = isVerboseIngestionEnabled();
|
|
194
207
|
const skippedByLang = logSkipped ? new Map() : null;
|
|
195
208
|
const resolveCache = new Map();
|
|
196
209
|
// Pre-compute normalized file list once (forward slashes)
|
|
197
|
-
const normalizedFileList = allFileList.map(p => p.replace(/\\/g, '/'));
|
|
210
|
+
const normalizedFileList = allFileList.map((p) => p.replace(/\\/g, '/'));
|
|
198
211
|
// Build suffix index for O(1) lookups
|
|
199
212
|
const index = buildSuffixIndex(normalizedFileList, allFileList);
|
|
200
213
|
// Track import statistics
|
|
201
214
|
let totalImportsFound = 0;
|
|
202
215
|
// Load language-specific configs once before the file loop
|
|
203
216
|
const configs = await loadImportConfigs(repoRoot || '');
|
|
204
|
-
const resolveCtx = {
|
|
217
|
+
const resolveCtx = {
|
|
218
|
+
allFilePaths,
|
|
219
|
+
allFileList,
|
|
220
|
+
normalizedFileList,
|
|
221
|
+
index,
|
|
222
|
+
resolveCache,
|
|
223
|
+
configs,
|
|
224
|
+
};
|
|
205
225
|
const { addImportEdge, addImportGraphEdge, getResolvedCount } = createImportEdgeHelpers(graph, importMap);
|
|
206
226
|
for (let i = 0; i < files.length; i++) {
|
|
207
227
|
const file = files[i];
|
|
@@ -229,7 +249,9 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
|
|
|
229
249
|
let wasReparsed = false;
|
|
230
250
|
if (!tree) {
|
|
231
251
|
try {
|
|
232
|
-
tree = parser.parse(file.content, undefined, {
|
|
252
|
+
tree = parser.parse(file.content, undefined, {
|
|
253
|
+
bufferSize: getTreeSitterBufferSize(file.content.length),
|
|
254
|
+
});
|
|
233
255
|
}
|
|
234
256
|
catch (parseError) {
|
|
235
257
|
continue;
|
|
@@ -260,9 +282,9 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
|
|
|
260
282
|
tree.delete?.();
|
|
261
283
|
continue;
|
|
262
284
|
}
|
|
263
|
-
matches.forEach(match => {
|
|
285
|
+
matches.forEach((match) => {
|
|
264
286
|
const captureMap = {};
|
|
265
|
-
match.captures.forEach(c => captureMap[c.name] = c.node);
|
|
287
|
+
match.captures.forEach((c) => (captureMap[c.name] = c.node));
|
|
266
288
|
if (captureMap['import']) {
|
|
267
289
|
const sourceNode = captureMap['import.source'];
|
|
268
290
|
if (!sourceNode) {
|
|
@@ -313,11 +335,18 @@ export const processImportsFromExtracted = async (graph, files, extractedImports
|
|
|
313
335
|
const packageMap = ctx.packageMap;
|
|
314
336
|
const namedImportMap = ctx.namedImportMap;
|
|
315
337
|
const moduleAliasMap = ctx.moduleAliasMap;
|
|
316
|
-
const importCtx = prebuiltCtx ?? buildImportResolutionContext(files.map(f => f.path));
|
|
338
|
+
const importCtx = prebuiltCtx ?? buildImportResolutionContext(files.map((f) => f.path));
|
|
317
339
|
const { allFilePaths, allFileList, normalizedFileList, index, resolveCache } = importCtx;
|
|
318
340
|
let totalImportsFound = 0;
|
|
319
341
|
const configs = await loadImportConfigs(repoRoot || '');
|
|
320
|
-
const resolveCtx = {
|
|
342
|
+
const resolveCtx = {
|
|
343
|
+
allFilePaths,
|
|
344
|
+
allFileList,
|
|
345
|
+
normalizedFileList,
|
|
346
|
+
index,
|
|
347
|
+
resolveCache,
|
|
348
|
+
configs,
|
|
349
|
+
};
|
|
321
350
|
const { addImportEdge, addImportGraphEdge, getResolvedCount } = createImportEdgeHelpers(graph, importMap);
|
|
322
351
|
// Group by file for progress reporting (users see file count, not import count)
|
|
323
352
|
const importsByFile = new Map();
|
|
@@ -345,7 +374,7 @@ export const processImportsFromExtracted = async (graph, files, extractedImports
|
|
|
345
374
|
}
|
|
346
375
|
}
|
|
347
376
|
onProgress?.(totalFiles, totalFiles);
|
|
348
|
-
wireImplicitImports(files.map(f => f.path), importMap, addImportEdge, configs);
|
|
377
|
+
wireImplicitImports(files.map((f) => f.path), importMap, addImportEdge, configs);
|
|
349
378
|
if (isDev) {
|
|
350
379
|
console.log(`📊 Import processing (fast path): ${getResolvedCount()}/${totalImportsFound} imports resolved to graph edges`);
|
|
351
380
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Handles using-directive resolution via .csproj root namespace stripping.
|
|
4
4
|
*/
|
|
5
5
|
import { suffixResolve } from './utils.js';
|
|
6
|
-
import { SupportedLanguages } from '
|
|
6
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
7
7
|
import { resolveStandard } from './standard.js';
|
|
8
8
|
/**
|
|
9
9
|
* Resolve a C# using-directive import path to matching .cs files (low-level helper).
|
|
@@ -26,7 +26,9 @@ export function resolveCSharpImportInternal(importPath, csharpConfigs, normalize
|
|
|
26
26
|
continue;
|
|
27
27
|
}
|
|
28
28
|
const dirPrefix = config.projectDir
|
|
29
|
-
?
|
|
29
|
+
? relative
|
|
30
|
+
? config.projectDir + '/' + relative
|
|
31
|
+
: config.projectDir
|
|
30
32
|
: relative;
|
|
31
33
|
// 1. Try as single file: relative.cs (e.g., "Models/DlqMessage.cs")
|
|
32
34
|
if (relative) {
|
|
@@ -101,7 +103,9 @@ export function resolveCSharpNamespaceDir(importPath, csharpConfigs) {
|
|
|
101
103
|
continue;
|
|
102
104
|
}
|
|
103
105
|
const dirPrefix = config.projectDir
|
|
104
|
-
?
|
|
106
|
+
? relative
|
|
107
|
+
? config.projectDir + '/' + relative
|
|
108
|
+
: config.projectDir
|
|
105
109
|
: relative;
|
|
106
110
|
if (!dirPrefix)
|
|
107
111
|
continue;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SDK imports (dart:*) and external packages are skipped.
|
|
5
5
|
*/
|
|
6
6
|
import { resolveStandard } from './standard.js';
|
|
7
|
-
import { SupportedLanguages } from '
|
|
7
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
8
8
|
export function resolveDartImport(rawImportPath, filePath, ctx) {
|
|
9
9
|
// Strip surrounding quotes from configurable_uri capture
|
|
10
10
|
const stripped = rawImportPath.replace(/^['"]|['"]$/g, '');
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Go package import resolution.
|
|
3
3
|
* Handles Go module path-based package imports.
|
|
4
4
|
*/
|
|
5
|
-
import { SupportedLanguages } from '
|
|
5
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
6
6
|
import { resolveStandard } from './standard.js';
|
|
7
7
|
/**
|
|
8
8
|
* Extract the package directory suffix from a Go import path.
|
|
@@ -33,7 +33,9 @@ export function resolveGoPackage(importPath, goModule, normalizedFileList, allFi
|
|
|
33
33
|
// Prepend '/' so paths like "internal/auth/service.go" match suffix "/internal/auth/"
|
|
34
34
|
const normalized = '/' + normalizedFileList[i];
|
|
35
35
|
// File must be directly in the package directory (not a subdirectory)
|
|
36
|
-
if (normalized.includes(pkgSuffix) &&
|
|
36
|
+
if (normalized.includes(pkgSuffix) &&
|
|
37
|
+
normalized.endsWith('.go') &&
|
|
38
|
+
!normalized.endsWith('_test.go')) {
|
|
37
39
|
const afterPkg = normalized.substring(normalized.indexOf(pkgSuffix) + pkgSuffix.length);
|
|
38
40
|
if (!afterPkg.includes('/')) {
|
|
39
41
|
matches.push(allFileList[i]);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* JVM import resolution (Java + Kotlin).
|
|
3
3
|
* Handles wildcard imports, member/static imports, and Kotlin-specific patterns.
|
|
4
4
|
*/
|
|
5
|
-
import { SupportedLanguages } from '
|
|
5
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
6
6
|
import { resolveStandard } from './standard.js';
|
|
7
7
|
/** Kotlin file extensions for JVM resolver reuse */
|
|
8
8
|
export const KOTLIN_EXTENSIONS = ['.kt', '.kts'];
|
|
@@ -26,11 +26,11 @@ export function resolveJvmWildcard(importPath, normalizedFileList, allFileList,
|
|
|
26
26
|
// "com.example.util.*" -> "com/example/util"
|
|
27
27
|
const packagePath = importPath.slice(0, -2).replace(/\./g, '/');
|
|
28
28
|
if (index) {
|
|
29
|
-
const candidates = extensions.flatMap(ext => index.getFilesInDir(packagePath, ext));
|
|
29
|
+
const candidates = extensions.flatMap((ext) => index.getFilesInDir(packagePath, ext));
|
|
30
30
|
// Filter to only direct children (no subdirectories)
|
|
31
31
|
const packageSuffix = '/' + packagePath + '/';
|
|
32
32
|
const packagePrefix = packagePath + '/';
|
|
33
|
-
return candidates.filter(f => {
|
|
33
|
+
return candidates.filter((f) => {
|
|
34
34
|
const normalized = f.replace(/\\/g, '/');
|
|
35
35
|
// Match both nested (src/models/User.kt) and root-level (models/User.kt) packages
|
|
36
36
|
let afterPkg;
|
|
@@ -53,7 +53,7 @@ export function resolveJvmWildcard(importPath, normalizedFileList, allFileList,
|
|
|
53
53
|
const matches = [];
|
|
54
54
|
for (let i = 0; i < normalizedFileList.length; i++) {
|
|
55
55
|
const normalized = normalizedFileList[i];
|
|
56
|
-
if (!extensions.some(ext => normalized.endsWith(ext)))
|
|
56
|
+
if (!extensions.some((ext) => normalized.endsWith(ext)))
|
|
57
57
|
continue;
|
|
58
58
|
// Match both nested (src/models/User.kt) and root-level (models/User.kt) packages
|
|
59
59
|
let afterPackage = null;
|
|
@@ -50,9 +50,7 @@ export function resolvePhpImportInternal(importPath, composerConfig, allFiles, n
|
|
|
50
50
|
// 2. Function/constant fallback: strip last segment (symbol name), scan namespace directory.
|
|
51
51
|
// e.g. App\Models\getUser → directory app/Models/, find first .php file in that dir.
|
|
52
52
|
const lastSlash = remainder.lastIndexOf('/');
|
|
53
|
-
const nsDir = lastSlash >= 0
|
|
54
|
-
? dirPrefix + '/' + remainder.slice(0, lastSlash)
|
|
55
|
-
: dirPrefix;
|
|
53
|
+
const nsDir = lastSlash >= 0 ? dirPrefix + '/' + remainder.slice(0, lastSlash) : dirPrefix;
|
|
56
54
|
// Prefer SuffixIndex directory lookup (O(log n + matches)) over linear scan
|
|
57
55
|
if (index) {
|
|
58
56
|
const candidates = index.getFilesInDir(nsDir, '.php');
|
|
@@ -62,7 +60,9 @@ export function resolvePhpImportInternal(importPath, composerConfig, allFiles, n
|
|
|
62
60
|
// Fallback: linear scan (only when SuffixIndex unavailable)
|
|
63
61
|
const nsDirPrefix = nsDir.endsWith('/') ? nsDir : nsDir + '/';
|
|
64
62
|
for (const f of allFiles) {
|
|
65
|
-
if (f.startsWith(nsDirPrefix) &&
|
|
63
|
+
if (f.startsWith(nsDirPrefix) &&
|
|
64
|
+
f.endsWith('.php') &&
|
|
65
|
+
!f.slice(nsDirPrefix.length).includes('/')) {
|
|
66
66
|
return f;
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Import system spec: PEP 302 (original), PEP 451 (current).
|
|
4
4
|
*/
|
|
5
5
|
import { tryResolveWithExtensions } from './utils.js';
|
|
6
|
-
import { SupportedLanguages } from '
|
|
6
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
7
7
|
import { resolveStandard } from './standard.js';
|
|
8
8
|
/**
|
|
9
9
|
* Resolve a Python import to a file path (low-level helper).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Rust module import resolution.
|
|
3
3
|
* Handles crate::, super::, self:: prefix paths and :: separators.
|
|
4
4
|
*/
|
|
5
|
-
import { SupportedLanguages } from '
|
|
5
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
6
6
|
import { resolveStandard } from './standard.js';
|
|
7
7
|
/**
|
|
8
8
|
* Resolve Rust use-path to a file (low-level helper).
|
|
@@ -78,7 +78,10 @@ export function resolveRustImport(rawImportPath, filePath, ctx) {
|
|
|
78
78
|
// Top-level grouped: use {crate::a, crate::b}
|
|
79
79
|
if (rawImportPath.startsWith('{') && rawImportPath.endsWith('}')) {
|
|
80
80
|
const inner = rawImportPath.slice(1, -1);
|
|
81
|
-
const parts = inner
|
|
81
|
+
const parts = inner
|
|
82
|
+
.split(',')
|
|
83
|
+
.map((p) => p.trim())
|
|
84
|
+
.filter(Boolean);
|
|
82
85
|
const resolved = [];
|
|
83
86
|
for (const part of parts) {
|
|
84
87
|
const r = resolveRustImportInternal(filePath, part, ctx.allFilePaths);
|
|
@@ -92,7 +95,10 @@ export function resolveRustImport(rawImportPath, filePath, ctx) {
|
|
|
92
95
|
if (braceIdx !== -1 && rawImportPath.endsWith('}')) {
|
|
93
96
|
const pathPrefix = rawImportPath.substring(0, braceIdx);
|
|
94
97
|
const braceContent = rawImportPath.substring(braceIdx + 3, rawImportPath.length - 1);
|
|
95
|
-
const items = braceContent
|
|
98
|
+
const items = braceContent
|
|
99
|
+
.split(',')
|
|
100
|
+
.map((s) => s.trim())
|
|
101
|
+
.filter(Boolean);
|
|
96
102
|
const resolved = [];
|
|
97
103
|
for (const item of items) {
|
|
98
104
|
// Handle `use crate::models::{User, Repo as R}` — strip alias for resolution
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Used as the fallback when language-specific resolvers don't match.
|
|
5
5
|
*/
|
|
6
6
|
import type { SuffixIndex } from './utils.js';
|
|
7
|
-
import { SupportedLanguages } from '
|
|
7
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
8
8
|
import type { ImportResult, ImportResolverFn, ResolveCtx } from './types.js';
|
|
9
9
|
import type { TsconfigPaths } from '../language-config.js';
|
|
10
10
|
/** Max entries in the resolve cache. Beyond this, entries are evicted.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { tryResolveWithExtensions, suffixResolve } from './utils.js';
|
|
7
7
|
import { resolveRustImportInternal } from './rust.js';
|
|
8
|
-
import { SupportedLanguages } from '
|
|
8
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
9
9
|
/** Max entries in the resolve cache. Beyond this, entries are evicted.
|
|
10
10
|
* 100K entries ≈ 15MB — covers the most common import patterns. */
|
|
11
11
|
export const RESOLVE_CACHE_CAP = 100_000;
|
|
@@ -76,7 +76,10 @@ export const resolveImportPath = (currentFile, importPath, allFiles, allFileList
|
|
|
76
76
|
// Rust grouped-import blocks in processImports / processImportsBatch). This fallback
|
|
77
77
|
// handles any path that reaches resolveImportPath directly.
|
|
78
78
|
const inner = importPath.slice(1, -1);
|
|
79
|
-
const parts = inner
|
|
79
|
+
const parts = inner
|
|
80
|
+
.split(',')
|
|
81
|
+
.map((p) => p.trim())
|
|
82
|
+
.filter(Boolean);
|
|
80
83
|
for (const part of parts) {
|
|
81
84
|
const partResult = resolveRustImportInternal(currentFile, part, allFiles);
|
|
82
85
|
if (partResult)
|
|
@@ -114,9 +117,7 @@ export const resolveImportPath = (currentFile, importPath, allFiles, allFileList
|
|
|
114
117
|
}
|
|
115
118
|
// C/C++ includes use actual file paths (e.g. "animal.h") — don't convert dots to slashes
|
|
116
119
|
const isCpp = language === SupportedLanguages.C || language === SupportedLanguages.CPlusPlus;
|
|
117
|
-
const pathLike = importPath.includes('/') || isCpp
|
|
118
|
-
? importPath
|
|
119
|
-
: importPath.replace(/\./g, '/');
|
|
120
|
+
const pathLike = importPath.includes('/') || isCpp ? importPath : importPath.replace(/\./g, '/');
|
|
120
121
|
const pathParts = pathLike.split('/').filter(Boolean);
|
|
121
122
|
const resolved = suffixResolve(pathParts, normalizedFileList, allFileList, index);
|
|
122
123
|
return cache(resolved);
|
|
@@ -11,7 +11,8 @@ export function resolveSwiftImport(rawImportPath, _filePath, ctx) {
|
|
|
11
11
|
const dirPrefix = targetDir + '/';
|
|
12
12
|
const files = [];
|
|
13
13
|
for (let i = 0; i < ctx.normalizedFileList.length; i++) {
|
|
14
|
-
if (ctx.normalizedFileList[i].startsWith(dirPrefix) &&
|
|
14
|
+
if (ctx.normalizedFileList[i].startsWith(dirPrefix) &&
|
|
15
|
+
ctx.normalizedFileList[i].endsWith('.swift')) {
|
|
15
16
|
files.push(ctx.allFileList[i]);
|
|
16
17
|
}
|
|
17
18
|
}
|
|
@@ -6,23 +6,41 @@
|
|
|
6
6
|
export const EXTENSIONS = [
|
|
7
7
|
'',
|
|
8
8
|
// TypeScript/JavaScript
|
|
9
|
-
'.tsx',
|
|
9
|
+
'.tsx',
|
|
10
|
+
'.ts',
|
|
11
|
+
'.jsx',
|
|
12
|
+
'.js',
|
|
13
|
+
'/index.tsx',
|
|
14
|
+
'/index.ts',
|
|
15
|
+
'/index.jsx',
|
|
16
|
+
'/index.js',
|
|
10
17
|
// Python
|
|
11
|
-
'.py',
|
|
18
|
+
'.py',
|
|
19
|
+
'/__init__.py',
|
|
12
20
|
// Java
|
|
13
21
|
'.java',
|
|
14
22
|
// Kotlin
|
|
15
|
-
'.kt',
|
|
23
|
+
'.kt',
|
|
24
|
+
'.kts',
|
|
16
25
|
// C/C++
|
|
17
|
-
'.c',
|
|
26
|
+
'.c',
|
|
27
|
+
'.h',
|
|
28
|
+
'.cpp',
|
|
29
|
+
'.hpp',
|
|
30
|
+
'.cc',
|
|
31
|
+
'.cxx',
|
|
32
|
+
'.hxx',
|
|
33
|
+
'.hh',
|
|
18
34
|
// C#
|
|
19
35
|
'.cs',
|
|
20
36
|
// Go
|
|
21
37
|
'.go',
|
|
22
38
|
// Rust
|
|
23
|
-
'.rs',
|
|
39
|
+
'.rs',
|
|
40
|
+
'/mod.rs',
|
|
24
41
|
// PHP
|
|
25
|
-
'.php',
|
|
42
|
+
'.php',
|
|
43
|
+
'.phtml',
|
|
26
44
|
// Swift
|
|
27
45
|
'.swift',
|
|
28
46
|
// Ruby
|
|
@@ -119,7 +137,8 @@ export function suffixResolve(pathParts, normalizedFileList, allFileList, index)
|
|
|
119
137
|
for (const ext of EXTENSIONS) {
|
|
120
138
|
const suffixWithExt = suffix + ext;
|
|
121
139
|
const suffixPattern = '/' + suffixWithExt;
|
|
122
|
-
const matchIdx = normalizedFileList.findIndex(filePath => filePath.endsWith(suffixPattern) ||
|
|
140
|
+
const matchIdx = normalizedFileList.findIndex((filePath) => filePath.endsWith(suffixPattern) ||
|
|
141
|
+
filePath.toLowerCase().endsWith(suffixPattern.toLowerCase()));
|
|
123
142
|
if (matchIdx !== -1) {
|
|
124
143
|
return allFileList[matchIdx];
|
|
125
144
|
}
|
|
@@ -107,7 +107,10 @@ export async function loadCSharpProjectConfig(repoRoot) {
|
|
|
107
107
|
for (const entry of entries) {
|
|
108
108
|
if (entry.isDirectory() && depth < maxDepth) {
|
|
109
109
|
// Skip common non-project directories
|
|
110
|
-
if (entry.name === 'node_modules' ||
|
|
110
|
+
if (entry.name === 'node_modules' ||
|
|
111
|
+
entry.name === '.git' ||
|
|
112
|
+
entry.name === 'bin' ||
|
|
113
|
+
entry.name === 'obj')
|
|
111
114
|
continue;
|
|
112
115
|
scanQueue.push({ dir: path.join(dir, entry.name), depth: depth + 1 });
|
|
113
116
|
}
|
|
@@ -116,9 +119,7 @@ export async function loadCSharpProjectConfig(repoRoot) {
|
|
|
116
119
|
const csprojPath = path.join(dir, entry.name);
|
|
117
120
|
const content = await fs.readFile(csprojPath, 'utf-8');
|
|
118
121
|
const nsMatch = content.match(/<RootNamespace>\s*([^<]+)\s*<\/RootNamespace>/);
|
|
119
|
-
const rootNamespace = nsMatch
|
|
120
|
-
? nsMatch[1].trim()
|
|
121
|
-
: entry.name.replace(/\.csproj$/, '');
|
|
122
|
+
const rootNamespace = nsMatch ? nsMatch[1].trim() : entry.name.replace(/\.csproj$/, '');
|
|
122
123
|
const projectDir = path.relative(repoRoot, dir).replace(/\\/g, '/');
|
|
123
124
|
configs.push({ rootNamespace, projectDir });
|
|
124
125
|
if (isDev) {
|
|
@@ -8,15 +8,16 @@
|
|
|
8
8
|
* The providers table in `languages/index.ts` uses `satisfies Record<SupportedLanguages, LanguageProvider>`
|
|
9
9
|
* so adding a language to the enum without creating a provider is a compiler error.
|
|
10
10
|
*/
|
|
11
|
-
import type { SupportedLanguages } from '
|
|
11
|
+
import type { SupportedLanguages } from 'gitnexus-shared';
|
|
12
12
|
import type { LanguageTypeConfig } from './type-extractors/types.js';
|
|
13
13
|
import type { CallRouter } from './call-routing.js';
|
|
14
14
|
import type { ExportChecker } from './export-detection.js';
|
|
15
15
|
import type { FieldExtractor } from './field-extractor.js';
|
|
16
|
+
import type { MethodExtractor } from './method-types.js';
|
|
16
17
|
import type { ImportResolverFn } from './import-resolvers/types.js';
|
|
17
18
|
import type { NamedBindingExtractorFn } from './named-bindings/types.js';
|
|
18
19
|
import type { SyntaxNode } from './utils/ast-helpers.js';
|
|
19
|
-
import type { NodeLabel } from '
|
|
20
|
+
import type { NodeLabel } from 'gitnexus-shared';
|
|
20
21
|
/** Tree-sitter query captures: capture name → AST node (or undefined if not captured). */
|
|
21
22
|
export type CaptureMap = Record<string, SyntaxNode | undefined>;
|
|
22
23
|
/** MRO strategy for multiple inheritance resolution. */
|
|
@@ -96,6 +97,10 @@ interface LanguageProviderConfig {
|
|
|
96
97
|
* declarations. Produces FieldInfo[] with name, type, visibility, static,
|
|
97
98
|
* readonly metadata. Default: undefined (no field extraction). */
|
|
98
99
|
readonly fieldExtractor?: FieldExtractor;
|
|
100
|
+
/** Method extractor for extracting method/function definitions from class/struct/interface
|
|
101
|
+
* declarations. Produces MethodInfo[] with name, parameters, visibility, isAbstract,
|
|
102
|
+
* isFinal, annotations metadata. Default: undefined (no method extraction). */
|
|
103
|
+
readonly methodExtractor?: MethodExtractor;
|
|
99
104
|
/** Extract a semantic description for a definition node (e.g., PHP Eloquent
|
|
100
105
|
* property arrays, relation method descriptions).
|
|
101
106
|
* Default: undefined (no description extraction). */
|