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
|
@@ -10,12 +10,31 @@
|
|
|
10
10
|
* two packages have separate build targets (Node native vs WASM/browser).
|
|
11
11
|
* Keep both copies in sync until a shared package is introduced.
|
|
12
12
|
*/
|
|
13
|
-
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
14
13
|
/** null = this call was not routed; fall through to default call handling */
|
|
15
14
|
export type CallRoutingResult = RubyCallRouting | null;
|
|
15
|
+
/**
|
|
16
|
+
* Per-language call router.
|
|
17
|
+
* IMPORTANT: Call-routed imports bypass preprocessImportPath(), so any router that
|
|
18
|
+
* returns an importPath MUST validate it independently (length cap, control-char
|
|
19
|
+
* rejection). See routeRubyCall for the reference implementation.
|
|
20
|
+
*/
|
|
16
21
|
export type CallRouter = (calledName: string, callNode: any) => CallRoutingResult;
|
|
17
22
|
/** Per-language call routing. noRouting = no special routing (normal call processing) */
|
|
18
|
-
export declare const callRouters:
|
|
23
|
+
export declare const callRouters: {
|
|
24
|
+
javascript: CallRouter;
|
|
25
|
+
typescript: CallRouter;
|
|
26
|
+
python: CallRouter;
|
|
27
|
+
java: CallRouter;
|
|
28
|
+
kotlin: CallRouter;
|
|
29
|
+
go: CallRouter;
|
|
30
|
+
rust: CallRouter;
|
|
31
|
+
csharp: CallRouter;
|
|
32
|
+
php: CallRouter;
|
|
33
|
+
swift: CallRouter;
|
|
34
|
+
cpp: CallRouter;
|
|
35
|
+
c: CallRouter;
|
|
36
|
+
ruby: typeof routeRubyCall;
|
|
37
|
+
};
|
|
19
38
|
export type RubyCallRouting = {
|
|
20
39
|
kind: 'import';
|
|
21
40
|
importPath: string;
|
|
@@ -42,6 +61,8 @@ export interface RubyPropertyItem {
|
|
|
42
61
|
accessorType: RubyAccessorType;
|
|
43
62
|
startLine: number;
|
|
44
63
|
endLine: number;
|
|
64
|
+
/** YARD @return [Type] annotation preceding the attr_accessor call */
|
|
65
|
+
declaredType?: string;
|
|
45
66
|
}
|
|
46
67
|
/**
|
|
47
68
|
* Classify a Ruby call node and extract its semantic payload.
|
|
@@ -89,6 +89,26 @@ export function routeRubyCall(calledName, callNode) {
|
|
|
89
89
|
}
|
|
90
90
|
// ── attr_accessor / attr_reader / attr_writer → property definitions ───
|
|
91
91
|
if (calledName === 'attr_accessor' || calledName === 'attr_reader' || calledName === 'attr_writer') {
|
|
92
|
+
// Extract YARD @return [Type] from preceding comment (e.g. `# @return [Address]`)
|
|
93
|
+
let yardType;
|
|
94
|
+
let sibling = callNode.previousSibling;
|
|
95
|
+
while (sibling) {
|
|
96
|
+
if (sibling.type === 'comment') {
|
|
97
|
+
const match = /@return\s+\[([^\]]+)\]/.exec(sibling.text);
|
|
98
|
+
if (match) {
|
|
99
|
+
const raw = match[1].trim();
|
|
100
|
+
// Extract simple type name: "User", "Array<User>" → "User"
|
|
101
|
+
const simple = raw.match(/^([A-Z]\w*)/);
|
|
102
|
+
if (simple)
|
|
103
|
+
yardType = simple[1];
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (sibling.isNamed) {
|
|
108
|
+
break; // stop at non-comment named sibling
|
|
109
|
+
}
|
|
110
|
+
sibling = sibling.previousSibling;
|
|
111
|
+
}
|
|
92
112
|
const items = [];
|
|
93
113
|
const argList = callNode.childForFieldName?.('arguments');
|
|
94
114
|
for (const arg of (argList?.children ?? [])) {
|
|
@@ -98,6 +118,7 @@ export function routeRubyCall(calledName, callNode) {
|
|
|
98
118
|
accessorType: calledName,
|
|
99
119
|
startLine: arg.startPosition.row,
|
|
100
120
|
endLine: arg.endPosition.row,
|
|
121
|
+
...(yardType ? { declaredType: yardType } : {}),
|
|
101
122
|
});
|
|
102
123
|
}
|
|
103
124
|
}
|
|
@@ -12,28 +12,31 @@
|
|
|
12
12
|
import { detectFrameworkFromPath } from './framework-detection.js';
|
|
13
13
|
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
14
14
|
// ============================================================================
|
|
15
|
-
// NAME PATTERNS - All
|
|
15
|
+
// NAME PATTERNS - All 13 supported languages
|
|
16
16
|
// ============================================================================
|
|
17
17
|
/**
|
|
18
|
-
* Common entry point naming patterns by language
|
|
19
|
-
* These patterns indicate functions that are likely feature entry points
|
|
18
|
+
* Common entry point naming patterns by language.
|
|
19
|
+
* These patterns indicate functions that are likely feature entry points.
|
|
20
|
+
*
|
|
21
|
+
* Universal patterns are separated from per-language patterns so the per-language
|
|
22
|
+
* table can use `satisfies Record<SupportedLanguages, RegExp[]>` for compile-time
|
|
23
|
+
* exhaustiveness — the compiler catches any missing language entry.
|
|
20
24
|
*/
|
|
25
|
+
const UNIVERSAL_ENTRY_POINT_PATTERNS = [
|
|
26
|
+
/^(main|init|bootstrap|start|run|setup|configure)$/i,
|
|
27
|
+
/^handle[A-Z]/, // handleLogin, handleSubmit
|
|
28
|
+
/^on[A-Z]/, // onClick, onSubmit
|
|
29
|
+
/Handler$/, // RequestHandler
|
|
30
|
+
/Controller$/, // UserController
|
|
31
|
+
/^process[A-Z]/, // processPayment
|
|
32
|
+
/^execute[A-Z]/, // executeQuery
|
|
33
|
+
/^perform[A-Z]/, // performAction
|
|
34
|
+
/^dispatch[A-Z]/, // dispatchEvent
|
|
35
|
+
/^trigger[A-Z]/, // triggerAction
|
|
36
|
+
/^fire[A-Z]/, // fireEvent
|
|
37
|
+
/^emit[A-Z]/, // emitEvent
|
|
38
|
+
];
|
|
21
39
|
const ENTRY_POINT_PATTERNS = {
|
|
22
|
-
// Universal patterns (apply to all languages)
|
|
23
|
-
'*': [
|
|
24
|
-
/^(main|init|bootstrap|start|run|setup|configure)$/i,
|
|
25
|
-
/^handle[A-Z]/, // handleLogin, handleSubmit
|
|
26
|
-
/^on[A-Z]/, // onClick, onSubmit
|
|
27
|
-
/Handler$/, // RequestHandler
|
|
28
|
-
/Controller$/, // UserController
|
|
29
|
-
/^process[A-Z]/, // processPayment
|
|
30
|
-
/^execute[A-Z]/, // executeQuery
|
|
31
|
-
/^perform[A-Z]/, // performAction
|
|
32
|
-
/^dispatch[A-Z]/, // dispatchEvent
|
|
33
|
-
/^trigger[A-Z]/, // triggerAction
|
|
34
|
-
/^fire[A-Z]/, // fireEvent
|
|
35
|
-
/^emit[A-Z]/, // emitEvent
|
|
36
|
-
],
|
|
37
40
|
// JavaScript/TypeScript
|
|
38
41
|
[SupportedLanguages.JavaScript]: [
|
|
39
42
|
/^use[A-Z]/, // React hooks (useEffect, etc.)
|
|
@@ -55,6 +58,16 @@ const ENTRY_POINT_PATTERNS = {
|
|
|
55
58
|
/^build[A-Z]/, // Builder patterns
|
|
56
59
|
/Service$/, // UserService
|
|
57
60
|
],
|
|
61
|
+
// Kotlin
|
|
62
|
+
[SupportedLanguages.Kotlin]: [
|
|
63
|
+
/^on(Create|Start|Resume|Pause|Stop|Destroy)$/, // Android lifecycle
|
|
64
|
+
/^do[A-Z]/, // doGet, doPost (shared JVM Servlet pattern)
|
|
65
|
+
/^create[A-Z]/, // Factory patterns
|
|
66
|
+
/^build[A-Z]/, // Builder patterns
|
|
67
|
+
/ViewModel$/, // MVVM pattern (Android)
|
|
68
|
+
/^module$/, // Ktor module entry point
|
|
69
|
+
/Service$/, // Service classes
|
|
70
|
+
],
|
|
58
71
|
// C#
|
|
59
72
|
[SupportedLanguages.CSharp]: [
|
|
60
73
|
/^(Get|Post|Put|Delete|Patch)/, // ASP.NET action methods
|
|
@@ -186,13 +199,10 @@ const ENTRY_POINT_PATTERNS = {
|
|
|
186
199
|
],
|
|
187
200
|
};
|
|
188
201
|
/** Pre-computed merged patterns (universal + language-specific) to avoid per-call array allocation. */
|
|
189
|
-
const MERGED_ENTRY_POINT_PATTERNS =
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
continue;
|
|
194
|
-
MERGED_ENTRY_POINT_PATTERNS[lang] = [...UNIVERSAL_PATTERNS, ...patterns];
|
|
195
|
-
}
|
|
202
|
+
const MERGED_ENTRY_POINT_PATTERNS = Object.fromEntries(Object.keys(ENTRY_POINT_PATTERNS).map(lang => [
|
|
203
|
+
lang,
|
|
204
|
+
[...UNIVERSAL_ENTRY_POINT_PATTERNS, ...ENTRY_POINT_PATTERNS[lang]],
|
|
205
|
+
]));
|
|
196
206
|
// ============================================================================
|
|
197
207
|
// UTILITY PATTERNS - Functions that should be penalized
|
|
198
208
|
// ============================================================================
|
|
@@ -258,7 +268,7 @@ export function calculateEntryPointScore(name, language, isExported, callerCount
|
|
|
258
268
|
}
|
|
259
269
|
else {
|
|
260
270
|
// Check positive patterns
|
|
261
|
-
const allPatterns = MERGED_ENTRY_POINT_PATTERNS[language]
|
|
271
|
+
const allPatterns = MERGED_ENTRY_POINT_PATTERNS[language];
|
|
262
272
|
if (allPatterns.some(p => p.test(name))) {
|
|
263
273
|
nameMultiplier = 1.5; // Bonus for matching entry point pattern
|
|
264
274
|
reasons.push('entry-pattern');
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* DESIGN: Returns null for unknown frameworks, which causes a 1.0 multiplier
|
|
10
10
|
* (no bonus, no penalty) - same behavior as before this feature.
|
|
11
11
|
*/
|
|
12
|
+
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
12
13
|
export interface FrameworkHint {
|
|
13
14
|
framework: string;
|
|
14
15
|
entryPointMultiplier: number;
|
|
@@ -37,15 +38,22 @@ export declare const FRAMEWORK_AST_PATTERNS: {
|
|
|
37
38
|
blazor: string[];
|
|
38
39
|
efcore: string[];
|
|
39
40
|
'go-http': string[];
|
|
41
|
+
gin: string[];
|
|
42
|
+
echo: string[];
|
|
43
|
+
fiber: string[];
|
|
44
|
+
'go-grpc': string[];
|
|
40
45
|
laravel: string[];
|
|
41
46
|
actix: string[];
|
|
42
47
|
axum: string[];
|
|
43
48
|
rocket: string[];
|
|
49
|
+
tokio: string[];
|
|
50
|
+
qt: string[];
|
|
44
51
|
uikit: string[];
|
|
45
52
|
swiftui: string[];
|
|
46
|
-
|
|
53
|
+
vapor: string[];
|
|
54
|
+
rails: string[];
|
|
55
|
+
sinatra: string[];
|
|
47
56
|
};
|
|
48
|
-
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
49
57
|
/**
|
|
50
58
|
* Detect framework entry points from AST definition text (decorators/annotations/attributes).
|
|
51
59
|
* Returns null if no known pattern is found.
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* DESIGN: Returns null for unknown frameworks, which causes a 1.0 multiplier
|
|
10
10
|
* (no bonus, no penalty) - same behavior as before this feature.
|
|
11
11
|
*/
|
|
12
|
+
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
12
13
|
// ============================================================================
|
|
13
14
|
// PATH-BASED FRAMEWORK DETECTION
|
|
14
15
|
// ============================================================================
|
|
@@ -180,8 +181,8 @@ export function detectFrameworkFromPath(filePath) {
|
|
|
180
181
|
if (p.includes('/controllers/') && p.endsWith('.go')) {
|
|
181
182
|
return { framework: 'go-mvc', entryPointMultiplier: 2.5, reason: 'go-controller' };
|
|
182
183
|
}
|
|
183
|
-
// Go main.go files (THE entry point)
|
|
184
|
-
if (p.endsWith('/main.go')
|
|
184
|
+
// Go main.go files (THE entry point) — only match main.go, not arbitrary .go files under cmd/
|
|
185
|
+
if (p.endsWith('/main.go')) {
|
|
185
186
|
return { framework: 'go', entryPointMultiplier: 3.0, reason: 'go-main' };
|
|
186
187
|
}
|
|
187
188
|
// ========== RUST FRAMEWORKS ==========
|
|
@@ -333,21 +334,31 @@ export const FRAMEWORK_AST_PATTERNS = {
|
|
|
333
334
|
'signalr': ['[HubMethodName]', ': Hub', ': Hub<'],
|
|
334
335
|
'blazor': ['@page', '[Parameter]', '@inject'],
|
|
335
336
|
'efcore': ['DbContext', 'DbSet<', 'OnModelCreating'],
|
|
336
|
-
// Go patterns (function signatures)
|
|
337
|
-
'go-http': ['http.Handler', 'http.HandlerFunc', 'ServeHTTP'],
|
|
337
|
+
// Go patterns (function signatures include framework types)
|
|
338
|
+
'go-http': ['http.Handler', 'http.HandlerFunc', 'ServeHTTP', 'http.ResponseWriter', 'http.Request'],
|
|
339
|
+
'gin': ['gin.Context', 'gin.Default', 'gin.New'],
|
|
340
|
+
'echo': ['echo.Context', 'echo.New'],
|
|
341
|
+
'fiber': ['fiber.Ctx', 'fiber.New', 'fiber.App'],
|
|
342
|
+
'go-grpc': ['grpc.Server', 'RegisterServer', 'pb.Unimplemented'],
|
|
338
343
|
// PHP/Laravel
|
|
339
344
|
'laravel': ['Route::get', 'Route::post', 'Route::put', 'Route::delete',
|
|
340
345
|
'Route::resource', 'Route::apiResource', '#[Route('],
|
|
341
|
-
// Rust macros
|
|
342
|
-
'actix': ['#[get', '#[post', '#[put', '#[delete'],
|
|
343
|
-
'axum': ['Router::new'],
|
|
344
|
-
'rocket': ['#[get', '#[post'],
|
|
346
|
+
// Rust macros (proc-macro attributes in definition text)
|
|
347
|
+
'actix': ['#[get', '#[post', '#[put', '#[delete', '#[actix_web', 'HttpRequest', 'HttpResponse'],
|
|
348
|
+
'axum': ['Router::new', 'axum::extract', 'axum::routing'],
|
|
349
|
+
'rocket': ['#[get', '#[post', '#[launch', 'rocket::'],
|
|
350
|
+
'tokio': ['#[tokio::main]', '#[tokio::test]'],
|
|
351
|
+
// C++ patterns (Qt, Boost)
|
|
352
|
+
'qt': ['Q_OBJECT', 'Q_INVOKABLE', 'Q_PROPERTY', 'Q_SIGNALS', 'Q_SLOTS', 'Q_SIGNAL', 'Q_SLOT', 'QWidget', 'QApplication'],
|
|
345
353
|
// Swift/iOS
|
|
346
|
-
'uikit': ['viewDidLoad', 'viewWillAppear', 'viewDidAppear', 'UIViewController'],
|
|
347
|
-
'swiftui': ['@main', 'WindowGroup', 'ContentView', '@StateObject', '@ObservedObject'],
|
|
348
|
-
'
|
|
354
|
+
'uikit': ['viewDidLoad', 'viewWillAppear', 'viewDidAppear', 'UIViewController', '@IBOutlet', '@IBAction', '@objc'],
|
|
355
|
+
'swiftui': ['@main', 'WindowGroup', 'ContentView', '@StateObject', '@ObservedObject', '@EnvironmentObject', '@Published'],
|
|
356
|
+
'vapor': ['app.get', 'app.post', 'req.content.decode', 'Vapor'],
|
|
357
|
+
// Ruby patterns (class-level macros in definition text)
|
|
358
|
+
'rails': ['ApplicationController', 'ApplicationRecord', 'ActiveRecord::Base',
|
|
359
|
+
'before_action', 'after_action', 'has_many', 'belongs_to', 'has_one', 'validates'],
|
|
360
|
+
'sinatra': ['Sinatra::Base', 'Sinatra::Application'],
|
|
349
361
|
};
|
|
350
|
-
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
351
362
|
const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
|
|
352
363
|
[SupportedLanguages.JavaScript]: [
|
|
353
364
|
{ framework: 'nestjs', entryPointMultiplier: 3.2, reason: 'nestjs-decorator', patterns: FRAMEWORK_AST_PATTERNS.nestjs },
|
|
@@ -378,6 +389,32 @@ const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
|
|
|
378
389
|
[SupportedLanguages.PHP]: [
|
|
379
390
|
{ framework: 'laravel', entryPointMultiplier: 3.0, reason: 'php-route-attribute', patterns: FRAMEWORK_AST_PATTERNS.laravel },
|
|
380
391
|
],
|
|
392
|
+
[SupportedLanguages.Go]: [
|
|
393
|
+
{ framework: 'go-http', entryPointMultiplier: 2.5, reason: 'go-http-handler', patterns: FRAMEWORK_AST_PATTERNS['go-http'] },
|
|
394
|
+
{ framework: 'gin', entryPointMultiplier: 3.0, reason: 'gin-handler', patterns: FRAMEWORK_AST_PATTERNS.gin },
|
|
395
|
+
{ framework: 'echo', entryPointMultiplier: 3.0, reason: 'echo-handler', patterns: FRAMEWORK_AST_PATTERNS.echo },
|
|
396
|
+
{ framework: 'fiber', entryPointMultiplier: 3.0, reason: 'fiber-handler', patterns: FRAMEWORK_AST_PATTERNS.fiber },
|
|
397
|
+
{ framework: 'go-grpc', entryPointMultiplier: 2.8, reason: 'grpc-service', patterns: FRAMEWORK_AST_PATTERNS['go-grpc'] },
|
|
398
|
+
],
|
|
399
|
+
[SupportedLanguages.Rust]: [
|
|
400
|
+
{ framework: 'actix-web', entryPointMultiplier: 3.0, reason: 'actix-attribute', patterns: FRAMEWORK_AST_PATTERNS.actix },
|
|
401
|
+
{ framework: 'axum', entryPointMultiplier: 3.0, reason: 'axum-routing', patterns: FRAMEWORK_AST_PATTERNS.axum },
|
|
402
|
+
{ framework: 'rocket', entryPointMultiplier: 3.0, reason: 'rocket-attribute', patterns: FRAMEWORK_AST_PATTERNS.rocket },
|
|
403
|
+
{ framework: 'tokio', entryPointMultiplier: 2.5, reason: 'tokio-runtime', patterns: FRAMEWORK_AST_PATTERNS.tokio },
|
|
404
|
+
],
|
|
405
|
+
[SupportedLanguages.C]: [], // C has no framework-specific AST patterns (POSIX/socket patterns are in entry-point-scoring)
|
|
406
|
+
[SupportedLanguages.CPlusPlus]: [
|
|
407
|
+
{ framework: 'qt', entryPointMultiplier: 2.8, reason: 'qt-macro', patterns: FRAMEWORK_AST_PATTERNS.qt },
|
|
408
|
+
],
|
|
409
|
+
[SupportedLanguages.Swift]: [
|
|
410
|
+
{ framework: 'uikit', entryPointMultiplier: 2.5, reason: 'uikit-lifecycle', patterns: FRAMEWORK_AST_PATTERNS.uikit },
|
|
411
|
+
{ framework: 'swiftui', entryPointMultiplier: 2.8, reason: 'swiftui-pattern', patterns: FRAMEWORK_AST_PATTERNS.swiftui },
|
|
412
|
+
{ framework: 'vapor', entryPointMultiplier: 3.0, reason: 'vapor-routing', patterns: FRAMEWORK_AST_PATTERNS.vapor },
|
|
413
|
+
],
|
|
414
|
+
[SupportedLanguages.Ruby]: [
|
|
415
|
+
{ framework: 'rails', entryPointMultiplier: 3.0, reason: 'rails-pattern', patterns: FRAMEWORK_AST_PATTERNS.rails },
|
|
416
|
+
{ framework: 'sinatra', entryPointMultiplier: 2.8, reason: 'sinatra-pattern', patterns: FRAMEWORK_AST_PATTERNS.sinatra },
|
|
417
|
+
],
|
|
381
418
|
};
|
|
382
419
|
/** Pre-lowercased patterns for O(1) pattern matching at runtime */
|
|
383
420
|
const AST_PATTERNS_LOWERED = Object.fromEntries(Object.entries(AST_FRAMEWORK_PATTERNS_BY_LANGUAGE).map(([lang, cfgs]) => [
|
|
@@ -20,6 +20,7 @@ import { generateId } from '../../lib/utils.js';
|
|
|
20
20
|
import { getLanguageFromFilename, isVerboseIngestionEnabled, yieldToEventLoop } from './utils.js';
|
|
21
21
|
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
22
22
|
import { getTreeSitterBufferSize } from './constants.js';
|
|
23
|
+
import { TIER_CONFIDENCE } from './resolution-context.js';
|
|
23
24
|
/** C#/Java convention: interfaces start with I followed by an uppercase letter */
|
|
24
25
|
const INTERFACE_NAME_RE = /^I[A-Z]/;
|
|
25
26
|
/**
|
|
@@ -50,20 +51,17 @@ const resolveExtendsType = (parentName, currentFilePath, ctx, language) => {
|
|
|
50
51
|
}
|
|
51
52
|
return { type: 'EXTENDS', idPrefix: 'Class' };
|
|
52
53
|
};
|
|
53
|
-
/**
|
|
54
|
-
* Resolve a symbol ID for heritage, with fallback to generated ID.
|
|
55
|
-
* Uses ctx.resolve() → pick first candidate's nodeId → generate synthetic ID.
|
|
56
|
-
*/
|
|
57
54
|
const resolveHeritageId = (name, filePath, ctx, fallbackLabel, fallbackKey) => {
|
|
58
55
|
const resolved = ctx.resolve(name, filePath);
|
|
59
56
|
if (resolved && resolved.candidates.length > 0) {
|
|
60
57
|
// For global with multiple candidates, refuse (a wrong edge is worse than no edge)
|
|
61
58
|
if (resolved.tier === 'global' && resolved.candidates.length > 1) {
|
|
62
|
-
return generateId(fallbackLabel, fallbackKey ?? name);
|
|
59
|
+
return { id: generateId(fallbackLabel, fallbackKey ?? name), confidence: TIER_CONFIDENCE['global'] };
|
|
63
60
|
}
|
|
64
|
-
return resolved.candidates[0].nodeId;
|
|
61
|
+
return { id: resolved.candidates[0].nodeId, confidence: TIER_CONFIDENCE[resolved.tier] };
|
|
65
62
|
}
|
|
66
|
-
|
|
63
|
+
// Unresolved: use global-tier confidence as fallback
|
|
64
|
+
return { id: generateId(fallbackLabel, fallbackKey ?? name), confidence: TIER_CONFIDENCE['global'] };
|
|
67
65
|
};
|
|
68
66
|
export const processHeritage = async (graph, files, astCache, ctx, onProgress) => {
|
|
69
67
|
const parser = await loadParser();
|
|
@@ -132,15 +130,15 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
|
|
|
132
130
|
const className = captureMap['heritage.class'].text;
|
|
133
131
|
const parentClassName = captureMap['heritage.extends'].text;
|
|
134
132
|
const { type: relType, idPrefix } = resolveExtendsType(parentClassName, file.path, ctx, language);
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
133
|
+
const child = resolveHeritageId(className, file.path, ctx, 'Class', `${file.path}:${className}`);
|
|
134
|
+
const parent = resolveHeritageId(parentClassName, file.path, ctx, idPrefix);
|
|
135
|
+
if (child.id && parent.id && child.id !== parent.id) {
|
|
138
136
|
graph.addRelationship({
|
|
139
|
-
id: generateId(relType, `${
|
|
140
|
-
sourceId:
|
|
141
|
-
targetId:
|
|
137
|
+
id: generateId(relType, `${child.id}->${parent.id}`),
|
|
138
|
+
sourceId: child.id,
|
|
139
|
+
targetId: parent.id,
|
|
142
140
|
type: relType,
|
|
143
|
-
confidence:
|
|
141
|
+
confidence: Math.sqrt(child.confidence * parent.confidence),
|
|
144
142
|
reason: '',
|
|
145
143
|
});
|
|
146
144
|
}
|
|
@@ -149,15 +147,15 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
|
|
|
149
147
|
if (captureMap['heritage.class'] && captureMap['heritage.implements']) {
|
|
150
148
|
const className = captureMap['heritage.class'].text;
|
|
151
149
|
const interfaceName = captureMap['heritage.implements'].text;
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
if (
|
|
150
|
+
const cls = resolveHeritageId(className, file.path, ctx, 'Class', `${file.path}:${className}`);
|
|
151
|
+
const iface = resolveHeritageId(interfaceName, file.path, ctx, 'Interface');
|
|
152
|
+
if (cls.id && iface.id) {
|
|
155
153
|
graph.addRelationship({
|
|
156
|
-
id: generateId('IMPLEMENTS', `${
|
|
157
|
-
sourceId:
|
|
158
|
-
targetId:
|
|
154
|
+
id: generateId('IMPLEMENTS', `${cls.id}->${iface.id}`),
|
|
155
|
+
sourceId: cls.id,
|
|
156
|
+
targetId: iface.id,
|
|
159
157
|
type: 'IMPLEMENTS',
|
|
160
|
-
confidence:
|
|
158
|
+
confidence: Math.sqrt(cls.confidence * iface.confidence),
|
|
161
159
|
reason: '',
|
|
162
160
|
});
|
|
163
161
|
}
|
|
@@ -166,15 +164,15 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
|
|
|
166
164
|
if (captureMap['heritage.trait'] && captureMap['heritage.class']) {
|
|
167
165
|
const structName = captureMap['heritage.class'].text;
|
|
168
166
|
const traitName = captureMap['heritage.trait'].text;
|
|
169
|
-
const
|
|
170
|
-
const
|
|
171
|
-
if (
|
|
167
|
+
const strct = resolveHeritageId(structName, file.path, ctx, 'Struct', `${file.path}:${structName}`);
|
|
168
|
+
const trait = resolveHeritageId(traitName, file.path, ctx, 'Trait');
|
|
169
|
+
if (strct.id && trait.id) {
|
|
172
170
|
graph.addRelationship({
|
|
173
|
-
id: generateId('IMPLEMENTS', `${
|
|
174
|
-
sourceId:
|
|
175
|
-
targetId:
|
|
171
|
+
id: generateId('IMPLEMENTS', `${strct.id}->${trait.id}`),
|
|
172
|
+
sourceId: strct.id,
|
|
173
|
+
targetId: trait.id,
|
|
176
174
|
type: 'IMPLEMENTS',
|
|
177
|
-
confidence:
|
|
175
|
+
confidence: Math.sqrt(strct.confidence * trait.confidence),
|
|
178
176
|
reason: 'trait-impl',
|
|
179
177
|
});
|
|
180
178
|
}
|
|
@@ -205,43 +203,43 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, ctx
|
|
|
205
203
|
if (!fileLanguage)
|
|
206
204
|
continue;
|
|
207
205
|
const { type: relType, idPrefix } = resolveExtendsType(h.parentName, h.filePath, ctx, fileLanguage);
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
if (
|
|
206
|
+
const child = resolveHeritageId(h.className, h.filePath, ctx, 'Class', `${h.filePath}:${h.className}`);
|
|
207
|
+
const parent = resolveHeritageId(h.parentName, h.filePath, ctx, idPrefix);
|
|
208
|
+
if (child.id && parent.id && child.id !== parent.id) {
|
|
211
209
|
graph.addRelationship({
|
|
212
|
-
id: generateId(relType, `${
|
|
213
|
-
sourceId:
|
|
214
|
-
targetId:
|
|
210
|
+
id: generateId(relType, `${child.id}->${parent.id}`),
|
|
211
|
+
sourceId: child.id,
|
|
212
|
+
targetId: parent.id,
|
|
215
213
|
type: relType,
|
|
216
|
-
confidence:
|
|
214
|
+
confidence: Math.sqrt(child.confidence * parent.confidence),
|
|
217
215
|
reason: '',
|
|
218
216
|
});
|
|
219
217
|
}
|
|
220
218
|
}
|
|
221
219
|
else if (h.kind === 'implements') {
|
|
222
|
-
const
|
|
223
|
-
const
|
|
224
|
-
if (
|
|
220
|
+
const cls = resolveHeritageId(h.className, h.filePath, ctx, 'Class', `${h.filePath}:${h.className}`);
|
|
221
|
+
const iface = resolveHeritageId(h.parentName, h.filePath, ctx, 'Interface');
|
|
222
|
+
if (cls.id && iface.id) {
|
|
225
223
|
graph.addRelationship({
|
|
226
|
-
id: generateId('IMPLEMENTS', `${
|
|
227
|
-
sourceId:
|
|
228
|
-
targetId:
|
|
224
|
+
id: generateId('IMPLEMENTS', `${cls.id}->${iface.id}`),
|
|
225
|
+
sourceId: cls.id,
|
|
226
|
+
targetId: iface.id,
|
|
229
227
|
type: 'IMPLEMENTS',
|
|
230
|
-
confidence:
|
|
228
|
+
confidence: Math.sqrt(cls.confidence * iface.confidence),
|
|
231
229
|
reason: '',
|
|
232
230
|
});
|
|
233
231
|
}
|
|
234
232
|
}
|
|
235
233
|
else if (h.kind === 'trait-impl' || h.kind === 'include' || h.kind === 'extend' || h.kind === 'prepend') {
|
|
236
|
-
const
|
|
237
|
-
const
|
|
238
|
-
if (
|
|
234
|
+
const strct = resolveHeritageId(h.className, h.filePath, ctx, 'Struct', `${h.filePath}:${h.className}`);
|
|
235
|
+
const trait = resolveHeritageId(h.parentName, h.filePath, ctx, 'Trait');
|
|
236
|
+
if (strct.id && trait.id) {
|
|
239
237
|
graph.addRelationship({
|
|
240
|
-
id: generateId('IMPLEMENTS', `${
|
|
241
|
-
sourceId:
|
|
242
|
-
targetId:
|
|
238
|
+
id: generateId('IMPLEMENTS', `${strct.id}->${trait.id}:${h.kind}`),
|
|
239
|
+
sourceId: strct.id,
|
|
240
|
+
targetId: trait.id,
|
|
243
241
|
type: 'IMPLEMENTS',
|
|
244
|
-
confidence:
|
|
242
|
+
confidence: Math.sqrt(strct.confidence * trait.confidence),
|
|
245
243
|
reason: h.kind,
|
|
246
244
|
});
|
|
247
245
|
}
|
|
@@ -21,7 +21,7 @@ export interface ImportResolutionContext {
|
|
|
21
21
|
allFilePaths: Set<string>;
|
|
22
22
|
allFileList: string[];
|
|
23
23
|
normalizedFileList: string[];
|
|
24
|
-
|
|
24
|
+
index: SuffixIndex;
|
|
25
25
|
resolveCache: Map<string, string | null>;
|
|
26
26
|
}
|
|
27
27
|
export declare function buildImportResolutionContext(allPaths: string[]): ImportResolutionContext;
|