gitnexus 1.4.0 → 1.4.1
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 +194 -214
- package/dist/cli/ai-context.d.ts +1 -2
- package/dist/cli/ai-context.js +90 -117
- package/dist/cli/analyze.d.ts +0 -2
- package/dist/cli/analyze.js +2 -20
- package/dist/cli/index.js +25 -17
- package/dist/cli/setup.js +19 -17
- package/dist/core/augmentation/engine.js +20 -20
- package/dist/core/embeddings/embedding-pipeline.js +26 -26
- package/dist/core/graph/types.d.ts +2 -5
- package/dist/core/ingestion/ast-cache.js +2 -3
- package/dist/core/ingestion/call-processor.d.ts +5 -5
- package/dist/core/ingestion/call-processor.js +258 -173
- package/dist/core/ingestion/cluster-enricher.js +16 -16
- package/dist/core/ingestion/entry-point-scoring.d.ts +1 -2
- package/dist/core/ingestion/entry-point-scoring.js +22 -81
- package/dist/core/ingestion/framework-detection.d.ts +1 -5
- package/dist/core/ingestion/framework-detection.js +8 -39
- package/dist/core/ingestion/heritage-processor.d.ts +4 -13
- package/dist/core/ingestion/heritage-processor.js +28 -92
- package/dist/core/ingestion/import-processor.d.ts +19 -17
- package/dist/core/ingestion/import-processor.js +695 -170
- package/dist/core/ingestion/parsing-processor.d.ts +10 -1
- package/dist/core/ingestion/parsing-processor.js +177 -41
- package/dist/core/ingestion/pipeline.js +26 -49
- package/dist/core/ingestion/process-processor.js +1 -2
- package/dist/core/ingestion/symbol-table.d.ts +1 -12
- package/dist/core/ingestion/symbol-table.js +12 -19
- package/dist/core/ingestion/tree-sitter-queries.d.ts +11 -11
- package/dist/core/ingestion/tree-sitter-queries.js +485 -590
- package/dist/core/ingestion/utils.d.ts +0 -67
- package/dist/core/ingestion/utils.js +9 -692
- package/dist/core/ingestion/workers/parse-worker.d.ts +3 -20
- package/dist/core/ingestion/workers/parse-worker.js +345 -84
- package/dist/core/ingestion/workers/worker-pool.js +0 -8
- package/dist/core/kuzu/csv-generator.js +3 -19
- package/dist/core/kuzu/kuzu-adapter.js +19 -14
- package/dist/core/kuzu/schema.d.ts +3 -3
- package/dist/core/kuzu/schema.js +288 -303
- package/dist/core/search/bm25-index.js +6 -7
- package/dist/core/search/hybrid-search.js +3 -3
- package/dist/core/wiki/diagrams.d.ts +27 -0
- package/dist/core/wiki/diagrams.js +163 -0
- package/dist/core/wiki/generator.d.ts +50 -2
- package/dist/core/wiki/generator.js +548 -49
- package/dist/core/wiki/graph-queries.d.ts +42 -0
- package/dist/core/wiki/graph-queries.js +276 -97
- package/dist/core/wiki/html-viewer.js +192 -192
- package/dist/core/wiki/llm-client.js +73 -11
- package/dist/core/wiki/prompts.d.ts +52 -8
- package/dist/core/wiki/prompts.js +200 -86
- package/dist/mcp/core/kuzu-adapter.d.ts +3 -1
- package/dist/mcp/core/kuzu-adapter.js +44 -13
- package/dist/mcp/local/local-backend.js +128 -128
- package/dist/mcp/resources.js +42 -42
- package/dist/mcp/server.js +19 -18
- package/dist/mcp/tools.js +104 -103
- package/hooks/claude/gitnexus-hook.cjs +155 -238
- package/hooks/claude/pre-tool-use.sh +79 -79
- package/hooks/claude/session-start.sh +42 -42
- package/package.json +96 -96
- package/scripts/patch-tree-sitter-swift.cjs +74 -74
- package/skills/gitnexus-cli.md +82 -82
- package/skills/gitnexus-debugging.md +89 -89
- package/skills/gitnexus-exploring.md +78 -78
- package/skills/gitnexus-guide.md +64 -64
- package/skills/gitnexus-impact-analysis.md +97 -97
- package/skills/gitnexus-pr-review.md +163 -163
- package/skills/gitnexus-refactoring.md +121 -121
- package/vendor/leiden/index.cjs +355 -355
- package/vendor/leiden/utils.cjs +392 -392
- package/dist/cli/lazy-action.d.ts +0 -6
- package/dist/cli/lazy-action.js +0 -18
- package/dist/cli/skill-gen.d.ts +0 -26
- package/dist/cli/skill-gen.js +0 -549
- package/dist/core/ingestion/constants.d.ts +0 -16
- package/dist/core/ingestion/constants.js +0 -16
- package/dist/core/ingestion/export-detection.d.ts +0 -18
- package/dist/core/ingestion/export-detection.js +0 -230
- package/dist/core/ingestion/language-config.d.ts +0 -46
- package/dist/core/ingestion/language-config.js +0 -167
- package/dist/core/ingestion/mro-processor.d.ts +0 -45
- package/dist/core/ingestion/mro-processor.js +0 -369
- package/dist/core/ingestion/named-binding-extraction.d.ts +0 -61
- package/dist/core/ingestion/named-binding-extraction.js +0 -363
- package/dist/core/ingestion/resolvers/csharp.d.ts +0 -22
- package/dist/core/ingestion/resolvers/csharp.js +0 -109
- package/dist/core/ingestion/resolvers/go.d.ts +0 -19
- package/dist/core/ingestion/resolvers/go.js +0 -42
- package/dist/core/ingestion/resolvers/index.d.ts +0 -16
- package/dist/core/ingestion/resolvers/index.js +0 -11
- package/dist/core/ingestion/resolvers/jvm.d.ts +0 -23
- package/dist/core/ingestion/resolvers/jvm.js +0 -87
- package/dist/core/ingestion/resolvers/php.d.ts +0 -15
- package/dist/core/ingestion/resolvers/php.js +0 -35
- package/dist/core/ingestion/resolvers/rust.d.ts +0 -15
- package/dist/core/ingestion/resolvers/rust.js +0 -73
- package/dist/core/ingestion/resolvers/standard.d.ts +0 -28
- package/dist/core/ingestion/resolvers/standard.js +0 -145
- package/dist/core/ingestion/resolvers/utils.d.ts +0 -33
- package/dist/core/ingestion/resolvers/utils.js +0 -120
- package/dist/core/ingestion/symbol-resolver.d.ts +0 -32
- package/dist/core/ingestion/symbol-resolver.js +0 -83
- package/dist/core/ingestion/type-env.d.ts +0 -27
- package/dist/core/ingestion/type-env.js +0 -86
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/c-cpp.js +0 -60
- package/dist/core/ingestion/type-extractors/csharp.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/csharp.js +0 -89
- package/dist/core/ingestion/type-extractors/go.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/go.js +0 -105
- package/dist/core/ingestion/type-extractors/index.d.ts +0 -21
- package/dist/core/ingestion/type-extractors/index.js +0 -29
- package/dist/core/ingestion/type-extractors/jvm.d.ts +0 -3
- package/dist/core/ingestion/type-extractors/jvm.js +0 -121
- package/dist/core/ingestion/type-extractors/php.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/php.js +0 -31
- package/dist/core/ingestion/type-extractors/python.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/python.js +0 -41
- package/dist/core/ingestion/type-extractors/rust.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/rust.js +0 -39
- package/dist/core/ingestion/type-extractors/shared.d.ts +0 -17
- package/dist/core/ingestion/type-extractors/shared.js +0 -97
- package/dist/core/ingestion/type-extractors/swift.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/swift.js +0 -43
- package/dist/core/ingestion/type-extractors/types.d.ts +0 -14
- package/dist/core/ingestion/type-extractors/types.js +0 -1
- package/dist/core/ingestion/type-extractors/typescript.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/typescript.js +0 -46
- package/dist/mcp/compatible-stdio-transport.d.ts +0 -25
- package/dist/mcp/compatible-stdio-transport.js +0 -200
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JVM import resolution (Java + Kotlin).
|
|
3
|
-
* Handles wildcard imports, member/static imports, and Kotlin-specific patterns.
|
|
4
|
-
*/
|
|
5
|
-
/** Kotlin file extensions for JVM resolver reuse */
|
|
6
|
-
export const KOTLIN_EXTENSIONS = ['.kt', '.kts'];
|
|
7
|
-
/**
|
|
8
|
-
* Append .* to a Kotlin import path if the AST has a wildcard_import sibling node.
|
|
9
|
-
* Pure function — returns a new string without mutating the input.
|
|
10
|
-
*/
|
|
11
|
-
export const appendKotlinWildcard = (importPath, importNode) => {
|
|
12
|
-
for (let i = 0; i < importNode.childCount; i++) {
|
|
13
|
-
if (importNode.child(i)?.type === 'wildcard_import') {
|
|
14
|
-
return importPath.endsWith('.*') ? importPath : `${importPath}.*`;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return importPath;
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* Resolve a JVM wildcard import (com.example.*) to all matching files.
|
|
21
|
-
* Works for both Java (.java) and Kotlin (.kt, .kts).
|
|
22
|
-
*/
|
|
23
|
-
export function resolveJvmWildcard(importPath, normalizedFileList, allFileList, extensions, index) {
|
|
24
|
-
// "com.example.util.*" -> "com/example/util"
|
|
25
|
-
const packagePath = importPath.slice(0, -2).replace(/\./g, '/');
|
|
26
|
-
if (index) {
|
|
27
|
-
const candidates = extensions.flatMap(ext => index.getFilesInDir(packagePath, ext));
|
|
28
|
-
// Filter to only direct children (no subdirectories)
|
|
29
|
-
const packageSuffix = '/' + packagePath + '/';
|
|
30
|
-
return candidates.filter(f => {
|
|
31
|
-
const normalized = f.replace(/\\/g, '/');
|
|
32
|
-
const idx = normalized.indexOf(packageSuffix);
|
|
33
|
-
if (idx < 0)
|
|
34
|
-
return false;
|
|
35
|
-
const afterPkg = normalized.substring(idx + packageSuffix.length);
|
|
36
|
-
return !afterPkg.includes('/');
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
// Fallback: linear scan
|
|
40
|
-
const packageSuffix = '/' + packagePath + '/';
|
|
41
|
-
const matches = [];
|
|
42
|
-
for (let i = 0; i < normalizedFileList.length; i++) {
|
|
43
|
-
const normalized = normalizedFileList[i];
|
|
44
|
-
if (normalized.includes(packageSuffix) &&
|
|
45
|
-
extensions.some(ext => normalized.endsWith(ext))) {
|
|
46
|
-
const afterPackage = normalized.substring(normalized.indexOf(packageSuffix) + packageSuffix.length);
|
|
47
|
-
if (!afterPackage.includes('/')) {
|
|
48
|
-
matches.push(allFileList[i]);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return matches;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Try to resolve a JVM member/static import by stripping the member name.
|
|
56
|
-
* Java: "com.example.Constants.VALUE" -> resolve "com.example.Constants"
|
|
57
|
-
* Kotlin: "com.example.Constants.VALUE" -> resolve "com.example.Constants"
|
|
58
|
-
*/
|
|
59
|
-
export function resolveJvmMemberImport(importPath, normalizedFileList, allFileList, extensions, index) {
|
|
60
|
-
// Member imports: com.example.Constants.VALUE or com.example.Constants.*
|
|
61
|
-
// The last segment is a member name if it starts with lowercase, is ALL_CAPS, or is a wildcard
|
|
62
|
-
const segments = importPath.split('.');
|
|
63
|
-
if (segments.length < 3)
|
|
64
|
-
return null;
|
|
65
|
-
const lastSeg = segments[segments.length - 1];
|
|
66
|
-
if (lastSeg === '*' || /^[a-z]/.test(lastSeg) || /^[A-Z_]+$/.test(lastSeg)) {
|
|
67
|
-
const classPath = segments.slice(0, -1).join('/');
|
|
68
|
-
for (const ext of extensions) {
|
|
69
|
-
const classSuffix = classPath + ext;
|
|
70
|
-
if (index) {
|
|
71
|
-
const result = index.get(classSuffix) || index.getInsensitive(classSuffix);
|
|
72
|
-
if (result)
|
|
73
|
-
return result;
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
const fullSuffix = '/' + classSuffix;
|
|
77
|
-
for (let i = 0; i < normalizedFileList.length; i++) {
|
|
78
|
-
if (normalizedFileList[i].endsWith(fullSuffix) ||
|
|
79
|
-
normalizedFileList[i].toLowerCase().endsWith(fullSuffix.toLowerCase())) {
|
|
80
|
-
return allFileList[i];
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PHP PSR-4 import resolution.
|
|
3
|
-
* Handles use-statement resolution via composer.json autoload mappings.
|
|
4
|
-
*/
|
|
5
|
-
import type { SuffixIndex } from './utils.js';
|
|
6
|
-
/** PHP Composer PSR-4 autoload config */
|
|
7
|
-
export interface ComposerConfig {
|
|
8
|
-
/** Map of namespace prefix -> directory (e.g., "App\\" -> "app/") */
|
|
9
|
-
psr4: Map<string, string>;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Resolve a PHP use-statement import path using PSR-4 mappings.
|
|
13
|
-
* e.g. "App\Http\Controllers\UserController" -> "app/Http/Controllers/UserController.php"
|
|
14
|
-
*/
|
|
15
|
-
export declare function resolvePhpImport(importPath: string, composerConfig: ComposerConfig | null, allFiles: Set<string>, normalizedFileList: string[], allFileList: string[], index?: SuffixIndex): string | null;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PHP PSR-4 import resolution.
|
|
3
|
-
* Handles use-statement resolution via composer.json autoload mappings.
|
|
4
|
-
*/
|
|
5
|
-
import { suffixResolve } from './utils.js';
|
|
6
|
-
/**
|
|
7
|
-
* Resolve a PHP use-statement import path using PSR-4 mappings.
|
|
8
|
-
* e.g. "App\Http\Controllers\UserController" -> "app/Http/Controllers/UserController.php"
|
|
9
|
-
*/
|
|
10
|
-
export function resolvePhpImport(importPath, composerConfig, allFiles, normalizedFileList, allFileList, index) {
|
|
11
|
-
// Normalize: replace backslashes with forward slashes
|
|
12
|
-
const normalized = importPath.replace(/\\/g, '/');
|
|
13
|
-
// Try PSR-4 resolution if composer.json was found
|
|
14
|
-
if (composerConfig) {
|
|
15
|
-
// Sort namespaces by length descending (longest match wins)
|
|
16
|
-
const sorted = [...composerConfig.psr4.entries()].sort((a, b) => b[0].length - a[0].length);
|
|
17
|
-
for (const [nsPrefix, dirPrefix] of sorted) {
|
|
18
|
-
const nsPrefixSlash = nsPrefix.replace(/\\/g, '/');
|
|
19
|
-
if (normalized.startsWith(nsPrefixSlash + '/') || normalized === nsPrefixSlash) {
|
|
20
|
-
const remainder = normalized.slice(nsPrefixSlash.length).replace(/^\//, '');
|
|
21
|
-
const filePath = dirPrefix + (remainder ? '/' + remainder : '') + '.php';
|
|
22
|
-
if (allFiles.has(filePath))
|
|
23
|
-
return filePath;
|
|
24
|
-
if (index) {
|
|
25
|
-
const result = index.getInsensitive(filePath);
|
|
26
|
-
if (result)
|
|
27
|
-
return result;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
// Fallback: suffix matching (works without composer.json)
|
|
33
|
-
const pathParts = normalized.split('/').filter(Boolean);
|
|
34
|
-
return suffixResolve(pathParts, normalizedFileList, allFileList, index);
|
|
35
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rust module import resolution.
|
|
3
|
-
* Handles crate::, super::, self:: prefix paths and :: separators.
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Resolve Rust use-path to a file.
|
|
7
|
-
* Handles crate::, super::, self:: prefixes and :: path separators.
|
|
8
|
-
*/
|
|
9
|
-
export declare function resolveRustImport(currentFile: string, importPath: string, allFiles: Set<string>): string | null;
|
|
10
|
-
/**
|
|
11
|
-
* Try to resolve a Rust module path to a file.
|
|
12
|
-
* Tries: path.rs, path/mod.rs, and with the last segment stripped
|
|
13
|
-
* (last segment might be a symbol name, not a module).
|
|
14
|
-
*/
|
|
15
|
-
export declare function tryRustModulePath(modulePath: string, allFiles: Set<string>): string | null;
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rust module import resolution.
|
|
3
|
-
* Handles crate::, super::, self:: prefix paths and :: separators.
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Resolve Rust use-path to a file.
|
|
7
|
-
* Handles crate::, super::, self:: prefixes and :: path separators.
|
|
8
|
-
*/
|
|
9
|
-
export function resolveRustImport(currentFile, importPath, allFiles) {
|
|
10
|
-
let rustPath;
|
|
11
|
-
if (importPath.startsWith('crate::')) {
|
|
12
|
-
// crate:: resolves from src/ directory (standard Rust layout)
|
|
13
|
-
rustPath = importPath.slice(7).replace(/::/g, '/');
|
|
14
|
-
// Try from src/ (standard layout)
|
|
15
|
-
const fromSrc = tryRustModulePath('src/' + rustPath, allFiles);
|
|
16
|
-
if (fromSrc)
|
|
17
|
-
return fromSrc;
|
|
18
|
-
// Try from repo root (non-standard)
|
|
19
|
-
const fromRoot = tryRustModulePath(rustPath, allFiles);
|
|
20
|
-
if (fromRoot)
|
|
21
|
-
return fromRoot;
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
if (importPath.startsWith('super::')) {
|
|
25
|
-
// super:: = parent directory of current file's module
|
|
26
|
-
const currentDir = currentFile.split('/').slice(0, -1);
|
|
27
|
-
currentDir.pop(); // Go up one level for super::
|
|
28
|
-
rustPath = importPath.slice(7).replace(/::/g, '/');
|
|
29
|
-
const fullPath = [...currentDir, rustPath].join('/');
|
|
30
|
-
return tryRustModulePath(fullPath, allFiles);
|
|
31
|
-
}
|
|
32
|
-
if (importPath.startsWith('self::')) {
|
|
33
|
-
// self:: = current module's directory
|
|
34
|
-
const currentDir = currentFile.split('/').slice(0, -1);
|
|
35
|
-
rustPath = importPath.slice(6).replace(/::/g, '/');
|
|
36
|
-
const fullPath = [...currentDir, rustPath].join('/');
|
|
37
|
-
return tryRustModulePath(fullPath, allFiles);
|
|
38
|
-
}
|
|
39
|
-
// Bare path without prefix (e.g., from a use in a nested module)
|
|
40
|
-
// Convert :: to / and try suffix matching
|
|
41
|
-
if (importPath.includes('::')) {
|
|
42
|
-
rustPath = importPath.replace(/::/g, '/');
|
|
43
|
-
return tryRustModulePath(rustPath, allFiles);
|
|
44
|
-
}
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Try to resolve a Rust module path to a file.
|
|
49
|
-
* Tries: path.rs, path/mod.rs, and with the last segment stripped
|
|
50
|
-
* (last segment might be a symbol name, not a module).
|
|
51
|
-
*/
|
|
52
|
-
export function tryRustModulePath(modulePath, allFiles) {
|
|
53
|
-
// Try direct: path.rs
|
|
54
|
-
if (allFiles.has(modulePath + '.rs'))
|
|
55
|
-
return modulePath + '.rs';
|
|
56
|
-
// Try directory: path/mod.rs
|
|
57
|
-
if (allFiles.has(modulePath + '/mod.rs'))
|
|
58
|
-
return modulePath + '/mod.rs';
|
|
59
|
-
// Try path/lib.rs (for crate root)
|
|
60
|
-
if (allFiles.has(modulePath + '/lib.rs'))
|
|
61
|
-
return modulePath + '/lib.rs';
|
|
62
|
-
// The last segment might be a symbol (function, struct, etc.), not a module.
|
|
63
|
-
// Strip it and try again.
|
|
64
|
-
const lastSlash = modulePath.lastIndexOf('/');
|
|
65
|
-
if (lastSlash > 0) {
|
|
66
|
-
const parentPath = modulePath.substring(0, lastSlash);
|
|
67
|
-
if (allFiles.has(parentPath + '.rs'))
|
|
68
|
-
return parentPath + '.rs';
|
|
69
|
-
if (allFiles.has(parentPath + '/mod.rs'))
|
|
70
|
-
return parentPath + '/mod.rs';
|
|
71
|
-
}
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standard import path resolution.
|
|
3
|
-
* Handles relative imports, path alias rewriting, and generic suffix matching.
|
|
4
|
-
* Used as the fallback when language-specific resolvers don't match.
|
|
5
|
-
*/
|
|
6
|
-
import type { SuffixIndex } from './utils.js';
|
|
7
|
-
import { SupportedLanguages } from '../../../config/supported-languages.js';
|
|
8
|
-
/** TypeScript path alias config parsed from tsconfig.json */
|
|
9
|
-
export interface TsconfigPaths {
|
|
10
|
-
/** Map of alias prefix -> target prefix (e.g., "@/" -> "src/") */
|
|
11
|
-
aliases: Map<string, string>;
|
|
12
|
-
/** Base URL for path resolution (relative to repo root) */
|
|
13
|
-
baseUrl: string;
|
|
14
|
-
}
|
|
15
|
-
/** Max entries in the resolve cache. Beyond this, entries are evicted.
|
|
16
|
-
* 100K entries ≈ 15MB — covers the most common import patterns. */
|
|
17
|
-
export declare const RESOLVE_CACHE_CAP = 100000;
|
|
18
|
-
/**
|
|
19
|
-
* Resolve an import path to a file path in the repository.
|
|
20
|
-
*
|
|
21
|
-
* Language-specific preprocessing is applied before the generic resolution:
|
|
22
|
-
* - TypeScript/JavaScript: rewrites tsconfig path aliases
|
|
23
|
-
* - Rust: converts crate::/super::/self:: to relative paths
|
|
24
|
-
*
|
|
25
|
-
* Java wildcards and Go package imports are handled separately in processImports
|
|
26
|
-
* because they resolve to multiple files.
|
|
27
|
-
*/
|
|
28
|
-
export declare const resolveImportPath: (currentFile: string, importPath: string, allFiles: Set<string>, allFileList: string[], normalizedFileList: string[], resolveCache: Map<string, string | null>, language: SupportedLanguages, tsconfigPaths: TsconfigPaths | null, index?: SuffixIndex) => string | null;
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standard import path resolution.
|
|
3
|
-
* Handles relative imports, path alias rewriting, and generic suffix matching.
|
|
4
|
-
* Used as the fallback when language-specific resolvers don't match.
|
|
5
|
-
*/
|
|
6
|
-
import { tryResolveWithExtensions, suffixResolve } from './utils.js';
|
|
7
|
-
import { resolveRustImport } from './rust.js';
|
|
8
|
-
import { SupportedLanguages } from '../../../config/supported-languages.js';
|
|
9
|
-
/** Max entries in the resolve cache. Beyond this, entries are evicted.
|
|
10
|
-
* 100K entries ≈ 15MB — covers the most common import patterns. */
|
|
11
|
-
export const RESOLVE_CACHE_CAP = 100_000;
|
|
12
|
-
/**
|
|
13
|
-
* Resolve an import path to a file path in the repository.
|
|
14
|
-
*
|
|
15
|
-
* Language-specific preprocessing is applied before the generic resolution:
|
|
16
|
-
* - TypeScript/JavaScript: rewrites tsconfig path aliases
|
|
17
|
-
* - Rust: converts crate::/super::/self:: to relative paths
|
|
18
|
-
*
|
|
19
|
-
* Java wildcards and Go package imports are handled separately in processImports
|
|
20
|
-
* because they resolve to multiple files.
|
|
21
|
-
*/
|
|
22
|
-
export const resolveImportPath = (currentFile, importPath, allFiles, allFileList, normalizedFileList, resolveCache, language, tsconfigPaths, index) => {
|
|
23
|
-
const cacheKey = `${currentFile}::${importPath}`;
|
|
24
|
-
if (resolveCache.has(cacheKey))
|
|
25
|
-
return resolveCache.get(cacheKey) ?? null;
|
|
26
|
-
const cache = (result) => {
|
|
27
|
-
// Evict oldest 20% when cap is reached instead of clearing all
|
|
28
|
-
if (resolveCache.size >= RESOLVE_CACHE_CAP) {
|
|
29
|
-
const evictCount = Math.floor(RESOLVE_CACHE_CAP * 0.2);
|
|
30
|
-
const iter = resolveCache.keys();
|
|
31
|
-
for (let i = 0; i < evictCount; i++) {
|
|
32
|
-
const key = iter.next().value;
|
|
33
|
-
if (key !== undefined)
|
|
34
|
-
resolveCache.delete(key);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
resolveCache.set(cacheKey, result);
|
|
38
|
-
return result;
|
|
39
|
-
};
|
|
40
|
-
// ---- TypeScript/JavaScript: rewrite path aliases ----
|
|
41
|
-
if ((language === SupportedLanguages.TypeScript || language === SupportedLanguages.JavaScript) &&
|
|
42
|
-
tsconfigPaths &&
|
|
43
|
-
!importPath.startsWith('.')) {
|
|
44
|
-
for (const [aliasPrefix, targetPrefix] of tsconfigPaths.aliases) {
|
|
45
|
-
if (importPath.startsWith(aliasPrefix)) {
|
|
46
|
-
const remainder = importPath.slice(aliasPrefix.length);
|
|
47
|
-
// Build the rewritten path relative to baseUrl
|
|
48
|
-
const rewritten = tsconfigPaths.baseUrl === '.'
|
|
49
|
-
? targetPrefix + remainder
|
|
50
|
-
: tsconfigPaths.baseUrl + '/' + targetPrefix + remainder;
|
|
51
|
-
// Try direct resolution from repo root
|
|
52
|
-
const resolved = tryResolveWithExtensions(rewritten, allFiles);
|
|
53
|
-
if (resolved)
|
|
54
|
-
return cache(resolved);
|
|
55
|
-
// Try suffix matching as fallback
|
|
56
|
-
const parts = rewritten.split('/').filter(Boolean);
|
|
57
|
-
const suffixResult = suffixResolve(parts, normalizedFileList, allFileList, index);
|
|
58
|
-
if (suffixResult)
|
|
59
|
-
return cache(suffixResult);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
// ---- Rust: convert module path syntax to file paths ----
|
|
64
|
-
if (language === SupportedLanguages.Rust) {
|
|
65
|
-
// Handle grouped imports: use crate::module::{Foo, Bar, Baz}
|
|
66
|
-
// Extract the prefix path before ::{...} and resolve the module, not the symbols
|
|
67
|
-
let rustImportPath = importPath;
|
|
68
|
-
const braceIdx = importPath.indexOf('::{');
|
|
69
|
-
if (braceIdx !== -1) {
|
|
70
|
-
rustImportPath = importPath.substring(0, braceIdx);
|
|
71
|
-
}
|
|
72
|
-
else if (importPath.startsWith('{') && importPath.endsWith('}')) {
|
|
73
|
-
// Top-level grouped imports: use {crate::a, crate::b}
|
|
74
|
-
// Iterate each part and return the first that resolves. This function returns a single
|
|
75
|
-
// string, so callers that need ALL edges must intercept before reaching here (see the
|
|
76
|
-
// Rust grouped-import blocks in processImports / processImportsBatch). This fallback
|
|
77
|
-
// handles any path that reaches resolveImportPath directly.
|
|
78
|
-
const inner = importPath.slice(1, -1);
|
|
79
|
-
const parts = inner.split(',').map(p => p.trim()).filter(Boolean);
|
|
80
|
-
for (const part of parts) {
|
|
81
|
-
const partResult = resolveRustImport(currentFile, part, allFiles);
|
|
82
|
-
if (partResult)
|
|
83
|
-
return cache(partResult);
|
|
84
|
-
}
|
|
85
|
-
return cache(null);
|
|
86
|
-
}
|
|
87
|
-
const rustResult = resolveRustImport(currentFile, rustImportPath, allFiles);
|
|
88
|
-
if (rustResult)
|
|
89
|
-
return cache(rustResult);
|
|
90
|
-
// Fall through to generic resolution if Rust-specific didn't match
|
|
91
|
-
}
|
|
92
|
-
// ---- Python relative imports (PEP 328): .module, ..module, ... ----
|
|
93
|
-
if (language === SupportedLanguages.Python && importPath.startsWith('.')) {
|
|
94
|
-
const dotMatch = importPath.match(/^(\.+)(.*)/);
|
|
95
|
-
if (dotMatch) {
|
|
96
|
-
const dotCount = dotMatch[1].length;
|
|
97
|
-
const modulePart = dotMatch[2]; // e.g., "models" from ".models"
|
|
98
|
-
const dirParts = currentFile.split('/').slice(0, -1); // remove filename
|
|
99
|
-
// Navigate up: 1 dot = same package, 2 dots = parent package, etc.
|
|
100
|
-
// First dot means "current package", each additional dot goes up one level
|
|
101
|
-
for (let i = 1; i < dotCount; i++) {
|
|
102
|
-
dirParts.pop();
|
|
103
|
-
}
|
|
104
|
-
if (modulePart) {
|
|
105
|
-
// from .models import User → resolve "models" relative to current package
|
|
106
|
-
const modulePath = modulePart.replace(/\./g, '/');
|
|
107
|
-
dirParts.push(...modulePath.split('/'));
|
|
108
|
-
}
|
|
109
|
-
const basePath = dirParts.join('/');
|
|
110
|
-
const resolved = tryResolveWithExtensions(basePath, allFiles);
|
|
111
|
-
return cache(resolved);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
// ---- Generic relative import resolution (./ and ../) ----
|
|
115
|
-
const currentDir = currentFile.split('/').slice(0, -1);
|
|
116
|
-
const parts = importPath.split('/');
|
|
117
|
-
for (const part of parts) {
|
|
118
|
-
if (part === '.')
|
|
119
|
-
continue;
|
|
120
|
-
if (part === '..') {
|
|
121
|
-
currentDir.pop();
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
currentDir.push(part);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
const basePath = currentDir.join('/');
|
|
128
|
-
if (importPath.startsWith('.')) {
|
|
129
|
-
const resolved = tryResolveWithExtensions(basePath, allFiles);
|
|
130
|
-
return cache(resolved);
|
|
131
|
-
}
|
|
132
|
-
// ---- Generic package/absolute import resolution (suffix matching) ----
|
|
133
|
-
// Java wildcards are handled in processImports, not here
|
|
134
|
-
if (importPath.endsWith('.*')) {
|
|
135
|
-
return cache(null);
|
|
136
|
-
}
|
|
137
|
-
// C/C++ includes use actual file paths (e.g. "animal.h") — don't convert dots to slashes
|
|
138
|
-
const isCpp = language === SupportedLanguages.C || language === SupportedLanguages.CPlusPlus;
|
|
139
|
-
const pathLike = importPath.includes('/') || isCpp
|
|
140
|
-
? importPath
|
|
141
|
-
: importPath.replace(/\./g, '/');
|
|
142
|
-
const pathParts = pathLike.split('/').filter(Boolean);
|
|
143
|
-
const resolved = suffixResolve(pathParts, normalizedFileList, allFileList, index);
|
|
144
|
-
return cache(resolved);
|
|
145
|
-
};
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared utilities for import resolution.
|
|
3
|
-
* Extracted from import-processor.ts to reduce file size.
|
|
4
|
-
*/
|
|
5
|
-
/** All file extensions to try during resolution */
|
|
6
|
-
export declare const EXTENSIONS: string[];
|
|
7
|
-
/**
|
|
8
|
-
* Try to match a path (with extensions) against the known file set.
|
|
9
|
-
* Returns the matched file path or null.
|
|
10
|
-
*/
|
|
11
|
-
export declare function tryResolveWithExtensions(basePath: string, allFiles: Set<string>): string | null;
|
|
12
|
-
/**
|
|
13
|
-
* Build a suffix index for O(1) endsWith lookups.
|
|
14
|
-
* Maps every possible path suffix to its original file path.
|
|
15
|
-
* e.g. for "src/com/example/Foo.java":
|
|
16
|
-
* "Foo.java" -> "src/com/example/Foo.java"
|
|
17
|
-
* "example/Foo.java" -> "src/com/example/Foo.java"
|
|
18
|
-
* "com/example/Foo.java" -> "src/com/example/Foo.java"
|
|
19
|
-
* etc.
|
|
20
|
-
*/
|
|
21
|
-
export interface SuffixIndex {
|
|
22
|
-
/** Exact suffix lookup (case-sensitive) */
|
|
23
|
-
get(suffix: string): string | undefined;
|
|
24
|
-
/** Case-insensitive suffix lookup */
|
|
25
|
-
getInsensitive(suffix: string): string | undefined;
|
|
26
|
-
/** Get all files in a directory suffix */
|
|
27
|
-
getFilesInDir(dirSuffix: string, extension: string): string[];
|
|
28
|
-
}
|
|
29
|
-
export declare function buildSuffixIndex(normalizedFileList: string[], allFileList: string[]): SuffixIndex;
|
|
30
|
-
/**
|
|
31
|
-
* Suffix-based resolution using index. O(1) per lookup instead of O(files).
|
|
32
|
-
*/
|
|
33
|
-
export declare function suffixResolve(pathParts: string[], normalizedFileList: string[], allFileList: string[], index?: SuffixIndex): string | null;
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared utilities for import resolution.
|
|
3
|
-
* Extracted from import-processor.ts to reduce file size.
|
|
4
|
-
*/
|
|
5
|
-
/** All file extensions to try during resolution */
|
|
6
|
-
export const EXTENSIONS = [
|
|
7
|
-
'',
|
|
8
|
-
// TypeScript/JavaScript
|
|
9
|
-
'.tsx', '.ts', '.jsx', '.js', '/index.tsx', '/index.ts', '/index.jsx', '/index.js',
|
|
10
|
-
// Python
|
|
11
|
-
'.py', '/__init__.py',
|
|
12
|
-
// Java
|
|
13
|
-
'.java',
|
|
14
|
-
// Kotlin
|
|
15
|
-
'.kt', '.kts',
|
|
16
|
-
// C/C++
|
|
17
|
-
'.c', '.h', '.cpp', '.hpp', '.cc', '.cxx', '.hxx', '.hh',
|
|
18
|
-
// C#
|
|
19
|
-
'.cs',
|
|
20
|
-
// Go
|
|
21
|
-
'.go',
|
|
22
|
-
// Rust
|
|
23
|
-
'.rs', '/mod.rs',
|
|
24
|
-
// PHP
|
|
25
|
-
'.php', '.phtml',
|
|
26
|
-
// Swift
|
|
27
|
-
'.swift',
|
|
28
|
-
];
|
|
29
|
-
/**
|
|
30
|
-
* Try to match a path (with extensions) against the known file set.
|
|
31
|
-
* Returns the matched file path or null.
|
|
32
|
-
*/
|
|
33
|
-
export function tryResolveWithExtensions(basePath, allFiles) {
|
|
34
|
-
for (const ext of EXTENSIONS) {
|
|
35
|
-
const candidate = basePath + ext;
|
|
36
|
-
if (allFiles.has(candidate))
|
|
37
|
-
return candidate;
|
|
38
|
-
}
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
export function buildSuffixIndex(normalizedFileList, allFileList) {
|
|
42
|
-
// Map: normalized suffix -> original file path
|
|
43
|
-
const exactMap = new Map();
|
|
44
|
-
// Map: lowercase suffix -> original file path
|
|
45
|
-
const lowerMap = new Map();
|
|
46
|
-
// Map: directory suffix -> list of file paths in that directory
|
|
47
|
-
const dirMap = new Map();
|
|
48
|
-
for (let i = 0; i < normalizedFileList.length; i++) {
|
|
49
|
-
const normalized = normalizedFileList[i];
|
|
50
|
-
const original = allFileList[i];
|
|
51
|
-
const parts = normalized.split('/');
|
|
52
|
-
// Index all suffixes: "a/b/c.java" -> ["c.java", "b/c.java", "a/b/c.java"]
|
|
53
|
-
for (let j = parts.length - 1; j >= 0; j--) {
|
|
54
|
-
const suffix = parts.slice(j).join('/');
|
|
55
|
-
// Only store first match (longest path wins for ambiguous suffixes)
|
|
56
|
-
if (!exactMap.has(suffix)) {
|
|
57
|
-
exactMap.set(suffix, original);
|
|
58
|
-
}
|
|
59
|
-
const lower = suffix.toLowerCase();
|
|
60
|
-
if (!lowerMap.has(lower)) {
|
|
61
|
-
lowerMap.set(lower, original);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
// Index directory membership
|
|
65
|
-
const lastSlash = normalized.lastIndexOf('/');
|
|
66
|
-
if (lastSlash >= 0) {
|
|
67
|
-
// Build all directory suffixes
|
|
68
|
-
const dirParts = parts.slice(0, -1);
|
|
69
|
-
const fileName = parts[parts.length - 1];
|
|
70
|
-
const ext = fileName.substring(fileName.lastIndexOf('.'));
|
|
71
|
-
for (let j = dirParts.length - 1; j >= 0; j--) {
|
|
72
|
-
const dirSuffix = dirParts.slice(j).join('/');
|
|
73
|
-
const key = `${dirSuffix}:${ext}`;
|
|
74
|
-
let list = dirMap.get(key);
|
|
75
|
-
if (!list) {
|
|
76
|
-
list = [];
|
|
77
|
-
dirMap.set(key, list);
|
|
78
|
-
}
|
|
79
|
-
list.push(original);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return {
|
|
84
|
-
get: (suffix) => exactMap.get(suffix),
|
|
85
|
-
getInsensitive: (suffix) => lowerMap.get(suffix.toLowerCase()),
|
|
86
|
-
getFilesInDir: (dirSuffix, extension) => {
|
|
87
|
-
return dirMap.get(`${dirSuffix}:${extension}`) || [];
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Suffix-based resolution using index. O(1) per lookup instead of O(files).
|
|
93
|
-
*/
|
|
94
|
-
export function suffixResolve(pathParts, normalizedFileList, allFileList, index) {
|
|
95
|
-
if (index) {
|
|
96
|
-
for (let i = 0; i < pathParts.length; i++) {
|
|
97
|
-
const suffix = pathParts.slice(i).join('/');
|
|
98
|
-
for (const ext of EXTENSIONS) {
|
|
99
|
-
const suffixWithExt = suffix + ext;
|
|
100
|
-
const result = index.get(suffixWithExt) || index.getInsensitive(suffixWithExt);
|
|
101
|
-
if (result)
|
|
102
|
-
return result;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
// Fallback: linear scan (for backward compatibility)
|
|
108
|
-
for (let i = 0; i < pathParts.length; i++) {
|
|
109
|
-
const suffix = pathParts.slice(i).join('/');
|
|
110
|
-
for (const ext of EXTENSIONS) {
|
|
111
|
-
const suffixWithExt = suffix + ext;
|
|
112
|
-
const suffixPattern = '/' + suffixWithExt;
|
|
113
|
-
const matchIdx = normalizedFileList.findIndex(filePath => filePath.endsWith(suffixPattern) || filePath.toLowerCase().endsWith(suffixPattern.toLowerCase()));
|
|
114
|
-
if (matchIdx !== -1) {
|
|
115
|
-
return allFileList[matchIdx];
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Symbol Resolver
|
|
3
|
-
*
|
|
4
|
-
* Import-filtered candidate narrowing for bare identifier resolution.
|
|
5
|
-
* NOT FQN resolution — does not parse qualifiers (ns::Bar, com.foo.Bar).
|
|
6
|
-
*
|
|
7
|
-
* Shared between heritage-processor.ts and call-processor.ts.
|
|
8
|
-
*/
|
|
9
|
-
import type { SymbolTable, SymbolDefinition } from './symbol-table.js';
|
|
10
|
-
import type { ImportMap, PackageMap, NamedImportMap } from './import-processor.js';
|
|
11
|
-
/** Resolution tier for internal tracking, logging, and test assertions. */
|
|
12
|
-
export type ResolutionTier = 'same-file' | 'import-scoped' | 'unique-global';
|
|
13
|
-
/** Internal resolution result preserving tier metadata. */
|
|
14
|
-
export interface InternalResolution {
|
|
15
|
-
definition: SymbolDefinition;
|
|
16
|
-
tier: ResolutionTier;
|
|
17
|
-
candidateCount: number;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Resolve a bare identifier to its best-matching definition using import context.
|
|
21
|
-
*
|
|
22
|
-
* Resolution tiers (highest confidence first):
|
|
23
|
-
* 1. Same file (lookupExactFull — authoritative)
|
|
24
|
-
* 2. Import-scoped (lookupFuzzy filtered by importMap — acceptable)
|
|
25
|
-
* 3. Unique global (lookupFuzzy with exactly 1 match — acceptable fallback)
|
|
26
|
-
*
|
|
27
|
-
* If multiple global candidates remain after filtering, returns null.
|
|
28
|
-
* A wrong edge is worse than no edge.
|
|
29
|
-
*/
|
|
30
|
-
export declare const resolveSymbol: (name: string, currentFilePath: string, symbolTable: SymbolTable, importMap: ImportMap, packageMap?: PackageMap, namedImportMap?: NamedImportMap) => SymbolDefinition | null;
|
|
31
|
-
/** Internal resolver preserving tier metadata for logging and test assertions. */
|
|
32
|
-
export declare const resolveSymbolInternal: (name: string, currentFilePath: string, symbolTable: SymbolTable, importMap: ImportMap, packageMap?: PackageMap, namedImportMap?: NamedImportMap) => InternalResolution | null;
|