MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / buildMembers

Function buildMembers

src/ui-server/api/node.ts:240–293  ·  view source on GitHub ↗

* The focal symbol's members, in source order, one level of nesting deep. * * A file's outline is file → class → method, so direct children alone would * show a class and nothing inside it. The grandchildren come from ONE batched * `getOutgoingEdgesFrom` over the container children, never a quer

(
  cg: CodeGraph,
  focal: Node,
  containsOut: readonly Edge[],
  endpoints: Map<string, Node>,
  overrides?: Map<string, WireOverride>
)

Source from the content-addressed store, hash-verified

238 * `getOutgoingEdgesFrom` over the container children, never a query per child.
239 */
240function buildMembers(
241 cg: CodeGraph,
242 focal: Node,
243 containsOut: readonly Edge[],
244 endpoints: Map<string, Node>,
245 overrides?: Map<string, WireOverride>
246): { items: WireMember[]; total: number } {
247 const direct: Array<{ node: Node; parentId: string; depth: number }> = [];
248 for (const edge of containsOut) {
249 const child = endpoints.get(edge.target);
250 if (child) direct.push({ node: child, parentId: focal.id, depth: 1 });
251 }
252
253 const containerIds = direct
254 .filter((entry) => CONTAINER_KINDS.has(entry.node.kind))
255 .map((entry) => entry.node.id);
256
257 const nested: Array<{ node: Node; parentId: string; depth: number }> = [];
258 if (containerIds.length > 0) {
259 const grandEdges = cg.getOutgoingEdgesFrom(containerIds, ['contains']);
260 const grandNodes = cg.getNodesByIds(grandEdges.map((e) => e.target));
261 for (const edge of grandEdges) {
262 const child = grandNodes.get(edge.target);
263 if (child) nested.push({ node: child, parentId: edge.source, depth: 2 });
264 }
265 }
266
267 const all = [...direct, ...nested].sort(
268 (a, b) => a.node.startLine - b.node.startLine || a.node.name.localeCompare(b.node.name)
269 );
270 const shown = all.slice(0, MAX_OUTLINE_NODES);
271
272 // Two queries for the whole outline, not two per row: a file with 400
273 // symbols would otherwise be 800 lookups behind one screen.
274 const memberIds = shown.map((entry) => entry.node.id);
275 const fanIn = cg.getFanIn(memberIds);
276 const fanOut = cg.getFanOut(memberIds);
277
278 return {
279 items: shown.map((entry) => {
280 const member: WireMember = {
281 ...toNodeRef(entry.node),
282 parentId: entry.parentId,
283 depth: entry.depth,
284 fanIn: fanIn.get(entry.node.id) ?? 0,
285 fanOut: fanOut.get(entry.node.id) ?? 0,
286 };
287 const override = overrides?.get(entry.node.id);
288 if (override) member.overrides = override;
289 return member;
290 }),
291 total: all.length,
292 };
293}
294
295// =============================================================================
296// Test coverage

Callers 1

buildNodeFunction · 0.85

Calls 9

toNodeRefFunction · 0.90
pushMethod · 0.80
mapMethod · 0.80
hasMethod · 0.80
getFanInMethod · 0.80
getFanOutMethod · 0.80
getMethod · 0.65
getOutgoingEdgesFromMethod · 0.45
getNodesByIdsMethod · 0.45

Tested by

no test coverage detected