feat(ui): Steps for servers — route roots, server effects, request/decorator triggers, guards for Python/Java/Kotlin/C#/Go/C
- api/route-roots.ts: the symbol a route runs (references-edge handler, exported page component, or the route itself for an inline handler), shared by steps and screens; the bare Steps tab lists an API's endpoints by router file - api/effects.ts: database / response / queue / email / payments / cache / auth / process / network / storage / device / telemetry, matched on the call as written per language family, with model + read/write and the literal status on a response site - graph/branch-guards.ts: callSitesForFile (the whole member chain), memberTypesInTree, decoratorsForFile, request/decorator triggers with the middleware/guard chain; guard + argument rules for Python, Java, Kotlin, C#, Go and C - steps.ts: classify on the chain before trusting a name match, retarget this.x.y() by declared type, skip test doubles after the effect pre-check, project kind on the wire - viewer: kindWord/kindWords per project kind, endpoint chooser, response boxes labelled by status codes - python.ts: FastAPI detected from a monorepo sub-directory; is-test-file: samples/examples package paths are not tests - tests: ui-steps-api-servers, ui-effects, branch-guards-languages; spec §3.13 Servers paragraph, CHANGELOG, plan doc Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01REFyW9hmNrxhwN5wxRoAkC
This commit is contained in:
co-authored by
Claude Fable 5
parent
5e06204deb
commit
950686def4
@@ -14,11 +14,16 @@ import type CodeGraph from '../../index';
|
||||
import type { Language } from '../../types';
|
||||
import {
|
||||
callArgumentsForFile,
|
||||
callSitesForFile,
|
||||
decoratorsForFile,
|
||||
guardLabel,
|
||||
guardsForFile,
|
||||
memberTypesForFile,
|
||||
siteKey,
|
||||
supportsBranchGuards,
|
||||
triggersForFile,
|
||||
type CallSiteText,
|
||||
type DefinitionDecorators,
|
||||
type SiteTrigger,
|
||||
} from '../../graph/branch-guards';
|
||||
import { resolveProjectFile } from '../security';
|
||||
@@ -96,6 +101,12 @@ export interface SiteReader {
|
||||
args(caller: { filePath: string; language: Language }, site: { line?: number; column?: number }): Promise<string | null>;
|
||||
/** What fires the site — the JSX prop, `on*` option or runs-later call it is written under; null when nothing binds it. */
|
||||
trigger(caller: { filePath: string; language: Language }, site: { line?: number; column?: number }): Promise<SiteTrigger | null>;
|
||||
/** The call as written (the whole member chain) and what it passes; null when unreadable. `callee` names the call when a position is shared. */
|
||||
callSite(caller: { filePath: string; language: Language }, site: { line?: number; column?: number; callee?: string }): Promise<CallSiteText | null>;
|
||||
/** The decorators / annotations / attributes on a definition, and on its class; null when unreadable. */
|
||||
decorators(definition: { filePath: string; language: Language; startLine: number }): Promise<DefinitionDecorators | null>;
|
||||
/** The declared types of the members of the class a definition belongs to, by member name; empty when unreadable. */
|
||||
memberTypes(definition: { filePath: string; language: Language; startLine: number }): Promise<Map<string, string>>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,6 +162,27 @@ export function createSiteReader(cg: CodeGraph, projectRoot: string, maxSites =
|
||||
const key = { line: site.line, column: typeof site.column === 'number' ? site.column : null };
|
||||
return (await triggersForFile(file.abs, file.language, [key])).get(siteKey(key)) ?? null;
|
||||
},
|
||||
async callSite(caller, site) {
|
||||
if (!site.line || sites >= maxSites || !supportsBranchGuards(caller.language)) return null;
|
||||
const file = resolve(caller);
|
||||
if (!file) return null;
|
||||
sites++;
|
||||
const key = { line: site.line, column: typeof site.column === 'number' ? site.column : null, ...(site.callee ? { callee: site.callee } : {}) };
|
||||
return (await callSitesForFile(file.abs, file.language, [key])).get(siteKey(key)) ?? null;
|
||||
},
|
||||
async decorators(definition) {
|
||||
// Not counted: one lookup per step, on a tree the walk has parsed anyway.
|
||||
if (!definition.startLine || !supportsBranchGuards(definition.language)) return null;
|
||||
const file = resolve(definition);
|
||||
if (!file) return null;
|
||||
return (await decoratorsForFile(file.abs, file.language, [definition.startLine])).get(definition.startLine) ?? null;
|
||||
},
|
||||
async memberTypes(definition) {
|
||||
if (!definition.startLine || !supportsBranchGuards(definition.language)) return new Map();
|
||||
const file = resolve(definition);
|
||||
if (!file) return new Map();
|
||||
return memberTypesForFile(file.abs, file.language, definition.startLine);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user