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
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import Resolution Dispatch
|
|
3
|
+
*
|
|
4
|
+
* Per-language dispatch table for import resolution and named binding extraction.
|
|
5
|
+
* Replaces the 120-line if-chain in resolveLanguageImport() and the 7-branch
|
|
6
|
+
* dispatch in extractNamedBindings() with a single table lookup each.
|
|
7
|
+
*
|
|
8
|
+
* Follows the existing ExportChecker / CallRouter pattern:
|
|
9
|
+
* - Function aliases (not interfaces) to avoid megamorphic inline-cache issues
|
|
10
|
+
* - `satisfies Record<SupportedLanguages, ...>` for compile-time exhaustiveness
|
|
11
|
+
* - Const dispatch table — configs are accessed via ctx.configs at call time
|
|
12
|
+
*/
|
|
13
|
+
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
14
|
+
import { KOTLIN_EXTENSIONS, appendKotlinWildcard, resolveJvmWildcard, resolveJvmMemberImport, resolveGoPackageDir, resolveGoPackage, resolveCSharpImport as resolveCSharpImportHelper, resolveCSharpNamespaceDir, resolvePhpImport as resolvePhpImportHelper, resolveRustImport as resolveRustImportHelper, resolveRubyImport as resolveRubyImportHelper, resolvePythonImport as resolvePythonImportHelper, resolveImportPath, } from './resolvers/index.js';
|
|
15
|
+
import { extractTsNamedBindings, extractPythonNamedBindings, extractKotlinNamedBindings, extractRustNamedBindings, extractPhpNamedBindings, extractCsharpNamedBindings, extractJavaNamedBindings, } from './named-binding-extraction.js';
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Import path preprocessing
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Clean and preprocess a raw import source text into a resolved import path.
|
|
21
|
+
* Strips quotes/angle brackets (universal) and applies language-specific
|
|
22
|
+
* transformations (currently only Kotlin wildcard import detection).
|
|
23
|
+
*/
|
|
24
|
+
export function preprocessImportPath(sourceText, importNode, language) {
|
|
25
|
+
const cleaned = sourceText.replace(/['"<>]/g, '');
|
|
26
|
+
// Defense-in-depth: reject null bytes and control characters (matches Ruby call-routing pattern)
|
|
27
|
+
if (!cleaned || cleaned.length > 2048 || /[\x00-\x1f]/.test(cleaned))
|
|
28
|
+
return null;
|
|
29
|
+
if (language === SupportedLanguages.Kotlin) {
|
|
30
|
+
return appendKotlinWildcard(cleaned, importNode);
|
|
31
|
+
}
|
|
32
|
+
return cleaned;
|
|
33
|
+
}
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// Per-language resolver functions
|
|
36
|
+
// ============================================================================
|
|
37
|
+
/**
|
|
38
|
+
* Standard single-file resolution (TS/JS/C/C++ and fallback for other languages).
|
|
39
|
+
* Handles relative imports, tsconfig path aliases, and suffix matching.
|
|
40
|
+
*/
|
|
41
|
+
function resolveStandard(rawImportPath, filePath, ctx, language) {
|
|
42
|
+
const resolvedPath = resolveImportPath(filePath, rawImportPath, ctx.allFilePaths, ctx.allFileList, ctx.normalizedFileList, ctx.resolveCache, language, ctx.configs.tsconfigPaths, ctx.index);
|
|
43
|
+
return resolvedPath ? { kind: 'files', files: [resolvedPath] } : null;
|
|
44
|
+
}
|
|
45
|
+
/** Java: JVM wildcard -> member import -> standard fallthrough */
|
|
46
|
+
function resolveJavaImport(rawImportPath, filePath, ctx) {
|
|
47
|
+
if (rawImportPath.endsWith('.*')) {
|
|
48
|
+
const matchedFiles = resolveJvmWildcard(rawImportPath, ctx.normalizedFileList, ctx.allFileList, ['.java'], ctx.index);
|
|
49
|
+
if (matchedFiles.length > 0)
|
|
50
|
+
return { kind: 'files', files: matchedFiles };
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const memberResolved = resolveJvmMemberImport(rawImportPath, ctx.normalizedFileList, ctx.allFileList, ['.java'], ctx.index);
|
|
54
|
+
if (memberResolved)
|
|
55
|
+
return { kind: 'files', files: [memberResolved] };
|
|
56
|
+
}
|
|
57
|
+
return resolveStandard(rawImportPath, filePath, ctx, SupportedLanguages.Java);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Kotlin: JVM wildcard/member with Java-interop fallback -> top-level function imports -> standard.
|
|
61
|
+
* Kotlin can import from .kt/.kts files OR from .java files (Java interop).
|
|
62
|
+
*/
|
|
63
|
+
function resolveKotlinImport(rawImportPath, filePath, ctx) {
|
|
64
|
+
if (rawImportPath.endsWith('.*')) {
|
|
65
|
+
const matchedFiles = resolveJvmWildcard(rawImportPath, ctx.normalizedFileList, ctx.allFileList, KOTLIN_EXTENSIONS, ctx.index);
|
|
66
|
+
if (matchedFiles.length === 0) {
|
|
67
|
+
const javaMatches = resolveJvmWildcard(rawImportPath, ctx.normalizedFileList, ctx.allFileList, ['.java'], ctx.index);
|
|
68
|
+
if (javaMatches.length > 0)
|
|
69
|
+
return { kind: 'files', files: javaMatches };
|
|
70
|
+
}
|
|
71
|
+
if (matchedFiles.length > 0)
|
|
72
|
+
return { kind: 'files', files: matchedFiles };
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
let memberResolved = resolveJvmMemberImport(rawImportPath, ctx.normalizedFileList, ctx.allFileList, KOTLIN_EXTENSIONS, ctx.index);
|
|
76
|
+
if (!memberResolved) {
|
|
77
|
+
memberResolved = resolveJvmMemberImport(rawImportPath, ctx.normalizedFileList, ctx.allFileList, ['.java'], ctx.index);
|
|
78
|
+
}
|
|
79
|
+
if (memberResolved)
|
|
80
|
+
return { kind: 'files', files: [memberResolved] };
|
|
81
|
+
// Kotlin: top-level function imports (e.g. import models.getUser) have only 2 segments,
|
|
82
|
+
// which resolveJvmMemberImport skips (requires >=3). Fall back to package-directory scan
|
|
83
|
+
// for lowercase last segments (function/property imports). Uppercase last segments
|
|
84
|
+
// (class imports like models.User) fall through to standard suffix resolution.
|
|
85
|
+
const segments = rawImportPath.split('.');
|
|
86
|
+
const lastSeg = segments[segments.length - 1];
|
|
87
|
+
if (segments.length >= 2 && lastSeg[0] && lastSeg[0] === lastSeg[0].toLowerCase()) {
|
|
88
|
+
const pkgWildcard = segments.slice(0, -1).join('.') + '.*';
|
|
89
|
+
let dirFiles = resolveJvmWildcard(pkgWildcard, ctx.normalizedFileList, ctx.allFileList, KOTLIN_EXTENSIONS, ctx.index);
|
|
90
|
+
if (dirFiles.length === 0) {
|
|
91
|
+
dirFiles = resolveJvmWildcard(pkgWildcard, ctx.normalizedFileList, ctx.allFileList, ['.java'], ctx.index);
|
|
92
|
+
}
|
|
93
|
+
if (dirFiles.length > 0)
|
|
94
|
+
return { kind: 'files', files: dirFiles };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return resolveStandard(rawImportPath, filePath, ctx, SupportedLanguages.Kotlin);
|
|
98
|
+
}
|
|
99
|
+
/** Go: package-level imports via go.mod module path. */
|
|
100
|
+
function resolveGoImport(rawImportPath, filePath, ctx) {
|
|
101
|
+
const goModule = ctx.configs.goModule;
|
|
102
|
+
if (goModule && rawImportPath.startsWith(goModule.modulePath)) {
|
|
103
|
+
const pkgSuffix = resolveGoPackageDir(rawImportPath, goModule);
|
|
104
|
+
if (pkgSuffix) {
|
|
105
|
+
const pkgFiles = resolveGoPackage(rawImportPath, goModule, ctx.normalizedFileList, ctx.allFileList);
|
|
106
|
+
if (pkgFiles.length > 0) {
|
|
107
|
+
return { kind: 'package', files: pkgFiles, dirSuffix: pkgSuffix };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Fall through if no files found (package might be external)
|
|
111
|
+
}
|
|
112
|
+
return resolveStandard(rawImportPath, filePath, ctx, SupportedLanguages.Go);
|
|
113
|
+
}
|
|
114
|
+
/** C#: namespace-based resolution via .csproj configs, with suffix-match fallback. */
|
|
115
|
+
function resolveCSharpImportDispatch(rawImportPath, filePath, ctx) {
|
|
116
|
+
const csharpConfigs = ctx.configs.csharpConfigs;
|
|
117
|
+
if (csharpConfigs.length > 0) {
|
|
118
|
+
const resolvedFiles = resolveCSharpImportHelper(rawImportPath, csharpConfigs, ctx.normalizedFileList, ctx.allFileList, ctx.index);
|
|
119
|
+
if (resolvedFiles.length > 1) {
|
|
120
|
+
const dirSuffix = resolveCSharpNamespaceDir(rawImportPath, csharpConfigs);
|
|
121
|
+
if (dirSuffix) {
|
|
122
|
+
return { kind: 'package', files: resolvedFiles, dirSuffix };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (resolvedFiles.length > 0)
|
|
126
|
+
return { kind: 'files', files: resolvedFiles };
|
|
127
|
+
}
|
|
128
|
+
return resolveStandard(rawImportPath, filePath, ctx, SupportedLanguages.CSharp);
|
|
129
|
+
}
|
|
130
|
+
/** PHP: namespace-based resolution via composer.json PSR-4. */
|
|
131
|
+
function resolvePhpImportDispatch(rawImportPath, _filePath, ctx) {
|
|
132
|
+
const resolved = resolvePhpImportHelper(rawImportPath, ctx.configs.composerConfig, ctx.allFilePaths, ctx.normalizedFileList, ctx.allFileList, ctx.index);
|
|
133
|
+
return resolved ? { kind: 'files', files: [resolved] } : null;
|
|
134
|
+
}
|
|
135
|
+
/** Swift: module imports via Package.swift target map. */
|
|
136
|
+
function resolveSwiftImportDispatch(rawImportPath, _filePath, ctx) {
|
|
137
|
+
const swiftPackageConfig = ctx.configs.swiftPackageConfig;
|
|
138
|
+
if (swiftPackageConfig) {
|
|
139
|
+
const targetDir = swiftPackageConfig.targets.get(rawImportPath);
|
|
140
|
+
if (targetDir) {
|
|
141
|
+
const dirPrefix = targetDir + '/';
|
|
142
|
+
const files = [];
|
|
143
|
+
for (let i = 0; i < ctx.normalizedFileList.length; i++) {
|
|
144
|
+
if (ctx.normalizedFileList[i].startsWith(dirPrefix) && ctx.normalizedFileList[i].endsWith('.swift')) {
|
|
145
|
+
files.push(ctx.allFileList[i]);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (files.length > 0)
|
|
149
|
+
return { kind: 'files', files };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return null; // External framework (Foundation, UIKit, etc.)
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Python: relative imports (PEP 328) + proximity-based bare imports.
|
|
156
|
+
* Falls through to standard suffix resolution when proximity finds no match.
|
|
157
|
+
*/
|
|
158
|
+
function resolvePythonImportDispatch(rawImportPath, filePath, ctx) {
|
|
159
|
+
const resolved = resolvePythonImportHelper(filePath, rawImportPath, ctx.allFilePaths);
|
|
160
|
+
if (resolved)
|
|
161
|
+
return { kind: 'files', files: [resolved] };
|
|
162
|
+
if (rawImportPath.startsWith('.'))
|
|
163
|
+
return null; // relative but unresolved -- don't suffix-match
|
|
164
|
+
return resolveStandard(rawImportPath, filePath, ctx, SupportedLanguages.Python);
|
|
165
|
+
}
|
|
166
|
+
/** Ruby: require / require_relative. */
|
|
167
|
+
function resolveRubyImportDispatch(rawImportPath, _filePath, ctx) {
|
|
168
|
+
const resolved = resolveRubyImportHelper(rawImportPath, ctx.normalizedFileList, ctx.allFileList, ctx.index);
|
|
169
|
+
return resolved ? { kind: 'files', files: [resolved] } : null;
|
|
170
|
+
}
|
|
171
|
+
/** Rust: expand grouped imports: use {crate::a, crate::b} and use crate::models::{User, Repo}. */
|
|
172
|
+
function resolveRustImportDispatch(rawImportPath, filePath, ctx) {
|
|
173
|
+
// Top-level grouped: use {crate::a, crate::b}
|
|
174
|
+
if (rawImportPath.startsWith('{') && rawImportPath.endsWith('}')) {
|
|
175
|
+
const inner = rawImportPath.slice(1, -1);
|
|
176
|
+
const parts = inner.split(',').map(p => p.trim()).filter(Boolean);
|
|
177
|
+
const resolved = [];
|
|
178
|
+
for (const part of parts) {
|
|
179
|
+
const r = resolveRustImportHelper(filePath, part, ctx.allFilePaths);
|
|
180
|
+
if (r)
|
|
181
|
+
resolved.push(r);
|
|
182
|
+
}
|
|
183
|
+
return resolved.length > 0 ? { kind: 'files', files: resolved } : null;
|
|
184
|
+
}
|
|
185
|
+
// Scoped grouped: use crate::models::{User, Repo}
|
|
186
|
+
const braceIdx = rawImportPath.indexOf('::{');
|
|
187
|
+
if (braceIdx !== -1 && rawImportPath.endsWith('}')) {
|
|
188
|
+
const pathPrefix = rawImportPath.substring(0, braceIdx);
|
|
189
|
+
const braceContent = rawImportPath.substring(braceIdx + 3, rawImportPath.length - 1);
|
|
190
|
+
const items = braceContent.split(',').map(s => s.trim()).filter(Boolean);
|
|
191
|
+
const resolved = [];
|
|
192
|
+
for (const item of items) {
|
|
193
|
+
// Handle `use crate::models::{User, Repo as R}` — strip alias for resolution
|
|
194
|
+
const itemName = item.includes(' as ') ? item.split(' as ')[0].trim() : item;
|
|
195
|
+
const r = resolveRustImportHelper(filePath, `${pathPrefix}::${itemName}`, ctx.allFilePaths);
|
|
196
|
+
if (r)
|
|
197
|
+
resolved.push(r);
|
|
198
|
+
}
|
|
199
|
+
if (resolved.length > 0)
|
|
200
|
+
return { kind: 'files', files: resolved };
|
|
201
|
+
// Fallback: resolve the prefix path itself (e.g. crate::models -> models.rs)
|
|
202
|
+
const prefixResult = resolveRustImportHelper(filePath, pathPrefix, ctx.allFilePaths);
|
|
203
|
+
if (prefixResult)
|
|
204
|
+
return { kind: 'files', files: [prefixResult] };
|
|
205
|
+
}
|
|
206
|
+
return resolveStandard(rawImportPath, filePath, ctx, SupportedLanguages.Rust);
|
|
207
|
+
}
|
|
208
|
+
// ============================================================================
|
|
209
|
+
// Dispatch tables
|
|
210
|
+
// ============================================================================
|
|
211
|
+
/**
|
|
212
|
+
* Per-language import resolver dispatch table.
|
|
213
|
+
* Configs are accessed via ctx.configs at call time — no factory closure needed.
|
|
214
|
+
* Each resolver encapsulates the full resolution flow for its language, including
|
|
215
|
+
* fallthrough to standard resolution where appropriate.
|
|
216
|
+
*/
|
|
217
|
+
export const importResolvers = {
|
|
218
|
+
[SupportedLanguages.JavaScript]: (raw, fp, ctx) => resolveStandard(raw, fp, ctx, SupportedLanguages.JavaScript),
|
|
219
|
+
[SupportedLanguages.TypeScript]: (raw, fp, ctx) => resolveStandard(raw, fp, ctx, SupportedLanguages.TypeScript),
|
|
220
|
+
[SupportedLanguages.Python]: (raw, fp, ctx) => resolvePythonImportDispatch(raw, fp, ctx),
|
|
221
|
+
[SupportedLanguages.Java]: (raw, fp, ctx) => resolveJavaImport(raw, fp, ctx),
|
|
222
|
+
[SupportedLanguages.C]: (raw, fp, ctx) => resolveStandard(raw, fp, ctx, SupportedLanguages.C),
|
|
223
|
+
[SupportedLanguages.CPlusPlus]: (raw, fp, ctx) => resolveStandard(raw, fp, ctx, SupportedLanguages.CPlusPlus),
|
|
224
|
+
[SupportedLanguages.CSharp]: (raw, fp, ctx) => resolveCSharpImportDispatch(raw, fp, ctx),
|
|
225
|
+
[SupportedLanguages.Go]: (raw, fp, ctx) => resolveGoImport(raw, fp, ctx),
|
|
226
|
+
[SupportedLanguages.Ruby]: (raw, fp, ctx) => resolveRubyImportDispatch(raw, fp, ctx),
|
|
227
|
+
[SupportedLanguages.Rust]: (raw, fp, ctx) => resolveRustImportDispatch(raw, fp, ctx),
|
|
228
|
+
[SupportedLanguages.PHP]: (raw, fp, ctx) => resolvePhpImportDispatch(raw, fp, ctx),
|
|
229
|
+
[SupportedLanguages.Kotlin]: (raw, fp, ctx) => resolveKotlinImport(raw, fp, ctx),
|
|
230
|
+
[SupportedLanguages.Swift]: (raw, fp, ctx) => resolveSwiftImportDispatch(raw, fp, ctx),
|
|
231
|
+
};
|
|
232
|
+
/**
|
|
233
|
+
* Per-language named binding extractor dispatch table.
|
|
234
|
+
* Languages with whole-module import semantics (Go, Ruby, C/C++, Swift) return undefined --
|
|
235
|
+
* their bindings are synthesized post-parse by synthesizeWildcardImportBindings() in pipeline.ts.
|
|
236
|
+
*/
|
|
237
|
+
export const namedBindingExtractors = {
|
|
238
|
+
[SupportedLanguages.JavaScript]: extractTsNamedBindings,
|
|
239
|
+
[SupportedLanguages.TypeScript]: extractTsNamedBindings,
|
|
240
|
+
[SupportedLanguages.Python]: extractPythonNamedBindings,
|
|
241
|
+
[SupportedLanguages.Java]: extractJavaNamedBindings,
|
|
242
|
+
[SupportedLanguages.C]: undefined,
|
|
243
|
+
[SupportedLanguages.CPlusPlus]: undefined,
|
|
244
|
+
[SupportedLanguages.CSharp]: extractCsharpNamedBindings,
|
|
245
|
+
[SupportedLanguages.Go]: undefined,
|
|
246
|
+
[SupportedLanguages.Ruby]: undefined,
|
|
247
|
+
[SupportedLanguages.Rust]: extractRustNamedBindings,
|
|
248
|
+
[SupportedLanguages.PHP]: extractPhpNamedBindings,
|
|
249
|
+
[SupportedLanguages.Kotlin]: extractKotlinNamedBindings,
|
|
250
|
+
[SupportedLanguages.Swift]: undefined,
|
|
251
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ImportConfigs } from './import-resolution.js';
|
|
1
2
|
/** TypeScript path alias config parsed from tsconfig.json */
|
|
2
3
|
export interface TsconfigPaths {
|
|
3
4
|
/** Map of alias prefix -> target prefix (e.g., "@/" -> "src/") */
|
|
@@ -44,3 +45,5 @@ export declare function loadComposerConfig(repoRoot: string): Promise<ComposerCo
|
|
|
44
45
|
*/
|
|
45
46
|
export declare function loadCSharpProjectConfig(repoRoot: string): Promise<CSharpProjectConfig[]>;
|
|
46
47
|
export declare function loadSwiftPackageConfig(repoRoot: string): Promise<SwiftPackageConfig | null>;
|
|
48
|
+
/** Load all language-specific configs once for an ingestion run. */
|
|
49
|
+
export declare function loadImportConfigs(repoRoot: string): Promise<ImportConfigs>;
|
|
@@ -165,3 +165,16 @@ export async function loadSwiftPackageConfig(repoRoot) {
|
|
|
165
165
|
}
|
|
166
166
|
return null;
|
|
167
167
|
}
|
|
168
|
+
// ============================================================================
|
|
169
|
+
// BUNDLED CONFIG LOADER
|
|
170
|
+
// ============================================================================
|
|
171
|
+
/** Load all language-specific configs once for an ingestion run. */
|
|
172
|
+
export async function loadImportConfigs(repoRoot) {
|
|
173
|
+
return {
|
|
174
|
+
tsconfigPaths: await loadTsconfigPaths(repoRoot),
|
|
175
|
+
goModule: await loadGoModulePath(repoRoot),
|
|
176
|
+
composerConfig: await loadComposerConfig(repoRoot),
|
|
177
|
+
swiftPackageConfig: await loadSwiftPackageConfig(repoRoot),
|
|
178
|
+
csharpConfigs: await loadCSharpProjectConfig(repoRoot),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Processor
|
|
3
|
+
*
|
|
4
|
+
* Extracts structure from .md files using regex (no tree-sitter dependency).
|
|
5
|
+
* Creates Section nodes for headings with hierarchy, and IMPORTS edges for
|
|
6
|
+
* cross-file links.
|
|
7
|
+
*/
|
|
8
|
+
import { KnowledgeGraph } from '../graph/types.js';
|
|
9
|
+
interface MdFile {
|
|
10
|
+
path: string;
|
|
11
|
+
content: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const processMarkdown: (graph: KnowledgeGraph, files: MdFile[], allPathSet: Set<string>) => {
|
|
14
|
+
sections: number;
|
|
15
|
+
links: number;
|
|
16
|
+
};
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Processor
|
|
3
|
+
*
|
|
4
|
+
* Extracts structure from .md files using regex (no tree-sitter dependency).
|
|
5
|
+
* Creates Section nodes for headings with hierarchy, and IMPORTS edges for
|
|
6
|
+
* cross-file links.
|
|
7
|
+
*/
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { generateId } from '../../lib/utils.js';
|
|
10
|
+
const HEADING_RE = /^(#{1,6})\s+(.+)$/;
|
|
11
|
+
const LINK_RE = /\[([^\]]*)\]\(([^)]+)\)/g;
|
|
12
|
+
const MD_EXTENSIONS = new Set(['.md', '.mdx']);
|
|
13
|
+
export const processMarkdown = (graph, files, allPathSet) => {
|
|
14
|
+
let totalSections = 0;
|
|
15
|
+
let totalLinks = 0;
|
|
16
|
+
for (const file of files) {
|
|
17
|
+
const ext = path.extname(file.path).toLowerCase();
|
|
18
|
+
if (!MD_EXTENSIONS.has(ext))
|
|
19
|
+
continue;
|
|
20
|
+
const fileNodeId = generateId('File', file.path);
|
|
21
|
+
// Skip if file node doesn't exist (shouldn't happen, structure-processor creates it)
|
|
22
|
+
if (!graph.getNode(fileNodeId))
|
|
23
|
+
continue;
|
|
24
|
+
const lines = file.content.split('\n');
|
|
25
|
+
// --- Extract headings and build hierarchy ---
|
|
26
|
+
// First pass: collect all heading positions so we can compute endLine spans
|
|
27
|
+
const headings = [];
|
|
28
|
+
for (let i = 0; i < lines.length; i++) {
|
|
29
|
+
const match = lines[i].match(HEADING_RE);
|
|
30
|
+
if (!match)
|
|
31
|
+
continue;
|
|
32
|
+
headings.push({
|
|
33
|
+
level: match[1].length,
|
|
34
|
+
heading: match[2].trim(),
|
|
35
|
+
lineNum: i + 1, // 1-indexed
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
// Second pass: create nodes with proper endLine spans
|
|
39
|
+
const sectionStack = [];
|
|
40
|
+
for (let h = 0; h < headings.length; h++) {
|
|
41
|
+
const { level, heading, lineNum } = headings[h];
|
|
42
|
+
// endLine = line before next heading at same or higher level, or EOF
|
|
43
|
+
let endLine = lines.length;
|
|
44
|
+
for (let j = h + 1; j < headings.length; j++) {
|
|
45
|
+
if (headings[j].level <= level) {
|
|
46
|
+
endLine = headings[j].lineNum - 1;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const sectionId = generateId('Section', `${file.path}:L${lineNum}:${heading}`);
|
|
51
|
+
const node = {
|
|
52
|
+
id: sectionId,
|
|
53
|
+
label: 'Section',
|
|
54
|
+
properties: {
|
|
55
|
+
name: heading,
|
|
56
|
+
filePath: file.path,
|
|
57
|
+
startLine: lineNum,
|
|
58
|
+
endLine,
|
|
59
|
+
level,
|
|
60
|
+
description: `h${level}`,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
graph.addNode(node);
|
|
64
|
+
totalSections++;
|
|
65
|
+
// Find parent: pop stack until we find a level strictly less than current
|
|
66
|
+
while (sectionStack.length > 0 && sectionStack[sectionStack.length - 1].level >= level) {
|
|
67
|
+
sectionStack.pop();
|
|
68
|
+
}
|
|
69
|
+
const parentId = sectionStack.length > 0
|
|
70
|
+
? sectionStack[sectionStack.length - 1].id
|
|
71
|
+
: fileNodeId;
|
|
72
|
+
graph.addRelationship({
|
|
73
|
+
id: generateId('CONTAINS', `${parentId}->${sectionId}`),
|
|
74
|
+
type: 'CONTAINS',
|
|
75
|
+
sourceId: parentId,
|
|
76
|
+
targetId: sectionId,
|
|
77
|
+
confidence: 1.0,
|
|
78
|
+
reason: 'markdown-heading',
|
|
79
|
+
});
|
|
80
|
+
sectionStack.push({ level, id: sectionId });
|
|
81
|
+
}
|
|
82
|
+
// --- Extract links to other files in the repo ---
|
|
83
|
+
const fileDir = path.dirname(file.path);
|
|
84
|
+
const seenLinks = new Set();
|
|
85
|
+
let linkMatch;
|
|
86
|
+
LINK_RE.lastIndex = 0;
|
|
87
|
+
while ((linkMatch = LINK_RE.exec(file.content)) !== null) {
|
|
88
|
+
const href = linkMatch[2];
|
|
89
|
+
// Skip external URLs, anchors, and mailto
|
|
90
|
+
if (href.startsWith('http://') || href.startsWith('https://') ||
|
|
91
|
+
href.startsWith('#') || href.startsWith('mailto:')) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
// Strip anchor fragments from local links
|
|
95
|
+
const cleanHref = href.split('#')[0];
|
|
96
|
+
if (!cleanHref)
|
|
97
|
+
continue;
|
|
98
|
+
// Resolve relative to the file's directory, then normalize
|
|
99
|
+
const resolved = path.posix.normalize(path.posix.join(fileDir, cleanHref));
|
|
100
|
+
if (allPathSet.has(resolved)) {
|
|
101
|
+
const targetFileId = generateId('File', resolved);
|
|
102
|
+
// Skip if target file node doesn't exist
|
|
103
|
+
if (!graph.getNode(targetFileId))
|
|
104
|
+
continue;
|
|
105
|
+
// Dedup: skip if we've already linked this file pair
|
|
106
|
+
const linkKey = `${fileNodeId}->${targetFileId}`;
|
|
107
|
+
if (seenLinks.has(linkKey))
|
|
108
|
+
continue;
|
|
109
|
+
seenLinks.add(linkKey);
|
|
110
|
+
const relId = generateId('IMPORTS', linkKey);
|
|
111
|
+
graph.addRelationship({
|
|
112
|
+
id: relId,
|
|
113
|
+
type: 'IMPORTS',
|
|
114
|
+
sourceId: fileNodeId,
|
|
115
|
+
targetId: targetFileId,
|
|
116
|
+
confidence: 0.8,
|
|
117
|
+
reason: 'markdown-link',
|
|
118
|
+
});
|
|
119
|
+
totalLinks++;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return { sections: totalSections, links: totalLinks };
|
|
124
|
+
};
|
|
@@ -158,10 +158,11 @@ function resolveByMroOrder(methodName, defs, mroOrder, reasonPrefix) {
|
|
|
158
158
|
return {
|
|
159
159
|
resolvedTo: match.methodId,
|
|
160
160
|
reason: `${reasonPrefix}: ${match.className}::${methodName}`,
|
|
161
|
+
confidence: 0.9, // MRO-ordered resolution
|
|
161
162
|
};
|
|
162
163
|
}
|
|
163
164
|
}
|
|
164
|
-
return { resolvedTo: defs[0].methodId, reason: `${reasonPrefix} fallback: first definition
|
|
165
|
+
return { resolvedTo: defs[0].methodId, reason: `${reasonPrefix} fallback: first definition`, confidence: 0.7 };
|
|
165
166
|
}
|
|
166
167
|
function resolveCsharpJava(methodName, defs, parentEdgeTypes) {
|
|
167
168
|
const classDefs = [];
|
|
@@ -179,21 +180,24 @@ function resolveCsharpJava(methodName, defs, parentEdgeTypes) {
|
|
|
179
180
|
return {
|
|
180
181
|
resolvedTo: classDefs[0].methodId,
|
|
181
182
|
reason: `class method wins: ${classDefs[0].className}::${methodName}`,
|
|
183
|
+
confidence: 0.95, // Class method is authoritative
|
|
182
184
|
};
|
|
183
185
|
}
|
|
184
186
|
if (interfaceDefs.length > 1) {
|
|
185
187
|
return {
|
|
186
188
|
resolvedTo: null,
|
|
187
189
|
reason: `ambiguous: ${methodName} defined in multiple interfaces: ${interfaceDefs.map(d => d.className).join(', ')}`,
|
|
190
|
+
confidence: 0.5,
|
|
188
191
|
};
|
|
189
192
|
}
|
|
190
193
|
if (interfaceDefs.length === 1) {
|
|
191
194
|
return {
|
|
192
195
|
resolvedTo: interfaceDefs[0].methodId,
|
|
193
196
|
reason: `single interface default: ${interfaceDefs[0].className}::${methodName}`,
|
|
197
|
+
confidence: 0.85, // Single interface, unambiguous
|
|
194
198
|
};
|
|
195
199
|
}
|
|
196
|
-
return { resolvedTo: null, reason: 'no resolution found' };
|
|
200
|
+
return { resolvedTo: null, reason: 'no resolution found', confidence: 0.5 };
|
|
197
201
|
}
|
|
198
202
|
// ---------------------------------------------------------------------------
|
|
199
203
|
// Main entry point
|
|
@@ -293,6 +297,7 @@ export function computeMRO(graph) {
|
|
|
293
297
|
resolution = {
|
|
294
298
|
resolvedTo: null,
|
|
295
299
|
reason: `Rust requires qualified syntax: <Type as Trait>::${methodName}()`,
|
|
300
|
+
confidence: 0.5,
|
|
296
301
|
};
|
|
297
302
|
break;
|
|
298
303
|
default:
|
|
@@ -316,7 +321,7 @@ export function computeMRO(graph) {
|
|
|
316
321
|
sourceId: classId,
|
|
317
322
|
targetId: resolution.resolvedTo,
|
|
318
323
|
type: 'OVERRIDES',
|
|
319
|
-
confidence:
|
|
324
|
+
confidence: resolution.confidence,
|
|
320
325
|
reason: resolution.reason,
|
|
321
326
|
});
|
|
322
327
|
overrideEdges++;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
2
1
|
import type { SymbolTable, SymbolDefinition } from './symbol-table.js';
|
|
3
2
|
import type { NamedImportMap } from './import-processor.js';
|
|
3
|
+
import type { NamedBinding } from './import-resolution.js';
|
|
4
|
+
import type { SyntaxNode } from './utils.js';
|
|
4
5
|
/**
|
|
5
6
|
* Walk a named-binding re-export chain through NamedImportMap.
|
|
6
7
|
*
|
|
@@ -17,45 +18,10 @@ import type { NamedImportMap } from './import-processor.js';
|
|
|
17
18
|
* silent misses at depth=0 for non-aliased bindings.
|
|
18
19
|
*/
|
|
19
20
|
export declare function walkBindingChain(name: string, currentFilePath: string, symbolTable: SymbolTable, namedImportMap: NamedImportMap, allDefs: SymbolDefinition[]): SymbolDefinition[] | null;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* Python: from models import User, Repo as R
|
|
28
|
-
* → [{local:'User', exported:'User'}, {local:'R', exported:'Repo'}]
|
|
29
|
-
*/
|
|
30
|
-
export declare function extractNamedBindings(importNode: any, language: SupportedLanguages): {
|
|
31
|
-
local: string;
|
|
32
|
-
exported: string;
|
|
33
|
-
}[] | undefined;
|
|
34
|
-
export declare function extractTsNamedBindings(importNode: any): {
|
|
35
|
-
local: string;
|
|
36
|
-
exported: string;
|
|
37
|
-
}[] | undefined;
|
|
38
|
-
export declare function extractPythonNamedBindings(importNode: any): {
|
|
39
|
-
local: string;
|
|
40
|
-
exported: string;
|
|
41
|
-
}[] | undefined;
|
|
42
|
-
export declare function extractKotlinNamedBindings(importNode: any): {
|
|
43
|
-
local: string;
|
|
44
|
-
exported: string;
|
|
45
|
-
}[] | undefined;
|
|
46
|
-
export declare function extractRustNamedBindings(importNode: any): {
|
|
47
|
-
local: string;
|
|
48
|
-
exported: string;
|
|
49
|
-
}[] | undefined;
|
|
50
|
-
export declare function extractPhpNamedBindings(importNode: any): {
|
|
51
|
-
local: string;
|
|
52
|
-
exported: string;
|
|
53
|
-
}[] | undefined;
|
|
54
|
-
export declare function extractCsharpNamedBindings(importNode: any): {
|
|
55
|
-
local: string;
|
|
56
|
-
exported: string;
|
|
57
|
-
}[] | undefined;
|
|
58
|
-
export declare function extractJavaNamedBindings(importNode: any): {
|
|
59
|
-
local: string;
|
|
60
|
-
exported: string;
|
|
61
|
-
}[] | undefined;
|
|
21
|
+
export declare function extractTsNamedBindings(importNode: SyntaxNode): NamedBinding[] | undefined;
|
|
22
|
+
export declare function extractPythonNamedBindings(importNode: SyntaxNode): NamedBinding[] | undefined;
|
|
23
|
+
export declare function extractKotlinNamedBindings(importNode: SyntaxNode): NamedBinding[] | undefined;
|
|
24
|
+
export declare function extractRustNamedBindings(importNode: SyntaxNode): NamedBinding[] | undefined;
|
|
25
|
+
export declare function extractPhpNamedBindings(importNode: SyntaxNode): NamedBinding[] | undefined;
|
|
26
|
+
export declare function extractCsharpNamedBindings(importNode: SyntaxNode): NamedBinding[] | undefined;
|
|
27
|
+
export declare function extractJavaNamedBindings(importNode: SyntaxNode): NamedBinding[] | undefined;
|