UNPKG

socraticode

Version:

SocratiCode — MCP server for local codebase indexing, semantic search, and code dependency graphs. All private, all local via Docker.

125 lines • 4.93 kB
// SPDX-License-Identifier: AGPL-3.0-only // Copyright (C) 2026 Giancarlo Erra - Altaire Limited /** * Per-file incremental updates for the symbol-level call graph. * * Wired into the watcher path so file saves do not corrupt cross-file symbol graphs. * Rejects schema-v1 graphs with fullRebuildRequired = true. * Until complete symbol-set cross-file incremental resolution is supported, * any changed or removed files trigger fullRebuildRequired = true before mutating storage. */ import { SYMBOL_REVERSE_SHARDS, } from "../constants.js"; import { loadSymbolGraphMeta, nameShardKey, reverseShardKeyForCallee, } from "./symbol-graph-store.js"; /** * Incrementally update the persisted symbol graph for a small batch of * changed and removed files. * * Returns `fullRebuildRequired = true` if no meta exists, schemaVersion < 2, * or if changed/removed files require cross-file caller re-resolution. */ export async function updateChangedFilesSymbolGraph(projectId, _projectPath, _fileGraph, changedRelPaths, removedRelPaths) { const meta = await loadSymbolGraphMeta(projectId); if (!meta || (meta.schemaVersion ?? 1) < 2) { return { filesChanged: 0, filesRemoved: 0, symbolsDelta: 0, edgesDelta: 0, fullRebuildRequired: true, }; } // Until incremental resolution uses the complete symbol set and re-resolves // affected callers, return fullRebuildRequired: true for changed and removed files // before mutating storage. if (changedRelPaths.length > 0 || removedRelPaths.length > 0) { return { filesChanged: 0, filesRemoved: 0, symbolsDelta: 0, edgesDelta: 0, fullRebuildRequired: true, }; } return { filesChanged: 0, filesRemoved: 0, symbolsDelta: 0, edgesDelta: 0, fullRebuildRequired: false, }; } // ── Internal helpers ──────────────────────────────────────────────────── export async function applyRemoval(projectId, payload, getNameShard, getReverseShard) { // Remove this file's symbols from the relevant name shards. for (const sym of payload.symbols) { if (sym.name === "<module>") continue; const shard = await getNameShard(nameShardKey(sym.name)); // Use hasOwn — `shard[sym.name]` for "constructor" returns a function. if (!Object.hasOwn(shard, sym.name)) continue; const refs = shard[sym.name]; if (!refs) continue; const filtered = refs.filter((r) => r.file !== payload.file); if (filtered.length === 0) delete shard[sym.name]; else shard[sym.name] = filtered; } // Remove caller entries from reverse shards (keyed by exact calleeSymbolId). for (const edge of payload.outgoingCalls) { for (const calleeId of edge.calleeCandidates) { const bucket = reverseShardKeyForCallee(calleeId); const shard = await getReverseShard(bucket); const arr = shard[calleeId]; if (!arr) continue; const filtered = arr.filter((callerId) => callerId !== edge.callerId); if (filtered.length === 0) delete shard[calleeId]; else shard[calleeId] = filtered; } } void projectId; void SYMBOL_REVERSE_SHARDS; } export async function applyAddition(projectId, payload, getNameShard, getReverseShard) { for (const sym of payload.symbols) { if (sym.name === "<module>") continue; const shard = await getNameShard(nameShardKey(sym.name)); const ref = { file: payload.file, id: sym.id }; const existing = Object.hasOwn(shard, sym.name) ? shard[sym.name] : undefined; if (existing) { if (!existing.some((e) => e.id === ref.id && e.file === ref.file)) { existing.push(ref); } } else { shard[sym.name] = [ref]; } } // Add caller entries to reverse shards (keyed by exact calleeSymbolId). for (const edge of payload.outgoingCalls) { for (const calleeId of edge.calleeCandidates) { const bucket = reverseShardKeyForCallee(calleeId); const shard = await getReverseShard(bucket); const existing = shard[calleeId]; if (existing) { if (!existing.includes(edge.callerId)) existing.push(edge.callerId); } else { shard[calleeId] = [edge.callerId]; } } } void projectId; } export const _internal = { applyRemoval, applyAddition, }; //# sourceMappingURL=symbol-graph-incremental.js.map