import type { TraceResult } from '../types.js'; import { displayEndpointCaption, endpointCaption, } from './endpoint-caption.js'; function mermaidText(value: string): string { return value .replace(/&/g, '&') .replace(/"/g, '"') .replace(/\|/g, '|') .replace(/[\r\n]+/g, ' '); } function edgeLabel(edge: TraceResult['edges'][number]): string { const basis = edge.evidence.selectionBasis; return mermaidText(typeof basis === 'string' ? `${edge.type} [basis=${basis}]` : edge.type); } export function renderMermaid(trace: TraceResult): string { const ids = new Map(); const nodeId = (value: string): string => { const existing = ids.get(value); if (existing) return existing; const id = `n${ids.size}`; ids.set(value, id); return id; }; const lines = ['flowchart TD']; for (const e of trace.edges) lines.push( ` ${nodeId(e.fromNodeId ?? e.from)}["${mermaidText( displayEndpointCaption(endpointCaption( trace, e.from, e.fromNodeId, )), )}"] -->|${edgeLabel(e)}| ${nodeId(e.toNodeId ?? e.to)}["${mermaidText( displayEndpointCaption(endpointCaption(trace, e.to, e.toNodeId)), )}"]`, ); return `${lines.join('\n')}\n`; }