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
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// gitnexus/src/core/ingestion/method-extractors/generic.ts
|
|
2
|
+
/** Owner node types where member functions are effectively static (JVM semantics). */
|
|
3
|
+
const STATIC_OWNER_TYPES = new Set(['companion_object', 'object_declaration']);
|
|
4
|
+
/**
|
|
5
|
+
* Create a MethodExtractor from a declarative config.
|
|
6
|
+
*/
|
|
7
|
+
export function createMethodExtractor(config) {
|
|
8
|
+
const typeDeclarationSet = new Set(config.typeDeclarationNodes);
|
|
9
|
+
const methodNodeSet = new Set(config.methodNodeTypes);
|
|
10
|
+
const bodyNodeSet = new Set(config.bodyNodeTypes);
|
|
11
|
+
return {
|
|
12
|
+
language: config.language,
|
|
13
|
+
isTypeDeclaration(node) {
|
|
14
|
+
return typeDeclarationSet.has(node.type);
|
|
15
|
+
},
|
|
16
|
+
extract(node, context) {
|
|
17
|
+
if (!typeDeclarationSet.has(node.type))
|
|
18
|
+
return null;
|
|
19
|
+
// Resolve owner name: field-based → type_identifier → simple_identifier → "Companion"
|
|
20
|
+
let ownerName;
|
|
21
|
+
const nameField = node.childForFieldName('name');
|
|
22
|
+
if (nameField) {
|
|
23
|
+
ownerName = nameField.text;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
27
|
+
const child = node.namedChild(i);
|
|
28
|
+
if (child && (child.type === 'type_identifier' || child.type === 'simple_identifier')) {
|
|
29
|
+
ownerName = child.text;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Unnamed companion objects use "Companion" (Kotlin convention)
|
|
35
|
+
if (!ownerName && node.type === 'companion_object') {
|
|
36
|
+
ownerName = 'Companion';
|
|
37
|
+
}
|
|
38
|
+
if (!ownerName)
|
|
39
|
+
return null;
|
|
40
|
+
const methods = [];
|
|
41
|
+
const bodies = findBodies(node, bodyNodeSet);
|
|
42
|
+
for (const body of bodies) {
|
|
43
|
+
extractMethodsFromBody(body, node, context, config, methodNodeSet, methods);
|
|
44
|
+
}
|
|
45
|
+
// Extract primary constructor from the owner node itself (e.g. C# 12)
|
|
46
|
+
if (config.extractPrimaryConstructor) {
|
|
47
|
+
const primaryCtor = config.extractPrimaryConstructor(node, context);
|
|
48
|
+
if (primaryCtor)
|
|
49
|
+
methods.push(primaryCtor);
|
|
50
|
+
}
|
|
51
|
+
return { ownerName, methods };
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function findBodies(node, bodyNodeSet) {
|
|
56
|
+
const result = [];
|
|
57
|
+
const bodyField = node.childForFieldName('body');
|
|
58
|
+
if (bodyField && bodyNodeSet.has(bodyField.type)) {
|
|
59
|
+
result.push(bodyField);
|
|
60
|
+
addNestedBodies(bodyField, bodyNodeSet, result);
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
64
|
+
const child = node.namedChild(i);
|
|
65
|
+
if (child && bodyNodeSet.has(child.type)) {
|
|
66
|
+
result.push(child);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (result.length === 0 && bodyField) {
|
|
70
|
+
// Fallback: body field exists but its type is not in bodyNodeTypes.
|
|
71
|
+
// This may indicate a config typo — log for debugging if NODE_ENV is development.
|
|
72
|
+
if (process.env.NODE_ENV === 'development') {
|
|
73
|
+
console.warn(`[MethodExtractor] body field type '${bodyField.type}' not in bodyNodeTypes for node '${node.type}'`);
|
|
74
|
+
}
|
|
75
|
+
result.push(bodyField);
|
|
76
|
+
addNestedBodies(bodyField, bodyNodeSet, result);
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
function addNestedBodies(parent, bodyNodeSet, out) {
|
|
81
|
+
for (let i = 0; i < parent.namedChildCount; i++) {
|
|
82
|
+
const child = parent.namedChild(i);
|
|
83
|
+
if (child && bodyNodeSet.has(child.type) && !out.includes(child)) {
|
|
84
|
+
out.push(child);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function extractMethodsFromBody(body, ownerNode, context, config, methodNodeSet, out) {
|
|
89
|
+
for (let i = 0; i < body.namedChildCount; i++) {
|
|
90
|
+
const child = body.namedChild(i);
|
|
91
|
+
if (!child)
|
|
92
|
+
continue;
|
|
93
|
+
if (methodNodeSet.has(child.type)) {
|
|
94
|
+
const method = buildMethod(child, ownerNode, context, config);
|
|
95
|
+
if (method)
|
|
96
|
+
out.push(method);
|
|
97
|
+
}
|
|
98
|
+
// Recurse into enum constant anonymous class bodies
|
|
99
|
+
if (child.type === 'enum_constant') {
|
|
100
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
101
|
+
const innerBody = child.namedChild(j);
|
|
102
|
+
if (innerBody && innerBody.type === 'class_body') {
|
|
103
|
+
extractMethodsFromBody(innerBody, ownerNode, context, config, methodNodeSet, out);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function buildMethod(node, ownerNode, context, config) {
|
|
110
|
+
const name = config.extractName(node);
|
|
111
|
+
if (!name)
|
|
112
|
+
return null;
|
|
113
|
+
const isAbstract = config.isAbstract(node, ownerNode);
|
|
114
|
+
let isFinal = config.isFinal(node);
|
|
115
|
+
// Domain invariant: abstract methods cannot be final
|
|
116
|
+
if (isAbstract)
|
|
117
|
+
isFinal = false;
|
|
118
|
+
// companion_object / object_declaration members are effectively static on JVM
|
|
119
|
+
const isStatic = STATIC_OWNER_TYPES.has(ownerNode.type) || config.isStatic(node);
|
|
120
|
+
return {
|
|
121
|
+
name,
|
|
122
|
+
receiverType: config.extractReceiverType?.(node) ?? null,
|
|
123
|
+
returnType: config.extractReturnType(node) ?? null,
|
|
124
|
+
parameters: config.extractParameters(node),
|
|
125
|
+
visibility: config.extractVisibility(node),
|
|
126
|
+
isStatic,
|
|
127
|
+
isAbstract,
|
|
128
|
+
isFinal,
|
|
129
|
+
...(config.isVirtual?.(node) ? { isVirtual: true } : {}),
|
|
130
|
+
...(config.isOverride?.(node) ? { isOverride: true } : {}),
|
|
131
|
+
...(config.isAsync?.(node) ? { isAsync: true } : {}),
|
|
132
|
+
...(config.isPartial?.(node) ? { isPartial: true } : {}),
|
|
133
|
+
annotations: config.extractAnnotations?.(node) ?? [],
|
|
134
|
+
sourceFile: context.filePath,
|
|
135
|
+
line: node.startPosition.row + 1,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { SupportedLanguages } from 'gitnexus-shared';
|
|
2
|
+
import type { FieldVisibility } from './field-types.js';
|
|
3
|
+
import type { SyntaxNode } from './utils/ast-helpers.js';
|
|
4
|
+
export type MethodVisibility = FieldVisibility;
|
|
5
|
+
export interface ParameterInfo {
|
|
6
|
+
name: string;
|
|
7
|
+
type: string | null;
|
|
8
|
+
isOptional: boolean;
|
|
9
|
+
isVariadic: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface MethodInfo {
|
|
12
|
+
name: string;
|
|
13
|
+
receiverType: string | null;
|
|
14
|
+
returnType: string | null;
|
|
15
|
+
parameters: ParameterInfo[];
|
|
16
|
+
visibility: MethodVisibility;
|
|
17
|
+
isStatic: boolean;
|
|
18
|
+
isAbstract: boolean;
|
|
19
|
+
isFinal: boolean;
|
|
20
|
+
isVirtual?: boolean;
|
|
21
|
+
isOverride?: boolean;
|
|
22
|
+
isAsync?: boolean;
|
|
23
|
+
isPartial?: boolean;
|
|
24
|
+
annotations: string[];
|
|
25
|
+
sourceFile: string;
|
|
26
|
+
line: number;
|
|
27
|
+
}
|
|
28
|
+
export interface MethodExtractorContext {
|
|
29
|
+
filePath: string;
|
|
30
|
+
language: SupportedLanguages;
|
|
31
|
+
}
|
|
32
|
+
export interface ExtractedMethods {
|
|
33
|
+
ownerName: string;
|
|
34
|
+
methods: MethodInfo[];
|
|
35
|
+
}
|
|
36
|
+
export interface MethodExtractor {
|
|
37
|
+
language: SupportedLanguages;
|
|
38
|
+
extract(node: SyntaxNode, context: MethodExtractorContext): ExtractedMethods | null;
|
|
39
|
+
isTypeDeclaration(node: SyntaxNode): boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface MethodExtractionConfig {
|
|
42
|
+
language: SupportedLanguages;
|
|
43
|
+
typeDeclarationNodes: string[];
|
|
44
|
+
methodNodeTypes: string[];
|
|
45
|
+
bodyNodeTypes: string[];
|
|
46
|
+
extractName: (node: SyntaxNode) => string | undefined;
|
|
47
|
+
extractReturnType: (node: SyntaxNode) => string | undefined;
|
|
48
|
+
extractParameters: (node: SyntaxNode) => ParameterInfo[];
|
|
49
|
+
extractVisibility: (node: SyntaxNode) => MethodVisibility;
|
|
50
|
+
isStatic: (node: SyntaxNode) => boolean;
|
|
51
|
+
isAbstract: (node: SyntaxNode, ownerNode: SyntaxNode) => boolean;
|
|
52
|
+
isFinal: (node: SyntaxNode) => boolean;
|
|
53
|
+
extractAnnotations?: (node: SyntaxNode) => string[];
|
|
54
|
+
extractReceiverType?: (node: SyntaxNode) => string | undefined;
|
|
55
|
+
isVirtual?: (node: SyntaxNode) => boolean;
|
|
56
|
+
isOverride?: (node: SyntaxNode) => boolean;
|
|
57
|
+
isAsync?: (node: SyntaxNode) => boolean;
|
|
58
|
+
isPartial?: (node: SyntaxNode) => boolean;
|
|
59
|
+
/** Extract a primary constructor from the owner node itself (e.g. C# 12 class Point(int x, int y)). */
|
|
60
|
+
extractPrimaryConstructor?: (ownerNode: SyntaxNode, context: MethodExtractorContext) => MethodInfo | null;
|
|
61
|
+
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* Cypher: MATCH (c:Class)-[r:CodeRelation {type: 'OVERRIDES'}]->(m:Method)
|
|
20
20
|
*/
|
|
21
21
|
import { KnowledgeGraph } from '../graph/types.js';
|
|
22
|
-
import { SupportedLanguages } from '
|
|
22
|
+
import { SupportedLanguages } from 'gitnexus-shared';
|
|
23
23
|
export interface MROEntry {
|
|
24
24
|
classId: string;
|
|
25
25
|
className: string;
|
|
@@ -119,14 +119,14 @@ function c3Linearize(classId, parentMap, cache, inProgress) {
|
|
|
119
119
|
// Add the direct parents list as the final sequence
|
|
120
120
|
const sequences = [...parentLinearizations, [...directParents]];
|
|
121
121
|
const result = [];
|
|
122
|
-
while (sequences.some(s => s.length > 0)) {
|
|
122
|
+
while (sequences.some((s) => s.length > 0)) {
|
|
123
123
|
// Find a good head: one that doesn't appear in the tail of any other sequence
|
|
124
124
|
let head = null;
|
|
125
125
|
for (const seq of sequences) {
|
|
126
126
|
if (seq.length === 0)
|
|
127
127
|
continue;
|
|
128
128
|
const candidate = seq[0];
|
|
129
|
-
const inTail = sequences.some(other => other.length > 1 && other.indexOf(candidate, 1) !== -1);
|
|
129
|
+
const inTail = sequences.some((other) => other.length > 1 && other.indexOf(candidate, 1) !== -1);
|
|
130
130
|
if (!inTail) {
|
|
131
131
|
head = candidate;
|
|
132
132
|
break;
|
|
@@ -153,7 +153,7 @@ function c3Linearize(classId, parentMap, cache, inProgress) {
|
|
|
153
153
|
/** Resolve by MRO order — first ancestor in linearized order wins. */
|
|
154
154
|
function resolveByMroOrder(methodName, defs, mroOrder, reasonPrefix) {
|
|
155
155
|
for (const ancestorId of mroOrder) {
|
|
156
|
-
const match = defs.find(d => d.classId === ancestorId);
|
|
156
|
+
const match = defs.find((d) => d.classId === ancestorId);
|
|
157
157
|
if (match) {
|
|
158
158
|
return {
|
|
159
159
|
resolvedTo: match.methodId,
|
|
@@ -162,7 +162,11 @@ function resolveByMroOrder(methodName, defs, mroOrder, reasonPrefix) {
|
|
|
162
162
|
};
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
|
-
return {
|
|
165
|
+
return {
|
|
166
|
+
resolvedTo: defs[0].methodId,
|
|
167
|
+
reason: `${reasonPrefix} fallback: first definition`,
|
|
168
|
+
confidence: 0.7,
|
|
169
|
+
};
|
|
166
170
|
}
|
|
167
171
|
function resolveCsharpJava(methodName, defs, parentEdgeTypes) {
|
|
168
172
|
const classDefs = [];
|
|
@@ -186,7 +190,7 @@ function resolveCsharpJava(methodName, defs, parentEdgeTypes) {
|
|
|
186
190
|
if (interfaceDefs.length > 1) {
|
|
187
191
|
return {
|
|
188
192
|
resolvedTo: null,
|
|
189
|
-
reason: `ambiguous: ${methodName} defined in multiple interfaces: ${interfaceDefs.map(d => d.className).join(', ')}`,
|
|
193
|
+
reason: `ambiguous: ${methodName} defined in multiple interfaces: ${interfaceDefs.map((d) => d.className).join(', ')}`,
|
|
190
194
|
confidence: 0.5,
|
|
191
195
|
};
|
|
192
196
|
}
|
|
@@ -231,7 +235,7 @@ export function computeMRO(graph) {
|
|
|
231
235
|
}
|
|
232
236
|
// Get the parent names for the MRO entry
|
|
233
237
|
const mroNames = mroOrder
|
|
234
|
-
.map(id => graph.getNode(id)?.properties.name)
|
|
238
|
+
.map((id) => graph.getNode(id)?.properties.name)
|
|
235
239
|
.filter((n) => n !== undefined);
|
|
236
240
|
// Collect methods from all ancestors, grouped by method name
|
|
237
241
|
const methodsByName = new Map();
|
|
@@ -254,7 +258,7 @@ export function computeMRO(graph) {
|
|
|
254
258
|
methodsByName.set(methodName, defs);
|
|
255
259
|
}
|
|
256
260
|
// Avoid duplicates (same method seen via multiple paths)
|
|
257
|
-
if (!defs.some(d => d.methodId === methodId)) {
|
|
261
|
+
if (!defs.some((d) => d.methodId === methodId)) {
|
|
258
262
|
defs.push({
|
|
259
263
|
classId: ancestorId,
|
|
260
264
|
className: ancestorNode.properties.name,
|
|
@@ -275,7 +279,7 @@ export function computeMRO(graph) {
|
|
|
275
279
|
continue;
|
|
276
280
|
// Own method shadows inherited — no ambiguity
|
|
277
281
|
const ownMethods = methodMap.get(classId) ?? [];
|
|
278
|
-
const ownDefinesIt = ownMethods.some(mid => {
|
|
282
|
+
const ownDefinesIt = ownMethods.some((mid) => {
|
|
279
283
|
const mn = graph.getNode(mid);
|
|
280
284
|
return mn?.properties.name === methodName;
|
|
281
285
|
});
|
|
@@ -30,8 +30,8 @@ export function walkBindingChain(name, currentFilePath, symbolTable, namedImport
|
|
|
30
30
|
visited.add(key);
|
|
31
31
|
const targetName = binding.exportedName;
|
|
32
32
|
const resolvedDefs = targetName !== lookupName || depth > 0
|
|
33
|
-
? symbolTable.lookupFuzzy(targetName).filter(def => def.filePath === binding.sourcePath)
|
|
34
|
-
: allDefs.filter(def => def.filePath === binding.sourcePath);
|
|
33
|
+
? symbolTable.lookupFuzzy(targetName).filter((def) => def.filePath === binding.sourcePath)
|
|
34
|
+
: allDefs.filter((def) => def.filePath === binding.sourcePath);
|
|
35
35
|
if (resolvedDefs.length > 0)
|
|
36
36
|
return resolvedDefs;
|
|
37
37
|
// No definition in source file → follow re-export chain
|
|
@@ -42,7 +42,9 @@ function collectRustBindings(node, bindings) {
|
|
|
42
42
|
let hasDeeper = false;
|
|
43
43
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
44
44
|
const child = node.namedChild(i);
|
|
45
|
-
if (child?.type === 'use_list' ||
|
|
45
|
+
if (child?.type === 'use_list' ||
|
|
46
|
+
child?.type === 'use_as_clause' ||
|
|
47
|
+
child?.type === 'scoped_use_list') {
|
|
46
48
|
hasDeeper = true;
|
|
47
49
|
break;
|
|
48
50
|
}
|
|
@@ -2,9 +2,9 @@ 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 '
|
|
5
|
+
import { getLanguageFromFilename } from 'gitnexus-shared';
|
|
6
6
|
import { yieldToEventLoop } from './utils/event-loop.js';
|
|
7
|
-
import { getDefinitionNodeFromCaptures, findEnclosingClassId, extractMethodSignature, getLabelFromCaptures, CLASS_CONTAINER_TYPES } from './utils/ast-helpers.js';
|
|
7
|
+
import { getDefinitionNodeFromCaptures, findEnclosingClassId, extractMethodSignature, getLabelFromCaptures, CLASS_CONTAINER_TYPES, } from './utils/ast-helpers.js';
|
|
8
8
|
import { detectFrameworkFromAST } from './framework-detection.js';
|
|
9
9
|
import { buildTypeEnv } from './type-env.js';
|
|
10
10
|
import { getTreeSitterBufferSize, TREE_SITTER_MAX_BUFFER } from './constants.js';
|
|
@@ -20,7 +20,19 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
20
20
|
parseableFiles.push({ path: file.path, content: file.content });
|
|
21
21
|
}
|
|
22
22
|
if (parseableFiles.length === 0)
|
|
23
|
-
return {
|
|
23
|
+
return {
|
|
24
|
+
imports: [],
|
|
25
|
+
calls: [],
|
|
26
|
+
assignments: [],
|
|
27
|
+
heritage: [],
|
|
28
|
+
routes: [],
|
|
29
|
+
fetchCalls: [],
|
|
30
|
+
decoratorRoutes: [],
|
|
31
|
+
toolDefs: [],
|
|
32
|
+
ormQueries: [],
|
|
33
|
+
constructorBindings: [],
|
|
34
|
+
typeEnvBindings: [],
|
|
35
|
+
};
|
|
24
36
|
const total = files.length;
|
|
25
37
|
// Dispatch to worker pool — pool handles splitting into chunks and sub-batching
|
|
26
38
|
const chunkResults = await workerPool.dispatch(parseableFiles, (filesProcessed) => {
|
|
@@ -87,7 +99,19 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
87
99
|
}
|
|
88
100
|
// Final progress
|
|
89
101
|
onFileProgress?.(total, total, 'done');
|
|
90
|
-
return {
|
|
102
|
+
return {
|
|
103
|
+
imports: allImports,
|
|
104
|
+
calls: allCalls,
|
|
105
|
+
assignments: allAssignments,
|
|
106
|
+
heritage: allHeritage,
|
|
107
|
+
routes: allRoutes,
|
|
108
|
+
fetchCalls: allFetchCalls,
|
|
109
|
+
decoratorRoutes: allDecoratorRoutes,
|
|
110
|
+
toolDefs: allToolDefs,
|
|
111
|
+
ormQueries: allORMQueries,
|
|
112
|
+
constructorBindings: allConstructorBindings,
|
|
113
|
+
typeEnvBindings: allTypeEnvBindings,
|
|
114
|
+
};
|
|
91
115
|
};
|
|
92
116
|
// ============================================================================
|
|
93
117
|
// Sequential fallback (original implementation)
|
|
@@ -178,7 +202,9 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
178
202
|
}
|
|
179
203
|
let tree;
|
|
180
204
|
try {
|
|
181
|
-
tree = parser.parse(file.content, undefined, {
|
|
205
|
+
tree = parser.parse(file.content, undefined, {
|
|
206
|
+
bufferSize: getTreeSitterBufferSize(file.content.length),
|
|
207
|
+
});
|
|
182
208
|
}
|
|
183
209
|
catch (parseError) {
|
|
184
210
|
console.warn(`Skipping unparseable file: ${file.path}`);
|
|
@@ -202,10 +228,12 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
202
228
|
continue;
|
|
203
229
|
}
|
|
204
230
|
// Build per-file type environment for FieldExtractor context (lightweight — skipped if no fieldExtractor)
|
|
205
|
-
const typeEnv = provider.fieldExtractor
|
|
206
|
-
|
|
231
|
+
const typeEnv = provider.fieldExtractor
|
|
232
|
+
? buildTypeEnv(tree, language, { enclosingFunctionFinder: provider.enclosingFunctionFinder })
|
|
233
|
+
: null;
|
|
234
|
+
matches.forEach((match) => {
|
|
207
235
|
const captureMap = {};
|
|
208
|
-
match.captures.forEach(c => {
|
|
236
|
+
match.captures.forEach((c) => {
|
|
209
237
|
captureMap[c.name] = c.node;
|
|
210
238
|
});
|
|
211
239
|
const nodeLabel = getLabelFromCaptures(captureMap, provider);
|
|
@@ -217,19 +245,27 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
217
245
|
return;
|
|
218
246
|
const nodeName = nameNode ? nameNode.text : 'init';
|
|
219
247
|
const definitionNodeForRange = getDefinitionNodeFromCaptures(captureMap);
|
|
220
|
-
const startLine = definitionNodeForRange
|
|
248
|
+
const startLine = definitionNodeForRange
|
|
249
|
+
? definitionNodeForRange.startPosition.row
|
|
250
|
+
: nameNode
|
|
251
|
+
? nameNode.startPosition.row
|
|
252
|
+
: 0;
|
|
221
253
|
const nodeId = generateId(nodeLabel, `${file.path}:${nodeName}`);
|
|
222
254
|
const definitionNode = getDefinitionNodeFromCaptures(captureMap);
|
|
223
255
|
const frameworkHint = definitionNode
|
|
224
256
|
? detectFrameworkFromAST(language, (definitionNode.text || '').slice(0, 300))
|
|
225
257
|
: null;
|
|
226
258
|
// Extract method signature for Method/Constructor nodes
|
|
227
|
-
const methodSig =
|
|
259
|
+
const methodSig = nodeLabel === 'Function' || nodeLabel === 'Method' || nodeLabel === 'Constructor'
|
|
228
260
|
? extractMethodSignature(definitionNode)
|
|
229
261
|
: undefined;
|
|
230
262
|
// Language-specific return type fallback (e.g. Ruby YARD @return [Type])
|
|
231
263
|
// Also upgrades uninformative AST types like PHP `array` with PHPDoc `@return User[]`
|
|
232
|
-
if (methodSig &&
|
|
264
|
+
if (methodSig &&
|
|
265
|
+
(!methodSig.returnType ||
|
|
266
|
+
methodSig.returnType === 'array' ||
|
|
267
|
+
methodSig.returnType === 'iterable') &&
|
|
268
|
+
definitionNode) {
|
|
233
269
|
const tc = provider.typeConfig;
|
|
234
270
|
if (tc?.extractReturnType) {
|
|
235
271
|
const docReturn = tc.extractReturnType(definitionNode);
|
|
@@ -247,23 +283,34 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
247
283
|
endLine: definitionNodeForRange ? definitionNodeForRange.endPosition.row : startLine,
|
|
248
284
|
language: language,
|
|
249
285
|
isExported: cachedExportCheck(provider.exportChecker, nameNode || definitionNodeForRange, nodeName),
|
|
250
|
-
...(frameworkHint
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
286
|
+
...(frameworkHint
|
|
287
|
+
? {
|
|
288
|
+
astFrameworkMultiplier: frameworkHint.entryPointMultiplier,
|
|
289
|
+
astFrameworkReason: frameworkHint.reason,
|
|
290
|
+
}
|
|
291
|
+
: {}),
|
|
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
|
+
: {}),
|
|
260
302
|
},
|
|
261
303
|
};
|
|
262
304
|
graph.addNode(node);
|
|
263
305
|
// Compute enclosing class for Method/Constructor/Property/Function — used for both ownerId and HAS_METHOD
|
|
264
306
|
// Function is included because Kotlin/Rust/Python capture class methods as Function nodes
|
|
265
|
-
const needsOwner = nodeLabel === 'Method' ||
|
|
266
|
-
|
|
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;
|
|
267
314
|
// Extract declared type and field metadata for Property nodes
|
|
268
315
|
let declaredType;
|
|
269
316
|
let seqVisibility;
|
|
@@ -275,7 +322,10 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
275
322
|
const classNode = seqFindEnclosingClassNode(definitionNode);
|
|
276
323
|
if (classNode) {
|
|
277
324
|
const fieldMap = seqGetFieldInfo(classNode, provider, {
|
|
278
|
-
typeEnv,
|
|
325
|
+
typeEnv,
|
|
326
|
+
symbolTable: NOOP_SYMBOL_TABLE_SEQ,
|
|
327
|
+
filePath: file.path,
|
|
328
|
+
language,
|
|
279
329
|
});
|
|
280
330
|
const info = fieldMap?.get(nodeName);
|
|
281
331
|
if (info) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { PipelineProgress
|
|
1
|
+
import { type PipelineProgress } from 'gitnexus-shared';
|
|
2
|
+
import { PipelineResult } from '../../types/pipeline.js';
|
|
2
3
|
/** A group of files with no mutual dependencies, safe to process in parallel. */
|
|
3
4
|
type IndependentFileGroup = readonly string[];
|
|
4
5
|
/** Kahn's algorithm: returns files grouped by topological level.
|