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

Function buildSteps

src/ui-server/api/steps.ts:397–1487  ·  view source on GitHub ↗
(cg: CodeGraph, projectRoot: string, query: URLSearchParams)

Source from the content-addressed store, hash-verified

395}
396
397export async function buildSteps(cg: CodeGraph, projectRoot: string, query: URLSearchParams): Promise<WireStepsPayload> {
398 const started = Date.now();
399 const depthCap = intParam(query, 'depth', { min: 1, max: MAX_DEPTH, default: DEFAULT_DEPTH });
400 const limit = intParam(query, 'limit', { min: 20, max: MAX_LIMIT, default: DEFAULT_LIMIT });
401 const through = query.get('through') === '1';
402 const stats = cg.getStats();
403 const index = { lastIndexedAt: cg.getLastIndexedAt() ?? null, edges: stats.edgeCount, files: stats.fileCount };
404
405 const { anchor, ambiguous } = resolveAnchor(cg, query);
406
407 // Route → where its code starts: the handler a resolver named, the page a
408 // screen file exports, or the route itself standing in for an inline
409 // handler (`route-roots.ts`) — and what kind of project this is, for the
410 // words the viewer uses.
411 const routes = cg.getNodesByKind('route');
412 const roots = routeRoots(cg, routes);
413 const project = projectKind(routes, stats.edgesByKind?.navigates ?? 0);
414
415 const reader = createSiteReader(cg, projectRoot, MAX_WHEN_SITES);
416 const calls = createSiteReader(cg, projectRoot, MAX_CALL_SITES);
417 /** The conditions a site runs under, structured — one read, joined where a string is wanted. */
418 const guardsAt = (caller: Node, site: { line?: number; column?: number }) => reader.guards(caller, site);
419 /** The loops a site is written inside — a run of calls that happens once per item. */
420 const loopsAt = (caller: Node, site: { line?: number; column?: number }) => reader.loops(caller, site);
421 const argsAt = (caller: Node, site: { line?: number; column?: number }) => reader.args(caller, site);
422 const withArgs = async (site: WireStepSite, caller: Node, at: { line?: number; column?: number }): Promise<WireStepSite> => {
423 const args = await argsAt(caller, at);
424 return args === null ? site : { ...site, args };
425 };
426 /** The call as written at a site, and what it passes — one read for both. */
427 const callAt = (caller: Node, site: { line?: number; column?: number; callee?: string }) => calls.callSite(caller, site);
428 /** A hop's position with its call's span and enclosing call, read from the tree; the bare position when unreadable. */
429 const hopAt = async (caller: Node, at: { line?: number; column?: number }, callee?: string): Promise<HopSite> => {
430 const line = at.line ?? caller.startLine;
431 const column = at.column ?? 0;
432 const read = at.line ? await callAt(caller, { ...at, ...(callee ? { callee } : {}) }) : null;
433 // The read must be THIS call. An inline handler's edges carry the ROUTE's
434 // line (`router.post('/users/login', async (req, res) => {`), where the
435 // only call is the registration itself — and taking its span would make
436 // every call in the handler read as written inside it, and so as running
437 // first. A miss is a bare position: no span to nest by, no `within`.
438 const last = (n: string) => n.replace(/\([^()]*\)/g, '').split(/[.:]/).pop() ?? n;
439 const usable = read !== null && (!callee || last(read.callee) === last(callee));
440 if (!usable) return { file: caller.filePath, line, column, end: { line, column }, within: null };
441 return {
442 file: caller.filePath,
443 line: read.span?.start.line ?? line,
444 column: read.span?.start.column ?? column,
445 end: read.span?.end ?? { line, column },
446 within: read.within ?? null,
447 };
448 };
449 const pointHop = (caller: Node, at: { line?: number; column?: number }): HopSite => {
450 const line = at.line ?? caller.startLine;
451 const column = at.column ?? 0;
452 return { file: caller.filePath, line, column, end: { line, column }, within: null };
453 };
454

Callers 7

handlerFunction · 0.90
nextjs.test.tsFile · 0.90

Calls 15

intParamFunction · 0.90
routeRootsFunction · 0.90
createSiteReaderFunction · 0.90
looksLikeComponentFunction · 0.90
isTestPathFunction · 0.90
guardLabelFunction · 0.90
buildProgramFunction · 0.90
toNodeRefFunction · 0.90
resolveAnchorFunction · 0.85
projectKindFunction · 0.85
stepForFunction · 0.85
requestTriggerFunction · 0.85

Tested by

no test coverage detected