MCPcopy
hub / github.com/giancarloerra/SocratiCode / persistSymbolGraph

Function persistSymbolGraph

src/services/code-graph.ts:250–356  ·  view source on GitHub ↗

Persist the symbol graph: per-file payloads + sharded indices + meta.

(
  projectId: string,
  resolvedPath: string,
  symbolsByFile: Map<string, SymbolNode[]>,
  outgoingCallsByFile: Map<string, SymbolEdge[]>,
)

Source from the content-addressed store, hash-verified

248
249/** Persist the symbol graph: per-file payloads + sharded indices + meta. */
250async function persistSymbolGraph(
251 projectId: string,
252 resolvedPath: string,
253 symbolsByFile: Map<string, SymbolNode[]>,
254 outgoingCallsByFile: Map<string, SymbolEdge[]>,
255): Promise<void> {
256 await ensureSymbolGraphCollections(projectId);
257
258 // Build per-file payloads (need source bytes for contentHash).
259 const payloads: SymbolGraphFilePayload[] = [];
260 let totalSymbols = 0;
261 let totalEdges = 0;
262 for (const [relPath, symbols] of symbolsByFile.entries()) {
263 const outgoingCalls = outgoingCallsByFile.get(relPath) ?? [];
264 let language = "plaintext";
265 const firstNonModule = symbols.find((s) => s.name !== "<module>");
266 if (firstNonModule) language = firstNonModule.language;
267 else language = symbols[0]?.language ?? language;
268
269 let contentHash = "";
270 try {
271 const src = await fs.readFile(path.join(resolvedPath, relPath), "utf-8");
272 contentHash = contentHashOf(src);
273 } catch {
274 // ignore
275 }
276 payloads.push({
277 file: relPath, language, contentHash, symbols, outgoingCalls,
278 });
279 totalSymbols += symbols.filter((s) => s.name !== "<module>").length;
280 totalEdges += outgoingCalls.length;
281 }
282
283 // Build sharded indices
284 const nameShards = new Map<string, Record<string, SymbolRef[]>>();
285 for (const key of allNameShardKeys()) nameShards.set(key, {});
286 for (const [file, symbols] of symbolsByFile.entries()) {
287 for (const sym of symbols) {
288 if (sym.name === "<module>") continue;
289 const shardKey = nameShardKey(sym.name);
290 const shard = nameShards.get(shardKey);
291 if (!shard) continue;
292 const ref: SymbolRef = { file, id: sym.id };
293 // Use hasOwn — `shard[sym.name]` would return Object.prototype.constructor
294 // (a function) for symbol names like "constructor" / "toString" / "hasOwnProperty".
295 const existing = Object.hasOwn(shard, sym.name) ? shard[sym.name] : undefined;
296 if (existing) existing.push(ref);
297 else shard[sym.name] = [ref];
298 }
299 }
300
301 const reverseShards = new Map<number, Record<string, string[]>>();
302 for (const [callerFile, edges] of outgoingCallsByFile.entries()) {
303 for (const e of edges) {
304 for (const calleeId of e.calleeCandidates) {
305 const calleeFile = calleeId.split("::")[0];
306 if (!calleeFile || calleeFile === callerFile) continue;
307 const bucket = reverseShardKey(calleeFile);

Callers 1

doRebuildGraphFunction · 0.85

Calls 14

contentHashOfFunction · 0.85
allNameShardKeysFunction · 0.85
nameShardKeyFunction · 0.85
reverseShardKeyFunction · 0.85
saveFilePayloadsFunction · 0.85
saveNameShardFunction · 0.85
saveReverseShardFunction · 0.85
computeUnresolvedPctFunction · 0.85
saveSymbolGraphMetaFunction · 0.85
setSymbolGraphCacheFunction · 0.85
getMethod · 0.80

Tested by

no test coverage detected