@zuvia-software-solutions/code-mapper 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/README.md +215 -0
  2. package/dist/cli/ai-context.d.ts +19 -0
  3. package/dist/cli/ai-context.js +168 -0
  4. package/dist/cli/analyze.d.ts +7 -0
  5. package/dist/cli/analyze.js +325 -0
  6. package/dist/cli/augment.d.ts +7 -0
  7. package/dist/cli/augment.js +27 -0
  8. package/dist/cli/clean.d.ts +5 -0
  9. package/dist/cli/clean.js +56 -0
  10. package/dist/cli/eval-server.d.ts +25 -0
  11. package/dist/cli/eval-server.js +365 -0
  12. package/dist/cli/index.d.ts +6 -0
  13. package/dist/cli/index.js +102 -0
  14. package/dist/cli/lazy-action.d.ts +6 -0
  15. package/dist/cli/lazy-action.js +19 -0
  16. package/dist/cli/list.d.ts +2 -0
  17. package/dist/cli/list.js +27 -0
  18. package/dist/cli/mcp.d.ts +8 -0
  19. package/dist/cli/mcp.js +35 -0
  20. package/dist/cli/refresh.d.ts +12 -0
  21. package/dist/cli/refresh.js +165 -0
  22. package/dist/cli/serve.d.ts +5 -0
  23. package/dist/cli/serve.js +8 -0
  24. package/dist/cli/setup.d.ts +6 -0
  25. package/dist/cli/setup.js +218 -0
  26. package/dist/cli/status.d.ts +2 -0
  27. package/dist/cli/status.js +33 -0
  28. package/dist/cli/tool.d.ts +28 -0
  29. package/dist/cli/tool.js +87 -0
  30. package/dist/config/ignore-service.d.ts +32 -0
  31. package/dist/config/ignore-service.js +282 -0
  32. package/dist/config/supported-languages.d.ts +23 -0
  33. package/dist/config/supported-languages.js +52 -0
  34. package/dist/core/augmentation/engine.d.ts +22 -0
  35. package/dist/core/augmentation/engine.js +232 -0
  36. package/dist/core/embeddings/embedder.d.ts +35 -0
  37. package/dist/core/embeddings/embedder.js +171 -0
  38. package/dist/core/embeddings/embedding-pipeline.d.ts +41 -0
  39. package/dist/core/embeddings/embedding-pipeline.js +402 -0
  40. package/dist/core/embeddings/index.d.ts +5 -0
  41. package/dist/core/embeddings/index.js +6 -0
  42. package/dist/core/embeddings/text-generator.d.ts +20 -0
  43. package/dist/core/embeddings/text-generator.js +159 -0
  44. package/dist/core/embeddings/types.d.ts +60 -0
  45. package/dist/core/embeddings/types.js +23 -0
  46. package/dist/core/graph/graph.d.ts +4 -0
  47. package/dist/core/graph/graph.js +65 -0
  48. package/dist/core/graph/types.d.ts +69 -0
  49. package/dist/core/graph/types.js +3 -0
  50. package/dist/core/incremental/child-process.d.ts +8 -0
  51. package/dist/core/incremental/child-process.js +649 -0
  52. package/dist/core/incremental/refresh-coordinator.d.ts +32 -0
  53. package/dist/core/incremental/refresh-coordinator.js +147 -0
  54. package/dist/core/incremental/types.d.ts +78 -0
  55. package/dist/core/incremental/types.js +153 -0
  56. package/dist/core/incremental/watcher.d.ts +63 -0
  57. package/dist/core/incremental/watcher.js +338 -0
  58. package/dist/core/ingestion/ast-cache.d.ts +12 -0
  59. package/dist/core/ingestion/ast-cache.js +34 -0
  60. package/dist/core/ingestion/call-processor.d.ts +34 -0
  61. package/dist/core/ingestion/call-processor.js +937 -0
  62. package/dist/core/ingestion/call-routing.d.ts +40 -0
  63. package/dist/core/ingestion/call-routing.js +97 -0
  64. package/dist/core/ingestion/cluster-enricher.d.ts +30 -0
  65. package/dist/core/ingestion/cluster-enricher.js +151 -0
  66. package/dist/core/ingestion/community-processor.d.ts +26 -0
  67. package/dist/core/ingestion/community-processor.js +272 -0
  68. package/dist/core/ingestion/constants.d.ts +5 -0
  69. package/dist/core/ingestion/constants.js +8 -0
  70. package/dist/core/ingestion/entry-point-scoring.d.ts +23 -0
  71. package/dist/core/ingestion/entry-point-scoring.js +317 -0
  72. package/dist/core/ingestion/export-detection.d.ts +11 -0
  73. package/dist/core/ingestion/export-detection.js +203 -0
  74. package/dist/core/ingestion/filesystem-walker.d.ts +18 -0
  75. package/dist/core/ingestion/filesystem-walker.js +64 -0
  76. package/dist/core/ingestion/framework-detection.d.ts +42 -0
  77. package/dist/core/ingestion/framework-detection.js +405 -0
  78. package/dist/core/ingestion/heritage-processor.d.ts +15 -0
  79. package/dist/core/ingestion/heritage-processor.js +237 -0
  80. package/dist/core/ingestion/import-processor.d.ts +31 -0
  81. package/dist/core/ingestion/import-processor.js +416 -0
  82. package/dist/core/ingestion/language-config.d.ts +32 -0
  83. package/dist/core/ingestion/language-config.js +161 -0
  84. package/dist/core/ingestion/mro-processor.d.ts +32 -0
  85. package/dist/core/ingestion/mro-processor.js +343 -0
  86. package/dist/core/ingestion/named-binding-extraction.d.ts +51 -0
  87. package/dist/core/ingestion/named-binding-extraction.js +343 -0
  88. package/dist/core/ingestion/parsing-processor.d.ts +20 -0
  89. package/dist/core/ingestion/parsing-processor.js +282 -0
  90. package/dist/core/ingestion/pipeline.d.ts +3 -0
  91. package/dist/core/ingestion/pipeline.js +416 -0
  92. package/dist/core/ingestion/process-processor.d.ts +42 -0
  93. package/dist/core/ingestion/process-processor.js +357 -0
  94. package/dist/core/ingestion/resolution-context.d.ts +40 -0
  95. package/dist/core/ingestion/resolution-context.js +171 -0
  96. package/dist/core/ingestion/resolvers/csharp.d.ts +10 -0
  97. package/dist/core/ingestion/resolvers/csharp.js +101 -0
  98. package/dist/core/ingestion/resolvers/go.d.ts +8 -0
  99. package/dist/core/ingestion/resolvers/go.js +33 -0
  100. package/dist/core/ingestion/resolvers/index.d.ts +14 -0
  101. package/dist/core/ingestion/resolvers/index.js +10 -0
  102. package/dist/core/ingestion/resolvers/jvm.d.ts +9 -0
  103. package/dist/core/ingestion/resolvers/jvm.js +74 -0
  104. package/dist/core/ingestion/resolvers/php.d.ts +7 -0
  105. package/dist/core/ingestion/resolvers/php.js +30 -0
  106. package/dist/core/ingestion/resolvers/ruby.d.ts +9 -0
  107. package/dist/core/ingestion/resolvers/ruby.js +13 -0
  108. package/dist/core/ingestion/resolvers/rust.d.ts +5 -0
  109. package/dist/core/ingestion/resolvers/rust.js +62 -0
  110. package/dist/core/ingestion/resolvers/standard.d.ts +16 -0
  111. package/dist/core/ingestion/resolvers/standard.js +144 -0
  112. package/dist/core/ingestion/resolvers/utils.d.ts +18 -0
  113. package/dist/core/ingestion/resolvers/utils.js +113 -0
  114. package/dist/core/ingestion/structure-processor.d.ts +4 -0
  115. package/dist/core/ingestion/structure-processor.js +39 -0
  116. package/dist/core/ingestion/symbol-table.d.ts +34 -0
  117. package/dist/core/ingestion/symbol-table.js +48 -0
  118. package/dist/core/ingestion/tree-sitter-queries.d.ts +20 -0
  119. package/dist/core/ingestion/tree-sitter-queries.js +691 -0
  120. package/dist/core/ingestion/type-env.d.ts +52 -0
  121. package/dist/core/ingestion/type-env.js +349 -0
  122. package/dist/core/ingestion/type-extractors/c-cpp.d.ts +4 -0
  123. package/dist/core/ingestion/type-extractors/c-cpp.js +214 -0
  124. package/dist/core/ingestion/type-extractors/csharp.d.ts +4 -0
  125. package/dist/core/ingestion/type-extractors/csharp.js +224 -0
  126. package/dist/core/ingestion/type-extractors/go.d.ts +4 -0
  127. package/dist/core/ingestion/type-extractors/go.js +261 -0
  128. package/dist/core/ingestion/type-extractors/index.d.ts +20 -0
  129. package/dist/core/ingestion/type-extractors/index.js +30 -0
  130. package/dist/core/ingestion/type-extractors/jvm.d.ts +5 -0
  131. package/dist/core/ingestion/type-extractors/jvm.js +386 -0
  132. package/dist/core/ingestion/type-extractors/php.d.ts +4 -0
  133. package/dist/core/ingestion/type-extractors/php.js +280 -0
  134. package/dist/core/ingestion/type-extractors/python.d.ts +4 -0
  135. package/dist/core/ingestion/type-extractors/python.js +175 -0
  136. package/dist/core/ingestion/type-extractors/ruby.d.ts +12 -0
  137. package/dist/core/ingestion/type-extractors/ruby.js +218 -0
  138. package/dist/core/ingestion/type-extractors/rust.d.ts +4 -0
  139. package/dist/core/ingestion/type-extractors/rust.js +290 -0
  140. package/dist/core/ingestion/type-extractors/shared.d.ts +81 -0
  141. package/dist/core/ingestion/type-extractors/shared.js +322 -0
  142. package/dist/core/ingestion/type-extractors/swift.d.ts +4 -0
  143. package/dist/core/ingestion/type-extractors/swift.js +140 -0
  144. package/dist/core/ingestion/type-extractors/types.d.ts +111 -0
  145. package/dist/core/ingestion/type-extractors/types.js +4 -0
  146. package/dist/core/ingestion/type-extractors/typescript.d.ts +4 -0
  147. package/dist/core/ingestion/type-extractors/typescript.js +227 -0
  148. package/dist/core/ingestion/utils.d.ts +73 -0
  149. package/dist/core/ingestion/utils.js +992 -0
  150. package/dist/core/ingestion/workers/parse-worker.d.ts +99 -0
  151. package/dist/core/ingestion/workers/parse-worker.js +1055 -0
  152. package/dist/core/ingestion/workers/worker-pool.d.ts +15 -0
  153. package/dist/core/ingestion/workers/worker-pool.js +123 -0
  154. package/dist/core/lbug/csv-generator.d.ts +28 -0
  155. package/dist/core/lbug/csv-generator.js +355 -0
  156. package/dist/core/lbug/lbug-adapter.d.ts +96 -0
  157. package/dist/core/lbug/lbug-adapter.js +753 -0
  158. package/dist/core/lbug/schema.d.ts +46 -0
  159. package/dist/core/lbug/schema.js +402 -0
  160. package/dist/core/search/bm25-index.d.ts +20 -0
  161. package/dist/core/search/bm25-index.js +123 -0
  162. package/dist/core/search/hybrid-search.d.ts +32 -0
  163. package/dist/core/search/hybrid-search.js +131 -0
  164. package/dist/core/search/query-cache.d.ts +18 -0
  165. package/dist/core/search/query-cache.js +47 -0
  166. package/dist/core/search/query-expansion.d.ts +19 -0
  167. package/dist/core/search/query-expansion.js +75 -0
  168. package/dist/core/search/reranker.d.ts +29 -0
  169. package/dist/core/search/reranker.js +122 -0
  170. package/dist/core/search/types.d.ts +154 -0
  171. package/dist/core/search/types.js +51 -0
  172. package/dist/core/semantic/tsgo-service.d.ts +67 -0
  173. package/dist/core/semantic/tsgo-service.js +355 -0
  174. package/dist/core/tree-sitter/parser-loader.d.ts +12 -0
  175. package/dist/core/tree-sitter/parser-loader.js +71 -0
  176. package/dist/lib/memory-guard.d.ts +35 -0
  177. package/dist/lib/memory-guard.js +70 -0
  178. package/dist/lib/utils.d.ts +3 -0
  179. package/dist/lib/utils.js +6 -0
  180. package/dist/mcp/compatible-stdio-transport.d.ts +32 -0
  181. package/dist/mcp/compatible-stdio-transport.js +209 -0
  182. package/dist/mcp/core/embedder.d.ts +24 -0
  183. package/dist/mcp/core/embedder.js +168 -0
  184. package/dist/mcp/core/lbug-adapter.d.ts +29 -0
  185. package/dist/mcp/core/lbug-adapter.js +330 -0
  186. package/dist/mcp/local/local-backend.d.ts +188 -0
  187. package/dist/mcp/local/local-backend.js +2759 -0
  188. package/dist/mcp/resources.d.ts +22 -0
  189. package/dist/mcp/resources.js +379 -0
  190. package/dist/mcp/server.d.ts +10 -0
  191. package/dist/mcp/server.js +217 -0
  192. package/dist/mcp/staleness.d.ts +10 -0
  193. package/dist/mcp/staleness.js +25 -0
  194. package/dist/mcp/tools.d.ts +21 -0
  195. package/dist/mcp/tools.js +202 -0
  196. package/dist/server/api.d.ts +5 -0
  197. package/dist/server/api.js +340 -0
  198. package/dist/server/mcp-http.d.ts +7 -0
  199. package/dist/server/mcp-http.js +95 -0
  200. package/dist/storage/git.d.ts +6 -0
  201. package/dist/storage/git.js +35 -0
  202. package/dist/storage/repo-manager.d.ts +87 -0
  203. package/dist/storage/repo-manager.js +249 -0
  204. package/dist/types/pipeline.d.ts +35 -0
  205. package/dist/types/pipeline.js +20 -0
  206. package/hooks/claude/code-mapper-hook.cjs +238 -0
  207. package/hooks/claude/pre-tool-use.sh +79 -0
  208. package/hooks/claude/session-start.sh +42 -0
  209. package/models/mlx-embedder.py +185 -0
  210. package/package.json +100 -0
  211. package/scripts/patch-tree-sitter-swift.cjs +74 -0
  212. package/vendor/leiden/index.cjs +355 -0
  213. package/vendor/leiden/utils.cjs +392 -0
@@ -0,0 +1,31 @@
1
+ /** @file import-processor.ts @description Resolves import statements across all supported languages, builds the ImportMap/PackageMap/NamedImportMap, and emits IMPORTS graph edges. Supports language-specific resolution for TS, Go, C#, PHP, Swift, Ruby, Rust, and JVM languages */
2
+ import { KnowledgeGraph } from '../graph/types.js';
3
+ import { ASTCache } from './ast-cache.js';
4
+ import type { ExtractedImport } from './workers/parse-worker.js';
5
+ import type { ResolutionContext } from './resolution-context.js';
6
+ import type { SuffixIndex } from './resolvers/index.js';
7
+ export type { SuffixIndex, TsconfigPaths, GoModuleConfig, CSharpProjectConfig, ComposerConfig } from './resolvers/index.js';
8
+ export type ImportMap = Map<string, Set<string>>;
9
+ export type PackageMap = Map<string, Set<string>>;
10
+ export interface NamedImportBinding {
11
+ sourcePath: string;
12
+ exportedName: string;
13
+ }
14
+ export type NamedImportMap = Map<string, Map<string, NamedImportBinding>>;
15
+ /** Check if a file path is directly inside a package directory identified by its suffix */
16
+ export declare function isFileInPackageDir(filePath: string, dirSuffix: string): boolean;
17
+ export interface ImportResolutionContext {
18
+ allFilePaths: Set<string>;
19
+ allFileList: string[];
20
+ normalizedFileList: string[];
21
+ suffixIndex: SuffixIndex;
22
+ resolveCache: Map<string, string | null>;
23
+ }
24
+ export declare function buildImportResolutionContext(allPaths: string[]): ImportResolutionContext;
25
+ export declare const processImports: (graph: KnowledgeGraph, files: {
26
+ path: string;
27
+ content: string;
28
+ }[], astCache: ASTCache, ctx: ResolutionContext, onProgress?: (current: number, total: number) => void, repoRoot?: string, allPaths?: string[]) => Promise<void>;
29
+ export declare const processImportsFromExtracted: (graph: KnowledgeGraph, files: {
30
+ path: string;
31
+ }[], extractedImports: ExtractedImport[], ctx: ResolutionContext, onProgress?: (current: number, total: number) => void, repoRoot?: string, prebuiltCtx?: ImportResolutionContext) => Promise<void>;
@@ -0,0 +1,416 @@
1
+ // code-mapper/src/core/ingestion/import-processor.ts
2
+ /** @file import-processor.ts @description Resolves import statements across all supported languages, builds the ImportMap/PackageMap/NamedImportMap, and emits IMPORTS graph edges. Supports language-specific resolution for TS, Go, C#, PHP, Swift, Ruby, Rust, and JVM languages */
3
+ import Parser from 'tree-sitter';
4
+ import { isLanguageAvailable, loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
5
+ import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
6
+ import { generateId } from '../../lib/utils.js';
7
+ import { getLanguageFromFilename, isVerboseIngestionEnabled, yieldToEventLoop } from './utils.js';
8
+ import { SupportedLanguages } from '../../config/supported-languages.js';
9
+ import { extractNamedBindings } from './named-binding-extraction.js';
10
+ import { getTreeSitterBufferSize } from './constants.js';
11
+ import { loadTsconfigPaths, loadGoModulePath, loadComposerConfig, loadCSharpProjectConfig, loadSwiftPackageConfig, } from './language-config.js';
12
+ import { buildSuffixIndex, resolveImportPath, appendKotlinWildcard, KOTLIN_EXTENSIONS, resolveJvmWildcard, resolveJvmMemberImport, resolveGoPackageDir, resolveGoPackage, resolveCSharpImport, resolveCSharpNamespaceDir, resolvePhpImport, resolveRustImport, resolveRubyImport, } from './resolvers/index.js';
13
+ import { callRouters } from './call-routing.js';
14
+ const isDev = process.env.NODE_ENV === 'development';
15
+ /** Check if a file path is directly inside a package directory identified by its suffix */
16
+ export function isFileInPackageDir(filePath, dirSuffix) {
17
+ // Prepend '/' so paths like "internal/auth/service.go" match suffix "/internal/auth/"
18
+ const normalized = '/' + filePath.replace(/\\/g, '/');
19
+ if (!normalized.includes(dirSuffix))
20
+ return false;
21
+ const afterDir = normalized.substring(normalized.indexOf(dirSuffix) + dirSuffix.length);
22
+ return !afterDir.includes('/');
23
+ }
24
+ export function buildImportResolutionContext(allPaths) {
25
+ const allFileList = allPaths;
26
+ const normalizedFileList = allFileList.map(p => p.replace(/\\/g, '/'));
27
+ const allFilePaths = new Set(allFileList);
28
+ const suffixIndex = buildSuffixIndex(normalizedFileList, allFileList);
29
+ return { allFilePaths, allFileList, normalizedFileList, suffixIndex, resolveCache: new Map() };
30
+ }
31
+ /** Shared language dispatch for import resolution, used by both AST and fast paths */
32
+ function resolveLanguageImport(filePath, rawImportPath, language, configs, ctx) {
33
+ const { allFilePaths, allFileList, normalizedFileList, index, resolveCache } = ctx;
34
+ const { tsconfigPaths, goModule, composerConfig, swiftPackageConfig, csharpConfigs } = configs;
35
+ // JVM languages (Java + Kotlin): handle wildcards and member imports
36
+ if (language === SupportedLanguages.Java || language === SupportedLanguages.Kotlin) {
37
+ const exts = language === SupportedLanguages.Java ? ['.java'] : KOTLIN_EXTENSIONS;
38
+ if (rawImportPath.endsWith('.*')) {
39
+ const matchedFiles = resolveJvmWildcard(rawImportPath, normalizedFileList, allFileList, exts, index);
40
+ if (matchedFiles.length === 0 && language === SupportedLanguages.Kotlin) {
41
+ const javaMatches = resolveJvmWildcard(rawImportPath, normalizedFileList, allFileList, ['.java'], index);
42
+ if (javaMatches.length > 0)
43
+ return { kind: 'files', files: javaMatches };
44
+ }
45
+ if (matchedFiles.length > 0)
46
+ return { kind: 'files', files: matchedFiles };
47
+ // Fall through to standard resolution
48
+ }
49
+ else {
50
+ let memberResolved = resolveJvmMemberImport(rawImportPath, normalizedFileList, allFileList, exts, index);
51
+ if (!memberResolved && language === SupportedLanguages.Kotlin) {
52
+ memberResolved = resolveJvmMemberImport(rawImportPath, normalizedFileList, allFileList, ['.java'], index);
53
+ }
54
+ if (memberResolved)
55
+ return { kind: 'files', files: [memberResolved] };
56
+ // Fall through to standard resolution
57
+ }
58
+ }
59
+ // Go: handle package-level imports
60
+ if (language === SupportedLanguages.Go && goModule && rawImportPath.startsWith(goModule.modulePath)) {
61
+ const pkgSuffix = resolveGoPackageDir(rawImportPath, goModule);
62
+ if (pkgSuffix) {
63
+ const pkgFiles = resolveGoPackage(rawImportPath, goModule, normalizedFileList, allFileList);
64
+ if (pkgFiles.length > 0) {
65
+ return { kind: 'package', files: pkgFiles, dirSuffix: pkgSuffix };
66
+ }
67
+ }
68
+ // Fall through if no files found (package might be external)
69
+ }
70
+ // C#: handle namespace-based imports (using directives)
71
+ if (language === SupportedLanguages.CSharp && csharpConfigs.length > 0) {
72
+ const resolvedFiles = resolveCSharpImport(rawImportPath, csharpConfigs, normalizedFileList, allFileList, index);
73
+ if (resolvedFiles.length > 1) {
74
+ const dirSuffix = resolveCSharpNamespaceDir(rawImportPath, csharpConfigs);
75
+ if (dirSuffix) {
76
+ return { kind: 'package', files: resolvedFiles, dirSuffix };
77
+ }
78
+ }
79
+ if (resolvedFiles.length > 0)
80
+ return { kind: 'files', files: resolvedFiles };
81
+ return null;
82
+ }
83
+ // PHP: namespace-based imports (use statements)
84
+ if (language === SupportedLanguages.PHP) {
85
+ const resolved = resolvePhpImport(rawImportPath, composerConfig, allFilePaths, normalizedFileList, allFileList, index);
86
+ return resolved ? { kind: 'files', files: [resolved] } : null;
87
+ }
88
+ // Swift: handle module imports
89
+ if (language === SupportedLanguages.Swift && swiftPackageConfig) {
90
+ const targetDir = swiftPackageConfig.targets.get(rawImportPath);
91
+ if (targetDir) {
92
+ const dirPrefix = targetDir + '/';
93
+ const files = [];
94
+ for (let i = 0; i < normalizedFileList.length; i++) {
95
+ if (normalizedFileList[i].startsWith(dirPrefix) && normalizedFileList[i].endsWith('.swift')) {
96
+ files.push(allFileList[i]);
97
+ }
98
+ }
99
+ if (files.length > 0)
100
+ return { kind: 'files', files };
101
+ }
102
+ return null; // External framework (Foundation, UIKit, etc)
103
+ }
104
+ // Ruby: require / require_relative
105
+ if (language === SupportedLanguages.Ruby) {
106
+ const resolved = resolveRubyImport(rawImportPath, normalizedFileList, allFileList, index);
107
+ return resolved ? { kind: 'files', files: [resolved] } : null;
108
+ }
109
+ // Rust: expand top-level grouped imports — use {crate::a, crate::b}
110
+ if (language === SupportedLanguages.Rust && rawImportPath.startsWith('{') && rawImportPath.endsWith('}')) {
111
+ const inner = rawImportPath.slice(1, -1);
112
+ const parts = inner.split(',').map(p => p.trim()).filter(Boolean);
113
+ const resolved = [];
114
+ for (const part of parts) {
115
+ const r = resolveRustImport(filePath, part, allFilePaths);
116
+ if (r)
117
+ resolved.push(r);
118
+ }
119
+ return resolved.length > 0 ? { kind: 'files', files: resolved } : null;
120
+ }
121
+ // Standard single-file resolution
122
+ const resolvedPath = resolveImportPath(filePath, rawImportPath, allFilePaths, allFileList, normalizedFileList, resolveCache, language, tsconfigPaths, index);
123
+ return resolvedPath ? { kind: 'files', files: [resolvedPath] } : null;
124
+ }
125
+ /** Apply an ImportResult — emit graph edges, update ImportMap/PackageMap and NamedImportMap */
126
+ function applyImportResult(result, filePath, importMap, packageMap, addImportEdge, addImportGraphEdge, namedBindings, namedImportMap) {
127
+ if (!result)
128
+ return;
129
+ if (result.kind === 'package' && packageMap) {
130
+ // Store directory suffix in PackageMap (skip ImportMap expansion)
131
+ for (const resolvedFile of result.files) {
132
+ addImportGraphEdge(filePath, resolvedFile);
133
+ }
134
+ if (!packageMap.has(filePath))
135
+ packageMap.set(filePath, new Set());
136
+ packageMap.get(filePath).add(result.dirSuffix);
137
+ }
138
+ else {
139
+ // 'files' kind or 'package' without PackageMap — use ImportMap directly
140
+ const files = result.files;
141
+ for (const resolvedFile of files) {
142
+ addImportEdge(filePath, resolvedFile);
143
+ }
144
+ // Record named bindings for precise Tier 2a resolution
145
+ if (namedBindings && namedImportMap && files.length === 1) {
146
+ const resolvedFile = files[0];
147
+ if (!namedImportMap.has(filePath))
148
+ namedImportMap.set(filePath, new Map());
149
+ const fileBindings = namedImportMap.get(filePath);
150
+ for (const binding of namedBindings) {
151
+ fileBindings.set(binding.local, { sourcePath: resolvedFile, exportedName: binding.exported });
152
+ }
153
+ }
154
+ }
155
+ }
156
+ /**
157
+ * Create transitive IMPORTS edges by walking re-export chains in the NamedImportMap
158
+ *
159
+ * When A imports {User} from B and B re-exports {User} from C, adds edge A→C
160
+ * Must be called AFTER all imports are processed
161
+ */
162
+ function addTransitiveImportEdges(namedImportMap, importMap, addImportEdge) {
163
+ for (const [filePath, bindings] of namedImportMap) {
164
+ const existingImports = importMap.get(filePath);
165
+ for (const [localName, binding] of bindings) {
166
+ // Walk the re-export chain to find the ultimate source file
167
+ let sourcePath = binding.sourcePath;
168
+ const visited = new Set([`${filePath}:${localName}`]);
169
+ let depth = 0;
170
+ while (depth < 5) {
171
+ const sourceBindings = namedImportMap.get(sourcePath);
172
+ if (!sourceBindings)
173
+ break;
174
+ const nextBinding = sourceBindings.get(binding.exportedName);
175
+ if (!nextBinding)
176
+ break;
177
+ const key = `${nextBinding.sourcePath}:${nextBinding.exportedName}`;
178
+ if (visited.has(key))
179
+ break;
180
+ visited.add(key);
181
+ sourcePath = nextBinding.sourcePath;
182
+ depth++;
183
+ }
184
+ // If the chain resolved to a different file, create a transitive edge
185
+ if (depth > 0 && (!existingImports || !existingImports.has(sourcePath))) {
186
+ addImportEdge(filePath, sourcePath);
187
+ }
188
+ }
189
+ }
190
+ }
191
+ export const processImports = async (graph, files, astCache, ctx, onProgress, repoRoot, allPaths) => {
192
+ const importMap = ctx.importMap;
193
+ const packageMap = ctx.packageMap;
194
+ const namedImportMap = ctx.namedImportMap;
195
+ // Use allPaths (full repo) when available for cross-chunk resolution
196
+ const allFileList = allPaths ?? files.map(f => f.path);
197
+ const allFilePaths = new Set(allFileList);
198
+ const parser = await loadParser();
199
+ const logSkipped = isVerboseIngestionEnabled();
200
+ const skippedByLang = logSkipped ? new Map() : null;
201
+ const resolveCache = new Map();
202
+ // Pre-compute normalized file list once
203
+ const normalizedFileList = allFileList.map(p => p.replace(/\\/g, '/'));
204
+ // Build suffix index for O(1) lookups
205
+ const index = buildSuffixIndex(normalizedFileList, allFileList);
206
+ // Track import statistics
207
+ let totalImportsFound = 0;
208
+ let totalImportsResolved = 0;
209
+ // Load language-specific configs once before the file loop
210
+ const effectiveRoot = repoRoot || '';
211
+ const configs = {
212
+ tsconfigPaths: await loadTsconfigPaths(effectiveRoot),
213
+ goModule: await loadGoModulePath(effectiveRoot),
214
+ composerConfig: await loadComposerConfig(effectiveRoot),
215
+ swiftPackageConfig: await loadSwiftPackageConfig(effectiveRoot),
216
+ csharpConfigs: await loadCSharpProjectConfig(effectiveRoot),
217
+ };
218
+ const resolveCtx = { allFilePaths, allFileList, normalizedFileList, index, resolveCache };
219
+ // Add IMPORTS edge to graph only (no ImportMap update)
220
+ const addImportGraphEdge = (filePath, resolvedPath) => {
221
+ const sourceId = generateId('File', filePath);
222
+ const targetId = generateId('File', resolvedPath);
223
+ const relId = generateId('IMPORTS', `${filePath}->${resolvedPath}`);
224
+ totalImportsResolved++;
225
+ graph.addRelationship({
226
+ id: relId,
227
+ sourceId,
228
+ targetId,
229
+ type: 'IMPORTS',
230
+ confidence: 1.0,
231
+ reason: '',
232
+ });
233
+ };
234
+ // Add IMPORTS edge + update ImportMap
235
+ const addImportEdge = (filePath, resolvedPath) => {
236
+ addImportGraphEdge(filePath, resolvedPath);
237
+ if (!importMap.has(filePath)) {
238
+ importMap.set(filePath, new Set());
239
+ }
240
+ importMap.get(filePath).add(resolvedPath);
241
+ };
242
+ for (let i = 0; i < files.length; i++) {
243
+ const file = files[i];
244
+ onProgress?.(i + 1, files.length);
245
+ if (i % 20 === 0)
246
+ await yieldToEventLoop();
247
+ // Check language support
248
+ const language = getLanguageFromFilename(file.path);
249
+ if (!language)
250
+ continue;
251
+ if (!isLanguageAvailable(language)) {
252
+ if (skippedByLang) {
253
+ skippedByLang.set(language, (skippedByLang.get(language) ?? 0) + 1);
254
+ }
255
+ continue;
256
+ }
257
+ const queryStr = LANGUAGE_QUERIES[language];
258
+ if (!queryStr)
259
+ continue;
260
+ // Load the language before querying (parser is stateful)
261
+ await loadLanguage(language, file.path);
262
+ // Get AST (try cache first)
263
+ let tree = astCache.get(file.path);
264
+ let wasReparsed = false;
265
+ if (!tree) {
266
+ try {
267
+ tree = parser.parse(file.content, undefined, { bufferSize: getTreeSitterBufferSize(file.content.length) });
268
+ }
269
+ catch (parseError) {
270
+ continue;
271
+ }
272
+ wasReparsed = true;
273
+ // Cache re-parsed tree for call/heritage phases
274
+ astCache.set(file.path, tree);
275
+ }
276
+ let query;
277
+ let matches;
278
+ try {
279
+ const lang = parser.getLanguage();
280
+ query = new Parser.Query(lang, queryStr);
281
+ matches = query.matches(tree.rootNode);
282
+ }
283
+ catch (queryError) {
284
+ if (isDev) {
285
+ console.group(`🔴 Query Error: ${file.path}`);
286
+ console.log('Language:', language);
287
+ console.log('Query (first 200 chars):', queryStr.substring(0, 200) + '...');
288
+ console.log('Error:', queryError?.message || queryError);
289
+ console.log('File content (first 300 chars):', file.content.substring(0, 300));
290
+ console.log('AST root type:', tree.rootNode?.type);
291
+ console.log('AST has errors:', tree.rootNode?.hasError);
292
+ console.groupEnd();
293
+ }
294
+ if (wasReparsed)
295
+ tree.delete?.();
296
+ continue;
297
+ }
298
+ matches.forEach(match => {
299
+ const captureMap = {};
300
+ match.captures.forEach(c => captureMap[c.name] = c.node);
301
+ if (captureMap['import']) {
302
+ const sourceNode = captureMap['import.source'];
303
+ if (!sourceNode) {
304
+ if (isDev) {
305
+ console.log(`⚠️ Import captured but no source node in ${file.path}`);
306
+ }
307
+ return;
308
+ }
309
+ // Clean path — remove quotes and angle brackets for C/C++ includes
310
+ const rawImportPath = language === SupportedLanguages.Kotlin
311
+ ? appendKotlinWildcard(sourceNode.text.replace(/['"<>]/g, ''), captureMap['import'])
312
+ : sourceNode.text.replace(/['"<>]/g, '');
313
+ totalImportsFound++;
314
+ const result = resolveLanguageImport(file.path, rawImportPath, language, configs, resolveCtx);
315
+ const bindings = namedImportMap ? extractNamedBindings(captureMap['import'], language) : undefined;
316
+ applyImportResult(result, file.path, importMap, packageMap, addImportEdge, addImportGraphEdge, bindings, namedImportMap);
317
+ }
318
+ // Language-specific call-as-import routing (Ruby require, etc)
319
+ if (captureMap['call']) {
320
+ const callNameNode = captureMap['call.name'];
321
+ if (callNameNode) {
322
+ const callRouter = callRouters[language];
323
+ const routed = callRouter(callNameNode.text, captureMap['call']);
324
+ if (routed && routed.kind === 'import') {
325
+ totalImportsFound++;
326
+ const result = resolveLanguageImport(file.path, routed.importPath, language, configs, resolveCtx);
327
+ applyImportResult(result, file.path, importMap, packageMap, addImportEdge, addImportGraphEdge);
328
+ }
329
+ }
330
+ }
331
+ });
332
+ // Tree owned by the LRU cache — no manual delete needed
333
+ }
334
+ if (skippedByLang && skippedByLang.size > 0) {
335
+ for (const [lang, count] of skippedByLang.entries()) {
336
+ console.warn(`[ingestion] Skipped ${count} ${lang} file(s) in import processing — ${lang} parser not available.`);
337
+ }
338
+ }
339
+ // Create transitive IMPORTS edges for re-export chains (barrel files)
340
+ addTransitiveImportEdges(namedImportMap, importMap, addImportEdge);
341
+ if (isDev) {
342
+ console.log(`Import processing complete: ${totalImportsResolved}/${totalImportsFound} imports resolved to graph edges`);
343
+ }
344
+ };
345
+ // Fast path: resolve pre-extracted imports (no AST parsing needed)
346
+ export const processImportsFromExtracted = async (graph, files, extractedImports, ctx, onProgress, repoRoot, prebuiltCtx) => {
347
+ const importMap = ctx.importMap;
348
+ const packageMap = ctx.packageMap;
349
+ const namedImportMap = ctx.namedImportMap;
350
+ const importCtx = prebuiltCtx ?? buildImportResolutionContext(files.map(f => f.path));
351
+ const { allFilePaths, allFileList, normalizedFileList, suffixIndex: index, resolveCache } = importCtx;
352
+ let totalImportsFound = 0;
353
+ let totalImportsResolved = 0;
354
+ const effectiveRoot = repoRoot || '';
355
+ const configs = {
356
+ tsconfigPaths: await loadTsconfigPaths(effectiveRoot),
357
+ goModule: await loadGoModulePath(effectiveRoot),
358
+ composerConfig: await loadComposerConfig(effectiveRoot),
359
+ swiftPackageConfig: await loadSwiftPackageConfig(effectiveRoot),
360
+ csharpConfigs: await loadCSharpProjectConfig(effectiveRoot),
361
+ };
362
+ const resolveCtx = { allFilePaths, allFileList, normalizedFileList, index, resolveCache };
363
+ // Add IMPORTS edge to graph only (no ImportMap update)
364
+ const addImportGraphEdge = (filePath, resolvedPath) => {
365
+ const sourceId = generateId('File', filePath);
366
+ const targetId = generateId('File', resolvedPath);
367
+ const relId = generateId('IMPORTS', `${filePath}->${resolvedPath}`);
368
+ totalImportsResolved++;
369
+ graph.addRelationship({
370
+ id: relId,
371
+ sourceId,
372
+ targetId,
373
+ type: 'IMPORTS',
374
+ confidence: 1.0,
375
+ reason: '',
376
+ });
377
+ };
378
+ // Add IMPORTS edge + update ImportMap
379
+ const addImportEdge = (filePath, resolvedPath) => {
380
+ addImportGraphEdge(filePath, resolvedPath);
381
+ if (!importMap.has(filePath)) {
382
+ importMap.set(filePath, new Set());
383
+ }
384
+ importMap.get(filePath).add(resolvedPath);
385
+ };
386
+ // Group by file for progress reporting
387
+ const importsByFile = new Map();
388
+ for (const imp of extractedImports) {
389
+ let list = importsByFile.get(imp.filePath);
390
+ if (!list) {
391
+ list = [];
392
+ importsByFile.set(imp.filePath, list);
393
+ }
394
+ list.push(imp);
395
+ }
396
+ const totalFiles = importsByFile.size;
397
+ let filesProcessed = 0;
398
+ for (const [filePath, fileImports] of importsByFile) {
399
+ filesProcessed++;
400
+ if (filesProcessed % 100 === 0) {
401
+ onProgress?.(filesProcessed, totalFiles);
402
+ await yieldToEventLoop();
403
+ }
404
+ for (const imp of fileImports) {
405
+ totalImportsFound++;
406
+ const result = resolveLanguageImport(filePath, imp.rawImportPath, imp.language, configs, resolveCtx);
407
+ applyImportResult(result, filePath, importMap, packageMap, addImportEdge, addImportGraphEdge, imp.namedBindings, namedImportMap);
408
+ }
409
+ }
410
+ onProgress?.(totalFiles, totalFiles);
411
+ // Create transitive IMPORTS edges for re-export chains (barrel files)
412
+ addTransitiveImportEdges(namedImportMap, importMap, addImportEdge);
413
+ if (isDev) {
414
+ console.log(`Import processing (fast path): ${totalImportsResolved}/${totalImportsFound} imports resolved to graph edges`);
415
+ }
416
+ };
@@ -0,0 +1,32 @@
1
+ /** @file language-config.ts @description Loads language-specific project configuration (tsconfig.json, go.mod, composer.json, .csproj, Package.swift) for import path resolution */
2
+ export interface TsconfigPaths {
3
+ aliases: Map<string, string>;
4
+ baseUrl: string;
5
+ }
6
+ export interface GoModuleConfig {
7
+ modulePath: string;
8
+ }
9
+ export interface ComposerConfig {
10
+ psr4: Map<string, string>;
11
+ }
12
+ export interface CSharpProjectConfig {
13
+ rootNamespace: string;
14
+ projectDir: string;
15
+ }
16
+ export interface SwiftPackageConfig {
17
+ targets: Map<string, string>;
18
+ }
19
+ /**
20
+ * Parse tsconfig.json to extract path aliases
21
+ *
22
+ * Tries tsconfig.json, tsconfig.app.json, tsconfig.base.json in order
23
+ */
24
+ export declare function loadTsconfigPaths(repoRoot: string): Promise<TsconfigPaths | null>;
25
+ /** Parse go.mod to extract module path */
26
+ export declare function loadGoModulePath(repoRoot: string): Promise<GoModuleConfig | null>;
27
+ /** Parse composer.json to extract PSR-4 autoload mappings (including autoload-dev) */
28
+ export declare function loadComposerConfig(repoRoot: string): Promise<ComposerConfig | null>;
29
+ /** Parse .csproj files to extract RootNamespace via BFS scan up to 5 levels deep */
30
+ export declare function loadCSharpProjectConfig(repoRoot: string): Promise<CSharpProjectConfig[]>;
31
+ /** Load Swift Package Manager target map from Sources/ directories */
32
+ export declare function loadSwiftPackageConfig(repoRoot: string): Promise<SwiftPackageConfig | null>;
@@ -0,0 +1,161 @@
1
+ // code-mapper/src/core/ingestion/language-config.ts
2
+ /** @file language-config.ts @description Loads language-specific project configuration (tsconfig.json, go.mod, composer.json, .csproj, Package.swift) for import path resolution */
3
+ import fs from 'fs/promises';
4
+ import path from 'path';
5
+ const isDev = process.env.NODE_ENV === 'development';
6
+ /**
7
+ * Parse tsconfig.json to extract path aliases
8
+ *
9
+ * Tries tsconfig.json, tsconfig.app.json, tsconfig.base.json in order
10
+ */
11
+ export async function loadTsconfigPaths(repoRoot) {
12
+ const candidates = ['tsconfig.json', 'tsconfig.app.json', 'tsconfig.base.json'];
13
+ for (const filename of candidates) {
14
+ try {
15
+ const tsconfigPath = path.join(repoRoot, filename);
16
+ const raw = await fs.readFile(tsconfigPath, 'utf-8');
17
+ // Strip JSON comments (// and /* */ style)
18
+ const stripped = raw.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
19
+ const tsconfig = JSON.parse(stripped);
20
+ const compilerOptions = tsconfig.compilerOptions;
21
+ if (!compilerOptions?.paths)
22
+ continue;
23
+ const baseUrl = compilerOptions.baseUrl || '.';
24
+ const aliases = new Map();
25
+ for (const [pattern, targets] of Object.entries(compilerOptions.paths)) {
26
+ if (!Array.isArray(targets) || targets.length === 0)
27
+ continue;
28
+ const target = targets[0];
29
+ // Convert glob patterns: "@/*" -> "@/", "src/*" -> "src/"
30
+ const aliasPrefix = pattern.endsWith('/*') ? pattern.slice(0, -1) : pattern;
31
+ const targetPrefix = target.endsWith('/*') ? target.slice(0, -1) : target;
32
+ aliases.set(aliasPrefix, targetPrefix);
33
+ }
34
+ if (aliases.size > 0) {
35
+ if (isDev) {
36
+ console.log(`📦 Loaded ${aliases.size} path aliases from ${filename}`);
37
+ }
38
+ return { aliases, baseUrl };
39
+ }
40
+ }
41
+ catch {
42
+ // File doesn't exist or isn't valid JSON — try next
43
+ }
44
+ }
45
+ return null;
46
+ }
47
+ /** Parse go.mod to extract module path */
48
+ export async function loadGoModulePath(repoRoot) {
49
+ try {
50
+ const goModPath = path.join(repoRoot, 'go.mod');
51
+ const content = await fs.readFile(goModPath, 'utf-8');
52
+ const match = content.match(/^module\s+(\S+)/m);
53
+ if (match) {
54
+ if (isDev) {
55
+ console.log(`📦 Loaded Go module path: ${match[1]}`);
56
+ }
57
+ return { modulePath: match[1] };
58
+ }
59
+ }
60
+ catch {
61
+ // No go.mod
62
+ }
63
+ return null;
64
+ }
65
+ /** Parse composer.json to extract PSR-4 autoload mappings (including autoload-dev) */
66
+ export async function loadComposerConfig(repoRoot) {
67
+ try {
68
+ const composerPath = path.join(repoRoot, 'composer.json');
69
+ const raw = await fs.readFile(composerPath, 'utf-8');
70
+ const composer = JSON.parse(raw);
71
+ const psr4Raw = composer.autoload?.['psr-4'] ?? {};
72
+ const psr4Dev = composer['autoload-dev']?.['psr-4'] ?? {};
73
+ const merged = { ...psr4Raw, ...psr4Dev };
74
+ const psr4 = new Map();
75
+ for (const [ns, dir] of Object.entries(merged)) {
76
+ const nsNorm = ns.replace(/\\+$/, '');
77
+ const dirNorm = dir.replace(/\\/g, '/').replace(/\/+$/, '');
78
+ psr4.set(nsNorm, dirNorm);
79
+ }
80
+ if (isDev) {
81
+ console.log(`📦 Loaded ${psr4.size} PSR-4 mappings from composer.json`);
82
+ }
83
+ return { psr4 };
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ }
89
+ /** Parse .csproj files to extract RootNamespace via BFS scan up to 5 levels deep */
90
+ export async function loadCSharpProjectConfig(repoRoot) {
91
+ const configs = [];
92
+ // BFS scan for .csproj files, capped at 100 dirs
93
+ const scanQueue = [{ dir: repoRoot, depth: 0 }];
94
+ const maxDepth = 5;
95
+ const maxDirs = 100;
96
+ let dirsScanned = 0;
97
+ while (scanQueue.length > 0 && dirsScanned < maxDirs) {
98
+ const { dir, depth } = scanQueue.shift();
99
+ dirsScanned++;
100
+ try {
101
+ const entries = await fs.readdir(dir, { withFileTypes: true });
102
+ for (const entry of entries) {
103
+ if (entry.isDirectory() && depth < maxDepth) {
104
+ // Skip common non-project directories
105
+ if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'bin' || entry.name === 'obj')
106
+ continue;
107
+ scanQueue.push({ dir: path.join(dir, entry.name), depth: depth + 1 });
108
+ }
109
+ if (entry.isFile() && entry.name.endsWith('.csproj')) {
110
+ try {
111
+ const csprojPath = path.join(dir, entry.name);
112
+ const content = await fs.readFile(csprojPath, 'utf-8');
113
+ const nsMatch = content.match(/<RootNamespace>\s*([^<]+)\s*<\/RootNamespace>/);
114
+ const rootNamespace = nsMatch
115
+ ? nsMatch[1].trim()
116
+ : entry.name.replace(/\.csproj$/, '');
117
+ const projectDir = path.relative(repoRoot, dir).replace(/\\/g, '/');
118
+ configs.push({ rootNamespace, projectDir });
119
+ if (isDev) {
120
+ console.log(`📦 Loaded C# project: ${entry.name} (namespace: ${rootNamespace}, dir: ${projectDir})`);
121
+ }
122
+ }
123
+ catch {
124
+ // Can't read .csproj
125
+ }
126
+ }
127
+ }
128
+ }
129
+ catch {
130
+ // Can't read directory
131
+ }
132
+ }
133
+ return configs;
134
+ }
135
+ /** Load Swift Package Manager target map from Sources/ directories */
136
+ export async function loadSwiftPackageConfig(repoRoot) {
137
+ // SPM convention: Sources/<TargetName>/ or Package/Sources/<TargetName>/
138
+ const targets = new Map();
139
+ const sourceDirs = ['Sources', 'Package/Sources', 'src'];
140
+ for (const sourceDir of sourceDirs) {
141
+ try {
142
+ const fullPath = path.join(repoRoot, sourceDir);
143
+ const entries = await fs.readdir(fullPath, { withFileTypes: true });
144
+ for (const entry of entries) {
145
+ if (entry.isDirectory()) {
146
+ targets.set(entry.name, sourceDir + '/' + entry.name);
147
+ }
148
+ }
149
+ }
150
+ catch {
151
+ // Directory doesn't exist
152
+ }
153
+ }
154
+ if (targets.size > 0) {
155
+ if (isDev) {
156
+ console.log(`📦 Loaded ${targets.size} Swift package targets`);
157
+ }
158
+ return { targets };
159
+ }
160
+ return null;
161
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @file mro-processor.ts
3
+ * @description Walks the inheritance DAG, collects methods from ancestors via HAS_METHOD
4
+ * edges, detects method-name collisions, and emits OVERRIDES edges using language-specific
5
+ * resolution rules (C++ leftmost base, C#/Java class-over-interface, Python C3 linearization,
6
+ * Rust requires qualified syntax). OVERRIDES edge direction: Class -> winning ancestor Method
7
+ */
8
+ import { KnowledgeGraph } from '../graph/types.js';
9
+ import { SupportedLanguages } from '../../config/supported-languages.js';
10
+ export interface MROEntry {
11
+ classId: string;
12
+ className: string;
13
+ language: SupportedLanguages;
14
+ mro: string[];
15
+ ambiguities: MethodAmbiguity[];
16
+ }
17
+ export interface MethodAmbiguity {
18
+ methodName: string;
19
+ definedIn: Array<{
20
+ classId: string;
21
+ className: string;
22
+ methodId: string;
23
+ }>;
24
+ resolvedTo: string | null;
25
+ reason: string;
26
+ }
27
+ export interface MROResult {
28
+ entries: MROEntry[];
29
+ overrideEdges: number;
30
+ ambiguityCount: number;
31
+ }
32
+ export declare function computeMRO(graph: KnowledgeGraph): MROResult;