@tldraw/mermaid 5.2.0-next.e2b8d10bf10e → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist-cjs/createMermaidDiagram.js +5 -5
- package/dist-cjs/createMermaidDiagram.js.map +3 -3
- package/dist-cjs/flowchartDiagram.js +7 -3
- package/dist-cjs/flowchartDiagram.js.map +2 -2
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/mindmapDiagram.js +1 -1
- package/dist-cjs/mindmapDiagram.js.map +2 -2
- package/dist-cjs/sequenceDiagram.js +20 -1
- package/dist-cjs/sequenceDiagram.js.map +2 -2
- package/dist-cjs/stateDiagram.js +7 -3
- package/dist-cjs/stateDiagram.js.map +2 -2
- package/dist-cjs/svgParsing.js +2 -2
- package/dist-cjs/svgParsing.js.map +2 -2
- package/dist-esm/createMermaidDiagram.mjs +1 -1
- package/dist-esm/createMermaidDiagram.mjs.map +2 -2
- package/dist-esm/flowchartDiagram.mjs +7 -3
- package/dist-esm/flowchartDiagram.mjs.map +2 -2
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/mindmapDiagram.mjs +1 -1
- package/dist-esm/mindmapDiagram.mjs.map +2 -2
- package/dist-esm/sequenceDiagram.mjs +20 -1
- package/dist-esm/sequenceDiagram.mjs.map +2 -2
- package/dist-esm/stateDiagram.mjs +7 -3
- package/dist-esm/stateDiagram.mjs.map +2 -2
- package/dist-esm/svgParsing.mjs +2 -2
- package/dist-esm/svgParsing.mjs.map +2 -2
- package/package.json +9 -6
- package/src/createMermaidDiagram.ts +7 -1
- package/src/flowchartDiagram.ts +8 -3
- package/src/layoutParsing.test.ts +71 -0
- package/src/mindmapDiagram.ts +1 -1
- package/src/sequenceDiagram.ts +19 -0
- package/src/stateDiagram.ts +10 -3
- package/src/svgParsing.test.ts +58 -0
- package/src/svgParsing.ts +6 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/sequenceDiagram.ts"],
|
|
4
|
-
"sourcesContent": ["import type { SequenceDB } from 'mermaid/dist/diagrams/sequence/sequenceDb.d.ts'\nimport type { Actor, Message } from 'mermaid/dist/diagrams/sequence/types.js'\nimport { TLArrowShapeArrowheadStyle, TLDefaultDashStyle } from 'tldraw'\nimport type {\n\tDiagramMermaidBlueprint,\n\tMermaidBlueprintEdge,\n\tMermaidBlueprintNode,\n\tMermaidBlueprintLineNode,\n} from './blueprint'\nimport { parseRgbToTldrawColor } from './colors'\nimport { getAccumulatedTranslate } from './svgParsing'\n\nexport interface SvgRect {\n\tx: number\n\ty: number\n\tw: number\n\th: number\n}\n\nexport interface ActorLayout {\n\tx: number\n\ty: number\n\tw: number\n\th: number\n\tbottomY: number\n}\n\nexport interface ParsedSequenceLayout {\n\tactorLayouts: ActorLayout[]\n\tnoteRects: SvgRect[]\n}\n\nconst LINETYPE = {\n\tSOLID: 0,\n\tDOTTED: 1,\n\tNOTE: 2,\n\tSOLID_CROSS: 3,\n\tDOTTED_CROSS: 4,\n\tSOLID_OPEN: 5,\n\tDOTTED_OPEN: 6,\n\tLOOP_START: 10,\n\tLOOP_END: 11,\n\tALT_START: 12,\n\tALT_ELSE: 13,\n\tALT_END: 14,\n\tOPT_START: 15,\n\tOPT_END: 16,\n\tACTIVE_START: 17,\n\tACTIVE_END: 18,\n\tPAR_START: 19,\n\tPAR_AND: 20,\n\tPAR_END: 21,\n\tRECT_START: 22,\n\tRECT_END: 23,\n\tSOLID_POINT: 24,\n\tDOTTED_POINT: 25,\n\tAUTONUMBER: 26,\n\tCRITICAL_START: 27,\n\tCRITICAL_OPTION: 28,\n\tCRITICAL_END: 29,\n\tBREAK_START: 30,\n\tBREAK_END: 31,\n\tPAR_OVER_START: 32,\n\tBIDIRECTIONAL_SOLID: 33,\n\tBIDIRECTIONAL_DOTTED: 34,\n} as const satisfies SequenceDB['LINETYPE']\n\nconst PLACEMENT = {\n\tLEFTOF: 0,\n\tRIGHTOF: 1,\n\tOVER: 2,\n} as const satisfies SequenceDB['PLACEMENT']\n\nconst signalTypes: number[] = [\n\tLINETYPE.SOLID,\n\tLINETYPE.DOTTED,\n\tLINETYPE.SOLID_CROSS,\n\tLINETYPE.DOTTED_CROSS,\n\tLINETYPE.SOLID_OPEN,\n\tLINETYPE.DOTTED_OPEN,\n\tLINETYPE.SOLID_POINT,\n\tLINETYPE.DOTTED_POINT,\n\tLINETYPE.BIDIRECTIONAL_SOLID,\n\tLINETYPE.BIDIRECTIONAL_DOTTED,\n]\n\nfunction isSignalMessage(type: number | undefined): boolean {\n\tif (type === undefined) return false\n\treturn signalTypes.includes(type)\n}\n\nfunction isNoteMessage(type: number | undefined): boolean {\n\treturn type === LINETYPE.NOTE\n}\n\nfunction isActiveStart(type: number | undefined): boolean {\n\treturn type === LINETYPE.ACTIVE_START\n}\n\nfunction isActiveEnd(type: number | undefined): boolean {\n\treturn type === LINETYPE.ACTIVE_END\n}\n\nfunction isAutonumber(type: number | undefined): boolean {\n\treturn type === LINETYPE.AUTONUMBER\n}\n\n/** Returns the fragment keyword (e.g. \"loop\", \"opt\") if this message starts a combined fragment, or null. */\nfunction getFragmentStartKeyword(type: number | undefined): string | null {\n\tif (type === undefined) return null\n\tif (type === LINETYPE.LOOP_START) return 'loop'\n\tif (type === LINETYPE.ALT_START) return 'alt'\n\tif (type === LINETYPE.OPT_START) return 'opt'\n\tif (type === LINETYPE.PAR_START) return 'par'\n\tif (type === LINETYPE.RECT_START) return 'rect'\n\tif (type === LINETYPE.CRITICAL_START) return 'critical'\n\tif (type === LINETYPE.BREAK_START) return 'break'\n\tif (type === LINETYPE.PAR_OVER_START) return 'par'\n\treturn null\n}\n\nfunction isFragmentEnd(type: number | undefined): boolean {\n\tif (type === undefined) return false\n\tconst endTypes: number[] = [\n\t\tLINETYPE.LOOP_END,\n\t\tLINETYPE.ALT_END,\n\t\tLINETYPE.OPT_END,\n\t\tLINETYPE.PAR_END,\n\t\tLINETYPE.RECT_END,\n\t\tLINETYPE.CRITICAL_END,\n\t\tLINETYPE.BREAK_END,\n\t]\n\treturn endTypes.includes(type)\n}\n\n/** Returns a keyword if this message is a section separator within a combined fragment, or null. */\nfunction getFragmentSeparatorKeyword(type: number | undefined): string | null {\n\tif (type === LINETYPE.ALT_ELSE) return 'else'\n\tif (type === LINETYPE.PAR_AND) return 'and'\n\tif (type === LINETYPE.CRITICAL_OPTION) return 'option'\n\treturn null\n}\n\n/** Map a Mermaid LINETYPE value to tldraw arrow props. */\nfunction mapLineTypeToArrowProps(type: number): {\n\tdash: TLDefaultDashStyle\n\tarrowheadEnd: TLArrowShapeArrowheadStyle\n} {\n\tswitch (type) {\n\t\tcase LINETYPE.SOLID:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'arrow' }\n\t\tcase LINETYPE.DOTTED:\n\t\t\treturn { dash: 'dotted', arrowheadEnd: 'arrow' }\n\t\tcase LINETYPE.SOLID_CROSS:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'bar' }\n\t\tcase LINETYPE.DOTTED_CROSS:\n\t\t\treturn { dash: 'dotted', arrowheadEnd: 'bar' }\n\t\tcase LINETYPE.SOLID_OPEN:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'none' }\n\t\tcase LINETYPE.DOTTED_OPEN:\n\t\t\treturn { dash: 'dotted', arrowheadEnd: 'none' }\n\t\tcase LINETYPE.SOLID_POINT:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'arrow' }\n\t\tcase LINETYPE.DOTTED_POINT:\n\t\t\treturn { dash: 'dotted', arrowheadEnd: 'arrow' }\n\t\tcase LINETYPE.BIDIRECTIONAL_SOLID:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'arrow' }\n\t\tcase LINETYPE.BIDIRECTIONAL_DOTTED:\n\t\t\treturn { dash: 'dotted', arrowheadEnd: 'arrow' }\n\t\tdefault:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'arrow' }\n\t}\n}\n\nfunction isBidirectional(type: number): boolean {\n\treturn type === LINETYPE.BIDIRECTIONAL_SOLID || type === LINETYPE.BIDIRECTIONAL_DOTTED\n}\n\nconst TARGET_ACTOR_SPACING = 300\nconst MIN_VERTICAL_GAP = 400\nconst FALLBACK_ACTOR_WIDTH = 200\nconst FALLBACK_ACTOR_HEIGHT = 70\nconst FALLBACK_ACTOR_SPACING = 100\nconst FALLBACK_EVENT_SPACING = 80\nconst FALLBACK_NOTE_WIDTH = 120\nconst FALLBACK_NOTE_HEIGHT = 50\nconst NOTE_PADDING = 5\n// tldraw's hand-drawn font is wider than Mermaid's default, so we estimate\n// the minimum note width from the label text to prevent wrapping.\nconst NOTE_CHAR_WIDTH = 11\nconst NOTE_TEXT_PADDING = 40\nconst FRAGMENT_PADDING_X = 30\nconst FRAGMENT_PADDING_TOP = 50\nconst FRAGMENT_PADDING_BOTTOM = 25\nconst ACTOR_PADDING_WIDTH = 30\nconst ACTOR_PADDING_HEIGHT = 10\nconst SELF_MSG_Y_OFFSET = 0.04\nconst SELF_MSG_BEND = -80\nconst ACTIVATION_BOX_WIDTH = 20\nconst ACTIVATION_NEST_OFFSET = 6\nconst ACTIVATION_PAD_RATIO = 0.15\nconst FRAGMENT_SECTION_LABEL_HEIGHT = 25\nconst FRAGMENT_SECTION_LABEL_PADDING = 5\n\ninterface FragmentSection {\n\ttitle: string\n\tfirstEventIndex: number\n}\n\ninterface OpenFragment {\n\tkeyword: string\n\tsections: FragmentSection[]\n\tfirstEventIndex: number\n\tactorKeys: Set<string>\n}\n\ninterface FragmentSpan extends OpenFragment {\n\tlastEventIndex: number\n}\n\ninterface ActivationSpan {\n\tparticipantKey: string\n\tstartEventIndex: number\n\tendEventIndex: number\n}\n\nfunction parseSvgRects(root: Element, selector: string): SvgRect[] {\n\tconst results: SvgRect[] = []\n\tfor (const rect of root.querySelectorAll(selector)) {\n\t\tconst ancestor = getAccumulatedTranslate(rect)\n\t\tconst x = parseFloat(rect.getAttribute('x') || '0')\n\t\tconst y = parseFloat(rect.getAttribute('y') || '0')\n\t\tconst w = parseFloat(rect.getAttribute('width') || '0')\n\t\tconst h = parseFloat(rect.getAttribute('height') || '0')\n\t\tif (w > 0 && h > 0) {\n\t\t\tresults.push({\n\t\t\t\tx: Number.isFinite(ancestor.x + x) ? ancestor.x + x : 0,\n\t\t\t\ty: Number.isFinite(ancestor.y + y) ? ancestor.y + y : 0,\n\t\t\t\tw,\n\t\t\t\th,\n\t\t\t})\n\t\t}\n\t}\n\treturn results\n}\n\n/**\n * Stick-figure (actor) participants use SVG <line> elements instead of <rect>.\n * We derive bounding rectangles from the min/max coordinates of each actor-man group.\n */\nfunction parseActorManRects(root: Element): SvgRect[] {\n\tconst results: SvgRect[] = []\n\tfor (const group of root.querySelectorAll('g.actor-man')) {\n\t\tconst ancestor = getAccumulatedTranslate(group)\n\t\tlet minX = Infinity\n\t\tlet minY = Infinity\n\t\tlet maxX = -Infinity\n\t\tlet maxY = -Infinity\n\t\tfor (const line of group.querySelectorAll('line')) {\n\t\t\tfor (const attr of ['x1', 'x2']) {\n\t\t\t\tconst coord = parseFloat(line.getAttribute(attr) || '0')\n\t\t\t\tif (coord < minX) minX = coord\n\t\t\t\tif (coord > maxX) maxX = coord\n\t\t\t}\n\t\t\tfor (const attr of ['y1', 'y2']) {\n\t\t\t\tconst coord = parseFloat(line.getAttribute(attr) || '0')\n\t\t\t\tif (coord < minY) minY = coord\n\t\t\t\tif (coord > maxY) maxY = coord\n\t\t\t}\n\t\t}\n\t\tif (Number.isFinite(minX) && Number.isFinite(minY)) {\n\t\t\tresults.push({\n\t\t\t\tx: ancestor.x + minX,\n\t\t\t\ty: ancestor.y + minY,\n\t\t\t\tw: maxX - minX || FALLBACK_ACTOR_WIDTH,\n\t\t\t\th: maxY - minY || FALLBACK_ACTOR_HEIGHT,\n\t\t\t})\n\t\t}\n\t}\n\treturn results\n}\n\nfunction computeActorLayouts(root: Element, actorCount: number, eventCount: number): ActorLayout[] {\n\tconst byX = (a: SvgRect, b: SvgRect) => a.x - b.x\n\tlet top = parseSvgRects(root, 'rect.actor-top').sort(byX)\n\tlet bottom = parseSvgRects(root, 'rect.actor-bottom').sort(byX)\n\n\tconst actorManRects = parseActorManRects(root).sort(byX)\n\tif (actorManRects.length > 0 && (top.length < actorCount || bottom.length < actorCount)) {\n\t\tconst midY =\n\t\t\ttop.length > 0 && bottom.length > 0\n\t\t\t\t? (Math.max(...top.map((r) => r.y + r.h)) + Math.min(...bottom.map((r) => r.y))) / 2\n\t\t\t\t: actorManRects.length >= 2\n\t\t\t\t\t? (actorManRects[0].y + actorManRects[actorManRects.length - 1].y) / 2\n\t\t\t\t\t: 0\n\t\tfor (const rect of actorManRects) {\n\t\t\tif (rect.y < midY) top.push(rect)\n\t\t\telse bottom.push(rect)\n\t\t}\n\t\ttop.sort(byX)\n\t\tbottom.sort(byX)\n\t}\n\n\tif (top.length < actorCount || bottom.length < actorCount) {\n\t\tconst all = parseSvgRects(root, 'rect[class*=\"actor\"]').sort((a, b) => a.y - b.y)\n\t\tif (all.length >= 2 * actorCount) {\n\t\t\tlet maxGap = 0\n\t\t\tlet splitAt = actorCount\n\t\t\tfor (let i = 1; i < all.length; i++) {\n\t\t\t\tconst gap = all[i].y - all[i - 1].y\n\t\t\t\tif (gap > maxGap) {\n\t\t\t\t\tmaxGap = gap\n\t\t\t\t\tsplitAt = i\n\t\t\t\t}\n\t\t\t}\n\t\t\ttop = all.slice(0, splitAt).sort(byX).slice(0, actorCount)\n\t\t\tbottom = all.slice(splitAt).sort(byX).slice(0, actorCount)\n\t\t} else {\n\t\t\ttop = []\n\t\t\tbottom = []\n\t\t}\n\t} else {\n\t\ttop = top.slice(0, actorCount)\n\t\tbottom = bottom.slice(0, actorCount)\n\t}\n\n\tif (actorManRects.length > 0) {\n\t\tconst actorManSet = new Set<SvgRect>(actorManRects)\n\t\tconst regularTops = top.filter((r) => !actorManSet.has(r))\n\t\tconst regularBottoms = bottom.filter((r) => !actorManSet.has(r))\n\t\tconst refHeight =\n\t\t\tregularTops.length > 0 ? Math.max(...regularTops.map((r) => r.h)) : FALLBACK_ACTOR_HEIGHT\n\t\tconst refWidth =\n\t\t\tregularTops.length > 0 ? Math.max(...regularTops.map((r) => r.w)) : FALLBACK_ACTOR_WIDTH\n\t\tconst refTopY = regularTops.length > 0 ? Math.min(...regularTops.map((r) => r.y)) : undefined\n\t\tconst refBottomEndY =\n\t\t\tregularBottoms.length > 0 ? Math.max(...regularBottoms.map((r) => r.y + r.h)) : undefined\n\n\t\tfor (const rect of top) {\n\t\t\tif (!actorManSet.has(rect)) continue\n\t\t\tconst centerY = rect.y + rect.h / 2\n\t\t\trect.h = refHeight\n\t\t\trect.w = Math.max(rect.w, refWidth)\n\t\t\trect.y = refTopY !== undefined ? refTopY : centerY - refHeight / 2\n\t\t}\n\t\tfor (const rect of bottom) {\n\t\t\tif (!actorManSet.has(rect)) continue\n\t\t\tconst centerY = rect.y + rect.h / 2\n\t\t\trect.h = refHeight\n\t\t\trect.w = Math.max(rect.w, refWidth)\n\t\t\trect.y = refBottomEndY !== undefined ? refBottomEndY - refHeight : centerY - refHeight / 2\n\t\t}\n\t}\n\n\tif (top.length >= actorCount && bottom.length >= actorCount) {\n\t\tconst svgCenters = top.map((r) => r.x + r.w / 2)\n\t\tconst spacings: number[] = []\n\t\tfor (let i = 1; i < svgCenters.length; i++) {\n\t\t\tspacings.push(svgCenters[i] - svgCenters[i - 1])\n\t\t}\n\t\tconst minSpacing = spacings.length > 0 ? Math.min(...spacings) : 1\n\t\tconst scale = Math.max(1, TARGET_ACTOR_SPACING / minSpacing)\n\n\t\tconst xCenters = svgCenters.map((c) => (c - svgCenters[0]) * scale)\n\t\tconst totalSpan = xCenters.length > 1 ? xCenters[xCenters.length - 1] : 0\n\n\t\tconst topRowBottom = Math.max(...top.map((r) => r.y + r.h))\n\t\tconst bottomRowTop = Math.min(...bottom.map((r) => r.y))\n\t\tconst yStretch = Math.max(0, MIN_VERTICAL_GAP - (bottomRowTop - topRowBottom))\n\t\tconst topMinY = Math.min(...top.map((r) => r.y))\n\t\tconst bottomMaxY = Math.max(...bottom.map((r) => r.y + r.h))\n\t\tconst originY = -(bottomMaxY + yStretch + topMinY) / 2\n\n\t\treturn top.map((topRect, i) => {\n\t\t\tconst w = topRect.w + ACTOR_PADDING_WIDTH\n\t\t\tconst h = topRect.h + ACTOR_PADDING_HEIGHT\n\t\t\treturn {\n\t\t\t\tx: xCenters[i] - totalSpan / 2 - w / 2,\n\t\t\t\ty: originY + topRect.y,\n\t\t\t\tw,\n\t\t\t\th,\n\t\t\t\tbottomY: originY + bottom[i].y + yStretch,\n\t\t\t}\n\t\t})\n\t}\n\n\tconst fallbackLifelineHeight = Math.max(300, eventCount * FALLBACK_EVENT_SPACING)\n\tconst totalWidth = actorCount * FALLBACK_ACTOR_WIDTH + (actorCount - 1) * FALLBACK_ACTOR_SPACING\n\tconst totalHeight = FALLBACK_ACTOR_HEIGHT * 2 + fallbackLifelineHeight\n\tconst startX = -totalWidth / 2\n\tconst startY = -totalHeight / 2\n\treturn Array.from({ length: actorCount }, (_, i) => ({\n\t\tx: startX + i * (FALLBACK_ACTOR_WIDTH + FALLBACK_ACTOR_SPACING),\n\t\ty: startY,\n\t\tw: FALLBACK_ACTOR_WIDTH,\n\t\th: FALLBACK_ACTOR_HEIGHT,\n\t\tbottomY: startY + totalHeight - FALLBACK_ACTOR_HEIGHT,\n\t}))\n}\n\nfunction getMessageLabel(msg: Message): string | undefined {\n\treturn typeof msg.message === 'string' ? msg.message : undefined\n}\n\n/** Count how many renderable events (signals + notes) a message list contains. */\nexport function countSequenceEvents(messages: Message[]): number {\n\tlet count = 0\n\tfor (const msg of messages) {\n\t\tif (isAutonumber(msg.type)) continue\n\t\tif (getFragmentStartKeyword(msg.type)) continue\n\t\tif (isFragmentEnd(msg.type)) continue\n\t\tif (getFragmentSeparatorKeyword(msg.type)) continue\n\t\tif (isActiveStart(msg.type) || isActiveEnd(msg.type)) continue\n\t\tconst isEvent =\n\t\t\t(isSignalMessage(msg.type) && msg.from && msg.to) || (isNoteMessage(msg.type) && msg.from)\n\t\tif (isEvent) count++\n\t}\n\treturn count\n}\n\n/** Parse sequence-diagram SVG layout data for use by {@link sequenceToBlueprint}. */\nexport function parseSequenceLayout(\n\troot: Element,\n\tactorCount: number,\n\teventCount: number\n): ParsedSequenceLayout {\n\treturn {\n\t\tactorLayouts: computeActorLayouts(root, actorCount, eventCount),\n\t\tnoteRects: parseSvgRects(root, 'rect.note'),\n\t}\n}\n\n/**\n * Build a complete blueprint for a sequence diagram:\n * top actors, lifelines, bottom actors, fragments, notes, and signal edges.\n */\nexport function sequenceToBlueprint(\n\tlayout: ParsedSequenceLayout,\n\tactors: Map<string, Actor>,\n\tactorKeys: string[],\n\tmessages: Message[],\n\tcreatedActors: Map<string, number> = new Map(),\n\tdestroyedActors: Map<string, number> = new Map()\n): DiagramMermaidBlueprint {\n\tconst actorCount = actorKeys.length\n\tconst keyIndex = new Map(actorKeys.map((key, i) => [key, i]))\n\n\tconst fragments: FragmentSpan[] = []\n\tconst fragmentStack: OpenFragment[] = []\n\tconst events: Message[] = []\n\tconst activationStack = new Map<string, number[]>()\n\tconst activationSpans: ActivationSpan[] = []\n\n\tlet autonumberStart = 0\n\tlet autonumberStep = 0\n\tlet autonumberVisible = false\n\n\tfor (const msg of messages) {\n\t\tif (isAutonumber(msg.type)) {\n\t\t\tautonumberStart = 1\n\t\t\tautonumberStep = 1\n\t\t\tautonumberVisible = true\n\t\t\tcontinue\n\t\t}\n\n\t\tconst keyword = getFragmentStartKeyword(msg.type)\n\t\tif (keyword) {\n\t\t\tfragmentStack.push({\n\t\t\t\tkeyword,\n\t\t\t\tsections: [{ title: getMessageLabel(msg) ?? '', firstEventIndex: events.length }],\n\t\t\t\tfirstEventIndex: events.length,\n\t\t\t\tactorKeys: new Set(),\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isFragmentEnd(msg.type)) {\n\t\t\tconst frag = fragmentStack.pop()\n\t\t\tif (frag) fragments.push({ ...frag, lastEventIndex: events.length - 1 })\n\t\t\tcontinue\n\t\t}\n\n\t\tif (getFragmentSeparatorKeyword(msg.type)) {\n\t\t\tconst current = fragmentStack[fragmentStack.length - 1]\n\t\t\tif (current) {\n\t\t\t\tcurrent.sections.push({\n\t\t\t\t\ttitle: getMessageLabel(msg) ?? '',\n\t\t\t\t\tfirstEventIndex: events.length,\n\t\t\t\t})\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isActiveStart(msg.type)) {\n\t\t\tconst key = msg.from ?? msg.to\n\t\t\tif (key) {\n\t\t\t\tif (!activationStack.has(key)) activationStack.set(key, [])\n\t\t\t\t// Explicit `activate` follows the triggering arrow,\n\t\t\t\t// so the activation starts at the previous event.\n\t\t\t\tactivationStack.get(key)!.push(Math.max(0, events.length - 1))\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isActiveEnd(msg.type)) {\n\t\t\tconst key = msg.from ?? msg.to\n\t\t\tif (key) {\n\t\t\t\tconst startIdx = activationStack.get(key)?.pop()\n\t\t\t\tif (startIdx !== undefined) {\n\t\t\t\t\tactivationSpans.push({\n\t\t\t\t\t\tparticipantKey: key,\n\t\t\t\t\t\tstartEventIndex: startIdx,\n\t\t\t\t\t\tendEventIndex: Math.max(events.length - 1, startIdx),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tconst isEvent =\n\t\t\t(isSignalMessage(msg.type) && msg.from && msg.to) || (isNoteMessage(msg.type) && msg.from)\n\t\tif (!isEvent) continue\n\n\t\tfor (const frag of fragmentStack) {\n\t\t\tif (msg.from) frag.actorKeys.add(msg.from)\n\t\t\tif (msg.to) frag.actorKeys.add(msg.to)\n\t\t}\n\t\tevents.push(msg)\n\t}\n\n\tconst layouts = layout.actorLayouts\n\n\t// Pre-compute lifecycle event indices for created/destroyed actors.\n\t// We scan events for the first signal targeting each created actor\n\t// and the first signal from each destroyed actor.\n\tconst creationEventIndex = new Map<string, number>()\n\tconst destructionEventIndex = new Map<string, number>()\n\tfor (let i = 0; i < events.length; i++) {\n\t\tconst ev = events[i]\n\t\tif (!isSignalMessage(ev.type)) continue\n\n\t\tif (ev.to && createdActors.has(ev.to) && !creationEventIndex.has(ev.to)) {\n\t\t\tcreationEventIndex.set(ev.to, i)\n\t\t}\n\t\tif (ev.from && destroyedActors.has(ev.from) && !destructionEventIndex.has(ev.from)) {\n\t\t\tdestructionEventIndex.set(ev.from, i)\n\t\t}\n\t}\n\n\t// Build blueprint\n\tconst svgNoteRects = layout.noteRects\n\tlet svgNoteIndex = 0\n\tconst nodes: MermaidBlueprintNode[] = []\n\tconst lines: MermaidBlueprintLineNode[] = []\n\tconst edges: MermaidBlueprintEdge[] = []\n\n\tconst { y: firstY, h: firstH, bottomY: firstBottomY } = layouts[0]\n\tconst lifelineTop = firstY + firstH\n\tconst eventStep = (firstBottomY - lifelineTop) / (events.length + 1)\n\n\t// --- Z-order: lifelines -> activations -> fragments -> actor boxes -> notes/arrows ---\n\n\t// 1. Lifelines (behind everything)\n\tfor (let i = 0; i < actorCount; i++) {\n\t\tconst key = actorKeys[i]\n\t\tconst { x, y, w, h, bottomY } = layouts[i]\n\n\t\tconst isCreated = creationEventIndex.has(key)\n\t\tconst isDestroyed = destructionEventIndex.has(key)\n\t\tconst eventY = isCreated ? lifelineTop + eventStep * (creationEventIndex.get(key)! + 1) : 0\n\t\tconst topY = isCreated ? eventY + h / 2 : y + h\n\t\tconst botY = isDestroyed\n\t\t\t? lifelineTop + eventStep * (destructionEventIndex.get(key)! + 1)\n\t\t\t: bottomY\n\n\t\tconst lifelineHeight = botY - topY\n\t\tif (lifelineHeight > 0) {\n\t\t\tlines.push({ id: `lifeline-${key}`, x: x + w / 2, y: topY, endY: lifelineHeight })\n\t\t}\n\t}\n\n\t// 2. Activation boxes (just after lifelines)\n\tconst activationPad = eventStep * ACTIVATION_PAD_RATIO\n\tconst sortedSpans = activationSpans\n\t\t.map((span, origIdx) => ({ ...span, origIdx }))\n\t\t.sort((a, b) => {\n\t\t\tconst sizeA = a.endEventIndex - a.startEventIndex\n\t\t\tconst sizeB = b.endEventIndex - b.startEventIndex\n\t\t\treturn sizeB - sizeA || a.origIdx - b.origIdx\n\t\t})\n\n\tfor (let i = 0; i < sortedSpans.length; i++) {\n\t\tconst span = sortedSpans[i]\n\t\tconst actorIdx = keyIndex.get(span.participantKey)\n\t\tif (actorIdx === undefined) continue\n\n\t\tconst spanSize = span.endEventIndex - span.startEventIndex\n\t\tlet depth = 0\n\t\tfor (const other of sortedSpans) {\n\t\t\tif (other === span) continue\n\t\t\tconst sameParticipant = other.participantKey === span.participantKey\n\t\t\tconst containsSpan =\n\t\t\t\tother.startEventIndex <= span.startEventIndex && other.endEventIndex >= span.endEventIndex\n\t\t\tconst strictlyLarger = other.endEventIndex - other.startEventIndex > spanSize\n\t\t\tif (sameParticipant && containsSpan && strictlyLarger) depth++\n\t\t}\n\n\t\tconst layout = layouts[actorIdx]\n\t\tconst lifelineCenterX = layout.x + layout.w / 2\n\t\tconst boxTop = lifelineTop + eventStep * (span.startEventIndex + 1) - activationPad\n\t\tconst boxBottom = lifelineTop + eventStep * (span.endEventIndex + 1) + activationPad\n\n\t\tconst id = `activation-${span.origIdx}`\n\t\tconst kind = 'sequence_activation'\n\t\tnodes.push({\n\t\t\tid,\n\t\t\tkind,\n\t\t\tx: lifelineCenterX - ACTIVATION_BOX_WIDTH / 2 + depth * ACTIVATION_NEST_OFFSET,\n\t\t\ty: boxTop,\n\t\t\tw: ACTIVATION_BOX_WIDTH,\n\t\t\th: boxBottom - boxTop,\n\t\t\tfill: 'solid',\n\t\t\tcolor: 'light-violet',\n\t\t\tsize: 's',\n\t\t})\n\t}\n\n\t// 3. Fragments\n\tfor (let fragmentIndex = 0; fragmentIndex < fragments.length; fragmentIndex++) {\n\t\tconst fragment = fragments[fragmentIndex]\n\t\tif (fragment.lastEventIndex < fragment.firstEventIndex) continue\n\n\t\tconst fragTop = lifelineTop + eventStep * (fragment.firstEventIndex + 1) - FRAGMENT_PADDING_TOP\n\t\tconst fragBottom =\n\t\t\tlifelineTop + eventStep * (fragment.lastEventIndex + 1) + FRAGMENT_PADDING_BOTTOM\n\t\tconst indices = [...fragment.actorKeys].map((k) => keyIndex.get(k)!).filter((idx) => idx >= 0)\n\t\tif (indices.length === 0) continue\n\n\t\tconst minIndex = Math.min(...indices)\n\t\tconst maxIndex = Math.max(...indices)\n\t\tconst leftX = layouts[minIndex].x - FRAGMENT_PADDING_X\n\t\tconst fragW = layouts[maxIndex].x + layouts[maxIndex].w + FRAGMENT_PADDING_X - leftX\n\t\tconst fragH = fragBottom - fragTop\n\n\t\tconst rgbColor =\n\t\t\tfragment.keyword === 'rect' ? parseRgbToTldrawColor(fragment.sections[0].title) : null\n\t\tconst fragId = `fragment-${fragmentIndex}`\n\t\tconst fragKind = 'sequence_fragment'\n\t\tif (rgbColor) {\n\t\t\tnodes.push({\n\t\t\t\tid: fragId,\n\t\t\t\tkind: fragKind,\n\t\t\t\tx: leftX,\n\t\t\t\ty: fragTop,\n\t\t\t\tw: fragW,\n\t\t\t\th: fragH,\n\t\t\t\tfill: rgbColor.hasAlpha ? 'semi' : 'solid',\n\t\t\t\tcolor: rgbColor.color,\n\t\t\t\tsize: 's',\n\t\t\t})\n\t\t} else {\n\t\t\tnodes.push({\n\t\t\t\tid: fragId,\n\t\t\t\tkind: fragKind,\n\t\t\t\tx: leftX,\n\t\t\t\ty: fragTop,\n\t\t\t\tw: fragW,\n\t\t\t\th: fragH,\n\t\t\t\tdash: 'dashed',\n\t\t\t\tfill: 'none',\n\t\t\t\tcolor: 'light-blue',\n\t\t\t\tsize: 's',\n\t\t\t\talign: 'start',\n\t\t\t\tverticalAlign: 'start',\n\t\t\t\tlabel: `${fragment.keyword} [${fragment.sections[0].title}]`,\n\t\t\t})\n\n\t\t\tfor (let s = 1; s < fragment.sections.length; s++) {\n\t\t\t\tconst section = fragment.sections[s]\n\t\t\t\tconst sepY = lifelineTop + eventStep * (section.firstEventIndex + 0.5)\n\n\t\t\t\tlines.push({\n\t\t\t\t\tid: `fragment-${fragmentIndex}-sep-${s}`,\n\t\t\t\t\tx: leftX,\n\t\t\t\t\ty: sepY,\n\t\t\t\t\tendX: fragW,\n\t\t\t\t\tendY: 0,\n\t\t\t\t\tdash: 'dashed',\n\t\t\t\t\tcolor: 'light-blue',\n\t\t\t\t\tsize: 's',\n\t\t\t\t})\n\n\t\t\t\tconst secId = `fragment-${fragmentIndex}-section-${s}`\n\t\t\t\tconst secKind = 'sequence_fragment_section'\n\t\t\t\tnodes.push({\n\t\t\t\t\tid: secId,\n\t\t\t\t\tkind: secKind,\n\t\t\t\t\tx: leftX + FRAGMENT_SECTION_LABEL_PADDING,\n\t\t\t\t\ty: sepY + FRAGMENT_SECTION_LABEL_PADDING,\n\t\t\t\t\tw: fragW - FRAGMENT_SECTION_LABEL_PADDING * 2,\n\t\t\t\t\th: FRAGMENT_SECTION_LABEL_HEIGHT,\n\t\t\t\t\tfill: 'none',\n\t\t\t\t\tdash: 'dashed',\n\t\t\t\t\tcolor: 'light-blue',\n\t\t\t\t\tsize: 's',\n\t\t\t\t\talign: 'start',\n\t\t\t\t\tverticalAlign: 'start',\n\t\t\t\t\tlabel: `[${section.title}]`,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\t// 4. Actor boxes (top and bottom)\n\tfor (let i = 0; i < actorCount; i++) {\n\t\tconst key = actorKeys[i]\n\t\tconst actor = actors.get(key)\n\t\tif (!actor) continue\n\t\tconst { x, y, w, h, bottomY } = layouts[i]\n\t\tconst isCreated = creationEventIndex.has(key)\n\t\tconst isDestroyed = destructionEventIndex.has(key)\n\t\tconst kind = actor.type\n\t\tconst label = actor.description || actor.name || key\n\t\tconst shared = {\n\t\t\tkind,\n\t\t\tlabel,\n\t\t\talign: 'middle' as const,\n\t\t\tverticalAlign: 'middle' as const,\n\t\t\tsize: 's' as const,\n\t\t}\n\n\t\tconst creationY = isCreated ? lifelineTop + eventStep * (creationEventIndex.get(key)! + 1) : 0\n\t\tconst topY = isCreated ? creationY - h / 2 : y\n\t\tconst topId = `actor-top-${key}`\n\t\tnodes.push({\n\t\t\tid: topId,\n\t\t\tx,\n\t\t\ty: topY,\n\t\t\tw,\n\t\t\th,\n\t\t\t...shared,\n\t\t})\n\n\t\tif (!isDestroyed) {\n\t\t\tconst botId = `actor-bottom-${key}`\n\t\t\tnodes.push({\n\t\t\t\tid: botId,\n\t\t\t\tx,\n\t\t\t\ty: bottomY,\n\t\t\t\tw,\n\t\t\t\th,\n\t\t\t\t...shared,\n\t\t\t})\n\t\t}\n\t}\n\n\t// 5. Events: signals and notes\n\tconst pendingCreations = new Set(createdActors.keys())\n\tlet sequenceNumber = autonumberStart\n\n\tfor (let eventIndex = 0; eventIndex < events.length; eventIndex++) {\n\t\tconst msg = events[eventIndex]\n\t\tconst anchor = (eventIndex + 1) / (events.length + 1)\n\n\t\tif (isSignalMessage(msg.type)) {\n\t\t\tconst fromKey = msg.from!\n\t\t\tconst toKey = msg.to!\n\t\t\tif (!keyIndex.has(fromKey) || !keyIndex.has(toKey)) continue\n\n\t\t\tconst isCreationMessage = pendingCreations.has(toKey)\n\t\t\tif (isCreationMessage) pendingCreations.delete(toKey)\n\n\t\t\tconst msgType = msg.type ?? LINETYPE.SOLID\n\t\t\tconst { dash, arrowheadEnd } = mapLineTypeToArrowProps(msgType)\n\t\t\tconst isSelf = fromKey === toKey\n\t\t\tconst bidir = !isSelf && isBidirectional(msgType)\n\n\t\t\tconst edge: MermaidBlueprintEdge = {\n\t\t\t\tstartNodeId: `lifeline-${fromKey}`,\n\t\t\t\tendNodeId: isCreationMessage ? `actor-top-${toKey}` : `lifeline-${toKey}`,\n\t\t\t\tlabel: getMessageLabel(msg),\n\t\t\t\tbend: isSelf ? SELF_MSG_BEND : 0,\n\t\t\t\tdash,\n\t\t\t\tarrowheadEnd,\n\t\t\t\tarrowheadStart: bidir ? 'arrow' : 'none',\n\t\t\t\tsize: 's',\n\t\t\t\tanchorStartY: isSelf ? anchor - SELF_MSG_Y_OFFSET : anchor,\n\t\t\t\tanchorEndY: isCreationMessage ? 0.5 : isSelf ? anchor + SELF_MSG_Y_OFFSET : anchor,\n\t\t\t\tisExact: true,\n\t\t\t\tisPrecise: true,\n\t\t\t\t...(isCreationMessage && { isExactEnd: false, isPreciseEnd: false }),\n\t\t\t}\n\n\t\t\tif (autonumberVisible) {\n\t\t\t\tedge.decoration = { type: 'autonumber', value: String(sequenceNumber) }\n\t\t\t\tsequenceNumber += autonumberStep\n\t\t\t}\n\n\t\t\tedges.push(edge)\n\t\t} else if (isNoteMessage(msg.type)) {\n\t\t\tconst eventY = lifelineTop + eventStep * (eventIndex + 1)\n\t\t\tconst fromKey = msg.from!\n\t\t\tconst fromIdx = keyIndex.get(fromKey)\n\t\t\tconst toIdx = keyIndex.get(msg.to ?? fromKey)\n\t\t\tif (fromIdx === undefined) continue\n\n\t\t\tconst label = getMessageLabel(msg)\n\t\t\t// Mermaid types `placement` as a string enum but the runtime value is numeric\n\t\t\tconst msgPlacement = msg.placement as unknown as number | undefined\n\t\t\tconst fromCenterX = layouts[fromIdx].x + layouts[fromIdx].w / 2\n\t\t\tconst toCenterX = toIdx !== undefined ? layouts[toIdx].x + layouts[toIdx].w / 2 : fromCenterX\n\t\t\tconst isSpanning =\n\t\t\t\tmsgPlacement === PLACEMENT.OVER && msg.from !== msg.to && toIdx !== undefined\n\n\t\t\tconst svgNote = svgNoteRects[svgNoteIndex++]\n\t\t\tconst noteHeight = svgNote?.h ?? FALLBACK_NOTE_HEIGHT\n\t\t\tconst textWidth = label ? label.length * NOTE_CHAR_WIDTH + NOTE_TEXT_PADDING : 0\n\t\t\tconst baseWidth = Math.max(svgNote?.w ?? FALLBACK_NOTE_WIDTH, textWidth)\n\t\t\tconst noteWidth = isSpanning\n\t\t\t\t? Math.max(baseWidth, Math.abs(toCenterX - fromCenterX) + NOTE_PADDING)\n\t\t\t\t: baseWidth\n\n\t\t\tlet noteX: number\n\t\t\tif (msgPlacement === PLACEMENT.LEFTOF) {\n\t\t\t\tnoteX = fromCenterX - noteWidth - NOTE_PADDING\n\t\t\t} else if (msgPlacement === PLACEMENT.RIGHTOF) {\n\t\t\t\tnoteX = fromCenterX + NOTE_PADDING\n\t\t\t} else if (isSpanning) {\n\t\t\t\tnoteX = (fromCenterX + toCenterX) / 2 - noteWidth / 2\n\t\t\t} else {\n\t\t\t\tnoteX = fromCenterX - noteWidth / 2\n\t\t\t}\n\n\t\t\tconst noteId = `note-${eventIndex}`\n\t\t\tconst noteKind = 'sequence_note'\n\t\t\tnodes.push({\n\t\t\t\tid: noteId,\n\t\t\t\tkind: noteKind,\n\t\t\t\tx: noteX,\n\t\t\t\ty: eventY - noteHeight / 2,\n\t\t\t\tw: noteWidth,\n\t\t\t\th: noteHeight,\n\t\t\t\tfill: 'solid',\n\t\t\t\tcolor: 'yellow',\n\t\t\t\tdash: 'draw',\n\t\t\t\tsize: 's',\n\t\t\t\talign: 'middle',\n\t\t\t\tverticalAlign: 'middle',\n\t\t\t\tlabel,\n\t\t\t})\n\t\t}\n\t}\n\n\treturn {\n\t\tdiagramKind: 'sequence',\n\t\tnodes,\n\t\tedges,\n\t\tlines,\n\t\tgroups: actorKeys.map((key) => {\n\t\t\tconst group = [`actor-top-${key}`, `lifeline-${key}`]\n\t\t\tif (!destructionEventIndex.has(key)) {\n\t\t\t\tgroup.push(`actor-bottom-${key}`)\n\t\t\t}\n\t\t\treturn group\n\t\t}),\n\t}\n}\n"],
|
|
5
|
-
"mappings": "AASA,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AAsBxC,MAAM,WAAW;AAAA,EAChB,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS;AAAA,EACT,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,aAAa;AAAA,EACb,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,sBAAsB;AACvB;AAEA,MAAM,YAAY;AAAA,EACjB,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AACP;AAEA,MAAM,cAAwB;AAAA,EAC7B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AACV;AAEA,SAAS,gBAAgB,MAAmC;AAC3D,MAAI,SAAS,OAAW,QAAO;AAC/B,SAAO,YAAY,SAAS,IAAI;AACjC;AAEA,SAAS,cAAc,MAAmC;AACzD,SAAO,SAAS,SAAS;AAC1B;AAEA,SAAS,cAAc,MAAmC;AACzD,SAAO,SAAS,SAAS;AAC1B;AAEA,SAAS,YAAY,MAAmC;AACvD,SAAO,SAAS,SAAS;AAC1B;AAEA,SAAS,aAAa,MAAmC;AACxD,SAAO,SAAS,SAAS;AAC1B;AAGA,SAAS,wBAAwB,MAAyC;AACzE,MAAI,SAAS,OAAW,QAAO;AAC/B,MAAI,SAAS,SAAS,WAAY,QAAO;AACzC,MAAI,SAAS,SAAS,UAAW,QAAO;AACxC,MAAI,SAAS,SAAS,UAAW,QAAO;AACxC,MAAI,SAAS,SAAS,UAAW,QAAO;AACxC,MAAI,SAAS,SAAS,WAAY,QAAO;AACzC,MAAI,SAAS,SAAS,eAAgB,QAAO;AAC7C,MAAI,SAAS,SAAS,YAAa,QAAO;AAC1C,MAAI,SAAS,SAAS,eAAgB,QAAO;AAC7C,SAAO;AACR;AAEA,SAAS,cAAc,MAAmC;AACzD,MAAI,SAAS,OAAW,QAAO;AAC/B,QAAM,WAAqB;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACV;AACA,SAAO,SAAS,SAAS,IAAI;AAC9B;AAGA,SAAS,4BAA4B,MAAyC;AAC7E,MAAI,SAAS,SAAS,SAAU,QAAO;AACvC,MAAI,SAAS,SAAS,QAAS,QAAO;AACtC,MAAI,SAAS,SAAS,gBAAiB,QAAO;AAC9C,SAAO;AACR;AAGA,SAAS,wBAAwB,MAG/B;AACD,UAAQ,MAAM;AAAA,IACb,KAAK,SAAS;AACb,aAAO,EAAE,MAAM,SAAS,cAAc,QAAQ;AAAA,IAC/C,KAAK,SAAS;AACb,aAAO,EAAE,MAAM,UAAU,cAAc,QAAQ;AAAA,IAChD,KAAK,SAAS;AACb,aAAO,EAAE,MAAM,SAAS,cAAc,MAAM;AAAA,IAC7C,KAAK,SAAS;AACb,aAAO,EAAE,MAAM,UAAU,cAAc,MAAM;AAAA,IAC9C,KAAK,SAAS;AACb,aAAO,EAAE,MAAM,SAAS,cAAc,OAAO;AAAA,IAC9C,KAAK,SAAS;AACb,aAAO,EAAE,MAAM,UAAU,cAAc,OAAO;AAAA,IAC/C,KAAK,SAAS;AACb,aAAO,EAAE,MAAM,SAAS,cAAc,QAAQ;AAAA,IAC/C,KAAK,SAAS;AACb,aAAO,EAAE,MAAM,UAAU,cAAc,QAAQ;AAAA,IAChD,KAAK,SAAS;AACb,aAAO,EAAE,MAAM,SAAS,cAAc,QAAQ;AAAA,IAC/C,KAAK,SAAS;AACb,aAAO,EAAE,MAAM,UAAU,cAAc,QAAQ;AAAA,IAChD;AACC,aAAO,EAAE,MAAM,SAAS,cAAc,QAAQ;AAAA,EAChD;AACD;AAEA,SAAS,gBAAgB,MAAuB;AAC/C,SAAO,SAAS,SAAS,uBAAuB,SAAS,SAAS;AACnE;AAEA,MAAM,uBAAuB;AAC7B,MAAM,mBAAmB;AACzB,MAAM,uBAAuB;AAC7B,MAAM,wBAAwB;AAC9B,MAAM,yBAAyB;AAC/B,MAAM,yBAAyB;AAC/B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAM,eAAe;AAGrB,MAAM,kBAAkB;AACxB,MAAM,oBAAoB;AAC1B,MAAM,qBAAqB;AAC3B,MAAM,uBAAuB;AAC7B,MAAM,0BAA0B;AAChC,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAM,oBAAoB;AAC1B,MAAM,gBAAgB;AACtB,MAAM,uBAAuB;AAC7B,MAAM,yBAAyB;AAC/B,MAAM,uBAAuB;AAC7B,MAAM,gCAAgC;AACtC,MAAM,iCAAiC;AAwBvC,SAAS,cAAc,MAAe,UAA6B;AAClE,QAAM,UAAqB,CAAC;AAC5B,aAAW,QAAQ,KAAK,iBAAiB,QAAQ,GAAG;AACnD,UAAM,WAAW,wBAAwB,IAAI;AAC7C,UAAM,IAAI,WAAW,KAAK,aAAa,GAAG,KAAK,GAAG;AAClD,UAAM,IAAI,WAAW,KAAK,aAAa,GAAG,KAAK,GAAG;AAClD,UAAM,IAAI,WAAW,KAAK,aAAa,OAAO,KAAK,GAAG;AACtD,UAAM,IAAI,WAAW,KAAK,aAAa,QAAQ,KAAK,GAAG;AACvD,QAAI,IAAI,KAAK,IAAI,GAAG;AACnB,cAAQ,KAAK;AAAA,QACZ,GAAG,OAAO,SAAS,SAAS,IAAI,CAAC,IAAI,SAAS,IAAI,IAAI;AAAA,QACtD,GAAG,OAAO,SAAS,SAAS,IAAI,CAAC,IAAI,SAAS,IAAI,IAAI;AAAA,QACtD;AAAA,QACA;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD;AACA,SAAO;AACR;AAMA,SAAS,mBAAmB,MAA0B;AACrD,QAAM,UAAqB,CAAC;AAC5B,aAAW,SAAS,KAAK,iBAAiB,aAAa,GAAG;AACzD,UAAM,WAAW,wBAAwB,KAAK;AAC9C,QAAI,OAAO;AACX,QAAI,OAAO;AACX,QAAI,OAAO;AACX,QAAI,OAAO;AACX,eAAW,QAAQ,MAAM,iBAAiB,MAAM,GAAG;AAClD,iBAAW,QAAQ,CAAC,MAAM,IAAI,GAAG;AAChC,cAAM,QAAQ,WAAW,KAAK,aAAa,IAAI,KAAK,GAAG;AACvD,YAAI,QAAQ,KAAM,QAAO;AACzB,YAAI,QAAQ,KAAM,QAAO;AAAA,MAC1B;AACA,iBAAW,QAAQ,CAAC,MAAM,IAAI,GAAG;AAChC,cAAM,QAAQ,WAAW,KAAK,aAAa,IAAI,KAAK,GAAG;AACvD,YAAI,QAAQ,KAAM,QAAO;AACzB,YAAI,QAAQ,KAAM,QAAO;AAAA,MAC1B;AAAA,IACD;AACA,QAAI,OAAO,SAAS,IAAI,KAAK,OAAO,SAAS,IAAI,GAAG;AACnD,cAAQ,KAAK;AAAA,QACZ,GAAG,SAAS,IAAI;AAAA,QAChB,GAAG,SAAS,IAAI;AAAA,QAChB,GAAG,OAAO,QAAQ;AAAA,QAClB,GAAG,OAAO,QAAQ;AAAA,MACnB,CAAC;AAAA,IACF;AAAA,EACD;AACA,SAAO;AACR;AAEA,SAAS,oBAAoB,MAAe,YAAoB,YAAmC;AAClG,QAAM,MAAM,CAAC,GAAY,MAAe,EAAE,IAAI,EAAE;AAChD,MAAI,MAAM,cAAc,MAAM,gBAAgB,EAAE,KAAK,GAAG;AACxD,MAAI,SAAS,cAAc,MAAM,mBAAmB,EAAE,KAAK,GAAG;AAE9D,QAAM,gBAAgB,mBAAmB,IAAI,EAAE,KAAK,GAAG;AACvD,MAAI,cAAc,SAAS,MAAM,IAAI,SAAS,cAAc,OAAO,SAAS,aAAa;AACxF,UAAM,OACL,IAAI,SAAS,KAAK,OAAO,SAAS,KAC9B,KAAK,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,IACjF,cAAc,UAAU,KACtB,cAAc,CAAC,EAAE,IAAI,cAAc,cAAc,SAAS,CAAC,EAAE,KAAK,IACnE;AACL,eAAW,QAAQ,eAAe;AACjC,UAAI,KAAK,IAAI,KAAM,KAAI,KAAK,IAAI;AAAA,UAC3B,QAAO,KAAK,IAAI;AAAA,IACtB;AACA,QAAI,KAAK,GAAG;AACZ,WAAO,KAAK,GAAG;AAAA,EAChB;AAEA,MAAI,IAAI,SAAS,cAAc,OAAO,SAAS,YAAY;AAC1D,UAAM,MAAM,cAAc,MAAM,sBAAsB,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;AAChF,QAAI,IAAI,UAAU,IAAI,YAAY;AACjC,UAAI,SAAS;AACb,UAAI,UAAU;AACd,eAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACpC,cAAM,MAAM,IAAI,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,EAAE;AAClC,YAAI,MAAM,QAAQ;AACjB,mBAAS;AACT,oBAAU;AAAA,QACX;AAAA,MACD;AACA,YAAM,IAAI,MAAM,GAAG,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,UAAU;AACzD,eAAS,IAAI,MAAM,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,UAAU;AAAA,IAC1D,OAAO;AACN,YAAM,CAAC;AACP,eAAS,CAAC;AAAA,IACX;AAAA,EACD,OAAO;AACN,UAAM,IAAI,MAAM,GAAG,UAAU;AAC7B,aAAS,OAAO,MAAM,GAAG,UAAU;AAAA,EACpC;AAEA,MAAI,cAAc,SAAS,GAAG;AAC7B,UAAM,cAAc,IAAI,IAAa,aAAa;AAClD,UAAM,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC;AACzD,UAAM,iBAAiB,OAAO,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC;AAC/D,UAAM,YACL,YAAY,SAAS,IAAI,KAAK,IAAI,GAAG,YAAY,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI;AACrE,UAAM,WACL,YAAY,SAAS,IAAI,KAAK,IAAI,GAAG,YAAY,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI;AACrE,UAAM,UAAU,YAAY,SAAS,IAAI,KAAK,IAAI,GAAG,YAAY,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI;AACpF,UAAM,gBACL,eAAe,SAAS,IAAI,KAAK,IAAI,GAAG,eAAe,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI;AAEjF,eAAW,QAAQ,KAAK;AACvB,UAAI,CAAC,YAAY,IAAI,IAAI,EAAG;AAC5B,YAAM,UAAU,KAAK,IAAI,KAAK,IAAI;AAClC,WAAK,IAAI;AACT,WAAK,IAAI,KAAK,IAAI,KAAK,GAAG,QAAQ;AAClC,WAAK,IAAI,YAAY,SAAY,UAAU,UAAU,YAAY;AAAA,IAClE;AACA,eAAW,QAAQ,QAAQ;AAC1B,UAAI,CAAC,YAAY,IAAI,IAAI,EAAG;AAC5B,YAAM,UAAU,KAAK,IAAI,KAAK,IAAI;AAClC,WAAK,IAAI;AACT,WAAK,IAAI,KAAK,IAAI,KAAK,GAAG,QAAQ;AAClC,WAAK,IAAI,kBAAkB,SAAY,gBAAgB,YAAY,UAAU,YAAY;AAAA,IAC1F;AAAA,EACD;AAEA,MAAI,IAAI,UAAU,cAAc,OAAO,UAAU,YAAY;AAC5D,UAAM,aAAa,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC;AAC/C,UAAM,WAAqB,CAAC;AAC5B,aAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC3C,eAAS,KAAK,WAAW,CAAC,IAAI,WAAW,IAAI,CAAC,CAAC;AAAA,IAChD;AACA,UAAM,aAAa,SAAS,SAAS,IAAI,KAAK,IAAI,GAAG,QAAQ,IAAI;AACjE,UAAM,QAAQ,KAAK,IAAI,GAAG,uBAAuB,UAAU;AAE3D,UAAM,WAAW,WAAW,IAAI,CAAC,OAAO,IAAI,WAAW,CAAC,KAAK,KAAK;AAClE,UAAM,YAAY,SAAS,SAAS,IAAI,SAAS,SAAS,SAAS,CAAC,IAAI;AAExE,UAAM,eAAe,KAAK,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1D,UAAM,eAAe,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AACvD,UAAM,WAAW,KAAK,IAAI,GAAG,oBAAoB,eAAe,aAAa;AAC7E,UAAM,UAAU,KAAK,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAC/C,UAAM,aAAa,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3D,UAAM,UAAU,EAAE,aAAa,WAAW,WAAW;AAErD,WAAO,IAAI,IAAI,CAAC,SAAS,MAAM;AAC9B,YAAM,IAAI,QAAQ,IAAI;AACtB,YAAM,IAAI,QAAQ,IAAI;AACtB,aAAO;AAAA,QACN,GAAG,SAAS,CAAC,IAAI,YAAY,IAAI,IAAI;AAAA,QACrC,GAAG,UAAU,QAAQ;AAAA,QACrB;AAAA,QACA;AAAA,QACA,SAAS,UAAU,OAAO,CAAC,EAAE,IAAI;AAAA,MAClC;AAAA,IACD,CAAC;AAAA,EACF;AAEA,QAAM,yBAAyB,KAAK,IAAI,KAAK,aAAa,sBAAsB;AAChF,QAAM,aAAa,aAAa,wBAAwB,aAAa,KAAK;AAC1E,QAAM,cAAc,wBAAwB,IAAI;AAChD,QAAM,SAAS,CAAC,aAAa;AAC7B,QAAM,SAAS,CAAC,cAAc;AAC9B,SAAO,MAAM,KAAK,EAAE,QAAQ,WAAW,GAAG,CAAC,GAAG,OAAO;AAAA,IACpD,GAAG,SAAS,KAAK,uBAAuB;AAAA,IACxC,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,SAAS,SAAS,cAAc;AAAA,EACjC,EAAE;AACH;AAEA,SAAS,gBAAgB,KAAkC;AAC1D,SAAO,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU;AACxD;AAGO,SAAS,oBAAoB,UAA6B;AAChE,MAAI,QAAQ;AACZ,aAAW,OAAO,UAAU;AAC3B,QAAI,aAAa,IAAI,IAAI,EAAG;AAC5B,QAAI,wBAAwB,IAAI,IAAI,EAAG;AACvC,QAAI,cAAc,IAAI,IAAI,EAAG;AAC7B,QAAI,4BAA4B,IAAI,IAAI,EAAG;AAC3C,QAAI,cAAc,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,EAAG;AACtD,UAAM,UACJ,gBAAgB,IAAI,IAAI,KAAK,IAAI,QAAQ,IAAI,MAAQ,cAAc,IAAI,IAAI,KAAK,IAAI;AACtF,QAAI,QAAS;AAAA,EACd;AACA,SAAO;AACR;AAGO,SAAS,oBACf,MACA,YACA,YACuB;AACvB,SAAO;AAAA,IACN,cAAc,oBAAoB,MAAM,YAAY,UAAU;AAAA,IAC9D,WAAW,cAAc,MAAM,WAAW;AAAA,EAC3C;AACD;AAMO,SAAS,oBACf,QACA,QACA,WACA,UACA,gBAAqC,oBAAI,IAAI,GAC7C,kBAAuC,oBAAI,IAAI,GACrB;AAC1B,QAAM,aAAa,UAAU;AAC7B,QAAM,WAAW,IAAI,IAAI,UAAU,IAAI,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAE5D,QAAM,YAA4B,CAAC;AACnC,QAAM,gBAAgC,CAAC;AACvC,QAAM,SAAoB,CAAC;AAC3B,QAAM,kBAAkB,oBAAI,IAAsB;AAClD,QAAM,kBAAoC,CAAC;AAE3C,MAAI,kBAAkB;AACtB,MAAI,iBAAiB;AACrB,MAAI,oBAAoB;AAExB,aAAW,OAAO,UAAU;AAC3B,QAAI,aAAa,IAAI,IAAI,GAAG;AAC3B,wBAAkB;AAClB,uBAAiB;AACjB,0BAAoB;AACpB;AAAA,IACD;AAEA,UAAM,UAAU,wBAAwB,IAAI,IAAI;AAChD,QAAI,SAAS;AACZ,oBAAc,KAAK;AAAA,QAClB;AAAA,QACA,UAAU,CAAC,EAAE,OAAO,gBAAgB,GAAG,KAAK,IAAI,iBAAiB,OAAO,OAAO,CAAC;AAAA,QAChF,iBAAiB,OAAO;AAAA,QACxB,WAAW,oBAAI,IAAI;AAAA,MACpB,CAAC;AACD;AAAA,IACD;AAEA,QAAI,cAAc,IAAI,IAAI,GAAG;AAC5B,YAAM,OAAO,cAAc,IAAI;AAC/B,UAAI,KAAM,WAAU,KAAK,EAAE,GAAG,MAAM,gBAAgB,OAAO,SAAS,EAAE,CAAC;AACvE;AAAA,IACD;AAEA,QAAI,4BAA4B,IAAI,IAAI,GAAG;AAC1C,YAAM,UAAU,cAAc,cAAc,SAAS,CAAC;AACtD,UAAI,SAAS;AACZ,gBAAQ,SAAS,KAAK;AAAA,UACrB,OAAO,gBAAgB,GAAG,KAAK;AAAA,UAC/B,iBAAiB,OAAO;AAAA,QACzB,CAAC;AAAA,MACF;AACA;AAAA,IACD;AAEA,QAAI,cAAc,IAAI,IAAI,GAAG;AAC5B,YAAM,MAAM,IAAI,QAAQ,IAAI;AAC5B,UAAI,KAAK;AACR,YAAI,CAAC,gBAAgB,IAAI,GAAG,EAAG,iBAAgB,IAAI,KAAK,CAAC,CAAC;AAG1D,wBAAgB,IAAI,GAAG,EAAG,KAAK,KAAK,IAAI,GAAG,OAAO,SAAS,CAAC,CAAC;AAAA,MAC9D;AACA;AAAA,IACD;AAEA,QAAI,YAAY,IAAI,IAAI,GAAG;AAC1B,YAAM,MAAM,IAAI,QAAQ,IAAI;AAC5B,UAAI,KAAK;AACR,cAAM,WAAW,gBAAgB,IAAI,GAAG,GAAG,IAAI;AAC/C,YAAI,aAAa,QAAW;AAC3B,0BAAgB,KAAK;AAAA,YACpB,gBAAgB;AAAA,YAChB,iBAAiB;AAAA,YACjB,eAAe,KAAK,IAAI,OAAO,SAAS,GAAG,QAAQ;AAAA,UACpD,CAAC;AAAA,QACF;AAAA,MACD;AACA;AAAA,IACD;AAEA,UAAM,UACJ,gBAAgB,IAAI,IAAI,KAAK,IAAI,QAAQ,IAAI,MAAQ,cAAc,IAAI,IAAI,KAAK,IAAI;AACtF,QAAI,CAAC,QAAS;AAEd,eAAW,QAAQ,eAAe;AACjC,UAAI,IAAI,KAAM,MAAK,UAAU,IAAI,IAAI,IAAI;AACzC,UAAI,IAAI,GAAI,MAAK,UAAU,IAAI,IAAI,EAAE;AAAA,IACtC;AACA,WAAO,KAAK,GAAG;AAAA,EAChB;AAEA,QAAM,UAAU,OAAO;AAKvB,QAAM,qBAAqB,oBAAI,IAAoB;AACnD,QAAM,wBAAwB,oBAAI,IAAoB;AACtD,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACvC,UAAM,KAAK,OAAO,CAAC;AACnB,QAAI,CAAC,gBAAgB,GAAG,IAAI,EAAG;AAE/B,QAAI,GAAG,MAAM,cAAc,IAAI,GAAG,EAAE,KAAK,CAAC,mBAAmB,IAAI,GAAG,EAAE,GAAG;AACxE,yBAAmB,IAAI,GAAG,IAAI,CAAC;AAAA,IAChC;AACA,QAAI,GAAG,QAAQ,gBAAgB,IAAI,GAAG,IAAI,KAAK,CAAC,sBAAsB,IAAI,GAAG,IAAI,GAAG;AACnF,4BAAsB,IAAI,GAAG,MAAM,CAAC;AAAA,IACrC;AAAA,EACD;AAGA,QAAM,eAAe,OAAO;AAC5B,MAAI,eAAe;AACnB,QAAM,QAAgC,CAAC;AACvC,QAAM,QAAoC,CAAC;AAC3C,QAAM,QAAgC,CAAC;AAEvC,QAAM,EAAE,GAAG,QAAQ,GAAG,QAAQ,SAAS,aAAa,IAAI,QAAQ,CAAC;AACjE,QAAM,cAAc,SAAS;AAC7B,QAAM,aAAa,eAAe,gBAAgB,OAAO,SAAS;AAKlE,WAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACpC,UAAM,MAAM,UAAU,CAAC;AACvB,UAAM,EAAE,GAAG,GAAG,GAAG,GAAG,QAAQ,IAAI,QAAQ,CAAC;AAEzC,UAAM,YAAY,mBAAmB,IAAI,GAAG;AAC5C,UAAM,cAAc,sBAAsB,IAAI,GAAG;AACjD,UAAM,SAAS,YAAY,cAAc,aAAa,mBAAmB,IAAI,GAAG,IAAK,KAAK;AAC1F,UAAM,OAAO,YAAY,SAAS,IAAI,IAAI,IAAI;AAC9C,UAAM,OAAO,cACV,cAAc,aAAa,sBAAsB,IAAI,GAAG,IAAK,KAC7D;AAEH,UAAM,iBAAiB,OAAO;AAC9B,QAAI,iBAAiB,GAAG;AACvB,YAAM,KAAK,EAAE,IAAI,YAAY,GAAG,IAAI,GAAG,IAAI,IAAI,GAAG,GAAG,MAAM,MAAM,eAAe,CAAC;AAAA,IAClF;AAAA,EACD;AAGA,QAAM,gBAAgB,YAAY;AAClC,QAAM,cAAc,gBAClB,IAAI,CAAC,MAAM,aAAa,EAAE,GAAG,MAAM,QAAQ,EAAE,EAC7C,KAAK,CAAC,GAAG,MAAM;AACf,UAAM,QAAQ,EAAE,gBAAgB,EAAE;AAClC,UAAM,QAAQ,EAAE,gBAAgB,EAAE;AAClC,WAAO,QAAQ,SAAS,EAAE,UAAU,EAAE;AAAA,EACvC,CAAC;AAEF,WAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC5C,UAAM,OAAO,YAAY,CAAC;AAC1B,UAAM,WAAW,SAAS,IAAI,KAAK,cAAc;AACjD,QAAI,aAAa,OAAW;AAE5B,UAAM,WAAW,KAAK,gBAAgB,KAAK;AAC3C,QAAI,QAAQ;AACZ,eAAW,SAAS,aAAa;AAChC,UAAI,UAAU,KAAM;AACpB,YAAM,kBAAkB,MAAM,mBAAmB,KAAK;AACtD,YAAM,eACL,MAAM,mBAAmB,KAAK,mBAAmB,MAAM,iBAAiB,KAAK;AAC9E,YAAM,iBAAiB,MAAM,gBAAgB,MAAM,kBAAkB;AACrE,UAAI,mBAAmB,gBAAgB,eAAgB;AAAA,IACxD;AAEA,UAAMA,UAAS,QAAQ,QAAQ;AAC/B,UAAM,kBAAkBA,QAAO,IAAIA,QAAO,IAAI;AAC9C,UAAM,SAAS,cAAc,aAAa,KAAK,kBAAkB,KAAK;AACtE,UAAM,YAAY,cAAc,aAAa,KAAK,gBAAgB,KAAK;AAEvE,UAAM,KAAK,cAAc,KAAK,OAAO;AACrC,UAAM,OAAO;AACb,UAAM,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA,GAAG,kBAAkB,uBAAuB,IAAI,QAAQ;AAAA,MACxD,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG,YAAY;AAAA,MACf,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,IACP,CAAC;AAAA,EACF;AAGA,WAAS,gBAAgB,GAAG,gBAAgB,UAAU,QAAQ,iBAAiB;AAC9E,UAAM,WAAW,UAAU,aAAa;AACxC,QAAI,SAAS,iBAAiB,SAAS,gBAAiB;AAExD,UAAM,UAAU,cAAc,aAAa,SAAS,kBAAkB,KAAK;AAC3E,UAAM,aACL,cAAc,aAAa,SAAS,iBAAiB,KAAK;AAC3D,UAAM,UAAU,CAAC,GAAG,SAAS,SAAS,EAAE,IAAI,CAAC,MAAM,SAAS,IAAI,CAAC,CAAE,EAAE,OAAO,CAAC,QAAQ,OAAO,CAAC;AAC7F,QAAI,QAAQ,WAAW,EAAG;AAE1B,UAAM,WAAW,KAAK,IAAI,GAAG,OAAO;AACpC,UAAM,WAAW,KAAK,IAAI,GAAG,OAAO;AACpC,UAAM,QAAQ,QAAQ,QAAQ,EAAE,IAAI;AACpC,UAAM,QAAQ,QAAQ,QAAQ,EAAE,IAAI,QAAQ,QAAQ,EAAE,IAAI,qBAAqB;AAC/E,UAAM,QAAQ,aAAa;AAE3B,UAAM,WACL,SAAS,YAAY,SAAS,sBAAsB,SAAS,SAAS,CAAC,EAAE,KAAK,IAAI;AACnF,UAAM,SAAS,YAAY,aAAa;AACxC,UAAM,WAAW;AACjB,QAAI,UAAU;AACb,YAAM,KAAK;AAAA,QACV,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,GAAG;AAAA,QACH,GAAG;AAAA,QACH,GAAG;AAAA,QACH,GAAG;AAAA,QACH,MAAM,SAAS,WAAW,SAAS;AAAA,QACnC,OAAO,SAAS;AAAA,QAChB,MAAM;AAAA,MACP,CAAC;AAAA,IACF,OAAO;AACN,YAAM,KAAK;AAAA,QACV,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,GAAG;AAAA,QACH,GAAG;AAAA,QACH,GAAG;AAAA,QACH,GAAG;AAAA,QACH,MAAM;AAAA,QACN,MAAM;AAAA,QACN,OAAO;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,QACP,eAAe;AAAA,QACf,OAAO,GAAG,SAAS,OAAO,KAAK,SAAS,SAAS,CAAC,EAAE,KAAK;AAAA,MAC1D,CAAC;AAED,eAAS,IAAI,GAAG,IAAI,SAAS,SAAS,QAAQ,KAAK;AAClD,cAAM,UAAU,SAAS,SAAS,CAAC;AACnC,cAAM,OAAO,cAAc,aAAa,QAAQ,kBAAkB;AAElE,cAAM,KAAK;AAAA,UACV,IAAI,YAAY,aAAa,QAAQ,CAAC;AAAA,UACtC,GAAG;AAAA,UACH,GAAG;AAAA,UACH,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA,UACN,OAAO;AAAA,UACP,MAAM;AAAA,QACP,CAAC;AAED,cAAM,QAAQ,YAAY,aAAa,YAAY,CAAC;AACpD,cAAM,UAAU;AAChB,cAAM,KAAK;AAAA,UACV,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,GAAG,QAAQ;AAAA,UACX,GAAG,OAAO;AAAA,UACV,GAAG,QAAQ,iCAAiC;AAAA,UAC5C,GAAG;AAAA,UACH,MAAM;AAAA,UACN,MAAM;AAAA,UACN,OAAO;AAAA,UACP,MAAM;AAAA,UACN,OAAO;AAAA,UACP,eAAe;AAAA,UACf,OAAO,IAAI,QAAQ,KAAK;AAAA,QACzB,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAGA,WAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACpC,UAAM,MAAM,UAAU,CAAC;AACvB,UAAM,QAAQ,OAAO,IAAI,GAAG;AAC5B,QAAI,CAAC,MAAO;AACZ,UAAM,EAAE,GAAG,GAAG,GAAG,GAAG,QAAQ,IAAI,QAAQ,CAAC;AACzC,UAAM,YAAY,mBAAmB,IAAI,GAAG;AAC5C,UAAM,cAAc,sBAAsB,IAAI,GAAG;AACjD,UAAM,OAAO,MAAM;AACnB,UAAM,QAAQ,MAAM,eAAe,MAAM,QAAQ;AACjD,UAAM,SAAS;AAAA,MACd;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP,eAAe;AAAA,MACf,MAAM;AAAA,IACP;AAEA,UAAM,YAAY,YAAY,cAAc,aAAa,mBAAmB,IAAI,GAAG,IAAK,KAAK;AAC7F,UAAM,OAAO,YAAY,YAAY,IAAI,IAAI;AAC7C,UAAM,QAAQ,aAAa,GAAG;AAC9B,UAAM,KAAK;AAAA,MACV,IAAI;AAAA,MACJ;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACJ,CAAC;AAED,QAAI,CAAC,aAAa;AACjB,YAAM,QAAQ,gBAAgB,GAAG;AACjC,YAAM,KAAK;AAAA,QACV,IAAI;AAAA,QACJ;AAAA,QACA,GAAG;AAAA,QACH;AAAA,QACA;AAAA,QACA,GAAG;AAAA,MACJ,CAAC;AAAA,IACF;AAAA,EACD;AAGA,QAAM,mBAAmB,IAAI,IAAI,cAAc,KAAK,CAAC;AACrD,MAAI,iBAAiB;AAErB,WAAS,aAAa,GAAG,aAAa,OAAO,QAAQ,cAAc;AAClE,UAAM,MAAM,OAAO,UAAU;AAC7B,UAAM,UAAU,aAAa,MAAM,OAAO,SAAS;AAEnD,QAAI,gBAAgB,IAAI,IAAI,GAAG;AAC9B,YAAM,UAAU,IAAI;AACpB,YAAM,QAAQ,IAAI;AAClB,UAAI,CAAC,SAAS,IAAI,OAAO,KAAK,CAAC,SAAS,IAAI,KAAK,EAAG;AAEpD,YAAM,oBAAoB,iBAAiB,IAAI,KAAK;AACpD,UAAI,kBAAmB,kBAAiB,OAAO,KAAK;AAEpD,YAAM,UAAU,IAAI,QAAQ,SAAS;AACrC,YAAM,EAAE,MAAM,aAAa,IAAI,wBAAwB,OAAO;AAC9D,YAAM,SAAS,YAAY;AAC3B,YAAM,QAAQ,CAAC,UAAU,gBAAgB,OAAO;AAEhD,YAAM,OAA6B;AAAA,QAClC,aAAa,YAAY,OAAO;AAAA,QAChC,WAAW,oBAAoB,aAAa,KAAK,KAAK,YAAY,KAAK;AAAA,QACvE,OAAO,gBAAgB,GAAG;AAAA,QAC1B,MAAM,SAAS,gBAAgB;AAAA,QAC/B;AAAA,QACA;AAAA,QACA,gBAAgB,QAAQ,UAAU;AAAA,QAClC,MAAM;AAAA,QACN,cAAc,SAAS,SAAS,oBAAoB;AAAA,QACpD,YAAY,oBAAoB,MAAM,SAAS,SAAS,oBAAoB;AAAA,QAC5E,SAAS;AAAA,QACT,WAAW;AAAA,QACX,GAAI,qBAAqB,EAAE,YAAY,OAAO,cAAc,MAAM;AAAA,MACnE;AAEA,UAAI,mBAAmB;AACtB,aAAK,aAAa,EAAE,MAAM,cAAc,OAAO,OAAO,cAAc,EAAE;AACtE,0BAAkB;AAAA,MACnB;AAEA,YAAM,KAAK,IAAI;AAAA,IAChB,WAAW,cAAc,IAAI,IAAI,GAAG;AACnC,YAAM,SAAS,cAAc,aAAa,aAAa;AACvD,YAAM,UAAU,IAAI;AACpB,YAAM,UAAU,SAAS,IAAI,OAAO;AACpC,YAAM,QAAQ,SAAS,IAAI,IAAI,MAAM,OAAO;AAC5C,UAAI,YAAY,OAAW;AAE3B,YAAM,QAAQ,gBAAgB,GAAG;AAEjC,YAAM,eAAe,IAAI;AACzB,YAAM,cAAc,QAAQ,OAAO,EAAE,IAAI,QAAQ,OAAO,EAAE,IAAI;AAC9D,YAAM,YAAY,UAAU,SAAY,QAAQ,KAAK,EAAE,IAAI,QAAQ,KAAK,EAAE,IAAI,IAAI;AAClF,YAAM,aACL,iBAAiB,UAAU,QAAQ,IAAI,SAAS,IAAI,MAAM,UAAU;AAErE,YAAM,UAAU,aAAa,cAAc;AAC3C,YAAM,aAAa,SAAS,KAAK;AACjC,YAAM,YAAY,QAAQ,MAAM,SAAS,kBAAkB,oBAAoB;AAC/E,YAAM,YAAY,KAAK,IAAI,SAAS,KAAK,qBAAqB,SAAS;AACvE,YAAM,YAAY,aACf,KAAK,IAAI,WAAW,KAAK,IAAI,YAAY,WAAW,IAAI,YAAY,IACpE;AAEH,UAAI;AACJ,UAAI,iBAAiB,UAAU,QAAQ;AACtC,gBAAQ,cAAc,YAAY;AAAA,MACnC,WAAW,iBAAiB,UAAU,SAAS;AAC9C,gBAAQ,cAAc;AAAA,MACvB,WAAW,YAAY;AACtB,iBAAS,cAAc,aAAa,IAAI,YAAY;AAAA,MACrD,OAAO;AACN,gBAAQ,cAAc,YAAY;AAAA,MACnC;AAEA,YAAM,SAAS,QAAQ,UAAU;AACjC,YAAM,WAAW;AACjB,YAAM,KAAK;AAAA,QACV,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,GAAG;AAAA,QACH,GAAG,SAAS,aAAa;AAAA,QACzB,GAAG;AAAA,QACH,GAAG;AAAA,QACH,MAAM;AAAA,QACN,OAAO;AAAA,QACP,MAAM;AAAA,QACN,MAAM;AAAA,QACN,OAAO;AAAA,QACP,eAAe;AAAA,QACf;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD;AAEA,SAAO;AAAA,IACN,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,UAAU,IAAI,CAAC,QAAQ;AAC9B,YAAM,QAAQ,CAAC,aAAa,GAAG,IAAI,YAAY,GAAG,EAAE;AACpD,UAAI,CAAC,sBAAsB,IAAI,GAAG,GAAG;AACpC,cAAM,KAAK,gBAAgB,GAAG,EAAE;AAAA,MACjC;AACA,aAAO;AAAA,IACR,CAAC;AAAA,EACF;AACD;",
|
|
4
|
+
"sourcesContent": ["import type { SequenceDB } from 'mermaid/dist/diagrams/sequence/sequenceDb.d.ts'\nimport type { Actor, Message } from 'mermaid/dist/diagrams/sequence/types.js'\nimport { TLArrowShapeArrowheadStyle, TLDefaultDashStyle } from 'tldraw'\nimport type {\n\tDiagramMermaidBlueprint,\n\tMermaidBlueprintEdge,\n\tMermaidBlueprintNode,\n\tMermaidBlueprintLineNode,\n} from './blueprint'\nimport { parseRgbToTldrawColor } from './colors'\nimport { getAccumulatedTranslate } from './svgParsing'\n\nexport interface SvgRect {\n\tx: number\n\ty: number\n\tw: number\n\th: number\n}\n\nexport interface ActorLayout {\n\tx: number\n\ty: number\n\tw: number\n\th: number\n\tbottomY: number\n}\n\nexport interface ParsedSequenceLayout {\n\tactorLayouts: ActorLayout[]\n\tnoteRects: SvgRect[]\n}\n\nconst LINETYPE = {\n\tSOLID: 0,\n\tDOTTED: 1,\n\tNOTE: 2,\n\tSOLID_CROSS: 3,\n\tDOTTED_CROSS: 4,\n\tSOLID_OPEN: 5,\n\tDOTTED_OPEN: 6,\n\tLOOP_START: 10,\n\tLOOP_END: 11,\n\tALT_START: 12,\n\tALT_ELSE: 13,\n\tALT_END: 14,\n\tOPT_START: 15,\n\tOPT_END: 16,\n\tACTIVE_START: 17,\n\tACTIVE_END: 18,\n\tPAR_START: 19,\n\tPAR_AND: 20,\n\tPAR_END: 21,\n\tRECT_START: 22,\n\tRECT_END: 23,\n\tSOLID_POINT: 24,\n\tDOTTED_POINT: 25,\n\tAUTONUMBER: 26,\n\tCRITICAL_START: 27,\n\tCRITICAL_OPTION: 28,\n\tCRITICAL_END: 29,\n\tBREAK_START: 30,\n\tBREAK_END: 31,\n\tPAR_OVER_START: 32,\n\tBIDIRECTIONAL_SOLID: 33,\n\tBIDIRECTIONAL_DOTTED: 34,\n\tSOLID_TOP: 41,\n\tSOLID_BOTTOM: 42,\n\tSTICK_TOP: 43,\n\tSTICK_BOTTOM: 44,\n\tSOLID_ARROW_TOP_REVERSE: 45,\n\tSOLID_ARROW_BOTTOM_REVERSE: 46,\n\tSTICK_ARROW_TOP_REVERSE: 47,\n\tSTICK_ARROW_BOTTOM_REVERSE: 48,\n\tSOLID_TOP_DOTTED: 51,\n\tSOLID_BOTTOM_DOTTED: 52,\n\tSTICK_TOP_DOTTED: 53,\n\tSTICK_BOTTOM_DOTTED: 54,\n\tSOLID_ARROW_TOP_REVERSE_DOTTED: 55,\n\tSOLID_ARROW_BOTTOM_REVERSE_DOTTED: 56,\n\tSTICK_ARROW_TOP_REVERSE_DOTTED: 57,\n\tSTICK_ARROW_BOTTOM_REVERSE_DOTTED: 58,\n\tCENTRAL_CONNECTION: 59,\n\tCENTRAL_CONNECTION_REVERSE: 60,\n\tCENTRAL_CONNECTION_DUAL: 61,\n} as const satisfies SequenceDB['LINETYPE']\n\nconst PLACEMENT = {\n\tLEFTOF: 0,\n\tRIGHTOF: 1,\n\tOVER: 2,\n} as const satisfies SequenceDB['PLACEMENT']\n\nconst signalTypes: number[] = [\n\tLINETYPE.SOLID,\n\tLINETYPE.DOTTED,\n\tLINETYPE.SOLID_CROSS,\n\tLINETYPE.DOTTED_CROSS,\n\tLINETYPE.SOLID_OPEN,\n\tLINETYPE.DOTTED_OPEN,\n\tLINETYPE.SOLID_POINT,\n\tLINETYPE.DOTTED_POINT,\n\tLINETYPE.BIDIRECTIONAL_SOLID,\n\tLINETYPE.BIDIRECTIONAL_DOTTED,\n]\n\nfunction isSignalMessage(type: number | undefined): boolean {\n\tif (type === undefined) return false\n\treturn signalTypes.includes(type)\n}\n\nfunction isNoteMessage(type: number | undefined): boolean {\n\treturn type === LINETYPE.NOTE\n}\n\nfunction isActiveStart(type: number | undefined): boolean {\n\treturn type === LINETYPE.ACTIVE_START\n}\n\nfunction isActiveEnd(type: number | undefined): boolean {\n\treturn type === LINETYPE.ACTIVE_END\n}\n\nfunction isAutonumber(type: number | undefined): boolean {\n\treturn type === LINETYPE.AUTONUMBER\n}\n\n/** Returns the fragment keyword (e.g. \"loop\", \"opt\") if this message starts a combined fragment, or null. */\nfunction getFragmentStartKeyword(type: number | undefined): string | null {\n\tif (type === undefined) return null\n\tif (type === LINETYPE.LOOP_START) return 'loop'\n\tif (type === LINETYPE.ALT_START) return 'alt'\n\tif (type === LINETYPE.OPT_START) return 'opt'\n\tif (type === LINETYPE.PAR_START) return 'par'\n\tif (type === LINETYPE.RECT_START) return 'rect'\n\tif (type === LINETYPE.CRITICAL_START) return 'critical'\n\tif (type === LINETYPE.BREAK_START) return 'break'\n\tif (type === LINETYPE.PAR_OVER_START) return 'par'\n\treturn null\n}\n\nfunction isFragmentEnd(type: number | undefined): boolean {\n\tif (type === undefined) return false\n\tconst endTypes: number[] = [\n\t\tLINETYPE.LOOP_END,\n\t\tLINETYPE.ALT_END,\n\t\tLINETYPE.OPT_END,\n\t\tLINETYPE.PAR_END,\n\t\tLINETYPE.RECT_END,\n\t\tLINETYPE.CRITICAL_END,\n\t\tLINETYPE.BREAK_END,\n\t]\n\treturn endTypes.includes(type)\n}\n\n/** Returns a keyword if this message is a section separator within a combined fragment, or null. */\nfunction getFragmentSeparatorKeyword(type: number | undefined): string | null {\n\tif (type === LINETYPE.ALT_ELSE) return 'else'\n\tif (type === LINETYPE.PAR_AND) return 'and'\n\tif (type === LINETYPE.CRITICAL_OPTION) return 'option'\n\treturn null\n}\n\n/** Map a Mermaid LINETYPE value to tldraw arrow props. */\nfunction mapLineTypeToArrowProps(type: number): {\n\tdash: TLDefaultDashStyle\n\tarrowheadEnd: TLArrowShapeArrowheadStyle\n} {\n\tswitch (type) {\n\t\tcase LINETYPE.SOLID:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'arrow' }\n\t\tcase LINETYPE.DOTTED:\n\t\t\treturn { dash: 'dotted', arrowheadEnd: 'arrow' }\n\t\tcase LINETYPE.SOLID_CROSS:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'bar' }\n\t\tcase LINETYPE.DOTTED_CROSS:\n\t\t\treturn { dash: 'dotted', arrowheadEnd: 'bar' }\n\t\tcase LINETYPE.SOLID_OPEN:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'none' }\n\t\tcase LINETYPE.DOTTED_OPEN:\n\t\t\treturn { dash: 'dotted', arrowheadEnd: 'none' }\n\t\tcase LINETYPE.SOLID_POINT:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'arrow' }\n\t\tcase LINETYPE.DOTTED_POINT:\n\t\t\treturn { dash: 'dotted', arrowheadEnd: 'arrow' }\n\t\tcase LINETYPE.BIDIRECTIONAL_SOLID:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'arrow' }\n\t\tcase LINETYPE.BIDIRECTIONAL_DOTTED:\n\t\t\treturn { dash: 'dotted', arrowheadEnd: 'arrow' }\n\t\tdefault:\n\t\t\treturn { dash: 'solid', arrowheadEnd: 'arrow' }\n\t}\n}\n\nfunction isBidirectional(type: number): boolean {\n\treturn type === LINETYPE.BIDIRECTIONAL_SOLID || type === LINETYPE.BIDIRECTIONAL_DOTTED\n}\n\nconst TARGET_ACTOR_SPACING = 300\nconst MIN_VERTICAL_GAP = 400\nconst FALLBACK_ACTOR_WIDTH = 200\nconst FALLBACK_ACTOR_HEIGHT = 70\nconst FALLBACK_ACTOR_SPACING = 100\nconst FALLBACK_EVENT_SPACING = 80\nconst FALLBACK_NOTE_WIDTH = 120\nconst FALLBACK_NOTE_HEIGHT = 50\nconst NOTE_PADDING = 5\n// tldraw's hand-drawn font is wider than Mermaid's default, so we estimate\n// the minimum note width from the label text to prevent wrapping.\nconst NOTE_CHAR_WIDTH = 11\nconst NOTE_TEXT_PADDING = 40\nconst FRAGMENT_PADDING_X = 30\nconst FRAGMENT_PADDING_TOP = 50\nconst FRAGMENT_PADDING_BOTTOM = 25\nconst ACTOR_PADDING_WIDTH = 30\nconst ACTOR_PADDING_HEIGHT = 10\nconst SELF_MSG_Y_OFFSET = 0.04\nconst SELF_MSG_BEND = -80\nconst ACTIVATION_BOX_WIDTH = 20\nconst ACTIVATION_NEST_OFFSET = 6\nconst ACTIVATION_PAD_RATIO = 0.15\nconst FRAGMENT_SECTION_LABEL_HEIGHT = 25\nconst FRAGMENT_SECTION_LABEL_PADDING = 5\n\ninterface FragmentSection {\n\ttitle: string\n\tfirstEventIndex: number\n}\n\ninterface OpenFragment {\n\tkeyword: string\n\tsections: FragmentSection[]\n\tfirstEventIndex: number\n\tactorKeys: Set<string>\n}\n\ninterface FragmentSpan extends OpenFragment {\n\tlastEventIndex: number\n}\n\ninterface ActivationSpan {\n\tparticipantKey: string\n\tstartEventIndex: number\n\tendEventIndex: number\n}\n\nfunction parseSvgRects(root: Element, selector: string): SvgRect[] {\n\tconst results: SvgRect[] = []\n\tfor (const rect of root.querySelectorAll(selector)) {\n\t\tconst ancestor = getAccumulatedTranslate(rect)\n\t\tconst x = parseFloat(rect.getAttribute('x') || '0')\n\t\tconst y = parseFloat(rect.getAttribute('y') || '0')\n\t\tconst w = parseFloat(rect.getAttribute('width') || '0')\n\t\tconst h = parseFloat(rect.getAttribute('height') || '0')\n\t\tif (w > 0 && h > 0) {\n\t\t\tresults.push({\n\t\t\t\tx: Number.isFinite(ancestor.x + x) ? ancestor.x + x : 0,\n\t\t\t\ty: Number.isFinite(ancestor.y + y) ? ancestor.y + y : 0,\n\t\t\t\tw,\n\t\t\t\th,\n\t\t\t})\n\t\t}\n\t}\n\treturn results\n}\n\n/**\n * Stick-figure (actor) participants use SVG <line> elements instead of <rect>.\n * We derive bounding rectangles from the min/max coordinates of each actor-man group.\n */\nfunction parseActorManRects(root: Element): SvgRect[] {\n\tconst results: SvgRect[] = []\n\tfor (const group of root.querySelectorAll('g.actor-man')) {\n\t\tconst ancestor = getAccumulatedTranslate(group)\n\t\tlet minX = Infinity\n\t\tlet minY = Infinity\n\t\tlet maxX = -Infinity\n\t\tlet maxY = -Infinity\n\t\tfor (const line of group.querySelectorAll('line')) {\n\t\t\tfor (const attr of ['x1', 'x2']) {\n\t\t\t\tconst coord = parseFloat(line.getAttribute(attr) || '0')\n\t\t\t\tif (coord < minX) minX = coord\n\t\t\t\tif (coord > maxX) maxX = coord\n\t\t\t}\n\t\t\tfor (const attr of ['y1', 'y2']) {\n\t\t\t\tconst coord = parseFloat(line.getAttribute(attr) || '0')\n\t\t\t\tif (coord < minY) minY = coord\n\t\t\t\tif (coord > maxY) maxY = coord\n\t\t\t}\n\t\t}\n\t\tif (Number.isFinite(minX) && Number.isFinite(minY)) {\n\t\t\tresults.push({\n\t\t\t\tx: ancestor.x + minX,\n\t\t\t\ty: ancestor.y + minY,\n\t\t\t\tw: maxX - minX || FALLBACK_ACTOR_WIDTH,\n\t\t\t\th: maxY - minY || FALLBACK_ACTOR_HEIGHT,\n\t\t\t})\n\t\t}\n\t}\n\treturn results\n}\n\nfunction computeActorLayouts(root: Element, actorCount: number, eventCount: number): ActorLayout[] {\n\tconst byX = (a: SvgRect, b: SvgRect) => a.x - b.x\n\tlet top = parseSvgRects(root, 'rect.actor-top').sort(byX)\n\tlet bottom = parseSvgRects(root, 'rect.actor-bottom').sort(byX)\n\n\tconst actorManRects = parseActorManRects(root).sort(byX)\n\tif (actorManRects.length > 0 && (top.length < actorCount || bottom.length < actorCount)) {\n\t\tconst midY =\n\t\t\ttop.length > 0 && bottom.length > 0\n\t\t\t\t? (Math.max(...top.map((r) => r.y + r.h)) + Math.min(...bottom.map((r) => r.y))) / 2\n\t\t\t\t: actorManRects.length >= 2\n\t\t\t\t\t? (actorManRects[0].y + actorManRects[actorManRects.length - 1].y) / 2\n\t\t\t\t\t: 0\n\t\tfor (const rect of actorManRects) {\n\t\t\tif (rect.y < midY) top.push(rect)\n\t\t\telse bottom.push(rect)\n\t\t}\n\t\ttop.sort(byX)\n\t\tbottom.sort(byX)\n\t}\n\n\tif (top.length < actorCount || bottom.length < actorCount) {\n\t\tconst all = parseSvgRects(root, 'rect[class*=\"actor\"]').sort((a, b) => a.y - b.y)\n\t\tif (all.length >= 2 * actorCount) {\n\t\t\tlet maxGap = 0\n\t\t\tlet splitAt = actorCount\n\t\t\tfor (let i = 1; i < all.length; i++) {\n\t\t\t\tconst gap = all[i].y - all[i - 1].y\n\t\t\t\tif (gap > maxGap) {\n\t\t\t\t\tmaxGap = gap\n\t\t\t\t\tsplitAt = i\n\t\t\t\t}\n\t\t\t}\n\t\t\ttop = all.slice(0, splitAt).sort(byX).slice(0, actorCount)\n\t\t\tbottom = all.slice(splitAt).sort(byX).slice(0, actorCount)\n\t\t} else {\n\t\t\ttop = []\n\t\t\tbottom = []\n\t\t}\n\t} else {\n\t\ttop = top.slice(0, actorCount)\n\t\tbottom = bottom.slice(0, actorCount)\n\t}\n\n\tif (actorManRects.length > 0) {\n\t\tconst actorManSet = new Set<SvgRect>(actorManRects)\n\t\tconst regularTops = top.filter((r) => !actorManSet.has(r))\n\t\tconst regularBottoms = bottom.filter((r) => !actorManSet.has(r))\n\t\tconst refHeight =\n\t\t\tregularTops.length > 0 ? Math.max(...regularTops.map((r) => r.h)) : FALLBACK_ACTOR_HEIGHT\n\t\tconst refWidth =\n\t\t\tregularTops.length > 0 ? Math.max(...regularTops.map((r) => r.w)) : FALLBACK_ACTOR_WIDTH\n\t\tconst refTopY = regularTops.length > 0 ? Math.min(...regularTops.map((r) => r.y)) : undefined\n\t\tconst refBottomEndY =\n\t\t\tregularBottoms.length > 0 ? Math.max(...regularBottoms.map((r) => r.y + r.h)) : undefined\n\n\t\tfor (const rect of top) {\n\t\t\tif (!actorManSet.has(rect)) continue\n\t\t\tconst centerY = rect.y + rect.h / 2\n\t\t\trect.h = refHeight\n\t\t\trect.w = Math.max(rect.w, refWidth)\n\t\t\trect.y = refTopY !== undefined ? refTopY : centerY - refHeight / 2\n\t\t}\n\t\tfor (const rect of bottom) {\n\t\t\tif (!actorManSet.has(rect)) continue\n\t\t\tconst centerY = rect.y + rect.h / 2\n\t\t\trect.h = refHeight\n\t\t\trect.w = Math.max(rect.w, refWidth)\n\t\t\trect.y = refBottomEndY !== undefined ? refBottomEndY - refHeight : centerY - refHeight / 2\n\t\t}\n\t}\n\n\tif (top.length >= actorCount && bottom.length >= actorCount) {\n\t\tconst svgCenters = top.map((r) => r.x + r.w / 2)\n\t\tconst spacings: number[] = []\n\t\tfor (let i = 1; i < svgCenters.length; i++) {\n\t\t\tspacings.push(svgCenters[i] - svgCenters[i - 1])\n\t\t}\n\t\tconst minSpacing = spacings.length > 0 ? Math.min(...spacings) : 1\n\t\tconst scale = Math.max(1, TARGET_ACTOR_SPACING / minSpacing)\n\n\t\tconst xCenters = svgCenters.map((c) => (c - svgCenters[0]) * scale)\n\t\tconst totalSpan = xCenters.length > 1 ? xCenters[xCenters.length - 1] : 0\n\n\t\tconst topRowBottom = Math.max(...top.map((r) => r.y + r.h))\n\t\tconst bottomRowTop = Math.min(...bottom.map((r) => r.y))\n\t\tconst yStretch = Math.max(0, MIN_VERTICAL_GAP - (bottomRowTop - topRowBottom))\n\t\tconst topMinY = Math.min(...top.map((r) => r.y))\n\t\tconst bottomMaxY = Math.max(...bottom.map((r) => r.y + r.h))\n\t\tconst originY = -(bottomMaxY + yStretch + topMinY) / 2\n\n\t\treturn top.map((topRect, i) => {\n\t\t\tconst w = topRect.w + ACTOR_PADDING_WIDTH\n\t\t\tconst h = topRect.h + ACTOR_PADDING_HEIGHT\n\t\t\treturn {\n\t\t\t\tx: xCenters[i] - totalSpan / 2 - w / 2,\n\t\t\t\ty: originY + topRect.y,\n\t\t\t\tw,\n\t\t\t\th,\n\t\t\t\tbottomY: originY + bottom[i].y + yStretch,\n\t\t\t}\n\t\t})\n\t}\n\n\tconst fallbackLifelineHeight = Math.max(300, eventCount * FALLBACK_EVENT_SPACING)\n\tconst totalWidth = actorCount * FALLBACK_ACTOR_WIDTH + (actorCount - 1) * FALLBACK_ACTOR_SPACING\n\tconst totalHeight = FALLBACK_ACTOR_HEIGHT * 2 + fallbackLifelineHeight\n\tconst startX = -totalWidth / 2\n\tconst startY = -totalHeight / 2\n\treturn Array.from({ length: actorCount }, (_, i) => ({\n\t\tx: startX + i * (FALLBACK_ACTOR_WIDTH + FALLBACK_ACTOR_SPACING),\n\t\ty: startY,\n\t\tw: FALLBACK_ACTOR_WIDTH,\n\t\th: FALLBACK_ACTOR_HEIGHT,\n\t\tbottomY: startY + totalHeight - FALLBACK_ACTOR_HEIGHT,\n\t}))\n}\n\nfunction getMessageLabel(msg: Message): string | undefined {\n\treturn typeof msg.message === 'string' ? msg.message : undefined\n}\n\n/** Count how many renderable events (signals + notes) a message list contains. */\nexport function countSequenceEvents(messages: Message[]): number {\n\tlet count = 0\n\tfor (const msg of messages) {\n\t\tif (isAutonumber(msg.type)) continue\n\t\tif (getFragmentStartKeyword(msg.type)) continue\n\t\tif (isFragmentEnd(msg.type)) continue\n\t\tif (getFragmentSeparatorKeyword(msg.type)) continue\n\t\tif (isActiveStart(msg.type) || isActiveEnd(msg.type)) continue\n\t\tconst isEvent =\n\t\t\t(isSignalMessage(msg.type) && msg.from && msg.to) || (isNoteMessage(msg.type) && msg.from)\n\t\tif (isEvent) count++\n\t}\n\treturn count\n}\n\n/** Parse sequence-diagram SVG layout data for use by {@link sequenceToBlueprint}. */\nexport function parseSequenceLayout(\n\troot: Element,\n\tactorCount: number,\n\teventCount: number\n): ParsedSequenceLayout {\n\treturn {\n\t\tactorLayouts: computeActorLayouts(root, actorCount, eventCount),\n\t\tnoteRects: parseSvgRects(root, 'rect.note'),\n\t}\n}\n\n/**\n * Build a complete blueprint for a sequence diagram:\n * top actors, lifelines, bottom actors, fragments, notes, and signal edges.\n */\nexport function sequenceToBlueprint(\n\tlayout: ParsedSequenceLayout,\n\tactors: Map<string, Actor>,\n\tactorKeys: string[],\n\tmessages: Message[],\n\tcreatedActors: Map<string, number> = new Map(),\n\tdestroyedActors: Map<string, number> = new Map()\n): DiagramMermaidBlueprint {\n\tconst actorCount = actorKeys.length\n\tconst keyIndex = new Map(actorKeys.map((key, i) => [key, i]))\n\n\tconst fragments: FragmentSpan[] = []\n\tconst fragmentStack: OpenFragment[] = []\n\tconst events: Message[] = []\n\tconst activationStack = new Map<string, number[]>()\n\tconst activationSpans: ActivationSpan[] = []\n\n\tlet autonumberStart = 0\n\tlet autonumberStep = 0\n\tlet autonumberVisible = false\n\n\tfor (const msg of messages) {\n\t\tif (isAutonumber(msg.type)) {\n\t\t\tautonumberStart = 1\n\t\t\tautonumberStep = 1\n\t\t\tautonumberVisible = true\n\t\t\tcontinue\n\t\t}\n\n\t\tconst keyword = getFragmentStartKeyword(msg.type)\n\t\tif (keyword) {\n\t\t\tfragmentStack.push({\n\t\t\t\tkeyword,\n\t\t\t\tsections: [{ title: getMessageLabel(msg) ?? '', firstEventIndex: events.length }],\n\t\t\t\tfirstEventIndex: events.length,\n\t\t\t\tactorKeys: new Set(),\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isFragmentEnd(msg.type)) {\n\t\t\tconst frag = fragmentStack.pop()\n\t\t\tif (frag) fragments.push({ ...frag, lastEventIndex: events.length - 1 })\n\t\t\tcontinue\n\t\t}\n\n\t\tif (getFragmentSeparatorKeyword(msg.type)) {\n\t\t\tconst current = fragmentStack[fragmentStack.length - 1]\n\t\t\tif (current) {\n\t\t\t\tcurrent.sections.push({\n\t\t\t\t\ttitle: getMessageLabel(msg) ?? '',\n\t\t\t\t\tfirstEventIndex: events.length,\n\t\t\t\t})\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isActiveStart(msg.type)) {\n\t\t\tconst key = msg.from ?? msg.to\n\t\t\tif (key) {\n\t\t\t\tif (!activationStack.has(key)) activationStack.set(key, [])\n\t\t\t\t// Explicit `activate` follows the triggering arrow,\n\t\t\t\t// so the activation starts at the previous event.\n\t\t\t\tactivationStack.get(key)!.push(Math.max(0, events.length - 1))\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isActiveEnd(msg.type)) {\n\t\t\tconst key = msg.from ?? msg.to\n\t\t\tif (key) {\n\t\t\t\tconst startIdx = activationStack.get(key)?.pop()\n\t\t\t\tif (startIdx !== undefined) {\n\t\t\t\t\tactivationSpans.push({\n\t\t\t\t\t\tparticipantKey: key,\n\t\t\t\t\t\tstartEventIndex: startIdx,\n\t\t\t\t\t\tendEventIndex: Math.max(events.length - 1, startIdx),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tconst isEvent =\n\t\t\t(isSignalMessage(msg.type) && msg.from && msg.to) || (isNoteMessage(msg.type) && msg.from)\n\t\tif (!isEvent) continue\n\n\t\tfor (const frag of fragmentStack) {\n\t\t\tif (msg.from) frag.actorKeys.add(msg.from)\n\t\t\tif (msg.to) frag.actorKeys.add(msg.to)\n\t\t}\n\t\tevents.push(msg)\n\t}\n\n\tconst layouts = layout.actorLayouts\n\n\t// Pre-compute lifecycle event indices for created/destroyed actors.\n\t// We scan events for the first signal targeting each created actor\n\t// and the first signal from each destroyed actor.\n\tconst creationEventIndex = new Map<string, number>()\n\tconst destructionEventIndex = new Map<string, number>()\n\tfor (let i = 0; i < events.length; i++) {\n\t\tconst ev = events[i]\n\t\tif (!isSignalMessage(ev.type)) continue\n\n\t\tif (ev.to && createdActors.has(ev.to) && !creationEventIndex.has(ev.to)) {\n\t\t\tcreationEventIndex.set(ev.to, i)\n\t\t}\n\t\tif (ev.from && destroyedActors.has(ev.from) && !destructionEventIndex.has(ev.from)) {\n\t\t\tdestructionEventIndex.set(ev.from, i)\n\t\t}\n\t}\n\n\t// Build blueprint\n\tconst svgNoteRects = layout.noteRects\n\tlet svgNoteIndex = 0\n\tconst nodes: MermaidBlueprintNode[] = []\n\tconst lines: MermaidBlueprintLineNode[] = []\n\tconst edges: MermaidBlueprintEdge[] = []\n\n\tconst { y: firstY, h: firstH, bottomY: firstBottomY } = layouts[0]\n\tconst lifelineTop = firstY + firstH\n\tconst eventStep = (firstBottomY - lifelineTop) / (events.length + 1)\n\n\t// --- Z-order: lifelines -> activations -> fragments -> actor boxes -> notes/arrows ---\n\n\t// 1. Lifelines (behind everything)\n\tfor (let i = 0; i < actorCount; i++) {\n\t\tconst key = actorKeys[i]\n\t\tconst { x, y, w, h, bottomY } = layouts[i]\n\n\t\tconst isCreated = creationEventIndex.has(key)\n\t\tconst isDestroyed = destructionEventIndex.has(key)\n\t\tconst eventY = isCreated ? lifelineTop + eventStep * (creationEventIndex.get(key)! + 1) : 0\n\t\tconst topY = isCreated ? eventY + h / 2 : y + h\n\t\tconst botY = isDestroyed\n\t\t\t? lifelineTop + eventStep * (destructionEventIndex.get(key)! + 1)\n\t\t\t: bottomY\n\n\t\tconst lifelineHeight = botY - topY\n\t\tif (lifelineHeight > 0) {\n\t\t\tlines.push({ id: `lifeline-${key}`, x: x + w / 2, y: topY, endY: lifelineHeight })\n\t\t}\n\t}\n\n\t// 2. Activation boxes (just after lifelines)\n\tconst activationPad = eventStep * ACTIVATION_PAD_RATIO\n\tconst sortedSpans = activationSpans\n\t\t.map((span, origIdx) => ({ ...span, origIdx }))\n\t\t.sort((a, b) => {\n\t\t\tconst sizeA = a.endEventIndex - a.startEventIndex\n\t\t\tconst sizeB = b.endEventIndex - b.startEventIndex\n\t\t\treturn sizeB - sizeA || a.origIdx - b.origIdx\n\t\t})\n\n\tfor (let i = 0; i < sortedSpans.length; i++) {\n\t\tconst span = sortedSpans[i]\n\t\tconst actorIdx = keyIndex.get(span.participantKey)\n\t\tif (actorIdx === undefined) continue\n\n\t\tconst spanSize = span.endEventIndex - span.startEventIndex\n\t\tlet depth = 0\n\t\tfor (const other of sortedSpans) {\n\t\t\tif (other === span) continue\n\t\t\tconst sameParticipant = other.participantKey === span.participantKey\n\t\t\tconst containsSpan =\n\t\t\t\tother.startEventIndex <= span.startEventIndex && other.endEventIndex >= span.endEventIndex\n\t\t\tconst strictlyLarger = other.endEventIndex - other.startEventIndex > spanSize\n\t\t\tif (sameParticipant && containsSpan && strictlyLarger) depth++\n\t\t}\n\n\t\tconst layout = layouts[actorIdx]\n\t\tconst lifelineCenterX = layout.x + layout.w / 2\n\t\tconst boxTop = lifelineTop + eventStep * (span.startEventIndex + 1) - activationPad\n\t\tconst boxBottom = lifelineTop + eventStep * (span.endEventIndex + 1) + activationPad\n\n\t\tconst id = `activation-${span.origIdx}`\n\t\tconst kind = 'sequence_activation'\n\t\tnodes.push({\n\t\t\tid,\n\t\t\tkind,\n\t\t\tx: lifelineCenterX - ACTIVATION_BOX_WIDTH / 2 + depth * ACTIVATION_NEST_OFFSET,\n\t\t\ty: boxTop,\n\t\t\tw: ACTIVATION_BOX_WIDTH,\n\t\t\th: boxBottom - boxTop,\n\t\t\tfill: 'solid',\n\t\t\tcolor: 'light-violet',\n\t\t\tsize: 's',\n\t\t})\n\t}\n\n\t// 3. Fragments\n\tfor (let fragmentIndex = 0; fragmentIndex < fragments.length; fragmentIndex++) {\n\t\tconst fragment = fragments[fragmentIndex]\n\t\tif (fragment.lastEventIndex < fragment.firstEventIndex) continue\n\n\t\tconst fragTop = lifelineTop + eventStep * (fragment.firstEventIndex + 1) - FRAGMENT_PADDING_TOP\n\t\tconst fragBottom =\n\t\t\tlifelineTop + eventStep * (fragment.lastEventIndex + 1) + FRAGMENT_PADDING_BOTTOM\n\t\tconst indices = [...fragment.actorKeys].map((k) => keyIndex.get(k)!).filter((idx) => idx >= 0)\n\t\tif (indices.length === 0) continue\n\n\t\tconst minIndex = Math.min(...indices)\n\t\tconst maxIndex = Math.max(...indices)\n\t\tconst leftX = layouts[minIndex].x - FRAGMENT_PADDING_X\n\t\tconst fragW = layouts[maxIndex].x + layouts[maxIndex].w + FRAGMENT_PADDING_X - leftX\n\t\tconst fragH = fragBottom - fragTop\n\n\t\tconst rgbColor =\n\t\t\tfragment.keyword === 'rect' ? parseRgbToTldrawColor(fragment.sections[0].title) : null\n\t\tconst fragId = `fragment-${fragmentIndex}`\n\t\tconst fragKind = 'sequence_fragment'\n\t\tif (rgbColor) {\n\t\t\tnodes.push({\n\t\t\t\tid: fragId,\n\t\t\t\tkind: fragKind,\n\t\t\t\tx: leftX,\n\t\t\t\ty: fragTop,\n\t\t\t\tw: fragW,\n\t\t\t\th: fragH,\n\t\t\t\tfill: rgbColor.hasAlpha ? 'semi' : 'solid',\n\t\t\t\tcolor: rgbColor.color,\n\t\t\t\tsize: 's',\n\t\t\t})\n\t\t} else {\n\t\t\tnodes.push({\n\t\t\t\tid: fragId,\n\t\t\t\tkind: fragKind,\n\t\t\t\tx: leftX,\n\t\t\t\ty: fragTop,\n\t\t\t\tw: fragW,\n\t\t\t\th: fragH,\n\t\t\t\tdash: 'dashed',\n\t\t\t\tfill: 'none',\n\t\t\t\tcolor: 'light-blue',\n\t\t\t\tsize: 's',\n\t\t\t\talign: 'start',\n\t\t\t\tverticalAlign: 'start',\n\t\t\t\tlabel: `${fragment.keyword} [${fragment.sections[0].title}]`,\n\t\t\t})\n\n\t\t\tfor (let s = 1; s < fragment.sections.length; s++) {\n\t\t\t\tconst section = fragment.sections[s]\n\t\t\t\tconst sepY = lifelineTop + eventStep * (section.firstEventIndex + 0.5)\n\n\t\t\t\tlines.push({\n\t\t\t\t\tid: `fragment-${fragmentIndex}-sep-${s}`,\n\t\t\t\t\tx: leftX,\n\t\t\t\t\ty: sepY,\n\t\t\t\t\tendX: fragW,\n\t\t\t\t\tendY: 0,\n\t\t\t\t\tdash: 'dashed',\n\t\t\t\t\tcolor: 'light-blue',\n\t\t\t\t\tsize: 's',\n\t\t\t\t})\n\n\t\t\t\tconst secId = `fragment-${fragmentIndex}-section-${s}`\n\t\t\t\tconst secKind = 'sequence_fragment_section'\n\t\t\t\tnodes.push({\n\t\t\t\t\tid: secId,\n\t\t\t\t\tkind: secKind,\n\t\t\t\t\tx: leftX + FRAGMENT_SECTION_LABEL_PADDING,\n\t\t\t\t\ty: sepY + FRAGMENT_SECTION_LABEL_PADDING,\n\t\t\t\t\tw: fragW - FRAGMENT_SECTION_LABEL_PADDING * 2,\n\t\t\t\t\th: FRAGMENT_SECTION_LABEL_HEIGHT,\n\t\t\t\t\tfill: 'none',\n\t\t\t\t\tdash: 'dashed',\n\t\t\t\t\tcolor: 'light-blue',\n\t\t\t\t\tsize: 's',\n\t\t\t\t\talign: 'start',\n\t\t\t\t\tverticalAlign: 'start',\n\t\t\t\t\tlabel: `[${section.title}]`,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\t// 4. Actor boxes (top and bottom)\n\tfor (let i = 0; i < actorCount; i++) {\n\t\tconst key = actorKeys[i]\n\t\tconst actor = actors.get(key)\n\t\tif (!actor) continue\n\t\tconst { x, y, w, h, bottomY } = layouts[i]\n\t\tconst isCreated = creationEventIndex.has(key)\n\t\tconst isDestroyed = destructionEventIndex.has(key)\n\t\tconst kind = actor.type\n\t\tconst label = actor.description || actor.name || key\n\t\tconst shared = {\n\t\t\tkind,\n\t\t\tlabel,\n\t\t\talign: 'middle' as const,\n\t\t\tverticalAlign: 'middle' as const,\n\t\t\tsize: 's' as const,\n\t\t}\n\n\t\tconst creationY = isCreated ? lifelineTop + eventStep * (creationEventIndex.get(key)! + 1) : 0\n\t\tconst topY = isCreated ? creationY - h / 2 : y\n\t\tconst topId = `actor-top-${key}`\n\t\tnodes.push({\n\t\t\tid: topId,\n\t\t\tx,\n\t\t\ty: topY,\n\t\t\tw,\n\t\t\th,\n\t\t\t...shared,\n\t\t})\n\n\t\tif (!isDestroyed) {\n\t\t\tconst botId = `actor-bottom-${key}`\n\t\t\tnodes.push({\n\t\t\t\tid: botId,\n\t\t\t\tx,\n\t\t\t\ty: bottomY,\n\t\t\t\tw,\n\t\t\t\th,\n\t\t\t\t...shared,\n\t\t\t})\n\t\t}\n\t}\n\n\t// 5. Events: signals and notes\n\tconst pendingCreations = new Set(createdActors.keys())\n\tlet sequenceNumber = autonumberStart\n\n\tfor (let eventIndex = 0; eventIndex < events.length; eventIndex++) {\n\t\tconst msg = events[eventIndex]\n\t\tconst anchor = (eventIndex + 1) / (events.length + 1)\n\n\t\tif (isSignalMessage(msg.type)) {\n\t\t\tconst fromKey = msg.from!\n\t\t\tconst toKey = msg.to!\n\t\t\tif (!keyIndex.has(fromKey) || !keyIndex.has(toKey)) continue\n\n\t\t\tconst isCreationMessage = pendingCreations.has(toKey)\n\t\t\tif (isCreationMessage) pendingCreations.delete(toKey)\n\n\t\t\tconst msgType = msg.type ?? LINETYPE.SOLID\n\t\t\tconst { dash, arrowheadEnd } = mapLineTypeToArrowProps(msgType)\n\t\t\tconst isSelf = fromKey === toKey\n\t\t\tconst bidir = !isSelf && isBidirectional(msgType)\n\n\t\t\tconst edge: MermaidBlueprintEdge = {\n\t\t\t\tstartNodeId: `lifeline-${fromKey}`,\n\t\t\t\tendNodeId: isCreationMessage ? `actor-top-${toKey}` : `lifeline-${toKey}`,\n\t\t\t\tlabel: getMessageLabel(msg),\n\t\t\t\tbend: isSelf ? SELF_MSG_BEND : 0,\n\t\t\t\tdash,\n\t\t\t\tarrowheadEnd,\n\t\t\t\tarrowheadStart: bidir ? 'arrow' : 'none',\n\t\t\t\tsize: 's',\n\t\t\t\tanchorStartY: isSelf ? anchor - SELF_MSG_Y_OFFSET : anchor,\n\t\t\t\tanchorEndY: isCreationMessage ? 0.5 : isSelf ? anchor + SELF_MSG_Y_OFFSET : anchor,\n\t\t\t\tisExact: true,\n\t\t\t\tisPrecise: true,\n\t\t\t\t...(isCreationMessage && { isExactEnd: false, isPreciseEnd: false }),\n\t\t\t}\n\n\t\t\tif (autonumberVisible) {\n\t\t\t\tedge.decoration = { type: 'autonumber', value: String(sequenceNumber) }\n\t\t\t\tsequenceNumber += autonumberStep\n\t\t\t}\n\n\t\t\tedges.push(edge)\n\t\t} else if (isNoteMessage(msg.type)) {\n\t\t\tconst eventY = lifelineTop + eventStep * (eventIndex + 1)\n\t\t\tconst fromKey = msg.from!\n\t\t\tconst fromIdx = keyIndex.get(fromKey)\n\t\t\tconst toIdx = keyIndex.get(msg.to ?? fromKey)\n\t\t\tif (fromIdx === undefined) continue\n\n\t\t\tconst label = getMessageLabel(msg)\n\t\t\t// Mermaid types `placement` as a string enum but the runtime value is numeric\n\t\t\tconst msgPlacement = msg.placement as unknown as number | undefined\n\t\t\tconst fromCenterX = layouts[fromIdx].x + layouts[fromIdx].w / 2\n\t\t\tconst toCenterX = toIdx !== undefined ? layouts[toIdx].x + layouts[toIdx].w / 2 : fromCenterX\n\t\t\tconst isSpanning =\n\t\t\t\tmsgPlacement === PLACEMENT.OVER && msg.from !== msg.to && toIdx !== undefined\n\n\t\t\tconst svgNote = svgNoteRects[svgNoteIndex++]\n\t\t\tconst noteHeight = svgNote?.h ?? FALLBACK_NOTE_HEIGHT\n\t\t\tconst textWidth = label ? label.length * NOTE_CHAR_WIDTH + NOTE_TEXT_PADDING : 0\n\t\t\tconst baseWidth = Math.max(svgNote?.w ?? FALLBACK_NOTE_WIDTH, textWidth)\n\t\t\tconst noteWidth = isSpanning\n\t\t\t\t? Math.max(baseWidth, Math.abs(toCenterX - fromCenterX) + NOTE_PADDING)\n\t\t\t\t: baseWidth\n\n\t\t\tlet noteX: number\n\t\t\tif (msgPlacement === PLACEMENT.LEFTOF) {\n\t\t\t\tnoteX = fromCenterX - noteWidth - NOTE_PADDING\n\t\t\t} else if (msgPlacement === PLACEMENT.RIGHTOF) {\n\t\t\t\tnoteX = fromCenterX + NOTE_PADDING\n\t\t\t} else if (isSpanning) {\n\t\t\t\tnoteX = (fromCenterX + toCenterX) / 2 - noteWidth / 2\n\t\t\t} else {\n\t\t\t\tnoteX = fromCenterX - noteWidth / 2\n\t\t\t}\n\n\t\t\tconst noteId = `note-${eventIndex}`\n\t\t\tconst noteKind = 'sequence_note'\n\t\t\tnodes.push({\n\t\t\t\tid: noteId,\n\t\t\t\tkind: noteKind,\n\t\t\t\tx: noteX,\n\t\t\t\ty: eventY - noteHeight / 2,\n\t\t\t\tw: noteWidth,\n\t\t\t\th: noteHeight,\n\t\t\t\tfill: 'solid',\n\t\t\t\tcolor: 'yellow',\n\t\t\t\tdash: 'draw',\n\t\t\t\tsize: 's',\n\t\t\t\talign: 'middle',\n\t\t\t\tverticalAlign: 'middle',\n\t\t\t\tlabel,\n\t\t\t})\n\t\t}\n\t}\n\n\treturn {\n\t\tdiagramKind: 'sequence',\n\t\tnodes,\n\t\tedges,\n\t\tlines,\n\t\tgroups: actorKeys.map((key) => {\n\t\t\tconst group = [`actor-top-${key}`, `lifeline-${key}`]\n\t\t\tif (!destructionEventIndex.has(key)) {\n\t\t\t\tgroup.push(`actor-bottom-${key}`)\n\t\t\t}\n\t\t\treturn group\n\t\t}),\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["layout"]
|
|
7
7
|
}
|
|
@@ -157,12 +157,16 @@ function parseStateDiagramLayout(root) {
|
|
|
157
157
|
const nodes = parseNodesFromSvg(
|
|
158
158
|
root,
|
|
159
159
|
".node",
|
|
160
|
-
(domId) => domId.match(/^state-(.+)-\d+$/)?.[1] ?? domId
|
|
160
|
+
(domId) => domId.match(/^(?:mermaid-\d+-)?state-(.+)-\d+$/)?.[1] ?? domId
|
|
161
|
+
);
|
|
162
|
+
const clusters = parseClustersFromSvg(
|
|
163
|
+
root,
|
|
164
|
+
".statediagram-cluster",
|
|
165
|
+
(domId) => domId.match(/^(?:mermaid-\d+-)?state-(.+)-\d+$/)?.[1] ?? domId
|
|
161
166
|
);
|
|
162
|
-
const clusters = parseClustersFromSvg(root, ".statediagram-cluster");
|
|
163
167
|
const edges = parseAllEdgePointsFromSvg(
|
|
164
168
|
root,
|
|
165
|
-
(dataId) =>
|
|
169
|
+
(dataId) => /(?:^|-)edge\d+$/.test(dataId) ? { start: "", end: "" } : null
|
|
166
170
|
);
|
|
167
171
|
scaleLayout(nodes, clusters, edges, LAYOUT_SCALE);
|
|
168
172
|
return { nodes, clusters, edges };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/stateDiagram.ts"],
|
|
4
|
-
"sourcesContent": ["import type { StateStmt, StyleClass } from 'mermaid/dist/diagrams/state/stateDb.d.ts'\nimport type {\n\tDiagramMermaidBlueprint,\n\tMermaidBlueprintEdge,\n\tMermaidBlueprintNode,\n} from './blueprint'\nimport { buildClassDefColorMap, type ParsedNodeColors } from './colors'\nimport {\n\tbuildNodeCentersFromSvg,\n\tparseAllEdgePointsFromSvg,\n\tparseClustersFromSvg,\n\ttype ParsedDiagramLayout,\n\tparseNodesFromSvg,\n\tscaleLayout,\n} from './svgParsing'\nimport { getArrowBend, LAYOUT_SCALE, orderTopDown } from './utils'\n\ninterface DiagramEdge {\n\tid1: string\n\tid2: string\n\trelationTitle?: string\n}\n\ninterface FlatState {\n\tid: string\n\ttype: string\n\tlabel: string\n}\n\nfunction getEffectiveType(state: StateStmt): string {\n\tif (state.type && state.type !== 'default') return state.type\n\t// Mermaid auto-generates start/end pseudo-state ids ending with \"_start\"\n\t// or \"_end\", optionally followed by a disambiguation digit (e.g. \"_start2\").\n\tif (/_start\\d*$/.test(state.id)) return 'start'\n\tif (/_end\\d*$/.test(state.id)) return 'end'\n\treturn state.type || 'default'\n}\n\nconst UNLABELED_TYPES = new Set(['start', 'end'])\n\nfunction getStateLabel(state: StateStmt): string {\n\tif (state.descriptions && state.descriptions.length > 0) {\n\t\treturn state.descriptions.join('\\n')\n\t}\n\tif (state.description) return state.description\n\tif (UNLABELED_TYPES.has(getEffectiveType(state))) return ''\n\treturn state.id\n}\n\ninterface FlattenResult {\n\tleafStates: Map<string, FlatState>\n\tcompoundLabels: Map<string, string>\n\tparentOf: Map<string, string>\n\tallEdges: DiagramEdge[]\n}\n\nfunction flattenStateHierarchy(\n\tstates: Map<string, StateStmt>,\n\trelations: DiagramEdge[],\n\tparentCompound: string | null = null,\n\ttopLevelStates?: Map<string, StateStmt>\n): FlattenResult {\n\tconst leafStates = new Map<string, FlatState>()\n\tconst compoundLabels = new Map<string, string>()\n\tconst parentOf = new Map<string, string>()\n\tconst allEdges: DiagramEdge[] = []\n\tconst root = topLevelStates ?? states\n\n\tfor (const [id, state] of states) {\n\t\tif (parentCompound) parentOf.set(id, parentCompound)\n\n\t\tif (state.doc && state.doc.length > 0) {\n\t\t\tcompoundLabels.set(id, state.description || id)\n\n\t\t\tconst childStatesMap = new Map<string, StateStmt>()\n\t\t\tconst childRelations: DiagramEdge[] = []\n\n\t\t\tfor (const stmt of state.doc) {\n\t\t\t\tif (typeof stmt === 'string') {\n\t\t\t\t\t// Mermaid emits raw strings for stereotyped state declarations\n\t\t\t\t\t// like `state H <<history>>` \u2014 the ID and stereotype are stored\n\t\t\t\t\t// as separate plain string entries. Look up the state in the\n\t\t\t\t\t// top-level map so it gets proper parentage.\n\t\t\t\t\tconst topState = root.get(stmt)\n\t\t\t\t\tif (topState && !childStatesMap.has(stmt)) {\n\t\t\t\t\t\tchildStatesMap.set(stmt, topState)\n\t\t\t\t\t}\n\t\t\t\t} else if (stmt.stmt === 'state' || stmt.stmt === 'default') {\n\t\t\t\t\tconst stateEntry = stmt as StateStmt\n\t\t\t\t\tchildStatesMap.set(stateEntry.id, stateEntry)\n\t\t\t\t} else if (stmt.stmt === 'relation') {\n\t\t\t\t\tconst relation = stmt as unknown as {\n\t\t\t\t\t\tstate1: StateStmt\n\t\t\t\t\t\tstate2: StateStmt\n\t\t\t\t\t\tdescription?: string\n\t\t\t\t\t}\n\t\t\t\t\t// Relation state refs are shallow objects without `doc`. Only add\n\t\t\t\t\t// them when the state hasn't been registered yet so we don't\n\t\t\t\t\t// overwrite a compound-state entry that carries its nested doc.\n\t\t\t\t\tif (!childStatesMap.has(relation.state1.id)) {\n\t\t\t\t\t\tchildStatesMap.set(relation.state1.id, relation.state1)\n\t\t\t\t\t}\n\t\t\t\t\tif (!childStatesMap.has(relation.state2.id)) {\n\t\t\t\t\t\tchildStatesMap.set(relation.state2.id, relation.state2)\n\t\t\t\t\t}\n\t\t\t\t\tchildRelations.push({\n\t\t\t\t\t\tid1: relation.state1.id,\n\t\t\t\t\t\tid2: relation.state2.id,\n\t\t\t\t\t\trelationTitle: relation.description,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst nested = flattenStateHierarchy(childStatesMap, childRelations, id, root)\n\t\t\tfor (const [key, state] of nested.leafStates) leafStates.set(key, state)\n\t\t\tfor (const [key, label] of nested.compoundLabels) compoundLabels.set(key, label)\n\t\t\tfor (const [key, parent] of nested.parentOf) parentOf.set(key, parent)\n\t\t\tallEdges.push(...nested.allEdges)\n\t\t} else {\n\t\t\tleafStates.set(id, {\n\t\t\t\tid,\n\t\t\t\ttype: getEffectiveType(state),\n\t\t\t\tlabel: getStateLabel(state),\n\t\t\t})\n\t\t}\n\t}\n\n\tallEdges.push(...relations)\n\n\treturn { leafStates, compoundLabels, parentOf, allEdges }\n}\n\nconst FIXED_NODE_SIZES: Record<string, [number, number]> = {\n\tstart: [36, 36],\n\tend: [40, 40],\n}\n\nfunction stateToNodes(\n\tstate: FlatState,\n\tx: number,\n\ty: number,\n\tw: number,\n\th: number,\n\tparentId: string | undefined,\n\tcolors: ParsedNodeColors | undefined\n): MermaidBlueprintNode[] {\n\tconst base = { x, y, w, h, parentId, color: 'black' as const }\n\tconst label = state.label || undefined\n\n\tconst node = (\n\t\tid: string,\n\t\tkind: string,\n\t\tpartial: Partial<Pick<MermaidBlueprintNode, 'x' | 'y' | 'w' | 'h' | 'parentId'>> &\n\t\t\tOmit<MermaidBlueprintNode, 'id' | 'kind' | 'x' | 'y' | 'w' | 'h' | 'parentId'>\n\t): MermaidBlueprintNode => ({\n\t\tid,\n\t\tkind,\n\t\t...base,\n\t\t...partial,\n\t})\n\n\tswitch (state.type) {\n\t\tcase 'note':\n\t\t\treturn [\n\t\t\t\tnode(state.id, 'note', {\n\t\t\t\t\tlabel,\n\t\t\t\t\tfill: 'solid',\n\t\t\t\t\tcolor: 'yellow',\n\t\t\t\t\tsize: 's',\n\t\t\t\t\talign: 'middle',\n\t\t\t\t\tverticalAlign: 'middle',\n\t\t\t\t}),\n\t\t\t]\n\t\tcase 'start':\n\t\t\treturn [node(state.id, 'start', { fill: 'solid' })]\n\t\tcase 'end': {\n\t\t\tconst innerSize = w * 0.6\n\t\t\tconst innerId = `${state.id}__inner`\n\t\t\treturn [\n\t\t\t\tnode(state.id, 'end', { fill: 'none' }),\n\t\t\t\tnode(innerId, 'end_inner', {\n\t\t\t\t\tx: x + (w - innerSize) / 2,\n\t\t\t\t\ty: y + (h - innerSize) / 2,\n\t\t\t\t\tw: innerSize,\n\t\t\t\t\th: innerSize,\n\t\t\t\t\tfill: 'solid',\n\t\t\t\t}),\n\t\t\t]\n\t\t}\n\t\tcase 'fork':\n\t\tcase 'join': {\n\t\t\tconst barW = w * 4\n\t\t\tconst barH = Math.max(16, barW / 10)\n\t\t\treturn [\n\t\t\t\tnode(state.id, state.type, {\n\t\t\t\t\tx: x - (barW - w) / 2,\n\t\t\t\t\ty: y + (h - barH) / 2,\n\t\t\t\t\tw: barW,\n\t\t\t\t\th: barH,\n\t\t\t\t\tfill: 'solid',\n\t\t\t\t}),\n\t\t\t]\n\t\t}\n\t\tcase 'choice':\n\t\t\treturn [\n\t\t\t\tnode(state.id, 'choice', {\n\t\t\t\t\tlabel,\n\t\t\t\t\talign: 'middle',\n\t\t\t\t\tverticalAlign: 'middle',\n\t\t\t\t\tsize: 'm',\n\t\t\t\t}),\n\t\t\t]\n\t\tdefault:\n\t\t\treturn [\n\t\t\t\tnode(state.id, state.type, {\n\t\t\t\t\tlabel,\n\t\t\t\t\t...(colors?.fillColor && { fill: 'solid' as const }),\n\t\t\t\t\t...(colors && { color: colors.strokeColor ?? colors.fillColor }),\n\t\t\t\t\talign: 'middle',\n\t\t\t\t\tverticalAlign: 'middle',\n\t\t\t\t\tsize: 'm',\n\t\t\t\t}),\n\t\t\t]\n\t}\n}\n\nconst FRAME_PAD = 24\nconst FRAME_TOP = 54\n\n/** Parse state-diagram SVG layout data for use by {@link stateToBlueprint}. */\nexport function parseStateDiagramLayout(root: Element): ParsedDiagramLayout {\n\tconst nodes = parseNodesFromSvg(\n\t\troot,\n\t\t'.node',\n\t\t(domId) => domId.match(/^state-(.+)-\\d+$/)?.[1] ?? domId\n\t)\n\tconst clusters = parseClustersFromSvg(root, '.statediagram-cluster')\n\tconst edges = parseAllEdgePointsFromSvg(root, (dataId) =>\n\t\t/^edge\\d+$/.test(dataId) ? { start: '', end: '' } : null\n\t)\n\tscaleLayout(nodes, clusters, edges, LAYOUT_SCALE)\n\treturn { nodes, clusters, edges }\n}\n\n/** Convert a parsed Mermaid state diagram into a tldraw blueprint of nodes and edges. */\nexport function stateToBlueprint(\n\tlayout: ParsedDiagramLayout,\n\tstates: Map<string, StateStmt>,\n\trelations: DiagramEdge[],\n\tclassDefs?: Map<string, StyleClass>\n): DiagramMermaidBlueprint {\n\tconst stateColorMap = classDefs ? buildClassDefColorMap(classDefs, states) : new Map()\n\tconst { nodes: svgNodes, clusters: svgClusters, edges: svgEdges } = layout\n\tconst nodeCenters = buildNodeCentersFromSvg(svgNodes, svgClusters)\n\n\tconst { leafStates, compoundLabels, parentOf, allEdges } = flattenStateHierarchy(\n\t\tstates,\n\t\trelations\n\t)\n\n\t// Collect notes attached to states and add them as synthetic leaf nodes + edges.\n\tfor (const [id, state] of states) {\n\t\tconst note = (state as StateStmt & { note?: { position?: string; text: string } }).note\n\t\tif (!note) continue\n\n\t\tconst noteId = `${id}----note`\n\t\tleafStates.set(noteId, { id: noteId, type: 'note', label: note.text.trim() })\n\t\tallEdges.push({ id1: id, id2: noteId, relationTitle: undefined })\n\t}\n\n\tconst nodeLayout = new Map<string, { absX: number; absY: number; w: number; h: number }>()\n\tfor (const [id, state] of leafStates) {\n\t\tconst svgNode = svgNodes.get(id)\n\t\tif (!svgNode) continue\n\n\t\tconst fixed = FIXED_NODE_SIZES[state.type]\n\t\tconst nodeWidth = fixed ? fixed[0] : svgNode.width + 20\n\t\tconst nodeHeight = fixed ? fixed[1] : svgNode.height + 8\n\t\tnodeLayout.set(id, {\n\t\t\tabsX: svgNode.center.x - nodeWidth / 2,\n\t\t\tabsY: svgNode.center.y - nodeHeight / 2,\n\t\t\tw: nodeWidth,\n\t\t\th: nodeHeight,\n\t\t})\n\t}\n\n\tconst compoundIds = [...compoundLabels.keys()]\n\tconst frameBounds = new Map<string, { absX: number; absY: number; w: number; h: number }>()\n\n\t// Use SVG cluster bounds as the authoritative frame size. Mermaid's\n\t// layout already accounts for label width, padding, and special nodes\n\t// like <<history>> that are rendered outside the visual cluster.\n\t// Fall back to child-based computation only when no SVG cluster exists.\n\tconst bottomUp = orderTopDown(\n\t\tcompoundIds,\n\t\t(id) => id,\n\t\t(id) => parentOf.get(id)\n\t).reverse()\n\n\tfor (const compoundId of bottomUp) {\n\t\tconst cluster = svgClusters.get(compoundId)\n\t\tif (cluster) {\n\t\t\tframeBounds.set(compoundId, {\n\t\t\t\tabsX: cluster.topLeft.x,\n\t\t\t\tabsY: cluster.topLeft.y,\n\t\t\t\tw: cluster.width,\n\t\t\t\th: cluster.height,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tlet frameMinX = Infinity\n\t\tlet frameMinY = Infinity\n\t\tlet frameMaxX = -Infinity\n\t\tlet frameMaxY = -Infinity\n\n\t\tfor (const [id] of leafStates) {\n\t\t\tif (parentOf.get(id) !== compoundId) continue\n\n\t\t\tconst layout = nodeLayout.get(id)\n\t\t\tif (!layout) continue\n\n\t\t\tframeMinX = Math.min(frameMinX, layout.absX)\n\t\t\tframeMinY = Math.min(frameMinY, layout.absY)\n\t\t\tframeMaxX = Math.max(frameMaxX, layout.absX + layout.w)\n\t\t\tframeMaxY = Math.max(frameMaxY, layout.absY + layout.h)\n\t\t}\n\n\t\tfor (const innerId of compoundIds) {\n\t\t\tif (parentOf.get(innerId) !== compoundId) continue\n\n\t\t\tconst innerBounds = frameBounds.get(innerId)\n\t\t\tif (!innerBounds) continue\n\n\t\t\tframeMinX = Math.min(frameMinX, innerBounds.absX)\n\t\t\tframeMinY = Math.min(frameMinY, innerBounds.absY)\n\t\t\tframeMaxX = Math.max(frameMaxX, innerBounds.absX + innerBounds.w)\n\t\t\tframeMaxY = Math.max(frameMaxY, innerBounds.absY + innerBounds.h)\n\t\t}\n\n\t\tif (!isFinite(frameMinX)) continue\n\n\t\tframeBounds.set(compoundId, {\n\t\t\tabsX: frameMinX - FRAME_PAD,\n\t\t\tabsY: frameMinY - FRAME_TOP,\n\t\t\tw: frameMaxX - frameMinX + FRAME_PAD * 2,\n\t\t\th: frameMaxY - frameMinY + FRAME_PAD + FRAME_TOP,\n\t\t})\n\t}\n\n\t// Un-parent any leaf state whose center falls outside its parent frame.\n\t// Mermaid renders some pseudo-states (e.g. <<history>>) outside the\n\t// visual compound cluster even though they're declared inside it.\n\tfor (const [id] of leafStates) {\n\t\tconst pid = parentOf.get(id)\n\t\tif (!pid) continue\n\n\t\tconst frame = frameBounds.get(pid)\n\t\tconst layout = nodeLayout.get(id)\n\t\tif (!frame || !layout) continue\n\n\t\tconst cx = layout.absX + layout.w / 2\n\t\tconst cy = layout.absY + layout.h / 2\n\t\tif (\n\t\t\tcx < frame.absX ||\n\t\t\tcx > frame.absX + frame.w ||\n\t\t\tcy < frame.absY ||\n\t\t\tcy > frame.absY + frame.h\n\t\t) {\n\t\t\tparentOf.delete(id)\n\t\t}\n\t}\n\n\tconst nodes: MermaidBlueprintNode[] = []\n\tconst blueprintEdges: MermaidBlueprintEdge[] = []\n\n\tfor (const compoundId of orderTopDown(\n\t\tcompoundIds,\n\t\t(id) => id,\n\t\t(id) => parentOf.get(id)\n\t)) {\n\t\tconst bounds = frameBounds.get(compoundId)\n\t\tif (!bounds) continue\n\n\t\tconst kind = 'compound'\n\t\tnodes.push({\n\t\t\tid: compoundId,\n\t\t\tkind,\n\t\t\tx: bounds.absX,\n\t\t\ty: bounds.absY,\n\t\t\tw: bounds.w,\n\t\t\th: bounds.h,\n\t\t\tparentId: parentOf.get(compoundId),\n\t\t\tlabel: compoundLabels.get(compoundId) || compoundId,\n\t\t\tfill: 'semi',\n\t\t\tcolor: 'black',\n\t\t\tdash: 'draw',\n\t\t\tsize: 's',\n\t\t\talign: 'middle',\n\t\t\tverticalAlign: 'start',\n\t\t})\n\t}\n\n\tfor (const [id, state] of leafStates) {\n\t\tconst layout = nodeLayout.get(id)\n\t\tif (!layout) continue\n\n\t\tnodes.push(\n\t\t\t...stateToNodes(\n\t\t\t\tstate,\n\t\t\t\tlayout.absX,\n\t\t\t\tlayout.absY,\n\t\t\t\tlayout.w,\n\t\t\t\tlayout.h,\n\t\t\t\tparentOf.get(id),\n\t\t\t\tstateColorMap.get(id)\n\t\t\t)\n\t\t)\n\t}\n\n\tconst claimed = new Set<number>()\n\n\tfor (const edge of allEdges) {\n\t\tconst startCenter = nodeCenters.get(edge.id1)\n\t\tconst endCenter = nodeCenters.get(edge.id2)\n\n\t\tlet bend = 0\n\t\tif (startCenter && endCenter) {\n\t\t\tlet bestIndex = -1\n\t\t\tlet bestDistance = Infinity\n\t\t\tfor (let edgeIndex = 0; edgeIndex < svgEdges.length; edgeIndex++) {\n\t\t\t\tif (claimed.has(edgeIndex) || svgEdges[edgeIndex].points.length < 2) continue\n\n\t\t\t\tconst points = svgEdges[edgeIndex].points\n\t\t\t\tconst distance =\n\t\t\t\t\tMath.hypot(points[0].x - startCenter.x, points[0].y - startCenter.y) +\n\t\t\t\t\tMath.hypot(\n\t\t\t\t\t\tpoints[points.length - 1].x - endCenter.x,\n\t\t\t\t\t\tpoints[points.length - 1].y - endCenter.y\n\t\t\t\t\t)\n\t\t\t\tif (distance < bestDistance) {\n\t\t\t\t\tbestDistance = distance\n\t\t\t\t\tbestIndex = edgeIndex\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (bestIndex >= 0) {\n\t\t\t\tclaimed.add(bestIndex)\n\t\t\t\tbend = getArrowBend(svgEdges[bestIndex])\n\t\t\t}\n\t\t}\n\n\t\tconst isNoteEdge = edge.id2.endsWith('----note') || edge.id1.endsWith('----note')\n\t\tblueprintEdges.push({\n\t\t\tstartNodeId: edge.id1,\n\t\t\tendNodeId: edge.id2,\n\t\t\tlabel: edge.relationTitle,\n\t\t\tbend,\n\t\t\t...(isNoteEdge && { dash: 'dotted' as const, arrowheadEnd: 'none' as const }),\n\t\t})\n\t}\n\n\tconst nodeIds = new Set(nodes.map((n) => n.id))\n\tconst validEdges = blueprintEdges.filter(\n\t\t(e) => nodeIds.has(e.startNodeId) && nodeIds.has(e.endNodeId)\n\t)\n\treturn { diagramKind: 'state', nodes, edges: validEdges }\n}\n"],
|
|
5
|
-
"mappings": "AAMA,SAAS,6BAAoD;AAC7D;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OACM;AACP,SAAS,cAAc,cAAc,oBAAoB;AAczD,SAAS,iBAAiB,OAA0B;AACnD,MAAI,MAAM,QAAQ,MAAM,SAAS,UAAW,QAAO,MAAM;AAGzD,MAAI,aAAa,KAAK,MAAM,EAAE,EAAG,QAAO;AACxC,MAAI,WAAW,KAAK,MAAM,EAAE,EAAG,QAAO;AACtC,SAAO,MAAM,QAAQ;AACtB;AAEA,MAAM,kBAAkB,oBAAI,IAAI,CAAC,SAAS,KAAK,CAAC;AAEhD,SAAS,cAAc,OAA0B;AAChD,MAAI,MAAM,gBAAgB,MAAM,aAAa,SAAS,GAAG;AACxD,WAAO,MAAM,aAAa,KAAK,IAAI;AAAA,EACpC;AACA,MAAI,MAAM,YAAa,QAAO,MAAM;AACpC,MAAI,gBAAgB,IAAI,iBAAiB,KAAK,CAAC,EAAG,QAAO;AACzD,SAAO,MAAM;AACd;AASA,SAAS,sBACR,QACA,WACA,iBAAgC,MAChC,gBACgB;AAChB,QAAM,aAAa,oBAAI,IAAuB;AAC9C,QAAM,iBAAiB,oBAAI,IAAoB;AAC/C,QAAM,WAAW,oBAAI,IAAoB;AACzC,QAAM,WAA0B,CAAC;AACjC,QAAM,OAAO,kBAAkB;AAE/B,aAAW,CAAC,IAAI,KAAK,KAAK,QAAQ;AACjC,QAAI,eAAgB,UAAS,IAAI,IAAI,cAAc;AAEnD,QAAI,MAAM,OAAO,MAAM,IAAI,SAAS,GAAG;AACtC,qBAAe,IAAI,IAAI,MAAM,eAAe,EAAE;AAE9C,YAAM,iBAAiB,oBAAI,IAAuB;AAClD,YAAM,iBAAgC,CAAC;AAEvC,iBAAW,QAAQ,MAAM,KAAK;AAC7B,YAAI,OAAO,SAAS,UAAU;AAK7B,gBAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,cAAI,YAAY,CAAC,eAAe,IAAI,IAAI,GAAG;AAC1C,2BAAe,IAAI,MAAM,QAAQ;AAAA,UAClC;AAAA,QACD,WAAW,KAAK,SAAS,WAAW,KAAK,SAAS,WAAW;AAC5D,gBAAM,aAAa;AACnB,yBAAe,IAAI,WAAW,IAAI,UAAU;AAAA,QAC7C,WAAW,KAAK,SAAS,YAAY;AACpC,gBAAM,WAAW;AAQjB,cAAI,CAAC,eAAe,IAAI,SAAS,OAAO,EAAE,GAAG;AAC5C,2BAAe,IAAI,SAAS,OAAO,IAAI,SAAS,MAAM;AAAA,UACvD;AACA,cAAI,CAAC,eAAe,IAAI,SAAS,OAAO,EAAE,GAAG;AAC5C,2BAAe,IAAI,SAAS,OAAO,IAAI,SAAS,MAAM;AAAA,UACvD;AACA,yBAAe,KAAK;AAAA,YACnB,KAAK,SAAS,OAAO;AAAA,YACrB,KAAK,SAAS,OAAO;AAAA,YACrB,eAAe,SAAS;AAAA,UACzB,CAAC;AAAA,QACF;AAAA,MACD;AAEA,YAAM,SAAS,sBAAsB,gBAAgB,gBAAgB,IAAI,IAAI;AAC7E,iBAAW,CAAC,KAAKA,MAAK,KAAK,OAAO,WAAY,YAAW,IAAI,KAAKA,MAAK;AACvE,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,eAAgB,gBAAe,IAAI,KAAK,KAAK;AAC/E,iBAAW,CAAC,KAAK,MAAM,KAAK,OAAO,SAAU,UAAS,IAAI,KAAK,MAAM;AACrE,eAAS,KAAK,GAAG,OAAO,QAAQ;AAAA,IACjC,OAAO;AACN,iBAAW,IAAI,IAAI;AAAA,QAClB;AAAA,QACA,MAAM,iBAAiB,KAAK;AAAA,QAC5B,OAAO,cAAc,KAAK;AAAA,MAC3B,CAAC;AAAA,IACF;AAAA,EACD;AAEA,WAAS,KAAK,GAAG,SAAS;AAE1B,SAAO,EAAE,YAAY,gBAAgB,UAAU,SAAS;AACzD;AAEA,MAAM,mBAAqD;AAAA,EAC1D,OAAO,CAAC,IAAI,EAAE;AAAA,EACd,KAAK,CAAC,IAAI,EAAE;AACb;AAEA,SAAS,aACR,OACA,GACA,GACA,GACA,GACA,UACA,QACyB;AACzB,QAAM,OAAO,EAAE,GAAG,GAAG,GAAG,GAAG,UAAU,OAAO,QAAiB;AAC7D,QAAM,QAAQ,MAAM,SAAS;AAE7B,QAAM,OAAO,CACZ,IACA,MACA,aAE2B;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH,GAAG;AAAA,EACJ;AAEA,UAAQ,MAAM,MAAM;AAAA,IACnB,KAAK;AACJ,aAAO;AAAA,QACN,KAAK,MAAM,IAAI,QAAQ;AAAA,UACtB;AAAA,UACA,MAAM;AAAA,UACN,OAAO;AAAA,UACP,MAAM;AAAA,UACN,OAAO;AAAA,UACP,eAAe;AAAA,QAChB,CAAC;AAAA,MACF;AAAA,IACD,KAAK;AACJ,aAAO,CAAC,KAAK,MAAM,IAAI,SAAS,EAAE,MAAM,QAAQ,CAAC,CAAC;AAAA,IACnD,KAAK,OAAO;AACX,YAAM,YAAY,IAAI;AACtB,YAAM,UAAU,GAAG,MAAM,EAAE;AAC3B,aAAO;AAAA,QACN,KAAK,MAAM,IAAI,OAAO,EAAE,MAAM,OAAO,CAAC;AAAA,QACtC,KAAK,SAAS,aAAa;AAAA,UAC1B,GAAG,KAAK,IAAI,aAAa;AAAA,UACzB,GAAG,KAAK,IAAI,aAAa;AAAA,UACzB,GAAG;AAAA,UACH,GAAG;AAAA,UACH,MAAM;AAAA,QACP,CAAC;AAAA,MACF;AAAA,IACD;AAAA,IACA,KAAK;AAAA,IACL,KAAK,QAAQ;AACZ,YAAM,OAAO,IAAI;AACjB,YAAM,OAAO,KAAK,IAAI,IAAI,OAAO,EAAE;AACnC,aAAO;AAAA,QACN,KAAK,MAAM,IAAI,MAAM,MAAM;AAAA,UAC1B,GAAG,KAAK,OAAO,KAAK;AAAA,UACpB,GAAG,KAAK,IAAI,QAAQ;AAAA,UACpB,GAAG;AAAA,UACH,GAAG;AAAA,UACH,MAAM;AAAA,QACP,CAAC;AAAA,MACF;AAAA,IACD;AAAA,IACA,KAAK;AACJ,aAAO;AAAA,QACN,KAAK,MAAM,IAAI,UAAU;AAAA,UACxB;AAAA,UACA,OAAO;AAAA,UACP,eAAe;AAAA,UACf,MAAM;AAAA,QACP,CAAC;AAAA,MACF;AAAA,IACD;AACC,aAAO;AAAA,QACN,KAAK,MAAM,IAAI,MAAM,MAAM;AAAA,UAC1B;AAAA,UACA,GAAI,QAAQ,aAAa,EAAE,MAAM,QAAiB;AAAA,UAClD,GAAI,UAAU,EAAE,OAAO,OAAO,eAAe,OAAO,UAAU;AAAA,UAC9D,OAAO;AAAA,UACP,eAAe;AAAA,UACf,MAAM;AAAA,QACP,CAAC;AAAA,MACF;AAAA,EACF;AACD;AAEA,MAAM,YAAY;AAClB,MAAM,YAAY;AAGX,SAAS,wBAAwB,MAAoC;
|
|
4
|
+
"sourcesContent": ["import type { StateStmt, StyleClass } from 'mermaid/dist/diagrams/state/stateDb.d.ts'\nimport type {\n\tDiagramMermaidBlueprint,\n\tMermaidBlueprintEdge,\n\tMermaidBlueprintNode,\n} from './blueprint'\nimport { buildClassDefColorMap, type ParsedNodeColors } from './colors'\nimport {\n\tbuildNodeCentersFromSvg,\n\tparseAllEdgePointsFromSvg,\n\tparseClustersFromSvg,\n\ttype ParsedDiagramLayout,\n\tparseNodesFromSvg,\n\tscaleLayout,\n} from './svgParsing'\nimport { getArrowBend, LAYOUT_SCALE, orderTopDown } from './utils'\n\ninterface DiagramEdge {\n\tid1: string\n\tid2: string\n\trelationTitle?: string\n}\n\ninterface FlatState {\n\tid: string\n\ttype: string\n\tlabel: string\n}\n\nfunction getEffectiveType(state: StateStmt): string {\n\tif (state.type && state.type !== 'default') return state.type\n\t// Mermaid auto-generates start/end pseudo-state ids ending with \"_start\"\n\t// or \"_end\", optionally followed by a disambiguation digit (e.g. \"_start2\").\n\tif (/_start\\d*$/.test(state.id)) return 'start'\n\tif (/_end\\d*$/.test(state.id)) return 'end'\n\treturn state.type || 'default'\n}\n\nconst UNLABELED_TYPES = new Set(['start', 'end'])\n\nfunction getStateLabel(state: StateStmt): string {\n\tif (state.descriptions && state.descriptions.length > 0) {\n\t\treturn state.descriptions.join('\\n')\n\t}\n\tif (state.description) return state.description\n\tif (UNLABELED_TYPES.has(getEffectiveType(state))) return ''\n\treturn state.id\n}\n\ninterface FlattenResult {\n\tleafStates: Map<string, FlatState>\n\tcompoundLabels: Map<string, string>\n\tparentOf: Map<string, string>\n\tallEdges: DiagramEdge[]\n}\n\nfunction flattenStateHierarchy(\n\tstates: Map<string, StateStmt>,\n\trelations: DiagramEdge[],\n\tparentCompound: string | null = null,\n\ttopLevelStates?: Map<string, StateStmt>\n): FlattenResult {\n\tconst leafStates = new Map<string, FlatState>()\n\tconst compoundLabels = new Map<string, string>()\n\tconst parentOf = new Map<string, string>()\n\tconst allEdges: DiagramEdge[] = []\n\tconst root = topLevelStates ?? states\n\n\tfor (const [id, state] of states) {\n\t\tif (parentCompound) parentOf.set(id, parentCompound)\n\n\t\tif (state.doc && state.doc.length > 0) {\n\t\t\tcompoundLabels.set(id, state.description || id)\n\n\t\t\tconst childStatesMap = new Map<string, StateStmt>()\n\t\t\tconst childRelations: DiagramEdge[] = []\n\n\t\t\tfor (const stmt of state.doc) {\n\t\t\t\tif (typeof stmt === 'string') {\n\t\t\t\t\t// Mermaid emits raw strings for stereotyped state declarations\n\t\t\t\t\t// like `state H <<history>>` \u2014 the ID and stereotype are stored\n\t\t\t\t\t// as separate plain string entries. Look up the state in the\n\t\t\t\t\t// top-level map so it gets proper parentage.\n\t\t\t\t\tconst topState = root.get(stmt)\n\t\t\t\t\tif (topState && !childStatesMap.has(stmt)) {\n\t\t\t\t\t\tchildStatesMap.set(stmt, topState)\n\t\t\t\t\t}\n\t\t\t\t} else if (stmt.stmt === 'state' || stmt.stmt === 'default') {\n\t\t\t\t\tconst stateEntry = stmt as StateStmt\n\t\t\t\t\tchildStatesMap.set(stateEntry.id, stateEntry)\n\t\t\t\t} else if (stmt.stmt === 'relation') {\n\t\t\t\t\tconst relation = stmt as unknown as {\n\t\t\t\t\t\tstate1: StateStmt\n\t\t\t\t\t\tstate2: StateStmt\n\t\t\t\t\t\tdescription?: string\n\t\t\t\t\t}\n\t\t\t\t\t// Relation state refs are shallow objects without `doc`. Only add\n\t\t\t\t\t// them when the state hasn't been registered yet so we don't\n\t\t\t\t\t// overwrite a compound-state entry that carries its nested doc.\n\t\t\t\t\tif (!childStatesMap.has(relation.state1.id)) {\n\t\t\t\t\t\tchildStatesMap.set(relation.state1.id, relation.state1)\n\t\t\t\t\t}\n\t\t\t\t\tif (!childStatesMap.has(relation.state2.id)) {\n\t\t\t\t\t\tchildStatesMap.set(relation.state2.id, relation.state2)\n\t\t\t\t\t}\n\t\t\t\t\tchildRelations.push({\n\t\t\t\t\t\tid1: relation.state1.id,\n\t\t\t\t\t\tid2: relation.state2.id,\n\t\t\t\t\t\trelationTitle: relation.description,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst nested = flattenStateHierarchy(childStatesMap, childRelations, id, root)\n\t\t\tfor (const [key, state] of nested.leafStates) leafStates.set(key, state)\n\t\t\tfor (const [key, label] of nested.compoundLabels) compoundLabels.set(key, label)\n\t\t\tfor (const [key, parent] of nested.parentOf) parentOf.set(key, parent)\n\t\t\tallEdges.push(...nested.allEdges)\n\t\t} else {\n\t\t\tleafStates.set(id, {\n\t\t\t\tid,\n\t\t\t\ttype: getEffectiveType(state),\n\t\t\t\tlabel: getStateLabel(state),\n\t\t\t})\n\t\t}\n\t}\n\n\tallEdges.push(...relations)\n\n\treturn { leafStates, compoundLabels, parentOf, allEdges }\n}\n\nconst FIXED_NODE_SIZES: Record<string, [number, number]> = {\n\tstart: [36, 36],\n\tend: [40, 40],\n}\n\nfunction stateToNodes(\n\tstate: FlatState,\n\tx: number,\n\ty: number,\n\tw: number,\n\th: number,\n\tparentId: string | undefined,\n\tcolors: ParsedNodeColors | undefined\n): MermaidBlueprintNode[] {\n\tconst base = { x, y, w, h, parentId, color: 'black' as const }\n\tconst label = state.label || undefined\n\n\tconst node = (\n\t\tid: string,\n\t\tkind: string,\n\t\tpartial: Partial<Pick<MermaidBlueprintNode, 'x' | 'y' | 'w' | 'h' | 'parentId'>> &\n\t\t\tOmit<MermaidBlueprintNode, 'id' | 'kind' | 'x' | 'y' | 'w' | 'h' | 'parentId'>\n\t): MermaidBlueprintNode => ({\n\t\tid,\n\t\tkind,\n\t\t...base,\n\t\t...partial,\n\t})\n\n\tswitch (state.type) {\n\t\tcase 'note':\n\t\t\treturn [\n\t\t\t\tnode(state.id, 'note', {\n\t\t\t\t\tlabel,\n\t\t\t\t\tfill: 'solid',\n\t\t\t\t\tcolor: 'yellow',\n\t\t\t\t\tsize: 's',\n\t\t\t\t\talign: 'middle',\n\t\t\t\t\tverticalAlign: 'middle',\n\t\t\t\t}),\n\t\t\t]\n\t\tcase 'start':\n\t\t\treturn [node(state.id, 'start', { fill: 'solid' })]\n\t\tcase 'end': {\n\t\t\tconst innerSize = w * 0.6\n\t\t\tconst innerId = `${state.id}__inner`\n\t\t\treturn [\n\t\t\t\tnode(state.id, 'end', { fill: 'none' }),\n\t\t\t\tnode(innerId, 'end_inner', {\n\t\t\t\t\tx: x + (w - innerSize) / 2,\n\t\t\t\t\ty: y + (h - innerSize) / 2,\n\t\t\t\t\tw: innerSize,\n\t\t\t\t\th: innerSize,\n\t\t\t\t\tfill: 'solid',\n\t\t\t\t}),\n\t\t\t]\n\t\t}\n\t\tcase 'fork':\n\t\tcase 'join': {\n\t\t\tconst barW = w * 4\n\t\t\tconst barH = Math.max(16, barW / 10)\n\t\t\treturn [\n\t\t\t\tnode(state.id, state.type, {\n\t\t\t\t\tx: x - (barW - w) / 2,\n\t\t\t\t\ty: y + (h - barH) / 2,\n\t\t\t\t\tw: barW,\n\t\t\t\t\th: barH,\n\t\t\t\t\tfill: 'solid',\n\t\t\t\t}),\n\t\t\t]\n\t\t}\n\t\tcase 'choice':\n\t\t\treturn [\n\t\t\t\tnode(state.id, 'choice', {\n\t\t\t\t\tlabel,\n\t\t\t\t\talign: 'middle',\n\t\t\t\t\tverticalAlign: 'middle',\n\t\t\t\t\tsize: 'm',\n\t\t\t\t}),\n\t\t\t]\n\t\tdefault:\n\t\t\treturn [\n\t\t\t\tnode(state.id, state.type, {\n\t\t\t\t\tlabel,\n\t\t\t\t\t...(colors?.fillColor && { fill: 'solid' as const }),\n\t\t\t\t\t...(colors && { color: colors.strokeColor ?? colors.fillColor }),\n\t\t\t\t\talign: 'middle',\n\t\t\t\t\tverticalAlign: 'middle',\n\t\t\t\t\tsize: 'm',\n\t\t\t\t}),\n\t\t\t]\n\t}\n}\n\nconst FRAME_PAD = 24\nconst FRAME_TOP = 54\n\n/** Parse state-diagram SVG layout data for use by {@link stateToBlueprint}. */\nexport function parseStateDiagramLayout(root: Element): ParsedDiagramLayout {\n\t// Mermaid 11.15 prefixes node and cluster dom ids with the diagram id (e.g.\n\t// `mermaid-0-state-Foo-1` instead of `state-Foo-1`), so tolerate that\n\t// optional `mermaid-<n>-` prefix when reading the clean id.\n\tconst nodes = parseNodesFromSvg(\n\t\troot,\n\t\t'.node',\n\t\t(domId) => domId.match(/^(?:mermaid-\\d+-)?state-(.+)-\\d+$/)?.[1] ?? domId\n\t)\n\tconst clusters = parseClustersFromSvg(\n\t\troot,\n\t\t'.statediagram-cluster',\n\t\t(domId) => domId.match(/^(?:mermaid-\\d+-)?state-(.+)-\\d+$/)?.[1] ?? domId\n\t)\n\tconst edges = parseAllEdgePointsFromSvg(root, (dataId) =>\n\t\t/(?:^|-)edge\\d+$/.test(dataId) ? { start: '', end: '' } : null\n\t)\n\tscaleLayout(nodes, clusters, edges, LAYOUT_SCALE)\n\treturn { nodes, clusters, edges }\n}\n\n/** Convert a parsed Mermaid state diagram into a tldraw blueprint of nodes and edges. */\nexport function stateToBlueprint(\n\tlayout: ParsedDiagramLayout,\n\tstates: Map<string, StateStmt>,\n\trelations: DiagramEdge[],\n\tclassDefs?: Map<string, StyleClass>\n): DiagramMermaidBlueprint {\n\tconst stateColorMap = classDefs ? buildClassDefColorMap(classDefs, states) : new Map()\n\tconst { nodes: svgNodes, clusters: svgClusters, edges: svgEdges } = layout\n\tconst nodeCenters = buildNodeCentersFromSvg(svgNodes, svgClusters)\n\n\tconst { leafStates, compoundLabels, parentOf, allEdges } = flattenStateHierarchy(\n\t\tstates,\n\t\trelations\n\t)\n\n\t// Collect notes attached to states and add them as synthetic leaf nodes + edges.\n\tfor (const [id, state] of states) {\n\t\tconst note = (state as StateStmt & { note?: { position?: string; text: string } }).note\n\t\tif (!note) continue\n\n\t\tconst noteId = `${id}----note`\n\t\tleafStates.set(noteId, { id: noteId, type: 'note', label: note.text.trim() })\n\t\tallEdges.push({ id1: id, id2: noteId, relationTitle: undefined })\n\t}\n\n\tconst nodeLayout = new Map<string, { absX: number; absY: number; w: number; h: number }>()\n\tfor (const [id, state] of leafStates) {\n\t\tconst svgNode = svgNodes.get(id)\n\t\tif (!svgNode) continue\n\n\t\tconst fixed = FIXED_NODE_SIZES[state.type]\n\t\tconst nodeWidth = fixed ? fixed[0] : svgNode.width + 20\n\t\tconst nodeHeight = fixed ? fixed[1] : svgNode.height + 8\n\t\tnodeLayout.set(id, {\n\t\t\tabsX: svgNode.center.x - nodeWidth / 2,\n\t\t\tabsY: svgNode.center.y - nodeHeight / 2,\n\t\t\tw: nodeWidth,\n\t\t\th: nodeHeight,\n\t\t})\n\t}\n\n\tconst compoundIds = [...compoundLabels.keys()]\n\tconst frameBounds = new Map<string, { absX: number; absY: number; w: number; h: number }>()\n\n\t// Use SVG cluster bounds as the authoritative frame size. Mermaid's\n\t// layout already accounts for label width, padding, and special nodes\n\t// like <<history>> that are rendered outside the visual cluster.\n\t// Fall back to child-based computation only when no SVG cluster exists.\n\tconst bottomUp = orderTopDown(\n\t\tcompoundIds,\n\t\t(id) => id,\n\t\t(id) => parentOf.get(id)\n\t).reverse()\n\n\tfor (const compoundId of bottomUp) {\n\t\tconst cluster = svgClusters.get(compoundId)\n\t\tif (cluster) {\n\t\t\tframeBounds.set(compoundId, {\n\t\t\t\tabsX: cluster.topLeft.x,\n\t\t\t\tabsY: cluster.topLeft.y,\n\t\t\t\tw: cluster.width,\n\t\t\t\th: cluster.height,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tlet frameMinX = Infinity\n\t\tlet frameMinY = Infinity\n\t\tlet frameMaxX = -Infinity\n\t\tlet frameMaxY = -Infinity\n\n\t\tfor (const [id] of leafStates) {\n\t\t\tif (parentOf.get(id) !== compoundId) continue\n\n\t\t\tconst layout = nodeLayout.get(id)\n\t\t\tif (!layout) continue\n\n\t\t\tframeMinX = Math.min(frameMinX, layout.absX)\n\t\t\tframeMinY = Math.min(frameMinY, layout.absY)\n\t\t\tframeMaxX = Math.max(frameMaxX, layout.absX + layout.w)\n\t\t\tframeMaxY = Math.max(frameMaxY, layout.absY + layout.h)\n\t\t}\n\n\t\tfor (const innerId of compoundIds) {\n\t\t\tif (parentOf.get(innerId) !== compoundId) continue\n\n\t\t\tconst innerBounds = frameBounds.get(innerId)\n\t\t\tif (!innerBounds) continue\n\n\t\t\tframeMinX = Math.min(frameMinX, innerBounds.absX)\n\t\t\tframeMinY = Math.min(frameMinY, innerBounds.absY)\n\t\t\tframeMaxX = Math.max(frameMaxX, innerBounds.absX + innerBounds.w)\n\t\t\tframeMaxY = Math.max(frameMaxY, innerBounds.absY + innerBounds.h)\n\t\t}\n\n\t\tif (!isFinite(frameMinX)) continue\n\n\t\tframeBounds.set(compoundId, {\n\t\t\tabsX: frameMinX - FRAME_PAD,\n\t\t\tabsY: frameMinY - FRAME_TOP,\n\t\t\tw: frameMaxX - frameMinX + FRAME_PAD * 2,\n\t\t\th: frameMaxY - frameMinY + FRAME_PAD + FRAME_TOP,\n\t\t})\n\t}\n\n\t// Un-parent any leaf state whose center falls outside its parent frame.\n\t// Mermaid renders some pseudo-states (e.g. <<history>>) outside the\n\t// visual compound cluster even though they're declared inside it.\n\tfor (const [id] of leafStates) {\n\t\tconst pid = parentOf.get(id)\n\t\tif (!pid) continue\n\n\t\tconst frame = frameBounds.get(pid)\n\t\tconst layout = nodeLayout.get(id)\n\t\tif (!frame || !layout) continue\n\n\t\tconst cx = layout.absX + layout.w / 2\n\t\tconst cy = layout.absY + layout.h / 2\n\t\tif (\n\t\t\tcx < frame.absX ||\n\t\t\tcx > frame.absX + frame.w ||\n\t\t\tcy < frame.absY ||\n\t\t\tcy > frame.absY + frame.h\n\t\t) {\n\t\t\tparentOf.delete(id)\n\t\t}\n\t}\n\n\tconst nodes: MermaidBlueprintNode[] = []\n\tconst blueprintEdges: MermaidBlueprintEdge[] = []\n\n\tfor (const compoundId of orderTopDown(\n\t\tcompoundIds,\n\t\t(id) => id,\n\t\t(id) => parentOf.get(id)\n\t)) {\n\t\tconst bounds = frameBounds.get(compoundId)\n\t\tif (!bounds) continue\n\n\t\tconst kind = 'compound'\n\t\tnodes.push({\n\t\t\tid: compoundId,\n\t\t\tkind,\n\t\t\tx: bounds.absX,\n\t\t\ty: bounds.absY,\n\t\t\tw: bounds.w,\n\t\t\th: bounds.h,\n\t\t\tparentId: parentOf.get(compoundId),\n\t\t\tlabel: compoundLabels.get(compoundId) || compoundId,\n\t\t\tfill: 'semi',\n\t\t\tcolor: 'black',\n\t\t\tdash: 'draw',\n\t\t\tsize: 's',\n\t\t\talign: 'middle',\n\t\t\tverticalAlign: 'start',\n\t\t})\n\t}\n\n\tfor (const [id, state] of leafStates) {\n\t\tconst layout = nodeLayout.get(id)\n\t\tif (!layout) continue\n\n\t\tnodes.push(\n\t\t\t...stateToNodes(\n\t\t\t\tstate,\n\t\t\t\tlayout.absX,\n\t\t\t\tlayout.absY,\n\t\t\t\tlayout.w,\n\t\t\t\tlayout.h,\n\t\t\t\tparentOf.get(id),\n\t\t\t\tstateColorMap.get(id)\n\t\t\t)\n\t\t)\n\t}\n\n\tconst claimed = new Set<number>()\n\n\tfor (const edge of allEdges) {\n\t\tconst startCenter = nodeCenters.get(edge.id1)\n\t\tconst endCenter = nodeCenters.get(edge.id2)\n\n\t\tlet bend = 0\n\t\tif (startCenter && endCenter) {\n\t\t\tlet bestIndex = -1\n\t\t\tlet bestDistance = Infinity\n\t\t\tfor (let edgeIndex = 0; edgeIndex < svgEdges.length; edgeIndex++) {\n\t\t\t\tif (claimed.has(edgeIndex) || svgEdges[edgeIndex].points.length < 2) continue\n\n\t\t\t\tconst points = svgEdges[edgeIndex].points\n\t\t\t\tconst distance =\n\t\t\t\t\tMath.hypot(points[0].x - startCenter.x, points[0].y - startCenter.y) +\n\t\t\t\t\tMath.hypot(\n\t\t\t\t\t\tpoints[points.length - 1].x - endCenter.x,\n\t\t\t\t\t\tpoints[points.length - 1].y - endCenter.y\n\t\t\t\t\t)\n\t\t\t\tif (distance < bestDistance) {\n\t\t\t\t\tbestDistance = distance\n\t\t\t\t\tbestIndex = edgeIndex\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (bestIndex >= 0) {\n\t\t\t\tclaimed.add(bestIndex)\n\t\t\t\tbend = getArrowBend(svgEdges[bestIndex])\n\t\t\t}\n\t\t}\n\n\t\tconst isNoteEdge = edge.id2.endsWith('----note') || edge.id1.endsWith('----note')\n\t\tblueprintEdges.push({\n\t\t\tstartNodeId: edge.id1,\n\t\t\tendNodeId: edge.id2,\n\t\t\tlabel: edge.relationTitle,\n\t\t\tbend,\n\t\t\t...(isNoteEdge && { dash: 'dotted' as const, arrowheadEnd: 'none' as const }),\n\t\t})\n\t}\n\n\tconst nodeIds = new Set(nodes.map((n) => n.id))\n\tconst validEdges = blueprintEdges.filter(\n\t\t(e) => nodeIds.has(e.startNodeId) && nodeIds.has(e.endNodeId)\n\t)\n\treturn { diagramKind: 'state', nodes, edges: validEdges }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["state", "layout"]
|
|
7
7
|
}
|
package/dist-esm/svgParsing.mjs
CHANGED
|
@@ -81,10 +81,10 @@ function parseNodesFromSvg(root, selector, idParser) {
|
|
|
81
81
|
}
|
|
82
82
|
return out;
|
|
83
83
|
}
|
|
84
|
-
function parseClustersFromSvg(root, selector) {
|
|
84
|
+
function parseClustersFromSvg(root, selector, idParser = (id) => id) {
|
|
85
85
|
const out = /* @__PURE__ */ new Map();
|
|
86
86
|
for (const groupEl of root.querySelectorAll(selector)) {
|
|
87
|
-
const id = groupEl.getAttribute("id") || "";
|
|
87
|
+
const id = idParser(groupEl.getAttribute("id") || "");
|
|
88
88
|
const rect = groupEl.querySelector("rect");
|
|
89
89
|
if (!rect) continue;
|
|
90
90
|
const rx = parseFloat(rect.getAttribute("x") || "0");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/svgParsing.ts"],
|
|
4
|
-
"sourcesContent": ["export interface Vec2 {\n\tx: number\n\ty: number\n}\n\nexport interface ParsedNode {\n\tid: string\n\tcenter: Vec2\n\twidth: number\n\theight: number\n}\n\nexport interface ParsedCluster {\n\tid: string\n\ttopLeft: Vec2\n\twidth: number\n\theight: number\n}\n\ntype NodeIdParser = (domId: string) => string\ntype EdgeIdParser = (dataId: string) => { start: string; end: string } | null\n\nfunction parseTranslate(attr: string | null): Vec2 {\n\tif (!attr) return { x: 0, y: 0 }\n\t// Matches SVG translate transforms, e.g. transform=\"translate(123.45, 67.8)\".\n\t// Handles scientific notation (1.2e+3). Group 1 = x offset, group 2 = y offset.\n\tconst translateMatch = attr.match(/translate\\(\\s*([\\d.e+-]+)[,\\s]+([\\d.e+-]+)\\s*\\)/)\n\tif (!translateMatch) return { x: 0, y: 0 }\n\treturn { x: parseFloat(translateMatch[1]), y: parseFloat(translateMatch[2]) }\n}\n\nexport function getAccumulatedTranslate(el: Element): Vec2 {\n\tlet x = 0\n\tlet y = 0\n\tlet cur: Element | null = el.parentElement\n\twhile (cur) {\n\t\tconst parentTranslate = parseTranslate(cur.getAttribute('transform'))\n\t\tx += parentTranslate.x\n\t\ty += parentTranslate.y\n\t\tcur = cur.parentElement\n\t}\n\treturn { x, y }\n}\n\n/**\n * Extract element dimensions from a live SVG element using getBBox(),\n * falling back to attribute parsing for non-browser environments (jsdom).\n */\nfunction getNodeDimensions(groupEl: Element): { w: number; h: number } {\n\tconst shapeEl = groupEl.querySelector('.label-container')\n\tif (shapeEl) {\n\t\ttry {\n\t\t\tconst bbox = (shapeEl as SVGGraphicsElement).getBBox()\n\t\t\tif (bbox.width > 0 && bbox.height > 0) return { w: bbox.width, h: bbox.height }\n\t\t} catch {\n\t\t\t/* fall through */\n\t\t}\n\t}\n\n\ttry {\n\t\tconst bbox = (groupEl as SVGGraphicsElement).getBBox()\n\t\tif (bbox.width > 0 && bbox.height > 0) return { w: bbox.width, h: bbox.height }\n\t} catch {\n\t\t/* fall through */\n\t}\n\n\tconst rect = groupEl.querySelector('rect')\n\tif (rect) {\n\t\tconst w = parseFloat(rect.getAttribute('width') || '0')\n\t\tconst h = parseFloat(rect.getAttribute('height') || '0')\n\t\tif (w > 0 && h > 0) return { w, h }\n\t}\n\tconst poly = groupEl.querySelector('polygon')\n\tif (poly) {\n\t\tconst pts = (poly.getAttribute('points') || '')\n\t\t\t.trim()\n\t\t\t.split(/\\s+/)\n\t\t\t.map((pointStr) => pointStr.split(',').map(Number))\n\t\tlet minX = Infinity\n\t\tlet maxX = -Infinity\n\t\tlet minY = Infinity\n\t\tlet maxY = -Infinity\n\t\tfor (const [px, py] of pts) {\n\t\t\tminX = Math.min(minX, px)\n\t\t\tmaxX = Math.max(maxX, px)\n\t\t\tminY = Math.min(minY, py)\n\t\t\tmaxY = Math.max(maxY, py)\n\t\t}\n\t\tif (maxX > minX && maxY > minY) return { w: maxX - minX, h: maxY - minY }\n\t}\n\tconst circle = groupEl.querySelector('circle')\n\tif (circle) {\n\t\tconst r = parseFloat(circle.getAttribute('r') || '0')\n\t\tif (r > 0) return { w: r * 2, h: r * 2 }\n\t}\n\tconst ellipse = groupEl.querySelector('ellipse')\n\tif (ellipse) {\n\t\tconst w = parseFloat(ellipse.getAttribute('rx') || '0') * 2\n\t\tconst h = parseFloat(ellipse.getAttribute('ry') || '0') * 2\n\t\tif (w > 0 && h > 0) return { w, h }\n\t}\n\treturn { w: 0, h: 0 }\n}\n\nexport function parseNodesFromSvg(\n\troot: Element,\n\tselector: string,\n\tidParser: NodeIdParser\n): Map<string, ParsedNode> {\n\tconst out = new Map<string, ParsedNode>()\n\tfor (const groupEl of root.querySelectorAll(selector)) {\n\t\tconst rawId = groupEl.getAttribute('id') || ''\n\t\tconst id = idParser(rawId)\n\t\tconst self = parseTranslate(groupEl.getAttribute('transform'))\n\t\tconst ancestor = getAccumulatedTranslate(groupEl)\n\t\tconst { w, h } = getNodeDimensions(groupEl)\n\t\tout.set(id, {\n\t\t\tid,\n\t\t\tcenter: { x: ancestor.x + self.x, y: ancestor.y + self.y },\n\t\t\twidth: w,\n\t\t\theight: h,\n\t\t})\n\t}\n\treturn out\n}\n\nexport function parseClustersFromSvg(
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["export interface Vec2 {\n\tx: number\n\ty: number\n}\n\nexport interface ParsedNode {\n\tid: string\n\tcenter: Vec2\n\twidth: number\n\theight: number\n}\n\nexport interface ParsedCluster {\n\tid: string\n\ttopLeft: Vec2\n\twidth: number\n\theight: number\n}\n\ntype NodeIdParser = (domId: string) => string\ntype EdgeIdParser = (dataId: string) => { start: string; end: string } | null\n\nfunction parseTranslate(attr: string | null): Vec2 {\n\tif (!attr) return { x: 0, y: 0 }\n\t// Matches SVG translate transforms, e.g. transform=\"translate(123.45, 67.8)\".\n\t// Handles scientific notation (1.2e+3). Group 1 = x offset, group 2 = y offset.\n\tconst translateMatch = attr.match(/translate\\(\\s*([\\d.e+-]+)[,\\s]+([\\d.e+-]+)\\s*\\)/)\n\tif (!translateMatch) return { x: 0, y: 0 }\n\treturn { x: parseFloat(translateMatch[1]), y: parseFloat(translateMatch[2]) }\n}\n\nexport function getAccumulatedTranslate(el: Element): Vec2 {\n\tlet x = 0\n\tlet y = 0\n\tlet cur: Element | null = el.parentElement\n\twhile (cur) {\n\t\tconst parentTranslate = parseTranslate(cur.getAttribute('transform'))\n\t\tx += parentTranslate.x\n\t\ty += parentTranslate.y\n\t\tcur = cur.parentElement\n\t}\n\treturn { x, y }\n}\n\n/**\n * Extract element dimensions from a live SVG element using getBBox(),\n * falling back to attribute parsing for non-browser environments (jsdom).\n */\nfunction getNodeDimensions(groupEl: Element): { w: number; h: number } {\n\tconst shapeEl = groupEl.querySelector('.label-container')\n\tif (shapeEl) {\n\t\ttry {\n\t\t\tconst bbox = (shapeEl as SVGGraphicsElement).getBBox()\n\t\t\tif (bbox.width > 0 && bbox.height > 0) return { w: bbox.width, h: bbox.height }\n\t\t} catch {\n\t\t\t/* fall through */\n\t\t}\n\t}\n\n\ttry {\n\t\tconst bbox = (groupEl as SVGGraphicsElement).getBBox()\n\t\tif (bbox.width > 0 && bbox.height > 0) return { w: bbox.width, h: bbox.height }\n\t} catch {\n\t\t/* fall through */\n\t}\n\n\tconst rect = groupEl.querySelector('rect')\n\tif (rect) {\n\t\tconst w = parseFloat(rect.getAttribute('width') || '0')\n\t\tconst h = parseFloat(rect.getAttribute('height') || '0')\n\t\tif (w > 0 && h > 0) return { w, h }\n\t}\n\tconst poly = groupEl.querySelector('polygon')\n\tif (poly) {\n\t\tconst pts = (poly.getAttribute('points') || '')\n\t\t\t.trim()\n\t\t\t.split(/\\s+/)\n\t\t\t.map((pointStr) => pointStr.split(',').map(Number))\n\t\tlet minX = Infinity\n\t\tlet maxX = -Infinity\n\t\tlet minY = Infinity\n\t\tlet maxY = -Infinity\n\t\tfor (const [px, py] of pts) {\n\t\t\tminX = Math.min(minX, px)\n\t\t\tmaxX = Math.max(maxX, px)\n\t\t\tminY = Math.min(minY, py)\n\t\t\tmaxY = Math.max(maxY, py)\n\t\t}\n\t\tif (maxX > minX && maxY > minY) return { w: maxX - minX, h: maxY - minY }\n\t}\n\tconst circle = groupEl.querySelector('circle')\n\tif (circle) {\n\t\tconst r = parseFloat(circle.getAttribute('r') || '0')\n\t\tif (r > 0) return { w: r * 2, h: r * 2 }\n\t}\n\tconst ellipse = groupEl.querySelector('ellipse')\n\tif (ellipse) {\n\t\tconst w = parseFloat(ellipse.getAttribute('rx') || '0') * 2\n\t\tconst h = parseFloat(ellipse.getAttribute('ry') || '0') * 2\n\t\tif (w > 0 && h > 0) return { w, h }\n\t}\n\treturn { w: 0, h: 0 }\n}\n\nexport function parseNodesFromSvg(\n\troot: Element,\n\tselector: string,\n\tidParser: NodeIdParser\n): Map<string, ParsedNode> {\n\tconst out = new Map<string, ParsedNode>()\n\tfor (const groupEl of root.querySelectorAll(selector)) {\n\t\tconst rawId = groupEl.getAttribute('id') || ''\n\t\tconst id = idParser(rawId)\n\t\tconst self = parseTranslate(groupEl.getAttribute('transform'))\n\t\tconst ancestor = getAccumulatedTranslate(groupEl)\n\t\tconst { w, h } = getNodeDimensions(groupEl)\n\t\tout.set(id, {\n\t\t\tid,\n\t\t\tcenter: { x: ancestor.x + self.x, y: ancestor.y + self.y },\n\t\t\twidth: w,\n\t\t\theight: h,\n\t\t})\n\t}\n\treturn out\n}\n\nexport function parseClustersFromSvg(\n\troot: Element,\n\tselector: string,\n\tidParser: NodeIdParser = (id) => id\n): Map<string, ParsedCluster> {\n\tconst out = new Map<string, ParsedCluster>()\n\tfor (const groupEl of root.querySelectorAll(selector)) {\n\t\tconst id = idParser(groupEl.getAttribute('id') || '')\n\t\tconst rect = groupEl.querySelector('rect')\n\t\tif (!rect) continue\n\t\tconst rx = parseFloat(rect.getAttribute('x') || '0')\n\t\tconst ry = parseFloat(rect.getAttribute('y') || '0')\n\t\tconst w = parseFloat(rect.getAttribute('width') || '0')\n\t\tconst h = parseFloat(rect.getAttribute('height') || '0')\n\t\tconst self = parseTranslate(groupEl.getAttribute('transform'))\n\t\tconst ancestor = getAccumulatedTranslate(groupEl)\n\t\tout.set(id, {\n\t\t\tid,\n\t\t\ttopLeft: { x: ancestor.x + self.x + rx, y: ancestor.y + self.y + ry },\n\t\t\twidth: w,\n\t\t\theight: h,\n\t\t})\n\t}\n\treturn out\n}\n\nexport interface ParsedEdge {\n\tstart: string\n\tend: string\n\tpoints: Vec2[]\n}\n\n/**\n * Pre-parsed SVG layout for flowchart and state diagram converters.\n * Contains already-scaled node, cluster, and edge data.\n */\nexport interface ParsedDiagramLayout {\n\tnodes: Map<string, ParsedNode>\n\tclusters: Map<string, ParsedCluster>\n\tedges: ParsedEdge[]\n}\n\n/**\n * Parse every SVG edge path in DOM order (matching mermaid's edge list order).\n * Unlike the old per-pair map, this preserves all parallel edges individually.\n */\nexport function parseAllEdgePointsFromSvg(root: Element, parser: EdgeIdParser): ParsedEdge[] {\n\tconst out: ParsedEdge[] = []\n\tfor (const path of root.querySelectorAll('path[data-points]')) {\n\t\tconst dataId = path.getAttribute('data-id') || path.getAttribute('id') || ''\n\t\tconst dataPoints = path.getAttribute('data-points')\n\t\tif (!dataPoints) continue\n\t\tconst parsed = parser(dataId)\n\t\tif (!parsed) continue\n\t\ttry {\n\t\t\tconst points = JSON.parse(atob(dataPoints))\n\t\t\tconst ancestor = getAccumulatedTranslate(path as Element)\n\t\t\tfor (const point of points) {\n\t\t\t\tpoint.x += ancestor.x\n\t\t\t\tpoint.y += ancestor.y\n\t\t\t}\n\t\t\tout.push({ start: parsed.start, end: parsed.end, points })\n\t\t} catch {\n\t\t\t/* ignore malformed data */\n\t\t}\n\t}\n\treturn out\n}\n\n/**\n * Build a map of node/cluster id \u2192 center (for flowchart and state diagram edge matching).\n */\nexport function buildNodeCentersFromSvg(\n\tnodes: Map<string, ParsedNode>,\n\tclusters: Map<string, ParsedCluster>\n): Map<string, Vec2> {\n\tconst out = new Map<string, Vec2>()\n\tfor (const [id, node] of nodes) {\n\t\tout.set(id, { x: node.center.x, y: node.center.y })\n\t}\n\tfor (const [id, cluster] of clusters) {\n\t\tout.set(id, {\n\t\t\tx: cluster.topLeft.x + cluster.width / 2,\n\t\t\ty: cluster.topLeft.y + cluster.height / 2,\n\t\t})\n\t}\n\treturn out\n}\n\n// ---------------------------------------------------------------------------\n// Layout scaling and bounds\n// ---------------------------------------------------------------------------\n\nexport function scaleLayout(\n\tnodes: Map<string, ParsedNode>,\n\tclusters: Map<string, ParsedCluster>,\n\tedges: ParsedEdge[],\n\tscale: number\n): void {\n\tfor (const [, node] of nodes) {\n\t\tnode.center.x *= scale\n\t\tnode.center.y *= scale\n\t\tnode.width *= scale\n\t\tnode.height *= scale\n\t}\n\tfor (const [, cluster] of clusters) {\n\t\tcluster.topLeft.x *= scale\n\t\tcluster.topLeft.y *= scale\n\t\tcluster.width *= scale\n\t\tcluster.height *= scale\n\t}\n\tfor (const edge of edges) {\n\t\tfor (const point of edge.points) {\n\t\t\tpoint.x *= scale\n\t\t\tpoint.y *= scale\n\t\t}\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/mermaid",
|
|
3
3
|
"description": "Mermaid diagram to tldraw shape conversion.",
|
|
4
|
-
"version": "5.2.0
|
|
4
|
+
"version": "5.2.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -40,18 +40,21 @@
|
|
|
40
40
|
"lint": "yarn run -T tsx ../../internal/scripts/lint.ts"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@tldraw/tlschema": "5.2.0
|
|
44
|
-
"@tldraw/utils": "5.2.0
|
|
45
|
-
"mermaid": "11.
|
|
43
|
+
"@tldraw/tlschema": "5.2.0",
|
|
44
|
+
"@tldraw/utils": "5.2.0",
|
|
45
|
+
"mermaid": "11.15.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"react": "^18.2.0 || ^19.2.1",
|
|
49
49
|
"react-dom": "^18.2.0 || ^19.2.1",
|
|
50
|
-
"tldraw": "5.2.0
|
|
50
|
+
"tldraw": "5.2.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"lazyrepo": "0.0.0-alpha.27",
|
|
54
|
-
"vitest": "^
|
|
54
|
+
"vitest": "^4.1.7"
|
|
55
|
+
},
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=22.12.0"
|
|
55
58
|
},
|
|
56
59
|
"module": "dist-esm/index.mjs",
|
|
57
60
|
"source": "src/index.ts",
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
let nextMermaidId = 0
|
|
2
2
|
|
|
3
|
-
import mermaid from 'mermaid'
|
|
4
3
|
import type { FlowDB } from 'mermaid/dist/diagrams/flowchart/flowDb.d.ts'
|
|
5
4
|
import type { FlowEdge, FlowSubGraph, FlowVertex } from 'mermaid/dist/diagrams/flowchart/types.js'
|
|
6
5
|
import type { MindmapDB } from 'mermaid/dist/diagrams/mindmap/mindmapDb.d.ts'
|
|
@@ -56,6 +55,13 @@ export async function createMermaidDiagram(
|
|
|
56
55
|
text: string,
|
|
57
56
|
options: MermaidDiagramOptions = {}
|
|
58
57
|
): Promise<void> {
|
|
58
|
+
// load mermaid lazily: it's a large, ESM-only dependency only needed when a
|
|
59
|
+
// diagram is actually created. a dynamic import() works from CommonJS (unlike
|
|
60
|
+
// a static import, which compiles to require(<esm>) and throws
|
|
61
|
+
// ERR_REQUIRE_ESM on Node <20.19, Jest, and ts-node) and avoids pulling
|
|
62
|
+
// mermaid in when @tldraw/mermaid is merely imported.
|
|
63
|
+
const mermaid = (await import('mermaid')).default
|
|
64
|
+
|
|
59
65
|
mermaid.initialize({
|
|
60
66
|
...MERMAID_CONFIG,
|
|
61
67
|
...(options.mermaidConfig ?? {}),
|
package/src/flowchartDiagram.ts
CHANGED
|
@@ -58,13 +58,18 @@ function buildHierarchy(subGraphs: FlowSubGraph[]) {
|
|
|
58
58
|
|
|
59
59
|
/** Parse flowchart-specific SVG layout data for use by {@link flowchartToBlueprint}. */
|
|
60
60
|
export function parseFlowchartLayout(root: Element): ParsedDiagramLayout {
|
|
61
|
+
// Mermaid 11.15 prefixes node and cluster dom ids with the diagram id (e.g.
|
|
62
|
+
// `mermaid-0-flowchart-s1-0` instead of `flowchart-s1-0`), so tolerate that
|
|
63
|
+
// optional `mermaid-<n>-` prefix when reading the clean id.
|
|
61
64
|
const nodes = parseNodesFromSvg(root, '.node', (domId) => {
|
|
62
|
-
const match = domId.match(/^flowchart-(.+)-\d+$/)
|
|
65
|
+
const match = domId.match(/^(?:mermaid-\d+-)?flowchart-(.+)-\d+$/)
|
|
63
66
|
return match ? match[1] : domId
|
|
64
67
|
})
|
|
65
|
-
const clusters = parseClustersFromSvg(root, '.cluster')
|
|
68
|
+
const clusters = parseClustersFromSvg(root, '.cluster', (domId) =>
|
|
69
|
+
domId.replace(/^mermaid-\d+-/, '')
|
|
70
|
+
)
|
|
66
71
|
const edges = parseAllEdgePointsFromSvg(root, (dataId) => {
|
|
67
|
-
const match = dataId.match(
|
|
72
|
+
const match = dataId.match(/(?:^|-)L_(.+)_([^_]+)_\d+$/)
|
|
68
73
|
return match ? { start: match[1], end: match[2] } : null
|
|
69
74
|
})
|
|
70
75
|
scaleLayout(nodes, clusters, edges, LAYOUT_SCALE)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { parseFlowchartLayout } from './flowchartDiagram'
|
|
2
|
+
import { parseStateDiagramLayout } from './stateDiagram'
|
|
3
|
+
|
|
4
|
+
function appendNode(root: Element, domId: string) {
|
|
5
|
+
const group = document.createElement('div')
|
|
6
|
+
group.classList.add('node')
|
|
7
|
+
group.setAttribute('id', domId)
|
|
8
|
+
group.setAttribute('transform', 'translate(100, 50)')
|
|
9
|
+
const rect = document.createElement('rect')
|
|
10
|
+
rect.setAttribute('width', '80')
|
|
11
|
+
rect.setAttribute('height', '40')
|
|
12
|
+
group.appendChild(rect)
|
|
13
|
+
root.appendChild(group)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function appendEdge(root: Element, dataId: string, points: [number, number][]) {
|
|
17
|
+
const path = document.createElement('path')
|
|
18
|
+
path.setAttribute('data-id', dataId)
|
|
19
|
+
path.setAttribute('id', `mermaid-0-${dataId}`)
|
|
20
|
+
path.setAttribute('data-points', btoa(JSON.stringify(points.map(([x, y]) => ({ x, y })))))
|
|
21
|
+
root.appendChild(path)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe('parseFlowchartLayout', () => {
|
|
25
|
+
// Mermaid 11.15 prefixes node dom ids with the diagram id.
|
|
26
|
+
it('parses node ids from diagram-id-prefixed dom ids', () => {
|
|
27
|
+
const root = document.createElement('div')
|
|
28
|
+
appendNode(root, 'mermaid-0-flowchart-s1-0')
|
|
29
|
+
appendNode(root, 'mermaid-0-flowchart-s2-1')
|
|
30
|
+
appendEdge(root, 'L_s1_s2_0', [
|
|
31
|
+
[0, 0],
|
|
32
|
+
[100, 0],
|
|
33
|
+
])
|
|
34
|
+
|
|
35
|
+
const layout = parseFlowchartLayout(root)
|
|
36
|
+
|
|
37
|
+
expect([...layout.nodes.keys()].sort()).toEqual(['s1', 's2'])
|
|
38
|
+
expect(layout.edges.map((e) => [e.start, e.end])).toEqual([['s1', 's2']])
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('still parses legacy unprefixed dom ids', () => {
|
|
42
|
+
const root = document.createElement('div')
|
|
43
|
+
appendNode(root, 'flowchart-s1-0')
|
|
44
|
+
appendEdge(root, 'L_s1_s2_0', [
|
|
45
|
+
[0, 0],
|
|
46
|
+
[100, 0],
|
|
47
|
+
])
|
|
48
|
+
|
|
49
|
+
const layout = parseFlowchartLayout(root)
|
|
50
|
+
|
|
51
|
+
expect([...layout.nodes.keys()]).toEqual(['s1'])
|
|
52
|
+
expect(layout.edges.map((e) => [e.start, e.end])).toEqual([['s1', 's2']])
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe('parseStateDiagramLayout', () => {
|
|
57
|
+
it('parses node ids from diagram-id-prefixed dom ids', () => {
|
|
58
|
+
const root = document.createElement('div')
|
|
59
|
+
appendNode(root, 'mermaid-0-state-Still-2')
|
|
60
|
+
appendNode(root, 'mermaid-0-state-Moving-3')
|
|
61
|
+
appendEdge(root, 'edge0', [
|
|
62
|
+
[0, 0],
|
|
63
|
+
[100, 0],
|
|
64
|
+
])
|
|
65
|
+
|
|
66
|
+
const layout = parseStateDiagramLayout(root)
|
|
67
|
+
|
|
68
|
+
expect([...layout.nodes.keys()].sort()).toEqual(['Moving', 'Still'])
|
|
69
|
+
expect(layout.edges).toHaveLength(1)
|
|
70
|
+
})
|
|
71
|
+
})
|