@zuvia-software-solutions/code-mapper 1.4.0 → 2.0.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 (137) hide show
  1. package/dist/cli/ai-context.js +1 -1
  2. package/dist/cli/analyze.d.ts +1 -0
  3. package/dist/cli/analyze.js +73 -82
  4. package/dist/cli/augment.js +0 -2
  5. package/dist/cli/eval-server.d.ts +2 -2
  6. package/dist/cli/eval-server.js +6 -6
  7. package/dist/cli/index.js +6 -10
  8. package/dist/cli/mcp.d.ts +1 -3
  9. package/dist/cli/mcp.js +3 -3
  10. package/dist/cli/refresh.d.ts +2 -2
  11. package/dist/cli/refresh.js +24 -29
  12. package/dist/cli/status.js +4 -13
  13. package/dist/cli/tool.d.ts +5 -4
  14. package/dist/cli/tool.js +8 -10
  15. package/dist/config/ignore-service.js +14 -34
  16. package/dist/core/augmentation/engine.js +53 -83
  17. package/dist/core/db/adapter.d.ts +99 -0
  18. package/dist/core/db/adapter.js +402 -0
  19. package/dist/core/db/graph-loader.d.ts +27 -0
  20. package/dist/core/db/graph-loader.js +148 -0
  21. package/dist/core/db/queries.d.ts +160 -0
  22. package/dist/core/db/queries.js +441 -0
  23. package/dist/core/db/schema.d.ts +108 -0
  24. package/dist/core/db/schema.js +136 -0
  25. package/dist/core/embeddings/embedder.d.ts +21 -12
  26. package/dist/core/embeddings/embedder.js +104 -50
  27. package/dist/core/embeddings/embedding-pipeline.d.ts +48 -22
  28. package/dist/core/embeddings/embedding-pipeline.js +220 -262
  29. package/dist/core/embeddings/text-generator.js +4 -19
  30. package/dist/core/embeddings/types.d.ts +1 -1
  31. package/dist/core/graph/graph.d.ts +1 -1
  32. package/dist/core/graph/graph.js +1 -0
  33. package/dist/core/graph/types.d.ts +11 -9
  34. package/dist/core/graph/types.js +4 -1
  35. package/dist/core/incremental/refresh.d.ts +46 -0
  36. package/dist/core/incremental/refresh.js +464 -0
  37. package/dist/core/incremental/types.d.ts +2 -1
  38. package/dist/core/incremental/types.js +42 -44
  39. package/dist/core/ingestion/ast-cache.js +1 -0
  40. package/dist/core/ingestion/call-processor.d.ts +15 -3
  41. package/dist/core/ingestion/call-processor.js +448 -60
  42. package/dist/core/ingestion/cluster-enricher.d.ts +1 -1
  43. package/dist/core/ingestion/cluster-enricher.js +2 -0
  44. package/dist/core/ingestion/community-processor.d.ts +1 -1
  45. package/dist/core/ingestion/community-processor.js +8 -3
  46. package/dist/core/ingestion/export-detection.d.ts +1 -1
  47. package/dist/core/ingestion/export-detection.js +1 -1
  48. package/dist/core/ingestion/filesystem-walker.js +1 -1
  49. package/dist/core/ingestion/heritage-processor.d.ts +2 -2
  50. package/dist/core/ingestion/heritage-processor.js +22 -11
  51. package/dist/core/ingestion/import-processor.d.ts +2 -2
  52. package/dist/core/ingestion/import-processor.js +24 -9
  53. package/dist/core/ingestion/language-config.js +7 -4
  54. package/dist/core/ingestion/mro-processor.d.ts +1 -1
  55. package/dist/core/ingestion/mro-processor.js +23 -11
  56. package/dist/core/ingestion/named-binding-extraction.js +5 -5
  57. package/dist/core/ingestion/parsing-processor.d.ts +4 -4
  58. package/dist/core/ingestion/parsing-processor.js +26 -18
  59. package/dist/core/ingestion/pipeline.d.ts +4 -2
  60. package/dist/core/ingestion/pipeline.js +50 -20
  61. package/dist/core/ingestion/process-processor.d.ts +2 -2
  62. package/dist/core/ingestion/process-processor.js +28 -14
  63. package/dist/core/ingestion/resolution-context.d.ts +1 -1
  64. package/dist/core/ingestion/resolution-context.js +14 -4
  65. package/dist/core/ingestion/resolvers/csharp.js +4 -3
  66. package/dist/core/ingestion/resolvers/go.js +3 -1
  67. package/dist/core/ingestion/resolvers/jvm.js +13 -4
  68. package/dist/core/ingestion/resolvers/standard.js +2 -2
  69. package/dist/core/ingestion/resolvers/utils.js +6 -2
  70. package/dist/core/ingestion/route-stitcher.d.ts +15 -0
  71. package/dist/core/ingestion/route-stitcher.js +92 -0
  72. package/dist/core/ingestion/structure-processor.d.ts +1 -1
  73. package/dist/core/ingestion/structure-processor.js +3 -2
  74. package/dist/core/ingestion/symbol-table.d.ts +2 -0
  75. package/dist/core/ingestion/symbol-table.js +5 -1
  76. package/dist/core/ingestion/tree-sitter-queries.d.ts +2 -2
  77. package/dist/core/ingestion/tree-sitter-queries.js +177 -0
  78. package/dist/core/ingestion/type-env.js +20 -0
  79. package/dist/core/ingestion/type-extractors/csharp.js +4 -3
  80. package/dist/core/ingestion/type-extractors/go.js +23 -12
  81. package/dist/core/ingestion/type-extractors/php.js +18 -10
  82. package/dist/core/ingestion/type-extractors/ruby.js +15 -3
  83. package/dist/core/ingestion/type-extractors/rust.js +3 -2
  84. package/dist/core/ingestion/type-extractors/shared.js +3 -2
  85. package/dist/core/ingestion/type-extractors/typescript.js +11 -5
  86. package/dist/core/ingestion/utils.d.ts +27 -4
  87. package/dist/core/ingestion/utils.js +145 -100
  88. package/dist/core/ingestion/workers/parse-worker.d.ts +1 -0
  89. package/dist/core/ingestion/workers/parse-worker.js +97 -29
  90. package/dist/core/ingestion/workers/worker-pool.js +3 -0
  91. package/dist/core/search/bm25-index.d.ts +15 -8
  92. package/dist/core/search/bm25-index.js +48 -98
  93. package/dist/core/search/hybrid-search.d.ts +9 -3
  94. package/dist/core/search/hybrid-search.js +30 -25
  95. package/dist/core/search/reranker.js +9 -7
  96. package/dist/core/search/types.d.ts +0 -4
  97. package/dist/core/semantic/tsgo-service.d.ts +5 -1
  98. package/dist/core/semantic/tsgo-service.js +161 -66
  99. package/dist/lib/tsgo-test.d.ts +2 -0
  100. package/dist/lib/tsgo-test.js +6 -0
  101. package/dist/lib/type-utils.d.ts +25 -0
  102. package/dist/lib/type-utils.js +22 -0
  103. package/dist/lib/utils.d.ts +3 -2
  104. package/dist/lib/utils.js +3 -2
  105. package/dist/mcp/compatible-stdio-transport.js +1 -1
  106. package/dist/mcp/local/local-backend.d.ts +29 -56
  107. package/dist/mcp/local/local-backend.js +808 -1118
  108. package/dist/mcp/resources.js +35 -25
  109. package/dist/mcp/server.d.ts +1 -1
  110. package/dist/mcp/server.js +5 -5
  111. package/dist/mcp/tools.js +24 -25
  112. package/dist/storage/repo-manager.d.ts +2 -12
  113. package/dist/storage/repo-manager.js +1 -47
  114. package/dist/types/pipeline.d.ts +8 -5
  115. package/dist/types/pipeline.js +5 -0
  116. package/package.json +18 -11
  117. package/dist/cli/serve.d.ts +0 -5
  118. package/dist/cli/serve.js +0 -8
  119. package/dist/core/incremental/child-process.d.ts +0 -8
  120. package/dist/core/incremental/child-process.js +0 -649
  121. package/dist/core/incremental/refresh-coordinator.d.ts +0 -32
  122. package/dist/core/incremental/refresh-coordinator.js +0 -147
  123. package/dist/core/lbug/csv-generator.d.ts +0 -28
  124. package/dist/core/lbug/csv-generator.js +0 -355
  125. package/dist/core/lbug/lbug-adapter.d.ts +0 -96
  126. package/dist/core/lbug/lbug-adapter.js +0 -753
  127. package/dist/core/lbug/schema.d.ts +0 -46
  128. package/dist/core/lbug/schema.js +0 -402
  129. package/dist/mcp/core/embedder.d.ts +0 -24
  130. package/dist/mcp/core/embedder.js +0 -168
  131. package/dist/mcp/core/lbug-adapter.d.ts +0 -29
  132. package/dist/mcp/core/lbug-adapter.js +0 -330
  133. package/dist/server/api.d.ts +0 -5
  134. package/dist/server/api.js +0 -340
  135. package/dist/server/mcp-http.d.ts +0 -7
  136. package/dist/server/mcp-http.js +0 -95
  137. package/models/mlx-embedder.py +0 -185
@@ -1,5 +1,5 @@
1
1
  /** @file cluster-enricher.ts @description LLM-based enrichment for community clusters, generating semantic names, keywords, and descriptions */
2
- import { CommunityNode } from './community-processor.js';
2
+ import type { CommunityNode } from './community-processor.js';
3
3
  export interface ClusterEnrichment {
4
4
  name: string;
5
5
  keywords: string[];
@@ -50,6 +50,8 @@ export const enrichClusters = async (communities, memberMap, llmClient, onProgre
50
50
  let tokensUsed = 0;
51
51
  for (let i = 0; i < communities.length; i++) {
52
52
  const community = communities[i];
53
+ if (community === undefined)
54
+ continue;
53
55
  const members = memberMap.get(community.id) || [];
54
56
  onProgress?.(i + 1, communities.length);
55
57
  if (members.length === 0) {
@@ -1,5 +1,5 @@
1
1
  /** @file community-processor.ts @description Detects code communities using the Leiden algorithm on CALLS/EXTENDS/IMPLEMENTS edges, grouping symbols by functional area */
2
- import { KnowledgeGraph } from '../graph/types.js';
2
+ import type { KnowledgeGraph } from '../graph/types.js';
3
3
  export interface CommunityNode {
4
4
  id: string;
5
5
  label: string;
@@ -28,7 +28,10 @@ export const COMMUNITY_COLORS = [
28
28
  '#84cc16', // lime
29
29
  ];
30
30
  export const getCommunityColor = (communityIndex) => {
31
- return COMMUNITY_COLORS[communityIndex % COMMUNITY_COLORS.length];
31
+ const color = COMMUNITY_COLORS[communityIndex % COMMUNITY_COLORS.length];
32
+ if (color === undefined)
33
+ return '#888888';
34
+ return color;
32
35
  };
33
36
  /** Detect communities in the knowledge graph using the Leiden algorithm on CALLS/EXTENDS/IMPLEMENTS edges */
34
37
  export const processCommunities = async (knowledgeGraph, onProgress) => {
@@ -149,7 +152,7 @@ const buildGraphologyGraph = (knowledgeGraph, isLarge) => {
149
152
  return graph;
150
153
  };
151
154
  /** Create Community nodes with auto-generated labels based on member file paths */
152
- const createCommunityNodes = (communities, communityCount, graph, knowledgeGraph) => {
155
+ const createCommunityNodes = (communities, _communityCount, graph, knowledgeGraph) => {
153
156
  // Group node IDs by community number
154
157
  const communityMembers = new Map();
155
158
  Object.entries(communities).forEach(([nodeId, commNum]) => {
@@ -195,7 +198,7 @@ const generateHeuristicLabel = (memberIds, nodePathMap, graph, commNum) => {
195
198
  if (parts.length >= 2) {
196
199
  const folder = parts[parts.length - 2];
197
200
  // Skip generic folders
198
- if (!['src', 'lib', 'core', 'utils', 'common', 'shared', 'helpers'].includes(folder.toLowerCase())) {
201
+ if (folder !== undefined && !['src', 'lib', 'core', 'utils', 'common', 'shared', 'helpers'].includes(folder.toLowerCase())) {
199
202
  folderCounts.set(folder, (folderCounts.get(folder) || 0) + 1);
200
203
  }
201
204
  }
@@ -237,6 +240,8 @@ const findCommonPrefix = (strings) => {
237
240
  const sorted = strings.slice().sort();
238
241
  const first = sorted[0];
239
242
  const last = sorted[sorted.length - 1];
243
+ if (first === undefined || last === undefined)
244
+ return '';
240
245
  let i = 0;
241
246
  while (i < first.length && first[i] === last[i]) {
242
247
  i++;
@@ -1,5 +1,5 @@
1
1
  /** @file export-detection.ts @description Per-language detection of whether a symbol is exported/public, pure function safe for worker threads */
2
- import { SyntaxNode } from './utils.js';
2
+ import { type SyntaxNode } from './utils.js';
3
3
  import { SupportedLanguages } from '../../config/supported-languages.js';
4
4
  /**
5
5
  * Check if a tree-sitter node is exported/public in its language
@@ -74,7 +74,7 @@ const csharpExportChecker = (node, _name) => {
74
74
  const goExportChecker = (_node, name) => {
75
75
  if (name.length === 0)
76
76
  return false;
77
- const first = name[0];
77
+ const first = name.charAt(0);
78
78
  return first === first.toUpperCase() && first !== first.toLowerCase();
79
79
  };
80
80
  // Rust declaration node types for visibility_modifier scanning
@@ -30,7 +30,7 @@ export const walkRepositoryPaths = async (repoPath, onProgress) => {
30
30
  onProgress?.(processed, filtered.length, result.value.path);
31
31
  }
32
32
  else {
33
- onProgress?.(processed, filtered.length, batch[results.indexOf(result)]);
33
+ onProgress?.(processed, filtered.length, batch[results.indexOf(result)] ?? '');
34
34
  }
35
35
  }
36
36
  }
@@ -1,6 +1,6 @@
1
1
  /** @file heritage-processor.ts @description Extracts class inheritance relationships (EXTENDS/IMPLEMENTS) from AST matches. Resolves the correct edge type via symbol table lookup, falling back to language-gated heuristics for unresolved symbols: C#/Java use I[A-Z] convention, Swift defaults to IMPLEMENTS, all others default to EXTENDS */
2
- import { KnowledgeGraph } from '../graph/types.js';
3
- import { ASTCache } from './ast-cache.js';
2
+ import type { KnowledgeGraph } from '../graph/types.js';
3
+ import type { ASTCache } from './ast-cache.js';
4
4
  import type { ExtractedHeritage } from './workers/parse-worker.js';
5
5
  import type { ResolutionContext } from './resolution-context.js';
6
6
  export declare const processHeritage: (graph: KnowledgeGraph, files: {
@@ -4,6 +4,7 @@ import Parser from 'tree-sitter';
4
4
  import { isLanguageAvailable, loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
5
5
  import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
6
6
  import { generateId } from '../../lib/utils.js';
7
+ import { toNodeId, toEdgeId } from '../db/schema.js';
7
8
  import { getLanguageFromFilename, isVerboseIngestionEnabled, yieldToEventLoop } from './utils.js';
8
9
  import { SupportedLanguages } from '../../config/supported-languages.js';
9
10
  import { getTreeSitterBufferSize } from './constants.js';
@@ -18,7 +19,10 @@ const INTERFACE_NAME_RE = /^I[A-Z]/;
18
19
  const resolveExtendsType = (parentName, currentFilePath, ctx, language) => {
19
20
  const resolved = ctx.resolve(parentName, currentFilePath);
20
21
  if (resolved && resolved.candidates.length > 0) {
21
- const isInterface = resolved.candidates[0].type === 'Interface';
22
+ const topCandidate = resolved.candidates[0];
23
+ if (!topCandidate)
24
+ return { type: 'EXTENDS', idPrefix: 'Class' };
25
+ const isInterface = topCandidate.type === 'Interface';
22
26
  return isInterface
23
27
  ? { type: 'IMPLEMENTS', idPrefix: 'Interface' }
24
28
  : { type: 'EXTENDS', idPrefix: 'Class' };
@@ -47,7 +51,10 @@ const resolveHeritageId = (name, filePath, ctx, fallbackLabel, fallbackKey) => {
47
51
  if (resolved.tier === 'global' && resolved.candidates.length > 1) {
48
52
  return generateId(fallbackLabel, fallbackKey ?? name);
49
53
  }
50
- return resolved.candidates[0].nodeId;
54
+ const topCandidate = resolved.candidates[0];
55
+ if (!topCandidate)
56
+ return generateId(fallbackLabel, fallbackKey ?? name);
57
+ return toNodeId(topCandidate.nodeId);
51
58
  }
52
59
  return generateId(fallbackLabel, fallbackKey ?? name);
53
60
  };
@@ -57,6 +64,8 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
57
64
  const skippedByLang = logSkipped ? new Map() : null;
58
65
  for (let i = 0; i < files.length; i++) {
59
66
  const file = files[i];
67
+ if (!file)
68
+ continue;
60
69
  onProgress?.(i + 1, files.length);
61
70
  if (i % 20 === 0)
62
71
  await yieldToEventLoop();
@@ -81,7 +90,7 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
81
90
  try {
82
91
  tree = parser.parse(file.content, undefined, { bufferSize: getTreeSitterBufferSize(file.content.length) });
83
92
  }
84
- catch (parseError) {
93
+ catch {
85
94
  // Skip files that can't be parsed
86
95
  continue;
87
96
  }
@@ -91,8 +100,8 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
91
100
  let query;
92
101
  let matches;
93
102
  try {
94
- const language = parser.getLanguage();
95
- query = new Parser.Query(language, queryStr);
103
+ const tsLang = parser.getLanguage();
104
+ query = new Parser.Query(tsLang, queryStr);
96
105
  matches = query.matches(tree.rootNode);
97
106
  }
98
107
  catch (queryError) {
@@ -121,7 +130,7 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
121
130
  const parentId = resolveHeritageId(parentClassName, file.path, ctx, idPrefix);
122
131
  if (childId && parentId && childId !== parentId) {
123
132
  graph.addRelationship({
124
- id: generateId(relType, `${childId}->${parentId}`),
133
+ id: toEdgeId(`${relType}:${childId}->${parentId}`),
125
134
  sourceId: childId,
126
135
  targetId: parentId,
127
136
  type: relType,
@@ -138,7 +147,7 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
138
147
  const interfaceId = resolveHeritageId(interfaceName, file.path, ctx, 'Interface');
139
148
  if (classId && interfaceId) {
140
149
  graph.addRelationship({
141
- id: generateId('IMPLEMENTS', `${classId}->${interfaceId}`),
150
+ id: toEdgeId(`IMPLEMENTS:${classId}->${interfaceId}`),
142
151
  sourceId: classId,
143
152
  targetId: interfaceId,
144
153
  type: 'IMPLEMENTS',
@@ -155,7 +164,7 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
155
164
  const traitId = resolveHeritageId(traitName, file.path, ctx, 'Trait');
156
165
  if (structId && traitId) {
157
166
  graph.addRelationship({
158
- id: generateId('IMPLEMENTS', `${structId}->${traitId}`),
167
+ id: toEdgeId(`IMPLEMENTS:${structId}->${traitId}`),
159
168
  sourceId: structId,
160
169
  targetId: traitId,
161
170
  type: 'IMPLEMENTS',
@@ -186,6 +195,8 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, ctx
186
195
  await yieldToEventLoop();
187
196
  }
188
197
  const h = extractedHeritage[i];
198
+ if (!h)
199
+ continue;
189
200
  if (h.kind === 'extends') {
190
201
  const fileLanguage = getLanguageFromFilename(h.filePath);
191
202
  if (!fileLanguage)
@@ -195,7 +206,7 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, ctx
195
206
  const parentId = resolveHeritageId(h.parentName, h.filePath, ctx, idPrefix);
196
207
  if (childId && parentId && childId !== parentId) {
197
208
  graph.addRelationship({
198
- id: generateId(relType, `${childId}->${parentId}`),
209
+ id: toEdgeId(`${relType}:${childId}->${parentId}`),
199
210
  sourceId: childId,
200
211
  targetId: parentId,
201
212
  type: relType,
@@ -209,7 +220,7 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, ctx
209
220
  const interfaceId = resolveHeritageId(h.parentName, h.filePath, ctx, 'Interface');
210
221
  if (classId && interfaceId) {
211
222
  graph.addRelationship({
212
- id: generateId('IMPLEMENTS', `${classId}->${interfaceId}`),
223
+ id: toEdgeId(`IMPLEMENTS:${classId}->${interfaceId}`),
213
224
  sourceId: classId,
214
225
  targetId: interfaceId,
215
226
  type: 'IMPLEMENTS',
@@ -223,7 +234,7 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, ctx
223
234
  const traitId = resolveHeritageId(h.parentName, h.filePath, ctx, 'Trait');
224
235
  if (structId && traitId) {
225
236
  graph.addRelationship({
226
- id: generateId('IMPLEMENTS', `${structId}->${traitId}:${h.kind}`),
237
+ id: toEdgeId(`IMPLEMENTS:${structId}->${traitId}:${h.kind}`),
227
238
  sourceId: structId,
228
239
  targetId: traitId,
229
240
  type: 'IMPLEMENTS',
@@ -1,6 +1,6 @@
1
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';
2
+ import type { KnowledgeGraph } from '../graph/types.js';
3
+ import type { ASTCache } from './ast-cache.js';
4
4
  import type { ExtractedImport } from './workers/parse-worker.js';
5
5
  import type { ResolutionContext } from './resolution-context.js';
6
6
  import type { SuffixIndex } from './resolvers/index.js';
@@ -4,6 +4,7 @@ import Parser from 'tree-sitter';
4
4
  import { isLanguageAvailable, loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
5
5
  import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
6
6
  import { generateId } from '../../lib/utils.js';
7
+ import { toEdgeId } from '../db/schema.js';
7
8
  import { getLanguageFromFilename, isVerboseIngestionEnabled, yieldToEventLoop } from './utils.js';
8
9
  import { SupportedLanguages } from '../../config/supported-languages.js';
9
10
  import { extractNamedBindings } from './named-binding-extraction.js';
@@ -11,7 +12,7 @@ import { getTreeSitterBufferSize } from './constants.js';
11
12
  import { loadTsconfigPaths, loadGoModulePath, loadComposerConfig, loadCSharpProjectConfig, loadSwiftPackageConfig, } from './language-config.js';
12
13
  import { buildSuffixIndex, resolveImportPath, appendKotlinWildcard, KOTLIN_EXTENSIONS, resolveJvmWildcard, resolveJvmMemberImport, resolveGoPackageDir, resolveGoPackage, resolveCSharpImport, resolveCSharpNamespaceDir, resolvePhpImport, resolveRustImport, resolveRubyImport, } from './resolvers/index.js';
13
14
  import { callRouters } from './call-routing.js';
14
- const isDev = process.env.NODE_ENV === 'development';
15
+ const isDev = process.env['NODE_ENV'] === 'development';
15
16
  /** Check if a file path is directly inside a package directory identified by its suffix */
16
17
  export function isFileInPackageDir(filePath, dirSuffix) {
17
18
  // Prepend '/' so paths like "internal/auth/service.go" match suffix "/internal/auth/"
@@ -92,8 +93,10 @@ function resolveLanguageImport(filePath, rawImportPath, language, configs, ctx)
92
93
  const dirPrefix = targetDir + '/';
93
94
  const files = [];
94
95
  for (let i = 0; i < normalizedFileList.length; i++) {
95
- if (normalizedFileList[i].startsWith(dirPrefix) && normalizedFileList[i].endsWith('.swift')) {
96
- files.push(allFileList[i]);
96
+ const normalizedPath = normalizedFileList[i];
97
+ const originalPath = allFileList[i];
98
+ if (normalizedPath && originalPath && normalizedPath.startsWith(dirPrefix) && normalizedPath.endsWith('.swift')) {
99
+ files.push(originalPath);
97
100
  }
98
101
  }
99
102
  if (files.length > 0)
@@ -123,7 +126,7 @@ function resolveLanguageImport(filePath, rawImportPath, language, configs, ctx)
123
126
  return resolvedPath ? { kind: 'files', files: [resolvedPath] } : null;
124
127
  }
125
128
  /** Apply an ImportResult — emit graph edges, update ImportMap/PackageMap and NamedImportMap */
126
- function applyImportResult(result, filePath, importMap, packageMap, addImportEdge, addImportGraphEdge, namedBindings, namedImportMap) {
129
+ function applyImportResult(result, filePath, _importMap, packageMap, addImportEdge, addImportGraphEdge, namedBindings, namedImportMap) {
127
130
  if (!result)
128
131
  return;
129
132
  if (result.kind === 'package' && packageMap) {
@@ -133,7 +136,9 @@ function applyImportResult(result, filePath, importMap, packageMap, addImportEdg
133
136
  }
134
137
  if (!packageMap.has(filePath))
135
138
  packageMap.set(filePath, new Set());
136
- packageMap.get(filePath).add(result.dirSuffix);
139
+ const pkgSet = packageMap.get(filePath);
140
+ if (pkgSet)
141
+ pkgSet.add(result.dirSuffix);
137
142
  }
138
143
  else {
139
144
  // 'files' kind or 'package' without PackageMap — use ImportMap directly
@@ -144,9 +149,13 @@ function applyImportResult(result, filePath, importMap, packageMap, addImportEdg
144
149
  // Record named bindings for precise Tier 2a resolution
145
150
  if (namedBindings && namedImportMap && files.length === 1) {
146
151
  const resolvedFile = files[0];
152
+ if (!resolvedFile)
153
+ return;
147
154
  if (!namedImportMap.has(filePath))
148
155
  namedImportMap.set(filePath, new Map());
149
156
  const fileBindings = namedImportMap.get(filePath);
157
+ if (!fileBindings)
158
+ return;
150
159
  for (const binding of namedBindings) {
151
160
  fileBindings.set(binding.local, { sourcePath: resolvedFile, exportedName: binding.exported });
152
161
  }
@@ -220,7 +229,7 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
220
229
  const addImportGraphEdge = (filePath, resolvedPath) => {
221
230
  const sourceId = generateId('File', filePath);
222
231
  const targetId = generateId('File', resolvedPath);
223
- const relId = generateId('IMPORTS', `${filePath}->${resolvedPath}`);
232
+ const relId = toEdgeId(`IMPORTS:${filePath}->${resolvedPath}`);
224
233
  totalImportsResolved++;
225
234
  graph.addRelationship({
226
235
  id: relId,
@@ -237,10 +246,14 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
237
246
  if (!importMap.has(filePath)) {
238
247
  importMap.set(filePath, new Set());
239
248
  }
240
- importMap.get(filePath).add(resolvedPath);
249
+ const fileImports = importMap.get(filePath);
250
+ if (fileImports)
251
+ fileImports.add(resolvedPath);
241
252
  };
242
253
  for (let i = 0; i < files.length; i++) {
243
254
  const file = files[i];
255
+ if (!file)
256
+ continue;
244
257
  onProgress?.(i + 1, files.length);
245
258
  if (i % 20 === 0)
246
259
  await yieldToEventLoop();
@@ -364,7 +377,7 @@ export const processImportsFromExtracted = async (graph, files, extractedImports
364
377
  const addImportGraphEdge = (filePath, resolvedPath) => {
365
378
  const sourceId = generateId('File', filePath);
366
379
  const targetId = generateId('File', resolvedPath);
367
- const relId = generateId('IMPORTS', `${filePath}->${resolvedPath}`);
380
+ const relId = toEdgeId(`IMPORTS:${filePath}->${resolvedPath}`);
368
381
  totalImportsResolved++;
369
382
  graph.addRelationship({
370
383
  id: relId,
@@ -381,7 +394,9 @@ export const processImportsFromExtracted = async (graph, files, extractedImports
381
394
  if (!importMap.has(filePath)) {
382
395
  importMap.set(filePath, new Set());
383
396
  }
384
- importMap.get(filePath).add(resolvedPath);
397
+ const fileImports = importMap.get(filePath);
398
+ if (fileImports)
399
+ fileImports.add(resolvedPath);
385
400
  };
386
401
  // Group by file for progress reporting
387
402
  const importsByFile = new Map();
@@ -2,7 +2,7 @@
2
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
3
  import fs from 'fs/promises';
4
4
  import path from 'path';
5
- const isDev = process.env.NODE_ENV === 'development';
5
+ const isDev = process.env['NODE_ENV'] === 'development';
6
6
  /**
7
7
  * Parse tsconfig.json to extract path aliases
8
8
  *
@@ -50,7 +50,7 @@ export async function loadGoModulePath(repoRoot) {
50
50
  const goModPath = path.join(repoRoot, 'go.mod');
51
51
  const content = await fs.readFile(goModPath, 'utf-8');
52
52
  const match = content.match(/^module\s+(\S+)/m);
53
- if (match) {
53
+ if (match && match[1]) {
54
54
  if (isDev) {
55
55
  console.log(`📦 Loaded Go module path: ${match[1]}`);
56
56
  }
@@ -95,7 +95,10 @@ export async function loadCSharpProjectConfig(repoRoot) {
95
95
  const maxDirs = 100;
96
96
  let dirsScanned = 0;
97
97
  while (scanQueue.length > 0 && dirsScanned < maxDirs) {
98
- const { dir, depth } = scanQueue.shift();
98
+ const entry = scanQueue.shift();
99
+ if (!entry)
100
+ break;
101
+ const { dir, depth } = entry;
99
102
  dirsScanned++;
100
103
  try {
101
104
  const entries = await fs.readdir(dir, { withFileTypes: true });
@@ -111,7 +114,7 @@ export async function loadCSharpProjectConfig(repoRoot) {
111
114
  const csprojPath = path.join(dir, entry.name);
112
115
  const content = await fs.readFile(csprojPath, 'utf-8');
113
116
  const nsMatch = content.match(/<RootNamespace>\s*([^<]+)\s*<\/RootNamespace>/);
114
- const rootNamespace = nsMatch
117
+ const rootNamespace = nsMatch?.[1]
115
118
  ? nsMatch[1].trim()
116
119
  : entry.name.replace(/\.csproj$/, '');
117
120
  const projectDir = path.relative(repoRoot, dir).replace(/\\/g, '/');
@@ -5,7 +5,7 @@
5
5
  * resolution rules (C++ leftmost base, C#/Java class-over-interface, Python C3 linearization,
6
6
  * Rust requires qualified syntax). OVERRIDES edge direction: Class -> winning ancestor Method
7
7
  */
8
- import { KnowledgeGraph } from '../graph/types.js';
8
+ import type { KnowledgeGraph } from '../graph/types.js';
9
9
  import { SupportedLanguages } from '../../config/supported-languages.js';
10
10
  export interface MROEntry {
11
11
  classId: string;
@@ -6,7 +6,7 @@
6
6
  * resolution rules (C++ leftmost base, C#/Java class-over-interface, Python C3 linearization,
7
7
  * Rust requires qualified syntax). OVERRIDES edge direction: Class -> winning ancestor Method
8
8
  */
9
- import { generateId } from '../../lib/utils.js';
9
+ import { toEdgeId } from '../db/schema.js';
10
10
  import { SupportedLanguages } from '../../config/supported-languages.js';
11
11
  /** Collect EXTENDS, IMPLEMENTS, and HAS_METHOD adjacency from the graph */
12
12
  function buildAdjacency(graph) {
@@ -105,6 +105,8 @@ function c3Linearize(classId, parentMap, cache, inProgress) {
105
105
  if (seq.length === 0)
106
106
  continue;
107
107
  const candidate = seq[0];
108
+ if (candidate === undefined)
109
+ continue;
108
110
  const inTail = sequences.some(other => other.length > 1 && other.indexOf(candidate, 1) !== -1);
109
111
  if (!inTail) {
110
112
  head = candidate;
@@ -140,7 +142,11 @@ function resolveByMroOrder(methodName, defs, mroOrder, reasonPrefix) {
140
142
  };
141
143
  }
142
144
  }
143
- return { resolvedTo: defs[0].methodId, reason: `${reasonPrefix} fallback: first definition` };
145
+ const first = defs[0];
146
+ if (first === undefined) {
147
+ return { resolvedTo: null, reason: `${reasonPrefix}: no definitions found` };
148
+ }
149
+ return { resolvedTo: first.methodId, reason: `${reasonPrefix} fallback: first definition` };
144
150
  }
145
151
  function resolveCsharpJava(methodName, defs, parentEdgeTypes) {
146
152
  const classDefs = [];
@@ -155,10 +161,13 @@ function resolveCsharpJava(methodName, defs, parentEdgeTypes) {
155
161
  }
156
162
  }
157
163
  if (classDefs.length > 0) {
158
- return {
159
- resolvedTo: classDefs[0].methodId,
160
- reason: `class method wins: ${classDefs[0].className}::${methodName}`,
161
- };
164
+ const winner = classDefs[0];
165
+ if (winner !== undefined) {
166
+ return {
167
+ resolvedTo: winner.methodId,
168
+ reason: `class method wins: ${winner.className}::${methodName}`,
169
+ };
170
+ }
162
171
  }
163
172
  if (interfaceDefs.length > 1) {
164
173
  return {
@@ -167,10 +176,13 @@ function resolveCsharpJava(methodName, defs, parentEdgeTypes) {
167
176
  };
168
177
  }
169
178
  if (interfaceDefs.length === 1) {
170
- return {
171
- resolvedTo: interfaceDefs[0].methodId,
172
- reason: `single interface default: ${interfaceDefs[0].className}::${methodName}`,
173
- };
179
+ const single = interfaceDefs[0];
180
+ if (single !== undefined) {
181
+ return {
182
+ resolvedTo: single.methodId,
183
+ reason: `single interface default: ${single.className}::${methodName}`,
184
+ };
185
+ }
174
186
  }
175
187
  return { resolvedTo: null, reason: 'no resolution found' };
176
188
  }
@@ -288,7 +300,7 @@ export function computeMRO(graph) {
288
300
  // Emit OVERRIDES edge if resolution found
289
301
  if (resolution.resolvedTo !== null) {
290
302
  graph.addRelationship({
291
- id: generateId('OVERRIDES', `${classId}->${resolution.resolvedTo}`),
303
+ id: toEdgeId(`OVERRIDES:${classId}->${resolution.resolvedTo}`),
292
304
  sourceId: classId,
293
305
  targetId: resolution.resolvedTo,
294
306
  type: 'OVERRIDES',
@@ -84,10 +84,10 @@ export function extractTsNamedBindings(importNode) {
84
84
  if (child?.type === 'identifier')
85
85
  identifiers.push(child.text);
86
86
  }
87
- if (identifiers.length === 1) {
87
+ if (identifiers.length === 1 && identifiers[0] !== undefined) {
88
88
  bindings.push({ local: identifiers[0], exported: identifiers[0] });
89
89
  }
90
- else if (identifiers.length === 2) {
90
+ else if (identifiers.length === 2 && identifiers[0] !== undefined && identifiers[1] !== undefined) {
91
91
  // import { Foo as Bar } -> exported='Foo', local='Bar'
92
92
  bindings.push({ local: identifiers[1], exported: identifiers[0] });
93
93
  }
@@ -108,10 +108,10 @@ export function extractTsNamedBindings(importNode) {
108
108
  if (child?.type === 'identifier')
109
109
  identifiers.push(child.text);
110
110
  }
111
- if (identifiers.length === 1) {
111
+ if (identifiers.length === 1 && identifiers[0] !== undefined) {
112
112
  bindings.push({ local: identifiers[0], exported: identifiers[0] });
113
113
  }
114
- else if (identifiers.length === 2) {
114
+ else if (identifiers.length === 2 && identifiers[0] !== undefined && identifiers[1] !== undefined) {
115
115
  // export { Repo as Repository } -> first is source name, second is exported alias
116
116
  bindings.push({ local: identifiers[1], exported: identifiers[0] });
117
117
  }
@@ -198,7 +198,7 @@ function collectRustBindings(node, bindings) {
198
198
  idents.push(nameNode.text);
199
199
  }
200
200
  }
201
- if (idents.length === 2) {
201
+ if (idents.length === 2 && idents[0] !== undefined && idents[1] !== undefined) {
202
202
  bindings.push({ local: idents[1], exported: idents[0] });
203
203
  }
204
204
  return;
@@ -1,8 +1,8 @@
1
1
  /** @file parsing-processor.ts @description Parses source files via tree-sitter, extracts code structure nodes (classes, functions, methods, etc), populates the symbol table, and emits DEFINES/HAS_METHOD graph relationships. Supports parallel worker pools with sequential fallback */
2
- import { KnowledgeGraph } from '../graph/types.js';
3
- import { SymbolTable } from './symbol-table.js';
4
- import { ASTCache } from './ast-cache.js';
5
- import { WorkerPool } from './workers/worker-pool.js';
2
+ import type { KnowledgeGraph } from '../graph/types.js';
3
+ import type { SymbolTable } from './symbol-table.js';
4
+ import type { ASTCache } from './ast-cache.js';
5
+ import type { WorkerPool } from './workers/worker-pool.js';
6
6
  import type { ExtractedImport, ExtractedCall, ExtractedHeritage, ExtractedRoute, FileConstructorBindings } from './workers/parse-worker.js';
7
7
  export type FileProgressCallback = (current: number, total: number, filePath: string) => void;
8
8
  export interface WorkerExtractedData {
@@ -4,6 +4,7 @@ import Parser from 'tree-sitter';
4
4
  import { loadParser, loadLanguage, isLanguageAvailable } from '../tree-sitter/parser-loader.js';
5
5
  import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
6
6
  import { generateId } from '../../lib/utils.js';
7
+ import { toNodeId, toEdgeId } from '../db/schema.js';
7
8
  import { getLanguageFromFilename, yieldToEventLoop, getDefinitionNodeFromCaptures, findEnclosingClassId, extractMethodSignature } from './utils.js';
8
9
  import { isNodeExported } from './export-detection.js';
9
10
  import { detectFrameworkFromAST } from './framework-detection.js';
@@ -11,7 +12,7 @@ import { typeConfigs } from './type-extractors/index.js';
11
12
  import { getTreeSitterBufferSize, TREE_SITTER_MAX_BUFFER } from './constants.js';
12
13
  export { isNodeExported } from './export-detection.js';
13
14
  // Worker-based parallel parsing
14
- const processParsingWithWorkers = async (graph, files, symbolTable, astCache, workerPool, onFileProgress) => {
15
+ const processParsingWithWorkers = async (graph, files, symbolTable, _astCache, workerPool, onFileProgress) => {
15
16
  // Filter to parseable files only
16
17
  const parseableFiles = [];
17
18
  for (const file of files) {
@@ -35,20 +36,27 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
35
36
  for (const result of chunkResults) {
36
37
  for (const node of result.nodes) {
37
38
  graph.addNode({
38
- id: node.id,
39
+ id: toNodeId(node.id),
39
40
  label: node.label,
40
41
  properties: node.properties,
41
42
  });
42
43
  }
43
44
  for (const rel of result.relationships) {
44
- graph.addRelationship(rel);
45
+ graph.addRelationship({
46
+ id: toEdgeId(rel.id),
47
+ sourceId: toNodeId(rel.sourceId),
48
+ targetId: toNodeId(rel.targetId),
49
+ type: rel.type,
50
+ confidence: rel.confidence,
51
+ reason: rel.reason,
52
+ });
45
53
  }
46
54
  for (const sym of result.symbols) {
47
55
  symbolTable.add(sym.filePath, sym.name, sym.nodeId, sym.type, {
48
- parameterCount: sym.parameterCount,
49
- returnType: sym.returnType,
50
- ownerId: sym.ownerId,
51
- parameterTypes: sym.parameterTypes,
56
+ ...(sym.parameterCount !== undefined ? { parameterCount: sym.parameterCount } : {}),
57
+ ...(sym.returnType !== undefined ? { returnType: sym.returnType } : {}),
58
+ ...(sym.ownerId !== undefined ? { ownerId: sym.ownerId } : {}),
59
+ ...(sym.parameterTypes !== undefined ? { parameterTypes: sym.parameterTypes } : {}),
52
60
  });
53
61
  }
54
62
  allImports.push(...result.imports);
@@ -81,6 +89,8 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
81
89
  const skippedLanguages = new Map();
82
90
  for (let i = 0; i < files.length; i++) {
83
91
  const file = files[i];
92
+ if (!file)
93
+ continue;
84
94
  onFileProgress?.(i + 1, total, file.path);
85
95
  if (i % 20 === 0)
86
96
  await yieldToEventLoop();
@@ -218,10 +228,8 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
218
228
  astFrameworkMultiplier: frameworkHint.entryPointMultiplier,
219
229
  astFrameworkReason: frameworkHint.reason,
220
230
  } : {}),
221
- ...(methodSig ? {
222
- parameterCount: methodSig.parameterCount,
223
- returnType: methodSig.returnType,
224
- } : {}),
231
+ ...(methodSig?.parameterCount !== undefined ? { parameterCount: methodSig.parameterCount } : {}),
232
+ ...(methodSig?.returnType !== undefined ? { returnType: methodSig.returnType } : {}),
225
233
  },
226
234
  };
227
235
  graph.addNode(node);
@@ -230,13 +238,13 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
230
238
  const needsOwner = nodeLabel === 'Method' || nodeLabel === 'Constructor' || nodeLabel === 'Property' || nodeLabel === 'Function';
231
239
  const enclosingClassId = needsOwner ? findEnclosingClassId(nameNode || definitionNodeForRange, file.path) : null;
232
240
  symbolTable.add(file.path, nodeName, nodeId, nodeLabel, {
233
- parameterCount: methodSig?.parameterCount,
234
- returnType: methodSig?.returnType,
235
- parameterTypes: methodSig?.parameterTypes,
236
- ownerId: enclosingClassId ?? undefined,
241
+ ...(methodSig?.parameterCount !== undefined ? { parameterCount: methodSig.parameterCount } : {}),
242
+ ...(methodSig?.returnType !== undefined ? { returnType: methodSig.returnType } : {}),
243
+ ...(methodSig?.parameterTypes !== undefined ? { parameterTypes: methodSig.parameterTypes } : {}),
244
+ ...(enclosingClassId !== null ? { ownerId: enclosingClassId } : {}),
237
245
  });
238
246
  const fileId = generateId('File', file.path);
239
- const relId = generateId('DEFINES', `${fileId}->${nodeId}`);
247
+ const relId = toEdgeId(`DEFINES:${fileId}->${nodeId}`);
240
248
  const relationship = {
241
249
  id: relId,
242
250
  sourceId: fileId,
@@ -249,8 +257,8 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
249
257
  // HAS_METHOD: link method/constructor/property to enclosing class
250
258
  if (enclosingClassId) {
251
259
  graph.addRelationship({
252
- id: generateId('HAS_METHOD', `${enclosingClassId}->${nodeId}`),
253
- sourceId: enclosingClassId,
260
+ id: toEdgeId(`HAS_METHOD:${enclosingClassId}->${nodeId}`),
261
+ sourceId: toNodeId(enclosingClassId),
254
262
  targetId: nodeId,
255
263
  type: 'HAS_METHOD',
256
264
  confidence: 1.0,
@@ -1,3 +1,5 @@
1
1
  /** @file pipeline.ts @description Main ingestion pipeline that orchestrates scanning, parsing, resolution, community detection, and process detection across chunked file batches */
2
- import { PipelineProgress, PipelineResult } from '../../types/pipeline.js';
3
- export declare const runPipelineFromRepo: (repoPath: string, onProgress: (progress: PipelineProgress) => void) => Promise<PipelineResult>;
2
+ import type { PipelineProgress, PipelineResult } from '../../types/pipeline.js';
3
+ export declare const runPipelineFromRepo: (repoPath: string, onProgress: (progress: PipelineProgress) => void, opts?: {
4
+ tsgo?: boolean;
5
+ }) => Promise<PipelineResult>;