flowchart-sequence-designer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/core/model.ts","../src/core/ids.ts","../src/exporters/mermaid.ts","../src/exporters/plantuml.ts","../src/exporters/json.ts","../src/exporters/svg.ts","../src/core/flowchart.ts","../src/core/sequence.ts","../src/importers/mermaid.ts","../src/importers/json.ts"],"sourcesContent":["/**\n * Headless entry point. Builders, the underlying `Model`, and every\n * exporter/importer are exported here. The editor React components live in\n * the `/ui` subpath export — `import { DiagramEditor } from\n * 'flowchart-sequence-designer/ui'` — so server-side or CLI consumers can\n * pull in this entry without dragging React along.\n */\n\n// Builders\nexport { flowchart, FlowchartBuilder } from './core/flowchart.js';\nexport { sequence, SequenceBuilder } from './core/sequence.js';\n\n// Model\nexport { Model } from './core/model.js';\n\n// Exporters\nexport { toMermaid } from './exporters/mermaid.js';\nexport { toPlantUML } from './exporters/plantuml.js';\nexport { toJSON } from './exporters/json.js';\nexport { toSVG, toPNG } from './exporters/svg.js';\n\n// Importers\nexport { fromMermaid } from './importers/mermaid.js';\nexport { fromJSON } from './importers/json.js';\n\n// Types\nexport type {\n DiagramType,\n DiagramVariant,\n DiagramModel,\n DiagramNode,\n DiagramEdge,\n DiagramEdge as Edge,\n DiagramNode as Node,\n NodeShape,\n ExportFormat,\n SequenceMessage,\n} from './core/types.js';\n","import type { DiagramModel, DiagramNode, DiagramEdge, DiagramType, DiagramVariant, SequenceMessage, ValidationError } from './types.js';\n\n/**\n * Mutable builder around a `DiagramModel`. Every public mutator returns\n * `this` so callers can chain (`new Model('flowchart').addNode(...).addEdge(...)`).\n * Call `.toJSON()` to extract a deep-cloned plain model suitable for\n * serialization or for handing to the editor components.\n *\n * All add/update operations validate immediately and throw on collisions or\n * dangling references. For non-throwing, batch-style structural checks call\n * `.validate()` instead.\n */\nexport class Model {\n private data: DiagramModel;\n\n /**\n * Create an empty model.\n *\n * @param type Top-level kind — `flowchart` or `sequence`.\n * @param title Optional human-readable title.\n * @param variant Optional UI variant (flowchart models only).\n */\n constructor(type: DiagramType, title?: string, variant?: DiagramVariant) {\n this.data = { type, ...(variant ? { variant } : {}), title, nodes: [], edges: [], actors: [], messages: [] };\n }\n\n /**\n * Rehydrate a `Model` from a previously serialized `DiagramModel`. The\n * incoming data is deep-cloned, so future mutations on the returned `Model`\n * do not affect the caller's object.\n */\n static fromData(data: DiagramModel): Model {\n const m = new Model(data.type, data.title, data.variant);\n m.data = structuredClone(data);\n return m;\n }\n\n /** Set the UI variant. No-op semantics for sequence models. */\n setVariant(variant: DiagramVariant): this {\n this.data.variant = variant;\n return this;\n }\n\n /**\n * Append a node. Throws if a node with the same id already exists. The\n * input is shallow-cloned, so later mutations of the caller's object do\n * not leak in.\n */\n addNode(node: DiagramNode): this {\n if (this.data.nodes.find(n => n.id === node.id)) {\n throw new Error(`Node with id \"${node.id}\" already exists`);\n }\n this.data.nodes.push({ ...node });\n return this;\n }\n\n /**\n * Patch an existing node in place. Throws if the id is not found. The id\n * field itself cannot be patched — to rename, remove + re-add.\n */\n updateNode(id: string, patch: Partial<Omit<DiagramNode, 'id'>>): this {\n const node = this.data.nodes.find(n => n.id === id);\n if (!node) throw new Error(`Node \"${id}\" not found`);\n Object.assign(node, patch);\n return this;\n }\n\n /**\n * Remove a node and every edge that referenced it as `from` or `to`. Safe\n * to call on a missing id (no-op).\n */\n removeNode(id: string): this {\n this.data.nodes = this.data.nodes.filter(n => n.id !== id);\n this.data.edges = this.data.edges.filter(e => e.from !== id && e.to !== id);\n return this;\n }\n\n /**\n * Append an edge. Throws on duplicate id or if either endpoint references\n * an unknown node — the model never holds dangling edges from this entry\n * point. (Importers can still construct dangling edges; call `validate()`\n * to detect them.)\n */\n addEdge(edge: DiagramEdge): this {\n if (this.data.edges.find(e => e.id === edge.id)) {\n throw new Error(`Edge with id \"${edge.id}\" already exists`);\n }\n if (!this.data.nodes.find(n => n.id === edge.from)) {\n throw new Error(`Edge \"${edge.id}\" references unknown source node \"${edge.from}\"`);\n }\n if (!this.data.nodes.find(n => n.id === edge.to)) {\n throw new Error(`Edge \"${edge.id}\" references unknown target node \"${edge.to}\"`);\n }\n this.data.edges.push({ ...edge });\n return this;\n }\n\n /**\n * Surface structural problems without throwing. Returns an array of\n * `ValidationError`s; empty array means the model is well-formed. Used by\n * the editor's status banner and by external tooling.\n */\n validate(): ValidationError[] {\n const errors: ValidationError[] = [];\n const nodeIds = new Set<string>();\n for (const n of this.data.nodes) {\n if (nodeIds.has(n.id)) errors.push({ kind: 'duplicate-node-id', id: n.id, message: `Duplicate node id \"${n.id}\"` });\n nodeIds.add(n.id);\n }\n const edgeIds = new Set<string>();\n for (const e of this.data.edges) {\n if (edgeIds.has(e.id)) errors.push({ kind: 'duplicate-edge-id', id: e.id, message: `Duplicate edge id \"${e.id}\"` });\n edgeIds.add(e.id);\n if (!nodeIds.has(e.from)) errors.push({ kind: 'dangling-from', id: e.id, message: `Edge \"${e.id}\" references unknown source node \"${e.from}\"` });\n if (!nodeIds.has(e.to)) errors.push({ kind: 'dangling-to', id: e.id, message: `Edge \"${e.id}\" references unknown target node \"${e.to}\"` });\n }\n return errors;\n }\n\n /** Remove an edge by id. Safe to call on a missing id (no-op). */\n removeEdge(id: string): this {\n this.data.edges = this.data.edges.filter(e => e.id !== id);\n return this;\n }\n\n /** Append a sequence actor. Duplicate names are silently ignored. */\n addActor(name: string): this {\n if (!this.data.actors!.includes(name)) {\n this.data.actors!.push(name);\n }\n return this;\n }\n\n /**\n * Append a sequence message. The actors referenced by `from`/`to` are not\n * validated here — callers are expected to register them via `addActor()`\n * first.\n */\n addMessage(message: SequenceMessage): this {\n this.data.messages!.push({ ...message });\n return this;\n }\n\n /**\n * Return a deep-cloned plain `DiagramModel`. Safe to mutate by the caller;\n * mutations do not flow back into this `Model`.\n */\n toJSON(): DiagramModel {\n return structuredClone(this.data);\n }\n}\n","/**\n * Mint the next available ID for a given prefix by scanning the existing\n * entities in a model.\n *\n * Avoids the classic collision pitfall of a module-level counter starting at\n * zero: if the model already contains `e1..e6` (e.g. from a preset or an\n * imported diagram), a counter that started at zero would produce a duplicate\n * `e1` on first use. By deriving from the model itself, generated IDs are\n * collision-proof against presets, imports, and concurrent editor instances.\n *\n * @example\n * nextId('node', model.nodes) // → 'node7' if model has node1..node6\n * nextId('e', model.edges) // → 'e1' if model has no edges yet\n * nextId('m', model.messages) // → 'm5' if model has m1..m4\n */\n/**\n * Returns a stateful id generator seeded from the current model. Use this\n * when a single operation needs to mint several IDs in succession (e.g.\n * duplicate or paste) — calling `nextId()` repeatedly against the same\n * snapshot would produce duplicates because the snapshot doesn't reflect\n * the freshly minted IDs.\n *\n * @example\n * const newNodeId = makeIdSource('node', model.nodes);\n * const a = newNodeId(); // → 'node7'\n * const b = newNodeId(); // → 'node8'\n */\nexport function makeIdSource(prefix: string, existing: Iterable<{ id: string }>): () => string {\n const first = nextId(prefix, existing);\n let counter = parseInt(first.slice(prefix.length), 10);\n return () => `${prefix}${counter++}`;\n}\n\nexport function nextId(prefix: string, existing: Iterable<{ id: string }>): string {\n const escaped = prefix.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp(`^${escaped}(\\\\d+)$`);\n let max = 0;\n for (const item of existing) {\n const match = re.exec(item.id);\n if (match) {\n const n = parseInt(match[1], 10);\n if (n > max) max = n;\n }\n }\n return `${prefix}${max + 1}`;\n}\n","import type { DiagramModel, DiagramNode, DiagramEdge, SequenceMessage } from '../core/types.js';\n\nconst SHAPE_OPEN: Record<string, string> = {\n rectangle: '[',\n diamond: '{',\n circle: '((',\n parallelogram: '[/',\n};\nconst SHAPE_CLOSE: Record<string, string> = {\n rectangle: ']',\n diamond: '}',\n circle: '))',\n parallelogram: '/]',\n};\n\nfunction formatNode(node: DiagramNode): string {\n const shape = node.shape ?? 'rectangle';\n const open = SHAPE_OPEN[shape] ?? '[';\n const close = SHAPE_CLOSE[shape] ?? ']';\n return ` ${node.id}${open}\"${node.label}\"${close}`;\n}\n\nfunction edgeArrow(edge: DiagramEdge): string {\n const style = edge.style ?? 'solid';\n const arrowhead = edge.arrowhead ?? 'arrow';\n // Mermaid flowcharts only have solid and dashed; dotted collapses to dashed.\n if (style === 'dashed' || style === 'dotted') return arrowhead === 'none' ? '-.-' : '-.->';\n return arrowhead === 'none' ? '---' : '-->';\n}\n\nfunction formatEdge(edge: DiagramEdge): string {\n const arrow = edgeArrow(edge);\n return edge.label\n ? ` ${edge.from} ${arrow}|\"${edge.label}\"| ${edge.to}`\n : ` ${edge.from} ${arrow} ${edge.to}`;\n}\n\nfunction exportFlowchart(model: DiagramModel): string {\n const lines: string[] = ['graph TD'];\n if (model.title) lines.unshift(`---\\ntitle: ${model.title}\\n---`);\n for (const node of model.nodes) lines.push(formatNode(node));\n for (const edge of model.edges) lines.push(formatEdge(edge));\n return lines.join('\\n');\n}\n\nfunction msgArrow(msg: SequenceMessage): string {\n return msg.style === 'dashed' ? '-->>' : '->>';\n}\n\nfunction exportSequence(model: DiagramModel): string {\n const lines: string[] = ['sequenceDiagram'];\n if (model.title) lines.unshift(`---\\ntitle: ${model.title}\\n---`);\n for (const actor of (model.actors ?? [])) lines.push(` participant ${actor}`);\n for (const msg of (model.messages ?? [])) {\n lines.push(` ${msg.from}${msgArrow(msg)}${msg.to}: ${msg.label}`);\n }\n return lines.join('\\n');\n}\n\n/**\n * Serialize a `DiagramModel` to Mermaid source. Dispatches between\n * `graph TD` (flowchart) and `sequenceDiagram` based on `model.type`.\n *\n * **Round-trip notes (flowchart):**\n * - Node shapes `rectangle`, `diamond`, `circle`, `parallelogram` map to\n * `[ ]`, `{ }`, `(( ))`, `[/ /]` respectively.\n * - Edge style `solid` → `-->`, `dashed` and `dotted` → `-.->` (Mermaid\n * collapses dotted to dashed). `arrowhead: 'none'` strips the head.\n * - `waypoint`, `metadata`, and `variant` are **dropped** — Mermaid has no\n * way to encode routing or arbitrary metadata.\n *\n * **Round-trip notes (sequence):**\n * - Message style `solid` → `->>`, `dashed` → `-->>`.\n */\nexport function toMermaid(model: DiagramModel): string {\n return model.type === 'sequence' ? exportSequence(model) : exportFlowchart(model);\n}\n","import type { DiagramModel, DiagramNode, DiagramEdge, SequenceMessage } from '../core/types.js';\n\nfunction nodeShape(node: DiagramNode): [string, string] {\n switch (node.shape) {\n case 'diamond': return ['<>', '<>'];\n case 'circle': return ['(', ')'];\n case 'parallelogram': return ['/', '/'];\n default: return ['[', ']'];\n }\n}\n\nfunction exportFlowchart(model: DiagramModel): string {\n const lines: string[] = ['@startuml'];\n if (model.title) lines.push(`title ${model.title}`);\n lines.push('');\n\n for (const node of model.nodes) {\n const [open, close] = nodeShape(node);\n lines.push(`state \"${node.label}\" as ${node.id} ${open}${close}`);\n }\n lines.push('');\n\n for (const edge of model.edges) {\n const arrow = edge.style === 'dashed' ? '-[dashed]->'\n : edge.style === 'dotted' ? '-[dotted]->'\n : '-->';\n const label = edge.label ? ` : ${edge.label}` : '';\n lines.push(`${edge.from} ${arrow} ${edge.to}${label}`);\n }\n\n lines.push('@enduml');\n return lines.join('\\n');\n}\n\nfunction msgArrow(msg: SequenceMessage): string {\n return msg.style === 'dashed' ? '-->' : '->';\n}\n\nfunction exportSequence(model: DiagramModel): string {\n const lines: string[] = ['@startuml'];\n if (model.title) lines.push(`title ${model.title}`);\n lines.push('');\n\n for (const actor of (model.actors ?? [])) {\n lines.push(`participant ${actor}`);\n }\n lines.push('');\n\n for (const msg of (model.messages ?? [])) {\n lines.push(`${msg.from} ${msgArrow(msg)} ${msg.to} : ${msg.label}`);\n }\n\n lines.push('@enduml');\n return lines.join('\\n');\n}\n\n/**\n * Serialize a `DiagramModel` to PlantUML source. Dispatches between the\n * state-diagram form (flowchart) and the sequence-diagram form based on\n * `model.type`.\n *\n * **Round-trip notes (flowchart):**\n * - Edge style maps `solid` → `-->`, `dashed` → `-[dashed]->`,\n * `dotted` → `-[dotted]->`.\n * - Node shapes are emitted via the `state \"..\" as id < >` syntax; some\n * shape information is lossy (PlantUML state diagrams don't distinguish\n * every shape this package supports).\n * - `waypoint`, `metadata`, and `variant` are **dropped**.\n *\n * **Round-trip notes (sequence):**\n * - Actor order is preserved; message style `solid` → `->`, `dashed` → `-->`.\n */\nexport function toPlantUML(model: DiagramModel): string {\n return model.type === 'sequence' ? exportSequence(model) : exportFlowchart(model);\n}\n","import type { DiagramModel } from '../core/types.js';\n\n/**\n * Serialize a `DiagramModel` to pretty-printed JSON. This is the canonical\n * round-trip format: every field — including `variant`, `waypoint`,\n * `metadata.group`, and `metadata.answers` — survives a round trip through\n * `toJSON` + `fromJSON` unchanged.\n */\nexport function toJSON(model: DiagramModel): string {\n return JSON.stringify(model, null, 2);\n}\n","import type { DiagramModel, DiagramNode, DiagramEdge } from '../core/types.js';\n\n// Layout constants — kept in sync with src/ui/DiagramEditor.tsx\nconst NODE_H = 48;\nconst Q_BASE_H = 68;\nconst Q_ANS_ROW_H = 80;\nconst Q_CARD_PAD = 8;\nconst MIN_NODE_W = 120;\nconst MAX_NODE_W = 320;\nconst MIN_Q_W = 220;\nconst PADDING = 48;\nconst H_GAP = 80;\nconst V_GAP = 96;\n\nfunction estimateTextW(text: string, pxPerChar = 7.5): number {\n return text.length * pxPerChar;\n}\n\nfunction nodeWidth(label: string): number {\n return Math.min(MAX_NODE_W, Math.max(MIN_NODE_W, Math.ceil(estimateTextW(label) + 48)));\n}\n\nfunction answerCardW(ans: string): number {\n return Math.max(86, Math.ceil(Math.max(estimateTextW(ans, 7.5) + 20, 56) + 32));\n}\n\nfunction questionNodeW(node: DiagramNode): number {\n const answers = (node.metadata?.answers as string[] | undefined) ?? [];\n const headerW = estimateTextW(node.label, 8) + 80;\n if (answers.length === 0) return Math.max(MIN_Q_W, Math.ceil(headerW));\n const cardsW = answers.reduce((s, a) => s + answerCardW(a), 0)\n + (answers.length - 1) * Q_CARD_PAD + 2 * Q_CARD_PAD;\n return Math.max(MIN_Q_W, Math.ceil(Math.max(headerW, cardsW)));\n}\n\nfunction questionNodeH(answers: string[]): number {\n return Q_BASE_H + (answers.length === 0 ? 48 : Q_ANS_ROW_H);\n}\n\nfunction bezierPath(x1: number, y1: number, x2: number, y2: number): string {\n const dy = y2 - y1;\n const dyAbs = Math.abs(dy);\n const dxAbs = Math.abs(x2 - x1);\n const base = dy > 0 ? dyAbs * 0.55 : Math.max(90, dyAbs * 0.5 + dxAbs * 0.28);\n const curve = Math.max(36, Math.min(220, base));\n return `M ${x1} ${y1} C ${x1} ${y1 + curve}, ${x2} ${y2 - curve}, ${x2} ${y2}`;\n}\n\ninterface LayoutBox { x: number; y: number; w: number; h: number }\n\nfunction isQuestion(node: DiagramNode, variant: DiagramModel['variant']): boolean {\n return variant === 'question' && !!node.metadata?.answers;\n}\n\n/** Honor x/y on nodes if present; otherwise BFS-layer fallback. */\nfunction computeLayout(model: DiagramModel): Map<string, LayoutBox> {\n const boxes = new Map<string, LayoutBox>();\n const sized = model.nodes.map(n => {\n const w = isQuestion(n, model.variant) ? questionNodeW(n) : nodeWidth(n.label);\n const h = isQuestion(n, model.variant)\n ? questionNodeH((n.metadata?.answers as string[] | undefined) ?? [])\n : NODE_H;\n return { node: n, w, h };\n });\n\n const allPositioned = sized.every(s => typeof s.node.x === 'number' && typeof s.node.y === 'number');\n if (allPositioned) {\n for (const s of sized) {\n boxes.set(s.node.id, { x: s.node.x as number, y: s.node.y as number, w: s.w, h: s.h });\n }\n return boxes;\n }\n\n // BFS-layer fallback for un-positioned graphs (e.g. fresh imports).\n const inDeg = new Map(model.nodes.map(n => [n.id, 0]));\n for (const e of model.edges) inDeg.set(e.to, (inDeg.get(e.to) ?? 0) + 1);\n\n const layers = new Map<string, number>();\n const queue = model.nodes.filter(n => (inDeg.get(n.id) ?? 0) === 0).map(n => n.id);\n for (const id of queue) layers.set(id, 0);\n let head = 0;\n while (head < queue.length) {\n const cur = queue[head++];\n const layer = layers.get(cur) ?? 0;\n for (const e of model.edges) {\n if (e.from === cur) {\n const next = layers.get(e.to) ?? -1;\n if (next < layer + 1) {\n layers.set(e.to, layer + 1);\n queue.push(e.to);\n }\n }\n }\n }\n model.nodes.forEach(n => { if (!layers.has(n.id)) layers.set(n.id, 0); });\n\n const byLayer = new Map<number, typeof sized>();\n for (const s of sized) {\n const layer = layers.get(s.node.id) ?? 0;\n if (!byLayer.has(layer)) byLayer.set(layer, []);\n byLayer.get(layer)!.push(s);\n }\n\n let y = PADDING;\n for (const layer of [...byLayer.keys()].sort((a, b) => a - b)) {\n const row = byLayer.get(layer)!;\n let x = PADDING;\n let maxH = 0;\n for (const s of row) {\n boxes.set(s.node.id, { x, y, w: s.w, h: s.h });\n x += s.w + H_GAP;\n maxH = Math.max(maxH, s.h);\n }\n y += maxH + V_GAP;\n }\n return boxes;\n}\n\nfunction escapeXML(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n}\n\n// Match canvas: indigo/slate palette, light theme by default.\nconst COLORS = {\n bg: '#fafbfc',\n dot: '#dbe3ee',\n nodeFill: '#ffffff',\n nodeStroke: '#cbd5e1',\n edge: '#94a3b8',\n text: '#1e293b',\n textSub: '#94a3b8',\n amber: '#d97706',\n amberSoft: '#fef9ee',\n amberLine: '#fde68a',\n amberCardBg: '#fffdf7',\n};\n\nfunction renderStandardNode(node: DiagramNode, box: LayoutBox): string {\n const cx = box.x + box.w / 2;\n const cy = box.y + box.h / 2;\n const shape = node.shape ?? 'rectangle';\n const label = `<text x=\"${cx}\" y=\"${cy + 4.5}\" text-anchor=\"middle\" font-family=\"ui-sans-serif,system-ui,-apple-system,sans-serif\" font-size=\"13\" font-weight=\"500\" fill=\"${COLORS.text}\">${escapeXML(node.label)}</text>`;\n\n let shapeEl = '';\n if (shape === 'diamond') {\n const pts = `${cx},${box.y} ${box.x + box.w},${cy} ${cx},${box.y + box.h} ${box.x},${cy}`;\n shapeEl = `<polygon points=\"${pts}\" fill=\"${COLORS.nodeFill}\" stroke=\"${COLORS.nodeStroke}\" stroke-width=\"1.25\" filter=\"url(#nodeShadow)\"/>`;\n } else if (shape === 'circle') {\n const r = Math.min(box.w, box.h) / 2 - 1;\n shapeEl = `<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"${COLORS.nodeFill}\" stroke=\"${COLORS.nodeStroke}\" stroke-width=\"1.25\" filter=\"url(#nodeShadow)\"/>`;\n } else if (shape === 'parallelogram') {\n const pts = `${box.x + 14},${box.y} ${box.x + box.w},${box.y} ${box.x + box.w - 14},${box.y + box.h} ${box.x},${box.y + box.h}`;\n shapeEl = `<polygon points=\"${pts}\" fill=\"${COLORS.nodeFill}\" stroke=\"${COLORS.nodeStroke}\" stroke-width=\"1.25\" filter=\"url(#nodeShadow)\"/>`;\n } else {\n shapeEl = `<rect x=\"${box.x}\" y=\"${box.y}\" width=\"${box.w}\" height=\"${box.h}\" rx=\"14\" fill=\"${COLORS.nodeFill}\" stroke=\"${COLORS.nodeStroke}\" stroke-width=\"1.25\" filter=\"url(#nodeShadow)\"/>`;\n }\n return shapeEl + label;\n}\n\nfunction renderQuestionNode(node: DiagramNode, box: LayoutBox): string {\n const answers = (node.metadata?.answers as string[] | undefined) ?? [];\n const clipId = `qhdr-${node.id.replace(/[^a-zA-Z0-9_-]/g, '_')}`;\n const x = box.x, y = box.y, w = box.w, h = box.h;\n const parts: string[] = [];\n\n // Card body\n parts.push(`<rect x=\"${x}\" y=\"${y}\" width=\"${w}\" height=\"${h}\" rx=\"14\" fill=\"${COLORS.nodeFill}\" stroke=\"${COLORS.amberLine}\" stroke-width=\"1.5\" filter=\"url(#nodeShadow)\"/>`);\n\n // Header tint (clipped to top rounded corners)\n parts.push(`<defs><clipPath id=\"${clipId}\"><rect x=\"${x}\" y=\"${y}\" width=\"${w}\" height=\"${Q_BASE_H}\" rx=\"14\"/></clipPath></defs>`);\n parts.push(`<rect x=\"${x}\" y=\"${y}\" width=\"${w}\" height=\"${Q_BASE_H}\" fill=\"${COLORS.amberSoft}\" clip-path=\"url(#${clipId})\"/>`);\n\n // Amber left accent\n parts.push(`<rect x=\"${x}\" y=\"${y}\" width=\"4\" height=\"${Q_BASE_H}\" rx=\"2\" fill=\"${COLORS.amber}\"/>`);\n\n // ? badge\n parts.push(`<rect x=\"${x + 12}\" y=\"${y + 14}\" width=\"28\" height=\"28\" rx=\"8\" fill=\"${COLORS.amber}\"/>`);\n parts.push(`<text x=\"${x + 26}\" y=\"${y + 33}\" text-anchor=\"middle\" font-size=\"15\" font-weight=\"900\" fill=\"white\">?</text>`);\n\n // QUESTION label + node label\n parts.push(`<text x=\"${x + 50}\" y=\"${y + 27}\" font-family=\"ui-sans-serif,system-ui,sans-serif\" font-size=\"9\" font-weight=\"700\" fill=\"${COLORS.textSub}\" letter-spacing=\"0.6\">QUESTION</text>`);\n parts.push(`<text x=\"${x + 50}\" y=\"${y + 42}\" font-family=\"ui-sans-serif,system-ui,sans-serif\" font-size=\"13\" font-weight=\"700\" fill=\"${COLORS.text}\">${escapeXML(node.label)}</text>`);\n\n // Divider\n parts.push(`<line x1=\"${x}\" y1=\"${y + Q_BASE_H}\" x2=\"${x + w}\" y2=\"${y + Q_BASE_H}\" stroke=\"${COLORS.amberLine}\" stroke-width=\"1\"/>`);\n\n if (answers.length === 0) {\n parts.push(`<text x=\"${x + w / 2}\" y=\"${y + Q_BASE_H + 22}\" text-anchor=\"middle\" font-size=\"10\" fill=\"${COLORS.amber}\" opacity=\"0.4\" font-weight=\"600\">No answers yet</text>`);\n } else {\n const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n answers.forEach((ans, i) => {\n const prevW = answers.slice(0, i).reduce((s, a) => s + answerCardW(a) + Q_CARD_PAD, 0);\n const cW = answerCardW(ans);\n const cardX = x + Q_CARD_PAD + prevW;\n const cardY = y + Q_BASE_H + 7;\n const cardH = Q_ANS_ROW_H - 20;\n const cx = cardX + cW / 2;\n const letter = i < 26 ? letters[i] : `${i + 1}`;\n const maxChars = Math.max(2, Math.floor((cW - 20) / 7.5));\n const displayAns = ans.length > maxChars ? ans.slice(0, maxChars - 1) + '…' : ans;\n\n parts.push(`<rect x=\"${cardX}\" y=\"${cardY}\" width=\"${cW}\" height=\"${cardH}\" rx=\"8\" fill=\"${COLORS.amberCardBg}\" stroke=\"${COLORS.amberLine}\" stroke-width=\"1\"/>`);\n parts.push(`<rect x=\"${cx - 11}\" y=\"${cardY + 7}\" width=\"22\" height=\"22\" rx=\"6\" fill=\"#fef3c7\"/>`);\n parts.push(`<text x=\"${cx}\" y=\"${cardY + 22}\" text-anchor=\"middle\" font-size=\"10\" font-weight=\"800\" fill=\"${COLORS.amber}\">${escapeXML(letter)}</text>`);\n parts.push(`<text x=\"${cx}\" y=\"${cardY + 46}\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"500\" fill=\"#374151\" font-family=\"ui-sans-serif,system-ui,sans-serif\">${escapeXML(displayAns)}</text>`);\n });\n }\n\n return parts.join('');\n}\n\nfunction renderEdge(edge: DiagramEdge, boxes: Map<string, LayoutBox>, variant: DiagramModel['variant'], nodes: DiagramNode[]): string {\n const fromBox = boxes.get(edge.from);\n const toBox = boxes.get(edge.to);\n if (!fromBox || !toBox) return '';\n\n let x1: number, y1: number;\n const fromNode = nodes.find(n => n.id === edge.from);\n\n if (fromNode && isQuestion(fromNode, variant)) {\n const answers = (fromNode.metadata?.answers as string[] | undefined) ?? [];\n const idx = answers.indexOf(edge.label ?? '');\n if (idx >= 0) {\n const prevW = answers.slice(0, idx).reduce((s, a) => s + answerCardW(a) + Q_CARD_PAD, 0);\n const cW = answerCardW(answers[idx]);\n x1 = fromBox.x + Q_CARD_PAD + prevW + cW / 2;\n y1 = fromBox.y + Q_BASE_H + Q_ANS_ROW_H - 8;\n } else {\n x1 = fromBox.x + fromBox.w / 2;\n y1 = fromBox.y + fromBox.h;\n }\n } else {\n x1 = fromBox.x + fromBox.w / 2;\n y1 = fromBox.y + fromBox.h;\n }\n const x2 = toBox.x + toBox.w / 2;\n const y2 = toBox.y;\n\n const dash = edge.style === 'dashed' ? ' stroke-dasharray=\"6,4\"'\n : edge.style === 'dotted' ? ' stroke-dasharray=\"2,3\"' : '';\n const marker = edge.arrowhead === 'none' ? '' : ' marker-end=\"url(#arrow)\"';\n const d = bezierPath(x1, y1, x2, y2);\n\n let out = `<path d=\"${d}\" fill=\"none\" stroke=\"${COLORS.edge}\" stroke-width=\"1.5\"${dash}${marker}/>`;\n\n if (edge.label) {\n const midX = (x1 + x2) / 2;\n const midY = (y1 + y2) / 2;\n const labelW = estimateTextW(edge.label, 7) + 14;\n out += `<rect x=\"${midX - labelW / 2}\" y=\"${midY - 11}\" width=\"${labelW}\" height=\"18\" rx=\"9\" fill=\"${COLORS.bg}\" stroke=\"${COLORS.nodeStroke}\" stroke-width=\"1\"/>`;\n out += `<text x=\"${midX}\" y=\"${midY + 2}\" text-anchor=\"middle\" font-family=\"ui-sans-serif,system-ui,sans-serif\" font-size=\"11\" fill=\"${COLORS.text}\">${escapeXML(edge.label)}</text>`;\n }\n return out;\n}\n\n/**\n * Render a `DiagramModel` to a standalone SVG string. The output mirrors the\n * editor canvas: dot-grid background, soft drop-shadowed nodes, smooth\n * cubic-bezier edges. No external assets — the result is fully inline and\n * pasteable into HTML, README files, or PR descriptions.\n *\n * Layout is computed identically to the editor's hit-test pass (same width\n * estimation, padding, and question-card sizing), so an exported SVG matches\n * what you see on screen.\n *\n * Works in Node, Bun, and the browser (no DOM APIs needed).\n */\nexport function toSVG(model: DiagramModel): string {\n const boxes = computeLayout(model);\n let maxX = 0, maxY = 0;\n for (const b of boxes.values()) {\n maxX = Math.max(maxX, b.x + b.w);\n maxY = Math.max(maxY, b.y + b.h);\n }\n const width = maxX + PADDING;\n const height = maxY + PADDING + (model.title ? 32 : 0);\n\n const defs = [\n `<defs>`,\n `<pattern id=\"dotgrid\" x=\"0\" y=\"0\" width=\"24\" height=\"24\" patternUnits=\"userSpaceOnUse\">`,\n `<circle cx=\"12\" cy=\"12\" r=\"1.1\" fill=\"${COLORS.dot}\"/>`,\n `</pattern>`,\n `<filter id=\"nodeShadow\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\">`,\n `<feDropShadow dx=\"0\" dy=\"3\" stdDeviation=\"5\" flood-color=\"rgba(15,23,42,0.09)\"/>`,\n `</filter>`,\n `<marker id=\"arrow\" markerWidth=\"9\" markerHeight=\"7\" refX=\"8.5\" refY=\"3.5\" orient=\"auto\" markerUnits=\"strokeWidth\">`,\n `<path d=\"M0,0.5 L9,3.5 L0,6.5 L2.2,3.5 Z\" fill=\"${COLORS.edge}\"/>`,\n `</marker>`,\n `</defs>`,\n ].join('');\n\n const titleEl = model.title\n ? `<text x=\"${width / 2}\" y=\"22\" text-anchor=\"middle\" font-family=\"ui-sans-serif,system-ui,sans-serif\" font-size=\"15\" font-weight=\"700\" fill=\"${COLORS.text}\">${escapeXML(model.title)}</text>`\n : '';\n\n const edges = model.edges.map(e => renderEdge(e, boxes, model.variant, model.nodes)).join('\\n');\n const nodes = model.nodes.map(n => {\n const b = boxes.get(n.id)!;\n return isQuestion(n, model.variant) ? renderQuestionNode(n, b) : renderStandardNode(n, b);\n }).join('\\n');\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\">\\n${defs}\\n<rect width=\"${width}\" height=\"${height}\" fill=\"${COLORS.bg}\"/>\\n<rect width=\"${width}\" height=\"${height}\" fill=\"url(#dotgrid)\"/>\\n${titleEl}\\n${edges}\\n${nodes}\\n</svg>`;\n}\n\n/**\n * Render a `DiagramModel` to a PNG `Blob`. Routes the SVG output through an\n * `<img>` and a `<canvas>` at `devicePixelRatio` scale, so the result is\n * crisp on hi-DPI displays.\n *\n * **Browser-only.** Throws if called in a Node/Bun environment (the Canvas\n * API is not available). For server-side PNG rendering, pipe `toSVG()` output\n * through a library like `@resvg/resvg-js`.\n */\nexport async function toPNG(model: DiagramModel): Promise<Blob> {\n if (typeof document === 'undefined') {\n throw new Error('toPNG requires a browser environment. For Node/Bun server use, pipe toSVG() through @resvg/resvg-js.');\n }\n const svg = toSVG(model);\n const blob = new Blob([svg], { type: 'image/svg+xml' });\n const url = URL.createObjectURL(blob);\n\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement('canvas');\n const scale = window.devicePixelRatio || 2;\n canvas.width = img.naturalWidth * scale;\n canvas.height = img.naturalHeight * scale;\n const ctx = canvas.getContext('2d')!;\n ctx.scale(scale, scale);\n ctx.drawImage(img, 0, 0);\n URL.revokeObjectURL(url);\n canvas.toBlob(b => b ? resolve(b) : reject(new Error('Canvas toBlob failed')), 'image/png');\n };\n img.onerror = () => { URL.revokeObjectURL(url); reject(new Error('SVG image load failed')); };\n img.src = url;\n });\n}\n","import { Model } from './model.js';\nimport type { DiagramEdge, DiagramNode, NodeShape } from './types.js';\nimport { nextId } from './ids.js';\nimport { toMermaid } from '../exporters/mermaid.js';\nimport { toPlantUML } from '../exporters/plantuml.js';\nimport { toJSON } from '../exporters/json.js';\nimport { toSVG, toPNG } from '../exporters/svg.js';\n\n/**\n * Fluent builder for flowchart-type diagrams. Wraps `Model` with shorter\n * method names tuned for one-shot construction in tests and scripts, and\n * with convenience exporters for every supported `ExportFormat`.\n *\n * @example\n * ```ts\n * const svg = flowchart('Login')\n * .node('start', 'Begin', { shape: 'circle' })\n * .node('check', 'Authenticated?', { shape: 'diamond' })\n * .edge('start', 'check')\n * .toSVG();\n * ```\n */\nexport class FlowchartBuilder {\n private model: Model;\n\n /** @param title Optional human-readable diagram title. */\n constructor(title?: string) {\n this.model = new Model('flowchart', title);\n }\n\n /**\n * Append a node. Defaults `shape` to `rectangle` when omitted from `options`.\n * Throws on duplicate id.\n */\n node(id: string, label: string, options: Partial<Omit<DiagramNode, 'id' | 'label'>> = {}): this {\n this.model.addNode({ id, label, shape: options.shape ?? 'rectangle', ...options });\n return this;\n }\n\n /**\n * Append an edge with an auto-generated id. The id is derived from the\n * current edge list to avoid collisions with imported models.\n */\n edge(from: string, to: string, options: Partial<Omit<DiagramEdge, 'id' | 'from' | 'to'>> = {}): this {\n this.model.addEdge({ id: nextId('e', this.model.toJSON().edges), from, to, ...options });\n return this;\n }\n\n /** Remove a node and every edge that references it. */\n removeNode(id: string): this {\n this.model.removeNode(id);\n return this;\n }\n\n /** Remove an edge by id. */\n removeEdge(id: string): this {\n this.model.removeEdge(id);\n return this;\n }\n\n /** Patch an existing node. See `Model.updateNode`. */\n updateNode(id: string, patch: Partial<Omit<DiagramNode, 'id'>>): this {\n this.model.updateNode(id, patch);\n return this;\n }\n\n /** Return the underlying `Model` for advanced operations or validation. */\n getModel(): Model {\n return this.model;\n }\n\n /** Serialize as Mermaid `flowchart TD` source. */\n toMermaid(): string {\n return toMermaid(this.model.toJSON());\n }\n\n /** Serialize as PlantUML activity-diagram source. */\n toPlantUML(): string {\n return toPlantUML(this.model.toJSON());\n }\n\n /** Serialize as the package's JSON shape (full round-trip fidelity). */\n toJSON(): string {\n return toJSON(this.model.toJSON());\n }\n\n /** Render to a standalone SVG string. */\n toSVG(): string {\n return toSVG(this.model.toJSON());\n }\n\n /** Render to a PNG `Blob`. Browser-only (uses the Canvas API). */\n toPNG(): Promise<Blob> {\n return toPNG(this.model.toJSON());\n }\n}\n\n/** Convenience constructor — `flowchart('My Diagram')` is `new FlowchartBuilder('My Diagram')`. */\nexport function flowchart(title?: string): FlowchartBuilder {\n return new FlowchartBuilder(title);\n}\n","import { Model } from './model.js';\nimport type { SequenceMessage } from './types.js';\nimport { nextId } from './ids.js';\nimport { toMermaid } from '../exporters/mermaid.js';\nimport { toPlantUML } from '../exporters/plantuml.js';\nimport { toJSON } from '../exporters/json.js';\n\n/**\n * Fluent builder for sequence-type diagrams. Mirrors `FlowchartBuilder` but\n * over `actors`/`messages` instead of `nodes`/`edges`.\n *\n * @example\n * ```ts\n * const puml = sequence('Checkout')\n * .actor('User')\n * .message('User', 'Server', 'POST /pay')\n * .replyMessage('Server', 'User', '200 OK')\n * .toPlantUML();\n * ```\n */\nexport class SequenceBuilder {\n private model: Model;\n\n /** @param title Optional human-readable diagram title. */\n constructor(title?: string) {\n this.model = new Model('sequence', title);\n }\n\n /** Register an actor. Duplicates are silently ignored. */\n actor(name: string): this {\n this.model.addActor(name);\n return this;\n }\n\n /**\n * Append a message. Both endpoints are auto-registered as actors if not\n * already present. The id is derived from the current message list.\n */\n message(from: string, to: string, label: string, options: Partial<Pick<SequenceMessage, 'style'>> = {}): this {\n this.model.addActor(from);\n this.model.addActor(to);\n const messages = this.model.toJSON().messages ?? [];\n this.model.addMessage({ id: nextId('m', messages), from, to, label, style: options.style ?? 'solid' });\n return this;\n }\n\n /** Convenience for a `dashed`-style return message. */\n replyMessage(from: string, to: string, label: string): this {\n return this.message(from, to, label, { style: 'dashed' });\n }\n\n /** Return the underlying `Model` for advanced operations or validation. */\n getModel(): Model {\n return this.model;\n }\n\n /** Serialize as Mermaid `sequenceDiagram` source. */\n toMermaid(): string {\n return toMermaid(this.model.toJSON());\n }\n\n /** Serialize as PlantUML sequence-diagram source. */\n toPlantUML(): string {\n return toPlantUML(this.model.toJSON());\n }\n\n /** Serialize as the package's JSON shape (full round-trip fidelity). */\n toJSON(): string {\n return toJSON(this.model.toJSON());\n }\n}\n\n/** Convenience constructor — `sequence('My Diagram')` is `new SequenceBuilder('My Diagram')`. */\nexport function sequence(title?: string): SequenceBuilder {\n return new SequenceBuilder(title);\n}\n","import { Model } from '../core/model.js';\nimport type { NodeShape } from '../core/types.js';\nimport { nextId } from '../core/ids.js';\n\n// Detects shape from Mermaid node syntax\nfunction parseNodeDecl(raw: string): { id: string; label: string; shape: NodeShape } | null {\n // diamond: id{label}, circle: id((label)), parallelogram: id[/label/], default: id[label] or id(\"label\")\n const patterns: [RegExp, NodeShape][] = [\n [/^(\\w+)\\{\\{?\"?(.+?)\"?\\}?\\}$/, 'diamond'],\n [/^(\\w+)\\(\\(\"?(.+?)\"?\\)\\)$/, 'circle'],\n [/^(\\w+)\\[\\/(.+?)\\/\\]$/, 'parallelogram'],\n [/^(\\w+)\\[[\"']?(.+?)[\"']?\\]$/, 'rectangle'],\n [/^(\\w+)\\(\"?(.+?)\"?\\)$/, 'rectangle'],\n ];\n for (const [re, shape] of patterns) {\n const m = raw.match(re);\n if (m) return { id: m[1], label: m[2].replace(/^[\"']|[\"']$/g, ''), shape };\n }\n return null;\n}\n\n// Mermaid flowchart edge connector: solid (-->, ---), dashed (-.->, -.-), or with labels.\n// Anchored so node IDs ending in `{`/`[`/`(` cannot bleed into the connector.\nconst EDGE_RE = /^(.+?)\\s*(-\\.->|-\\.-|-->|---)(?:\\|(.+?)\\|)?\\s*(.+)$/;\n\nfunction detectStyle(connector: string): 'solid' | 'dashed' {\n return connector.startsWith('-.') ? 'dashed' : 'solid';\n}\n\nfunction detectArrowhead(connector: string): 'arrow' | 'none' {\n return connector.endsWith('>') ? 'arrow' : 'none';\n}\n\nfunction parseFlowchart(lines: string[]): Model {\n const model = new Model('flowchart');\n const nodeMap = new Map<string, boolean>();\n const groupStack: string[] = [];\n\n const ensureNode = (id: string, group?: string) => {\n if (!nodeMap.has(id)) {\n nodeMap.set(id, true);\n const metadata = group ? { group } : undefined;\n model.addNode({ id, label: id, shape: 'rectangle', ...(metadata ? { metadata } : {}) });\n }\n };\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n // Skip Mermaid comments, config blocks, header directives, and click handlers.\n if (\n trimmed.startsWith('%%') ||\n trimmed.startsWith('graph') ||\n trimmed.startsWith('flowchart') ||\n trimmed.startsWith('click ') ||\n trimmed.startsWith('classDef ') ||\n trimmed.startsWith('class ') ||\n trimmed.startsWith('style ') ||\n trimmed.startsWith('linkStyle ')\n ) continue;\n\n // Subgraphs: track current group so contained nodes get metadata.group set.\n const subgraphOpen = trimmed.match(/^subgraph\\s+(\\S+)/i);\n if (subgraphOpen) { groupStack.push(subgraphOpen[1]); continue; }\n if (/^end\\b/i.test(trimmed)) { groupStack.pop(); continue; }\n\n const currentGroup = groupStack[groupStack.length - 1];\n\n const edgeMatch = trimmed.match(EDGE_RE);\n if (edgeMatch) {\n const fromRaw = edgeMatch[1].trim();\n const connector = edgeMatch[2];\n const label = edgeMatch[3]?.replace(/^[\"']|[\"']$/g, '');\n const toRaw = edgeMatch[4].trim();\n const style = detectStyle(connector);\n const arrowhead = detectArrowhead(connector);\n\n const fromNode = parseNodeDecl(fromRaw);\n const toNode = parseNodeDecl(toRaw);\n\n if (fromNode && !nodeMap.has(fromNode.id)) {\n nodeMap.set(fromNode.id, true);\n const metadata = currentGroup ? { group: currentGroup } : undefined;\n model.addNode({ ...fromNode, ...(metadata ? { metadata } : {}) });\n } else if (!fromNode) {\n ensureNode(fromRaw.replace(/\\W.*/, ''), currentGroup);\n }\n if (toNode && !nodeMap.has(toNode.id)) {\n nodeMap.set(toNode.id, true);\n const metadata = currentGroup ? { group: currentGroup } : undefined;\n model.addNode({ ...toNode, ...(metadata ? { metadata } : {}) });\n } else if (!toNode) {\n ensureNode(toRaw.replace(/\\W.*/, ''), currentGroup);\n }\n\n const fromId = fromNode?.id ?? fromRaw.replace(/\\W.*/, '');\n const toId = toNode?.id ?? toRaw.replace(/\\W.*/, '');\n model.addEdge({\n id: nextId('e', model.toJSON().edges),\n from: fromId, to: toId,\n ...(label ? { label } : {}),\n style,\n ...(arrowhead === 'none' ? { arrowhead } : {}),\n });\n continue;\n }\n\n const nodeDecl = parseNodeDecl(trimmed);\n if (nodeDecl && !nodeMap.has(nodeDecl.id)) {\n nodeMap.set(nodeDecl.id, true);\n const metadata = currentGroup ? { group: currentGroup } : undefined;\n model.addNode({ ...nodeDecl, ...(metadata ? { metadata } : {}) });\n }\n }\n\n return model;\n}\n\nfunction parseSequence(lines: string[], title?: string): Model {\n const model = new Model('sequence', title);\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('sequenceDiagram') || trimmed.startsWith('%%')) continue;\n\n const participantMatch = trimmed.match(/^participant\\s+(.+)$/i);\n if (participantMatch) {\n model.addActor(participantMatch[1].trim());\n continue;\n }\n\n const actorMatch = trimmed.match(/^actor\\s+(.+)$/i);\n if (actorMatch) {\n model.addActor(actorMatch[1].trim());\n continue;\n }\n\n // Sequence message arrows: ->, ->>, -->, -->> (-- prefix = dashed)\n const msgMatch = trimmed.match(/^(.+?)\\s*(-->>|->>|-->|->)\\s*(.+?):\\s*(.+)$/);\n if (msgMatch) {\n const from = msgMatch[1].trim();\n const arrow = msgMatch[2];\n const to = msgMatch[3].trim();\n const label = msgMatch[4].trim();\n model.addActor(from);\n model.addActor(to);\n const messages = model.toJSON().messages ?? [];\n model.addMessage({ id: nextId('m', messages), from, to, label, style: arrow.startsWith('--') ? 'dashed' : 'solid' });\n }\n }\n\n return model;\n}\n\n/**\n * Parse Mermaid source into a `Model`. Auto-detects `flowchart` /\n * `sequenceDiagram` from the directive line and dispatches accordingly.\n *\n * **What is preserved:**\n * - Flowcharts: node shapes (`[]` / `{}` / `(())` / `[/]`), node labels,\n * edge connectors (`-->`, `-.->`, `---`, `-.-`), edge labels, and\n * `subgraph` grouping (stored on `node.metadata.group`).\n * - Sequence: actor declarations, message arrows (`->>`, `-->>`), labels.\n * - Frontmatter `title: ...` blocks are lifted into `model.title`.\n *\n * **What is dropped or normalized:**\n * - `mermaid.initialize(...)` blocks, `%%{init: ...}%%` directives, and\n * click handlers — stripped before parsing.\n * - Dotted edges collapse to `dashed` (Mermaid's dot/dash style is lossy).\n * - Node positions, `waypoint`, and any package-specific metadata other\n * than `group` are not present in Mermaid and so cannot round-trip.\n */\nexport function fromMermaid(mermaid: string): Model {\n // Strip mermaid.initialize(...) and similar JS-style config blocks that\n // sometimes appear in copy-pasted snippets — anything between `init` and `)`.\n const cleaned = mermaid.replace(/mermaid\\.initialize\\([\\s\\S]*?\\)\\s*;?/g, '');\n const rawLines = cleaned.split('\\n');\n\n // Strip frontmatter\n let startIdx = 0;\n let title: string | undefined;\n if (rawLines[0]?.trim() === '---') {\n const endFm = rawLines.findIndex((l, i) => i > 0 && l.trim() === '---');\n if (endFm !== -1) {\n const fmLines = rawLines.slice(1, endFm);\n for (const fl of fmLines) {\n const tm = fl.match(/^title:\\s*(.+)$/);\n if (tm) title = tm[1].trim();\n }\n startIdx = endFm + 1;\n }\n }\n\n const lines = rawLines.slice(startIdx);\n const firstContent = lines.find(l => l.trim());\n\n if (firstContent?.trim().startsWith('sequenceDiagram')) {\n const m = parseSequence(lines, title);\n return m;\n }\n\n const m = parseFlowchart(lines);\n if (title) {\n // patch title via internal JSON round-trip\n const data = m.toJSON();\n data.title = title;\n return Model.fromData(data);\n }\n return m;\n}\n","import { Model } from '../core/model.js';\nimport type { DiagramModel } from '../core/types.js';\n\n/**\n * Rehydrate a `Model` from the package's JSON shape. Accepts either the raw\n * JSON string or an already-parsed `DiagramModel` (handy when the caller has\n * received the data from a typed source).\n *\n * Validation here is minimal — only the structural fields needed by the\n * downstream renderer (`type`, `nodes`, `edges`) are checked. For deeper\n * checks call `model.validate()` after import.\n *\n * @throws If `json` is not a valid `DiagramModel` shape.\n */\nexport function fromJSON(json: string | DiagramModel): Model {\n const data: DiagramModel = typeof json === 'string' ? JSON.parse(json) : json;\n if (!data.type || !Array.isArray(data.nodes) || !Array.isArray(data.edges)) {\n throw new Error('Invalid DiagramModel JSON');\n }\n return Model.fromData(data);\n}\n"],"mappings":"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","names":["exportFlowchart","msgArrow","exportSequence","m"]}
@@ -0,0 +1,398 @@
1
+ /**
2
+ * Top-level kind of diagram. `flowchart` uses `nodes` + `edges`; `sequence`
3
+ * uses `actors` + `messages`. The two are rendered by different editors and
4
+ * serialized differently in every exporter.
5
+ */
6
+ type DiagramType = 'flowchart' | 'sequence';
7
+ /**
8
+ * UI variant for flowchart-type models. `flowchart` is the default linear
9
+ * graph; `question` is a decision-tree variant whose nodes carry
10
+ * `metadata.answers`; `journey` is a horizontal user-journey style. The
11
+ * variant selects styling and a few interactions inside `DiagramEditor`.
12
+ */
13
+ type DiagramVariant = 'flowchart' | 'question' | 'journey';
14
+ /**
15
+ * Visual shape of a flowchart node. Defaults to `rectangle`. `diamond` is
16
+ * conventional for decisions, `circle` for start/end terminators, and
17
+ * `parallelogram` for I/O.
18
+ */
19
+ type NodeShape = 'rectangle' | 'diamond' | 'circle' | 'parallelogram';
20
+ /**
21
+ * Supported export targets.
22
+ * - `mermaid` / `plantuml` / `json` / `svg` produce a `string`.
23
+ * - `png` produces a `Blob` (browser-only — uses the Canvas API).
24
+ */
25
+ type ExportFormat = 'mermaid' | 'plantuml' | 'json' | 'svg' | 'png';
26
+ /**
27
+ * A flowchart node.
28
+ *
29
+ * @property id Stable, unique-within-model identifier. Used by edges.
30
+ * @property label Visible text. Multi-line input is wrapped by the renderer.
31
+ * @property shape Visual shape; defaults to `rectangle` when omitted.
32
+ * @property x Optional canvas x-coordinate. When omitted, the renderer
33
+ * auto-positions on first paint.
34
+ * @property y Optional canvas y-coordinate. Same defaulting as `x`.
35
+ * @property metadata Free-form bag for variant-specific data (e.g.
36
+ * `metadata.group` for journey columns, `metadata.answers`
37
+ * for question branches). Round-trips through JSON only.
38
+ */
39
+ interface DiagramNode {
40
+ id: string;
41
+ label: string;
42
+ shape?: NodeShape;
43
+ x?: number;
44
+ y?: number;
45
+ metadata?: Record<string, unknown>;
46
+ }
47
+ /**
48
+ * A directed edge between two flowchart nodes.
49
+ *
50
+ * @property id Stable, unique-within-model identifier.
51
+ * @property from Source node id. Must match an existing `DiagramNode.id`.
52
+ * @property to Target node id. Must match an existing `DiagramNode.id`.
53
+ * @property label Optional edge label rendered at the midpoint.
54
+ * @property style Line style. `solid` is default; `dashed` maps to
55
+ * Mermaid `-.->` and PlantUML `-[dashed]->`; `dotted`
56
+ * maps to Mermaid `-..->` and PlantUML `-[dotted]->`.
57
+ * @property arrowhead Arrow style at the target end. `arrow` is default.
58
+ * @property waypoint Optional manual waypoint in canvas coordinates. When
59
+ * set, the edge is routed as two cubic segments meeting
60
+ * at this point. Persisted in JSON exports; ignored by
61
+ * Mermaid/PlantUML serializers (those formats don't
62
+ * encode routing).
63
+ */
64
+ interface DiagramEdge {
65
+ id: string;
66
+ from: string;
67
+ to: string;
68
+ label?: string;
69
+ style?: 'solid' | 'dashed' | 'dotted';
70
+ arrowhead?: 'arrow' | 'none' | 'open';
71
+ waypoint?: {
72
+ x: number;
73
+ y: number;
74
+ };
75
+ }
76
+ /**
77
+ * A single message in a sequence diagram.
78
+ *
79
+ * @property id Stable, unique-within-model identifier.
80
+ * @property from Source actor name. Must appear in the model's `actors` list.
81
+ * @property to Target actor name. Must appear in the model's `actors` list.
82
+ * @property label Message text rendered above the arrow.
83
+ * @property style Arrow style. `solid` is default; `dashed` is conventional
84
+ * for asynchronous or return messages.
85
+ */
86
+ interface SequenceMessage {
87
+ id: string;
88
+ from: string;
89
+ to: string;
90
+ label: string;
91
+ style?: 'solid' | 'dashed';
92
+ }
93
+ /**
94
+ * The serialized shape of any diagram. Flowchart-type models populate
95
+ * `nodes`/`edges`; sequence-type models populate `actors`/`messages`. Both
96
+ * sub-shapes coexist on a single union to keep the JSON exporter / importer
97
+ * straightforward.
98
+ *
99
+ * @property type Discriminator — selects which sub-shape is active.
100
+ * @property variant UI variant. Only meaningful when `type === 'flowchart'`.
101
+ * @property title Optional human-readable diagram title.
102
+ * @property nodes Flowchart nodes. Always present (empty for sequence
103
+ * models) so the type stays uniform.
104
+ * @property edges Flowchart edges. Always present (empty for sequence
105
+ * models).
106
+ * @property actors Ordered list of actor names. Sequence models only.
107
+ * @property messages Ordered list of messages between actors. Sequence
108
+ * models only.
109
+ */
110
+ interface DiagramModel {
111
+ type: DiagramType;
112
+ variant?: DiagramVariant;
113
+ title?: string;
114
+ nodes: DiagramNode[];
115
+ edges: DiagramEdge[];
116
+ actors?: string[];
117
+ messages?: SequenceMessage[];
118
+ }
119
+ /**
120
+ * A single problem found by `Model.validate()`.
121
+ *
122
+ * @property kind Category of the problem:
123
+ * - `dangling-from`: edge `from` references a missing node.
124
+ * - `dangling-to`: edge `to` references a missing node.
125
+ * - `duplicate-node-id`: two nodes share an `id`.
126
+ * - `duplicate-edge-id`: two edges share an `id`.
127
+ * @property id Identifier of the offending node or edge.
128
+ * @property message Human-readable description suitable for surfacing in UI.
129
+ */
130
+ interface ValidationError {
131
+ kind: 'dangling-from' | 'dangling-to' | 'duplicate-node-id' | 'duplicate-edge-id';
132
+ id: string;
133
+ message: string;
134
+ }
135
+
136
+ /**
137
+ * Mutable builder around a `DiagramModel`. Every public mutator returns
138
+ * `this` so callers can chain (`new Model('flowchart').addNode(...).addEdge(...)`).
139
+ * Call `.toJSON()` to extract a deep-cloned plain model suitable for
140
+ * serialization or for handing to the editor components.
141
+ *
142
+ * All add/update operations validate immediately and throw on collisions or
143
+ * dangling references. For non-throwing, batch-style structural checks call
144
+ * `.validate()` instead.
145
+ */
146
+ declare class Model {
147
+ private data;
148
+ /**
149
+ * Create an empty model.
150
+ *
151
+ * @param type Top-level kind — `flowchart` or `sequence`.
152
+ * @param title Optional human-readable title.
153
+ * @param variant Optional UI variant (flowchart models only).
154
+ */
155
+ constructor(type: DiagramType, title?: string, variant?: DiagramVariant);
156
+ /**
157
+ * Rehydrate a `Model` from a previously serialized `DiagramModel`. The
158
+ * incoming data is deep-cloned, so future mutations on the returned `Model`
159
+ * do not affect the caller's object.
160
+ */
161
+ static fromData(data: DiagramModel): Model;
162
+ /** Set the UI variant. No-op semantics for sequence models. */
163
+ setVariant(variant: DiagramVariant): this;
164
+ /**
165
+ * Append a node. Throws if a node with the same id already exists. The
166
+ * input is shallow-cloned, so later mutations of the caller's object do
167
+ * not leak in.
168
+ */
169
+ addNode(node: DiagramNode): this;
170
+ /**
171
+ * Patch an existing node in place. Throws if the id is not found. The id
172
+ * field itself cannot be patched — to rename, remove + re-add.
173
+ */
174
+ updateNode(id: string, patch: Partial<Omit<DiagramNode, 'id'>>): this;
175
+ /**
176
+ * Remove a node and every edge that referenced it as `from` or `to`. Safe
177
+ * to call on a missing id (no-op).
178
+ */
179
+ removeNode(id: string): this;
180
+ /**
181
+ * Append an edge. Throws on duplicate id or if either endpoint references
182
+ * an unknown node — the model never holds dangling edges from this entry
183
+ * point. (Importers can still construct dangling edges; call `validate()`
184
+ * to detect them.)
185
+ */
186
+ addEdge(edge: DiagramEdge): this;
187
+ /**
188
+ * Surface structural problems without throwing. Returns an array of
189
+ * `ValidationError`s; empty array means the model is well-formed. Used by
190
+ * the editor's status banner and by external tooling.
191
+ */
192
+ validate(): ValidationError[];
193
+ /** Remove an edge by id. Safe to call on a missing id (no-op). */
194
+ removeEdge(id: string): this;
195
+ /** Append a sequence actor. Duplicate names are silently ignored. */
196
+ addActor(name: string): this;
197
+ /**
198
+ * Append a sequence message. The actors referenced by `from`/`to` are not
199
+ * validated here — callers are expected to register them via `addActor()`
200
+ * first.
201
+ */
202
+ addMessage(message: SequenceMessage): this;
203
+ /**
204
+ * Return a deep-cloned plain `DiagramModel`. Safe to mutate by the caller;
205
+ * mutations do not flow back into this `Model`.
206
+ */
207
+ toJSON(): DiagramModel;
208
+ }
209
+
210
+ /**
211
+ * Fluent builder for flowchart-type diagrams. Wraps `Model` with shorter
212
+ * method names tuned for one-shot construction in tests and scripts, and
213
+ * with convenience exporters for every supported `ExportFormat`.
214
+ *
215
+ * @example
216
+ * ```ts
217
+ * const svg = flowchart('Login')
218
+ * .node('start', 'Begin', { shape: 'circle' })
219
+ * .node('check', 'Authenticated?', { shape: 'diamond' })
220
+ * .edge('start', 'check')
221
+ * .toSVG();
222
+ * ```
223
+ */
224
+ declare class FlowchartBuilder {
225
+ private model;
226
+ /** @param title Optional human-readable diagram title. */
227
+ constructor(title?: string);
228
+ /**
229
+ * Append a node. Defaults `shape` to `rectangle` when omitted from `options`.
230
+ * Throws on duplicate id.
231
+ */
232
+ node(id: string, label: string, options?: Partial<Omit<DiagramNode, 'id' | 'label'>>): this;
233
+ /**
234
+ * Append an edge with an auto-generated id. The id is derived from the
235
+ * current edge list to avoid collisions with imported models.
236
+ */
237
+ edge(from: string, to: string, options?: Partial<Omit<DiagramEdge, 'id' | 'from' | 'to'>>): this;
238
+ /** Remove a node and every edge that references it. */
239
+ removeNode(id: string): this;
240
+ /** Remove an edge by id. */
241
+ removeEdge(id: string): this;
242
+ /** Patch an existing node. See `Model.updateNode`. */
243
+ updateNode(id: string, patch: Partial<Omit<DiagramNode, 'id'>>): this;
244
+ /** Return the underlying `Model` for advanced operations or validation. */
245
+ getModel(): Model;
246
+ /** Serialize as Mermaid `flowchart TD` source. */
247
+ toMermaid(): string;
248
+ /** Serialize as PlantUML activity-diagram source. */
249
+ toPlantUML(): string;
250
+ /** Serialize as the package's JSON shape (full round-trip fidelity). */
251
+ toJSON(): string;
252
+ /** Render to a standalone SVG string. */
253
+ toSVG(): string;
254
+ /** Render to a PNG `Blob`. Browser-only (uses the Canvas API). */
255
+ toPNG(): Promise<Blob>;
256
+ }
257
+ /** Convenience constructor — `flowchart('My Diagram')` is `new FlowchartBuilder('My Diagram')`. */
258
+ declare function flowchart(title?: string): FlowchartBuilder;
259
+
260
+ /**
261
+ * Fluent builder for sequence-type diagrams. Mirrors `FlowchartBuilder` but
262
+ * over `actors`/`messages` instead of `nodes`/`edges`.
263
+ *
264
+ * @example
265
+ * ```ts
266
+ * const puml = sequence('Checkout')
267
+ * .actor('User')
268
+ * .message('User', 'Server', 'POST /pay')
269
+ * .replyMessage('Server', 'User', '200 OK')
270
+ * .toPlantUML();
271
+ * ```
272
+ */
273
+ declare class SequenceBuilder {
274
+ private model;
275
+ /** @param title Optional human-readable diagram title. */
276
+ constructor(title?: string);
277
+ /** Register an actor. Duplicates are silently ignored. */
278
+ actor(name: string): this;
279
+ /**
280
+ * Append a message. Both endpoints are auto-registered as actors if not
281
+ * already present. The id is derived from the current message list.
282
+ */
283
+ message(from: string, to: string, label: string, options?: Partial<Pick<SequenceMessage, 'style'>>): this;
284
+ /** Convenience for a `dashed`-style return message. */
285
+ replyMessage(from: string, to: string, label: string): this;
286
+ /** Return the underlying `Model` for advanced operations or validation. */
287
+ getModel(): Model;
288
+ /** Serialize as Mermaid `sequenceDiagram` source. */
289
+ toMermaid(): string;
290
+ /** Serialize as PlantUML sequence-diagram source. */
291
+ toPlantUML(): string;
292
+ /** Serialize as the package's JSON shape (full round-trip fidelity). */
293
+ toJSON(): string;
294
+ }
295
+ /** Convenience constructor — `sequence('My Diagram')` is `new SequenceBuilder('My Diagram')`. */
296
+ declare function sequence(title?: string): SequenceBuilder;
297
+
298
+ /**
299
+ * Serialize a `DiagramModel` to Mermaid source. Dispatches between
300
+ * `graph TD` (flowchart) and `sequenceDiagram` based on `model.type`.
301
+ *
302
+ * **Round-trip notes (flowchart):**
303
+ * - Node shapes `rectangle`, `diamond`, `circle`, `parallelogram` map to
304
+ * `[ ]`, `{ }`, `(( ))`, `[/ /]` respectively.
305
+ * - Edge style `solid` → `-->`, `dashed` and `dotted` → `-.->` (Mermaid
306
+ * collapses dotted to dashed). `arrowhead: 'none'` strips the head.
307
+ * - `waypoint`, `metadata`, and `variant` are **dropped** — Mermaid has no
308
+ * way to encode routing or arbitrary metadata.
309
+ *
310
+ * **Round-trip notes (sequence):**
311
+ * - Message style `solid` → `->>`, `dashed` → `-->>`.
312
+ */
313
+ declare function toMermaid(model: DiagramModel): string;
314
+
315
+ /**
316
+ * Serialize a `DiagramModel` to PlantUML source. Dispatches between the
317
+ * state-diagram form (flowchart) and the sequence-diagram form based on
318
+ * `model.type`.
319
+ *
320
+ * **Round-trip notes (flowchart):**
321
+ * - Edge style maps `solid` → `-->`, `dashed` → `-[dashed]->`,
322
+ * `dotted` → `-[dotted]->`.
323
+ * - Node shapes are emitted via the `state ".." as id < >` syntax; some
324
+ * shape information is lossy (PlantUML state diagrams don't distinguish
325
+ * every shape this package supports).
326
+ * - `waypoint`, `metadata`, and `variant` are **dropped**.
327
+ *
328
+ * **Round-trip notes (sequence):**
329
+ * - Actor order is preserved; message style `solid` → `->`, `dashed` → `-->`.
330
+ */
331
+ declare function toPlantUML(model: DiagramModel): string;
332
+
333
+ /**
334
+ * Serialize a `DiagramModel` to pretty-printed JSON. This is the canonical
335
+ * round-trip format: every field — including `variant`, `waypoint`,
336
+ * `metadata.group`, and `metadata.answers` — survives a round trip through
337
+ * `toJSON` + `fromJSON` unchanged.
338
+ */
339
+ declare function toJSON(model: DiagramModel): string;
340
+
341
+ /**
342
+ * Render a `DiagramModel` to a standalone SVG string. The output mirrors the
343
+ * editor canvas: dot-grid background, soft drop-shadowed nodes, smooth
344
+ * cubic-bezier edges. No external assets — the result is fully inline and
345
+ * pasteable into HTML, README files, or PR descriptions.
346
+ *
347
+ * Layout is computed identically to the editor's hit-test pass (same width
348
+ * estimation, padding, and question-card sizing), so an exported SVG matches
349
+ * what you see on screen.
350
+ *
351
+ * Works in Node, Bun, and the browser (no DOM APIs needed).
352
+ */
353
+ declare function toSVG(model: DiagramModel): string;
354
+ /**
355
+ * Render a `DiagramModel` to a PNG `Blob`. Routes the SVG output through an
356
+ * `<img>` and a `<canvas>` at `devicePixelRatio` scale, so the result is
357
+ * crisp on hi-DPI displays.
358
+ *
359
+ * **Browser-only.** Throws if called in a Node/Bun environment (the Canvas
360
+ * API is not available). For server-side PNG rendering, pipe `toSVG()` output
361
+ * through a library like `@resvg/resvg-js`.
362
+ */
363
+ declare function toPNG(model: DiagramModel): Promise<Blob>;
364
+
365
+ /**
366
+ * Parse Mermaid source into a `Model`. Auto-detects `flowchart` /
367
+ * `sequenceDiagram` from the directive line and dispatches accordingly.
368
+ *
369
+ * **What is preserved:**
370
+ * - Flowcharts: node shapes (`[]` / `{}` / `(())` / `[/]`), node labels,
371
+ * edge connectors (`-->`, `-.->`, `---`, `-.-`), edge labels, and
372
+ * `subgraph` grouping (stored on `node.metadata.group`).
373
+ * - Sequence: actor declarations, message arrows (`->>`, `-->>`), labels.
374
+ * - Frontmatter `title: ...` blocks are lifted into `model.title`.
375
+ *
376
+ * **What is dropped or normalized:**
377
+ * - `mermaid.initialize(...)` blocks, `%%{init: ...}%%` directives, and
378
+ * click handlers — stripped before parsing.
379
+ * - Dotted edges collapse to `dashed` (Mermaid's dot/dash style is lossy).
380
+ * - Node positions, `waypoint`, and any package-specific metadata other
381
+ * than `group` are not present in Mermaid and so cannot round-trip.
382
+ */
383
+ declare function fromMermaid(mermaid: string): Model;
384
+
385
+ /**
386
+ * Rehydrate a `Model` from the package's JSON shape. Accepts either the raw
387
+ * JSON string or an already-parsed `DiagramModel` (handy when the caller has
388
+ * received the data from a typed source).
389
+ *
390
+ * Validation here is minimal — only the structural fields needed by the
391
+ * downstream renderer (`type`, `nodes`, `edges`) are checked. For deeper
392
+ * checks call `model.validate()` after import.
393
+ *
394
+ * @throws If `json` is not a valid `DiagramModel` shape.
395
+ */
396
+ declare function fromJSON(json: string | DiagramModel): Model;
397
+
398
+ export { type DiagramEdge, type DiagramModel, type DiagramNode, type DiagramType, type DiagramVariant, type DiagramEdge as Edge, type ExportFormat, FlowchartBuilder, Model, type DiagramNode as Node, type NodeShape, SequenceBuilder, type SequenceMessage, flowchart, fromJSON, fromMermaid, sequence, toJSON, toMermaid, toPNG, toPlantUML, toSVG };