@pixerate/editor 0.54.0 → 0.56.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/dist/agent/index.cjs +24 -23
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.js +9 -8
- package/dist/agent/index.js.map +1 -1
- package/dist/animation/index.cjs +1 -1
- package/dist/animation/index.cjs.map +1 -1
- package/dist/animation/index.d.cts +2 -1
- package/dist/animation/index.d.ts +2 -1
- package/dist/animation/index.js +1 -1
- package/dist/animation-editor/index.cjs +2221 -0
- package/dist/animation-editor/index.cjs.map +1 -0
- package/dist/animation-editor/index.d.cts +1117 -0
- package/dist/animation-editor/index.d.ts +1117 -0
- package/dist/animation-editor/index.js +2221 -0
- package/dist/animation-editor/index.js.map +1 -0
- package/dist/bezier-BfwIbVTl.d.cts +548 -0
- package/dist/bezier-DYBvLgUH.d.ts +548 -0
- package/dist/canvas/index.cjs +2740 -580
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +402 -6
- package/dist/canvas/index.d.ts +402 -6
- package/dist/canvas/index.js +2735 -575
- package/dist/canvas/index.js.map +1 -1
- package/dist/chart/index.cjs +33 -31
- package/dist/chart/index.cjs.map +1 -1
- package/dist/chart/index.d.cts +4 -2
- package/dist/chart/index.d.ts +4 -2
- package/dist/chart/index.js +21 -19
- package/dist/chart/index.js.map +1 -1
- package/dist/{chunk-C3JHII3M.cjs → chunk-3I6V7PI4.cjs} +45 -45
- package/dist/{chunk-C3JHII3M.cjs.map → chunk-3I6V7PI4.cjs.map} +1 -1
- package/dist/{chunk-P43HUQRX.cjs → chunk-AHCENCU4.cjs} +12 -10
- package/dist/chunk-AHCENCU4.cjs.map +1 -0
- package/dist/{chunk-TO22LX34.js → chunk-GTMJ4Y3S.js} +2208 -2920
- package/dist/chunk-GTMJ4Y3S.js.map +1 -0
- package/dist/chunk-II77MLHN.cjs +11106 -0
- package/dist/chunk-II77MLHN.cjs.map +1 -0
- package/dist/{chunk-OIKYP7XC.js → chunk-LMUDHBWR.js} +2 -2
- package/dist/chunk-MLREO6J3.cjs +737 -0
- package/dist/chunk-MLREO6J3.cjs.map +1 -0
- package/dist/chunk-NONDTTH7.js +5979 -0
- package/dist/chunk-NONDTTH7.js.map +1 -0
- package/dist/{chunk-YNSK4MGT.cjs → chunk-O2UH7LZE.cjs} +1549 -2261
- package/dist/chunk-O2UH7LZE.cjs.map +1 -0
- package/dist/{chunk-VODBAO32.js → chunk-OEFCLWZ3.js} +4 -1425
- package/dist/chunk-OEFCLWZ3.js.map +1 -0
- package/dist/{chunk-NK3WL5TJ.cjs → chunk-P2CTDJNF.cjs} +27 -1448
- package/dist/chunk-P2CTDJNF.cjs.map +1 -0
- package/dist/chunk-TKPPIVW7.cjs +1443 -0
- package/dist/chunk-TKPPIVW7.cjs.map +1 -0
- package/dist/chunk-VWZB6BCY.js +737 -0
- package/dist/chunk-VWZB6BCY.js.map +1 -0
- package/dist/chunk-WJSCGBJ2.js +11106 -0
- package/dist/chunk-WJSCGBJ2.js.map +1 -0
- package/dist/{chunk-RIXTW3C4.js → chunk-WLVZ235X.js} +5 -3
- package/dist/{chunk-RIXTW3C4.js.map → chunk-WLVZ235X.js.map} +1 -1
- package/dist/chunk-XCXQDPID.cjs +5979 -0
- package/dist/chunk-XCXQDPID.cjs.map +1 -0
- package/dist/chunk-ZOH6X3VR.js +1443 -0
- package/dist/chunk-ZOH6X3VR.js.map +1 -0
- package/dist/color-E9pwm--w.d.cts +33 -0
- package/dist/color-E9pwm--w.d.ts +33 -0
- package/dist/commands/index.cjs +2 -2
- package/dist/commands/index.cjs.map +1 -1
- package/dist/commands/index.js +3 -3
- package/dist/{controller-DscWQbjO.d.ts → controller-D2rj5umx.d.ts} +2 -362
- package/dist/{controller-CX0QfSv0.d.cts → controller-R2biKk_E.d.cts} +2 -362
- package/dist/diagram/index.cjs +1481 -50
- package/dist/diagram/index.cjs.map +1 -1
- package/dist/diagram/index.d.cts +1757 -15
- package/dist/diagram/index.d.ts +1757 -15
- package/dist/diagram/index.js +1469 -38
- package/dist/diagram/index.js.map +1 -1
- package/dist/extensions/index.cjs +5 -4
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +4 -3
- package/dist/extensions/index.d.ts +4 -3
- package/dist/extensions/index.js +4 -3
- package/dist/{index-DIWB6xMf.d.cts → index-BcHyG0Wq.d.cts} +2 -1
- package/dist/{index-CALDD35B.d.ts → index-CTCc3m3C.d.ts} +2 -1
- package/dist/index.cjs +10 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/pathfinder-BZL8aSu0.d.cts +469 -0
- package/dist/pathfinder-CNtsbCRK.d.ts +469 -0
- package/dist/{player-DSMjdgQ9.d.cts → player-Dg0FT0UI.d.cts} +1 -33
- package/dist/{player-DdfVrKWq.d.ts → player-W-5DX3Go.d.ts} +1 -33
- package/dist/svg-CLg2zqZA.d.cts +847 -0
- package/dist/svg-CPK82TtU.d.ts +847 -0
- package/dist/types-BRp-6zkY.d.cts +362 -0
- package/dist/types-BRp-6zkY.d.ts +362 -0
- package/dist/{types-BULrFyuQ.d.cts → types-DYkjhzdz.d.cts} +1 -1
- package/dist/{types-BULrFyuQ.d.ts → types-DYkjhzdz.d.ts} +1 -1
- package/dist/vector/index.cjs +1328 -6752
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +6 -846
- package/dist/vector/index.d.ts +6 -846
- package/dist/vector/index.js +645 -6069
- package/dist/vector/index.js.map +1 -1
- package/package.json +6 -1
- package/dist/chunk-H5K77C7Y.cjs +0 -3848
- package/dist/chunk-H5K77C7Y.cjs.map +0 -1
- package/dist/chunk-NK3WL5TJ.cjs.map +0 -1
- package/dist/chunk-P43HUQRX.cjs.map +0 -1
- package/dist/chunk-TO22LX34.js.map +0 -1
- package/dist/chunk-VODBAO32.js.map +0 -1
- package/dist/chunk-WWJNC7SX.js +0 -3848
- package/dist/chunk-WWJNC7SX.js.map +0 -1
- package/dist/chunk-YNSK4MGT.cjs.map +0 -1
- package/dist/pathfinder-B9xh_pCZ.d.ts +0 -1013
- package/dist/pathfinder-QdG70sr9.d.cts +0 -1013
- /package/dist/{chunk-OIKYP7XC.js.map → chunk-LMUDHBWR.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-H5K77C7Y.cjs","../src/diagram/source/lines.ts","../src/diagram/source/metadata.ts","../src/diagram/flowchart/edges.ts","../src/diagram/flowchart/shapes.ts","../src/diagram/flowchart/statements.ts","../src/diagram/flowchart/parse.ts","../src/diagram/flowchart/serialize.ts","../src/diagram/flowchart/edit.ts","../src/diagram/flowchart/index.ts","../src/diagram/lines-grammar/engine.ts","../src/diagram/passthrough.ts","../src/diagram/lines-grammar/state.ts","../src/diagram/lines-grammar/class.ts","../src/diagram/lines-grammar/er.ts","../src/diagram/registry.ts","../src/diagram/document.ts"],"names":["parentOf","detectIndent","reparse","insertIntoGroup","filterInPlace","depthAt","groupRange","setFrontmatterTitle","RELATION","next"],"mappings":"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ACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AAAA;AAEQ,EAAA;AACR,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACQ,EAAA;AACA,EAAA;AACR,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACQ,EAAA;AACA,EAAA;AACR,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACQ,EAAA;AACR,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACF,E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A;AACF,IAAA;AACK,IAAA;AACH,MAAA;AACI,MAAA;AACJ,MAAA;AACI,MAAA;AACA,MAAA;AACA,MAAA;AACJ,MAAA;AACA,MAAA;AACE,QAAA;AAAgD,QAAA;AAElD,MAAA;AACI,MAAA;AACA,MAAA;AACJ,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACF,QAAA;AACA,QAAA;AACF,MAAA;AAEA,MAAA;AACI,MAAA;AACF,QAAA;AACE,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACD,QAAA;AACH,MAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAAA;AACA,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACF,QAAA;AACF,MAAA;AACA,MAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACA,IAAA;AACA,IAAA;AACH,MAAA;AACI,MAAA;AACJ,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACA,MAAA;AACI,MAAA;AACF,QAAA;AACA,QAAA;AACF,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACF,QAAA;AACF,MAAA;AACE,QAAA;AACA,QAAA;AACF,MAAA;AACA,MAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACF,MAAA;AACE,QAAA;AACA,QAAA;AACE,QAAA;AACJ,MAAA;AACI,MAAA;AACC,MAAA;AACL,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAAA;AACI,MAAA;AACJ,MAAA;AACA,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACE,UAAA;AACE,YAAA;AACF,UAAA;AACF,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACF,QAAA;AACF,MAAA;AACA,MAAA;AACA,MAAA;AAEA,MAAA;AACE,QAAA;AACA,QAAA;AAKE,UAAA;AACA,UAAA;AACF,QAAA;AACF,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAAA;AACI,MAAA;AACJ,MAAA;AACA,MAAA;AACI,MAAA;AACA,MAAA;AAEF,QAAA;AACF,MAAA;AACA,MAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAAA;AACI,MAAA;AACA,MAAA;AACJ,MAAA;AACE,QAAA;AACA,QAAA;AAIE,UAAA;AACA,UAAA;AACF,QAAA;AACF,MAAA;AACI,MAAA;AACF,QAAA;AACE,UAAA;AACA,UAAA;AACA,UAAA;AACF,QAAA;AACE,UAAA;AACA,UAAA;AAAsC,YAAA;AAC9B,YAAA;AACD,YAAA;AACG,YAAA;AACM,YAAA;AAEhB,UAAA;AACF,QAAA;AACF,MAAA;AACE,QAAA;AACF,MAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAAA;AAEE,QAAA;AAGI,UAAA;AAKF,QAAA;AACF,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACA,UAAA;AACF,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AAAwB,YAAA;AAChB,YAAA;AACD,YAAA;AACL,YAAA;AACoC,YAAA;AAEtC,UAAA;AACA,UAAA;AACF,QAAA;AACE,UAAA;AAAwB,YAAA;AAChB,YAAA;AACD,YAAA;AACL,YAAA;AACqC,YAAA;AAEvC,UAAA;AACF,QAAA;AACF,MAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACC,MAAA;AACJ,MAAA;AACE,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACE,YAAA;AACA,YAAA;AACF,UAAA;AACF,QAAA;AACE,UAAA;AACA,UAAA;AACF,QAAA;AACF,MAAA;AACI,MAAA;AACF,QAAA;AACE,UAAA;AACA,UAAA;AACF,QAAA;AAAA,MAAA;AAEA,QAAA;AACE,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACD,QAAA;AACH,MAAA;AACF,IAAA;AACA,IAAA;AACE,MAAA;AACJ,EAAA;AAEO,EAAA;AACT;AAOS;AACD,EAAA;AACA,EAAA;AACA,EAAA;AACN,EAAA;AACQ,IAAA;AACD,IAAA;AACC,IAAA;AACD,IAAA;AACH,MAAA;AACA,MAAA;AACD,IAAA;AACF,EAAA;AACM,EAAA;AACT;AAES;AACD,EAAA;AACJ,IAAA;AACK,MAAA;AACH,MAAA;AACE,QAAA;AAA2B,UAAA;AACX,YAAA;AACT,YAAA;AACmB,YAAA;AAExB,UAAA;AACF,QAAA;AACA,QAAA;AACF,MAAA;AACF,IAAA;AACF,EAAA;AACM,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACJ,IAAA;AACK,MAAA;AACH,MAAA;AACA,MAAA;AACF,IAAA;AACK,EAAA;AACT;AAES;AACD,EAAA;AACA,EAAA;AACD,EAAA;AACE,EAAA;AACT;AAES;AACA,EAAA;AACT;AAGgB;AACR,EAAA;AACA,EAAA;AACA,EAAA;AACF,EAAA;AACA,EAAA;AACA,EAAA;AACG,EAAA;AACL,IAAA;AACK,IAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AAEA,IAAA;AACD,EAAA;AACH;AAES;AACC,EAAA;AACR,EAAA;AACM,IAAA;AACN,EAAA;AACI,EAAA;AACN;AAES;AACD,EAAA;AACE,EAAA;AACF,EAAA;AACA,EAAA;AACC,EAAA;AACT;AAES;AACD,EAAA;AACA,EAAA;AACD,EAAA;AACC,IAAA;AACJ,IAAA;AACF,EAAA;AACM,EAAA;AACA,EAAA;AACA,EAAA;AACF,EAAA;AACE,IAAA;A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A;AACD,QAAA;AACD,QAAA;AACA,QAAA;AACF,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACF,MAAA;AACE,QAAA;AACA,QAAA;AACF,MAAA;AACE,QAAA;AACA,QAAA;AACF,MAAA;AACE,QAAA;AACJ,IAAA;AACF,EAAA;AACI,EAAA;AACF,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACD,IAAA;AAGH,EAAA;AACE,IAAA;AACE,MAAA;AACI,MAAA;AACN,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACE,MAAA;AACI,MAAA;AACN,IAAA;AACF,EAAA;AACA,EAAA;AACQ,IAAA;AACF,IAAA;AACN,EAAA;AAEO,EAAA;AACL,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACF,IAAA;AACA,IAAA;AACF,EAAA;AACF;AAES;AAID,EAAA;AACN,EAAA;AACM,IAAA;AACC,IAAA;AACP,EAAA;AACO,EAAA;AACT;AAEgB;AAKR,EAAA;AACA,EAAA;AACA,EAAA;AAIE,EAAA;AACD,EAAA;AACL,IAAA;AACM,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACK,IAAA;AACL,IAAA;AACM,IAAA;AACN,IAAA;AACM,IAAA;AACN,IAAA;AACA,IAAA;AACF,EAAA;AACF;AAEgB;AACR,EAAA;AACN,EAAA;AACM,IAAA;AACF,MAAA;AACA,MAAA;AACF,IAAA;AACM,IAAA;AACJ,MAAA;AACI,MAAA;AACJ,MAAA;AACF,IAAA;AACM,IAAA;AACF,IAAA;AACN,EAAA;AACM,EAAA;AACC,EAAA;AACT;AAEgBC;AACd,EAAA;AACO,EAAA;AACT;AAES;AAKD,EAAA;AACA,EAAA;AACA,EAAA;AACF,EAAA;AACA,EAAA;AACA,EAAA;AACG,EAAA;AACL,IAAA;AACK,IAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AAEA,IAAA;AACD,EAAA;AACH;AAMgB;AACR,EAAA;AACD,IAAA;AACC,IAAA;AAEE,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AAED,IAAA;AACD,IAAA;AAEE,MAAA;AACA,MAAA;AAED,IAAA;AACL,EAAA;AACI,EAAA;AACD,IAAA;AACG,IAAA;AACA,IAAA;AACR,EAAA;AACM,EAAA;AACAC,EAAAA;AACE,IAAA;AACA,IAAA;AACD,IAAA;AACL,IAAA;AACF,EAAA;AAEQ,EAAA;AACD,IAAA;AACH,MAAA;AACA,MAAA;AACG,IAAA;AACC,MAAA;AACC,MAAA;AACL,MAAA;AACG,IAAA;AACH,MAAA;AACA,MAAA;AACG,IAAA;AACH,MAAA;AACI,MAAA;AACJ,MAAA;AACG,IAAA;AACH,MAAA;AACG,IAAA;AACH,MAAA;AACA,MAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACC,MAAA;AACF,QAAA;AACE,UAAA;AACF,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACA,UAAA;AACF,QAAA;AACE,UAAA;AAAmB,YAAA;AACX,YAAA;AACD,YAAA;AACL,YAAA;AACc,YAAA;AAEhB,UAAA;AACF,QAAA;AACF,MAAA;AACE,QAAA;AACF,MAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACAC,MAAAA;AACI,MAAA;AACJ,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAAA;AACAC,MAAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACA,UAAA;AACF,QAAA;AACA,QAAA;AACD,MAAA;AAED,MAAA;AACE,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACF,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACH,MAAA;AACI,MAAA;AACA,MAAA;AAEF,QAAA;AACA,QAAA;AACE,UAAA;AAAA,YAAA;AACE,YAAA;AAC0C,YAAA;AACkB,YAAA;AAE9D,UAAA;AACA,UAAA;AACF,QAAA;AACA,QAAA;AACE,UAAA;AACF,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACA,MAAA;AACI,MAAA;AACA,MAAA;AACA,MAAA;AACF,QAAA;AACAA,QAAAA;AACE,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACD,QAAA;AACH,MAAA;AACI,MAAA;AACF,QAAA;AAGA,QAAA;AACE,UAAA;AACA,UAAA;AACF,QAAA;AACF,MAAA;AACC,MAAA;AACD,MAAA;AACF,IAAA;AACK,IAAA;AACHA,MAAAA;AACI,MAAA;AACF,QAAA;AACE,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACD,QAAA;AACH,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AAAW,YAAA;AACsC,YAAA;AAEjD,UAAA;AACF,QAAA;AACF,MAAA;AACA,MAAA;AAEA,MAAA;AACA,MAAA;AACAD,MAAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAAA;AACI,MAAA;AACJC,MAAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACD,MAAA;AACD,MAAA;AACF,IAAA;AACK,IAAA;AACA,IAAA;AACA,IAAA;AACH,MAAA;AACI,MAAA;AACA,MAAA;AACA,MAAA;AACF,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACI,MAAA;AACF,QAAA;AACA,QAAA;AACF,MAAA;AACA,MAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACC,MAAA;AACJ,MAAA;AACA,MAAA;AAEA,MAAA;AACAA,MAAAA;AACE,QAAA;AACE,UAAA;AACA,UAAA;AACF,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACF,QAAA;AACA,QAAA;AACD,MAAA;AACD,MAAA;AACE,QAAA;AACE,UAAA;AACF,QAAA;AACF,MAAA;AACAD,MAAAA;AACA,MAAA;AACF,IAAA;AACK,IAAA;AACH,MAA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;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACE,EAAA;AACF,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACE,EAAA;AACA,EAAA;AACJ;AAEM;AACJ,EAAA;AACF;AACM;AACG,EAAA;AACT;AAEgB;AAMZ,EAAA;AACG,IAAA;AACE,EAAA;AAET;AAQgB;AACR,EAAA;AACN,EAAA;AACQ,IAAA;AACD,IAAA;AACC,IAAA;AACF,IAAA;AACN,EAAA;AACO,EAAA;AACT;AAES;AACA,EAAA;AAIT;AAEa;AACH,EAAA;AACR,EAAA;AACA,EAAA;AACA,EAAA;AAEA,EAAA;AACE,IAAA;AACF,EAAA;AAEA,EAAA;AACQ,IAAA;AACA,IAAA;AACA,IAAA;AACF,IAAA;AACF,MAAA;AACE,IAAA;AACA,IAAA;AAEC,IA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AQ,EAAA;AACY;AACpB,EAAA;AACF;Af8oHU;AACA;AgB7pHM;AACP,EAAA;AACT;AAQgB;AACR,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF,EAAA;AACA,EAAA;AACA,EAAA;AACE,EAAA;AAEA,EAAA;AACA,EAAA;AACJ,IAAA;AACK,IAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACD,EAAA;AACM,EAAA;AACT;AAGgB;AACP,EAAA;AACT;AAMgB;AACP,EAAA;AACCC,IAAAA;AACD,IAAA;AACL,IAAA;AACF,EAAA;AACM,EAAA;AACF,EAAA;AAEG,IAAA;AACP,EAAA;AACO,EAAA;AACT;AAGgB;AACP,EAAA;AACT;AhB6oHU;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-H5K77C7Y.cjs","sourcesContent":[null,"import type { DiagramFamily, Preamble } from \"../types.js\";\n\nexport interface SplitSource {\n eol: \"\\n\" | \"\\r\\n\";\n preamble: Preamble;\n /** Header line without EOL; empty string if none was found. */\n header: string;\n /** 0-based index of the header line in the original line array. */\n headerIndex: number;\n bodyLines: string[];\n trailing: string;\n}\n\n/** Matches the first token of a diagram header and maps it to a family. */\nconst HEADER_PATTERNS: [RegExp, DiagramFamily][] = [\n [/^\\s*(flowchart|graph)(?:-elk)?\\b/i, \"flowchart\"],\n [/^\\s*stateDiagram(?:-v2)?\\b/i, \"state\"],\n [/^\\s*classDiagram(?:-v2)?\\b/i, \"class\"],\n [/^\\s*erDiagram\\b/i, \"er\"],\n [/^\\s*requirementDiagram\\b/i, \"requirement\"],\n [/^\\s*mindmap\\b/i, \"mindmap\"],\n [/^\\s*sequenceDiagram\\b/i, \"sequence\"],\n [/^\\s*gantt\\b/i, \"gantt\"],\n [/^\\s*pie\\b/i, \"pie\"],\n [/^\\s*journey\\b/i, \"journey\"],\n [/^\\s*timeline\\b/i, \"timeline\"],\n [/^\\s*gitGraph\\b/i, \"gitGraph\"],\n [/^\\s*C4(Context|Container|Component|Dynamic|Deployment)\\b/, \"c4\"],\n [/^\\s*quadrantChart\\b/i, \"quadrant\"],\n [/^\\s*sankey(?:-beta)?\\b/i, \"sankey\"],\n [/^\\s*xychart(?:-beta)?\\b/i, \"xychart\"],\n [/^\\s*block(?:-beta)?\\b/i, \"block\"],\n [/^\\s*architecture(?:-beta)?\\b/i, \"architecture\"],\n [/^\\s*packet(?:-beta)?\\b/i, \"packet\"],\n [/^\\s*kanban\\b/i, \"kanban\"],\n [/^\\s*radar(?:-beta)?\\b/i, \"radar\"],\n [/^\\s*treemap(?:-beta)?\\b/i, \"treemap\"],\n [/^\\s*info\\b/i, \"info\"],\n];\n\n/** Detects the diagram family of a header line (or whole source). */\nexport function detectFamilyFromHeader(header: string): DiagramFamily {\n for (const [re, family] of HEADER_PATTERNS) {\n if (re.test(header)) return family;\n }\n return \"unknown\";\n}\n\nexport function isCommentLine(line: string): boolean {\n const t = line.trim();\n return t.startsWith(\"%%\") && !t.startsWith(\"%%{\");\n}\n\nexport function isDirectiveLine(line: string): boolean {\n return /^\\s*%%\\{.*\\}%%\\s*$/.test(line);\n}\n\n/**\n * Splits a Mermaid source into preamble, header, body and trailing whitespace.\n *\n * The preamble is everything before the header: an optional YAML frontmatter\n * block (which must start on the first line), directives, comments and blank\n * lines. All of it is kept verbatim.\n */\nexport function splitSource(source: string): SplitSource {\n const eol: \"\\n\" | \"\\r\\n\" = source.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const rawLines = source.split(/\\r\\n|\\n/);\n\n // Trailing: blank lines at the very end (and whether the source ended with EOL)\n let end = rawLines.length;\n while (end > 0 && rawLines[end - 1]!.trim() === \"\") end--;\n const trailingLines = rawLines.slice(end);\n // If the source ended with an EOL, split() produced a final \"\" entry. We\n // reconstruct trailing as the exact suffix after the last non-blank line.\n const trailing = trailingLines.length ? eol + trailingLines.join(eol) : \"\";\n const lines = rawLines.slice(0, end);\n\n const preambleLines: string[] = [];\n let i = 0;\n let frontmatter: Record<string, unknown> | undefined;\n\n if (lines[0] !== undefined && /^---\\s*$/.test(lines[0])) {\n // Frontmatter block\n preambleLines.push(lines[0]);\n i = 1;\n const fm: string[] = [];\n while (i < lines.length && !/^---\\s*$/.test(lines[i]!)) {\n fm.push(lines[i]!);\n preambleLines.push(lines[i]!);\n i++;\n }\n if (i < lines.length) {\n preambleLines.push(lines[i]!);\n i++;\n }\n frontmatter = parseSimpleYaml(fm);\n }\n\n while (i < lines.length) {\n const line = lines[i]!;\n if (line.trim() === \"\" || isDirectiveLine(line) || isCommentLine(line)) {\n preambleLines.push(line);\n i++;\n continue;\n }\n break;\n }\n\n const headerIndex = i;\n const header = lines[i] ?? \"\";\n const bodyLines = lines.slice(i + 1);\n\n return {\n eol,\n preamble: { lines: preambleLines, frontmatter },\n header,\n headerIndex,\n bodyLines,\n trailing,\n };\n}\n\n/**\n * Minimal YAML reader for Mermaid frontmatter. Handles scalar `key: value`\n * pairs, JSON flow values (`key: {\"a\":1}`) and one level of nested maps —\n * enough for `title`, `displayMode`, `config` and the diagram module's own key. Anything\n * else is kept as the raw string.\n */\nexport function parseSimpleYaml(lines: string[]): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n let currentKey: string | null = null;\n let nested: Record<string, unknown> | null = null;\n for (const raw of lines) {\n if (raw.trim() === \"\" || raw.trim().startsWith(\"#\")) continue;\n const indent = raw.length - raw.trimStart().length;\n const m = /^([A-Za-z_][\\w-]*)\\s*:\\s*(.*)$/.exec(raw.trim());\n if (!m) continue;\n const [, key, valueRaw] = m;\n const value = parseYamlScalar(valueRaw!);\n if (indent === 0) {\n currentKey = key!;\n if (valueRaw!.trim() === \"\") {\n nested = {};\n out[key!] = nested;\n } else {\n nested = null;\n out[key!] = value;\n }\n } else if (nested && currentKey) {\n nested[key!] = value;\n }\n }\n return out;\n}\n\nfunction parseYamlScalar(v: string): unknown {\n const t = v.trim();\n if (t === \"\") return \"\";\n if (t.startsWith(\"{\") || t.startsWith(\"[\")) {\n try {\n return JSON.parse(t);\n } catch {\n return t;\n }\n }\n if (/^(true|false)$/i.test(t)) return t.toLowerCase() === \"true\";\n if (/^-?\\d+(\\.\\d+)?$/.test(t)) return Number(t);\n if ((t.startsWith('\"') && t.endsWith('\"')) || (t.startsWith(\"'\") && t.endsWith(\"'\"))) {\n return t.slice(1, -1);\n }\n return t;\n}\n\n/**\n * Splits a single line into `;`-separated statements, ignoring separators\n * inside quotes or brackets. Mermaid allows `A --> B; B --> C` on one line.\n */\nexport function splitStatements(line: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let quote: string | null = null;\n let cur = \"\";\n for (let i = 0; i < line.length; i++) {\n const ch = line[i]!;\n if (quote) {\n cur += ch;\n if (ch === quote) quote = null;\n continue;\n }\n if (ch === '\"' || ch === \"`\") {\n quote = ch;\n cur += ch;\n continue;\n }\n if (ch === \"[\" || ch === \"(\" || ch === \"{\") depth++;\n else if (ch === \"]\" || ch === \")\" || ch === \"}\") depth = Math.max(0, depth - 1);\n if (ch === \";\" && depth === 0) {\n parts.push(cur);\n cur = \"\";\n continue;\n }\n cur += ch;\n }\n parts.push(cur);\n return parts;\n}\n","import type { MetaCarrier, Point, Preamble, DiagramMeta } from \"../types.js\";\n\n/** Prefix of the metadata comment line. */\nexport const META_COMMENT_PREFIX = \"%% @pixerate \";\n/** Frontmatter key used when comments are not safe for a family. */\nexport const META_FRONTMATTER_KEY = \"pixerate\";\n/** Frontmatter key written by Ursula, still read. */\nconst LEGACY_FRONTMATTER_KEY = \"ursula\";\n\n/** `%% @pixerate {json}`; Ursula's `%% @ursula {json}` is read the same way and rewritten as `@pixerate`. */\nconst META_LINE = /^\\s*%%\\s*@(?:pixerate|ursula)\\s+(\\{.*\\})\\s*$/;\n/**\n * `%% @layout {\"id\":[x,y]}`, the positions-only comment written by the\n * redesign-agentic-web diagram editor. Same coordinates as `meta.layout`\n * (absolute top-left), so it is read as layout and replaced by `@pixerate` the\n * next time the document is serialised.\n */\nconst LEGACY_LAYOUT_LINE = /^\\s*%%\\s*@layout\\b\\s*(.*?)\\s*$/;\n\nexport function emptyMeta(): DiagramMeta {\n return { v: 1 };\n}\n\nexport function isMetaLine(line: string): boolean {\n return META_LINE.test(line) || LEGACY_LAYOUT_LINE.test(line);\n}\n\n/**\n * Extracts `%% @pixerate {json}` lines from a body. Several lines are merged\n * (later wins) so that hand-edited documents stay tolerant.\n */\nexport function extractMetaFromBody(bodyLines: string[]): {\n bodyLines: string[];\n meta: DiagramMeta | null;\n} {\n let meta: DiagramMeta | null = null;\n let legacy: DiagramMeta | null = null;\n const rest: string[] = [];\n for (const line of bodyLines) {\n const m = META_LINE.exec(line);\n if (m) {\n const parsed = safeParseMeta(m[1]!);\n if (parsed) meta = mergeMeta(meta ?? emptyMeta(), parsed);\n continue;\n }\n const lm = LEGACY_LAYOUT_LINE.exec(line);\n if (lm) {\n // A malformed payload is dropped too: keeping it would leave a second,\n // stale layout comment beside the `@pixerate` one.\n const parsed = safeParseMeta(`{\"layout\":${lm[1] || \"null\"}}`);\n if (parsed) legacy = mergeMeta(legacy ?? emptyMeta(), parsed);\n continue;\n }\n rest.push(line);\n }\n // `@pixerate` wins wherever both carry a position.\n if (legacy) meta = meta ? mergeMeta(legacy, meta) : legacy;\n return { bodyLines: rest, meta };\n}\n\nexport function extractMetaFromFrontmatter(preamble: Preamble): DiagramMeta | null {\n const value = preamble.frontmatter?.[META_FRONTMATTER_KEY] ?? preamble.frontmatter?.[LEGACY_FRONTMATTER_KEY];\n if (!value) return null;\n if (typeof value === \"string\") return safeParseMeta(value);\n if (typeof value === \"object\") return normaliseMeta(value as Record<string, unknown>);\n return null;\n}\n\nfunction safeParseMeta(json: string): DiagramMeta | null {\n try {\n const value = JSON.parse(json) as Record<string, unknown>;\n return normaliseMeta(value);\n } catch {\n return null;\n }\n}\n\nfunction normaliseMeta(value: Record<string, unknown>): DiagramMeta {\n const meta: DiagramMeta = { v: 1 };\n if (value.layout && typeof value.layout === \"object\") {\n const layout: Record<string, Point> = {};\n for (const [id, pos] of Object.entries(value.layout as Record<string, unknown>)) {\n if (Array.isArray(pos) && pos.length === 2 && pos.every((n) => typeof n === \"number\")) {\n layout[id] = [pos[0] as number, pos[1] as number];\n }\n }\n meta.layout = layout;\n }\n if (value.sizes && typeof value.sizes === \"object\") {\n const sizes: Record<string, readonly [number, number]> = {};\n for (const [id, size] of Object.entries(value.sizes as Record<string, unknown>)) {\n if (Array.isArray(size) && size.length === 2 && size.every((n) => typeof n === \"number\")) {\n sizes[id] = [size[0] as number, size[1] as number];\n }\n }\n meta.sizes = sizes;\n }\n if (value.viewport && typeof value.viewport === \"object\") {\n const vp = value.viewport as Record<string, unknown>;\n if (typeof vp.x === \"number\" && typeof vp.y === \"number\" && typeof vp.zoom === \"number\") {\n meta.viewport = { x: vp.x, y: vp.y, zoom: vp.zoom };\n }\n }\n if (value.ext && typeof value.ext === \"object\") meta.ext = value.ext as Record<string, unknown>;\n return meta;\n}\n\nexport function mergeMeta(a: DiagramMeta, b: DiagramMeta): DiagramMeta {\n return {\n v: 1,\n layout: a.layout || b.layout ? { ...a.layout, ...b.layout } : undefined,\n sizes: a.sizes || b.sizes ? { ...a.sizes, ...b.sizes } : undefined,\n viewport: b.viewport ?? a.viewport,\n ext: a.ext || b.ext ? { ...a.ext, ...b.ext } : undefined,\n };\n}\n\n/** True when there is nothing worth writing. */\nexport function isMetaEmpty(meta: DiagramMeta): boolean {\n const hasLayout = !!meta.layout && Object.keys(meta.layout).length > 0;\n const hasSizes = !!meta.sizes && Object.keys(meta.sizes).length > 0;\n const hasExt = !!meta.ext && Object.keys(meta.ext).length > 0;\n return !hasLayout && !hasSizes && !meta.viewport && !hasExt;\n}\n\n/** Compact, deterministic JSON so diffs stay small. Positions are rounded. */\nexport function serializeMeta(meta: DiagramMeta): string {\n const out: Record<string, unknown> = { v: 1 };\n if (meta.layout && Object.keys(meta.layout).length) {\n const layout: Record<string, Point> = {};\n for (const id of Object.keys(meta.layout).sort()) {\n const [x, y] = meta.layout[id]!;\n layout[id] = [Math.round(x), Math.round(y)];\n }\n out.layout = layout;\n }\n if (meta.sizes && Object.keys(meta.sizes).length) {\n const sizes: Record<string, readonly [number, number]> = {};\n for (const id of Object.keys(meta.sizes).sort()) {\n const [w, h] = meta.sizes[id]!;\n sizes[id] = [Math.round(w), Math.round(h)];\n }\n out.sizes = sizes;\n }\n if (meta.viewport) {\n out.viewport = {\n x: Math.round(meta.viewport.x),\n y: Math.round(meta.viewport.y),\n zoom: Math.round(meta.viewport.zoom * 1000) / 1000,\n };\n }\n if (meta.ext && Object.keys(meta.ext).length) out.ext = meta.ext;\n return JSON.stringify(out);\n}\n\nexport function metaCommentLine(meta: DiagramMeta, indent = \" \"): string {\n return `${indent}${META_COMMENT_PREFIX}${serializeMeta(meta)}`;\n}\n\n/**\n * Returns preamble lines with the `pixerate:` frontmatter entry set/removed.\n * Creates a frontmatter block when none exists.\n */\nexport function writeMetaToPreamble(preamble: Preamble, meta: DiagramMeta | null): string[] {\n const lines = [...preamble.lines];\n const hasFm = lines[0] !== undefined && /^---\\s*$/.test(lines[0]);\n const entry =\n meta && !isMetaEmpty(meta) ? `${META_FRONTMATTER_KEY}: ${serializeMeta(meta)}` : null;\n\n if (!hasFm) {\n if (!entry) return lines;\n return [\"---\", entry, \"---\", ...lines];\n }\n const close = lines.findIndex((l, i) => i > 0 && /^---\\s*$/.test(l));\n const fmEnd = close === -1 ? lines.length : close;\n const existing = lines.findIndex(\n (l, i) => i > 0 && i < fmEnd && new RegExp(`^(?:${META_FRONTMATTER_KEY}|${LEGACY_FRONTMATTER_KEY})\\\\s*:`).test(l),\n );\n if (existing !== -1) {\n if (entry) lines[existing] = entry;\n else lines.splice(existing, 1);\n } else if (entry) {\n lines.splice(fmEnd, 0, entry);\n }\n // Collapse an emptied frontmatter block.\n if (!entry) {\n const close2 = lines.findIndex((l, i) => i > 0 && /^---\\s*$/.test(l));\n if (close2 === 1) lines.splice(0, 2);\n }\n return lines;\n}\n\n/** Families whose grammar rejects `%%` comments in the body. */\nexport const FRONTMATTER_META_FAMILIES = new Set([\"requirement\"]);\n\nexport function defaultCarrierFor(family: string): MetaCarrier {\n return FRONTMATTER_META_FAMILIES.has(family) ? \"frontmatter\" : \"comment\";\n}\n","import type { ArrowHead, EdgePattern } from \"../types.js\";\n\n/**\n * Flowchart link syntax.\n *\n * Grammar (informal):\n *\n * link := [edgeId '@'] (plainLink | textLink) [ '|' label '|' ]\n * plainLink := [head] body [head]\n * textLink := [head] open ws label ws close [head]\n * body := '--'+ | '=='+ | '-' '.'+ '-' | '~~~'+\n * head := '>' | 'x' | 'o' | '<' (start only)\n *\n * @module\n */\n\nexport interface ParsedLink {\n /** User-defined edge id (`A e1@--> B`). */\n id?: string;\n pattern: EdgePattern;\n arrowStart: ArrowHead;\n arrowEnd: ArrowHead;\n length: number;\n label?: string;\n /** How the label was written, so regeneration keeps the author's style. */\n labelStyle?: \"inline\" | \"pipe\";\n /** Characters consumed from the input. */\n consumed: number;\n raw: string;\n}\n\nconst START_HEADS: Record<string, ArrowHead> = {\n \"<\": \"arrow_point\",\n x: \"arrow_cross\",\n o: \"arrow_circle\",\n};\nconst END_HEADS: Record<string, ArrowHead> = {\n \">\": \"arrow_point\",\n x: \"arrow_cross\",\n o: \"arrow_circle\",\n};\n\nconst EDGE_ID = /^([A-Za-z0-9_À--]+)@(?=[<xo]?[-=~.])/;\n// Head + body + head. Dotted body is `-` dots `-`.\nconst PLAIN = /^([<xo](?=[-=~]))?(-{2,}|={2,}|-\\.+-|~{3,})([>xo])?/;\n// Text link opener: `--`, `-.` or `==` followed by whitespace then label.\nconst TEXT_OPEN = /^([<xo](?=[-=]))?(--|-\\.|==)(?=\\s)/;\n// Text link closer, searched after the label.\nconst TEXT_CLOSE = /\\s+(-{2,}|\\.+-|={2,})([>xo])?(?=$|\\s|\\||[A-Za-z0-9_À-([{>\"`&])/;\n\nfunction patternOf(body: string): EdgePattern {\n if (body.startsWith(\"~\")) return \"invisible\";\n if (body.startsWith(\"=\")) return \"thick\";\n if (body.includes(\".\")) return \"dotted\";\n return \"solid\";\n}\n\nfunction lengthOf(body: string, hasEndHead: boolean): number {\n if (body.startsWith(\"~\")) return Math.max(1, body.length - 2);\n if (body.includes(\".\")) return Math.max(1, (body.match(/\\./g) ?? []).length);\n // solid / thick\n return Math.max(1, body.length - (hasEndHead ? 1 : 2));\n}\n\n/** Length of a text-link closer (`-->` is 1, `--->` is 2, `.->` is 1, `..->` 2). */\nfunction closerLength(closer: string, hasEndHead: boolean): number {\n if (closer.includes(\".\")) return Math.max(1, (closer.match(/\\./g) ?? []).length);\n return Math.max(1, closer.length - (hasEndHead ? 1 : 2));\n}\n\n/**\n * Attempts to parse a link at the start of `input`. Returns `null` when the\n * input does not begin with a link.\n */\nexport function parseLink(input: string): ParsedLink | null {\n let pos = 0;\n let id: string | undefined;\n const idm = EDGE_ID.exec(input);\n if (idm) {\n id = idm[1]!;\n pos += idm[0].length;\n }\n const rest = input.slice(pos);\n\n // Text link first: `-- label -->`\n const tm = TEXT_OPEN.exec(rest);\n if (tm) {\n const afterOpen = rest.slice(tm[0].length);\n const cm = TEXT_CLOSE.exec(afterOpen);\n if (cm && cm.index > 0) {\n const label = afterOpen.slice(0, cm.index).trim();\n // Label must not start with a link char (that would be a plain link).\n if (label && !/^[-=.>|]/.test(label)) {\n const closer = cm[1]!;\n const endHead = cm[2];\n const consumed = pos + tm[0].length + cm.index + cm[0].length;\n const body = tm[2]!;\n const result: ParsedLink = {\n id,\n pattern: patternOf(body === \"-.\" ? \"-.-\" : body),\n arrowStart: tm[1] ? START_HEADS[tm[1]]! : \"none\",\n arrowEnd: endHead ? END_HEADS[endHead]! : \"none\",\n length: closerLength(closer, !!endHead),\n label: unquoteLabel(label),\n labelStyle: \"inline\",\n consumed,\n raw: input.slice(0, consumed),\n };\n return withPipeLabel(input, result);\n }\n }\n }\n\n const pm = PLAIN.exec(rest);\n if (!pm) return null;\n const body = pm[2]!;\n const endHead = pm[3];\n const consumed = pos + pm[0].length;\n const result: ParsedLink = {\n id,\n pattern: patternOf(body),\n arrowStart: pm[1] ? START_HEADS[pm[1]]! : \"none\",\n arrowEnd: endHead ? END_HEADS[endHead]! : \"none\",\n length: lengthOf(body, !!endHead),\n consumed,\n raw: input.slice(0, consumed),\n };\n return withPipeLabel(input, result);\n}\n\n/** Consumes an optional `|label|` after the link token. */\nfunction withPipeLabel(input: string, link: ParsedLink): ParsedLink {\n const after = input.slice(link.consumed);\n // A quoted label may contain `|` (Mermaid accepts it, and `quoteLabelIfNeeded`\n // writes it), so try the quoted form before stopping at the first pipe.\n const m = /^\\s*\\|(\\s*\"[^\"]*\"\\s*)\\|/.exec(after) ?? /^\\s*\\|([^|]*)\\|/.exec(after);\n if (!m) return link;\n const consumed = link.consumed + m[0].length;\n return {\n ...link,\n label: unquoteLabel(m[1]!.trim()),\n labelStyle: link.label ? link.labelStyle : \"pipe\",\n consumed,\n raw: input.slice(0, consumed),\n };\n}\n\nexport function unquoteLabel(text: string): string {\n const t = text.trim();\n if (t.length >= 2 && t.startsWith('\"') && t.endsWith('\"')) return t.slice(1, -1);\n return t;\n}\n\n/** Characters that force a label to be quoted in Mermaid. */\nconst NEEDS_QUOTE = /[[\\]{}()|<>\"#;&%]|^\\s|\\s$|^-|^=|^\\./;\n\nexport function quoteLabelIfNeeded(label: string): string {\n if (label === \"\") return '\"\"';\n if (label.startsWith(\"`\") && label.endsWith(\"`\")) return `\"${label}\"`;\n if (NEEDS_QUOTE.test(label)) {\n return `\"${label.replace(/\"/g, \"#quot;\")}\"`;\n }\n return label;\n}\n\nconst START_CHAR: Partial<Record<ArrowHead, string>> = {\n arrow_point: \"<\",\n arrow_cross: \"x\",\n arrow_circle: \"o\",\n};\nconst END_CHAR: Partial<Record<ArrowHead, string>> = {\n arrow_point: \">\",\n arrow_cross: \"x\",\n arrow_circle: \"o\",\n};\n\nexport interface LinkSpec {\n id?: string;\n pattern: EdgePattern;\n arrowStart: ArrowHead;\n arrowEnd: ArrowHead;\n length: number;\n label?: string;\n labelStyle?: \"inline\" | \"pipe\";\n}\n\n/** Serialises a link back to Mermaid syntax. */\nexport function formatLink(spec: LinkSpec): string {\n const start = START_CHAR[spec.arrowStart] ?? \"\";\n const end = END_CHAR[spec.arrowEnd] ?? \"\";\n const len = Math.max(1, spec.length);\n const label = spec.label?.trim();\n\n const body = (closing: boolean): string => {\n switch (spec.pattern) {\n case \"invisible\":\n return \"~\".repeat(len + 2);\n case \"thick\":\n return \"=\".repeat(end ? len + 1 : len + 2);\n case \"dotted\":\n return closing ? `${\".\".repeat(len)}-` : `-${\".\".repeat(len)}-`;\n default:\n return \"-\".repeat(end ? len + 1 : len + 2);\n }\n };\n\n const prefix = spec.id ? `${spec.id}@` : \"\";\n\n if (label && spec.labelStyle === \"inline\" && spec.pattern !== \"invisible\") {\n const open = spec.pattern === \"thick\" ? \"==\" : spec.pattern === \"dotted\" ? \"-.\" : \"--\";\n return `${prefix}${start}${open} ${quoteLabelIfNeeded(label)} ${body(true)}${end}`;\n }\n const token = `${prefix}${start}${body(false)}${end}`;\n if (label) return `${token}|${quoteLabelIfNeeded(label)}|`;\n return token;\n}\n","/**\n * Flowchart shape vocabulary.\n *\n * Mermaid has two ways to express a shape: classic bracket syntax (`A[text]`)\n * and the `@{ shape: … }` data syntax introduced in v11. the diagram module normalises\n * both to the *short name* used by the data syntax (`rect`, `diam`, `cyl`…),\n * which is also what Mermaid's `getData()` reports for data-syntax nodes.\n *\n * @module\n */\n\nexport interface BracketForm {\n open: string;\n close: string;\n}\n\nexport interface ShapeDef {\n /** Canonical short name (what `@{ shape: … }` expects). */\n name: string;\n /** Human-readable name for UIs. */\n title: string;\n /** Alternative names accepted by Mermaid's data syntax. */\n aliases: string[];\n /** Classic bracket syntax when one exists. */\n bracket?: BracketForm;\n /** Broad visual category, handy for toolbars. */\n category: \"basic\" | \"process\" | \"data\" | \"control\" | \"misc\";\n}\n\nexport const FLOWCHART_SHAPES: ShapeDef[] = [\n {\n name: \"rect\",\n title: \"Rectangle\",\n aliases: [\"rectangle\", \"proc\", \"process\", \"squareRect\", \"square\"],\n bracket: { open: \"[\", close: \"]\" },\n category: \"basic\",\n },\n {\n name: \"rounded\",\n title: \"Rounded rectangle\",\n aliases: [\"rounded-rectangle\", \"event\", \"roundedRect\", \"round\"],\n bracket: { open: \"(\", close: \")\" },\n category: \"basic\",\n },\n {\n name: \"stadium\",\n title: \"Stadium\",\n aliases: [\"pill\", \"terminal\"],\n bracket: { open: \"([\", close: \"])\" },\n category: \"basic\",\n },\n {\n name: \"subproc\",\n title: \"Subprocess\",\n aliases: [\"subprocess\", \"subroutine\", \"framed-rectangle\", \"fr-rect\"],\n bracket: { open: \"[[\", close: \"]]\" },\n category: \"process\",\n },\n {\n name: \"cyl\",\n title: \"Cylinder (database)\",\n aliases: [\"cylinder\", \"database\", \"db\"],\n bracket: { open: \"[(\", close: \")]\" },\n category: \"data\",\n },\n {\n name: \"circle\",\n title: \"Circle\",\n aliases: [\"circ\"],\n bracket: { open: \"((\", close: \"))\" },\n category: \"basic\",\n },\n {\n name: \"odd\",\n title: \"Asymmetric\",\n aliases: [\"asymmetric\", \"rect_left_inv_arrow\"],\n bracket: { open: \">\", close: \"]\" },\n category: \"misc\",\n },\n {\n name: \"diam\",\n title: \"Diamond (decision)\",\n aliases: [\"diamond\", \"decision\", \"question\"],\n bracket: { open: \"{\", close: \"}\" },\n category: \"control\",\n },\n {\n name: \"hex\",\n title: \"Hexagon (prepare)\",\n aliases: [\"hexagon\", \"prepare\"],\n bracket: { open: \"{{\", close: \"}}\" },\n category: \"process\",\n },\n {\n name: \"lean-r\",\n title: \"Parallelogram (lean right)\",\n aliases: [\"lean-right\", \"in-out\", \"lean_right\"],\n bracket: { open: \"[/\", close: \"/]\" },\n category: \"data\",\n },\n {\n name: \"lean-l\",\n title: \"Parallelogram (lean left)\",\n aliases: [\"lean-left\", \"out-in\", \"lean_left\"],\n bracket: { open: \"[\\\\\", close: \"\\\\]\" },\n category: \"data\",\n },\n {\n name: \"trap-b\",\n title: \"Trapezoid (base bottom)\",\n aliases: [\"trapezoid-bottom\", \"priority\", \"trapezoid\"],\n bracket: { open: \"[/\", close: \"\\\\]\" },\n category: \"process\",\n },\n {\n name: \"trap-t\",\n title: \"Trapezoid (base top)\",\n aliases: [\"trapezoid-top\", \"manual\", \"inv_trapezoid\"],\n bracket: { open: \"[\\\\\", close: \"/]\" },\n category: \"process\",\n },\n {\n name: \"dbl-circ\",\n title: \"Double circle\",\n aliases: [\"double-circle\", \"doublecircle\"],\n bracket: { open: \"(((\", close: \")))\" },\n category: \"basic\",\n },\n // Data-syntax-only shapes\n { name: \"text\", title: \"Text\", aliases: [], category: \"misc\" },\n {\n name: \"card\",\n title: \"Card (notched rectangle)\",\n aliases: [\"notched-rectangle\", \"notch-rect\"],\n category: \"misc\",\n },\n {\n name: \"lin-rect\",\n title: \"Lined rectangle (shaded process)\",\n aliases: [\"lined-rectangle\", \"lin-proc\", \"lined-process\", \"shaded-process\"],\n category: \"process\",\n },\n {\n name: \"sm-circ\",\n title: \"Small circle (start)\",\n aliases: [\"small-circle\", \"start\"],\n category: \"control\",\n },\n {\n name: \"fr-circ\",\n title: \"Framed circle (stop)\",\n aliases: [\"framed-circle\", \"stop\"],\n category: \"control\",\n },\n { name: \"fork\", title: \"Fork / join\", aliases: [\"join\"], category: \"control\" },\n { name: \"hourglass\", title: \"Hourglass (collate)\", aliases: [\"collate\"], category: \"process\" },\n {\n name: \"brace\",\n title: \"Comment (left brace)\",\n aliases: [\"brace-l\", \"comment\"],\n category: \"misc\",\n },\n { name: \"brace-r\", title: \"Comment (right brace)\", aliases: [], category: \"misc\" },\n { name: \"braces\", title: \"Comment (both braces)\", aliases: [], category: \"misc\" },\n {\n name: \"bolt\",\n title: \"Lightning bolt (com link)\",\n aliases: [\"com-link\", \"lightning-bolt\"],\n category: \"misc\",\n },\n { name: \"doc\", title: \"Document\", aliases: [\"document\"], category: \"data\" },\n {\n name: \"delay\",\n title: \"Delay (half-rounded rectangle)\",\n aliases: [\"half-rounded-rectangle\"],\n category: \"process\",\n },\n {\n name: \"h-cyl\",\n title: \"Horizontal cylinder (direct access)\",\n aliases: [\"das\", \"horizontal-cylinder\"],\n category: \"data\",\n },\n {\n name: \"lin-cyl\",\n title: \"Lined cylinder (disk storage)\",\n aliases: [\"disk\", \"lined-cylinder\"],\n category: \"data\",\n },\n {\n name: \"curv-trap\",\n title: \"Curved trapezoid (display)\",\n aliases: [\"curved-trapezoid\", \"display\"],\n category: \"misc\",\n },\n {\n name: \"div-rect\",\n title: \"Divided rectangle\",\n aliases: [\"div-proc\", \"divided-process\", \"divided-rectangle\"],\n category: \"process\",\n },\n {\n name: \"tri\",\n title: \"Triangle (extract)\",\n aliases: [\"extract\", \"triangle\"],\n category: \"process\",\n },\n {\n name: \"win-pane\",\n title: \"Window pane (internal storage)\",\n aliases: [\"internal-storage\", \"window-pane\"],\n category: \"data\",\n },\n {\n name: \"f-circ\",\n title: \"Filled circle (junction)\",\n aliases: [\"filled-circle\", \"junction\"],\n category: \"control\",\n },\n { name: \"lin-doc\", title: \"Lined document\", aliases: [\"lined-document\"], category: \"data\" },\n { name: \"notch-rect\", title: \"Notched rectangle (card)\", aliases: [], category: \"misc\" },\n { name: \"flag\", title: \"Flag (paper tape)\", aliases: [\"paper-tape\"], category: \"data\" },\n {\n name: \"docs\",\n title: \"Stacked documents\",\n aliases: [\"documents\", \"st-doc\", \"stacked-document\"],\n category: \"data\",\n },\n {\n name: \"st-rect\",\n title: \"Stacked rectangles\",\n aliases: [\"processes\", \"procs\", \"stacked-rectangle\"],\n category: \"process\",\n },\n {\n name: \"bow-rect\",\n title: \"Bow-tie rectangle (stored data)\",\n aliases: [\"bow-tie-rectangle\", \"stored-data\"],\n category: \"data\",\n },\n {\n name: \"cross-circ\",\n title: \"Crossed circle (summary)\",\n aliases: [\"crossed-circle\", \"summary\"],\n category: \"process\",\n },\n { name: \"tag-doc\", title: \"Tagged document\", aliases: [\"tagged-document\"], category: \"data\" },\n {\n name: \"tag-rect\",\n title: \"Tagged rectangle\",\n aliases: [\"tag-proc\", \"tagged-process\", \"tagged-rectangle\"],\n category: \"process\",\n },\n {\n name: \"notch-pent\",\n title: \"Notched pentagon (loop limit)\",\n aliases: [\"loop-limit\", \"notched-pentagon\"],\n category: \"control\",\n },\n {\n name: \"flip-tri\",\n title: \"Flipped triangle (manual file)\",\n aliases: [\"flipped-triangle\", \"manual-file\"],\n category: \"data\",\n },\n {\n name: \"sl-rect\",\n title: \"Sloped rectangle (manual input)\",\n aliases: [\"manual-input\", \"sloped-rectangle\"],\n category: \"data\",\n },\n { name: \"icon\", title: \"Icon\", aliases: [], category: \"misc\" },\n { name: \"image\", title: \"Image\", aliases: [\"img\"], category: \"misc\" },\n { name: \"anchor\", title: \"Anchor (invisible)\", aliases: [], category: \"misc\" },\n];\n\nconst BY_NAME = new Map<string, ShapeDef>();\nfor (const def of FLOWCHART_SHAPES) {\n BY_NAME.set(def.name, def);\n for (const alias of def.aliases) BY_NAME.set(alias, def);\n}\n\n/** Resolves any accepted shape name/alias (or Mermaid `getData()` id) to its definition. */\nexport function resolveShape(name: string | undefined): ShapeDef | undefined {\n if (!name) return undefined;\n return BY_NAME.get(name) ?? BY_NAME.get(name.toLowerCase());\n}\n\n/** Canonical short name for any alias; unknown names pass through unchanged. */\nexport function canonicalShape(name: string | undefined): string {\n if (!name) return \"rect\";\n return resolveShape(name)?.name ?? name;\n}\n\n/**\n * Bracket openers ordered longest-first so that greedy matching finds\n * `(((` before `((` before `(`.\n */\nexport const BRACKET_OPENERS: string[] = Array.from(\n new Set(FLOWCHART_SHAPES.filter((s) => s.bracket).map((s) => s.bracket!.open)),\n).sort((a, b) => b.length - a.length);\n\n/** Closers that can follow a given opener (e.g. `[/` may close with `/]` or `\\]`). */\nexport function closersFor(open: string): string[] {\n return FLOWCHART_SHAPES.filter((s) => s.bracket?.open === open)\n .map((s) => s.bracket!.close)\n .sort((a, b) => b.length - a.length);\n}\n\nexport function shapeForBracket(open: string, close: string): ShapeDef | undefined {\n return FLOWCHART_SHAPES.find((s) => s.bracket?.open === open && s.bracket.close === close);\n}\n\n/** Default label Mermaid shows for a node declared without text: the id itself. */\nexport const DEFAULT_SHAPE = \"rect\";\n","import type { ArrowHead, EdgePattern } from \"../types.js\";\nimport { parseLink, quoteLabelIfNeeded, unquoteLabel, formatLink } from \"./edges.js\";\nimport {\n BRACKET_OPENERS,\n closersFor,\n shapeForBracket,\n canonicalShape,\n resolveShape,\n} from \"./shapes.js\";\n\n/**\n * Statement-level model of a flowchart body. Every line of the source maps\n * to exactly one statement (multi-line `@{ … }` blocks and `;`-joined\n * statements are normalised during tokenisation). Statements remember their\n * raw text and are re-emitted verbatim unless marked `dirty`.\n *\n * @module\n */\n\nexport interface NodeRef {\n id: string;\n /** Shape when declared on this occurrence (bracket or data syntax). */\n shape?: string;\n /** How the shape was expressed: classic brackets or `@{ … }`. */\n form?: \"bracket\" | \"data\";\n label?: string;\n labelQuoted?: boolean;\n /** Parsed `@{ … }` entries (shape/label removed). Values keep their raw text. */\n data?: Record<string, string>;\n classes: string[];\n}\n\nexport interface LinkRef {\n id?: string;\n pattern: EdgePattern;\n arrowStart: ArrowHead;\n arrowEnd: ArrowHead;\n length: number;\n label?: string;\n labelStyle?: \"inline\" | \"pipe\";\n}\n\nexport interface Chain {\n /** `groups[i]` are the nodes joined by `&`; `links[i]` connects group i → i+1. */\n groups: NodeRef[][];\n links: LinkRef[];\n}\n\nexport type FlowStatement =\n | { kind: \"raw\"; raw: string }\n | { kind: \"chain\"; raw: string; indent: string; chain: Chain; dirty?: boolean }\n | {\n kind: \"subgraph\";\n raw: string;\n indent: string;\n id: string;\n title?: string;\n /** `subgraph id [title]` vs `subgraph \"title\"` */\n titleForm: \"bracket\" | \"bare\" | \"none\";\n dirty?: boolean;\n }\n | { kind: \"end\"; raw: string; indent: string }\n | { kind: \"direction\"; raw: string; indent: string; direction: string; dirty?: boolean }\n | {\n kind: \"classDef\";\n raw: string;\n indent: string;\n names: string[];\n styles: string[];\n dirty?: boolean;\n }\n | {\n kind: \"class\";\n raw: string;\n indent: string;\n ids: string[];\n className: string;\n dirty?: boolean;\n }\n | { kind: \"style\"; raw: string; indent: string; id: string; styles: string[]; dirty?: boolean }\n | {\n kind: \"linkStyle\";\n raw: string;\n indent: string;\n targets: number[] | \"default\";\n styles: string[];\n dirty?: boolean;\n }\n | { kind: \"click\"; raw: string; indent: string; id: string; rest: string; dirty?: boolean };\n\n// ---------------------------------------------------------------------------\n// Tokenisation helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Mermaid's NODE_STRING: letters, digits and a generous set of punctuation,\n * plus `-` when not followed by `>`, `-` or `.`, and `=` when not followed by `=`.\n */\nfunction readId(input: string, pos: number): string {\n let i = pos;\n while (i < input.length) {\n const ch = input[i]!;\n const next = input[i + 1];\n if (/[A-Za-z0-9_À-!#$%*+?/\\\\'`]/.test(ch)) {\n i++;\n continue;\n }\n if (ch === \".\" && next !== \"-\") {\n i++;\n continue;\n }\n if (\n ch === \"-\" &&\n next !== \">\" &&\n next !== \"-\" &&\n next !== \".\" &&\n next !== undefined &&\n !/\\s/.test(next)\n ) {\n i++;\n continue;\n }\n if (ch === \"=\" && next !== \"=\") {\n i++;\n continue;\n }\n break;\n }\n return input.slice(pos, i);\n}\n\n/** Finds the first occurrence of any closer outside double quotes. */\nfunction findCloser(\n input: string,\n pos: number,\n closers: string[],\n): { index: number; closer: string } | null {\n let quote: string | null = null;\n for (let i = pos; i < input.length; i++) {\n const ch = input[i]!;\n if (quote) {\n if (ch === quote) quote = null;\n continue;\n }\n if (ch === '\"') {\n quote = ch;\n continue;\n }\n for (const closer of closers) {\n if (input.startsWith(closer, i)) return { index: i, closer };\n }\n }\n return null;\n}\n\n/** Reads a balanced `{ … }` block starting at `pos` (which must be `{`). */\nfunction readBraceBlock(input: string, pos: number): number {\n let depth = 0;\n let quote: string | null = null;\n for (let i = pos; i < input.length; i++) {\n const ch = input[i]!;\n if (quote) {\n if (ch === quote) quote = null;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch;\n continue;\n }\n if (ch === \"{\") depth++;\n else if (ch === \"}\") {\n depth--;\n if (depth === 0) return i + 1;\n }\n }\n return -1;\n}\n\n/** Parses the inside of `@{ … }` into key → raw value. */\nexport function parseShapeData(inner: string): Record<string, string> {\n const out: Record<string, string> = {};\n // Split on commas/newlines outside quotes.\n const parts: string[] = [];\n let cur = \"\";\n let quote: string | null = null;\n for (const ch of inner) {\n if (quote) {\n cur += ch;\n if (ch === quote) quote = null;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch;\n cur += ch;\n continue;\n }\n if (ch === \",\" || ch === \"\\n\") {\n parts.push(cur);\n cur = \"\";\n continue;\n }\n cur += ch;\n }\n parts.push(cur);\n for (const part of parts) {\n const m = /^\\s*([A-Za-z_][\\w-]*)\\s*:\\s*([\\s\\S]*?)\\s*$/.exec(part);\n if (m) out[m[1]!] = m[2]!;\n }\n return out;\n}\n\nfunction unquoteData(value: string | undefined): string | undefined {\n if (value === undefined) return undefined;\n const t = value.trim();\n if ((t.startsWith('\"') && t.endsWith('\"')) || (t.startsWith(\"'\") && t.endsWith(\"'\"))) {\n return t.slice(1, -1);\n }\n return t;\n}\n\nexport function formatShapeData(data: Record<string, string>): string {\n const entries = Object.entries(data).map(([k, v]) => `${k}: ${v}`);\n return `@{ ${entries.join(\", \")} }`;\n}\n\n/**\n * Parses one node reference at `pos`. Returns `null` when no id is present.\n */\nfunction readNode(input: string, pos: number): { node: NodeRef; end: number } | null {\n const id = readId(input, pos);\n if (!id) return null;\n let i = pos + id.length;\n const node: NodeRef = { id, classes: [] };\n\n // Data syntax: id@{ ... }\n if (input[i] === \"@\" && input[i + 1] === \"{\") {\n const end = readBraceBlock(input, i + 1);\n if (end !== -1) {\n const inner = input.slice(i + 2, end - 1);\n const data = parseShapeData(inner);\n node.form = \"data\";\n if (data.shape !== undefined) {\n node.shape = canonicalShape(unquoteData(data.shape));\n delete data.shape;\n }\n if (data.label !== undefined) {\n node.label = unquoteData(data.label);\n node.labelQuoted = /^\\s*[\"']/.test(data.label);\n delete data.label;\n }\n // Mermaid draws a node with `img` as an image and one with `icon` as an\n // icon, whatever its `shape` says.\n if (\"img\" in data) node.shape = \"image\";\n else if (\"icon\" in data && node.shape === undefined) node.shape = \"icon\";\n node.data = data;\n i = end;\n }\n } else {\n // Bracket syntax\n for (const open of BRACKET_OPENERS) {\n if (!input.startsWith(open, i)) continue;\n const closers = closersFor(open);\n const found = findCloser(input, i + open.length, closers);\n if (!found) break;\n const shapeDef = shapeForBracket(open, found.closer);\n if (!shapeDef) break;\n const rawLabel = input.slice(i + open.length, found.index);\n node.shape = shapeDef.name;\n node.form = \"bracket\";\n node.label = unquoteLabel(rawLabel);\n node.labelQuoted = rawLabel.trim().startsWith('\"');\n i = found.index + found.closer.length;\n break;\n }\n }\n\n // :::class (repeatable)\n while (input.startsWith(\":::\", i)) {\n const cls = readId(input, i + 3);\n if (!cls) break;\n node.classes.push(cls);\n i += 3 + cls.length;\n }\n return { node, end: i };\n}\n\nfunction skipWs(input: string, pos: number): number {\n let i = pos;\n while (i < input.length && /\\s/.test(input[i]!)) i++;\n return i;\n}\n\n/**\n * Parses a chain statement (`A[x] --> B & C -- t --> D:::k`).\n * Returns `null` if the text is not a chain.\n */\nexport function parseChain(text: string): Chain | null {\n const groups: NodeRef[][] = [];\n const links: LinkRef[] = [];\n let pos = skipWs(text, 0);\n let group: NodeRef[] = [];\n\n const first = readNode(text, pos);\n if (!first) return null;\n group.push(first.node);\n pos = skipWs(text, first.end);\n\n while (pos < text.length) {\n if (text[pos] === \"&\") {\n pos = skipWs(text, pos + 1);\n const n = readNode(text, pos);\n if (!n) return null;\n group.push(n.node);\n pos = skipWs(text, n.end);\n continue;\n }\n const link = parseLink(text.slice(pos));\n if (link) {\n groups.push(group);\n group = [];\n links.push({\n id: link.id,\n pattern: link.pattern,\n arrowStart: link.arrowStart,\n arrowEnd: link.arrowEnd,\n length: link.length,\n label: link.label,\n labelStyle: link.labelStyle,\n });\n pos = skipWs(text, pos + link.consumed);\n const n = readNode(text, pos);\n if (!n) return null;\n group.push(n.node);\n pos = skipWs(text, n.end);\n continue;\n }\n return null; // trailing garbage\n }\n groups.push(group);\n return { groups, links };\n}\n\n// ---------------------------------------------------------------------------\n// Statement classification\n// ---------------------------------------------------------------------------\n\nfunction splitStyles(text: string): string[] {\n return text\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n}\n\n/** Classifies a single logical statement line. */\nexport function parseStatement(line: string): FlowStatement {\n const indent = line.match(/^\\s*/)![0];\n const text = line.trim();\n if (text === \"\" || text.startsWith(\"%%\")) return { kind: \"raw\", raw: line };\n\n let m: RegExpExecArray | null;\n\n if (/^end\\s*$/i.test(text)) return { kind: \"end\", raw: line, indent };\n\n if ((m = /^direction\\s+(TB|TD|BT|LR|RL)\\s*$/i.exec(text))) {\n return { kind: \"direction\", raw: line, indent, direction: m[1]!.toUpperCase() };\n }\n\n if ((m = /^subgraph\\s+(.*)$/i.exec(text))) {\n const rest = m[1]!.trim();\n let sm: RegExpExecArray | null;\n if ((sm = /^([^\\s[\"]+)\\s*\\[(.*)\\]\\s*$/.exec(rest))) {\n return {\n kind: \"subgraph\",\n raw: line,\n indent,\n id: sm[1]!,\n title: unquoteLabel(sm[2]!),\n titleForm: \"bracket\",\n };\n }\n if ((sm = /^\"(.*)\"\\s*$/.exec(rest))) {\n return { kind: \"subgraph\", raw: line, indent, id: sm[1]!, title: sm[1]!, titleForm: \"bare\" };\n }\n if (/\\s/.test(rest)) {\n // `subgraph My Title` — id is the title text, as Mermaid does.\n return { kind: \"subgraph\", raw: line, indent, id: rest, title: rest, titleForm: \"bare\" };\n }\n return { kind: \"subgraph\", raw: line, indent, id: rest, titleForm: \"none\" };\n }\n\n if ((m = /^classDef\\s+([^\\s]+)\\s+(.*)$/.exec(text))) {\n return {\n kind: \"classDef\",\n raw: line,\n indent,\n names: m[1]!.split(\",\"),\n styles: splitStyles(m[2]!),\n };\n }\n\n if ((m = /^class\\s+([^\\s]+)\\s+([^\\s]+)\\s*$/.exec(text))) {\n return { kind: \"class\", raw: line, indent, ids: m[1]!.split(\",\"), className: m[2]! };\n }\n\n if ((m = /^style\\s+([^\\s]+)\\s+(.*)$/.exec(text))) {\n return { kind: \"style\", raw: line, indent, id: m[1]!, styles: splitStyles(m[2]!) };\n }\n\n if ((m = /^linkStyle\\s+(default|[\\d,\\s]+)\\s+(.*)$/.exec(text))) {\n const targets =\n m[1] === \"default\"\n ? (\"default\" as const)\n : m[1]!\n .split(\",\")\n .map((s) => Number.parseInt(s.trim(), 10))\n .filter((n) => !Number.isNaN(n));\n return { kind: \"linkStyle\", raw: line, indent, targets, styles: splitStyles(m[2]!) };\n }\n\n if ((m = /^click\\s+([^\\s]+)\\s+(.*)$/.exec(text))) {\n return { kind: \"click\", raw: line, indent, id: m[1]!, rest: m[2]! };\n }\n\n if (/^(accTitle|accDescr)\\b/.test(text) || /^title\\s/.test(text))\n return { kind: \"raw\", raw: line };\n\n const chain = parseChain(text);\n if (chain) return { kind: \"chain\", raw: line, indent, chain };\n\n return { kind: \"raw\", raw: line };\n}\n\n// ---------------------------------------------------------------------------\n// Serialisation\n// ---------------------------------------------------------------------------\n\nexport function formatNode(node: NodeRef): string {\n let out = node.id;\n const shape = node.shape ? resolveShape(node.shape) : undefined;\n const useData =\n node.form === \"data\" ||\n (node.shape && !shape?.bracket) ||\n (node.data && Object.keys(node.data).length);\n if (\n useData &&\n (node.shape || node.label !== undefined || (node.data && Object.keys(node.data).length))\n ) {\n const data: Record<string, string> = {};\n // Mermaid infers these shapes from `img` / `icon` (and has no `shape: image`).\n const implied =\n (node.shape === \"image\" && node.data && \"img\" in node.data) ||\n (node.shape === \"icon\" && node.data && \"icon\" in node.data);\n if (node.shape && !implied) data.shape = node.shape;\n if (node.label !== undefined) data.label = JSON.stringify(node.label);\n Object.assign(data, node.data ?? {});\n out += formatShapeData(data);\n } else if (\n shape?.bracket &&\n (node.label !== undefined || node.shape !== \"rect\" || node.form === \"bracket\")\n ) {\n const label = node.label ?? node.id;\n const text = node.labelQuoted\n ? `\"${label.replace(/\"/g, \"#quot;\")}\"`\n : quoteLabelIfNeeded(label);\n out += `${shape.bracket.open}${text}${shape.bracket.close}`;\n } else if (node.label !== undefined && node.label !== node.id) {\n out += `[${quoteLabelIfNeeded(node.label)}]`;\n }\n for (const cls of node.classes) out += `:::${cls}`;\n return out;\n}\n\nexport function formatChain(chain: Chain): string {\n const parts: string[] = [];\n chain.groups.forEach((group, i) => {\n parts.push(group.map(formatNode).join(\" & \"));\n const link = chain.links[i];\n if (link) parts.push(formatLink(link));\n });\n return parts.join(\" \");\n}\n\nexport function formatStatement(stmt: FlowStatement): string {\n if (stmt.kind === \"raw\" || stmt.kind === \"end\") return stmt.raw;\n if (!stmt.dirty) return stmt.raw;\n switch (stmt.kind) {\n case \"chain\":\n return stmt.indent + formatChain(stmt.chain);\n case \"subgraph\": {\n if (stmt.titleForm === \"none\" || stmt.title === undefined)\n return `${stmt.indent}subgraph ${stmt.id}`;\n if (stmt.titleForm === \"bare\")\n return `${stmt.indent}subgraph ${stmt.title.includes(\" \") || stmt.title !== stmt.id ? `\"${stmt.title}\"` : stmt.title}`;\n return `${stmt.indent}subgraph ${stmt.id} [${quoteLabelIfNeeded(stmt.title)}]`;\n }\n case \"direction\":\n return `${stmt.indent}direction ${stmt.direction}`;\n case \"classDef\":\n return `${stmt.indent}classDef ${stmt.names.join(\",\")} ${stmt.styles.join(\",\")}`;\n case \"class\":\n return `${stmt.indent}class ${stmt.ids.join(\",\")} ${stmt.className}`;\n case \"style\":\n return `${stmt.indent}style ${stmt.id} ${stmt.styles.join(\",\")}`;\n case \"linkStyle\":\n return `${stmt.indent}linkStyle ${stmt.targets === \"default\" ? \"default\" : stmt.targets.join(\",\")} ${stmt.styles.join(\",\")}`;\n case \"click\":\n return `${stmt.indent}click ${stmt.id} ${stmt.rest}`;\n }\n}\n\n/**\n * Joins physical lines into logical statements: a line with an unclosed\n * `@{` absorbs following lines until the block closes. Returns the logical\n * statements and, for each, how many physical lines it spans.\n */\nexport function joinLogicalLines(lines: string[]): string[] {\n const out: string[] = [];\n let i = 0;\n while (i < lines.length) {\n let cur = lines[i]!;\n const at = cur.indexOf(\"@{\");\n if (at !== -1 && readBraceBlock(cur, at + 1) === -1) {\n let j = i + 1;\n while (j < lines.length) {\n cur += \"\\n\" + lines[j];\n j++;\n if (readBraceBlock(cur, at + 1) !== -1) break;\n }\n out.push(cur);\n i = j;\n continue;\n }\n out.push(cur);\n i++;\n }\n return out;\n}\n","import type {\n AdapterParseContext,\n Diagnostic,\n DiagramGraph,\n GraphEdge,\n GraphGroup,\n GraphNode,\n MermaidDocument,\n} from \"../types.js\";\nimport { splitStatements } from \"../source/lines.js\";\nimport { joinLogicalLines, parseStatement, type FlowStatement, type NodeRef } from \"./statements.js\";\nimport { DEFAULT_SHAPE } from \"./shapes.js\";\n\n/** Body model of a flowchart document. */\nexport interface FlowchartBody {\n statements: FlowStatement[];\n}\n\nexport type FlowchartDocument = MermaidDocument<FlowchartBody>;\n\n/** Mermaid's auto edge id scheme. */\nexport function autoEdgeId(source: string, target: string, ordinal: number): string {\n return `L_${source}_${target}_${ordinal}`;\n}\n\nconst HEADER_DIRECTION = /^\\s*(?:flowchart|graph)(?:-elk)?\\s*(TB|TD|BT|LR|RL)?\\s*;?\\s*$/i;\n\nexport function headerDirection(header: string): string {\n const m = HEADER_DIRECTION.exec(header);\n return (m?.[1] ?? \"TB\").toUpperCase();\n}\n\n/** Tokenises body lines into statements (one per logical line or `;` segment). */\nexport function tokenizeBody(bodyLines: string[]): FlowStatement[] {\n const statements: FlowStatement[] = [];\n for (const logical of joinLogicalLines(bodyLines)) {\n // `;` separated statements on one line are kept as separate statements\n // but we remember they shared a line through a trailing marker so the\n // serializer can join them back. Simpler: only split when it is unambiguous\n // (no `@{`), otherwise keep the whole line.\n if (logical.includes(\"@{\") || !logical.includes(\";\")) {\n statements.push(parseStatement(logical));\n continue;\n }\n const segments = splitStatements(logical);\n const nonEmpty = segments.filter((s) => s.trim() !== \"\");\n if (nonEmpty.length <= 1) {\n // A single statement, possibly with a trailing `;` — keep the line intact.\n const stmt = parseStatement(nonEmpty[0] ?? logical);\n stmt.raw = logical;\n statements.push(stmt);\n continue;\n }\n // Keep `;`-joined statements as one raw-ish compound: parse each segment\n // so the graph is right, but mark the group so re-emission stays on a line.\n const parsed = nonEmpty.map((seg, i) => parseStatement(i === 0 ? seg : seg.trimStart()));\n // Attach the original for lossless output when untouched.\n statements.push(...withCompoundMarker(parsed, logical));\n }\n return statements;\n}\n\n/**\n * Compound (`a; b`) handling: the first statement carries the full raw line\n * and the rest carry an empty raw so that serialising untouched output\n * reproduces the single line. When any member becomes dirty, each member is\n * emitted on its own line — a semantics-preserving normalisation.\n */\nconst COMPOUND = Symbol(\"compound\");\nexport interface CompoundMarked {\n [COMPOUND]?: { members: FlowStatement[]; raw: string };\n}\n\nfunction withCompoundMarker(parsed: FlowStatement[], raw: string): FlowStatement[] {\n parsed.forEach((stmt, i) => markCompound(stmt, parsed, i === 0 ? raw : \"\"));\n return parsed;\n}\n\n/** Attaches compound membership to a statement (used when cloning). */\nexport function markCompound(stmt: FlowStatement, members: FlowStatement[], raw: string): void {\n (stmt as CompoundMarked)[COMPOUND] = { members, raw };\n}\n\nexport function compoundInfo(\n stmt: FlowStatement,\n): { members: FlowStatement[]; raw: string } | undefined {\n return (stmt as CompoundMarked)[COMPOUND];\n}\n\n/**\n * Builds the normalised graph from statements. Follows Mermaid's rules:\n * a node belongs to the innermost subgraph in which it is mentioned; when it\n * is mentioned in several, the one declared last wins (Mermaid's `makeUniq`).\n */\nexport function buildGraph(\n statements: FlowStatement[],\n direction: string,\n title?: string,\n): {\n graph: DiagramGraph;\n diagnostics: Diagnostic[];\n} {\n const nodes = new Map<string, GraphNode>();\n const groups = new Map<string, GraphGroup>();\n const edges: GraphEdge[] = [];\n const classDefs: Record<string, string[]> = {};\n const diagnostics: Diagnostic[] = [];\n const stack: string[] = [];\n /** Mentions per subgraph, in declaration order. */\n const membership = new Map<string, Set<string>>();\n const classAssignments: { ids: string[]; className: string }[] = [];\n const styleAssignments: { id: string; styles: string[] }[] = [];\n const clicks: { id: string; rest: string }[] = [];\n const linkStyles: { targets: number[] | \"default\"; styles: string[] }[] = [];\n const dataOnly: { id: string; data: Record<string, string> }[] = [];\n let ordinal = 0;\n\n const touch = (ref: NodeRef): GraphNode => {\n let node = nodes.get(ref.id);\n if (!node) {\n node = { id: ref.id, label: ref.id, shape: DEFAULT_SHAPE, classes: [], styles: [] };\n nodes.set(ref.id, node);\n }\n if (ref.label !== undefined) node.label = ref.label;\n if (ref.shape) node.shape = ref.shape;\n for (const cls of ref.classes) if (!node.classes.includes(cls)) node.classes.push(cls);\n if (ref.data && Object.keys(ref.data).length) {\n node.data = { ...(node.data ?? {}), ...stripQuotes(ref.data) };\n }\n const current = stack[stack.length - 1];\n if (current) membership.get(current)!.add(ref.id);\n return node;\n };\n\n statements.forEach((stmt, index) => {\n switch (stmt.kind) {\n case \"subgraph\": {\n const parent = stack[stack.length - 1];\n if (groups.has(stmt.id)) {\n diagnostics.push({\n severity: \"warning\",\n message: `Duplicate subgraph id \"${stmt.id}\"`,\n line: index + 1,\n source: \"pixerate\",\n });\n }\n groups.set(stmt.id, {\n id: stmt.id,\n label: stmt.title ?? stmt.id,\n parentId: parent,\n classes: [],\n styles: [],\n });\n membership.set(stmt.id, new Set());\n if (parent) membership.get(parent)!.add(stmt.id);\n stack.push(stmt.id);\n break;\n }\n case \"end\":\n if (!stack.length) {\n diagnostics.push({\n severity: \"warning\",\n message: \"Stray `end` without a subgraph\",\n line: index + 1,\n source: \"pixerate\",\n });\n }\n stack.pop();\n break;\n case \"direction\": {\n const current = stack[stack.length - 1];\n if (current) groups.get(current)!.direction = stmt.direction;\n break;\n }\n case \"chain\": {\n const { groups: ngroups, links } = stmt.chain;\n // A lone `id@{ animate: true }` targets an edge, not a node — resolve later.\n if (ngroups.length === 1 && ngroups[0]!.length === 1 && links.length === 0) {\n const ref = ngroups[0]!;\n const only = ref[0]!;\n if (\n only.form === \"data\" &&\n only.data &&\n !only.shape &&\n only.label === undefined &&\n (\"animate\" in only.data || \"animation\" in only.data)\n ) {\n dataOnly.push({ id: only.id, data: only.data });\n break;\n }\n }\n for (const group of ngroups) for (const ref of group) touch(ref);\n links.forEach((link, i) => {\n const from = ngroups[i]!;\n const to = ngroups[i + 1]!;\n for (const s of from) {\n for (const t of to) {\n const id = link.id ?? autoEdgeId(s.id, t.id, ordinal);\n edges.push({\n id,\n source: s.id,\n target: t.id,\n label: link.label,\n pattern: link.pattern,\n arrowStart: link.arrowStart,\n arrowEnd: link.arrowEnd,\n length: link.length,\n classes: [],\n styles: [],\n userDefinedId: !!link.id,\n });\n ordinal++;\n }\n }\n });\n break;\n }\n case \"classDef\":\n for (const name of stmt.names) classDefs[name] = [...stmt.styles];\n break;\n case \"class\":\n classAssignments.push({ ids: stmt.ids, className: stmt.className });\n break;\n case \"style\":\n styleAssignments.push({ id: stmt.id, styles: stmt.styles });\n break;\n case \"linkStyle\":\n linkStyles.push({ targets: stmt.targets, styles: stmt.styles });\n break;\n case \"click\":\n clicks.push({ id: stmt.id, rest: stmt.rest });\n break;\n default:\n break;\n }\n });\n\n if (stack.length) {\n diagnostics.push({\n severity: \"warning\",\n message: `${stack.length} subgraph(s) missing \\`end\\``,\n source: \"pixerate\",\n });\n }\n\n // Resolve group membership: last mention wins.\n const parentOf = new Map<string, string>();\n for (const [groupId, members] of membership) {\n for (const member of members) parentOf.set(member, groupId);\n }\n for (const node of nodes.values()) {\n const parent = parentOf.get(node.id);\n if (parent && groups.has(parent)) node.parentId = parent;\n }\n for (const group of groups.values()) {\n const parent = parentOf.get(group.id);\n if (parent && parent !== group.id && groups.has(parent)) group.parentId = parent;\n }\n\n for (const { ids, className } of classAssignments) {\n for (const id of ids) {\n const node = nodes.get(id);\n const group = groups.get(id);\n const target = node ?? group;\n if (target && !target.classes.includes(className)) target.classes.push(className);\n }\n }\n for (const { id, styles } of styleAssignments) {\n const target = nodes.get(id) ?? groups.get(id);\n if (target) target.styles.push(...styles);\n }\n for (const { id, rest } of clicks) {\n const node = nodes.get(id);\n if (!node) continue;\n const parsed = parseClick(rest);\n if (parsed.href) {\n node.link = parsed.href;\n node.linkTarget = parsed.target;\n }\n if (parsed.tooltip) node.tooltip = parsed.tooltip;\n if (parsed.callback) node.data = { ...(node.data ?? {}), callback: parsed.callback };\n }\n for (const { targets, styles } of linkStyles) {\n if (targets === \"default\") {\n for (const edge of edges) edge.styles.push(...styles);\n } else {\n for (const idx of targets) {\n const edge = edges[idx];\n if (edge) edge.styles.push(...styles);\n else\n diagnostics.push({\n severity: \"warning\",\n message: `linkStyle index ${idx} has no edge`,\n source: \"pixerate\",\n });\n }\n }\n }\n for (const { id, data } of dataOnly) {\n const edge = edges.find((e) => e.id === id);\n if (edge) {\n if (data.animate !== undefined) edge.animate = data.animate.trim() === \"true\";\n if (data.animation !== undefined) {\n const a = data.animation.trim();\n if (a === \"fast\" || a === \"slow\") edge.animation = a;\n }\n } else {\n // Not an edge after all: treat as a node with data.\n const node: GraphNode = {\n id,\n label: id,\n shape: DEFAULT_SHAPE,\n classes: [],\n styles: [],\n data: stripQuotes(data),\n };\n nodes.set(id, node);\n }\n }\n\n return {\n graph: {\n direction,\n nodes: [...nodes.values()],\n edges,\n groups: [...groups.values()],\n classDefs,\n title,\n },\n diagnostics,\n };\n}\n\nfunction stripQuotes(data: Record<string, string>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(data)) {\n const t = v.trim();\n if ((t.startsWith('\"') && t.endsWith('\"')) || (t.startsWith(\"'\") && t.endsWith(\"'\")))\n out[k] = t.slice(1, -1);\n else if (t === \"true\" || t === \"false\") out[k] = t === \"true\";\n else if (/^-?\\d+(\\.\\d+)?$/.test(t)) out[k] = Number(t);\n else out[k] = t;\n }\n return out;\n}\n\nexport interface ParsedClick {\n href?: string;\n target?: string;\n tooltip?: string;\n callback?: string;\n}\n\n/** Parses the tail of a `click` statement. */\nexport function parseClick(rest: string): ParsedClick {\n const out: ParsedClick = {};\n const strings = [...rest.matchAll(/\"([^\"]*)\"/g)].map((m) => m[1]!);\n const words = rest\n .replace(/\"[^\"]*\"/g, \"\")\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n const targetWord = words.find((w) => /^_(blank|self|parent|top)$/.test(w));\n if (targetWord) out.target = targetWord;\n if (words[0] === \"href\") {\n out.href = strings[0];\n out.tooltip = strings[1];\n } else if (words[0] === \"call\" || words[0] === \"callback\") {\n out.callback =\n words[0] === \"callback\"\n ? words[1]\n : rest\n .replace(/^call\\s+/, \"\")\n .replace(/\"[^\"]*\"/g, \"\")\n .trim();\n out.tooltip = strings[0];\n } else if (strings.length && /^https?:|^\\/|^#|^mailto:/.test(strings[0]!)) {\n out.href = strings[0];\n out.tooltip = strings[1];\n } else if (words.length) {\n out.callback = words[0];\n out.tooltip = strings[0];\n }\n return out;\n}\n\n/** Parses a flowchart body into a document. */\nexport function parseFlowchart(_source: string, ctx: AdapterParseContext): FlowchartDocument {\n const statements = tokenizeBody(ctx.bodyLines);\n const direction = headerDirection(ctx.header);\n const title =\n typeof ctx.preamble.frontmatter?.title === \"string\"\n ? ctx.preamble.frontmatter.title\n : undefined;\n const { graph, diagnostics } = buildGraph(statements, direction, title);\n return {\n family: \"flowchart\",\n tier: \"editable\",\n source: ctx.source,\n preamble: ctx.preamble,\n header: ctx.header,\n trailing: ctx.trailing,\n eol: ctx.eol,\n graph,\n meta: ctx.meta,\n metaCarrier: ctx.metaCarrier,\n body: { statements },\n diagnostics,\n dirty: false,\n };\n}\n","import type { MermaidDocument, DiagramMeta } from \"../types.js\";\nimport { isMetaEmpty, metaCommentLine, writeMetaToPreamble } from \"../source/metadata.js\";\nimport { compoundInfo, type FlowchartBody } from \"./parse.js\";\nimport { formatStatement, type FlowStatement } from \"./statements.js\";\n\n/** Serialises statements, honouring compound (`a; b`) lines. */\nexport function serializeStatements(statements: FlowStatement[]): string[] {\n const out: string[] = [];\n const emitted = new Set<FlowStatement>();\n const present = new Set(statements);\n for (const stmt of statements) {\n if (emitted.has(stmt)) continue;\n const compound = compoundInfo(stmt);\n if (compound) {\n const members = compound.members.filter((m) => present.has(m));\n const complete = members.length === compound.members.length;\n const anyDirty = members.some((m) => \"dirty\" in m && m.dirty);\n if (complete && !anyDirty) {\n out.push(compound.raw);\n for (const member of compound.members) emitted.add(member);\n continue;\n }\n // Normalise to one statement per line; each member keeps its own text.\n const indent =\n \"indent\" in compound.members[0]! ? (compound.members[0] as { indent: string }).indent : \"\";\n for (const member of members) {\n const text = formatStatement(member);\n if (text.trim() === \"\") continue;\n out.push(text.startsWith(indent) ? text : indent + text.trimStart());\n }\n for (const member of compound.members) emitted.add(member);\n continue;\n }\n out.push(formatStatement(stmt));\n emitted.add(stmt);\n }\n return out;\n}\n\n/** Indentation used by the first indented body statement, defaulting to two spaces. */\nexport function detectIndent(statements: FlowStatement[]): string {\n for (const stmt of statements) {\n if (\"indent\" in stmt && stmt.indent) return stmt.indent;\n }\n return \" \";\n}\n\n/**\n * Assembles the full document text: preamble, header, metadata, body and the\n * original trailing whitespace.\n */\nexport function assembleDocument(\n doc: Pick<MermaidDocument, \"preamble\" | \"header\" | \"trailing\" | \"eol\" | \"meta\" | \"metaCarrier\">,\n bodyLines: string[],\n indent: string,\n): string {\n const meta: DiagramMeta | null = isMetaEmpty(doc.meta) ? null : doc.meta;\n const preambleLines =\n doc.metaCarrier === \"frontmatter\"\n ? writeMetaToPreamble(doc.preamble, meta)\n : [...doc.preamble.lines];\n const lines = [...preambleLines];\n if (doc.header) lines.push(doc.header);\n if (meta && doc.metaCarrier === \"comment\") lines.push(metaCommentLine(meta, indent));\n lines.push(...bodyLines);\n return lines.join(doc.eol) + doc.trailing;\n}\n\nexport function serializeFlowchart(doc: MermaidDocument<FlowchartBody>): string {\n const bodyLines = serializeStatements(doc.body.statements);\n return assembleDocument(doc, bodyLines, detectIndent(doc.body.statements));\n}\n","import type { EditOp, GraphEdge, MermaidDocument } from \"../types.js\";\nimport { type FlowchartBody, parseFlowchart, compoundInfo, markCompound } from \"./parse.js\";\nimport { serializeFlowchart, detectIndent } from \"./serialize.js\";\nimport { splitSource } from \"../source/lines.js\";\nimport {\n defaultCarrierFor,\n extractMetaFromBody,\n extractMetaFromFrontmatter,\n emptyMeta,\n mergeMeta,\n} from \"../source/metadata.js\";\nimport type { Chain, FlowStatement, LinkRef, NodeRef } from \"./statements.js\";\nimport { canonicalShape } from \"./shapes.js\";\n\ntype Doc = MermaidDocument<FlowchartBody>;\ntype ChainStmt = Extract<FlowStatement, { kind: \"chain\" }>;\ntype SubgraphStmt = Extract<FlowStatement, { kind: \"subgraph\" }>;\n\n/**\n * Applies an edit to a flowchart document. Statements are mutated in place\n * on a shallow copy, the document is re-serialised and re-parsed so that the\n * returned model is always consistent with its text.\n */\nexport function applyFlowchartEdit(doc: Doc, op: EditOp): Doc {\n if (op.type === \"removeEdges\" && op.ids.length > 1) return removeEdgesOneByOne(doc, op.ids);\n const statements = cloneStatements(doc.body.statements);\n const work: Doc = {\n ...doc,\n body: { statements },\n meta: { ...doc.meta, layout: { ...doc.meta.layout }, sizes: { ...doc.meta.sizes } },\n };\n const indent = detectIndent(statements);\n\n switch (op.type) {\n case \"moveNodes\":\n for (const { id, position } of op.moves) work.meta.layout![id] = position;\n return reparse(work, false);\n case \"resizeNode\":\n if (op.size) work.meta.sizes![op.id] = op.size;\n else delete work.meta.sizes![op.id];\n return reparse(work, false);\n case \"setViewport\":\n work.meta.viewport = op.viewport;\n return reparse(work, false);\n case \"setMetaExt\":\n work.meta.ext = { ...(work.meta.ext ?? {}), [op.key]: op.value };\n if (op.value === undefined) delete work.meta.ext[op.key];\n return reparse(work, false);\n case \"setDirection\":\n work.header = setHeaderDirection(work.header, op.direction);\n return reparse(work, true);\n case \"setTitle\":\n work.preamble = {\n ...work.preamble,\n lines: setFrontmatterTitle(work.preamble.lines, op.title),\n };\n return reparse(work, true);\n case \"replaceSource\":\n return parseFlowchartSource(op.source, work.metaCarrier);\n default:\n break;\n }\n\n // Structural edits below.\n switch (op.type) {\n case \"addNode\": {\n const ref: NodeRef = {\n id: op.node.id,\n label: op.node.label ?? op.node.id,\n shape: canonicalShape(op.node.shape ?? \"rect\"),\n form: \"bracket\",\n classes: [...(op.node.classes ?? [])],\n };\n const data = shapeDataFor(ref.shape!, encodeData(op.node.data));\n if (Object.keys(data).length) {\n ref.form = \"data\";\n ref.data = data;\n }\n const stmt: ChainStmt = {\n kind: \"chain\",\n raw: \"\",\n indent,\n chain: { groups: [[ref]], links: [] },\n dirty: true,\n };\n insertIntoGroup(statements, stmt, op.node.parentId, indent);\n if (op.position) work.meta.layout![op.node.id] = op.position;\n if (op.node.styles?.length) {\n statements.push({\n kind: \"style\",\n raw: \"\",\n indent,\n id: op.node.id,\n styles: [...op.node.styles],\n dirty: true,\n });\n }\n break;\n }\n case \"removeNodes\": {\n const ids = new Set(op.ids.filter((id) => !doc.graph.groups.some((g) => g.id === id)));\n // Group ids: drop the subgraph wrapper, keep its content (same as `ungroup`).\n for (const gid of op.ids.filter((id) => doc.graph.groups.some((g) => g.id === id))) {\n const range = groupRange(statements, gid);\n if (!range) continue;\n statements.splice(range.end, 1);\n statements.splice(range.start, 1);\n delete work.meta.layout![gid];\n delete work.meta.sizes![gid];\n }\n const removedEdgeOrdinals = edgeOrdinalsTouching(\n doc.graph.edges,\n (e) => ids.has(e.source) || ids.has(e.target),\n );\n removeNodesFromStatements(statements, ids);\n dropRedundantBareMentions(statements);\n // Drop class/style/click statements for removed nodes.\n filterInPlace(statements, (s) => {\n if (s.kind === \"style\" || s.kind === \"click\") return !ids.has(s.id);\n if (s.kind === \"class\") {\n s.ids = s.ids.filter((id) => !ids.has(id));\n if (!s.ids.length) return false;\n s.dirty = true;\n return true;\n }\n return true;\n });\n adjustLinkStyles(statements, removedEdgeOrdinals);\n for (const id of ids) {\n delete work.meta.layout![id];\n delete work.meta.sizes![id];\n }\n break;\n }\n case \"renameNode\": {\n const ref = declaringRef(statements, op.id, \"label\") ?? firstRef(statements, op.id);\n if (!ref) break;\n const node = doc.graph.nodes.find((n) => n.id === op.id);\n if (ref.ref.label === undefined) {\n ref.ref.shape = ref.ref.shape ?? node?.shape ?? \"rect\";\n ref.ref.form = ref.ref.form ?? \"bracket\";\n }\n ref.ref.label = op.label;\n ref.ref.labelQuoted = undefined;\n ref.stmt.dirty = true;\n break;\n }\n case \"setNodeShape\": {\n const shape = canonicalShape(op.shape);\n const ref = declaringRef(statements, op.id, \"shape\") ?? firstRef(statements, op.id);\n if (!ref) break;\n const node = doc.graph.nodes.find((n) => n.id === op.id);\n ref.ref.shape = shape;\n if (ref.ref.label === undefined) ref.ref.label = node?.label ?? op.id;\n ref.ref.form = ref.ref.form ?? \"bracket\";\n const data = shapeDataFor(shape, ref.ref.data ?? {});\n if (Object.keys(data).length) ref.ref.form = \"data\";\n ref.ref.data = Object.keys(data).length ? data : undefined;\n ref.stmt.dirty = true;\n break;\n }\n case \"setNodeClasses\": {\n // Clear existing `:::` and `class` references.\n for (const s of statements) {\n if (s.kind === \"chain\") {\n for (const g of s.chain.groups) {\n for (const r of g) {\n if (r.id === op.id && r.classes.length) {\n r.classes = [];\n s.dirty = true;\n }\n }\n }\n }\n }\n filterInPlace(statements, (s) => {\n if (s.kind !== \"class\") return true;\n if (!s.ids.includes(op.id)) return true;\n s.ids = s.ids.filter((id) => id !== op.id);\n s.dirty = true;\n return s.ids.length > 0;\n });\n const [first, ...rest] = op.classes;\n if (first) {\n const ref = declaringRef(statements, op.id, \"label\") ?? firstRef(statements, op.id);\n if (ref) {\n ref.ref.classes = [first];\n ref.stmt.dirty = true;\n }\n }\n for (const cls of rest)\n statements.push({\n kind: \"class\",\n raw: \"\",\n indent,\n ids: [op.id],\n className: cls,\n dirty: true,\n });\n break;\n }\n case \"setNodeStyles\": {\n filterInPlace(statements, (s) => !(s.kind === \"style\" && s.id === op.id));\n if (op.styles.length)\n statements.push({\n kind: \"style\",\n raw: \"\",\n indent,\n id: op.id,\n styles: [...op.styles],\n dirty: true,\n });\n break;\n }\n case \"setNodeLink\": {\n filterInPlace(statements, (s) => !(s.kind === \"click\" && s.id === op.id));\n if (op.link) {\n const parts = [`href \"${op.link}\"`];\n if (op.tooltip) parts.push(`\"${op.tooltip}\"`);\n if (op.target) parts.push(op.target);\n statements.push({\n kind: \"click\",\n raw: \"\",\n indent,\n id: op.id,\n rest: parts.join(\" \"),\n dirty: true,\n });\n }\n break;\n }\n case \"setNodeData\": {\n const ref = declaringRef(statements, op.id, \"label\") ?? firstRef(statements, op.id);\n if (!ref) break;\n const node = doc.graph.nodes.find((n) => n.id === op.id);\n ref.ref.form = \"data\";\n ref.ref.shape = ref.ref.shape ?? node?.shape ?? \"rect\";\n if (ref.ref.label === undefined) ref.ref.label = node?.label ?? op.id;\n const data = { ...(ref.ref.data ?? {}) };\n for (const [k, v] of Object.entries(op.data)) {\n if (v === undefined || v === null) delete data[k];\n else data[k] = typeof v === \"string\" ? JSON.stringify(v) : String(v);\n }\n ref.ref.data = data;\n ref.stmt.dirty = true;\n break;\n }\n case \"addEdge\": {\n const link: LinkRef = {\n id: op.edge.userDefinedId ? op.edge.id : undefined,\n pattern: op.edge.pattern ?? \"solid\",\n arrowStart: op.edge.arrowStart ?? \"none\",\n arrowEnd: op.edge.arrowEnd ?? \"arrow_point\",\n length: op.edge.length ?? 1,\n label: op.edge.label || undefined,\n labelStyle: op.edge.label ? \"pipe\" : undefined,\n };\n const stmt: ChainStmt = {\n kind: \"chain\",\n raw: \"\",\n indent,\n chain: {\n groups: [[{ id: op.edge.source, classes: [] }], [{ id: op.edge.target, classes: [] }]],\n links: [link],\n },\n dirty: true,\n };\n // Appending at top level never changes subgraph membership.\n appendAtEnd(statements, stmt);\n if (op.edge.styles?.length) {\n statements.push({\n kind: \"linkStyle\",\n raw: \"\",\n indent,\n targets: [doc.graph.edges.length],\n styles: [...op.edge.styles],\n dirty: true,\n });\n }\n break;\n }\n case \"removeEdges\": {\n const ids = new Set(op.ids);\n const removedOrdinals = edgeOrdinalsTouching(doc.graph.edges, (e) => ids.has(e.id));\n for (const edge of doc.graph.edges) {\n if (!ids.has(edge.id)) continue;\n const located = locateEdge(statements, doc.graph.edges, edge.id);\n if (!located) continue;\n removeLinkFromChain(\n statements,\n located.stmt,\n located.linkIndex,\n located.source,\n located.target,\n indent,\n );\n }\n adjustLinkStyles(statements, removedOrdinals);\n break;\n }\n case \"setEdgeLabel\":\n case \"setEdgeStyle\":\n case \"reconnectEdge\": {\n const located = locateEdge(statements, doc.graph.edges, op.id);\n if (!located) break;\n const stmt = isolateEdge(\n statements,\n located.stmt,\n located.linkIndex,\n located.source,\n located.target,\n indent,\n );\n const link = stmt.chain.links[0]!;\n if (op.type === \"setEdgeLabel\") {\n link.label = op.label || undefined;\n if (link.label && !link.labelStyle) link.labelStyle = \"pipe\";\n } else if (op.type === \"setEdgeStyle\") {\n if (op.pattern) link.pattern = op.pattern;\n if (op.arrowStart) link.arrowStart = op.arrowStart;\n if (op.arrowEnd) link.arrowEnd = op.arrowEnd;\n if (op.length) link.length = op.length;\n if (op.styles) {\n const ordinal = doc.graph.edges.findIndex((e) => e.id === op.id);\n setLinkStyleFor(statements, ordinal, op.styles, indent);\n }\n } else {\n stmt.chain.groups[0] = [{ id: op.source, classes: [] }];\n stmt.chain.groups[1] = [{ id: op.target, classes: [] }];\n }\n stmt.dirty = true;\n break;\n }\n case \"groupNodes\": {\n const open: SubgraphStmt = {\n kind: \"subgraph\",\n raw: \"\",\n indent,\n id: op.groupId,\n title: op.label,\n titleForm: \"bracket\",\n dirty: true,\n };\n const members: FlowStatement[] = op.nodeIds.map((id) => ({\n kind: \"chain\" as const,\n raw: \"\",\n indent: indent + indent,\n chain: { groups: [[{ id, classes: [] }]], links: [] },\n dirty: true,\n }));\n const block: FlowStatement[] = [\n open,\n ...members,\n { kind: \"end\", raw: `${indent}end`, indent },\n ];\n if (op.parentId) insertManyIntoGroup(statements, block, op.parentId, indent);\n else statements.push(...block);\n break;\n }\n case \"ungroup\": {\n const range = groupRange(statements, op.groupId);\n if (!range) break;\n const openIndent = (statements[range.start] as SubgraphStmt).indent;\n const inner = openIndent + indent;\n for (let i = range.start + 1; i < range.end; i++) {\n const s = statements[i]!;\n if (s.kind === \"raw\" || s.kind === \"end\") {\n if (s.raw.startsWith(inner))\n (s as { raw: string }).raw = openIndent + s.raw.slice(inner.length);\n continue;\n }\n if (s.indent.startsWith(inner)) {\n s.indent = openIndent + s.indent.slice(inner.length);\n s.dirty = true;\n }\n }\n statements.splice(range.end, 1);\n statements.splice(range.start, 1);\n // Remove direction statements that belonged to the group.\n for (let i = range.start; i < range.end - 1; i++) {\n const s = statements[i];\n if (\n s &&\n s.kind === \"direction\" &&\n depthAt(statements, i) === depthAt(statements, range.start)\n ) {\n statements.splice(i, 1);\n break;\n }\n }\n delete work.meta.layout![op.groupId];\n delete work.meta.sizes![op.groupId];\n break;\n }\n case \"renameGroup\": {\n const range = groupRange(statements, op.id);\n if (!range) break;\n const open = statements[range.start] as SubgraphStmt;\n open.title = op.label;\n if (open.titleForm === \"none\") open.titleForm = \"bracket\";\n if (open.titleForm === \"bare\") {\n // `subgraph Title` uses the title as id; switch to id [title] to keep the id stable.\n open.titleForm = \"bracket\";\n }\n open.dirty = true;\n break;\n }\n case \"setGroupDirection\": {\n const range = groupRange(statements, op.id);\n if (!range) break;\n let found = -1;\n for (let i = range.start + 1; i < range.end; i++) {\n const s = statements[i]!;\n if (\n s.kind === \"direction\" &&\n depthAt(statements, i) === depthAt(statements, range.start) + 1\n ) {\n found = i;\n break;\n }\n }\n if (op.direction) {\n if (found !== -1) {\n const s = statements[found] as Extract<FlowStatement, { kind: \"direction\" }>;\n s.direction = op.direction;\n s.dirty = true;\n } else {\n const inner = (statements[range.start] as SubgraphStmt).indent + indent;\n statements.splice(range.start + 1, 0, {\n kind: \"direction\",\n raw: \"\",\n indent: inner,\n direction: op.direction,\n dirty: true,\n });\n }\n } else if (found !== -1) {\n statements.splice(found, 1);\n }\n break;\n }\n case \"setNodeParent\": {\n for (const id of op.ids) {\n // Remove bare declarations (single-node chains) so the new mention is last.\n const bare = statements\n .map((s, i) => ({ s, i }))\n .filter(\n ({ s }) =>\n s.kind === \"chain\" &&\n s.chain.links.length === 0 &&\n s.chain.groups[0]!.length === 1 &&\n s.chain.groups[0]![0]!.id === id,\n );\n let decl: NodeRef | undefined;\n for (const { s, i } of bare.reverse()) {\n const ref = (s as ChainStmt).chain.groups[0]![0]!;\n if (ref.label !== undefined || ref.shape) decl = { ...ref };\n statements.splice(i, 1);\n }\n if (op.parentId) {\n const ref: NodeRef = decl ?? { id, classes: [] };\n const stmt: ChainStmt = {\n kind: \"chain\",\n raw: \"\",\n indent,\n chain: { groups: [[ref]], links: [] },\n dirty: true,\n };\n insertIntoGroup(statements, stmt, op.parentId, indent);\n } else if (decl) {\n appendAtEnd(statements, {\n kind: \"chain\",\n raw: \"\",\n indent,\n chain: { groups: [[decl]], links: [] },\n dirty: true,\n });\n }\n }\n break;\n }\n case \"setClassDef\": {\n let found = false;\n for (const s of statements) {\n if (s.kind !== \"classDef\") continue;\n if (s.names.length === 1 && s.names[0] === op.name) {\n found = true;\n if (op.styles) {\n s.styles = [...op.styles];\n s.dirty = true;\n }\n } else if (s.names.includes(op.name) && op.styles) {\n s.names = s.names.filter((n) => n !== op.name);\n s.dirty = true;\n }\n }\n if (!op.styles)\n filterInPlace(\n statements,\n (s) => !(s.kind === \"classDef\" && s.names.length === 1 && s.names[0] === op.name),\n );\n else if (!found)\n statements.push({\n kind: \"classDef\",\n raw: \"\",\n indent,\n names: [op.name],\n styles: [...op.styles],\n dirty: true,\n });\n break;\n }\n default:\n break;\n }\n\n return reparse(work, true);\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Clones statements and re-links compound (`a; b`) groups onto the clones. */\nfunction cloneStatements(statements: FlowStatement[]): FlowStatement[] {\n const clones = statements.map(cloneStatement);\n const index = new Map(statements.map((s, i) => [s, i]));\n const done = new Set<FlowStatement>();\n statements.forEach((original) => {\n const info = compoundInfo(original);\n if (!info || done.has(original)) return;\n const members = info.members.map((m) => clones[index.get(m)!]!);\n info.members.forEach((m, j) => {\n done.add(m);\n markCompound(members[j]!, members, j === 0 ? info.raw : \"\");\n });\n });\n return clones;\n}\n\nfunction cloneStatement(s: FlowStatement): FlowStatement {\n if (s.kind === \"chain\") {\n return {\n ...s,\n chain: {\n groups: s.chain.groups.map((g) =>\n g.map((r) => ({\n ...r,\n classes: [...r.classes],\n data: r.data ? { ...r.data } : undefined,\n })),\n ),\n links: s.chain.links.map((l) => ({ ...l })),\n },\n };\n }\n if (s.kind === \"classDef\") return { ...s, names: [...s.names], styles: [...s.styles] };\n if (s.kind === \"class\") return { ...s, ids: [...s.ids] };\n if (s.kind === \"style\") return { ...s, styles: [...s.styles] };\n if (s.kind === \"linkStyle\")\n return {\n ...s,\n targets: s.targets === \"default\" ? \"default\" : [...s.targets],\n styles: [...s.styles],\n };\n return { ...s };\n}\n\nfunction reparse(work: Doc, structural: boolean): Doc {\n const text = serializeFlowchart(work);\n const next = parseFlowchartSource(text, work.metaCarrier);\n next.dirty = doc_dirty(work, structural);\n return next;\n}\n\nfunction doc_dirty(work: Doc, structural: boolean): boolean {\n return work.dirty || structural;\n}\n\n/** Full parse of a flowchart source, used after edits. */\nexport function parseFlowchartSource(source: string, carrier?: Doc[\"metaCarrier\"]): Doc {\n const split = splitSource(source);\n const fromBody = extractMetaFromBody(split.bodyLines);\n const fromFm = extractMetaFromFrontmatter(split.preamble);\n let meta = emptyMeta();\n if (fromFm) meta = mergeMeta(meta, fromFm);\n if (fromBody.meta) meta = mergeMeta(meta, fromBody.meta);\n return parseFlowchart(source, {\n source,\n eol: split.eol,\n preamble: split.preamble,\n header: split.header,\n bodyLines: fromBody.bodyLines,\n trailing: split.trailing,\n meta,\n metaCarrier:\n carrier ?? (fromFm && !fromBody.meta ? \"frontmatter\" : defaultCarrierFor(\"flowchart\")),\n family: \"flowchart\",\n });\n}\n\nfunction filterInPlace<T>(arr: T[], keep: (item: T) => boolean): void {\n let j = 0;\n for (let i = 0; i < arr.length; i++) {\n if (keep(arr[i]!)) arr[j++] = arr[i]!;\n }\n arr.length = j;\n}\n\nfunction setHeaderDirection(header: string, direction: string): string {\n const m = /^(\\s*)(flowchart|graph)(-elk)?\\b/i.exec(header);\n if (!m) return header;\n const keyword = `${m[2]}${m[3] ?? \"\"}`;\n const trailingSemi = /;\\s*$/.test(header) ? \";\" : \"\";\n return `${m[1]}${keyword} ${direction}${trailingSemi}`;\n}\n\nfunction setFrontmatterTitle(lines: string[], title: string | undefined): string[] {\n const out = [...lines];\n const hasFm = out[0] !== undefined && /^---\\s*$/.test(out[0]);\n if (!hasFm) {\n if (title === undefined) return out;\n return [\"---\", `title: ${title}`, \"---\", ...out];\n }\n const close = out.findIndex((l, i) => i > 0 && /^---\\s*$/.test(l));\n const end = close === -1 ? out.length : close;\n const idx = out.findIndex((l, i) => i > 0 && i < end && /^title\\s*:/.test(l));\n if (title === undefined) {\n if (idx !== -1) out.splice(idx, 1);\n const close2 = out.findIndex((l, i) => i > 0 && /^---\\s*$/.test(l));\n if (close2 === 1) out.splice(0, 2);\n return out;\n }\n if (idx !== -1) out[idx] = `title: ${title}`;\n else out.splice(end, 0, `title: ${title}`);\n return out;\n}\n\n/** 0-based nesting depth before statement `index`. */\nfunction depthAt(statements: FlowStatement[], index: number): number {\n let depth = 0;\n for (let i = 0; i < index; i++) {\n const s = statements[i]!;\n if (s.kind === \"subgraph\") depth++;\n else if (s.kind === \"end\") depth = Math.max(0, depth - 1);\n }\n return depth;\n}\n\n/** Index range [start, end] of a subgraph's open/`end` statements. */\nfunction groupRange(\n statements: FlowStatement[],\n groupId: string,\n): { start: number; end: number } | null {\n const start = statements.findIndex((s) => s.kind === \"subgraph\" && s.id === groupId);\n if (start === -1) return null;\n let depth = 0;\n for (let i = start; i < statements.length; i++) {\n const s = statements[i]!;\n if (s.kind === \"subgraph\") depth++;\n else if (s.kind === \"end\") {\n depth--;\n if (depth === 0) return { start, end: i };\n }\n }\n return { start, end: statements.length };\n}\n\n/** Appends a statement at the top level, before trailing classDef/style blocks if present. */\nfunction appendAtEnd(statements: FlowStatement[], stmt: FlowStatement): void {\n statements.push(stmt);\n}\n\nfunction insertIntoGroup(\n statements: FlowStatement[],\n stmt: FlowStatement,\n groupId: string | undefined,\n indent: string,\n): void {\n insertManyIntoGroup(statements, [stmt], groupId, indent);\n}\n\nfunction insertManyIntoGroup(\n statements: FlowStatement[],\n block: FlowStatement[],\n groupId: string | undefined,\n indent: string,\n): void {\n const range = groupId ? groupRange(statements, groupId) : null;\n if (!range) {\n statements.push(...block);\n return;\n }\n const open = statements[range.start] as SubgraphStmt;\n const inner = open.indent + indent;\n for (const s of block)\n if (\"indent\" in s)\n (s as { indent: string }).indent =\n inner + (s as { indent: string }).indent.slice(indent.length);\n statements.splice(range.end, 0, ...block);\n}\n\ninterface RefLocation {\n stmt: ChainStmt;\n ref: NodeRef;\n}\n\nfunction declaringRef(\n statements: FlowStatement[],\n id: string,\n prop: \"label\" | \"shape\",\n): RefLocation | null {\n for (const s of statements) {\n if (s.kind !== \"chain\") continue;\n for (const g of s.chain.groups) {\n for (const r of g) {\n if (r.id === id && r[prop] !== undefined) return { stmt: s, ref: r };\n }\n }\n }\n return null;\n}\n\nfunction firstRef(statements: FlowStatement[], id: string): RefLocation | null {\n for (const s of statements) {\n if (s.kind !== \"chain\") continue;\n for (const g of s.chain.groups) for (const r of g) if (r.id === id) return { stmt: s, ref: r };\n }\n return null;\n}\n\nfunction edgeOrdinalsTouching(edges: GraphEdge[], predicate: (e: GraphEdge) => boolean): number[] {\n const out: number[] = [];\n edges.forEach((e, i) => {\n if (predicate(e)) out.push(i);\n });\n return out;\n}\n\n/** Re-indexes `linkStyle` statements after edges were removed. */\nfunction adjustLinkStyles(statements: FlowStatement[], removedOrdinals: number[]): void {\n if (!removedOrdinals.length) return;\n const removed = new Set(removedOrdinals);\n filterInPlace(statements, (s) => {\n if (s.kind !== \"linkStyle\" || s.targets === \"default\") return true;\n const next = s.targets\n .filter((t) => !removed.has(t))\n .map((t) => t - removedOrdinals.filter((r) => r < t).length);\n if (next.length !== s.targets.length || next.some((t, i) => t !== s.targets[i])) {\n s.targets = next;\n s.dirty = true;\n }\n return next.length > 0;\n });\n}\n\nfunction setLinkStyleFor(\n statements: FlowStatement[],\n ordinal: number,\n styles: string[],\n indent: string,\n): void {\n if (ordinal < 0) return;\n // Remove the ordinal from existing statements, then add a dedicated one.\n filterInPlace(statements, (s) => {\n if (s.kind !== \"linkStyle\" || s.targets === \"default\") return true;\n if (!s.targets.includes(ordinal)) return true;\n s.targets = s.targets.filter((t) => t !== ordinal);\n s.dirty = true;\n return s.targets.length > 0;\n });\n if (styles.length)\n statements.push({\n kind: \"linkStyle\",\n raw: \"\",\n indent,\n targets: [ordinal],\n styles: [...styles],\n dirty: true,\n });\n}\n\ninterface EdgeLocation {\n stmt: ChainStmt;\n linkIndex: number;\n source: string;\n target: string;\n}\n\n/**\n * Finds the chain statement and link index that produced a graph edge, by\n * replaying the edge ordinal assignment of {@link buildGraph}.\n */\nfunction locateEdge(\n statements: FlowStatement[],\n edges: GraphEdge[],\n edgeId: string,\n): EdgeLocation | null {\n const target = edges.find((e) => e.id === edgeId);\n if (!target) return null;\n const ordinal = edges.indexOf(target);\n let n = 0;\n for (const s of statements) {\n if (s.kind !== \"chain\") continue;\n const { groups, links } = s.chain;\n if (\n groups.length === 1 &&\n groups[0]!.length === 1 &&\n links.length === 0 &&\n isEdgeDataStatement(groups[0]![0]!)\n )\n continue;\n for (let i = 0; i < links.length; i++) {\n for (const from of groups[i]!) {\n for (const to of groups[i + 1]!) {\n if (n === ordinal) return { stmt: s, linkIndex: i, source: from.id, target: to.id };\n n++;\n }\n }\n }\n }\n return null;\n}\n\nfunction isEdgeDataStatement(ref: NodeRef): boolean {\n return (\n ref.form === \"data\" &&\n !!ref.data &&\n !ref.shape &&\n ref.label === undefined &&\n (\"animate\" in ref.data || \"animation\" in ref.data)\n );\n}\n\n/**\n * Rewrites a chain so that the given link/pair lives in its own two-node\n * statement, returning that statement. Other pairs and declarations are kept.\n */\nfunction isolateEdge(\n statements: FlowStatement[],\n stmt: ChainStmt,\n linkIndex: number,\n source: string,\n target: string,\n indent: string,\n): ChainStmt {\n const { groups, links } = stmt.chain;\n const simple = groups.length === 2 && groups[0]!.length === 1 && groups[1]!.length === 1;\n if (simple) return stmt;\n const expanded = expandChain(stmt.chain);\n const idx = statements.indexOf(stmt);\n const out: ChainStmt[] = expanded.map((chain) => ({\n kind: \"chain\",\n raw: \"\",\n indent: stmt.indent || indent,\n chain,\n dirty: true,\n }));\n statements.splice(idx, 1, ...out);\n const found = out.find(\n (s) =>\n s.chain.links.length === 1 &&\n s.chain.groups[0]![0]!.id === source &&\n s.chain.groups[1]![0]!.id === target &&\n sameLink(s.chain.links[0]!, links[linkIndex]!),\n );\n return found ?? out[0]!;\n}\n\nfunction sameLink(a: LinkRef, b: LinkRef): boolean {\n return (\n a.pattern === b.pattern &&\n a.arrowStart === b.arrowStart &&\n a.arrowEnd === b.arrowEnd &&\n a.label === b.label &&\n a.id === b.id &&\n a.length === b.length\n );\n}\n\n/**\n * Expands `A & B --> C --> D` into one two-node chain per edge, keeping\n * every node declaration on its first occurrence.\n */\nfunction expandChain(chain: Chain): Chain[] {\n const out: Chain[] = [];\n const declared = new Set<string>();\n const refFor = (r: NodeRef): NodeRef => {\n if (declared.has(r.id)) return { id: r.id, classes: [] };\n declared.add(r.id);\n return { ...r, classes: [...r.classes] };\n };\n chain.links.forEach((link, i) => {\n for (const from of chain.groups[i]!) {\n for (const to of chain.groups[i + 1]!) {\n out.push({ groups: [[refFor(from)], [refFor(to)]], links: [{ ...link }] });\n }\n }\n });\n if (!chain.links.length) {\n for (const ref of chain.groups[0]!) out.push({ groups: [[refFor(ref)]], links: [] });\n }\n return out;\n}\n\nfunction removeLinkFromChain(\n statements: FlowStatement[],\n stmt: ChainStmt,\n linkIndex: number,\n source: string,\n target: string,\n indent: string,\n): void {\n const isolated = isolateEdge(statements, stmt, linkIndex, source, target, indent);\n const idx = statements.indexOf(isolated);\n if (idx === -1) return;\n const [from, to] = [isolated.chain.groups[0]![0]!, isolated.chain.groups[1]![0]!];\n const keep: ChainStmt[] = [];\n // Keep declarations (or bare mentions of otherwise-unmentioned nodes) that would be lost.\n for (const ref of [from, to]) {\n const declares =\n ref.label !== undefined ||\n ref.shape ||\n ref.classes.length ||\n (ref.data && Object.keys(ref.data).length);\n const mentionedElsewhere = statements.some(\n (s) =>\n s !== isolated &&\n s.kind === \"chain\" &&\n s.chain.groups.some((g) => g.some((r) => r.id === ref.id)),\n );\n if (declares || !mentionedElsewhere) {\n keep.push({\n kind: \"chain\",\n raw: \"\",\n indent: isolated.indent || indent,\n chain: { groups: [[ref]], links: [] },\n dirty: true,\n });\n }\n }\n statements.splice(idx, 1, ...keep);\n}\n\n/** Removes single bare-id statements for nodes that are mentioned elsewhere. */\nfunction dropRedundantBareMentions(statements: FlowStatement[]): void {\n const mentions = new Map<string, number>();\n for (const s of statements) {\n if (s.kind !== \"chain\") continue;\n for (const g of s.chain.groups)\n for (const r of g) mentions.set(r.id, (mentions.get(r.id) ?? 0) + 1);\n }\n filterInPlace(statements, (s) => {\n if (s.kind !== \"chain\" || !s.dirty || s.chain.links.length || s.chain.groups[0]!.length !== 1)\n return true;\n const ref = s.chain.groups[0]![0]!;\n const bare =\n ref.label === undefined &&\n !ref.shape &&\n !ref.classes.length &&\n !(ref.data && Object.keys(ref.data).length);\n if (!bare) return true;\n if ((mentions.get(ref.id) ?? 0) > 1) {\n mentions.set(ref.id, mentions.get(ref.id)! - 1);\n return false;\n }\n return true;\n });\n}\n\nfunction removeNodesFromStatements(statements: FlowStatement[], ids: Set<string>): void {\n for (let i = 0; i < statements.length; i++) {\n const s = statements[i]!;\n if (s.kind !== \"chain\") continue;\n const mentions = s.chain.groups.some((g) => g.some((r) => ids.has(r.id)));\n if (!mentions) continue;\n const pieces = splitChainWithout(s.chain, ids);\n const replacement: ChainStmt[] = pieces.map((chain) => ({\n kind: \"chain\",\n raw: \"\",\n indent: s.indent,\n chain,\n dirty: true,\n }));\n statements.splice(i, 1, ...replacement);\n i += replacement.length - 1;\n }\n}\n\n/** Removes nodes from a chain, splitting it where a group becomes empty. */\nfunction splitChainWithout(chain: Chain, ids: Set<string>): Chain[] {\n const out: Chain[] = [];\n let cur: Chain = { groups: [], links: [] };\n for (let i = 0; i < chain.groups.length; i++) {\n const group = chain.groups[i]!.filter((r) => !ids.has(r.id));\n if (!group.length) {\n if (cur.groups.length) out.push(cur);\n cur = { groups: [], links: [] };\n continue;\n }\n if (cur.groups.length) cur.links.push({ ...chain.links[i - 1]! });\n cur.groups.push(group);\n }\n if (cur.groups.length) out.push(cur);\n return out;\n}\n\n/**\n * Removes several edges. Edges are located by their ordinal in the parsed\n * graph, and removing one rewrites (and may split) chain statements, so the\n * ordinals of the others are only valid against the document they came from.\n * Removing them one at a time, last first, means each removal leaves the\n * edges still to remove untouched; each is re-found in the updated document\n * by its endpoints and its index among edges between the same pair.\n */\nfunction removeEdgesOneByOne(doc: Doc, ids: string[]): Doc {\n const wanted = new Set(ids);\n const targets = doc.graph.edges\n .map((edge, ordinal) => ({ edge, ordinal }))\n .filter(({ edge }) => wanted.has(edge.id))\n .map(({ edge, ordinal }) => ({\n ordinal,\n source: edge.source,\n target: edge.target,\n pairIndex: doc.graph.edges\n .slice(0, ordinal)\n .filter((e) => e.source === edge.source && e.target === edge.target).length,\n }))\n .sort((a, b) => b.ordinal - a.ordinal);\n let current = doc;\n for (const t of targets) {\n const match = current.graph.edges.filter((e) => e.source === t.source && e.target === t.target)[\n t.pairIndex\n ];\n if (match) current = applyFlowchartEdit(current, { type: \"removeEdges\", ids: [match.id] });\n }\n return current;\n}\n\n/** Node data as `@{ … }` raw values: strings quoted, numbers and booleans bare. */\nfunction encodeData(data: Record<string, unknown> | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(data ?? {})) {\n if (v === undefined || v === null) continue;\n out[k] = typeof v === \"string\" ? JSON.stringify(v) : String(v);\n }\n return out;\n}\n\n/** Image-node keys Mermaid reads (`img` makes a node an image whatever its shape). */\nconst IMAGE_KEYS = [\"img\", \"pos\", \"w\", \"h\", \"constraint\"];\n\n/**\n * Keeps a node's data consistent with its shape: an image node always has\n * `img` (empty until one is chosen) so it stays an image; any other shape\n * drops the image keys, which would otherwise turn it back into one.\n */\nfunction shapeDataFor(shape: string, data: Record<string, string>): Record<string, string> {\n const out = { ...data };\n if (shape === \"image\") {\n if (!(\"img\" in out)) out.img = '\"\"';\n } else {\n for (const key of IMAGE_KEYS) delete out[key];\n }\n return out;\n}\n","import type { DiagramAdapter } from \"../types.js\";\nimport { applyFlowchartEdit } from \"./edit.js\";\nimport { parseFlowchart, type FlowchartBody } from \"./parse.js\";\nimport { serializeFlowchart } from \"./serialize.js\";\n\nexport const flowchartAdapter: DiagramAdapter<FlowchartBody> = {\n family: \"flowchart\",\n tier: \"editable\",\n parse: parseFlowchart,\n serialize: serializeFlowchart,\n apply: applyFlowchartEdit,\n};\n\nexport type { FlowchartBody, FlowchartDocument } from \"./parse.js\";\nexport { parseFlowchartSource } from \"./edit.js\";\nexport { FLOWCHART_SHAPES, resolveShape, canonicalShape, type ShapeDef } from \"./shapes.js\";\nexport { parseLink, formatLink, quoteLabelIfNeeded, type LinkSpec } from \"./edges.js\";\nexport {\n parseChain,\n parseStatement,\n formatChain,\n formatNode,\n type FlowStatement,\n type Chain,\n type NodeRef,\n type LinkRef,\n} from \"./statements.js\";\n","import type {\n AdapterParseContext,\n ArrowHead,\n Diagnostic,\n DiagramAdapter,\n DiagramFamily,\n DiagramGraph,\n EditOp,\n GraphEdge,\n GraphGroup,\n GraphNode,\n MermaidDocument,\n Point,\n} from \"../types.js\";\nimport { assembleDocument } from \"../flowchart/serialize.js\";\nimport { splitSource } from \"../source/lines.js\";\nimport {\n defaultCarrierFor,\n emptyMeta,\n extractMetaFromBody,\n extractMetaFromFrontmatter,\n mergeMeta,\n} from \"../source/metadata.js\";\n\n/**\n * A small engine for \"one statement per line\" Mermaid grammars\n * (stateDiagram, classDiagram, erDiagram). A grammar classifies each logical\n * line into a typed statement; the engine builds the graph, applies edits and\n * re-emits untouched statements verbatim.\n *\n * @module\n */\n\nexport interface NodeDecl {\n id: string;\n label?: string;\n shape?: string;\n classes: string[];\n /** Family-specific data (members, attributes, descriptions…). */\n data?: Record<string, unknown>;\n}\n\nexport type LineStatement =\n | { kind: \"raw\"; raw: string; indent: string }\n | {\n kind: \"node\";\n raw: string;\n indent: string;\n decl: NodeDecl;\n /** Multi-line body `{ … }` kept verbatim. */ body?: string[];\n dirty?: boolean;\n }\n | {\n kind: \"edge\";\n raw: string;\n indent: string;\n source: NodeDecl;\n target: NodeDecl;\n label?: string;\n arrowStart: ArrowHead;\n arrowEnd: ArrowHead;\n pattern: GraphEdge[\"pattern\"];\n /** Family-specific data (cardinalities…). */\n data?: Record<string, unknown>;\n dirty?: boolean;\n }\n | { kind: \"groupOpen\"; raw: string; indent: string; id: string; label?: string; dirty?: boolean }\n | { kind: \"groupClose\"; raw: string; indent: string }\n | { kind: \"direction\"; raw: string; indent: string; direction: string; dirty?: boolean }\n | {\n kind: \"classDef\";\n raw: string;\n indent: string;\n names: string[];\n styles: string[];\n dirty?: boolean;\n }\n | {\n kind: \"class\";\n raw: string;\n indent: string;\n ids: string[];\n className: string;\n dirty?: boolean;\n }\n | { kind: \"style\"; raw: string; indent: string; id: string; styles: string[]; dirty?: boolean };\n\nexport interface EdgeSpec {\n label?: string;\n arrowStart: ArrowHead;\n arrowEnd: ArrowHead;\n pattern: GraphEdge[\"pattern\"];\n data?: Record<string, unknown>;\n}\n\nexport interface LineGrammar {\n family: DiagramFamily;\n defaultShape: string;\n /** Groups logical statements from physical lines (brace blocks, `end note`, …). */\n joinLines(lines: string[]): string[];\n parseLine(line: string): LineStatement;\n formatStatement(stmt: LineStatement): string;\n /** Builds a node statement for a new node. */\n nodeStatement(decl: NodeDecl, indent: string): LineStatement;\n /** Builds an edge statement. */\n edgeStatement(source: string, target: string, spec: EdgeSpec, indent: string): LineStatement;\n /** Builds the open/close statements of a group. */\n groupStatements(\n id: string,\n label: string | undefined,\n indent: string,\n ): { open: LineStatement; close: LineStatement };\n /** Reads the header direction. */\n headerDirection(header: string, statements: LineStatement[]): string;\n /** Optional: pseudo-node ids such as `[*]` that need special graph handling. */\n resolveEndpoint?(\n id: string,\n groupStack: string[],\n role: \"source\" | \"target\",\n ): { id: string; shape: string; label: string; synthetic: true } | null;\n /** Default edge spec when the UI connects two nodes. */\n defaultEdge: EdgeSpec;\n /** Whether `setDirection` writes a `direction` statement (true) or the header. */\n directionAsStatement: boolean;\n /** False when the family has no grouping construct (ER). Group ops become no-ops. */\n supportsGroups?: boolean;\n}\n\nexport interface LineBody {\n statements: LineStatement[];\n}\n\nexport type LineDocument = MermaidDocument<LineBody>;\n\n// ---------------------------------------------------------------------------\n// Parsing\n// ---------------------------------------------------------------------------\n\nexport function buildLineGraph(\n grammar: LineGrammar,\n statements: LineStatement[],\n direction: string,\n title?: string,\n): { graph: DiagramGraph; diagnostics: Diagnostic[] } {\n const nodes = new Map<string, GraphNode>();\n const groups = new Map<string, GraphGroup>();\n const edges: GraphEdge[] = [];\n const classDefs: Record<string, string[]> = {};\n const diagnostics: Diagnostic[] = [];\n const stack: string[] = [];\n const classAssignments: { ids: string[]; className: string }[] = [];\n const styleAssignments: { id: string; styles: string[] }[] = [];\n let ordinal = 0;\n\n const touch = (decl: NodeDecl, role: \"source\" | \"target\" | \"decl\"): string => {\n if (role !== \"decl\" && grammar.resolveEndpoint) {\n const resolved = grammar.resolveEndpoint(decl.id, stack, role);\n if (resolved) {\n if (!nodes.has(resolved.id)) {\n nodes.set(resolved.id, {\n id: resolved.id,\n label: resolved.label,\n shape: resolved.shape,\n parentId: stack[stack.length - 1],\n classes: [],\n styles: [],\n data: { synthetic: true },\n });\n }\n return resolved.id;\n }\n }\n let node = nodes.get(decl.id);\n if (!node) {\n node = { id: decl.id, label: decl.id, shape: grammar.defaultShape, classes: [], styles: [] };\n nodes.set(decl.id, node);\n }\n // Mermaid: a mention inside a group claims the node, whatever the order;\n // root-level mentions never un-claim it.\n const parent = stack[stack.length - 1];\n if (parent) node.parentId = parent;\n if (decl.label !== undefined) node.label = decl.label;\n if (decl.shape) node.shape = decl.shape;\n for (const cls of decl.classes) if (!node.classes.includes(cls)) node.classes.push(cls);\n if (decl.data) node.data = mergeData(node.data, decl.data);\n return node.id;\n };\n\n for (const stmt of statements) {\n switch (stmt.kind) {\n case \"groupOpen\": {\n const parent = stack[stack.length - 1];\n // A group may have been referenced as a node earlier (state X then state X { }).\n const existing = nodes.get(stmt.id);\n if (existing) nodes.delete(stmt.id);\n groups.set(stmt.id, {\n id: stmt.id,\n label: stmt.label ?? existing?.label ?? stmt.id,\n parentId: parent,\n classes: existing?.classes ?? [],\n styles: existing?.styles ?? [],\n data: existing?.data,\n });\n stack.push(stmt.id);\n break;\n }\n case \"groupClose\":\n if (!stack.length)\n diagnostics.push({\n severity: \"warning\",\n message: \"Unbalanced closing brace\",\n source: \"pixerate\",\n });\n stack.pop();\n break;\n case \"direction\": {\n const current = stack[stack.length - 1];\n if (current) groups.get(current)!.direction = stmt.direction;\n break;\n }\n case \"node\":\n touch(stmt.decl, \"decl\");\n break;\n case \"edge\": {\n const s = touch(stmt.source, \"source\");\n const t = touch(stmt.target, \"target\");\n edges.push({\n id: `L_${s}_${t}_${ordinal}`,\n source: s,\n target: t,\n label: stmt.label,\n pattern: stmt.pattern,\n arrowStart: stmt.arrowStart,\n arrowEnd: stmt.arrowEnd,\n length: 1,\n classes: [],\n styles: [],\n userDefinedId: false,\n data: stmt.data,\n });\n ordinal++;\n break;\n }\n case \"classDef\":\n for (const name of stmt.names) classDefs[name] = [...stmt.styles];\n break;\n case \"class\":\n classAssignments.push({ ids: stmt.ids, className: stmt.className });\n break;\n case \"style\":\n styleAssignments.push({ id: stmt.id, styles: stmt.styles });\n break;\n default:\n break;\n }\n }\n if (stack.length)\n diagnostics.push({\n severity: \"warning\",\n message: `${stack.length} block(s) not closed`,\n source: \"pixerate\",\n });\n\n // Edges may reference a group id (e.g. transitions to a composite state).\n for (const edge of edges) {\n for (const end of [\"source\", \"target\"] as const) {\n const id = edge[end];\n if (groups.has(id) && nodes.has(id)) nodes.delete(id);\n }\n }\n for (const { ids, className } of classAssignments) {\n for (const id of ids) {\n const target = nodes.get(id) ?? groups.get(id);\n if (target && !target.classes.includes(className)) target.classes.push(className);\n }\n }\n for (const { id, styles } of styleAssignments) {\n const target = nodes.get(id) ?? groups.get(id);\n if (target) target.styles.push(...styles);\n }\n\n return {\n graph: {\n direction,\n nodes: [...nodes.values()],\n edges,\n groups: [...groups.values()],\n classDefs,\n title,\n },\n diagnostics,\n };\n}\n\nfunction mergeData(\n a: Record<string, unknown> | undefined,\n b: Record<string, unknown>,\n): Record<string, unknown> {\n const out: Record<string, unknown> = { ...(a ?? {}) };\n for (const [k, v] of Object.entries(b)) {\n if (Array.isArray(v) && Array.isArray(out[k])) out[k] = [...(out[k] as unknown[]), ...v];\n else out[k] = v;\n }\n return out;\n}\n\nexport function parseLineDocument(\n grammar: LineGrammar,\n source: string,\n ctx: AdapterParseContext,\n): LineDocument {\n const statements = grammar.joinLines(ctx.bodyLines).map((line) => grammar.parseLine(line));\n const direction = grammar.headerDirection(ctx.header, statements);\n const title =\n typeof ctx.preamble.frontmatter?.title === \"string\"\n ? ctx.preamble.frontmatter.title\n : undefined;\n const { graph, diagnostics } = buildLineGraph(grammar, statements, direction, title);\n return {\n family: grammar.family,\n tier: \"editable\",\n source,\n preamble: ctx.preamble,\n header: ctx.header,\n trailing: ctx.trailing,\n eol: ctx.eol,\n graph,\n meta: ctx.meta,\n metaCarrier: ctx.metaCarrier,\n body: { statements },\n diagnostics,\n dirty: false,\n };\n}\n\nexport function serializeLineDocument(grammar: LineGrammar, doc: LineDocument): string {\n const lines: string[] = [];\n for (const stmt of doc.body.statements) {\n if (stmt.kind === \"raw\") {\n lines.push(stmt.raw);\n continue;\n }\n if (!(\"dirty\" in stmt) || !stmt.dirty) {\n lines.push(stmt.raw);\n if (stmt.kind === \"node\" && stmt.body) lines.push(...stmt.body);\n continue;\n }\n lines.push(grammar.formatStatement(stmt));\n if (stmt.kind === \"node\" && stmt.body) lines.push(...stmt.body);\n }\n const indent = detectIndent(doc.body.statements);\n return assembleDocument(doc, lines, indent);\n}\n\nexport function detectIndent(statements: LineStatement[]): string {\n for (const s of statements) if (s.indent) return s.indent;\n return \" \";\n}\n\nfunction parseFull(\n grammar: LineGrammar,\n source: string,\n carrier?: LineDocument[\"metaCarrier\"],\n): LineDocument {\n const split = splitSource(source);\n const fromBody = extractMetaFromBody(split.bodyLines);\n const fromFm = extractMetaFromFrontmatter(split.preamble);\n let meta = emptyMeta();\n if (fromFm) meta = mergeMeta(meta, fromFm);\n if (fromBody.meta) meta = mergeMeta(meta, fromBody.meta);\n return parseLineDocument(grammar, source, {\n source,\n eol: split.eol,\n preamble: split.preamble,\n header: split.header,\n bodyLines: fromBody.bodyLines,\n trailing: split.trailing,\n meta,\n metaCarrier:\n carrier ?? (fromFm && !fromBody.meta ? \"frontmatter\" : defaultCarrierFor(grammar.family)),\n family: grammar.family,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Editing\n// ---------------------------------------------------------------------------\n\nexport function applyLineEdit(grammar: LineGrammar, doc: LineDocument, op: EditOp): LineDocument {\n const statements = doc.body.statements.map((s) => ({\n ...s,\n ...(\"decl\" in s\n ? {\n decl: {\n ...s.decl,\n classes: [...s.decl.classes],\n data: s.decl.data ? { ...s.decl.data } : undefined,\n },\n }\n : {}),\n ...(\"source\" in s\n ? {\n source: { ...s.source, classes: [...s.source.classes] },\n target: { ...s.target, classes: [...s.target.classes] },\n }\n : {}),\n })) as LineStatement[];\n const work: LineDocument = {\n ...doc,\n body: { statements },\n meta: { ...doc.meta, layout: { ...doc.meta.layout }, sizes: { ...doc.meta.sizes } },\n };\n const indent = detectIndent(statements);\n const reparse = (structural: boolean): LineDocument => {\n const text = serializeLineDocument(grammar, work);\n const next = parseFull(grammar, text, work.metaCarrier);\n next.dirty = doc.dirty || structural;\n return next;\n };\n\n switch (op.type) {\n case \"moveNodes\":\n for (const { id, position } of op.moves) work.meta.layout![id] = position as Point;\n return reparse(false);\n case \"resizeNode\":\n if (op.size) work.meta.sizes![op.id] = op.size;\n else delete work.meta.sizes![op.id];\n return reparse(false);\n case \"setViewport\":\n work.meta.viewport = op.viewport;\n return reparse(false);\n case \"setMetaExt\":\n work.meta.ext = { ...(work.meta.ext ?? {}), [op.key]: op.value };\n if (op.value === undefined) delete work.meta.ext[op.key];\n return reparse(false);\n case \"replaceSource\":\n return parseFull(grammar, op.source, work.metaCarrier);\n case \"setTitle\": {\n const lines = [...work.preamble.lines];\n work.preamble = { ...work.preamble, lines: setTitle(lines, op.title) };\n return reparse(true);\n }\n case \"setDirection\": {\n if (grammar.directionAsStatement) {\n const idx = statements.findIndex(\n (s, i) => s.kind === \"direction\" && depthAt(statements, i) === 0,\n );\n if (idx !== -1) {\n const s = statements[idx] as Extract<LineStatement, { kind: \"direction\" }>;\n s.direction = op.direction;\n s.dirty = true;\n } else {\n statements.unshift({\n kind: \"direction\",\n raw: \"\",\n indent,\n direction: op.direction,\n dirty: true,\n });\n }\n } else {\n work.header = work.header.replace(/\\s+(TB|TD|BT|LR|RL)\\s*$/i, \"\") + ` ${op.direction}`;\n }\n return reparse(true);\n }\n case \"addNode\": {\n const decl: NodeDecl = {\n id: op.node.id,\n label: op.node.label,\n shape: op.node.shape,\n classes: [...(op.node.classes ?? [])],\n data: op.node.data,\n };\n insertIntoGroup(statements, [grammar.nodeStatement(decl, indent)], op.node.parentId, indent);\n if (op.position) work.meta.layout![op.node.id] = op.position;\n return reparse(true);\n }\n case \"removeNodes\": {\n const ids = new Set(op.ids);\n filterInPlace(statements, (s) => {\n if (s.kind === \"node\") return !ids.has(s.decl.id);\n if (s.kind === \"edge\") return !(ids.has(s.source.id) || ids.has(s.target.id));\n if (s.kind === \"style\") return !ids.has(s.id);\n if (s.kind === \"class\") {\n s.ids = s.ids.filter((id) => !ids.has(id));\n s.dirty = true;\n return s.ids.length > 0;\n }\n return true;\n });\n // Remove groups whose id was deleted (keep their content).\n for (const id of ids) {\n const range = groupRange(statements, id);\n if (range) {\n statements.splice(range.end, 1);\n statements.splice(range.start, 1);\n }\n delete work.meta.layout![id];\n delete work.meta.sizes![id];\n }\n return reparse(true);\n }\n case \"renameNode\":\n case \"setNodeShape\":\n case \"setNodeClasses\":\n case \"setNodeData\": {\n const id = op.id;\n let decl = findDecl(statements, id);\n if (!decl) {\n // Create a declaration statement right after the first mention.\n const node = doc.graph.nodes.find((n) => n.id === id);\n const stmt = grammar.nodeStatement(\n {\n id,\n label: node?.label !== id ? node?.label : undefined,\n shape: node?.shape !== grammar.defaultShape ? node?.shape : undefined,\n classes: [],\n },\n indent,\n );\n const first = statements.findIndex(\n (s) => s.kind === \"edge\" && (s.source.id === id || s.target.id === id),\n );\n statements.splice(first === -1 ? statements.length : first, 0, stmt);\n decl = findDecl(statements, id)!;\n }\n const target = decl.stmt;\n if (op.type === \"renameNode\") decl.decl.label = op.label;\n if (op.type === \"setNodeShape\") decl.decl.shape = op.shape;\n if (op.type === \"setNodeClasses\") {\n decl.decl.classes = [...op.classes];\n filterInPlace(statements, (s) => {\n if (s.kind !== \"class\" || !s.ids.includes(id)) return true;\n s.ids = s.ids.filter((x) => x !== id);\n s.dirty = true;\n return s.ids.length > 0;\n });\n }\n if (op.type === \"setNodeData\") {\n decl.decl.data = { ...(decl.decl.data ?? {}), ...op.data };\n // Body-bearing data (class members, ER attributes) lives in the `{ … }`\n // block: regenerate it from the grammar so the text follows the data.\n if (target.kind === \"node\" && (\"members\" in op.data || \"attributes\" in op.data)) {\n const fresh = grammar.nodeStatement(decl.decl, target.indent);\n target.body = fresh.kind === \"node\" ? fresh.body : undefined;\n }\n }\n (target as { dirty?: boolean }).dirty = true;\n return reparse(true);\n }\n case \"setNodeStyles\": {\n filterInPlace(statements, (s) => !(s.kind === \"style\" && s.id === op.id));\n if (op.styles.length)\n statements.push({\n kind: \"style\",\n raw: \"\",\n indent,\n id: op.id,\n styles: [...op.styles],\n dirty: true,\n });\n return reparse(true);\n }\n case \"addEdge\": {\n const spec: EdgeSpec = {\n ...grammar.defaultEdge,\n ...(op.edge.pattern ? { pattern: op.edge.pattern } : {}),\n ...(op.edge.arrowStart ? { arrowStart: op.edge.arrowStart } : {}),\n ...(op.edge.arrowEnd ? { arrowEnd: op.edge.arrowEnd } : {}),\n label: op.edge.label,\n data: {\n ...(op.edge.data ?? {}),\n synthetic: {\n source: isSyntheticEndpoint(doc, op.edge.source),\n target: isSyntheticEndpoint(doc, op.edge.target),\n },\n },\n };\n const stmt = grammar.edgeStatement(op.edge.source, op.edge.target, spec, indent);\n // Place inside the common parent group when both ends share one.\n const sp = parentOf(doc, op.edge.source);\n const tp = parentOf(doc, op.edge.target);\n insertIntoGroup(statements, [stmt], sp && sp === tp ? sp : undefined, indent);\n return reparse(true);\n }\n case \"removeEdges\": {\n const targets = new Set(op.ids.map((id) => edgeOrdinal(doc, id)).filter((n) => n >= 0));\n let ordinal = 0;\n filterInPlace(statements, (s) => {\n if (s.kind !== \"edge\") return true;\n const keep = !targets.has(ordinal);\n ordinal++;\n return keep;\n });\n return reparse(true);\n }\n case \"setEdgeLabel\":\n case \"setEdgeStyle\":\n case \"reconnectEdge\": {\n const stmt = edgeStatementFor(statements, doc, op.id);\n if (!stmt) return doc;\n if (op.type === \"setEdgeLabel\") stmt.label = op.label || undefined;\n if (op.type === \"setEdgeStyle\") {\n if (op.pattern) stmt.pattern = op.pattern;\n if (op.arrowStart) stmt.arrowStart = op.arrowStart;\n if (op.arrowEnd) stmt.arrowEnd = op.arrowEnd;\n }\n if (op.type === \"reconnectEdge\") {\n stmt.source = { id: op.source, classes: [] };\n stmt.target = { id: op.target, classes: [] };\n }\n stmt.dirty = true;\n return reparse(true);\n }\n case \"groupNodes\": {\n if (grammar.supportsGroups === false) return doc;\n const { open, close } = grammar.groupStatements(op.groupId, op.label, indent);\n const moved: LineStatement[] = [];\n // Move node declarations (and edges fully inside the set) into the group.\n const set = new Set(op.nodeIds);\n filterInPlace(statements, (s) => {\n if (s.kind === \"node\" && set.has(s.decl.id)) {\n moved.push(reindent(s, indent + indent));\n return false;\n }\n if (s.kind === \"edge\" && set.has(s.source.id) && set.has(s.target.id)) {\n moved.push(reindent(s, indent + indent));\n return false;\n }\n return true;\n });\n for (const id of op.nodeIds) {\n if (!moved.some((s) => s.kind === \"node\" && s.decl.id === id)) {\n moved.push(grammar.nodeStatement({ id, classes: [] }, indent + indent));\n }\n }\n insertIntoGroup(statements, [open, ...moved, close], op.parentId, indent);\n return reparse(true);\n }\n case \"ungroup\": {\n const range = groupRange(statements, op.groupId);\n if (!range) return doc;\n const inner = statements\n .slice(range.start + 1, range.end)\n .map((s) => reindent(s, (statements[range.start] as { indent: string }).indent));\n statements.splice(\n range.start,\n range.end - range.start + 1,\n ...inner.filter((s) => s.kind !== \"direction\"),\n );\n delete work.meta.layout![op.groupId];\n return reparse(true);\n }\n case \"renameGroup\": {\n const range = groupRange(statements, op.id);\n if (!range) return doc;\n const open = statements[range.start] as Extract<LineStatement, { kind: \"groupOpen\" }>;\n open.label = op.label;\n open.dirty = true;\n return reparse(true);\n }\n case \"setGroupDirection\": {\n const range = groupRange(statements, op.id);\n if (!range) return doc;\n const idx = statements.findIndex(\n (s, i) =>\n i > range.start &&\n i < range.end &&\n s.kind === \"direction\" &&\n depthAt(statements, i) === depthAt(statements, range.start) + 1,\n );\n if (op.direction) {\n if (idx !== -1) {\n const s = statements[idx] as Extract<LineStatement, { kind: \"direction\" }>;\n s.direction = op.direction;\n s.dirty = true;\n } else {\n const inner = (statements[range.start] as { indent: string }).indent + indent;\n statements.splice(range.start + 1, 0, {\n kind: \"direction\",\n raw: \"\",\n indent: inner,\n direction: op.direction,\n dirty: true,\n });\n }\n } else if (idx !== -1) statements.splice(idx, 1);\n return reparse(true);\n }\n case \"setNodeParent\": {\n for (const id of op.ids) {\n const found = findDecl(statements, id);\n let stmt: LineStatement;\n if (found) {\n statements.splice(statements.indexOf(found.stmt), 1);\n stmt = found.stmt;\n } else {\n stmt = grammar.nodeStatement({ id, classes: [] }, indent);\n }\n insertIntoGroup(statements, [stmt], op.parentId, indent);\n }\n return reparse(true);\n }\n case \"setClassDef\": {\n let found = false;\n for (const s of statements) {\n if (s.kind !== \"classDef\") continue;\n if (s.names.length === 1 && s.names[0] === op.name) {\n found = true;\n if (op.styles) {\n s.styles = [...op.styles];\n s.dirty = true;\n }\n }\n }\n if (!op.styles)\n filterInPlace(\n statements,\n (s) => !(s.kind === \"classDef\" && s.names.length === 1 && s.names[0] === op.name),\n );\n else if (!found)\n statements.push({\n kind: \"classDef\",\n raw: \"\",\n indent,\n names: [op.name],\n styles: [...op.styles],\n dirty: true,\n });\n return reparse(true);\n }\n default:\n return doc;\n }\n}\n\n/**\n * A node is a synthetic endpoint (`[*]`) when the graph says so, or when it is\n * unknown but named like one — the UI may offer \"connect to end\" for a scope\n * that has no end pseudo-state yet.\n */\nfunction isSyntheticEndpoint(doc: LineDocument, id: string): boolean {\n const node = doc.graph.nodes.find((n) => n.id === id);\n if (node) return !!node.data?.synthetic;\n // Unknown id: only `root_start|end` or `<existing group>_start|end` count as `[*]`.\n const m = /^(.+)_(start|end)$/.exec(id);\n if (!m) return false;\n return m[1] === \"root\" || doc.graph.groups.some((g) => g.id === m[1]);\n}\n\nfunction reindent(s: LineStatement, indent: string): LineStatement {\n const next = { ...s, indent } as LineStatement;\n if (s.kind === \"raw\") return s;\n (next as { dirty?: boolean }).dirty = true;\n if (s.kind === \"node\" && s.body) {\n const delta = indent.length - s.indent.length;\n (next as { body?: string[] }).body = s.body.map((l) =>\n delta >= 0\n ? \" \".repeat(delta) + l\n : l.slice(Math.min(-delta, l.length - l.trimStart().length)),\n );\n }\n return next;\n}\n\nfunction findDecl(\n statements: LineStatement[],\n id: string,\n): { stmt: LineStatement; decl: NodeDecl } | null {\n for (const s of statements) {\n if (s.kind === \"node\" && s.decl.id === id) return { stmt: s, decl: s.decl };\n }\n for (const s of statements) {\n if (s.kind === \"edge\") {\n if (\n s.source.id === id &&\n (s.source.label !== undefined || s.source.shape || s.source.classes.length)\n )\n return { stmt: s, decl: s.source };\n if (\n s.target.id === id &&\n (s.target.label !== undefined || s.target.shape || s.target.classes.length)\n )\n return { stmt: s, decl: s.target };\n }\n }\n return null;\n}\n\nfunction parentOf(doc: LineDocument, id: string): string | undefined {\n return (\n doc.graph.nodes.find((n) => n.id === id)?.parentId ??\n doc.graph.groups.find((g) => g.id === id)?.parentId\n );\n}\n\nfunction edgeOrdinal(doc: LineDocument, edgeId: string): number {\n return doc.graph.edges.findIndex((e) => e.id === edgeId);\n}\n\nfunction edgeStatementFor(\n statements: LineStatement[],\n doc: LineDocument,\n edgeId: string,\n): Extract<LineStatement, { kind: \"edge\" }> | null {\n const ordinal = edgeOrdinal(doc, edgeId);\n if (ordinal < 0) return null;\n let n = 0;\n for (const s of statements) {\n if (s.kind !== \"edge\") continue;\n if (n === ordinal) return s;\n n++;\n }\n return null;\n}\n\nfunction depthAt(statements: LineStatement[], index: number): number {\n let depth = 0;\n for (let i = 0; i < index; i++) {\n const s = statements[i]!;\n if (s.kind === \"groupOpen\") depth++;\n else if (s.kind === \"groupClose\") depth = Math.max(0, depth - 1);\n }\n return depth;\n}\n\nfunction groupRange(\n statements: LineStatement[],\n groupId: string,\n): { start: number; end: number } | null {\n const start = statements.findIndex((s) => s.kind === \"groupOpen\" && s.id === groupId);\n if (start === -1) return null;\n let depth = 0;\n for (let i = start; i < statements.length; i++) {\n const s = statements[i]!;\n if (s.kind === \"groupOpen\") depth++;\n else if (s.kind === \"groupClose\") {\n depth--;\n if (depth === 0) return { start, end: i };\n }\n }\n return { start, end: statements.length };\n}\n\nfunction insertIntoGroup(\n statements: LineStatement[],\n block: LineStatement[],\n groupId: string | undefined,\n indent: string,\n): void {\n const range = groupId ? groupRange(statements, groupId) : null;\n if (!range) {\n statements.push(...block);\n return;\n }\n const open = statements[range.start] as { indent: string };\n const inner = open.indent + indent;\n const adjusted = block.map((s) =>\n s.kind === \"raw\" ? s : reindent(s, inner + s.indent.slice(indent.length)),\n );\n statements.splice(range.end, 0, ...adjusted);\n}\n\nfunction filterInPlace<T>(arr: T[], keep: (item: T) => boolean): void {\n let j = 0;\n for (let i = 0; i < arr.length; i++) if (keep(arr[i]!)) arr[j++] = arr[i]!;\n arr.length = j;\n}\n\nfunction setTitle(lines: string[], title: string | undefined): string[] {\n const out = [...lines];\n const hasFm = out[0] !== undefined && /^---\\s*$/.test(out[0]);\n if (!hasFm) return title === undefined ? out : [\"---\", `title: ${title}`, \"---\", ...out];\n const close = out.findIndex((l, i) => i > 0 && /^---\\s*$/.test(l));\n const end = close === -1 ? out.length : close;\n const idx = out.findIndex((l, i) => i > 0 && i < end && /^title\\s*:/.test(l));\n if (title === undefined) {\n if (idx !== -1) out.splice(idx, 1);\n if (out.length >= 2 && /^---\\s*$/.test(out[1]!)) out.splice(0, 2);\n return out;\n }\n if (idx !== -1) out[idx] = `title: ${title}`;\n else out.splice(end, 0, `title: ${title}`);\n return out;\n}\n\n/** Sets or removes the frontmatter `title`. Shared with the passthrough adapter. */\nexport function setFrontmatterTitle(lines: string[], title: string | undefined): string[] {\n return setTitle(lines, title);\n}\n\n/** Creates a full adapter from a grammar. */\nexport function createLineAdapter(grammar: LineGrammar): DiagramAdapter<LineBody> {\n return {\n family: grammar.family,\n tier: \"editable\",\n parse: (source, ctx) => parseLineDocument(grammar, source, ctx),\n serialize: (doc) => serializeLineDocument(grammar, doc),\n apply: (doc, op) => applyLineEdit(grammar, doc, op),\n };\n}\n\n/** Joins lines into logical statements by matching `{ … }` across lines. */\nexport function joinBraceBlocks(\n lines: string[],\n extraBlock?: { open: RegExp; close: RegExp },\n): string[] {\n const out: string[] = [];\n let i = 0;\n while (i < lines.length) {\n const line = lines[i]!;\n if (extraBlock && extraBlock.open.test(line)) {\n let cur = line;\n let j = i + 1;\n while (j < lines.length && !extraBlock.close.test(lines[j]!)) {\n cur += \"\\n\" + lines[j];\n j++;\n }\n if (j < lines.length) {\n cur += \"\\n\" + lines[j];\n j++;\n }\n out.push(cur);\n i = j;\n continue;\n }\n const opens = (line.match(/\\{/g) ?? []).length;\n const closes = (line.match(/\\}/g) ?? []).length;\n if (opens > closes && /\\{\\s*$/.test(line)) {\n // Peek: a block whose content is attribute lines (no nested statements)\n // is kept with its opener as one \"node with body\" statement. The group\n // grammars decide via parseLine; here we just gather until the matching `}`.\n let depth = opens - closes;\n let j = i + 1;\n const body: string[] = [];\n let isSimpleBody = true;\n while (j < lines.length && depth > 0) {\n const l = lines[j]!;\n depth += (l.match(/\\{/g) ?? []).length - (l.match(/\\}/g) ?? []).length;\n if (depth > 0) body.push(l);\n if (\n /-->|<\\|--|\\*--|o--|\\.\\.>|--\\|>|\\|\\|--|\\}o--|\\}\\|--|^\\s*(state|class|namespace|note|direction)\\b/.test(\n l,\n ) &&\n depth > 0\n )\n isSimpleBody = false;\n j++;\n }\n if (isSimpleBody && depth === 0) {\n out.push([line, ...body, lines[j - 1]!].join(\"\\n\"));\n i = j;\n continue;\n }\n }\n out.push(line);\n i++;\n }\n return out;\n}\n","import type {\n AdapterParseContext,\n DiagramAdapter,\n DiagramFamily,\n EditOp,\n MermaidDocument,\n SupportTier,\n} from \"./types.js\";\nimport { assembleDocument } from \"./flowchart/serialize.js\";\nimport { setFrontmatterTitle } from \"./lines-grammar/engine.js\";\n\n/** Body of a render-only document: the raw body lines. */\nexport interface PassthroughBody {\n lines: string[];\n}\n\n/**\n * Adapter for families the diagram module cannot edit on a canvas. The text is preserved\n * verbatim; only `replaceSource`, `setTitle` and metadata edits apply.\n */\nexport function createPassthroughAdapter(\n family: DiagramFamily,\n tier: SupportTier = \"render-only\",\n): DiagramAdapter<PassthroughBody> {\n const adapter: DiagramAdapter<PassthroughBody> = {\n family,\n tier,\n parse(source: string, ctx: AdapterParseContext): MermaidDocument<PassthroughBody> {\n const title =\n typeof ctx.preamble.frontmatter?.title === \"string\"\n ? ctx.preamble.frontmatter.title\n : undefined;\n return {\n family,\n tier,\n source,\n preamble: ctx.preamble,\n header: ctx.header,\n trailing: ctx.trailing,\n eol: ctx.eol,\n graph: { direction: \"TB\", nodes: [], edges: [], groups: [], classDefs: {}, title },\n meta: ctx.meta,\n metaCarrier: ctx.metaCarrier,\n body: { lines: ctx.bodyLines },\n diagnostics: [],\n dirty: false,\n };\n },\n serialize(doc) {\n return assembleDocument(doc, doc.body.lines, \" \");\n },\n apply(doc, op: EditOp) {\n const next: MermaidDocument<PassthroughBody> = { ...doc, meta: { ...doc.meta } };\n switch (op.type) {\n case \"setViewport\":\n next.meta.viewport = op.viewport;\n break;\n case \"setMetaExt\":\n next.meta.ext = { ...(next.meta.ext ?? {}), [op.key]: op.value };\n break;\n case \"moveNodes\":\n next.meta.layout = { ...(next.meta.layout ?? {}) };\n for (const { id, position } of op.moves) next.meta.layout[id] = position;\n break;\n case \"setTitle\":\n next.preamble = {\n ...next.preamble,\n lines: setFrontmatterTitle(next.preamble.lines, op.title),\n };\n next.dirty = true;\n break;\n default:\n return doc;\n }\n next.source = adapter.serialize(next);\n return next;\n },\n };\n return adapter;\n}\n","import type { LineGrammar, NodeDecl, EdgeSpec } from \"./engine.js\";\nimport { joinBraceBlocks } from \"./engine.js\";\n\n/**\n * stateDiagram / stateDiagram-v2 grammar.\n *\n * Supported statements: transitions (`A --> B : label`), `state \"desc\" as A`,\n * `state A <<fork|join|choice>>`, composite `state A { … }`, `A : description`,\n * `[*]` start/end pseudo-states, `direction`, `classDef`, `class`, `style`,\n * `A:::cls`. Notes, concurrency separators (`--`) and anything else are kept\n * verbatim as passthrough statements.\n *\n * @module\n */\n\nconst ID = String.raw`[A-Za-z0-9_À-.-]+`;\nconst TRANSITION = new RegExp(\n String.raw`^(\\[\\*\\]|${ID}(?::::${ID})?)\\s*-->\\s*(\\[\\*\\]|${ID}(?::::${ID})?)\\s*(?::\\s*(.*))?$`,\n);\n\nexport const STATE_SHAPES = [\n { name: \"rect\", title: \"State\" },\n { name: \"fork\", title: \"Fork\" },\n { name: \"join\", title: \"Join\" },\n { name: \"choice\", title: \"Choice\" },\n] as const;\n\nfunction splitClasses(token: string): { id: string; classes: string[] } {\n const [id, ...classes] = token.split(\":::\");\n return { id: id!, classes };\n}\n\nfunction quoteIfNeeded(label: string): string {\n return /[\\s:{}\"]/.test(label) || label === \"\" ? `\"${label.replace(/\"/g, \"'\")}\"` : label;\n}\n\nexport const stateGrammar: LineGrammar = {\n family: \"state\",\n defaultShape: \"rect\",\n directionAsStatement: true,\n defaultEdge: { arrowStart: \"none\", arrowEnd: \"arrow_barb\", pattern: \"solid\" },\n\n joinLines(lines) {\n // Multi-line notes: `note right of A` … `end note`\n return joinBraceBlocks(lines, {\n open: /^\\s*note\\s+(left|right)\\s+of\\s+\\S+\\s*$/i,\n close: /^\\s*end\\s+note\\s*$/i,\n }).flatMap((logical) => {\n // Composite states are groups: keep `{` opener and `}` closer as their own lines.\n if (/^\\s*state\\b.*\\{\\s*$/.test(logical.split(\"\\n\")[0]!) && logical.includes(\"\\n\"))\n return logical.split(\"\\n\");\n return [logical];\n });\n },\n\n parseLine(line) {\n const indent = line.match(/^\\s*/)![0];\n const text = line.trim();\n if (text === \"\" || text.startsWith(\"%%\") || text.startsWith(\"note\") || text === \"--\")\n return { kind: \"raw\", raw: line, indent };\n if (text === \"}\") return { kind: \"groupClose\", raw: line, indent };\n let m: RegExpExecArray | null;\n\n if ((m = /^direction\\s+(TB|TD|BT|LR|RL)\\s*$/i.exec(text)))\n return { kind: \"direction\", raw: line, indent, direction: m[1]!.toUpperCase() };\n if ((m = /^classDef\\s+(\\S+)\\s+(.*)$/.exec(text)))\n return {\n kind: \"classDef\",\n raw: line,\n indent,\n names: m[1]!.split(\",\"),\n styles: m[2]!\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean),\n };\n if ((m = /^class\\s+(\\S+)\\s+(\\S+)\\s*$/.exec(text)))\n return { kind: \"class\", raw: line, indent, ids: m[1]!.split(\",\"), className: m[2]! };\n if ((m = /^style\\s+(\\S+)\\s+(.*)$/.exec(text)))\n return {\n kind: \"style\",\n raw: line,\n indent,\n id: m[1]!,\n styles: m[2]!\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean),\n };\n\n // state \"Label\" as A { | state A {\n if ((m = new RegExp(String.raw`^state\\s+(?:\"([^\"]*)\"\\s+as\\s+)?(${ID})\\s*\\{\\s*$`).exec(text))) {\n return { kind: \"groupOpen\", raw: line, indent, id: m[2]!, label: m[1] };\n }\n // state \"Label\" as A | state A <<fork>> | state A\n if (\n (m = new RegExp(\n String.raw`^state\\s+(?:\"([^\"]*)\"\\s+as\\s+)?(${ID})(?::::(${ID}))?(?:\\s+<<(fork|join|choice|end)>>)?\\s*$`,\n ).exec(text))\n ) {\n const decl: NodeDecl = { id: m[2]!, label: m[1], classes: m[3] ? [m[3]] : [] };\n if (m[4]) decl.shape = m[4] === \"end\" ? \"stateEnd\" : m[4];\n return { kind: \"node\", raw: line, indent, decl };\n }\n // Transition\n if ((m = TRANSITION.exec(text))) {\n const s = splitClasses(m[1]!);\n const t = splitClasses(m[2]!);\n return {\n kind: \"edge\",\n raw: line,\n indent,\n source: { id: s.id, classes: s.classes },\n target: { id: t.id, classes: t.classes },\n label: m[3]?.trim() || undefined,\n arrowStart: \"none\",\n arrowEnd: \"arrow_barb\",\n pattern: \"solid\",\n };\n }\n // A : description\n if ((m = new RegExp(String.raw`^(${ID})\\s*:\\s*(.*)$`).exec(text))) {\n return {\n kind: \"node\",\n raw: line,\n indent,\n decl: { id: m[1]!, classes: [], data: { descriptions: [m[2]!.trim()] } },\n };\n }\n // bare id (with optional :::class)\n if ((m = new RegExp(String.raw`^(${ID})(?::::(${ID}))?\\s*$`).exec(text))) {\n return { kind: \"node\", raw: line, indent, decl: { id: m[1]!, classes: m[2] ? [m[2]] : [] } };\n }\n return { kind: \"raw\", raw: line, indent };\n },\n\n formatStatement(stmt) {\n switch (stmt.kind) {\n case \"node\": {\n const d = stmt.decl;\n const descriptions = d.data?.descriptions as string[] | undefined;\n if (descriptions?.length && d.label === undefined && !d.shape) {\n return `${stmt.indent}${d.id} : ${descriptions[0]}`;\n }\n let out = `${stmt.indent}state `;\n if (d.label !== undefined && d.label !== d.id) out += `\"${d.label.replace(/\"/g, \"'\")}\" as `;\n out += d.id;\n for (const c of d.classes) out += `:::${c}`;\n if (d.shape && d.shape !== \"rect\")\n out += ` <<${d.shape === \"stateEnd\" ? \"end\" : d.shape}>>`;\n return out;\n }\n case \"edge\": {\n const fmt = (n: NodeDecl) => n.id + n.classes.map((c) => `:::${c}`).join(\"\");\n const src = fmt(stmt.source);\n const tgt = fmt(stmt.target);\n return `${stmt.indent}${src} --> ${tgt}${stmt.label ? ` : ${stmt.label}` : \"\"}`;\n }\n case \"groupOpen\":\n return `${stmt.indent}state ${stmt.label !== undefined && stmt.label !== stmt.id ? `\"${stmt.label}\" as ` : \"\"}${stmt.id} {`;\n case \"groupClose\":\n return `${stmt.indent}}`;\n case \"direction\":\n return `${stmt.indent}direction ${stmt.direction}`;\n case \"classDef\":\n return `${stmt.indent}classDef ${stmt.names.join(\",\")} ${stmt.styles.join(\",\")}`;\n case \"class\":\n return `${stmt.indent}class ${stmt.ids.join(\",\")} ${stmt.className}`;\n case \"style\":\n return `${stmt.indent}style ${stmt.id} ${stmt.styles.join(\",\")}`;\n default:\n return stmt.raw;\n }\n },\n\n nodeStatement(decl, indent) {\n return {\n kind: \"node\",\n raw: \"\",\n indent,\n decl: { ...decl, classes: [...decl.classes] },\n dirty: true,\n };\n },\n\n edgeStatement(source, target, spec: EdgeSpec, indent) {\n const synthetic = (spec.data?.synthetic ?? {}) as { source?: boolean; target?: boolean };\n const endpoint = (id: string, isSynthetic: boolean | undefined): NodeDecl =>\n isSynthetic ? { id: \"[*]\", classes: [] } : { id, classes: [] };\n return {\n kind: \"edge\",\n raw: \"\",\n indent,\n source: endpoint(source, synthetic.source),\n target: endpoint(target, synthetic.target),\n label: spec.label,\n arrowStart: \"none\",\n arrowEnd: \"arrow_barb\",\n pattern: \"solid\",\n dirty: true,\n };\n },\n\n groupStatements(id, label, indent) {\n return {\n open: { kind: \"groupOpen\", raw: \"\", indent, id, label, dirty: true },\n close: { kind: \"groupClose\", raw: `${indent}}`, indent },\n };\n },\n\n headerDirection(_header, statements) {\n const top = statements.find((s) => s.kind === \"direction\");\n return top && top.kind === \"direction\" ? top.direction : \"TB\";\n },\n\n resolveEndpoint(id, stack, role) {\n if (id !== \"[*]\") return null;\n const scope = stack[stack.length - 1] ?? \"root\";\n return role === \"source\"\n ? { id: `${scope}_start`, shape: \"stateStart\", label: \"\", synthetic: true }\n : { id: `${scope}_end`, shape: \"stateEnd\", label: \"\", synthetic: true };\n },\n};\n\nexport function quoteStateLabel(label: string): string {\n return quoteIfNeeded(label);\n}\n","import type { ArrowHead, EdgePattern } from \"../types.js\";\nimport type { LineGrammar, LineStatement, NodeDecl, EdgeSpec } from \"./engine.js\";\nimport { joinBraceBlocks } from \"./engine.js\";\n\n/**\n * classDiagram grammar.\n *\n * Supported: `class A`, `class A[\"Label\"]`, `class A:::cls`, `class A { … }`\n * bodies (kept verbatim and parsed into members), `A : member`, relations\n * with cardinalities and labels, `namespace N { … }`, `direction`, `classDef`,\n * `cssClass`, `style`. `<<annotation>> A`, notes, `click`, `link`, `callback`\n * stay as passthrough.\n *\n * @module\n */\n\nconst ID = String.raw`[A-Za-z0-9_À-.~-]+`;\n\n/** Relation syntax → arrow heads. Order matters: longer tokens first. */\nexport interface ClassRelation {\n token: string;\n arrowStart: ArrowHead;\n arrowEnd: ArrowHead;\n pattern: EdgePattern;\n title: string;\n}\n\nexport const CLASS_RELATIONS: ClassRelation[] = [\n {\n token: \"<|--\",\n arrowStart: \"extension\",\n arrowEnd: \"none\",\n pattern: \"solid\",\n title: \"Inheritance\",\n },\n {\n token: \"--|>\",\n arrowStart: \"none\",\n arrowEnd: \"extension\",\n pattern: \"solid\",\n title: \"Inheritance (reversed)\",\n },\n {\n token: \"<|..\",\n arrowStart: \"extension\",\n arrowEnd: \"none\",\n pattern: \"dotted\",\n title: \"Realization\",\n },\n {\n token: \"..|>\",\n arrowStart: \"none\",\n arrowEnd: \"extension\",\n pattern: \"dotted\",\n title: \"Realization (reversed)\",\n },\n {\n token: \"*--\",\n arrowStart: \"composition\",\n arrowEnd: \"none\",\n pattern: \"solid\",\n title: \"Composition\",\n },\n {\n token: \"--*\",\n arrowStart: \"none\",\n arrowEnd: \"composition\",\n pattern: \"solid\",\n title: \"Composition (reversed)\",\n },\n {\n token: \"o--\",\n arrowStart: \"aggregation\",\n arrowEnd: \"none\",\n pattern: \"solid\",\n title: \"Aggregation\",\n },\n {\n token: \"--o\",\n arrowStart: \"none\",\n arrowEnd: \"aggregation\",\n pattern: \"solid\",\n title: \"Aggregation (reversed)\",\n },\n {\n token: \"<--\",\n arrowStart: \"dependency\",\n arrowEnd: \"none\",\n pattern: \"solid\",\n title: \"Association (reversed)\",\n },\n {\n token: \"-->\",\n arrowStart: \"none\",\n arrowEnd: \"dependency\",\n pattern: \"solid\",\n title: \"Association\",\n },\n {\n token: \"<..\",\n arrowStart: \"dependency\",\n arrowEnd: \"none\",\n pattern: \"dotted\",\n title: \"Dependency (reversed)\",\n },\n {\n token: \"..>\",\n arrowStart: \"none\",\n arrowEnd: \"dependency\",\n pattern: \"dotted\",\n title: \"Dependency\",\n },\n { token: \"()--\", arrowStart: \"lollipop\", arrowEnd: \"none\", pattern: \"solid\", title: \"Lollipop\" },\n {\n token: \"--()\",\n arrowStart: \"none\",\n arrowEnd: \"lollipop\",\n pattern: \"solid\",\n title: \"Lollipop (reversed)\",\n },\n { token: \"--\", arrowStart: \"none\", arrowEnd: \"none\", pattern: \"solid\", title: \"Link (solid)\" },\n { token: \"..\", arrowStart: \"none\", arrowEnd: \"none\", pattern: \"dotted\", title: \"Link (dashed)\" },\n];\n\nconst REL_TOKENS = CLASS_RELATIONS.map((r) => r.token.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")).join(\n \"|\",\n);\nconst RELATION = new RegExp(\n String.raw`^(${ID})(?:\\[\"([^\"]*)\"\\])?(?::::(${ID}))?\\s*(?:\"([^\"]*)\"\\s*)?(${REL_TOKENS})\\s*(?:\"([^\"]*)\"\\s*)?(${ID})(?:\\[\"([^\"]*)\"\\])?(?::::(${ID}))?\\s*(?::\\s*(.*))?$`,\n);\n\nexport function relationFor(\n arrowStart: ArrowHead,\n arrowEnd: ArrowHead,\n pattern: EdgePattern,\n): ClassRelation {\n return (\n CLASS_RELATIONS.find(\n (r) => r.arrowStart === arrowStart && r.arrowEnd === arrowEnd && r.pattern === pattern,\n ) ?? CLASS_RELATIONS.find((r) => r.token === \"-->\")!\n );\n}\n\nexport interface ClassMember {\n raw: string;\n visibility?: \"+\" | \"-\" | \"#\" | \"~\";\n kind: \"attribute\" | \"method\";\n}\n\nexport function parseMembers(bodyLines: string[]): ClassMember[] {\n const out: ClassMember[] = [];\n for (const line of bodyLines) {\n const t = line.trim();\n if (!t || t === \"}\" || t.startsWith(\"%%\") || /^<<.*>>$/.test(t)) continue;\n const vis = /^[+\\-#~]/.exec(t)?.[0] as ClassMember[\"visibility\"] | undefined;\n out.push({ raw: t, visibility: vis, kind: /\\(.*\\)/.test(t) ? \"method\" : \"attribute\" });\n }\n return out;\n}\n\nfunction annotationsOf(bodyLines: string[]): string[] {\n return bodyLines\n .map((l) => l.trim())\n .filter((t) => /^<<.*>>$/.test(t))\n .map((t) => t.slice(2, -2));\n}\n\nexport const classGrammar: LineGrammar = {\n family: \"class\",\n defaultShape: \"classBox\",\n directionAsStatement: true,\n defaultEdge: { arrowStart: \"none\", arrowEnd: \"dependency\", pattern: \"solid\" },\n\n joinLines(lines) {\n return joinBraceBlocks(lines, { open: /^\\s*note\\s+(for\\s+\\S+\\s+)?\"[^\"]*$/i, close: /\"\\s*$/ });\n },\n\n parseLine(logical) {\n const [line, ...bodyRest] = logical.split(\"\\n\");\n const indent = line!.match(/^\\s*/)![0];\n const text = line!.trim();\n if (text === \"\" || text.startsWith(\"%%\") || /^(note|click|link|callback|<<)/.test(text))\n return { kind: \"raw\", raw: logical, indent };\n if (text === \"}\") return { kind: \"groupClose\", raw: line!, indent };\n let m: RegExpExecArray | null;\n\n if ((m = /^direction\\s+(TB|TD|BT|LR|RL)\\s*$/i.exec(text)))\n return { kind: \"direction\", raw: line!, indent, direction: m[1]!.toUpperCase() };\n if ((m = /^classDef\\s+(\\S+)\\s+(.*)$/.exec(text)))\n return {\n kind: \"classDef\",\n raw: line!,\n indent,\n names: m[1]!.split(\",\"),\n styles: m[2]!\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean),\n };\n if ((m = /^cssClass\\s+\"([^\"]+)\"\\s+(\\S+)\\s*$/.exec(text)))\n return {\n kind: \"class\",\n raw: line!,\n indent,\n ids: m[1]!.split(\",\").map((s) => s.trim()),\n className: m[2]!,\n };\n if ((m = /^style\\s+(\\S+)\\s+(.*)$/.exec(text)))\n return {\n kind: \"style\",\n raw: line!,\n indent,\n id: m[1]!,\n styles: m[2]!\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean),\n };\n\n if ((m = new RegExp(String.raw`^namespace\\s+(${ID})\\s*\\{\\s*$`).exec(text)))\n return { kind: \"groupOpen\", raw: line!, indent, id: m[1]! };\n\n // class A[\"Label\"]:::cls { (body joined) | class A\n if (\n (m = new RegExp(\n String.raw`^class\\s+(${ID})(?:\\[\"([^\"]*)\"\\])?(?::::(${ID}))?\\s*(\\{)?\\s*$`,\n ).exec(text))\n ) {\n const decl: NodeDecl = { id: m[1]!, label: m[2], classes: m[3] ? [m[3]] : [] };\n if (m[4] && bodyRest.length) {\n decl.data = { members: parseMembers(bodyRest), annotations: annotationsOf(bodyRest) };\n return { kind: \"node\", raw: line!, indent, decl, body: bodyRest };\n }\n if (m[4] && !bodyRest.length) {\n // `class A {` whose body contains statements → treat as a group-like raw.\n return { kind: \"raw\", raw: line!, indent };\n }\n return { kind: \"node\", raw: line!, indent, decl };\n }\n\n if ((m = RELATION.exec(text))) {\n const rel = CLASS_RELATIONS.find((r) => r.token === m![5])!;\n return {\n kind: \"edge\",\n raw: line!,\n indent,\n source: { id: m[1]!, label: m[2], classes: m[3] ? [m[3]] : [] },\n target: { id: m[7]!, label: m[8], classes: m[9] ? [m[9]] : [] },\n label: m[10]?.trim() || undefined,\n arrowStart: rel.arrowStart,\n arrowEnd: rel.arrowEnd,\n pattern: rel.pattern,\n data: { cardinalityStart: m[4], cardinalityEnd: m[6] },\n };\n }\n\n // A : +member\n if ((m = new RegExp(String.raw`^(${ID})\\s*:\\s*(.+)$`).exec(text))) {\n return {\n kind: \"node\",\n raw: line!,\n indent,\n decl: { id: m[1]!, classes: [], data: { members: parseMembers([m[2]!]) } },\n };\n }\n return { kind: \"raw\", raw: logical, indent };\n },\n\n formatStatement(stmt) {\n switch (stmt.kind) {\n case \"node\": {\n const d = stmt.decl;\n const members = d.data?.members as ClassMember[] | undefined;\n if (\n !stmt.body &&\n members?.length === 1 &&\n d.label === undefined &&\n !d.classes.length &&\n stmt.raw.includes(\" : \")\n ) {\n return `${stmt.indent}${d.id} : ${members[0]!.raw}`;\n }\n let out = `${stmt.indent}class ${d.id}`;\n if (d.label !== undefined && d.label !== d.id) out += `[\"${d.label.replace(/\"/g, \"'\")}\"]`;\n for (const c of d.classes) out += `:::${c}`;\n if (stmt.body) out += \" {\";\n return out;\n }\n case \"edge\": {\n const rel = relationFor(stmt.arrowStart, stmt.arrowEnd, stmt.pattern);\n const cs = stmt.data?.cardinalityStart as string | undefined;\n const ce = stmt.data?.cardinalityEnd as string | undefined;\n const fmt = (n: NodeDecl) =>\n n.id +\n (n.label !== undefined ? `[\"${n.label}\"]` : \"\") +\n n.classes.map((c) => `:::${c}`).join(\"\");\n return `${stmt.indent}${fmt(stmt.source)} ${cs ? `\"${cs}\" ` : \"\"}${rel.token} ${ce ? `\"${ce}\" ` : \"\"}${fmt(stmt.target)}${stmt.label ? ` : ${stmt.label}` : \"\"}`;\n }\n case \"groupOpen\":\n return `${stmt.indent}namespace ${stmt.id} {`;\n case \"groupClose\":\n return `${stmt.indent}}`;\n case \"direction\":\n return `${stmt.indent}direction ${stmt.direction}`;\n case \"classDef\":\n return `${stmt.indent}classDef ${stmt.names.join(\",\")} ${stmt.styles.join(\",\")}`;\n case \"class\":\n return `${stmt.indent}cssClass \"${stmt.ids.join(\",\")}\" ${stmt.className}`;\n case \"style\":\n return `${stmt.indent}style ${stmt.id} ${stmt.styles.join(\",\")}`;\n default:\n return stmt.raw;\n }\n },\n\n nodeStatement(decl, indent) {\n const members = decl.data?.members as ClassMember[] | undefined;\n const body = members?.length\n ? [...members.map((m) => `${indent} ${m.raw}`), `${indent}}`]\n : undefined;\n return {\n kind: \"node\",\n raw: \"\",\n indent,\n decl: { ...decl, classes: [...decl.classes] },\n body,\n dirty: true,\n };\n },\n\n edgeStatement(source, target, spec: EdgeSpec, indent) {\n return {\n kind: \"edge\",\n raw: \"\",\n indent,\n source: { id: source, classes: [] },\n target: { id: target, classes: [] },\n label: spec.label,\n arrowStart: spec.arrowStart,\n arrowEnd: spec.arrowEnd,\n pattern: spec.pattern,\n data: spec.data,\n dirty: true,\n };\n },\n\n groupStatements(id, _label, indent) {\n return {\n open: { kind: \"groupOpen\", raw: \"\", indent, id, dirty: true },\n close: { kind: \"groupClose\", raw: `${indent}}`, indent },\n };\n },\n\n headerDirection(_header, statements) {\n const top = statements.find((s) => s.kind === \"direction\");\n return top && top.kind === \"direction\" ? top.direction : \"TB\";\n },\n};\n\nexport type { LineStatement };\n","import type { ArrowHead, EdgePattern } from \"../types.js\";\nimport type { LineGrammar, NodeDecl, EdgeSpec } from \"./engine.js\";\nimport { joinBraceBlocks } from \"./engine.js\";\n\n/**\n * erDiagram grammar.\n *\n * Supported: relationships with crow's-foot cardinalities\n * (`A ||--o{ B : label`), entities with attribute blocks (kept verbatim and\n * parsed), aliases (`A[Alias]`), `direction`, `classDef`, `class`, `style`,\n * `A:::cls`. Word-form cardinalities (`one or more to …`) are passthrough.\n *\n * @module\n */\n\nconst ID = String.raw`[A-Za-z0-9_À--]+|\"[^\"]+\"`;\n\nexport const ER_CARDINALITIES: {\n token: string;\n head: ArrowHead;\n side: \"left\" | \"right\";\n title: string;\n}[] = [\n { token: \"|o\", head: \"zero_or_one\", side: \"left\", title: \"Zero or one\" },\n { token: \"||\", head: \"only_one\", side: \"left\", title: \"Exactly one\" },\n { token: \"}o\", head: \"zero_or_more\", side: \"left\", title: \"Zero or more\" },\n { token: \"}|\", head: \"one_or_more\", side: \"left\", title: \"One or more\" },\n { token: \"o|\", head: \"zero_or_one\", side: \"right\", title: \"Zero or one\" },\n { token: \"||\", head: \"only_one\", side: \"right\", title: \"Exactly one\" },\n { token: \"o{\", head: \"zero_or_more\", side: \"right\", title: \"Zero or more\" },\n { token: \"|{\", head: \"one_or_more\", side: \"right\", title: \"One or more\" },\n];\n\nconst LEFT: Record<string, ArrowHead> = {\n \"|o\": \"zero_or_one\",\n \"||\": \"only_one\",\n \"}o\": \"zero_or_more\",\n \"}|\": \"one_or_more\",\n};\nconst RIGHT: Record<string, ArrowHead> = {\n \"o|\": \"zero_or_one\",\n \"||\": \"only_one\",\n \"o{\": \"zero_or_more\",\n \"|{\": \"one_or_more\",\n};\nconst LEFT_TOKEN: Partial<Record<ArrowHead, string>> = {\n zero_or_one: \"|o\",\n only_one: \"||\",\n zero_or_more: \"}o\",\n one_or_more: \"}|\",\n};\nconst RIGHT_TOKEN: Partial<Record<ArrowHead, string>> = {\n zero_or_one: \"o|\",\n only_one: \"||\",\n zero_or_more: \"o{\",\n one_or_more: \"|{\",\n};\n\nconst RELATION = new RegExp(\n String.raw`^(${ID})(?:\\[([^\\]]*)\\])?(?::::([\\w-]+))?\\s+(\\|o|\\|\\||\\}o|\\}\\|)(--|\\.\\.|\\.-|-\\.)(o\\||\\|\\||o\\{|\\|\\{)\\s+(${ID})(?:\\[([^\\]]*)\\])?(?::::([\\w-]+))?\\s*:\\s*(.*)$`,\n);\n\nexport interface ErAttribute {\n raw: string;\n type: string;\n name: string;\n keys: string[];\n comment?: string;\n}\n\nexport function parseAttributes(bodyLines: string[]): ErAttribute[] {\n const out: ErAttribute[] = [];\n for (const line of bodyLines) {\n const t = line.trim();\n if (!t || t === \"}\" || t.startsWith(\"%%\")) continue;\n const m =\n /^(\\S+)\\s+(\\S+)((?:\\s+(?:PK|FK|UK)(?:\\s*,\\s*(?:PK|FK|UK))*)?)\\s*(?:\"([^\"]*)\")?\\s*$/.exec(t);\n if (m) {\n out.push({\n raw: t,\n type: m[1]!,\n name: m[2]!,\n keys: (m[3] ?? \"\").split(/[\\s,]+/).filter(Boolean),\n comment: m[4],\n });\n } else {\n out.push({ raw: t, type: \"\", name: t, keys: [] });\n }\n }\n return out;\n}\n\nfunction unq(id: string): string {\n return id.startsWith('\"') && id.endsWith('\"') ? id.slice(1, -1) : id;\n}\n\nfunction fmtId(id: string): string {\n return /[\\s]/.test(id) ? `\"${id}\"` : id;\n}\n\nexport const erGrammar: LineGrammar = {\n family: \"er\",\n defaultShape: \"erBox\",\n directionAsStatement: true,\n supportsGroups: false,\n defaultEdge: { arrowStart: \"only_one\", arrowEnd: \"zero_or_more\", pattern: \"solid\", label: \"has\" },\n\n joinLines(lines) {\n return joinBraceBlocks(lines);\n },\n\n parseLine(logical) {\n const [line, ...bodyRest] = logical.split(\"\\n\");\n const indent = line!.match(/^\\s*/)![0];\n const text = line!.trim();\n if (text === \"\" || text.startsWith(\"%%\")) return { kind: \"raw\", raw: logical, indent };\n let m: RegExpExecArray | null;\n\n if ((m = /^direction\\s+(TB|TD|BT|LR|RL)\\s*$/i.exec(text)))\n return { kind: \"direction\", raw: line!, indent, direction: m[1]!.toUpperCase() };\n if ((m = /^classDef\\s+(\\S+)\\s+(.*)$/.exec(text)))\n return {\n kind: \"classDef\",\n raw: line!,\n indent,\n names: m[1]!.split(\",\"),\n styles: m[2]!\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean),\n };\n if ((m = /^class\\s+(\\S+)\\s+(\\S+)\\s*$/.exec(text)))\n return { kind: \"class\", raw: line!, indent, ids: m[1]!.split(\",\"), className: m[2]! };\n if ((m = /^style\\s+(\\S+)\\s+(.*)$/.exec(text)))\n return {\n kind: \"style\",\n raw: line!,\n indent,\n id: m[1]!,\n styles: m[2]!\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean),\n };\n\n if ((m = RELATION.exec(text))) {\n const line_ = m[5]!;\n return {\n kind: \"edge\",\n raw: line!,\n indent,\n source: { id: unq(m[1]!), label: m[2], classes: m[3] ? [m[3]] : [] },\n target: { id: unq(m[7]!), label: m[8], classes: m[9] ? [m[9]] : [] },\n label: unq(m[10]!.trim()),\n arrowStart: LEFT[m[4]!]!,\n arrowEnd: RIGHT[m[6]!]!,\n pattern: line_ === \"--\" ? \"solid\" : \"dotted\",\n data: { identifying: line_ === \"--\" },\n };\n }\n\n // Entity with attributes: NAME[\"Label\"]:::cls {\n if (\n (m = new RegExp(String.raw`^(${ID})(?:\\[([^\\]]*)\\])?(?::::([\\w-]+))?\\s*(\\{)?\\s*$`).exec(text))\n ) {\n const decl: NodeDecl = {\n id: unq(m[1]!),\n label: m[2] !== undefined ? unq(m[2]) : undefined,\n classes: m[3] ? [m[3]] : [],\n };\n if (m[4]) {\n decl.data = { attributes: parseAttributes(bodyRest) };\n return { kind: \"node\", raw: line!, indent, decl, body: bodyRest };\n }\n return { kind: \"node\", raw: line!, indent, decl };\n }\n return { kind: \"raw\", raw: logical, indent };\n },\n\n formatStatement(stmt) {\n switch (stmt.kind) {\n case \"node\": {\n const d = stmt.decl;\n let out = `${stmt.indent}${fmtId(d.id)}`;\n if (d.label !== undefined && d.label !== d.id) out += `[\"${d.label}\"]`;\n for (const c of d.classes) out += `:::${c}`;\n if (stmt.body) out += \" {\";\n return out;\n }\n case \"edge\": {\n const fmt = (n: NodeDecl) =>\n fmtId(n.id) +\n (n.label !== undefined ? `[\"${n.label}\"]` : \"\") +\n n.classes.map((c) => `:::${c}`).join(\"\");\n const l = LEFT_TOKEN[stmt.arrowStart] ?? \"||\";\n const r = RIGHT_TOKEN[stmt.arrowEnd] ?? \"o{\";\n const mid = stmt.pattern === \"dotted\" ? \"..\" : \"--\";\n const label = stmt.label ?? \"\";\n return `${stmt.indent}${fmt(stmt.source)} ${l}${mid}${r} ${fmt(stmt.target)} : ${/\\s/.test(label) ? `\"${label}\"` : label || '\"\"'}`;\n }\n case \"direction\":\n return `${stmt.indent}direction ${stmt.direction}`;\n case \"classDef\":\n return `${stmt.indent}classDef ${stmt.names.join(\",\")} ${stmt.styles.join(\",\")}`;\n case \"class\":\n return `${stmt.indent}class ${stmt.ids.join(\",\")} ${stmt.className}`;\n case \"style\":\n return `${stmt.indent}style ${stmt.id} ${stmt.styles.join(\",\")}`;\n default:\n return stmt.raw;\n }\n },\n\n nodeStatement(decl, indent) {\n const attrs = decl.data?.attributes as ErAttribute[] | undefined;\n const body = attrs?.length\n ? [...attrs.map((a) => `${indent} ${a.raw}`), `${indent}}`]\n : undefined;\n return {\n kind: \"node\",\n raw: \"\",\n indent,\n decl: { ...decl, classes: [...decl.classes] },\n body,\n dirty: true,\n };\n },\n\n edgeStatement(source, target, spec: EdgeSpec, indent) {\n return {\n kind: \"edge\",\n raw: \"\",\n indent,\n source: { id: source, classes: [] },\n target: { id: target, classes: [] },\n label: spec.label ?? \"has\",\n arrowStart: spec.arrowStart,\n arrowEnd: spec.arrowEnd,\n pattern: spec.pattern,\n data: spec.data,\n dirty: true,\n };\n },\n\n groupStatements(id, _label, indent) {\n // ER diagrams have no grouping construct; emit a comment pair so the\n // engine's bookkeeping still works and Mermaid ignores it.\n return {\n open: { kind: \"raw\", raw: `${indent}%% group ${id}`, indent },\n close: { kind: \"raw\", raw: `${indent}%% end group ${id}`, indent },\n };\n },\n\n headerDirection(_header, statements) {\n const top = statements.find((s) => s.kind === \"direction\");\n return top && top.kind === \"direction\" ? top.direction : \"TB\";\n },\n};\n\nexport const ER_PATTERNS: { pattern: EdgePattern; title: string }[] = [\n { pattern: \"solid\", title: \"Identifying\" },\n { pattern: \"dotted\", title: \"Non-identifying\" },\n];\n","import type { DiagramAdapter, DiagramFamily, SupportTier } from \"./types.js\";\nimport { flowchartAdapter } from \"./flowchart/index.js\";\nimport { createPassthroughAdapter } from \"./passthrough.js\";\nimport { classGrammar, createLineAdapter, erGrammar, stateGrammar } from \"./lines-grammar/index.js\";\n\nconst adapters = new Map<DiagramFamily, DiagramAdapter<unknown>>();\n\n/** Registers (or replaces) the adapter for a family. */\nexport function registerDiagramAdapter(adapter: DiagramAdapter<unknown>): void {\n adapters.set(adapter.family, adapter);\n}\n\nexport function getDiagramAdapter(family: DiagramFamily): DiagramAdapter<unknown> {\n return adapters.get(family) ?? adapters.get(\"unknown\")!;\n}\n\n/** `editable` for flowchart, state, class and ER diagrams; `render-only` otherwise. */\nexport function supportTierOf(family: DiagramFamily): SupportTier {\n return getDiagramAdapter(family).tier;\n}\n\nregisterDiagramAdapter(flowchartAdapter as DiagramAdapter<unknown>);\nregisterDiagramAdapter(createLineAdapter(stateGrammar) as DiagramAdapter<unknown>);\nregisterDiagramAdapter(createLineAdapter(classGrammar) as DiagramAdapter<unknown>);\nregisterDiagramAdapter(createLineAdapter(erGrammar) as DiagramAdapter<unknown>);\nfor (const family of [\n \"requirement\", \"mindmap\", \"sequence\", \"gantt\", \"pie\", \"journey\", \"timeline\", \"gitGraph\", \"c4\",\n \"quadrant\", \"sankey\", \"xychart\", \"block\", \"architecture\", \"packet\", \"kanban\", \"radar\", \"treemap\",\n \"info\", \"unknown\",\n] as DiagramFamily[]) {\n registerDiagramAdapter(createPassthroughAdapter(family) as DiagramAdapter<unknown>);\n}\n","import type { DiagramFamily, EditOp, MermaidDocument, MetaCarrier } from \"./types.js\";\nimport { detectFamilyFromHeader, splitSource } from \"./source/lines.js\";\nimport {\n defaultCarrierFor,\n emptyMeta,\n extractMetaFromBody,\n extractMetaFromFrontmatter,\n mergeMeta,\n} from \"./source/metadata.js\";\nimport { getDiagramAdapter } from \"./registry.js\";\n\nexport interface ParseOptions {\n /** Force where metadata is written. Defaults per family. */\n metaCarrier?: MetaCarrier;\n}\n\n/** Detects the diagram family of a Mermaid source without fully parsing it. */\nexport function detectFamily(source: string): DiagramFamily {\n return detectFamilyFromHeader(splitSource(source).header);\n}\n\n/**\n * Parses Mermaid text into a {@link MermaidDocument}.\n *\n * Never throws: unknown or malformed input yields a `render-only` document\n * with diagnostics, so hosts can always show the source editor.\n */\nexport function parseMermaid(source: string, options: ParseOptions = {}): MermaidDocument {\n const split = splitSource(source);\n const family = detectFamilyFromHeader(split.header);\n const fromBody = extractMetaFromBody(split.bodyLines);\n const fromFm = extractMetaFromFrontmatter(split.preamble);\n let meta = emptyMeta();\n if (fromFm) meta = mergeMeta(meta, fromFm);\n if (fromBody.meta) meta = mergeMeta(meta, fromBody.meta);\n const metaCarrier: MetaCarrier =\n options.metaCarrier ?? (fromFm && !fromBody.meta ? \"frontmatter\" : defaultCarrierFor(family));\n const adapter = getDiagramAdapter(family);\n const doc = adapter.parse(source, {\n source,\n eol: split.eol,\n preamble: split.preamble,\n header: split.header,\n bodyLines: fromBody.bodyLines,\n trailing: split.trailing,\n meta,\n metaCarrier,\n family,\n });\n return doc;\n}\n\n/** Serialises a document back to Mermaid text. */\nexport function serializeMermaid(doc: MermaidDocument): string {\n return getDiagramAdapter(doc.family).serialize(doc);\n}\n\n/**\n * Applies an edit and returns a new document whose `source` is the updated\n * text. Documents are immutable; keep the returned value.\n */\nexport function applyEdit(doc: MermaidDocument, op: EditOp): MermaidDocument {\n if (op.type === \"replaceSource\") {\n const next = parseMermaid(op.source, { metaCarrier: doc.metaCarrier });\n next.dirty = true;\n return next;\n }\n const next = getDiagramAdapter(doc.family).apply(doc, op);\n if (next !== doc && next.source === doc.source) {\n // Adapters normally refresh `source`; make sure it is current.\n next.source = serializeMermaid(next);\n }\n return next;\n}\n\n/** Applies several edits in order. */\nexport function applyEdits(doc: MermaidDocument, ops: EditOp[]): MermaidDocument {\n return ops.reduce((d, op) => applyEdit(d, op), doc);\n}\n"]}
|