All files / src/domain graph-model.ts

86.27% Statements 44/51
75% Branches 12/16
81.81% Functions 9/11
86.27% Lines 44/51

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 521x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x           1x     1x 1x  
export type GraphNode = {
  id: string
  label: string
  version?: string
  sprint?: string | null
  status?: string
  /** Import graph: canonical language key (typescript, python, …). */
  fileType?: string
  /** Import graph: resolved fill color for canvas. */
  color?: string
  meta?: Record<string, string>
}
 
export type GraphEdge = {
  from: string
  to: string
}
 
export type GraphModel = {
  nodes: GraphNode[]
  edges: GraphEdge[]
}
 
/** Escape Meridian node ids for Mermaid (US-0162 → US_0162). */
export function mermaidNodeId(id: string): string {
  return id.replace(/[^A-Za-z0-9_]/g, "_")
}
 
export function escapeMermaidLabel(text: string): string {
  return text.replace(/"/g, "'").replace(/\n/g, " ").slice(0, 80)
}
 
export function toMermaidFlowchart(model: GraphModel, direction: "LR" | "TD" = "LR"): string {
  const lines = [`flowchart ${direction}`]
  const nodeIds = new Set(model.nodes.map((n) => n.id))
  for (const node of model.nodes) {
    const mid = mermaidNodeId(node.id)
    const label = escapeMermaidLabel(`${node.id} ${node.label}`.trim())
    lines.push(`  ${mid}["${label}"]`)
  }
  for (const edge of model.edges) {
    if (!nodeIds.has(edge.from) || !nodeIds.has(edge.to)) {
      continue
    }
    lines.push(`  ${mermaidNodeId(edge.from)} --> ${mermaidNodeId(edge.to)}`)
  }
  if (model.nodes.length === 0) {
    lines.push('  empty["No nodes in filter"]')
  }
  return lines.join("\n")
}