flowchart-sequence-designer 1.2.0 → 1.2.2

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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../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/core/sanitize.ts","../src/importers/mermaid.ts","../src/importers/json.ts"],"sourcesContent":["import type {\n DiagramModel,\n DiagramNode,\n DiagramEdge,\n DiagramType,\n DiagramVariant,\n SequenceMessage,\n ValidationError,\n} 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 = {\n type,\n ...(variant ? { variant } : {}),\n title,\n nodes: [],\n edges: [],\n actors: [],\n messages: [],\n };\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 const { __proto__, constructor, ...safe } = patch as Record<string, unknown>;\n Object.assign(node, safe);\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))\n errors.push({\n kind: 'duplicate-node-id',\n id: n.id,\n message: `Duplicate node id \"${n.id}\"`,\n });\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))\n errors.push({\n kind: 'duplicate-edge-id',\n id: e.id,\n message: `Duplicate edge id \"${e.id}\"`,\n });\n edgeIds.add(e.id);\n if (!nodeIds.has(e.from))\n errors.push({\n kind: 'dangling-from',\n id: e.id,\n message: `Edge \"${e.id}\" references unknown source node \"${e.from}\"`,\n });\n if (!nodeIds.has(e.to))\n errors.push({\n kind: 'dangling-to',\n id: e.id,\n message: `Edge \"${e.id}\" references unknown target node \"${e.to}\"`,\n });\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':\n return ['<>', '<>'];\n case 'circle':\n return ['(', ')'];\n case 'parallelogram':\n return ['/', '/'];\n default:\n 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 =\n edge.style === 'dashed' ? '-[dashed]->' : edge.style === 'dotted' ? '-[dotted]->' : '-->';\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 =\n answers.reduce((s, a) => s + answerCardW(a), 0) +\n (answers.length - 1) * Q_CARD_PAD +\n 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 {\n x: number;\n y: number;\n w: number;\n h: number;\n}\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(\n (s) => typeof s.node.x === 'number' && typeof s.node.y === 'number',\n );\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) => {\n if (!layers.has(n.id)) layers.set(n.id, 0);\n });\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\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\n/**\n * Defence-in-depth sanitizer for SVG output. Strips dangerous patterns\n * before XML-escaping. Prevents script injection even if escapeXML were\n * somehow bypassed or if the SVG is consumed by a less-strict parser.\n */\nfunction sanitizeForSVG(s: string): string {\n let clean = s;\n // Strip HTML/XML tags\n clean = clean.replace(/<\\/?[a-zA-Z][^>]*>/g, '');\n // Strip javascript:/data:/vbscript: URIs\n clean = clean.replace(/\\b(?:javascript|data|vbscript)\\s*:/gi, '');\n // Strip on* event handlers\n clean = clean.replace(/\\bon[a-z]+\\s*=/gi, '');\n // Strip null bytes\n // eslint-disable-next-line no-control-regex\n clean = clean.replace(/\\x00/g, '');\n return escapeXML(clean);\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}\">${sanitizeForSVG(node.label)}</text>`;\n\n let shapeEl: string;\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,\n y = box.y,\n w = box.w,\n h = box.h;\n const parts: string[] = [];\n\n // Card body\n parts.push(\n `<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\n // Header tint (clipped to top rounded corners)\n parts.push(\n `<defs><clipPath id=\"${clipId}\"><rect x=\"${x}\" y=\"${y}\" width=\"${w}\" height=\"${Q_BASE_H}\" rx=\"14\"/></clipPath></defs>`,\n );\n parts.push(\n `<rect x=\"${x}\" y=\"${y}\" width=\"${w}\" height=\"${Q_BASE_H}\" fill=\"${COLORS.amberSoft}\" clip-path=\"url(#${clipId})\"/>`,\n );\n\n // Amber left accent\n parts.push(\n `<rect x=\"${x}\" y=\"${y}\" width=\"4\" height=\"${Q_BASE_H}\" rx=\"2\" fill=\"${COLORS.amber}\"/>`,\n );\n\n // ? badge\n parts.push(\n `<rect x=\"${x + 12}\" y=\"${y + 14}\" width=\"28\" height=\"28\" rx=\"8\" fill=\"${COLORS.amber}\"/>`,\n );\n parts.push(\n `<text x=\"${x + 26}\" y=\"${y + 33}\" text-anchor=\"middle\" font-size=\"15\" font-weight=\"900\" fill=\"white\">?</text>`,\n );\n\n // QUESTION label + node label\n parts.push(\n `<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 );\n parts.push(\n `<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}\">${sanitizeForSVG(node.label)}</text>`,\n );\n\n // Divider\n parts.push(\n `<line x1=\"${x}\" y1=\"${y + Q_BASE_H}\" x2=\"${x + w}\" y2=\"${y + Q_BASE_H}\" stroke=\"${COLORS.amberLine}\" stroke-width=\"1\"/>`,\n );\n\n if (answers.length === 0) {\n parts.push(\n `<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 );\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(\n `<rect x=\"${cardX}\" y=\"${cardY}\" width=\"${cW}\" height=\"${cardH}\" rx=\"8\" fill=\"${COLORS.amberCardBg}\" stroke=\"${COLORS.amberLine}\" stroke-width=\"1\"/>`,\n );\n parts.push(\n `<rect x=\"${cx - 11}\" y=\"${cardY + 7}\" width=\"22\" height=\"22\" rx=\"6\" fill=\"#fef3c7\"/>`,\n );\n parts.push(\n `<text x=\"${cx}\" y=\"${cardY + 22}\" text-anchor=\"middle\" font-size=\"10\" font-weight=\"800\" fill=\"${COLORS.amber}\">${sanitizeForSVG(letter)}</text>`,\n );\n parts.push(\n `<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\">${sanitizeForSVG(displayAns)}</text>`,\n );\n });\n }\n\n return parts.join('');\n}\n\nfunction renderEdge(\n edge: DiagramEdge,\n boxes: Map<string, LayoutBox>,\n variant: DiagramModel['variant'],\n nodes: DiagramNode[],\n): 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 =\n edge.style === 'dashed'\n ? ' stroke-dasharray=\"6,4\"'\n : edge.style === 'dotted'\n ? ' stroke-dasharray=\"2,3\"'\n : '';\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}\">${sanitizeForSVG(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,\n 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}\">${sanitizeForSVG(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\n .map((n) => {\n const b = boxes.get(n.id)!;\n return isQuestion(n, model.variant) ? renderQuestionNode(n, b) : renderStandardNode(n, b);\n })\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(\n 'toPNG requires a browser environment. For Node/Bun server use, pipe toSVG() through @resvg/resvg-js.',\n );\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(\n (b) => (b ? resolve(b) : reject(new Error('Canvas toBlob failed'))),\n 'image/png',\n );\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('SVG image load failed'));\n };\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(\n from: string,\n to: string,\n options: Partial<Omit<DiagramEdge, 'id' | 'from' | 'to'>> = {},\n ): 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(\n from: string,\n to: string,\n label: string,\n options: Partial<Pick<SequenceMessage, 'style'>> = {},\n ): this {\n this.model.addActor(from);\n this.model.addActor(to);\n const messages = this.model.toJSON().messages ?? [];\n this.model.addMessage({\n id: nextId('m', messages),\n from,\n to,\n label,\n style: options.style ?? 'solid',\n });\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","/**\n * Centralized input sanitization for all user-provided text that flows\n * into SVG output, labels, or any rendering context.\n *\n * Defence-in-depth: even though `escapeXML()` prevents most injection,\n * stripping dangerous patterns at the source stops payloads from reaching\n * any downstream consumer (clipboard, third-party renderers, etc.).\n */\n\n/** Maximum characters allowed in a single label/text field. */\nexport const MAX_LABEL_LENGTH = 2000;\n\n/** Maximum number of nodes allowed in a single diagram. */\nexport const MAX_NODES = 500;\n\n/** Maximum number of edges allowed in a single diagram. */\nexport const MAX_EDGES = 2000;\n\n/** Maximum number of actors in a sequence diagram. */\nexport const MAX_ACTORS = 100;\n\n/** Maximum number of messages in a sequence diagram. */\nexport const MAX_MESSAGES = 2000;\n\n/** Maximum raw input length for importers (bytes). ~2 MB */\nexport const MAX_IMPORT_LENGTH = 2 * 1024 * 1024;\n\n/**\n * Strip dangerous content from user-supplied text. Removes:\n * - HTML tags (`<script>`, `<img>`, `<foreignObject>`, etc.)\n * - `javascript:`, `data:`, `vbscript:` URI schemes\n * - `on*` event handler attributes (onerror, onclick, etc.)\n * - Null bytes and other control characters\n */\nexport function sanitizeLabel(raw: string): string {\n let s = raw;\n // Remove null bytes and ASCII control chars (except \\n, \\r, \\t)\n // eslint-disable-next-line no-control-regex\n s = s.replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g, '');\n // Strip HTML/XML tags\n s = s.replace(/<\\/?[a-zA-Z][^>]*>/g, '');\n // Strip javascript:/data:/vbscript: URIs (case-insensitive, whitespace-tolerant)\n s = s.replace(/\\b(?:javascript|data|vbscript)\\s*:/gi, '');\n // Strip on* event handlers (e.g. onerror=, onclick=)\n s = s.replace(/\\bon[a-z]+\\s*=/gi, '');\n // Enforce length limit\n if (s.length > MAX_LABEL_LENGTH) {\n s = s.slice(0, MAX_LABEL_LENGTH);\n }\n return s;\n}\n\n/**\n * Validate a URL is safe for use in href attributes.\n * Only allows http:, https:, and mailto: protocols.\n * Returns the URL if safe, or `undefined` if dangerous.\n */\nexport function sanitizeURL(url: string): string | undefined {\n const trimmed = url.trim();\n // Allow relative URLs (start with / or #)\n if (trimmed.startsWith('/') || trimmed.startsWith('#')) return trimmed;\n // Allow http(s) and mailto\n if (/^https?:\\/\\//i.test(trimmed) || /^mailto:/i.test(trimmed)) return trimmed;\n // Block everything else (javascript:, data:, vbscript:, etc.)\n return undefined;\n}\n","import { Model } from '../core/model.js';\nimport type { NodeShape } from '../core/types.js';\nimport { nextId } from '../core/ids.js';\nimport {\n sanitizeLabel,\n MAX_NODES,\n MAX_EDGES,\n MAX_ACTORS,\n MAX_MESSAGES,\n MAX_IMPORT_LENGTH,\n} from '../core/sanitize.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: sanitizeLabel(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 let edgeCount = 0;\n\n const ensureNode = (id: string, group?: string) => {\n if (!nodeMap.has(id)) {\n if (nodeMap.size >= MAX_NODES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_NODES} nodes`);\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 )\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) {\n groupStack.push(subgraphOpen[1]!);\n continue;\n }\n if (/^end\\b/i.test(trimmed)) {\n groupStack.pop();\n continue;\n }\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 sanitizedLabel = label ? sanitizeLabel(label) : undefined;\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 if (nodeMap.size >= MAX_NODES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_NODES} nodes`);\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 if (nodeMap.size >= MAX_NODES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_NODES} nodes`);\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 if (edgeCount >= MAX_EDGES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_EDGES} edges`);\n edgeCount++;\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,\n to: toId,\n ...(sanitizedLabel ? { label: sanitizedLabel } : {}),\n style,\n ...(arrowhead === 'none' ? { arrowhead } : {}),\n });\n continue;\n }\n\n const nodeDecl = parseNodeDecl(trimmed);\n if (nodeDecl && !nodeMap.has(nodeDecl.id)) {\n if (nodeMap.size >= MAX_NODES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_NODES} nodes`);\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 let actorCount = 0;\n let messageCount = 0;\n\n const safeAddActor = (name: string) => {\n const safeName = sanitizeLabel(name);\n if (!model.toJSON().actors?.includes(safeName)) {\n if (actorCount >= MAX_ACTORS)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_ACTORS} actors`);\n actorCount++;\n }\n model.addActor(safeName);\n return safeName;\n };\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 safeAddActor(participantMatch[1]!.trim());\n continue;\n }\n\n const actorMatch = trimmed.match(/^actor\\s+(.+)$/i);\n if (actorMatch) {\n safeAddActor(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 = safeAddActor(msgMatch[1]!.trim());\n const arrow = msgMatch[2]!;\n const to = safeAddActor(msgMatch[3]!.trim());\n const label = sanitizeLabel(msgMatch[4]!.trim());\n if (messageCount >= MAX_MESSAGES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_MESSAGES} messages`);\n messageCount++;\n const messages = model.toJSON().messages ?? [];\n model.addMessage({\n id: nextId('m', messages),\n from,\n to,\n label,\n style: arrow.startsWith('--') ? 'dashed' : 'solid',\n });\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 if (mermaid.length > MAX_IMPORT_LENGTH) {\n throw new Error(`Import aborted: input exceeds the maximum of ${MAX_IMPORT_LENGTH} characters`);\n }\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';\nimport {\n sanitizeLabel,\n MAX_NODES,\n MAX_EDGES,\n MAX_ACTORS,\n MAX_MESSAGES,\n MAX_IMPORT_LENGTH,\n} from '../core/sanitize.js';\n\n/**\n * Deep-strip prototype-pollution keys (`__proto__`, `constructor`,\n * `prototype`) from any parsed JSON value before it enters the model.\n */\nfunction stripDangerousKeys(obj: unknown): unknown {\n if (Array.isArray(obj)) return obj.map(stripDangerousKeys);\n if (obj !== null && typeof obj === 'object') {\n const clean: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(obj)) {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue;\n clean[key] = stripDangerousKeys(val);\n }\n return clean;\n }\n return obj;\n}\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 * Validates the top-level structure and ensures nodes/edges contain only\n * expected shapes. All labels are sanitized to strip dangerous content.\n * Prototype-pollution keys are stripped from parsed JSON.\n * Resource limits are enforced to prevent browser-tab crashes.\n *\n * @throws If `json` is not a valid `DiagramModel` shape.\n */\nexport function fromJSON(json: string | DiagramModel): Model {\n if (typeof json === 'string' && json.length > MAX_IMPORT_LENGTH) {\n throw new Error(`Import aborted: input exceeds the maximum of ${MAX_IMPORT_LENGTH} characters`);\n }\n const raw = typeof json === 'string' ? JSON.parse(json) : json;\n const data = stripDangerousKeys(raw) as DiagramModel;\n\n // Structural validation\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n throw new Error('Invalid DiagramModel JSON: expected an object');\n }\n if (data.type !== 'flowchart' && data.type !== 'sequence') {\n throw new Error(`Invalid DiagramModel JSON: unknown type \"${data.type}\"`);\n }\n if (!Array.isArray(data.nodes) || !Array.isArray(data.edges)) {\n throw new Error('Invalid DiagramModel JSON: nodes and edges must be arrays');\n }\n\n // Resource limits\n if (data.nodes.length > MAX_NODES) {\n throw new Error(\n `Import aborted: diagram has ${data.nodes.length} nodes, maximum is ${MAX_NODES}`,\n );\n }\n if (data.edges.length > MAX_EDGES) {\n throw new Error(\n `Import aborted: diagram has ${data.edges.length} edges, maximum is ${MAX_EDGES}`,\n );\n }\n if (data.actors && data.actors.length > MAX_ACTORS) {\n throw new Error(\n `Import aborted: diagram has ${data.actors.length} actors, maximum is ${MAX_ACTORS}`,\n );\n }\n if (data.messages && data.messages.length > MAX_MESSAGES) {\n throw new Error(\n `Import aborted: diagram has ${data.messages.length} messages, maximum is ${MAX_MESSAGES}`,\n );\n }\n\n // Validate node shape (must have id + label at minimum)\n for (const node of data.nodes) {\n if (\n typeof node !== 'object' ||\n node === null ||\n typeof node.id !== 'string' ||\n typeof node.label !== 'string'\n ) {\n throw new Error('Invalid DiagramModel JSON: each node must have string id and label');\n }\n node.label = sanitizeLabel(node.label);\n }\n\n // Validate edge shape (must have id, from, to)\n for (const edge of data.edges) {\n if (\n typeof edge !== 'object' ||\n edge === null ||\n typeof edge.id !== 'string' ||\n typeof edge.from !== 'string' ||\n typeof edge.to !== 'string'\n ) {\n throw new Error('Invalid DiagramModel JSON: each edge must have string id, from, and to');\n }\n if (edge.label) edge.label = sanitizeLabel(edge.label);\n }\n\n // Sanitize sequence fields\n if (data.actors) {\n data.actors = data.actors.map((a) => (typeof a === 'string' ? sanitizeLabel(a) : a));\n }\n if (data.messages) {\n for (const msg of data.messages) {\n if (typeof msg === 'object' && msg !== null && typeof msg.label === 'string') {\n msg.label = sanitizeLabel(msg.label);\n }\n }\n }\n\n return Model.fromData(data);\n}\n"],"mappings":"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","names":["exportFlowchart","msgArrow","exportSequence","m"]}
1
+ {"version":3,"sources":["../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/core/sanitize.ts","../src/importers/mermaid.ts","../src/importers/json.ts"],"sourcesContent":["import type {\n DiagramModel,\n DiagramNode,\n DiagramEdge,\n DiagramType,\n DiagramVariant,\n SequenceMessage,\n ValidationError,\n} 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 = {\n type,\n ...(variant ? { variant } : {}),\n title,\n nodes: [],\n edges: [],\n actors: [],\n messages: [],\n };\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 const { __proto__, constructor, ...safe } = patch as Record<string, unknown>;\n Object.assign(node, safe);\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))\n errors.push({\n kind: 'duplicate-node-id',\n id: n.id,\n message: `Duplicate node id \"${n.id}\"`,\n });\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))\n errors.push({\n kind: 'duplicate-edge-id',\n id: e.id,\n message: `Duplicate edge id \"${e.id}\"`,\n });\n edgeIds.add(e.id);\n if (!nodeIds.has(e.from))\n errors.push({\n kind: 'dangling-from',\n id: e.id,\n message: `Edge \"${e.id}\" references unknown source node \"${e.from}\"`,\n });\n if (!nodeIds.has(e.to))\n errors.push({\n kind: 'dangling-to',\n id: e.id,\n message: `Edge \"${e.id}\" references unknown target node \"${e.to}\"`,\n });\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?.[1]) {\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':\n return ['<>', '<>'];\n case 'circle':\n return ['(', ')'];\n case 'parallelogram':\n return ['/', '/'];\n default:\n 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 =\n edge.style === 'dashed' ? '-[dashed]->' : edge.style === 'dotted' ? '-[dotted]->' : '-->';\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 =\n answers.reduce((s, a) => s + answerCardW(a), 0) +\n (answers.length - 1) * Q_CARD_PAD +\n 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 {\n x: number;\n y: number;\n w: number;\n h: number;\n}\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(\n (s) => typeof s.node.x === 'number' && typeof s.node.y === 'number',\n );\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) => {\n if (!layers.has(n.id)) layers.set(n.id, 0);\n });\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\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\n/**\n * Defence-in-depth sanitizer for SVG output. Strips dangerous patterns\n * before XML-escaping. Prevents script injection even if escapeXML were\n * somehow bypassed or if the SVG is consumed by a less-strict parser.\n */\nfunction sanitizeForSVG(s: string): string {\n let clean = s;\n // Strip HTML/XML tags (loop to handle nested constructions)\n // Requires letter or / after < to avoid matching plain text like \"x < y > z\"\n while (/<[a-zA-Z/][^>]{0,500}>/g.test(clean)) {\n clean = clean.replace(/<[a-zA-Z/][^>]{0,500}>/g, '');\n }\n // Strip javascript:/data:/vbscript: URIs (loop for incomplete multi-char sanitization)\n while (/\\b(?:javascript|data|vbscript)\\s*:/gi.test(clean)) {\n clean = clean.replace(/\\b(?:javascript|data|vbscript)\\s*:/gi, '');\n }\n // Strip on* event handlers (loop for incomplete multi-char sanitization)\n while (/\\bon[a-z]+\\s*=/gi.test(clean)) {\n clean = clean.replace(/\\bon[a-z]+\\s*=/gi, '');\n }\n // Strip null bytes\n // eslint-disable-next-line no-control-regex\n clean = clean.replace(/\\x00/g, '');\n return escapeXML(clean);\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}\">${sanitizeForSVG(node.label)}</text>`;\n\n let shapeEl: string;\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,\n y = box.y,\n w = box.w,\n h = box.h;\n const parts: string[] = [];\n\n // Card body\n parts.push(\n `<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\n // Header tint (clipped to top rounded corners)\n parts.push(\n `<defs><clipPath id=\"${clipId}\"><rect x=\"${x}\" y=\"${y}\" width=\"${w}\" height=\"${Q_BASE_H}\" rx=\"14\"/></clipPath></defs>`,\n );\n parts.push(\n `<rect x=\"${x}\" y=\"${y}\" width=\"${w}\" height=\"${Q_BASE_H}\" fill=\"${COLORS.amberSoft}\" clip-path=\"url(#${clipId})\"/>`,\n );\n\n // Amber left accent\n parts.push(\n `<rect x=\"${x}\" y=\"${y}\" width=\"4\" height=\"${Q_BASE_H}\" rx=\"2\" fill=\"${COLORS.amber}\"/>`,\n );\n\n // ? badge\n parts.push(\n `<rect x=\"${x + 12}\" y=\"${y + 14}\" width=\"28\" height=\"28\" rx=\"8\" fill=\"${COLORS.amber}\"/>`,\n );\n parts.push(\n `<text x=\"${x + 26}\" y=\"${y + 33}\" text-anchor=\"middle\" font-size=\"15\" font-weight=\"900\" fill=\"white\">?</text>`,\n );\n\n // QUESTION label + node label\n parts.push(\n `<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 );\n parts.push(\n `<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}\">${sanitizeForSVG(node.label)}</text>`,\n );\n\n // Divider\n parts.push(\n `<line x1=\"${x}\" y1=\"${y + Q_BASE_H}\" x2=\"${x + w}\" y2=\"${y + Q_BASE_H}\" stroke=\"${COLORS.amberLine}\" stroke-width=\"1\"/>`,\n );\n\n if (answers.length === 0) {\n parts.push(\n `<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 );\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(\n `<rect x=\"${cardX}\" y=\"${cardY}\" width=\"${cW}\" height=\"${cardH}\" rx=\"8\" fill=\"${COLORS.amberCardBg}\" stroke=\"${COLORS.amberLine}\" stroke-width=\"1\"/>`,\n );\n parts.push(\n `<rect x=\"${cx - 11}\" y=\"${cardY + 7}\" width=\"22\" height=\"22\" rx=\"6\" fill=\"#fef3c7\"/>`,\n );\n parts.push(\n `<text x=\"${cx}\" y=\"${cardY + 22}\" text-anchor=\"middle\" font-size=\"10\" font-weight=\"800\" fill=\"${COLORS.amber}\">${sanitizeForSVG(letter)}</text>`,\n );\n parts.push(\n `<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\">${sanitizeForSVG(displayAns)}</text>`,\n );\n });\n }\n\n return parts.join('');\n}\n\nfunction renderEdge(\n edge: DiagramEdge,\n boxes: Map<string, LayoutBox>,\n variant: DiagramModel['variant'],\n nodes: DiagramNode[],\n): 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 =\n edge.style === 'dashed'\n ? ' stroke-dasharray=\"6,4\"'\n : edge.style === 'dotted'\n ? ' stroke-dasharray=\"2,3\"'\n : '';\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}\">${sanitizeForSVG(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,\n 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}\">${sanitizeForSVG(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\n .map((n) => {\n const b = boxes.get(n.id)!;\n return isQuestion(n, model.variant) ? renderQuestionNode(n, b) : renderStandardNode(n, b);\n })\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(\n 'toPNG requires a browser environment. For Node/Bun server use, pipe toSVG() through @resvg/resvg-js.',\n );\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(\n (b) => (b ? resolve(b) : reject(new Error('Canvas toBlob failed'))),\n 'image/png',\n );\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('SVG image load failed'));\n };\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(\n from: string,\n to: string,\n options: Partial<Omit<DiagramEdge, 'id' | 'from' | 'to'>> = {},\n ): 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(\n from: string,\n to: string,\n label: string,\n options: Partial<Pick<SequenceMessage, 'style'>> = {},\n ): this {\n this.model.addActor(from);\n this.model.addActor(to);\n const messages = this.model.toJSON().messages ?? [];\n this.model.addMessage({\n id: nextId('m', messages),\n from,\n to,\n label,\n style: options.style ?? 'solid',\n });\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","/**\n * Centralized input sanitization for all user-provided text that flows\n * into SVG output, labels, or any rendering context.\n *\n * Defence-in-depth: even though `escapeXML()` prevents most injection,\n * stripping dangerous patterns at the source stops payloads from reaching\n * any downstream consumer (clipboard, third-party renderers, etc.).\n */\n\n/** Maximum characters allowed in a single label/text field. */\nexport const MAX_LABEL_LENGTH = 2000;\n\n/** Maximum number of nodes allowed in a single diagram. */\nexport const MAX_NODES = 500;\n\n/** Maximum number of edges allowed in a single diagram. */\nexport const MAX_EDGES = 2000;\n\n/** Maximum number of actors in a sequence diagram. */\nexport const MAX_ACTORS = 100;\n\n/** Maximum number of messages in a sequence diagram. */\nexport const MAX_MESSAGES = 2000;\n\n/** Maximum raw input length for importers (bytes). ~2 MB */\nexport const MAX_IMPORT_LENGTH = 2 * 1024 * 1024;\n\n/**\n * Strip dangerous content from user-supplied text. Removes:\n * - HTML tags (`<script>`, `<img>`, `<foreignObject>`, etc.)\n * - `javascript:`, `data:`, `vbscript:` URI schemes\n * - `on*` event handler attributes (onerror, onclick, etc.)\n * - Null bytes and other control characters\n */\nexport function sanitizeLabel(raw: string): string {\n let s = raw;\n // Remove null bytes and ASCII control chars (except \\n, \\r, \\t)\n // eslint-disable-next-line no-control-regex\n s = s.replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g, '');\n // Strip HTML/XML tags (loop to handle nested constructions)\n // Requires letter or / after < to avoid matching plain text like \"x < y > z\"\n while (/<[a-zA-Z/][^>]{0,500}>/g.test(s)) {\n s = s.replace(/<[a-zA-Z/][^>]{0,500}>/g, '');\n }\n // Strip javascript:/data:/vbscript: URIs (loop for incomplete multi-char sanitization)\n while (/\\b(?:javascript|data|vbscript)\\s*:/gi.test(s)) {\n s = s.replace(/\\b(?:javascript|data|vbscript)\\s*:/gi, '');\n }\n // Strip on* event handlers (loop for incomplete multi-char sanitization)\n while (/\\bon[a-z]+\\s*=/gi.test(s)) {\n s = s.replace(/\\bon[a-z]+\\s*=/gi, '');\n }\n // Enforce length limit\n if (s.length > MAX_LABEL_LENGTH) {\n s = s.slice(0, MAX_LABEL_LENGTH);\n }\n return s;\n}\n\n/**\n * Validate a URL is safe for use in href attributes.\n * Only allows http:, https:, and mailto: protocols.\n * Returns the URL if safe, or `undefined` if dangerous.\n */\nexport function sanitizeURL(url: string): string | undefined {\n const trimmed = url.trim();\n // Allow relative URLs (start with / or #)\n if (trimmed.startsWith('/') || trimmed.startsWith('#')) return trimmed;\n // Allow http(s) and mailto\n if (/^https?:\\/\\//i.test(trimmed) || /^mailto:/i.test(trimmed)) return trimmed;\n // Block everything else (javascript:, data:, vbscript:, etc.)\n return undefined;\n}\n","import { Model } from '../core/model.js';\nimport type { NodeShape } from '../core/types.js';\nimport { nextId } from '../core/ids.js';\nimport {\n sanitizeLabel,\n MAX_NODES,\n MAX_EDGES,\n MAX_ACTORS,\n MAX_MESSAGES,\n MAX_IMPORT_LENGTH,\n} from '../core/sanitize.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: sanitizeLabel(m[2]!.replace(/^[\"']|[\"']$/g, '')), shape };\n }\n return null;\n}\n\n// Mermaid flowchart edge connector: solid (-->, ---), dashed (-.->, -.-), or with labels.\n// Uses \\S+ for node IDs to prevent polynomial backtracking (no overlap with \\s*).\nconst EDGE_RE = /^(\\S+)\\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 let edgeCount = 0;\n\n const ensureNode = (id: string, group?: string) => {\n if (!nodeMap.has(id)) {\n if (nodeMap.size >= MAX_NODES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_NODES} nodes`);\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 )\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) {\n groupStack.push(subgraphOpen[1]!);\n continue;\n }\n if (/^end\\b/i.test(trimmed)) {\n groupStack.pop();\n continue;\n }\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 sanitizedLabel = label ? sanitizeLabel(label) : undefined;\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 if (nodeMap.size >= MAX_NODES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_NODES} nodes`);\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 if (nodeMap.size >= MAX_NODES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_NODES} nodes`);\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 if (edgeCount >= MAX_EDGES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_EDGES} edges`);\n edgeCount++;\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,\n to: toId,\n ...(sanitizedLabel ? { label: sanitizedLabel } : {}),\n style,\n ...(arrowhead === 'none' ? { arrowhead } : {}),\n });\n continue;\n }\n\n const nodeDecl = parseNodeDecl(trimmed);\n if (nodeDecl && !nodeMap.has(nodeDecl.id)) {\n if (nodeMap.size >= MAX_NODES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_NODES} nodes`);\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 let actorCount = 0;\n let messageCount = 0;\n\n const safeAddActor = (name: string) => {\n const safeName = sanitizeLabel(name);\n if (!model.toJSON().actors?.includes(safeName)) {\n if (actorCount >= MAX_ACTORS)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_ACTORS} actors`);\n actorCount++;\n }\n model.addActor(safeName);\n return safeName;\n };\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 safeAddActor(participantMatch[1]!.trim());\n continue;\n }\n\n const actorMatch = trimmed.match(/^actor\\s+(.+)$/i);\n if (actorMatch) {\n safeAddActor(actorMatch[1]!.trim());\n continue;\n }\n\n // Sequence message arrows: ->, ->>, -->, -->> (-- prefix = dashed)\n // Uses negated char classes to prevent polynomial backtracking.\n const msgMatch = trimmed.match(/^(\\w+)\\s*(-->>|->>|-->|->)\\s*(\\w+):\\s*(.+)$/);\n if (msgMatch) {\n const from = safeAddActor(msgMatch[1]!.trim());\n const arrow = msgMatch[2]!;\n const to = safeAddActor(msgMatch[3]!.trim());\n const label = sanitizeLabel(msgMatch[4]!.trim());\n if (messageCount >= MAX_MESSAGES)\n throw new Error(`Import aborted: diagram exceeds the maximum of ${MAX_MESSAGES} messages`);\n messageCount++;\n const messages = model.toJSON().messages ?? [];\n model.addMessage({\n id: nextId('m', messages),\n from,\n to,\n label,\n style: arrow.startsWith('--') ? 'dashed' : 'solid',\n });\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 if (mermaid.length > MAX_IMPORT_LENGTH) {\n throw new Error(`Import aborted: input exceeds the maximum of ${MAX_IMPORT_LENGTH} characters`);\n }\n // Strip mermaid.initialize(...) and similar JS-style config blocks that\n // sometimes appear in copy-pasted snippets. Uses [^)]* to avoid backtracking.\n const cleaned = mermaid.replace(/mermaid\\.initialize\\([^)]*\\)\\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';\nimport {\n sanitizeLabel,\n MAX_NODES,\n MAX_EDGES,\n MAX_ACTORS,\n MAX_MESSAGES,\n MAX_IMPORT_LENGTH,\n} from '../core/sanitize.js';\n\n/**\n * Deep-strip prototype-pollution keys (`__proto__`, `constructor`,\n * `prototype`) from any parsed JSON value before it enters the model.\n */\nfunction stripDangerousKeys(obj: unknown): unknown {\n if (Array.isArray(obj)) return obj.map(stripDangerousKeys);\n if (obj !== null && typeof obj === 'object') {\n const clean: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(obj)) {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue;\n clean[key] = stripDangerousKeys(val);\n }\n return clean;\n }\n return obj;\n}\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 * Validates the top-level structure and ensures nodes/edges contain only\n * expected shapes. All labels are sanitized to strip dangerous content.\n * Prototype-pollution keys are stripped from parsed JSON.\n * Resource limits are enforced to prevent browser-tab crashes.\n *\n * @throws If `json` is not a valid `DiagramModel` shape.\n */\nexport function fromJSON(json: string | DiagramModel): Model {\n if (typeof json === 'string' && json.length > MAX_IMPORT_LENGTH) {\n throw new Error(`Import aborted: input exceeds the maximum of ${MAX_IMPORT_LENGTH} characters`);\n }\n const raw = typeof json === 'string' ? JSON.parse(json) : json;\n const data = stripDangerousKeys(raw) as DiagramModel;\n\n // Structural validation\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n throw new Error('Invalid DiagramModel JSON: expected an object');\n }\n if (data.type !== 'flowchart' && data.type !== 'sequence') {\n throw new Error(`Invalid DiagramModel JSON: unknown type \"${data.type}\"`);\n }\n if (!Array.isArray(data.nodes) || !Array.isArray(data.edges)) {\n throw new Error('Invalid DiagramModel JSON: nodes and edges must be arrays');\n }\n\n // Resource limits\n if (data.nodes.length > MAX_NODES) {\n throw new Error(\n `Import aborted: diagram has ${data.nodes.length} nodes, maximum is ${MAX_NODES}`,\n );\n }\n if (data.edges.length > MAX_EDGES) {\n throw new Error(\n `Import aborted: diagram has ${data.edges.length} edges, maximum is ${MAX_EDGES}`,\n );\n }\n if (data.actors && data.actors.length > MAX_ACTORS) {\n throw new Error(\n `Import aborted: diagram has ${data.actors.length} actors, maximum is ${MAX_ACTORS}`,\n );\n }\n if (data.messages && data.messages.length > MAX_MESSAGES) {\n throw new Error(\n `Import aborted: diagram has ${data.messages.length} messages, maximum is ${MAX_MESSAGES}`,\n );\n }\n\n // Validate node shape (must have id + label at minimum)\n for (const node of data.nodes) {\n if (\n typeof node !== 'object' ||\n node === null ||\n typeof node.id !== 'string' ||\n typeof node.label !== 'string'\n ) {\n throw new Error('Invalid DiagramModel JSON: each node must have string id and label');\n }\n node.label = sanitizeLabel(node.label);\n }\n\n // Validate edge shape (must have id, from, to)\n for (const edge of data.edges) {\n if (\n typeof edge !== 'object' ||\n edge === null ||\n typeof edge.id !== 'string' ||\n typeof edge.from !== 'string' ||\n typeof edge.to !== 'string'\n ) {\n throw new Error('Invalid DiagramModel JSON: each edge must have string id, from, and to');\n }\n if (edge.label) edge.label = sanitizeLabel(edge.label);\n }\n\n // Sanitize sequence fields\n if (data.actors) {\n data.actors = data.actors.map((a) => (typeof a === 'string' ? sanitizeLabel(a) : a));\n }\n if (data.messages) {\n for (const msg of data.messages) {\n if (typeof msg === 'object' && msg !== null && typeof msg.label === 'string') {\n msg.label = sanitizeLabel(msg.label);\n }\n }\n }\n\n return Model.fromData(data);\n}\n"],"mappings":"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","names":["exportFlowchart","msgArrow","exportSequence","m"]}
package/dist/ui/index.cjs CHANGED
@@ -560,7 +560,7 @@ function nextId(prefix, existing) {
560
560
  let max = 0;
561
561
  for (const item of existing) {
562
562
  const match = re.exec(item.id);
563
- if (match) {
563
+ if (match?.[1]) {
564
564
  const n = parseInt(match[1], 10);
565
565
  if (n > max) max = n;
566
566
  }
@@ -1384,7 +1384,7 @@ function estimateW(text, pxPerChar = 7) {
1384
1384
  }
1385
1385
  function SequenceCanvas(props) {
1386
1386
  const {
1387
- model,
1387
+ model: _model,
1388
1388
  actors,
1389
1389
  messages,
1390
1390
  t,
@@ -1988,9 +1988,15 @@ function escapeXML(s2) {
1988
1988
  }
1989
1989
  function sanitizeForSVG(s2) {
1990
1990
  let clean = s2;
1991
- clean = clean.replace(/<\/?[a-zA-Z][^>]*>/g, "");
1992
- clean = clean.replace(/\b(?:javascript|data|vbscript)\s*:/gi, "");
1993
- clean = clean.replace(/\bon[a-z]+\s*=/gi, "");
1991
+ while (/<[a-zA-Z/][^>]{0,500}>/g.test(clean)) {
1992
+ clean = clean.replace(/<[a-zA-Z/][^>]{0,500}>/g, "");
1993
+ }
1994
+ while (/\b(?:javascript|data|vbscript)\s*:/gi.test(clean)) {
1995
+ clean = clean.replace(/\b(?:javascript|data|vbscript)\s*:/gi, "");
1996
+ }
1997
+ while (/\bon[a-z]+\s*=/gi.test(clean)) {
1998
+ clean = clean.replace(/\bon[a-z]+\s*=/gi, "");
1999
+ }
1994
2000
  clean = clean.replace(/\x00/g, "");
1995
2001
  return escapeXML(clean);
1996
2002
  }
@@ -2410,9 +2416,15 @@ var MAX_IMPORT_LENGTH = 2 * 1024 * 1024;
2410
2416
  function sanitizeLabel(raw) {
2411
2417
  let s2 = raw;
2412
2418
  s2 = s2.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
2413
- s2 = s2.replace(/<\/?[a-zA-Z][^>]*>/g, "");
2414
- s2 = s2.replace(/\b(?:javascript|data|vbscript)\s*:/gi, "");
2415
- s2 = s2.replace(/\bon[a-z]+\s*=/gi, "");
2419
+ while (/<[a-zA-Z/][^>]{0,500}>/g.test(s2)) {
2420
+ s2 = s2.replace(/<[a-zA-Z/][^>]{0,500}>/g, "");
2421
+ }
2422
+ while (/\b(?:javascript|data|vbscript)\s*:/gi.test(s2)) {
2423
+ s2 = s2.replace(/\b(?:javascript|data|vbscript)\s*:/gi, "");
2424
+ }
2425
+ while (/\bon[a-z]+\s*=/gi.test(s2)) {
2426
+ s2 = s2.replace(/\bon[a-z]+\s*=/gi, "");
2427
+ }
2416
2428
  if (s2.length > MAX_LABEL_LENGTH) {
2417
2429
  s2 = s2.slice(0, MAX_LABEL_LENGTH);
2418
2430
  }
@@ -2422,11 +2434,11 @@ function sanitizeLabel(raw) {
2422
2434
  // src/importers/mermaid.ts
2423
2435
  function parseNodeDecl(raw) {
2424
2436
  const patterns = [
2425
- [/^(\w+)\{\{?"?(.+?)"?\}?\}$/, "diamond"],
2426
- [/^(\w+)\(\("?(.+?)"?\)\)$/, "circle"],
2427
- [/^(\w+)\[\/(.+?)\/\]$/, "parallelogram"],
2428
- [/^(\w+)\[["']?(.+?)["']?\]$/, "rectangle"],
2429
- [/^(\w+)\("?(.+?)"?\)$/, "rectangle"]
2437
+ [/^(\w+)\{\{?"?([^}"]+)"?\}?\}$/, "diamond"],
2438
+ [/^(\w+)\(\("?([^)"]+)"?\)\)$/, "circle"],
2439
+ [/^(\w+)\[\/([^/\]]+)\/\]$/, "parallelogram"],
2440
+ [/^(\w+)\[["']?([^\]"']+)["']?\]$/, "rectangle"],
2441
+ [/^(\w+)\("?([^)"]+)"?\)$/, "rectangle"]
2430
2442
  ];
2431
2443
  for (const [re, shape] of patterns) {
2432
2444
  const m = raw.match(re);
@@ -2434,7 +2446,7 @@ function parseNodeDecl(raw) {
2434
2446
  }
2435
2447
  return null;
2436
2448
  }
2437
- var EDGE_RE = /^(.+?)\s*(-\.->|-\.-|-->|---)(?:\|(.+?)\|)?\s*(.+)$/;
2449
+ var EDGE_RE = /^(\S+)\s*(-\.->|-\.-|-->|---)(?:\|([^|]+)\|)?\s*(.+)$/;
2438
2450
  function detectStyle(connector) {
2439
2451
  return connector.startsWith("-.") ? "dashed" : "solid";
2440
2452
  }
@@ -2552,7 +2564,7 @@ function parseSequence(lines, title) {
2552
2564
  safeAddActor(actorMatch[1].trim());
2553
2565
  continue;
2554
2566
  }
2555
- const msgMatch = trimmed.match(/^(.+?)\s*(-->>|->>|-->|->)\s*(.+?):\s*(.+)$/);
2567
+ const msgMatch = trimmed.match(/^(\w+)\s*(-->>|->>|-->|->)\s*(\w+):\s*(.+)$/);
2556
2568
  if (msgMatch) {
2557
2569
  const from = safeAddActor(msgMatch[1].trim());
2558
2570
  const arrow = msgMatch[2];
@@ -2577,7 +2589,7 @@ function fromMermaid(mermaid) {
2577
2589
  if (mermaid.length > MAX_IMPORT_LENGTH) {
2578
2590
  throw new Error(`Import aborted: input exceeds the maximum of ${MAX_IMPORT_LENGTH} characters`);
2579
2591
  }
2580
- const cleaned = mermaid.replace(/mermaid\.initialize\([\s\S]*?\)\s*;?/g, "");
2592
+ const cleaned = mermaid.replace(/mermaid\.initialize\([^)]*\)\s*;?/g, "");
2581
2593
  const rawLines = cleaned.split("\n");
2582
2594
  let startIdx = 0;
2583
2595
  let title;
@@ -4807,7 +4819,7 @@ function DiagramCanvas(props) {
4807
4819
  acc,
4808
4820
  transform,
4809
4821
  setTransform,
4810
- selected,
4822
+ selected: _selected,
4811
4823
  selectedSet,
4812
4824
  hoveredId,
4813
4825
  setHoveredId,