gitnexus 1.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.
- package/README.md +181 -0
- package/dist/cli/ai-context.d.ts +21 -0
- package/dist/cli/ai-context.js +219 -0
- package/dist/cli/analyze.d.ts +10 -0
- package/dist/cli/analyze.js +118 -0
- package/dist/cli/clean.d.ts +8 -0
- package/dist/cli/clean.js +29 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +42 -0
- package/dist/cli/list.d.ts +6 -0
- package/dist/cli/list.js +27 -0
- package/dist/cli/mcp.d.ts +7 -0
- package/dist/cli/mcp.js +85 -0
- package/dist/cli/serve.d.ts +3 -0
- package/dist/cli/serve.js +5 -0
- package/dist/cli/status.d.ts +6 -0
- package/dist/cli/status.js +27 -0
- package/dist/config/ignore-service.d.ts +1 -0
- package/dist/config/ignore-service.js +208 -0
- package/dist/config/supported-languages.d.ts +11 -0
- package/dist/config/supported-languages.js +15 -0
- package/dist/core/embeddings/embedder.d.ts +60 -0
- package/dist/core/embeddings/embedder.js +205 -0
- package/dist/core/embeddings/embedding-pipeline.d.ts +50 -0
- package/dist/core/embeddings/embedding-pipeline.js +321 -0
- package/dist/core/embeddings/index.d.ts +9 -0
- package/dist/core/embeddings/index.js +9 -0
- package/dist/core/embeddings/text-generator.d.ts +24 -0
- package/dist/core/embeddings/text-generator.js +182 -0
- package/dist/core/embeddings/types.d.ts +87 -0
- package/dist/core/embeddings/types.js +32 -0
- package/dist/core/graph/graph.d.ts +2 -0
- package/dist/core/graph/graph.js +61 -0
- package/dist/core/graph/types.d.ts +50 -0
- package/dist/core/graph/types.js +1 -0
- package/dist/core/ingestion/ast-cache.d.ts +11 -0
- package/dist/core/ingestion/ast-cache.js +34 -0
- package/dist/core/ingestion/call-processor.d.ts +8 -0
- package/dist/core/ingestion/call-processor.js +269 -0
- package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
- package/dist/core/ingestion/cluster-enricher.js +170 -0
- package/dist/core/ingestion/community-processor.d.ts +39 -0
- package/dist/core/ingestion/community-processor.js +269 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +39 -0
- package/dist/core/ingestion/entry-point-scoring.js +235 -0
- package/dist/core/ingestion/filesystem-walker.d.ts +5 -0
- package/dist/core/ingestion/filesystem-walker.js +26 -0
- package/dist/core/ingestion/framework-detection.d.ts +38 -0
- package/dist/core/ingestion/framework-detection.js +183 -0
- package/dist/core/ingestion/heritage-processor.d.ts +14 -0
- package/dist/core/ingestion/heritage-processor.js +134 -0
- package/dist/core/ingestion/import-processor.d.ts +8 -0
- package/dist/core/ingestion/import-processor.js +490 -0
- package/dist/core/ingestion/parsing-processor.d.ts +8 -0
- package/dist/core/ingestion/parsing-processor.js +249 -0
- package/dist/core/ingestion/pipeline.d.ts +2 -0
- package/dist/core/ingestion/pipeline.js +228 -0
- package/dist/core/ingestion/process-processor.d.ts +51 -0
- package/dist/core/ingestion/process-processor.js +278 -0
- package/dist/core/ingestion/structure-processor.d.ts +2 -0
- package/dist/core/ingestion/structure-processor.js +36 -0
- package/dist/core/ingestion/symbol-table.d.ts +33 -0
- package/dist/core/ingestion/symbol-table.js +38 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +11 -0
- package/dist/core/ingestion/tree-sitter-queries.js +319 -0
- package/dist/core/ingestion/utils.d.ts +10 -0
- package/dist/core/ingestion/utils.js +44 -0
- package/dist/core/kuzu/csv-generator.d.ts +22 -0
- package/dist/core/kuzu/csv-generator.js +272 -0
- package/dist/core/kuzu/kuzu-adapter.d.ts +81 -0
- package/dist/core/kuzu/kuzu-adapter.js +568 -0
- package/dist/core/kuzu/schema.d.ts +53 -0
- package/dist/core/kuzu/schema.js +380 -0
- package/dist/core/search/bm25-index.d.ts +22 -0
- package/dist/core/search/bm25-index.js +52 -0
- package/dist/core/search/hybrid-search.d.ts +49 -0
- package/dist/core/search/hybrid-search.js +118 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +4 -0
- package/dist/core/tree-sitter/parser-loader.js +42 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.js +3 -0
- package/dist/mcp/core/embedder.d.ts +27 -0
- package/dist/mcp/core/embedder.js +93 -0
- package/dist/mcp/core/kuzu-adapter.d.ts +23 -0
- package/dist/mcp/core/kuzu-adapter.js +62 -0
- package/dist/mcp/local/local-backend.d.ts +73 -0
- package/dist/mcp/local/local-backend.js +752 -0
- package/dist/mcp/resources.d.ts +31 -0
- package/dist/mcp/resources.js +279 -0
- package/dist/mcp/server.d.ts +12 -0
- package/dist/mcp/server.js +130 -0
- package/dist/mcp/staleness.d.ts +15 -0
- package/dist/mcp/staleness.js +29 -0
- package/dist/mcp/tools.d.ts +24 -0
- package/dist/mcp/tools.js +160 -0
- package/dist/server/api.d.ts +6 -0
- package/dist/server/api.js +156 -0
- package/dist/storage/git.d.ts +7 -0
- package/dist/storage/git.js +39 -0
- package/dist/storage/repo-manager.d.ts +61 -0
- package/dist/storage/repo-manager.js +106 -0
- package/dist/types/pipeline.d.ts +28 -0
- package/dist/types/pipeline.js +16 -0
- package/package.json +80 -0
- package/skills/debugging.md +104 -0
- package/skills/exploring.md +112 -0
- package/skills/impact-analysis.md +114 -0
- package/skills/refactoring.md +119 -0
- package/vendor/leiden/index.cjs +355 -0
- package/vendor/leiden/utils.cjs +392 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process Detection Processor
|
|
3
|
+
*
|
|
4
|
+
* Detects execution flows (Processes) in the code graph by:
|
|
5
|
+
* 1. Finding entry points (functions with no internal callers)
|
|
6
|
+
* 2. Tracing forward via CALLS edges (BFS)
|
|
7
|
+
* 3. Grouping and deduplicating similar paths
|
|
8
|
+
* 4. Labeling with heuristic names
|
|
9
|
+
*
|
|
10
|
+
* Processes help agents understand how features work through the codebase.
|
|
11
|
+
*/
|
|
12
|
+
import { calculateEntryPointScore, isTestFile } from './entry-point-scoring.js';
|
|
13
|
+
const isDev = process.env.NODE_ENV !== 'production';
|
|
14
|
+
const DEFAULT_CONFIG = {
|
|
15
|
+
maxTraceDepth: 10,
|
|
16
|
+
maxBranching: 4,
|
|
17
|
+
maxProcesses: 75,
|
|
18
|
+
minSteps: 2,
|
|
19
|
+
};
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// MAIN PROCESSOR
|
|
22
|
+
// ============================================================================
|
|
23
|
+
/**
|
|
24
|
+
* Detect processes (execution flows) in the knowledge graph
|
|
25
|
+
*
|
|
26
|
+
* This runs AFTER community detection, using CALLS edges to trace flows.
|
|
27
|
+
*/
|
|
28
|
+
export const processProcesses = async (knowledgeGraph, memberships, onProgress, config = {}) => {
|
|
29
|
+
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
30
|
+
onProgress?.('Finding entry points...', 0);
|
|
31
|
+
// Build lookup maps
|
|
32
|
+
const membershipMap = new Map();
|
|
33
|
+
memberships.forEach(m => membershipMap.set(m.nodeId, m.communityId));
|
|
34
|
+
const callsEdges = buildCallsGraph(knowledgeGraph);
|
|
35
|
+
const reverseCallsEdges = buildReverseCallsGraph(knowledgeGraph);
|
|
36
|
+
const nodeMap = new Map();
|
|
37
|
+
knowledgeGraph.nodes.forEach(n => nodeMap.set(n.id, n));
|
|
38
|
+
// Step 1: Find entry points (functions that call others but have few callers)
|
|
39
|
+
const entryPoints = findEntryPoints(knowledgeGraph, reverseCallsEdges, callsEdges);
|
|
40
|
+
onProgress?.(`Found ${entryPoints.length} entry points, tracing flows...`, 20);
|
|
41
|
+
onProgress?.(`Found ${entryPoints.length} entry points, tracing flows...`, 20);
|
|
42
|
+
// Step 2: Trace processes from each entry point
|
|
43
|
+
const allTraces = [];
|
|
44
|
+
for (let i = 0; i < entryPoints.length && allTraces.length < cfg.maxProcesses * 2; i++) {
|
|
45
|
+
const entryId = entryPoints[i];
|
|
46
|
+
const traces = traceFromEntryPoint(entryId, callsEdges, cfg);
|
|
47
|
+
// Filter out traces that are too short
|
|
48
|
+
traces.filter(t => t.length >= cfg.minSteps).forEach(t => allTraces.push(t));
|
|
49
|
+
if (i % 10 === 0) {
|
|
50
|
+
onProgress?.(`Tracing entry point ${i + 1}/${entryPoints.length}...`, 20 + (i / entryPoints.length) * 40);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
onProgress?.(`Found ${allTraces.length} traces, deduplicating...`, 60);
|
|
54
|
+
// Step 3: Deduplicate similar traces
|
|
55
|
+
const uniqueTraces = deduplicateTraces(allTraces);
|
|
56
|
+
// Step 4: Limit to max processes (prioritize longer traces)
|
|
57
|
+
const limitedTraces = uniqueTraces
|
|
58
|
+
.sort((a, b) => b.length - a.length)
|
|
59
|
+
.slice(0, cfg.maxProcesses);
|
|
60
|
+
onProgress?.(`Creating ${limitedTraces.length} process nodes...`, 80);
|
|
61
|
+
// Step 5: Create process nodes
|
|
62
|
+
const processes = [];
|
|
63
|
+
const steps = [];
|
|
64
|
+
limitedTraces.forEach((trace, idx) => {
|
|
65
|
+
const entryPointId = trace[0];
|
|
66
|
+
const terminalId = trace[trace.length - 1];
|
|
67
|
+
// Get communities touched
|
|
68
|
+
const communitiesSet = new Set();
|
|
69
|
+
trace.forEach(nodeId => {
|
|
70
|
+
const comm = membershipMap.get(nodeId);
|
|
71
|
+
if (comm)
|
|
72
|
+
communitiesSet.add(comm);
|
|
73
|
+
});
|
|
74
|
+
const communities = Array.from(communitiesSet);
|
|
75
|
+
// Determine process type
|
|
76
|
+
const processType = communities.length > 1 ? 'cross_community' : 'intra_community';
|
|
77
|
+
// Generate label
|
|
78
|
+
const entryNode = nodeMap.get(entryPointId);
|
|
79
|
+
const terminalNode = nodeMap.get(terminalId);
|
|
80
|
+
const entryName = entryNode?.properties.name || 'Unknown';
|
|
81
|
+
const terminalName = terminalNode?.properties.name || 'Unknown';
|
|
82
|
+
const heuristicLabel = `${capitalize(entryName)} → ${capitalize(terminalName)}`;
|
|
83
|
+
const processId = `proc_${idx}_${sanitizeId(entryName)}`;
|
|
84
|
+
processes.push({
|
|
85
|
+
id: processId,
|
|
86
|
+
label: heuristicLabel,
|
|
87
|
+
heuristicLabel,
|
|
88
|
+
processType,
|
|
89
|
+
stepCount: trace.length,
|
|
90
|
+
communities,
|
|
91
|
+
entryPointId,
|
|
92
|
+
terminalId,
|
|
93
|
+
trace,
|
|
94
|
+
});
|
|
95
|
+
// Create step relationships
|
|
96
|
+
trace.forEach((nodeId, stepIdx) => {
|
|
97
|
+
steps.push({
|
|
98
|
+
nodeId,
|
|
99
|
+
processId,
|
|
100
|
+
step: stepIdx + 1, // 1-indexed
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
onProgress?.('Process detection complete!', 100);
|
|
105
|
+
// Calculate stats
|
|
106
|
+
const crossCommunityCount = processes.filter(p => p.processType === 'cross_community').length;
|
|
107
|
+
const avgStepCount = processes.length > 0
|
|
108
|
+
? processes.reduce((sum, p) => sum + p.stepCount, 0) / processes.length
|
|
109
|
+
: 0;
|
|
110
|
+
return {
|
|
111
|
+
processes,
|
|
112
|
+
steps,
|
|
113
|
+
stats: {
|
|
114
|
+
totalProcesses: processes.length,
|
|
115
|
+
crossCommunityCount,
|
|
116
|
+
avgStepCount: Math.round(avgStepCount * 10) / 10,
|
|
117
|
+
entryPointsFound: entryPoints.length,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
const buildCallsGraph = (graph) => {
|
|
122
|
+
const adj = new Map();
|
|
123
|
+
graph.relationships.forEach(rel => {
|
|
124
|
+
if (rel.type === 'CALLS') {
|
|
125
|
+
if (!adj.has(rel.sourceId)) {
|
|
126
|
+
adj.set(rel.sourceId, []);
|
|
127
|
+
}
|
|
128
|
+
adj.get(rel.sourceId).push(rel.targetId);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return adj;
|
|
132
|
+
};
|
|
133
|
+
const buildReverseCallsGraph = (graph) => {
|
|
134
|
+
const adj = new Map();
|
|
135
|
+
graph.relationships.forEach(rel => {
|
|
136
|
+
if (rel.type === 'CALLS') {
|
|
137
|
+
if (!adj.has(rel.targetId)) {
|
|
138
|
+
adj.set(rel.targetId, []);
|
|
139
|
+
}
|
|
140
|
+
adj.get(rel.targetId).push(rel.sourceId);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
return adj;
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Find functions/methods that are good entry points for tracing.
|
|
147
|
+
*
|
|
148
|
+
* Entry points are scored based on:
|
|
149
|
+
* 1. Call ratio (calls many, called by few)
|
|
150
|
+
* 2. Export status (exported/public functions rank higher)
|
|
151
|
+
* 3. Name patterns (handle*, on*, *Controller, etc.)
|
|
152
|
+
*
|
|
153
|
+
* Test files are excluded entirely.
|
|
154
|
+
*/
|
|
155
|
+
const findEntryPoints = (graph, reverseCallsEdges, callsEdges) => {
|
|
156
|
+
const symbolTypes = new Set(['Function', 'Method']);
|
|
157
|
+
const entryPointCandidates = [];
|
|
158
|
+
graph.nodes.forEach(node => {
|
|
159
|
+
if (!symbolTypes.has(node.label))
|
|
160
|
+
return;
|
|
161
|
+
const filePath = node.properties.filePath || '';
|
|
162
|
+
// Skip test files entirely
|
|
163
|
+
if (isTestFile(filePath))
|
|
164
|
+
return;
|
|
165
|
+
const callers = reverseCallsEdges.get(node.id) || [];
|
|
166
|
+
const callees = callsEdges.get(node.id) || [];
|
|
167
|
+
// Must have at least 1 outgoing call to trace forward
|
|
168
|
+
if (callees.length === 0)
|
|
169
|
+
return;
|
|
170
|
+
// Calculate entry point score using new scoring system
|
|
171
|
+
const { score, reasons } = calculateEntryPointScore(node.properties.name, node.properties.language || 'javascript', node.properties.isExported ?? false, callers.length, callees.length, filePath // Pass filePath for framework detection
|
|
172
|
+
);
|
|
173
|
+
if (score > 0) {
|
|
174
|
+
entryPointCandidates.push({ id: node.id, score, reasons });
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
// Sort by score descending and return top candidates
|
|
178
|
+
const sorted = entryPointCandidates.sort((a, b) => b.score - a.score);
|
|
179
|
+
// DEBUG: Log top candidates with new scoring details
|
|
180
|
+
if (sorted.length > 0 && isDev) {
|
|
181
|
+
console.log(`[Process] Top 10 entry point candidates (new scoring):`);
|
|
182
|
+
sorted.slice(0, 10).forEach((c, i) => {
|
|
183
|
+
const node = graph.nodes.find(n => n.id === c.id);
|
|
184
|
+
const exported = node?.properties.isExported ? '✓' : '✗';
|
|
185
|
+
const shortPath = node?.properties.filePath?.split('/').slice(-2).join('/') || '';
|
|
186
|
+
console.log(` ${i + 1}. ${node?.properties.name} [exported:${exported}] (${shortPath})`);
|
|
187
|
+
console.log(` score: ${c.score.toFixed(2)} = [${c.reasons.join(' × ')}]`);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return sorted
|
|
191
|
+
.slice(0, 200) // Limit to prevent explosion
|
|
192
|
+
.map(c => c.id);
|
|
193
|
+
};
|
|
194
|
+
// ============================================================================
|
|
195
|
+
// HELPER: Trace from entry point (BFS)
|
|
196
|
+
// ============================================================================
|
|
197
|
+
/**
|
|
198
|
+
* Trace forward from an entry point using BFS.
|
|
199
|
+
* Returns all distinct paths up to maxDepth.
|
|
200
|
+
*/
|
|
201
|
+
const traceFromEntryPoint = (entryId, callsEdges, config) => {
|
|
202
|
+
const traces = [];
|
|
203
|
+
// BFS with path tracking
|
|
204
|
+
// Each queue item: [currentNodeId, pathSoFar]
|
|
205
|
+
const queue = [[entryId, [entryId]]];
|
|
206
|
+
const visited = new Set();
|
|
207
|
+
while (queue.length > 0 && traces.length < config.maxBranching * 3) {
|
|
208
|
+
const [currentId, path] = queue.shift();
|
|
209
|
+
// Get outgoing calls
|
|
210
|
+
const callees = callsEdges.get(currentId) || [];
|
|
211
|
+
if (callees.length === 0) {
|
|
212
|
+
// Terminal node - this is a complete trace
|
|
213
|
+
if (path.length >= config.minSteps) {
|
|
214
|
+
traces.push([...path]);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else if (path.length >= config.maxTraceDepth) {
|
|
218
|
+
// Max depth reached - save what we have
|
|
219
|
+
if (path.length >= config.minSteps) {
|
|
220
|
+
traces.push([...path]);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
// Continue tracing - limit branching
|
|
225
|
+
const limitedCallees = callees.slice(0, config.maxBranching);
|
|
226
|
+
let addedBranch = false;
|
|
227
|
+
for (const calleeId of limitedCallees) {
|
|
228
|
+
// Avoid cycles
|
|
229
|
+
if (!path.includes(calleeId)) {
|
|
230
|
+
queue.push([calleeId, [...path, calleeId]]);
|
|
231
|
+
addedBranch = true;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// If all branches were cycles, save current path as terminal
|
|
235
|
+
if (!addedBranch && path.length >= config.minSteps) {
|
|
236
|
+
traces.push([...path]);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return traces;
|
|
241
|
+
};
|
|
242
|
+
// ============================================================================
|
|
243
|
+
// HELPER: Deduplicate traces
|
|
244
|
+
// ============================================================================
|
|
245
|
+
/**
|
|
246
|
+
* Merge traces that are subsets of other traces.
|
|
247
|
+
* Keep longer traces, remove redundant shorter ones.
|
|
248
|
+
*/
|
|
249
|
+
const deduplicateTraces = (traces) => {
|
|
250
|
+
if (traces.length === 0)
|
|
251
|
+
return [];
|
|
252
|
+
// Sort by length descending
|
|
253
|
+
const sorted = [...traces].sort((a, b) => b.length - a.length);
|
|
254
|
+
const unique = [];
|
|
255
|
+
for (const trace of sorted) {
|
|
256
|
+
// Check if this trace is a subset of any already-added trace
|
|
257
|
+
const traceKey = trace.join('->');
|
|
258
|
+
const isSubset = unique.some(existing => {
|
|
259
|
+
const existingKey = existing.join('->');
|
|
260
|
+
return existingKey.includes(traceKey);
|
|
261
|
+
});
|
|
262
|
+
if (!isSubset) {
|
|
263
|
+
unique.push(trace);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return unique;
|
|
267
|
+
};
|
|
268
|
+
// ============================================================================
|
|
269
|
+
// HELPER: String utilities
|
|
270
|
+
// ============================================================================
|
|
271
|
+
const capitalize = (s) => {
|
|
272
|
+
if (!s)
|
|
273
|
+
return s;
|
|
274
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
275
|
+
};
|
|
276
|
+
const sanitizeId = (s) => {
|
|
277
|
+
return s.replace(/[^a-zA-Z0-9]/g, '_').substring(0, 20).toLowerCase();
|
|
278
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { generateId } from "../../lib/utils.js";
|
|
2
|
+
export const processStructure = (graph, paths) => {
|
|
3
|
+
paths.forEach(path => {
|
|
4
|
+
const parts = path.split('/');
|
|
5
|
+
let currentPath = '';
|
|
6
|
+
let parentId = '';
|
|
7
|
+
parts.forEach((part, index) => {
|
|
8
|
+
const isFile = index === parts.length - 1;
|
|
9
|
+
const label = isFile ? 'File' : 'Folder';
|
|
10
|
+
currentPath = currentPath ? `${currentPath}/${part}` : part;
|
|
11
|
+
const nodeId = generateId(label, currentPath);
|
|
12
|
+
const node = {
|
|
13
|
+
id: nodeId,
|
|
14
|
+
label: label,
|
|
15
|
+
properties: {
|
|
16
|
+
name: part,
|
|
17
|
+
filePath: currentPath
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
graph.addNode(node);
|
|
21
|
+
if (parentId) {
|
|
22
|
+
const relId = generateId('CONTAINS', `${parentId}->${nodeId}`);
|
|
23
|
+
const relationship = {
|
|
24
|
+
id: relId,
|
|
25
|
+
type: 'CONTAINS',
|
|
26
|
+
sourceId: parentId,
|
|
27
|
+
targetId: nodeId,
|
|
28
|
+
confidence: 1.0,
|
|
29
|
+
reason: '',
|
|
30
|
+
};
|
|
31
|
+
graph.addRelationship(relationship);
|
|
32
|
+
}
|
|
33
|
+
parentId = nodeId;
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface SymbolDefinition {
|
|
2
|
+
nodeId: string;
|
|
3
|
+
filePath: string;
|
|
4
|
+
type: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SymbolTable {
|
|
7
|
+
/**
|
|
8
|
+
* Register a new symbol definition
|
|
9
|
+
*/
|
|
10
|
+
add: (filePath: string, name: string, nodeId: string, type: string) => void;
|
|
11
|
+
/**
|
|
12
|
+
* High Confidence: Look for a symbol specifically inside a file
|
|
13
|
+
* Returns the Node ID if found
|
|
14
|
+
*/
|
|
15
|
+
lookupExact: (filePath: string, name: string) => string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Low Confidence: Look for a symbol anywhere in the project
|
|
18
|
+
* Used when imports are missing or for framework magic
|
|
19
|
+
*/
|
|
20
|
+
lookupFuzzy: (name: string) => SymbolDefinition[];
|
|
21
|
+
/**
|
|
22
|
+
* Debugging: See how many symbols are tracked
|
|
23
|
+
*/
|
|
24
|
+
getStats: () => {
|
|
25
|
+
fileCount: number;
|
|
26
|
+
globalSymbolCount: number;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Cleanup memory
|
|
30
|
+
*/
|
|
31
|
+
clear: () => void;
|
|
32
|
+
}
|
|
33
|
+
export declare const createSymbolTable: () => SymbolTable;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export const createSymbolTable = () => {
|
|
2
|
+
// 1. File-Specific Index (The "Good" one)
|
|
3
|
+
// Structure: FilePath -> (SymbolName -> NodeID)
|
|
4
|
+
const fileIndex = new Map();
|
|
5
|
+
// 2. Global Reverse Index (The "Backup")
|
|
6
|
+
// Structure: SymbolName -> [List of Definitions]
|
|
7
|
+
const globalIndex = new Map();
|
|
8
|
+
const add = (filePath, name, nodeId, type) => {
|
|
9
|
+
// A. Add to File Index
|
|
10
|
+
if (!fileIndex.has(filePath)) {
|
|
11
|
+
fileIndex.set(filePath, new Map());
|
|
12
|
+
}
|
|
13
|
+
fileIndex.get(filePath).set(name, nodeId);
|
|
14
|
+
// B. Add to Global Index
|
|
15
|
+
if (!globalIndex.has(name)) {
|
|
16
|
+
globalIndex.set(name, []);
|
|
17
|
+
}
|
|
18
|
+
globalIndex.get(name).push({ nodeId, filePath, type });
|
|
19
|
+
};
|
|
20
|
+
const lookupExact = (filePath, name) => {
|
|
21
|
+
const fileSymbols = fileIndex.get(filePath);
|
|
22
|
+
if (!fileSymbols)
|
|
23
|
+
return undefined;
|
|
24
|
+
return fileSymbols.get(name);
|
|
25
|
+
};
|
|
26
|
+
const lookupFuzzy = (name) => {
|
|
27
|
+
return globalIndex.get(name) || [];
|
|
28
|
+
};
|
|
29
|
+
const getStats = () => ({
|
|
30
|
+
fileCount: fileIndex.size,
|
|
31
|
+
globalSymbolCount: globalIndex.size
|
|
32
|
+
});
|
|
33
|
+
const clear = () => {
|
|
34
|
+
fileIndex.clear();
|
|
35
|
+
globalIndex.clear();
|
|
36
|
+
};
|
|
37
|
+
return { add, lookupExact, lookupFuzzy, getStats, clear };
|
|
38
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
2
|
+
export declare const TYPESCRIPT_QUERIES = "\n(class_declaration\n name: (type_identifier) @name) @definition.class\n\n(interface_declaration\n name: (type_identifier) @name) @definition.interface\n\n(function_declaration\n name: (identifier) @name) @definition.function\n\n(method_definition\n name: (property_identifier) @name) @definition.method\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function))) @definition.function\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function)))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression)))) @definition.function\n\n(import_statement\n source: (string) @import.source) @import\n\n(call_expression\n function: (identifier) @call.name) @call\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @call.name)) @call\n\n; Heritage queries - class extends\n(class_declaration\n name: (type_identifier) @heritage.class\n (class_heritage\n (extends_clause\n value: (identifier) @heritage.extends))) @heritage\n\n; Heritage queries - class implements interface\n(class_declaration\n name: (type_identifier) @heritage.class\n (class_heritage\n (implements_clause\n (type_identifier) @heritage.implements))) @heritage.impl\n";
|
|
3
|
+
export declare const JAVASCRIPT_QUERIES = "\n(class_declaration\n name: (identifier) @name) @definition.class\n\n(function_declaration\n name: (identifier) @name) @definition.function\n\n(method_definition\n name: (property_identifier) @name) @definition.method\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function))) @definition.function\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function)))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression)))) @definition.function\n\n(import_statement\n source: (string) @import.source) @import\n\n(call_expression\n function: (identifier) @call.name) @call\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @call.name)) @call\n\n; Heritage queries - class extends (JavaScript uses different AST than TypeScript)\n; In tree-sitter-javascript, class_heritage directly contains the parent identifier\n(class_declaration\n name: (identifier) @heritage.class\n (class_heritage\n (identifier) @heritage.extends)) @heritage\n";
|
|
4
|
+
export declare const PYTHON_QUERIES = "\n(class_definition\n name: (identifier) @name) @definition.class\n\n(function_definition\n name: (identifier) @name) @definition.function\n\n(import_statement\n name: (dotted_name) @import.source) @import\n\n(import_from_statement\n module_name: (dotted_name) @import.source) @import\n\n(call\n function: (identifier) @call.name) @call\n\n(call\n function: (attribute\n attribute: (identifier) @call.name)) @call\n\n; Heritage queries - Python class inheritance\n(class_definition\n name: (identifier) @heritage.class\n superclasses: (argument_list\n (identifier) @heritage.extends)) @heritage\n";
|
|
5
|
+
export declare const JAVA_QUERIES = "\n; Classes, Interfaces, Enums, Annotations\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(enum_declaration name: (identifier) @name) @definition.enum\n(annotation_type_declaration name: (identifier) @name) @definition.annotation\n\n; Methods & Constructors\n(method_declaration name: (identifier) @name) @definition.method\n(constructor_declaration name: (identifier) @name) @definition.constructor\n\n; Imports - capture any import declaration child as source\n(import_declaration (_) @import.source) @import\n\n; Calls\n(method_invocation name: (identifier) @call.name) @call\n(method_invocation object: (_) name: (identifier) @call.name) @call\n\n; Heritage - extends class\n(class_declaration name: (identifier) @heritage.class\n (superclass (type_identifier) @heritage.extends)) @heritage\n\n; Heritage - implements interfaces\n(class_declaration name: (identifier) @heritage.class\n (super_interfaces (type_list (type_identifier) @heritage.implements))) @heritage.impl\n";
|
|
6
|
+
export declare const C_QUERIES = "\n; Functions\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(declaration declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n\n; Structs, Unions, Enums, Typedefs\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(union_specifier name: (type_identifier) @name) @definition.union\n(enum_specifier name: (type_identifier) @name) @definition.enum\n(type_definition declarator: (type_identifier) @name) @definition.typedef\n\n; Macros\n(preproc_function_def name: (identifier) @name) @definition.macro\n(preproc_def name: (identifier) @name) @definition.macro\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n";
|
|
7
|
+
export declare const GO_QUERIES = "\n; Functions & Methods\n(function_declaration name: (identifier) @name) @definition.function\n(method_declaration name: (field_identifier) @name) @definition.method\n\n; Types\n(type_declaration (type_spec name: (type_identifier) @name type: (struct_type))) @definition.struct\n(type_declaration (type_spec name: (type_identifier) @name type: (interface_type))) @definition.interface\n(type_declaration (type_spec name: (type_identifier) @name)) @definition.type\n\n; Imports\n(import_declaration (import_spec path: (interpreted_string_literal) @import.source)) @import\n(import_declaration (import_spec_list (import_spec path: (interpreted_string_literal) @import.source))) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (selector_expression field: (field_identifier) @call.name)) @call\n";
|
|
8
|
+
export declare const CPP_QUERIES = "\n; Classes, Structs, Namespaces\n(class_specifier name: (type_identifier) @name) @definition.class\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(namespace_definition name: (namespace_identifier) @name) @definition.namespace\n(enum_specifier name: (type_identifier) @name) @definition.enum\n\n; Functions & Methods\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))) @definition.method\n\n; Templates\n(template_declaration (class_specifier name: (type_identifier) @name)) @definition.template\n(template_declaration (function_definition declarator: (function_declarator declarator: (identifier) @name))) @definition.template\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n(call_expression function: (qualified_identifier name: (identifier) @call.name)) @call\n(call_expression function: (template_function name: (identifier) @call.name)) @call\n\n; Heritage\n(class_specifier name: (type_identifier) @heritage.class\n (base_class_clause (type_identifier) @heritage.extends)) @heritage\n(class_specifier name: (type_identifier) @heritage.class\n (base_class_clause (access_specifier) (type_identifier) @heritage.extends)) @heritage\n";
|
|
9
|
+
export declare const CSHARP_QUERIES = "\n; Types\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(struct_declaration name: (identifier) @name) @definition.struct\n(enum_declaration name: (identifier) @name) @definition.enum\n(record_declaration name: (identifier) @name) @definition.record\n(delegate_declaration name: (identifier) @name) @definition.delegate\n\n; Namespaces\n(namespace_declaration name: (identifier) @name) @definition.namespace\n(namespace_declaration name: (qualified_name) @name) @definition.namespace\n\n; Methods & Properties\n(method_declaration name: (identifier) @name) @definition.method\n(local_function_statement name: (identifier) @name) @definition.function\n(constructor_declaration name: (identifier) @name) @definition.constructor\n(property_declaration name: (identifier) @name) @definition.property\n\n; Using\n(using_directive (qualified_name) @import.source) @import\n(using_directive (identifier) @import.source) @import\n\n; Calls\n(invocation_expression function: (identifier) @call.name) @call\n(invocation_expression function: (member_access_expression name: (identifier) @call.name)) @call\n\n; Heritage\n(class_declaration name: (identifier) @heritage.class\n (base_list (simple_base_type (identifier) @heritage.extends))) @heritage\n(class_declaration name: (identifier) @heritage.class\n (base_list (simple_base_type (generic_name (identifier) @heritage.extends)))) @heritage\n";
|
|
10
|
+
export declare const RUST_QUERIES = "\n; Functions & Items\n(function_item name: (identifier) @name) @definition.function\n(struct_item name: (type_identifier) @name) @definition.struct\n(enum_item name: (type_identifier) @name) @definition.enum\n(trait_item name: (type_identifier) @name) @definition.trait\n(impl_item type: (type_identifier) @name) @definition.impl\n(mod_item name: (identifier) @name) @definition.module\n\n; Type aliases, const, static, macros\n(type_item name: (type_identifier) @name) @definition.type\n(const_item name: (identifier) @name) @definition.const\n(static_item name: (identifier) @name) @definition.static\n(macro_definition name: (identifier) @name) @definition.macro\n\n; Use statements\n(use_declaration argument: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n(call_expression function: (scoped_identifier name: (identifier) @call.name)) @call\n(call_expression function: (generic_function function: (identifier) @call.name)) @call\n\n; Heritage (trait implementation)\n(impl_item trait: (type_identifier) @heritage.trait type: (type_identifier) @heritage.class) @heritage\n(impl_item trait: (generic_type type: (type_identifier) @heritage.trait) type: (type_identifier) @heritage.class) @heritage\n";
|
|
11
|
+
export declare const LANGUAGE_QUERIES: Record<SupportedLanguages, string>;
|