schematex 0.9.6 → 0.9.8

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.
Files changed (172) hide show
  1. package/README.md +43 -3
  2. package/dist/ai/ai-sdk.cjs +23 -23
  3. package/dist/ai/ai-sdk.d.cts +3 -3
  4. package/dist/ai/ai-sdk.d.ts +3 -3
  5. package/dist/ai/ai-sdk.js +18 -18
  6. package/dist/ai/index.cjs +32 -32
  7. package/dist/ai/index.d.cts +4 -4
  8. package/dist/ai/index.d.ts +4 -4
  9. package/dist/ai/index.js +19 -19
  10. package/dist/{api-BOJJlNb1.d.ts → api-D_d-JklT.d.ts} +1 -1
  11. package/dist/{api-v9t1T1v6.d.cts → api-DnTyW-6F.d.cts} +1 -1
  12. package/dist/browser.cjs +24 -24
  13. package/dist/browser.d.cts +3 -3
  14. package/dist/browser.d.ts +3 -3
  15. package/dist/browser.js +18 -18
  16. package/dist/{chunk-6QZQTASC.cjs → chunk-246OJILS.cjs} +12 -12
  17. package/dist/{chunk-6QZQTASC.cjs.map → chunk-246OJILS.cjs.map} +1 -1
  18. package/dist/{chunk-JEMAOC2D.js → chunk-2IRYXK4M.js} +3 -3
  19. package/dist/{chunk-JEMAOC2D.js.map → chunk-2IRYXK4M.js.map} +1 -1
  20. package/dist/{chunk-HX64QWB6.cjs → chunk-2LVU75P3.cjs} +175 -11
  21. package/dist/chunk-2LVU75P3.cjs.map +1 -0
  22. package/dist/{chunk-CVTHUOAM.js → chunk-33BFUEYU.js} +173 -9
  23. package/dist/chunk-33BFUEYU.js.map +1 -0
  24. package/dist/{chunk-ITI3STJ6.cjs → chunk-3JN4762U.cjs} +4 -4
  25. package/dist/{chunk-ITI3STJ6.cjs.map → chunk-3JN4762U.cjs.map} +1 -1
  26. package/dist/{chunk-GAQ36VFD.cjs → chunk-4MANMKQ4.cjs} +4 -4
  27. package/dist/{chunk-GAQ36VFD.cjs.map → chunk-4MANMKQ4.cjs.map} +1 -1
  28. package/dist/{chunk-4W75FGWO.js → chunk-4QLIFOKH.js} +1877 -568
  29. package/dist/chunk-4QLIFOKH.js.map +1 -0
  30. package/dist/{chunk-64LABNTF.js → chunk-7NO5LYLL.js} +3 -3
  31. package/dist/{chunk-64LABNTF.js.map → chunk-7NO5LYLL.js.map} +1 -1
  32. package/dist/{chunk-ENUM7GMZ.cjs → chunk-7OOUU6BL.cjs} +147 -2
  33. package/dist/chunk-7OOUU6BL.cjs.map +1 -0
  34. package/dist/{chunk-M26ORU4P.js → chunk-AETIGJXP.js} +3 -3
  35. package/dist/{chunk-M26ORU4P.js.map → chunk-AETIGJXP.js.map} +1 -1
  36. package/dist/{chunk-KH5GRKUM.cjs → chunk-BEPVTFXK.cjs} +2080 -770
  37. package/dist/chunk-BEPVTFXK.cjs.map +1 -0
  38. package/dist/{chunk-OJ3P4IC4.cjs → chunk-DLXDR2E7.cjs} +4 -4
  39. package/dist/{chunk-OJ3P4IC4.cjs.map → chunk-DLXDR2E7.cjs.map} +1 -1
  40. package/dist/{chunk-3J4DZPZC.js → chunk-EB7T5SEO.js} +3 -3
  41. package/dist/{chunk-3J4DZPZC.js.map → chunk-EB7T5SEO.js.map} +1 -1
  42. package/dist/{chunk-VY6UZYYL.cjs → chunk-F5RYWDWO.cjs} +15 -15
  43. package/dist/{chunk-VY6UZYYL.cjs.map → chunk-F5RYWDWO.cjs.map} +1 -1
  44. package/dist/{chunk-INVLJYAE.cjs → chunk-GTCGATOL.cjs} +4 -4
  45. package/dist/{chunk-INVLJYAE.cjs.map → chunk-GTCGATOL.cjs.map} +1 -1
  46. package/dist/{chunk-ZCHGIWJK.js → chunk-HIWJMJJB.js} +3 -3
  47. package/dist/{chunk-ZCHGIWJK.js.map → chunk-HIWJMJJB.js.map} +1 -1
  48. package/dist/{chunk-RDYACU2G.js → chunk-IHX6J4HF.js} +3 -3
  49. package/dist/{chunk-RDYACU2G.js.map → chunk-IHX6J4HF.js.map} +1 -1
  50. package/dist/{chunk-4MRVJI7G.js → chunk-JVNV2T2T.js} +147 -3
  51. package/dist/chunk-JVNV2T2T.js.map +1 -0
  52. package/dist/{chunk-SXOAAQNY.js → chunk-KUSW5I2P.js} +3 -3
  53. package/dist/{chunk-SXOAAQNY.js.map → chunk-KUSW5I2P.js.map} +1 -1
  54. package/dist/{chunk-35NGXDT2.cjs → chunk-KYE7CRED.cjs} +12 -12
  55. package/dist/{chunk-35NGXDT2.cjs.map → chunk-KYE7CRED.cjs.map} +1 -1
  56. package/dist/{chunk-II4GLKGF.js → chunk-MVTYPWHO.js} +3 -3
  57. package/dist/chunk-MVTYPWHO.js.map +1 -0
  58. package/dist/{chunk-N3HU635X.cjs → chunk-MXV3XJFH.cjs} +4 -4
  59. package/dist/chunk-MXV3XJFH.cjs.map +1 -0
  60. package/dist/{chunk-XCCXG6RR.js → chunk-NB7MFQCZ.js} +3 -3
  61. package/dist/{chunk-XCCXG6RR.js.map → chunk-NB7MFQCZ.js.map} +1 -1
  62. package/dist/{chunk-GYYYULBL.js → chunk-NP7N3DZG.js} +3 -3
  63. package/dist/{chunk-GYYYULBL.js.map → chunk-NP7N3DZG.js.map} +1 -1
  64. package/dist/{chunk-3PH2MQGN.js → chunk-P4U565XH.js} +3 -3
  65. package/dist/{chunk-3PH2MQGN.js.map → chunk-P4U565XH.js.map} +1 -1
  66. package/dist/{chunk-VYQXB2RC.cjs → chunk-QC2RICQ4.cjs} +12 -12
  67. package/dist/{chunk-VYQXB2RC.cjs.map → chunk-QC2RICQ4.cjs.map} +1 -1
  68. package/dist/{chunk-3WX24RCH.js → chunk-QMJHLDGY.js} +3 -3
  69. package/dist/{chunk-3WX24RCH.js.map → chunk-QMJHLDGY.js.map} +1 -1
  70. package/dist/{chunk-C4Y24X3U.cjs → chunk-T55OQILI.cjs} +4 -4
  71. package/dist/{chunk-C4Y24X3U.cjs.map → chunk-T55OQILI.cjs.map} +1 -1
  72. package/dist/{chunk-6ZD7TCWO.cjs → chunk-TFUVNQNA.cjs} +15 -15
  73. package/dist/{chunk-6ZD7TCWO.cjs.map → chunk-TFUVNQNA.cjs.map} +1 -1
  74. package/dist/{chunk-4AC6I7KJ.cjs → chunk-TXWVJAMR.cjs} +4 -4
  75. package/dist/{chunk-4AC6I7KJ.cjs.map → chunk-TXWVJAMR.cjs.map} +1 -1
  76. package/dist/{chunk-4OC3CTGE.cjs → chunk-UHRNFBWY.cjs} +4 -4
  77. package/dist/{chunk-4OC3CTGE.cjs.map → chunk-UHRNFBWY.cjs.map} +1 -1
  78. package/dist/{chunk-B4CMWA6Y.js → chunk-W4UVDMUC.js} +3 -3
  79. package/dist/{chunk-B4CMWA6Y.js.map → chunk-W4UVDMUC.js.map} +1 -1
  80. package/dist/{chunk-5ZQRHDMQ.cjs → chunk-YDEQZSPQ.cjs} +4 -4
  81. package/dist/{chunk-5ZQRHDMQ.cjs.map → chunk-YDEQZSPQ.cjs.map} +1 -1
  82. package/dist/{chunk-627GHE2N.cjs → chunk-YFPDZVB7.cjs} +5 -5
  83. package/dist/{chunk-627GHE2N.cjs.map → chunk-YFPDZVB7.cjs.map} +1 -1
  84. package/dist/{chunk-NKYR4PAS.js → chunk-YXEPF3SL.js} +3 -3
  85. package/dist/{chunk-NKYR4PAS.js.map → chunk-YXEPF3SL.js.map} +1 -1
  86. package/dist/{chunk-AXMBXAEA.js → chunk-ZRFKIERV.js} +3 -3
  87. package/dist/{chunk-AXMBXAEA.js.map → chunk-ZRFKIERV.js.map} +1 -1
  88. package/dist/{diagnostics-5bVLlGNj.d.cts → diagnostics-D2qkBfFx.d.cts} +1 -1
  89. package/dist/{diagnostics-5bVLlGNj.d.ts → diagnostics-D2qkBfFx.d.ts} +1 -1
  90. package/dist/diagrams/blockdiagram/index.cjs +6 -6
  91. package/dist/diagrams/blockdiagram/index.d.cts +1 -1
  92. package/dist/diagrams/blockdiagram/index.d.ts +1 -1
  93. package/dist/diagrams/blockdiagram/index.js +2 -2
  94. package/dist/diagrams/circuit/index.cjs +9 -9
  95. package/dist/diagrams/circuit/index.d.cts +1 -1
  96. package/dist/diagrams/circuit/index.d.ts +1 -1
  97. package/dist/diagrams/circuit/index.js +2 -2
  98. package/dist/diagrams/ecomap/index.cjs +7 -7
  99. package/dist/diagrams/ecomap/index.d.cts +1 -1
  100. package/dist/diagrams/ecomap/index.d.ts +1 -1
  101. package/dist/diagrams/ecomap/index.js +2 -2
  102. package/dist/diagrams/entity/index.cjs +6 -6
  103. package/dist/diagrams/entity/index.d.cts +1 -1
  104. package/dist/diagrams/entity/index.d.ts +1 -1
  105. package/dist/diagrams/entity/index.js +2 -2
  106. package/dist/diagrams/fishbone/index.cjs +8 -8
  107. package/dist/diagrams/fishbone/index.d.cts +1 -1
  108. package/dist/diagrams/fishbone/index.d.ts +1 -1
  109. package/dist/diagrams/fishbone/index.js +2 -2
  110. package/dist/diagrams/flowchart/index.cjs +8 -8
  111. package/dist/diagrams/flowchart/index.d.cts +2 -2
  112. package/dist/diagrams/flowchart/index.d.ts +2 -2
  113. package/dist/diagrams/flowchart/index.js +2 -2
  114. package/dist/diagrams/genogram/index.cjs +9 -9
  115. package/dist/diagrams/genogram/index.d.cts +1 -1
  116. package/dist/diagrams/genogram/index.d.ts +1 -1
  117. package/dist/diagrams/genogram/index.js +2 -2
  118. package/dist/diagrams/ladder/index.cjs +6 -6
  119. package/dist/diagrams/ladder/index.d.cts +1 -1
  120. package/dist/diagrams/ladder/index.d.ts +1 -1
  121. package/dist/diagrams/ladder/index.js +2 -2
  122. package/dist/diagrams/logic/index.cjs +8 -8
  123. package/dist/diagrams/logic/index.d.cts +1 -1
  124. package/dist/diagrams/logic/index.d.ts +1 -1
  125. package/dist/diagrams/logic/index.js +2 -2
  126. package/dist/diagrams/orgchart/index.cjs +8 -8
  127. package/dist/diagrams/orgchart/index.d.cts +1 -1
  128. package/dist/diagrams/orgchart/index.d.ts +1 -1
  129. package/dist/diagrams/orgchart/index.js +2 -2
  130. package/dist/diagrams/pedigree/index.cjs +7 -7
  131. package/dist/diagrams/pedigree/index.d.cts +1 -1
  132. package/dist/diagrams/pedigree/index.d.ts +1 -1
  133. package/dist/diagrams/pedigree/index.js +2 -2
  134. package/dist/diagrams/phylo/index.cjs +7 -7
  135. package/dist/diagrams/phylo/index.d.cts +1 -1
  136. package/dist/diagrams/phylo/index.d.ts +1 -1
  137. package/dist/diagrams/phylo/index.js +2 -2
  138. package/dist/diagrams/sld/index.cjs +8 -8
  139. package/dist/diagrams/sld/index.d.cts +1 -1
  140. package/dist/diagrams/sld/index.d.ts +1 -1
  141. package/dist/diagrams/sld/index.js +2 -2
  142. package/dist/diagrams/sociogram/index.cjs +6 -6
  143. package/dist/diagrams/sociogram/index.d.cts +1 -1
  144. package/dist/diagrams/sociogram/index.d.ts +1 -1
  145. package/dist/diagrams/sociogram/index.js +2 -2
  146. package/dist/diagrams/timing/index.d.cts +1 -1
  147. package/dist/diagrams/timing/index.d.ts +1 -1
  148. package/dist/diagrams/venn/index.cjs +9 -9
  149. package/dist/diagrams/venn/index.d.cts +1 -1
  150. package/dist/diagrams/venn/index.d.ts +1 -1
  151. package/dist/diagrams/venn/index.js +2 -2
  152. package/dist/{index-syc0E5Ss.d.ts → index-D9u0YRxL.d.ts} +1 -1
  153. package/dist/{index-Cmf4Rcve.d.cts → index-JZlLiE6K.d.cts} +1 -1
  154. package/dist/index.cjs +91 -87
  155. package/dist/index.d.cts +7 -5
  156. package/dist/index.d.ts +7 -5
  157. package/dist/index.js +22 -22
  158. package/dist/react.cjs +18 -18
  159. package/dist/react.d.cts +2 -2
  160. package/dist/react.d.ts +2 -2
  161. package/dist/react.js +17 -17
  162. package/dist/{tools-B98iarLm.d.cts → tools-DAKYNcPv.d.cts} +2 -2
  163. package/dist/{tools-CCZ1IcIN.d.ts → tools-DM0aLCbc.d.ts} +2 -2
  164. package/package.json +3 -1
  165. package/dist/chunk-4MRVJI7G.js.map +0 -1
  166. package/dist/chunk-4W75FGWO.js.map +0 -1
  167. package/dist/chunk-CVTHUOAM.js.map +0 -1
  168. package/dist/chunk-ENUM7GMZ.cjs.map +0 -1
  169. package/dist/chunk-HX64QWB6.cjs.map +0 -1
  170. package/dist/chunk-II4GLKGF.js.map +0 -1
  171. package/dist/chunk-KH5GRKUM.cjs.map +0 -1
  172. package/dist/chunk-N3HU635X.cjs.map +0 -1
@@ -1,21 +1,21 @@
1
- import { orgchart } from './chunk-3J4DZPZC.js';
2
- import { circuit } from './chunk-RDYACU2G.js';
3
- import { blockdiagram } from './chunk-3PH2MQGN.js';
4
- import { ladder } from './chunk-B4CMWA6Y.js';
5
- import { sld } from './chunk-II4GLKGF.js';
6
- import { entity } from './chunk-JEMAOC2D.js';
7
- import { fishbone } from './chunk-GYYYULBL.js';
8
- import { venn } from './chunk-SXOAAQNY.js';
9
- import { flowchart, layoutFlowchart } from './chunk-AXMBXAEA.js';
10
- import { genogram } from './chunk-M26ORU4P.js';
11
- import { ecomap, estimateTextWidth } from './chunk-XCCXG6RR.js';
12
- import { pedigree } from './chunk-ZCHGIWJK.js';
1
+ import { orgchart } from './chunk-EB7T5SEO.js';
2
+ import { circuit } from './chunk-IHX6J4HF.js';
3
+ import { blockdiagram } from './chunk-P4U565XH.js';
4
+ import { ladder } from './chunk-W4UVDMUC.js';
5
+ import { sld } from './chunk-MVTYPWHO.js';
6
+ import { entity } from './chunk-2IRYXK4M.js';
7
+ import { fishbone } from './chunk-NP7N3DZG.js';
8
+ import { venn } from './chunk-KUSW5I2P.js';
9
+ import { flowchart, layoutFlowchart } from './chunk-ZRFKIERV.js';
10
+ import { genogram } from './chunk-AETIGJXP.js';
11
+ import { ecomap, estimateTextWidth } from './chunk-NB7MFQCZ.js';
12
+ import { pedigree } from './chunk-HIWJMJJB.js';
13
13
  import { parseFrontmatter } from './chunk-2KTQ75LN.js';
14
- import { phylo } from './chunk-3WX24RCH.js';
15
- import { sociogram } from './chunk-64LABNTF.js';
14
+ import { phylo } from './chunk-QMJHLDGY.js';
15
+ import { sociogram } from './chunk-7NO5LYLL.js';
16
16
  import { timing } from './chunk-MTIZIHWE.js';
17
- import { logic } from './chunk-NKYR4PAS.js';
18
- import { resolveBaseTheme, resolveTimelineTheme, resolveStateTheme, cssCustomProperties, resolvePetriTheme, resolveNetworkTheme, resolveUmlClassTheme, DEFAULT_FONT_FAMILY, FONT_SIZE, resolveReliabilityTheme, STROKE_WIDTH, resolveBowtieTheme, resolveMindmapTheme, resolveMatrixTheme, resolveBpmnTheme, resolveFloorplanTheme, TITLE, resolvePlaybookTheme } from './chunk-4MRVJI7G.js';
17
+ import { logic } from './chunk-YXEPF3SL.js';
18
+ import { resolveBaseTheme, resolveTimelineTheme, resolveStateTheme, cssCustomProperties, resolvePetriTheme, resolveNetworkTheme, resolveUmlClassTheme, DEFAULT_FONT_FAMILY, FONT_SIZE, resolveReliabilityTheme, STROKE_WIDTH, resolveBowtieTheme, resolveComparisonTheme, TITLE, resolveMindmapTheme, resolveMatrixTheme, resolveBpmnTheme, resolveFloorplanTheme, resolvePlaybookTheme } from './chunk-JVNV2T2T.js';
19
19
  import { QUOTE_PAIRS, stripQuotes, isOpenQuote, extractQuotedString, matchQuotedTitle } from './chunk-TO6PNBT3.js';
20
20
  import { el, escapeXml, group, rect, text, line, path, circle, polygon, title, desc, svgRoot, defs, multilineText } from './chunk-SYYBKDL7.js';
21
21
 
@@ -1613,8 +1613,8 @@ function renderDecisionTree(ast, config) {
1613
1613
  lx += nx * perpOffset * flip;
1614
1614
  ly += ny * perpOffset * flip;
1615
1615
  }
1616
- const charW = isProb ? 5.5 : 6.2;
1617
- const w = Math.max(e.label.length * charW + 10, 18);
1616
+ const charW2 = isProb ? 5.5 : 6.2;
1617
+ const w = Math.max(e.label.length * charW2 + 10, 18);
1618
1618
  const h = 14;
1619
1619
  inner.push(rect({
1620
1620
  x: lx - w / 2,
@@ -7603,8 +7603,8 @@ function renderBox(box2) {
7603
7603
  );
7604
7604
  }
7605
7605
  function approxLineWidth(line2) {
7606
- const charW = line2.style === "label" || line2.style === "count" ? 7.4 : 6.4;
7607
- return line2.text.length * charW;
7606
+ const charW2 = line2.style === "label" || line2.style === "count" ? 7.4 : 6.4;
7607
+ return line2.text.length * charW2;
7608
7608
  }
7609
7609
  function renderPrismaLayout(layout, config) {
7610
7610
  const t = resolveBaseTheme(config?.theme ?? "default");
@@ -8271,35 +8271,35 @@ function ellipsePerimeterPoint(cx, cy, rx, ry, tx, ty) {
8271
8271
  function isWideGlyph(cp) {
8272
8272
  return cp >= 12288 && cp <= 40959 || cp >= 44032 && cp <= 55203 || cp >= 65280 && cp <= 65519;
8273
8273
  }
8274
- function estimateTextWidth2(s, charW) {
8274
+ function estimateTextWidth2(s, charW2) {
8275
8275
  let w = 0;
8276
8276
  for (const ch of s) {
8277
- w += isWideGlyph(ch.codePointAt(0) ?? 0) ? charW * 1.7 : charW;
8277
+ w += isWideGlyph(ch.codePointAt(0) ?? 0) ? charW2 * 1.7 : charW2;
8278
8278
  }
8279
8279
  return w;
8280
8280
  }
8281
8281
  function sizeEllipse(uc) {
8282
- const C2 = USECASE_CONST;
8283
- const nameW = estimateTextWidth2(uc.name, C2.CHAR_W_NAME);
8282
+ const C3 = USECASE_CONST;
8283
+ const nameW = estimateTextWidth2(uc.name, C3.CHAR_W_NAME);
8284
8284
  let widest = nameW;
8285
8285
  if (uc.stereotype) {
8286
- widest = Math.max(widest, estimateTextWidth2(`\xAB${uc.stereotype}\xBB`, C2.CHAR_W_EXT));
8286
+ widest = Math.max(widest, estimateTextWidth2(`\xAB${uc.stereotype}\xBB`, C3.CHAR_W_EXT));
8287
8287
  }
8288
8288
  let stack = 0;
8289
- if (uc.stereotype) stack += C2.STEREO_LH;
8290
- stack += C2.NAME_LH;
8289
+ if (uc.stereotype) stack += C3.STEREO_LH;
8290
+ stack += C3.NAME_LH;
8291
8291
  const hasExt = uc.extensionPoints.length > 0;
8292
8292
  if (hasExt) {
8293
8293
  stack += 8;
8294
- stack += C2.EXTPOINT_LH;
8295
- stack += uc.extensionPoints.length * C2.EXTPOINT_LH;
8296
- widest = Math.max(widest, estimateTextWidth2(C2.EXT_HEADER, C2.CHAR_W_EXT));
8294
+ stack += C3.EXTPOINT_LH;
8295
+ stack += uc.extensionPoints.length * C3.EXTPOINT_LH;
8296
+ widest = Math.max(widest, estimateTextWidth2(C3.EXT_HEADER, C3.CHAR_W_EXT));
8297
8297
  for (const ep of uc.extensionPoints) {
8298
- widest = Math.max(widest, estimateTextWidth2(ep, C2.CHAR_W_EXT) + 16);
8298
+ widest = Math.max(widest, estimateTextWidth2(ep, C3.CHAR_W_EXT) + 16);
8299
8299
  }
8300
8300
  }
8301
- const rx = Math.max(C2.MIN_RX, widest / 2 * Math.SQRT2 + C2.ELLIPSE_PAD_X);
8302
- const ry = Math.max(C2.MIN_RY, stack / 2 * Math.SQRT2 + C2.ELLIPSE_PAD_Y);
8301
+ const rx = Math.max(C3.MIN_RX, widest / 2 * Math.SQRT2 + C3.ELLIPSE_PAD_X);
8302
+ const ry = Math.max(C3.MIN_RY, stack / 2 * Math.SQRT2 + C3.ELLIPSE_PAD_Y);
8303
8303
  const result = {
8304
8304
  rx: Math.round(rx),
8305
8305
  ry: Math.round(ry)
@@ -8384,7 +8384,7 @@ function classifyActorSides(ast) {
8384
8384
  return sides;
8385
8385
  }
8386
8386
  function layoutUsecase(ast) {
8387
- const C2 = USECASE_CONST;
8387
+ const C3 = USECASE_CONST;
8388
8388
  const ucIds = new Set(ast.usecases.map((u) => u.id));
8389
8389
  const actorById = new Map(ast.actors.map((a) => [a.id, a]));
8390
8390
  const sizes = /* @__PURE__ */ new Map();
@@ -8447,18 +8447,18 @@ function layoutUsecase(ast) {
8447
8447
  }
8448
8448
  }
8449
8449
  const colMaxRx = columns.map(
8450
- (col) => col.reduce((m, u) => Math.max(m, sizes.get(u.id).rx), C2.MIN_RX)
8450
+ (col) => col.reduce((m, u) => Math.max(m, sizes.get(u.id).rx), C3.MIN_RX)
8451
8451
  );
8452
8452
  const colCenterX = [];
8453
8453
  let cursorX = 0;
8454
8454
  for (let d = 0; d <= maxDepth; d++) {
8455
8455
  cursorX += colMaxRx[d];
8456
8456
  colCenterX[d] = cursorX;
8457
- cursorX += colMaxRx[d] + C2.COL_GAP;
8457
+ cursorX += colMaxRx[d] + C3.COL_GAP;
8458
8458
  }
8459
- let maxRy = C2.MIN_RY;
8459
+ let maxRy = C3.MIN_RY;
8460
8460
  for (const s of sizes.values()) maxRy = Math.max(maxRy, s.ry);
8461
- const rowPitch = Math.max(C2.ROW_PITCH, 2 * maxRy + C2.ROW_GAP_MIN);
8461
+ const rowPitch = Math.max(C3.ROW_PITCH, 2 * maxRy + C3.ROW_GAP_MIN);
8462
8462
  const ellipses = [];
8463
8463
  const ellById = /* @__PURE__ */ new Map();
8464
8464
  for (let d = 0; d <= maxDepth; d++) {
@@ -8481,7 +8481,7 @@ function layoutUsecase(ast) {
8481
8481
  for (let i = 1; i < colE.length; i++) {
8482
8482
  const prev = colE[i - 1];
8483
8483
  const cur = colE[i];
8484
- const minGap = prev.ry + cur.ry + C2.ROW_GAP_MIN;
8484
+ const minGap = prev.ry + cur.ry + C3.ROW_GAP_MIN;
8485
8485
  if (cur.cy - prev.cy < minGap) {
8486
8486
  cur.cy = prev.cy + minGap;
8487
8487
  if (cur.dividerY !== void 0) cur.dividerY = cur.cy + 6;
@@ -8502,10 +8502,10 @@ function layoutUsecase(ast) {
8502
8502
  ucMaxY = 100;
8503
8503
  }
8504
8504
  const hasSubject = !!ast.system;
8505
- const subjLeft = ucMinX - C2.SUBJECT_PAD;
8506
- const subjRight = ucMaxX + C2.SUBJECT_PAD;
8507
- const subjTop = ucMinY - C2.SUBJECT_TOP_PAD;
8508
- const subjBottom = ucMaxY + C2.SUBJECT_BOTTOM_PAD;
8505
+ const subjLeft = ucMinX - C3.SUBJECT_PAD;
8506
+ const subjRight = ucMaxX + C3.SUBJECT_PAD;
8507
+ const subjTop = ucMinY - C3.SUBJECT_TOP_PAD;
8508
+ const subjBottom = ucMaxY + C3.SUBJECT_BOTTOM_PAD;
8509
8509
  const leftActors = ast.actors.filter((a) => sides.get(a.id) === "left");
8510
8510
  const rightActors = ast.actors.filter((a) => sides.get(a.id) === "right");
8511
8511
  const actorBoxes = [];
@@ -8513,17 +8513,17 @@ function layoutUsecase(ast) {
8513
8513
  const subjCenterY = (subjTop + subjBottom) / 2;
8514
8514
  function placeStack(actors, side) {
8515
8515
  if (actors.length === 0) return;
8516
- const totalH = (actors.length - 1) * C2.ACTOR_PITCH;
8516
+ const totalH = (actors.length - 1) * C3.ACTOR_PITCH;
8517
8517
  let cy = subjCenterY - totalH / 2;
8518
8518
  for (const a of actors) {
8519
8519
  const isRect = a.kind === "external" || a.kind === "system";
8520
- const w = isRect ? C2.EXTERNAL_W : C2.ACTOR_W;
8521
- const h = isRect ? C2.EXTERNAL_H : C2.ACTOR_H;
8520
+ const w = isRect ? C3.EXTERNAL_W : C3.ACTOR_W;
8521
+ const h = isRect ? C3.EXTERNAL_H : C3.ACTOR_H;
8522
8522
  let x;
8523
8523
  if (side === "left") {
8524
- x = subjLeft - C2.ACTOR_GAP - w;
8524
+ x = subjLeft - C3.ACTOR_GAP - w;
8525
8525
  } else {
8526
- x = subjRight + C2.ACTOR_GAP;
8526
+ x = subjRight + C3.ACTOR_GAP;
8527
8527
  }
8528
8528
  const y = cy - h / 2;
8529
8529
  const anchorX = side === "left" ? x + w : x;
@@ -8540,7 +8540,7 @@ function layoutUsecase(ast) {
8540
8540
  };
8541
8541
  actorBoxes.push(box2);
8542
8542
  actorById2.set(a.id, box2);
8543
- cy += C2.ACTOR_PITCH;
8543
+ cy += C3.ACTOR_PITCH;
8544
8544
  }
8545
8545
  }
8546
8546
  placeStack(leftActors, "left");
@@ -8559,11 +8559,11 @@ function layoutUsecase(ast) {
8559
8559
  minX = Math.min(minX, left);
8560
8560
  maxX = Math.max(maxX, right);
8561
8561
  minY = Math.min(minY, b.y);
8562
- maxY = Math.max(maxY, b.y + b.height + C2.ACTOR_LABEL_H);
8562
+ maxY = Math.max(maxY, b.y + b.height + C3.ACTOR_LABEL_H);
8563
8563
  }
8564
- const titleSpace = ast.title ? C2.TITLE_H : 0;
8565
- const offsetX = C2.MARGIN - minX;
8566
- const offsetY = C2.MARGIN + titleSpace - minY;
8564
+ const titleSpace = ast.title ? C3.TITLE_H : 0;
8565
+ const offsetX = C3.MARGIN - minX;
8566
+ const offsetY = C3.MARGIN + titleSpace - minY;
8567
8567
  const translate = (px, py) => ({ x: px + offsetX, y: py + offsetY });
8568
8568
  for (const e of ellipses) {
8569
8569
  const p = translate(e.cx, e.cy);
@@ -8584,8 +8584,8 @@ function layoutUsecase(ast) {
8584
8584
  height: subjBottom - subjTop
8585
8585
  } : void 0;
8586
8586
  if (subject && ast.system) subject.name = ast.system;
8587
- const width = maxX - minX + 2 * C2.MARGIN;
8588
- const height = maxY - minY + 2 * C2.MARGIN + titleSpace;
8587
+ const width = maxX - minX + 2 * C3.MARGIN;
8588
+ const height = maxY - minY + 2 * C3.MARGIN + titleSpace;
8589
8589
  const edges = [];
8590
8590
  const trees = [];
8591
8591
  const genByParent = /* @__PURE__ */ new Map();
@@ -8625,7 +8625,7 @@ function layoutUsecase(ast) {
8625
8625
  return { x, y };
8626
8626
  }
8627
8627
  for (const [parentId, rels] of genByParent) {
8628
- const useTree = ast.generalizationTree && rels.length >= C2.GEN_TREE_THRESHOLD;
8628
+ const useTree = ast.generalizationTree && rels.length >= C3.GEN_TREE_THRESHOLD;
8629
8629
  const allActors = actorById2.has(parentId) && rels.every((r7) => actorById2.has(r7.source));
8630
8630
  if (allActors) {
8631
8631
  const side = sides.get(parentId) ?? "left";
@@ -8677,8 +8677,8 @@ function layoutUsecase(ast) {
8677
8677
  const dirX = avgX - parent.cx;
8678
8678
  const dirY = avgY - parent.cy;
8679
8679
  const len = Math.hypot(dirX, dirY) || 1;
8680
- const jx = pPt.x + dirX / len * C2.GEN_JUNCTION_OFFSET;
8681
- const jy = pPt.y + dirY / len * C2.GEN_JUNCTION_OFFSET;
8680
+ const jx = pPt.x + dirX / len * C3.GEN_JUNCTION_OFFSET;
8681
+ const jy = pPt.y + dirY / len * C3.GEN_JUNCTION_OFFSET;
8682
8682
  const legPaths = [];
8683
8683
  for (const r7 of rels) {
8684
8684
  const cPt = perimeter(r7.source, jx, jy);
@@ -10113,7 +10113,7 @@ function routeEdge2(s, t, direction) {
10113
10113
  return { d, labelX: mid, labelY: (sy + ty) / 2 };
10114
10114
  }
10115
10115
  function layoutNetwork(ast, schedule) {
10116
- const C2 = PERT_CONST;
10116
+ const C3 = PERT_CONST;
10117
10117
  const { rank, maxRank } = assignRanks(ast);
10118
10118
  const layers = orderLayers(ast, schedule, rank, maxRank);
10119
10119
  const dir = ast.direction;
@@ -10122,16 +10122,16 @@ function layoutNetwork(ast, schedule) {
10122
10122
  const colExtent = layers.map((layer) => {
10123
10123
  const n = layer.length;
10124
10124
  if (n === 0) return 0;
10125
- const unit = dir === "TB" ? C2.BOX_W : C2.BOX_H;
10126
- const gap = dir === "TB" ? C2.H_GAP : C2.V_GAP;
10125
+ const unit = dir === "TB" ? C3.BOX_W : C3.BOX_H;
10126
+ const gap = dir === "TB" ? C3.H_GAP : C3.V_GAP;
10127
10127
  return n * unit + (n - 1) * gap;
10128
10128
  });
10129
10129
  const maxExtent = Math.max(0, ...colExtent);
10130
10130
  const hasSentinels = ast.showSentinels;
10131
- const sentLead = hasSentinels ? C2.SENT_R * 2 + C2.H_GAP : 0;
10132
- const titleH = ast.title ? C2.TITLE_H : 0;
10133
- const originPrimary = dir === "TB" ? C2.PAD + titleH + sentLead : C2.PAD + sentLead;
10134
- const originCross = dir === "TB" ? C2.PAD : C2.PAD + titleH;
10131
+ const sentLead = hasSentinels ? C3.SENT_R * 2 + C3.H_GAP : 0;
10132
+ const titleH = ast.title ? C3.TITLE_H : 0;
10133
+ const originPrimary = dir === "TB" ? C3.PAD + titleH + sentLead : C3.PAD + sentLead;
10134
+ const originCross = dir === "TB" ? C3.PAD : C3.PAD + titleH;
10135
10135
  const boxes = [];
10136
10136
  const boxById = /* @__PURE__ */ new Map();
10137
10137
  for (let r7 = 0; r7 <= maxRank; r7++) {
@@ -10142,20 +10142,20 @@ function layoutNetwork(ast, schedule) {
10142
10142
  for (const id of layer) {
10143
10143
  const t = byId.get(id);
10144
10144
  const computed = schedule.computed.get(id);
10145
- const w = t.milestone ? C2.MS_W : C2.BOX_W;
10146
- const h = C2.BOX_H;
10145
+ const w = t.milestone ? C3.MS_W : C3.BOX_W;
10146
+ const h = C3.BOX_H;
10147
10147
  let x;
10148
10148
  let y;
10149
10149
  if (dir === "TB") {
10150
- const rankPos = originPrimary + r7 * (C2.BOX_H + C2.H_GAP);
10151
- x = cursor + (C2.BOX_W - w) / 2;
10150
+ const rankPos = originPrimary + r7 * (C3.BOX_H + C3.H_GAP);
10151
+ x = cursor + (C3.BOX_W - w) / 2;
10152
10152
  y = rankPos;
10153
- cursor += C2.BOX_W + C2.H_GAP;
10153
+ cursor += C3.BOX_W + C3.H_GAP;
10154
10154
  } else {
10155
- const rankPos = originPrimary + r7 * (C2.BOX_W + C2.H_GAP);
10156
- x = rankPos + (C2.BOX_W - w) / 2;
10155
+ const rankPos = originPrimary + r7 * (C3.BOX_W + C3.H_GAP);
10156
+ x = rankPos + (C3.BOX_W - w) / 2;
10157
10157
  y = cursor;
10158
- cursor += C2.BOX_H + C2.V_GAP;
10158
+ cursor += C3.BOX_H + C3.V_GAP;
10159
10159
  }
10160
10160
  const box2 = {
10161
10161
  id,
@@ -10202,11 +10202,11 @@ function layoutNetwork(ast, schedule) {
10202
10202
  const sentinels = [];
10203
10203
  if (hasSentinels) {
10204
10204
  const contentMidCross = originCross + maxExtent / 2;
10205
- const startPrimary = C2.PAD + C2.SENT_R;
10206
- const finishPrimary = maxPrimary + C2.H_GAP + C2.SENT_R;
10205
+ const startPrimary = C3.PAD + C3.SENT_R;
10206
+ const finishPrimary = maxPrimary + C3.H_GAP + C3.SENT_R;
10207
10207
  const place = (primary) => dir === "TB" ? { cx: contentMidCross, cy: primary } : { cx: primary, cy: contentMidCross };
10208
- sentinels.push({ id: "__start__", label: "Start", r: C2.SENT_R, ...place(startPrimary) });
10209
- sentinels.push({ id: "__finish__", label: "Finish", r: C2.SENT_R, ...place(finishPrimary) });
10208
+ sentinels.push({ id: "__start__", label: "Start", r: C3.SENT_R, ...place(startPrimary) });
10209
+ sentinels.push({ id: "__finish__", label: "Finish", r: C3.SENT_R, ...place(finishPrimary) });
10210
10210
  const usedAsPred = /* @__PURE__ */ new Set();
10211
10211
  for (const t of ast.tasks) for (const dep of t.deps) usedAsPred.add(dep.pred);
10212
10212
  const startSent = sentinels[0];
@@ -10220,19 +10220,19 @@ function layoutNetwork(ast, schedule) {
10220
10220
  edges.push(sentinelEdge(finishSent, b, dir, false, schedule.computed.get(t.id)));
10221
10221
  }
10222
10222
  }
10223
- maxPrimary = finishPrimary + C2.SENT_R;
10223
+ maxPrimary = finishPrimary + C3.SENT_R;
10224
10224
  }
10225
10225
  const crossEnd = Math.max(maxCross, originCross + maxExtent);
10226
10226
  let width;
10227
10227
  let footerY;
10228
10228
  if (dir === "TB") {
10229
- width = crossEnd + C2.PAD;
10229
+ width = crossEnd + C3.PAD;
10230
10230
  footerY = maxPrimary + 14;
10231
10231
  } else {
10232
- width = maxPrimary + C2.PAD;
10232
+ width = maxPrimary + C3.PAD;
10233
10233
  footerY = crossEnd + 14;
10234
10234
  }
10235
- const height = footerY + C2.FOOTER_H;
10235
+ const height = footerY + C3.FOOTER_H;
10236
10236
  return {
10237
10237
  width: Math.ceil(width),
10238
10238
  height: Math.ceil(height),
@@ -10310,7 +10310,7 @@ function buildDependencyEdges(ast, schedule, boxById, dir) {
10310
10310
  return edges;
10311
10311
  }
10312
10312
  function layoutSwimlane2(ast, schedule) {
10313
- const C2 = PERT_CONST;
10313
+ const C3 = PERT_CONST;
10314
10314
  const { rank, maxRank } = assignRanks(ast);
10315
10315
  const byId = /* @__PURE__ */ new Map();
10316
10316
  for (const t of ast.tasks) byId.set(t.id, t);
@@ -10341,9 +10341,9 @@ function layoutSwimlane2(ast, schedule) {
10341
10341
  return declIndex.get(a) - declIndex.get(b);
10342
10342
  });
10343
10343
  }
10344
- const titleH = ast.title ? C2.TITLE_H : 0;
10345
- const topY = C2.PAD + titleH;
10346
- const colX = (r7) => C2.LANE_LABEL_W + C2.PAD + r7 * (C2.BOX_W + C2.H_GAP);
10344
+ const titleH = ast.title ? C3.TITLE_H : 0;
10345
+ const topY = C3.PAD + titleH;
10346
+ const colX = (r7) => C3.LANE_LABEL_W + C3.PAD + r7 * (C3.BOX_W + C3.H_GAP);
10347
10347
  const lanes = [];
10348
10348
  const laneY = /* @__PURE__ */ new Map();
10349
10349
  const laneH = /* @__PURE__ */ new Map();
@@ -10354,7 +10354,7 @@ function layoutSwimlane2(ast, schedule) {
10354
10354
  const arr = cell.get(key(lane, r7));
10355
10355
  if (arr) stack = Math.max(stack, arr.length);
10356
10356
  }
10357
- const bandH = stack * C2.BOX_H + (stack - 1) * C2.V_GAP + 2 * C2.LANE_PAD;
10357
+ const bandH = stack * C3.BOX_H + (stack - 1) * C3.V_GAP + 2 * C3.LANE_PAD;
10358
10358
  laneY.set(lane, cursor);
10359
10359
  laneH.set(lane, bandH);
10360
10360
  lanes.push({ name: lane, y: cursor, height: bandH, alt: i % 2 === 1 });
@@ -10369,13 +10369,13 @@ function layoutSwimlane2(ast, schedule) {
10369
10369
  for (let r7 = 0; r7 <= maxRank; r7++) {
10370
10370
  const arr = cell.get(key(lane, r7));
10371
10371
  if (!arr) continue;
10372
- const colInnerH = arr.length * C2.BOX_H + (arr.length - 1) * C2.V_GAP;
10372
+ const colInnerH = arr.length * C3.BOX_H + (arr.length - 1) * C3.V_GAP;
10373
10373
  const y0 = bandTop + (bandH - colInnerH) / 2;
10374
10374
  arr.forEach((id, idx) => {
10375
10375
  const t = byId.get(id);
10376
- const w = t.milestone ? C2.MS_W : C2.BOX_W;
10377
- const x = colX(r7) + (C2.BOX_W - w) / 2;
10378
- const y = y0 + idx * (C2.BOX_H + C2.V_GAP);
10376
+ const w = t.milestone ? C3.MS_W : C3.BOX_W;
10377
+ const x = colX(r7) + (C3.BOX_W - w) / 2;
10378
+ const y = y0 + idx * (C3.BOX_H + C3.V_GAP);
10379
10379
  const box2 = {
10380
10380
  id,
10381
10381
  task: t,
@@ -10383,7 +10383,7 @@ function layoutSwimlane2(ast, schedule) {
10383
10383
  x,
10384
10384
  y,
10385
10385
  width: w,
10386
- height: C2.BOX_H,
10386
+ height: C3.BOX_H,
10387
10387
  milestone: t.milestone,
10388
10388
  rank: r7
10389
10389
  };
@@ -10393,9 +10393,9 @@ function layoutSwimlane2(ast, schedule) {
10393
10393
  }
10394
10394
  }
10395
10395
  const edges = buildDependencyEdges(ast, schedule, boxById, "LR");
10396
- const width = colX(maxRank) + C2.BOX_W + C2.PAD;
10396
+ const width = colX(maxRank) + C3.BOX_W + C3.PAD;
10397
10397
  const footerY = contentBottom + 14;
10398
- const height = footerY + C2.FOOTER_H;
10398
+ const height = footerY + C3.FOOTER_H;
10399
10399
  return {
10400
10400
  width: Math.ceil(width),
10401
10401
  height: Math.ceil(height),
@@ -10413,20 +10413,20 @@ function layoutSwimlane2(ast, schedule) {
10413
10413
  };
10414
10414
  }
10415
10415
  function layoutTimescaled(ast, schedule) {
10416
- const C2 = PERT_CONST;
10416
+ const C3 = PERT_CONST;
10417
10417
  const T = schedule.projectDuration || 1;
10418
10418
  const pxPerUnit = Math.min(56, Math.max(16, 1300 / T));
10419
- const titleH = ast.title ? C2.TITLE_H : 0;
10420
- const leftPad = C2.PAD;
10421
- const topPad = C2.PAD + titleH + 14;
10419
+ const titleH = ast.title ? C3.TITLE_H : 0;
10420
+ const leftPad = C3.PAD;
10421
+ const topPad = C3.PAD + titleH + 14;
10422
10422
  const intervals = ast.tasks.map((t) => {
10423
10423
  const c = schedule.computed.get(t.id);
10424
10424
  if (t.milestone) {
10425
10425
  const cx = leftPad + c.es * pxPerUnit;
10426
- return { id: t.id, x: cx - C2.TS_MS_W / 2, w: C2.TS_MS_W };
10426
+ return { id: t.id, x: cx - C3.TS_MS_W / 2, w: C3.TS_MS_W };
10427
10427
  }
10428
10428
  const x = leftPad + c.es * pxPerUnit;
10429
- const w = Math.max(C2.TS_MIN_W, t.duration * pxPerUnit);
10429
+ const w = Math.max(C3.TS_MIN_W, t.duration * pxPerUnit);
10430
10430
  return { id: t.id, x, w };
10431
10431
  });
10432
10432
  intervals.sort((a, b) => a.x - b.x || a.w - b.w);
@@ -10435,7 +10435,7 @@ function layoutTimescaled(ast, schedule) {
10435
10435
  for (const iv of intervals) {
10436
10436
  let placed = -1;
10437
10437
  for (let l = 0; l < laneRight.length; l++) {
10438
- if (iv.x >= laneRight[l] + C2.TS_GAP) {
10438
+ if (iv.x >= laneRight[l] + C3.TS_GAP) {
10439
10439
  placed = l;
10440
10440
  break;
10441
10441
  }
@@ -10457,7 +10457,7 @@ function layoutTimescaled(ast, schedule) {
10457
10457
  for (const t of ast.tasks) {
10458
10458
  const iv = intervalById.get(t.id);
10459
10459
  const lane = laneOf.get(t.id);
10460
- const y = topPad + lane * (C2.TS_BOX_H + C2.TS_LANE_GAP);
10460
+ const y = topPad + lane * (C3.TS_BOX_H + C3.TS_LANE_GAP);
10461
10461
  const box2 = {
10462
10462
  id: t.id,
10463
10463
  task: t,
@@ -10465,7 +10465,7 @@ function layoutTimescaled(ast, schedule) {
10465
10465
  x: iv.x,
10466
10466
  y,
10467
10467
  width: iv.w,
10468
- height: C2.TS_BOX_H,
10468
+ height: C3.TS_BOX_H,
10469
10469
  milestone: t.milestone,
10470
10470
  rank: 0
10471
10471
  };
@@ -10493,7 +10493,7 @@ function layoutTimescaled(ast, schedule) {
10493
10493
  edges.push(edge);
10494
10494
  }
10495
10495
  }
10496
- const contentBottom = topPad + laneCount * C2.TS_BOX_H + (laneCount - 1) * C2.TS_LANE_GAP;
10496
+ const contentBottom = topPad + laneCount * C3.TS_BOX_H + (laneCount - 1) * C3.TS_LANE_GAP;
10497
10497
  const axisBaseline = contentBottom + 22;
10498
10498
  const timeEnd = leftPad + T * pxPerUnit;
10499
10499
  let maxRight = timeEnd;
@@ -10509,8 +10509,8 @@ function layoutTimescaled(ast, schedule) {
10509
10509
  major: Math.abs(rounded % majorStep) < 1e-9
10510
10510
  });
10511
10511
  }
10512
- const width = Math.ceil(Math.max(maxRight, timeEnd) + C2.PAD);
10513
- const height = Math.ceil(axisBaseline + C2.AXIS_H + C2.FOOTER_H);
10512
+ const width = Math.ceil(Math.max(maxRight, timeEnd) + C3.PAD);
10513
+ const height = Math.ceil(axisBaseline + C3.AXIS_H + C3.FOOTER_H);
10514
10514
  return {
10515
10515
  width,
10516
10516
  height,
@@ -12163,7 +12163,7 @@ var SequenceLayout = class {
12163
12163
  left = mid - 20;
12164
12164
  right = mid + 20;
12165
12165
  }
12166
- const frame = {
12166
+ const frame2 = {
12167
12167
  op,
12168
12168
  x: left,
12169
12169
  y: frameTop,
@@ -12171,8 +12171,8 @@ var SequenceLayout = class {
12171
12171
  height: frameBottom - frameTop,
12172
12172
  operands: operandGeom
12173
12173
  };
12174
- if (messageSet && messageSet.length) frame.messageSet = messageSet;
12175
- this.fragments.push(frame);
12174
+ if (messageSet && messageSet.length) frame2.messageSet = messageSet;
12175
+ this.fragments.push(frame2);
12176
12176
  this.noteRight(left, right - left);
12177
12177
  this.y = frameBottom;
12178
12178
  }
@@ -12840,7 +12840,7 @@ var PETRI_CONST = {
12840
12840
  CHAR_W: 6.2
12841
12841
  };
12842
12842
  function layoutPetri(ast) {
12843
- const C2 = PETRI_CONST;
12843
+ const C3 = PETRI_CONST;
12844
12844
  const dir = ast.direction;
12845
12845
  const warnings = [...ast.warnings];
12846
12846
  const kindOf = /* @__PURE__ */ new Map();
@@ -12924,10 +12924,10 @@ function layoutPetri(ast) {
12924
12924
  }
12925
12925
  }
12926
12926
  const sizeOf5 = (id) => {
12927
- if (kindOf.get(id) === "place") return { halfW: C2.PLACE_R, halfH: C2.PLACE_R, r: C2.PLACE_R };
12927
+ if (kindOf.get(id) === "place") return { halfW: C3.PLACE_R, halfH: C3.PLACE_R, r: C3.PLACE_R };
12928
12928
  const tr = ast.transitions.find((t) => t.id === id);
12929
- const long = tr.kind === "timed" ? C2.TRANS_BOX_H : C2.TRANS_BAR_H;
12930
- const thin = tr.kind === "timed" ? C2.TRANS_BOX_W : C2.TRANS_BAR_W;
12929
+ const long = tr.kind === "timed" ? C3.TRANS_BOX_H : C3.TRANS_BAR_H;
12930
+ const thin = tr.kind === "timed" ? C3.TRANS_BOX_W : C3.TRANS_BAR_W;
12931
12931
  const halfW = dir === "lr" ? thin / 2 : long / 2;
12932
12932
  const halfH = dir === "lr" ? long / 2 : thin / 2;
12933
12933
  return { halfW, halfH, r: 0 };
@@ -12941,15 +12941,15 @@ function layoutPetri(ast) {
12941
12941
  return dir === "lr" ? s.halfH : s.halfW;
12942
12942
  };
12943
12943
  const layerHalf = layers.map((arr) => Math.max(0, ...arr.map(flowHalf)));
12944
- const slot = Math.max(0, ...ids.map(crossHalf)) * 2 + C2.RANK_GAP;
12944
+ const slot = Math.max(0, ...ids.map(crossHalf)) * 2 + C3.RANK_GAP;
12945
12945
  const maxCount = Math.max(1, ...layers.map((a) => a.length));
12946
- const crossCenter = C2.MARGIN + C2.LABEL_LINE_H * 2 + maxCount * slot / 2;
12946
+ const crossCenter = C3.MARGIN + C3.LABEL_LINE_H * 2 + maxCount * slot / 2;
12947
12947
  const flowCenter = [];
12948
- let acc = C2.MARGIN + C2.LABEL_LINE_H * 2;
12948
+ let acc = C3.MARGIN + C3.LABEL_LINE_H * 2;
12949
12949
  for (let L = 0; L < layers.length; L++) {
12950
12950
  acc += layerHalf[L];
12951
12951
  flowCenter[L] = acc;
12952
- acc += layerHalf[L] + C2.LAYER_GAP;
12952
+ acc += layerHalf[L] + C3.LAYER_GAP;
12953
12953
  }
12954
12954
  const geom = /* @__PURE__ */ new Map();
12955
12955
  layers.forEach((arr, L) => {
@@ -13032,12 +13032,12 @@ function layoutPetri(ast) {
13032
13032
  if (dir === "lr") {
13033
13033
  const pA = boundary(A, 0, 1);
13034
13034
  const pB = boundary(B, 0, 1);
13035
- const bowY = bandMaxCross + C2.BACKEDGE_BOW;
13035
+ const bowY = bandMaxCross + C3.BACKEDGE_BOW;
13036
13036
  points = [pA, { x: pA.x, y: bowY }, { x: pB.x, y: bowY }, pB];
13037
13037
  } else {
13038
13038
  const pA = boundary(A, 1, 0);
13039
13039
  const pB = boundary(B, 1, 0);
13040
- const bowX = bandMaxCross + C2.BACKEDGE_BOW;
13040
+ const bowX = bandMaxCross + C3.BACKEDGE_BOW;
13041
13041
  points = [pA, { x: bowX, y: pA.y }, { x: bowX, y: pB.y }, pB];
13042
13042
  }
13043
13043
  }
@@ -13048,8 +13048,8 @@ function layoutPetri(ast) {
13048
13048
  const ddx = p1.x - p0.x;
13049
13049
  const ddy = p1.y - p0.y;
13050
13050
  const dl = Math.hypot(ddx, ddy) || 1;
13051
- const labelX = mx - ddy / dl * C2.ARC_WEIGHT_OFFSET;
13052
- const labelY = my + ddx / dl * C2.ARC_WEIGHT_OFFSET;
13051
+ const labelX = mx - ddy / dl * C3.ARC_WEIGHT_OFFSET;
13052
+ const labelY = my + ddx / dl * C3.ARC_WEIGHT_OFFSET;
13053
13053
  return { arc: a, type: a.type, weight: a.weight, points, reversed, labelX, labelY };
13054
13054
  });
13055
13055
  const hasIncoming = (pid2) => ast.arcs.some((a) => a.to === pid2);
@@ -13086,24 +13086,24 @@ function layoutPetri(ast) {
13086
13086
  bb.maxY = Math.max(bb.maxY, y0, y1);
13087
13087
  };
13088
13088
  const addPt = (p) => addBox(p.x, p.y, p.x, p.y);
13089
- const labelW = (s) => s ? s.length * C2.CHAR_W : 0;
13089
+ const labelW = (s) => s ? s.length * C3.CHAR_W : 0;
13090
13090
  for (const pb of placeBoxes) {
13091
13091
  addBox(pb.cx - pb.r, pb.cy - pb.r, pb.cx + pb.r, pb.cy + pb.r);
13092
13092
  const lw = Math.max(labelW(pb.place.id), labelW(pb.place.label)) / 2;
13093
- addBox(pb.cx - lw, pb.cy - pb.r - C2.LABEL_LINE_H * 2, pb.cx + lw, pb.cy);
13094
- if (pb.place.capacity !== void 0) addBox(pb.cx, pb.cy + pb.r, pb.cx + 24, pb.cy + pb.r + C2.LABEL_LINE_H);
13093
+ addBox(pb.cx - lw, pb.cy - pb.r - C3.LABEL_LINE_H * 2, pb.cx + lw, pb.cy);
13094
+ if (pb.place.capacity !== void 0) addBox(pb.cx, pb.cy + pb.r, pb.cx + 24, pb.cy + pb.r + C3.LABEL_LINE_H);
13095
13095
  }
13096
13096
  for (const tb of transBoxes) {
13097
13097
  addBox(tb.cx - tb.w / 2, tb.cy - tb.h / 2, tb.cx + tb.w / 2, tb.cy + tb.h / 2);
13098
13098
  const lw = Math.max(labelW(tb.transition.id), labelW(tb.transition.label)) / 2;
13099
- addBox(tb.cx - lw, tb.cy - tb.h / 2 - C2.LABEL_LINE_H * 2, tb.cx + lw, tb.cy);
13099
+ addBox(tb.cx - lw, tb.cy - tb.h / 2 - C3.LABEL_LINE_H * 2, tb.cx + lw, tb.cy);
13100
13100
  }
13101
13101
  for (const ag of arcGeoms) {
13102
13102
  ag.points.forEach(addPt);
13103
13103
  if (ag.weight > 1) addBox(ag.labelX - 6, ag.labelY - 8, ag.labelX + 6, ag.labelY + 4);
13104
13104
  }
13105
- const dx = C2.MARGIN - bb.minX;
13106
- const dy = C2.MARGIN - bb.minY;
13105
+ const dx = C3.MARGIN - bb.minX;
13106
+ const dy = C3.MARGIN - bb.minY;
13107
13107
  const shift = (p) => ({ x: p.x + dx, y: p.y + dy });
13108
13108
  placeBoxes.forEach((pb) => {
13109
13109
  pb.cx += dx;
@@ -13118,8 +13118,8 @@ function layoutPetri(ast) {
13118
13118
  ag.labelX += dx;
13119
13119
  ag.labelY += dy;
13120
13120
  });
13121
- const width = bb.maxX - bb.minX + 2 * C2.MARGIN;
13122
- const height = bb.maxY - bb.minY + 2 * C2.MARGIN;
13121
+ const width = bb.maxX - bb.minX + 2 * C3.MARGIN;
13122
+ const height = bb.maxY - bb.minY + 2 * C3.MARGIN;
13123
13123
  const subclass = detectSubclass(ast);
13124
13124
  return {
13125
13125
  width: Math.round(width),
@@ -17464,6 +17464,19 @@ function truncate3(s, n) {
17464
17464
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
17465
17465
  }
17466
17466
 
17467
+ // src/core/format.ts
17468
+ function formatProbability(n) {
17469
+ if (!Number.isFinite(n)) return String(n);
17470
+ if (n <= 0) return "0";
17471
+ if (n >= 1) return "1";
17472
+ if (n < 1e-3) return n.toExponential(2);
17473
+ for (let p = 3; p <= 9; p++) {
17474
+ const s = parseFloat(n.toPrecision(p));
17475
+ if (s > 0 && s < 1) return String(s);
17476
+ }
17477
+ return String(parseFloat(n.toPrecision(9)));
17478
+ }
17479
+
17467
17480
  // src/diagrams/faulttree/analysis.ts
17468
17481
  var EXPANSION_CAP = 5e4;
17469
17482
  var EXACT_CUTSET_CAP = 20;
@@ -17714,7 +17727,7 @@ var FAULTTREE_CONST = {
17714
17727
  TITLE_H: 34
17715
17728
  };
17716
17729
  function eventBox(label) {
17717
- const C2 = FAULTTREE_CONST;
17730
+ const C3 = FAULTTREE_CONST;
17718
17731
  const words = label.split(/\s+/).filter(Boolean);
17719
17732
  const lines = [];
17720
17733
  let cur = "";
@@ -17732,11 +17745,11 @@ function eventBox(label) {
17732
17745
  else if (cur && lines.length === 2) lines[1] = `${lines[1]} ${cur}`;
17733
17746
  if (lines.length === 0) lines.push(label);
17734
17747
  const longest = Math.max(...lines.map((l) => l.length), 1);
17735
- const width = Math.min(C2.EVENT_MAX_W, Math.max(C2.EVENT_MIN_W, Math.ceil(longest * C2.CHAR_W) + 2 * C2.EVENT_PAD_X));
17748
+ const width = Math.min(C3.EVENT_MAX_W, Math.max(C3.EVENT_MIN_W, Math.ceil(longest * C3.CHAR_W) + 2 * C3.EVENT_PAD_X));
17736
17749
  return { width, lines };
17737
17750
  }
17738
17751
  function layoutFaultTree(ast) {
17739
- const C2 = FAULTTREE_CONST;
17752
+ const C3 = FAULTTREE_CONST;
17740
17753
  const analysis = analyseFaultTree(ast);
17741
17754
  const byId = new Map(ast.events.map((e) => [e.id, e]));
17742
17755
  const refCount = /* @__PURE__ */ new Map();
@@ -17752,13 +17765,13 @@ function layoutFaultTree(ast) {
17752
17765
  case "intermediate":
17753
17766
  return eventBox(label).width;
17754
17767
  case "basic":
17755
- return 2 * C2.BASIC_R;
17768
+ return 2 * C3.BASIC_R;
17756
17769
  case "undeveloped":
17757
- return C2.DIAMOND_W;
17770
+ return C3.DIAMOND_W;
17758
17771
  case "house":
17759
- return C2.HOUSE_W;
17772
+ return C3.HOUSE_W;
17760
17773
  case "condition":
17761
- return C2.COND_W;
17774
+ return C3.COND_W;
17762
17775
  }
17763
17776
  };
17764
17777
  const build = (eventId, depth, onPath) => {
@@ -17805,9 +17818,9 @@ function layoutFaultTree(ast) {
17805
17818
  }
17806
17819
  let x = originX;
17807
17820
  for (const c of n.children) {
17808
- x += place(c, x) + C2.SIBLING_GAP;
17821
+ x += place(c, x) + C3.SIBLING_GAP;
17809
17822
  }
17810
- const childrenWidth = x - originX - C2.SIBLING_GAP;
17823
+ const childrenWidth = x - originX - C3.SIBLING_GAP;
17811
17824
  if (n.width <= childrenWidth) {
17812
17825
  n.cx = (n.children[0].cx + n.children[n.children.length - 1].cx) / 2;
17813
17826
  return childrenWidth;
@@ -17817,24 +17830,24 @@ function layoutFaultTree(ast) {
17817
17830
  n.cx = originX + n.width / 2;
17818
17831
  return n.width;
17819
17832
  };
17820
- const baseY = C2.CANVAS_PAD + (ast.title ? C2.TITLE_H : 0) + (ast.analysis.probability ? 18 : 0);
17821
- place(root, C2.CANVAS_PAD);
17822
- const ROW_PITCH = C2.EVENT_H + C2.GATE_GAP + C2.GATE_H + C2.LEVEL_GAP;
17833
+ const baseY = C3.CANVAS_PAD + (ast.title ? C3.TITLE_H : 0) + (ast.analysis.probability ? 18 : 0);
17834
+ place(root, C3.CANVAS_PAD);
17835
+ const ROW_PITCH = C3.EVENT_H + C3.GATE_GAP + C3.GATE_H + C3.LEVEL_GAP;
17823
17836
  const rowY = (depth) => baseY + depth * ROW_PITCH;
17824
- const centerY = (n) => n.topY + C2.EVENT_H / 2;
17837
+ const centerY = (n) => n.topY + C3.EVENT_H / 2;
17825
17838
  const halfH = (role) => {
17826
17839
  switch (role) {
17827
17840
  case "top":
17828
17841
  case "intermediate":
17829
- return C2.EVENT_H / 2;
17842
+ return C3.EVENT_H / 2;
17830
17843
  case "basic":
17831
- return C2.BASIC_R;
17844
+ return C3.BASIC_R;
17832
17845
  case "undeveloped":
17833
- return C2.DIAMOND_W / 2;
17846
+ return C3.DIAMOND_W / 2;
17834
17847
  case "house":
17835
- return C2.HOUSE_H / 2;
17848
+ return C3.HOUSE_H / 2;
17836
17849
  case "condition":
17837
- return C2.COND_H / 2;
17850
+ return C3.COND_H / 2;
17838
17851
  }
17839
17852
  };
17840
17853
  const topAnchorY = (n) => n.role === "top" || n.role === "intermediate" ? n.topY : centerY(n) - halfH(n.role);
@@ -17848,7 +17861,7 @@ function layoutFaultTree(ast) {
17848
17861
  cx: n.cx,
17849
17862
  topY: n.topY,
17850
17863
  width: n.width,
17851
- height: n.role === "top" || n.role === "intermediate" ? C2.EVENT_H : 2 * halfH(n.role),
17864
+ height: n.role === "top" || n.role === "intermediate" ? C3.EVENT_H : 2 * halfH(n.role),
17852
17865
  depth: n.depth,
17853
17866
  shared: n.shared
17854
17867
  };
@@ -17856,28 +17869,28 @@ function layoutFaultTree(ast) {
17856
17869
  (instancesByEvent.get(n.eventId) ?? instancesByEvent.set(n.eventId, []).get(n.eventId)).push(lay);
17857
17870
  if (n.gate && n.children.length > 0) {
17858
17871
  const gx = n.cx;
17859
- const gy = n.topY + C2.EVENT_H + C2.GATE_GAP + C2.GATE_H / 2;
17872
+ const gy = n.topY + C3.EVENT_H + C3.GATE_GAP + C3.GATE_H / 2;
17860
17873
  const glay = {
17861
17874
  gate: n.gate,
17862
17875
  ownerInstanceId: n.instanceId,
17863
17876
  cx: gx,
17864
17877
  cy: gy,
17865
- width: C2.GATE_W,
17866
- height: C2.GATE_H
17878
+ width: C3.GATE_W,
17879
+ height: C3.GATE_H
17867
17880
  };
17868
17881
  if ((n.gate.kind === "inhibit" || n.gate.kind === "pand") && (n.gate.condition || n.gate.order)) {
17869
17882
  const condEv = n.gate.condition ? byId.get(n.gate.condition) : void 0;
17870
17883
  const text2 = n.gate.order ? n.gate.order.join(" \u227A ") : condEv?.label ?? n.gate.condition ?? "";
17871
17884
  glay.cond = {
17872
- x: gx + C2.GATE_W / 2 + C2.COND_GAP + C2.COND_W / 2,
17885
+ x: gx + C3.GATE_W / 2 + C3.COND_GAP + C3.COND_W / 2,
17873
17886
  y: gy,
17874
- w: C2.COND_W,
17875
- h: C2.COND_H,
17887
+ w: C3.COND_W,
17888
+ h: C3.COND_H,
17876
17889
  text: text2
17877
17890
  };
17878
17891
  }
17879
17892
  gates.push(glay);
17880
- const gateBaseY = gy + C2.GATE_H / 2;
17893
+ const gateBaseY = gy + C3.GATE_H / 2;
17881
17894
  for (const c of n.children) {
17882
17895
  c.topY = rowY(c.depth);
17883
17896
  const childTop = topAnchorY(c);
@@ -17895,7 +17908,7 @@ function layoutFaultTree(ast) {
17895
17908
  const cutSetBoxes = [];
17896
17909
  let boxIndex = 0;
17897
17910
  const visualBounds = (e) => {
17898
- const cy = e.topY + C2.EVENT_H / 2;
17911
+ const cy = e.topY + C3.EVENT_H / 2;
17899
17912
  const hw = e.width / 2;
17900
17913
  const hh = halfH(e.role);
17901
17914
  return { minX: e.cx - hw, maxX: e.cx + hw, minY: cy - hh, maxY: cy + hh };
@@ -17909,7 +17922,7 @@ function layoutFaultTree(ast) {
17909
17922
  maxX2 = Math.max(maxX2, b.maxX);
17910
17923
  maxY2 = Math.max(maxY2, b.maxY);
17911
17924
  }
17912
- const pad = C2.CUTSET_PAD + idx % 3 * C2.CUTSET_OFFSET_STEP;
17925
+ const pad = C3.CUTSET_PAD + idx % 3 * C3.CUTSET_OFFSET_STEP;
17913
17926
  return {
17914
17927
  cutSet: cs,
17915
17928
  index: idx,
@@ -17940,7 +17953,7 @@ function layoutFaultTree(ast) {
17940
17953
  ownerInstanceId: inst.instanceId,
17941
17954
  name: tr.name,
17942
17955
  x: inst.cx,
17943
- y: inst.topY + C2.EVENT_H + C2.GATE_GAP
17956
+ y: inst.topY + C3.EVENT_H + C3.GATE_GAP
17944
17957
  });
17945
17958
  }
17946
17959
  let maxX = 0, maxY = 0;
@@ -17954,7 +17967,7 @@ function layoutFaultTree(ast) {
17954
17967
  if (e.role === "basic" || e.role === "undeveloped" || e.role === "house") {
17955
17968
  const hasLabel = !!e.event.label && e.event.label !== e.event.id;
17956
17969
  const hasProb = ast.analysis.probability && e.event.prob !== void 0;
17957
- if (hasLabel || hasProb) bump(b.maxX, b.maxY + (hasLabel && hasProb ? C2.CAP_GAP + C2.CAP_LINE_H + 8 : C2.CAP_GAP + 6));
17970
+ if (hasLabel || hasProb) bump(b.maxX, b.maxY + (hasLabel && hasProb ? C3.CAP_GAP + C3.CAP_LINE_H + 8 : C3.CAP_GAP + 6));
17958
17971
  }
17959
17972
  }
17960
17973
  for (const g of gates) {
@@ -17963,7 +17976,7 @@ function layoutFaultTree(ast) {
17963
17976
  }
17964
17977
  for (const box2 of cutSetBoxes) bump(box2.x + box2.width, box2.y + box2.height);
17965
17978
  for (const t of transfers) bump(t.x + 22, t.y + 30);
17966
- if (ast.title) bump(C2.CANVAS_PAD + ast.title.length * 8.5, 0);
17979
+ if (ast.title) bump(C3.CANVAS_PAD + ast.title.length * 8.5, 0);
17967
17980
  if (ast.analysis.probability) {
17968
17981
  const top = events.find((e) => e.role === "top");
17969
17982
  if (top) bump(top.cx + 95, 0);
@@ -17976,8 +17989,8 @@ function layoutFaultTree(ast) {
17976
17989
  edges,
17977
17990
  cutSetBoxes,
17978
17991
  transfers,
17979
- width: Math.ceil(maxX + C2.CANVAS_PAD),
17980
- height: Math.ceil(maxY + C2.CANVAS_PAD)
17992
+ width: Math.ceil(maxX + C3.CANVAS_PAD),
17993
+ height: Math.ceil(maxY + C3.CANVAS_PAD)
17981
17994
  };
17982
17995
  }
17983
17996
  function r(n) {
@@ -18217,9 +18230,7 @@ function summarise2(layout) {
18217
18230
  return parts.join(" ");
18218
18231
  }
18219
18232
  function fmtProb(n) {
18220
- if (n === 0) return "0";
18221
- if (n >= 1e-3) return String(parseFloat(n.toPrecision(3)));
18222
- return n.toExponential(2);
18233
+ return formatProbability(n);
18223
18234
  }
18224
18235
  function clip2(s, n) {
18225
18236
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
@@ -18505,40 +18516,40 @@ var BOWTIE_CONST = {
18505
18516
  LEGEND_H: 30
18506
18517
  };
18507
18518
  function dropBottom(barrier) {
18508
- const C2 = BOWTIE_CONST;
18509
- if (barrier.escalations.length === 0) return C2.NODE_H / 2;
18510
- let cursor = C2.EF_DROP;
18511
- let lastBottom = C2.NODE_H / 2;
18519
+ const C3 = BOWTIE_CONST;
18520
+ if (barrier.escalations.length === 0) return C3.NODE_H / 2;
18521
+ let cursor = C3.EF_DROP;
18522
+ let lastBottom = C3.NODE_H / 2;
18512
18523
  for (const esc of barrier.escalations) {
18513
- lastBottom = cursor + C2.NODE_H / 2;
18514
- cursor += C2.NODE_H + C2.EF_GAP;
18524
+ lastBottom = cursor + C3.NODE_H / 2;
18525
+ cursor += C3.NODE_H + C3.EF_GAP;
18515
18526
  for (const _ef of esc.barriers) {
18516
- lastBottom = cursor + C2.NODE_H / 2;
18517
- cursor += C2.NODE_H + C2.EF_GAP;
18527
+ lastBottom = cursor + C3.NODE_H / 2;
18528
+ cursor += C3.NODE_H + C3.EF_GAP;
18518
18529
  }
18519
18530
  }
18520
18531
  return lastBottom;
18521
18532
  }
18522
18533
  function bandLayout(lines) {
18523
- const C2 = BOWTIE_CONST;
18524
- const below = lines.map((l) => Math.max(...l.barriers.map(dropBottom), C2.NODE_H / 2));
18534
+ const C3 = BOWTIE_CONST;
18535
+ const below = lines.map((l) => Math.max(...l.barriers.map(dropBottom), C3.NODE_H / 2));
18525
18536
  const rel = [];
18526
18537
  for (let k = 0; k < lines.length; k++) {
18527
18538
  if (k === 0) {
18528
18539
  rel.push(0);
18529
18540
  continue;
18530
18541
  }
18531
- const pitch = Math.max(C2.ROW_BAND_H, below[k - 1] + C2.ROW_GAP + C2.NODE_H / 2);
18542
+ const pitch = Math.max(C3.ROW_BAND_H, below[k - 1] + C3.ROW_GAP + C3.NODE_H / 2);
18532
18543
  rel.push(rel[k - 1] + pitch);
18533
18544
  }
18534
18545
  const last = lines.length - 1;
18535
18546
  const blockMid = lines.length ? rel[last] / 2 : 0;
18536
- const aboveExtent = lines.length ? blockMid + C2.NODE_H / 2 : 0;
18547
+ const aboveExtent = lines.length ? blockMid + C3.NODE_H / 2 : 0;
18537
18548
  const belowExtent = lines.length ? rel[last] - blockMid + below[last] : 0;
18538
18549
  return { rel, below, blockMid, aboveExtent, belowExtent };
18539
18550
  }
18540
18551
  function layoutBowtie(ast) {
18541
- const C2 = BOWTIE_CONST;
18552
+ const C3 = BOWTIE_CONST;
18542
18553
  const boxes = [];
18543
18554
  const lines = [];
18544
18555
  const escalationLines = [];
@@ -18546,42 +18557,42 @@ function layoutBowtie(ast) {
18546
18557
  const conseqLines = ast.consequences.map((c) => ({ id: c.id, label: c.label, barriers: c.barriers }));
18547
18558
  const left = bandLayout(threatLines);
18548
18559
  const right = bandLayout(conseqLines);
18549
- const aboveCy = Math.max(left.aboveExtent, right.aboveExtent, C2.TOPEVENT_R);
18560
+ const aboveCy = Math.max(left.aboveExtent, right.aboveExtent, C3.TOPEVENT_R);
18550
18561
  const maxLeftChain = Math.max(0, ...threatLines.map((l) => l.barriers.length));
18551
- const innerOffset = C2.TOPEVENT_R + C2.CENTER_GUTTER + C2.BARRIER_W / 2;
18552
- const cx = C2.PAGE_PAD + C2.NODE_W / 2 + maxLeftChain * C2.WING_X_STEP + innerOffset;
18553
- const titleZone = ast.title ? C2.TITLE_H : 0;
18554
- const hazardReserve = ast.hazard ? C2.NODE_H + C2.HAZARD_GAP : 0;
18555
- const cy = C2.PAGE_PAD + titleZone + hazardReserve + aboveCy;
18556
- const topEvent = { cx, cy, r: C2.TOPEVENT_R, label: ast.topEvent };
18562
+ const innerOffset = C3.TOPEVENT_R + C3.CENTER_GUTTER + C3.BARRIER_W / 2;
18563
+ const cx = C3.PAGE_PAD + C3.NODE_W / 2 + maxLeftChain * C3.WING_X_STEP + innerOffset;
18564
+ const titleZone = ast.title ? C3.TITLE_H : 0;
18565
+ const hazardReserve = ast.hazard ? C3.NODE_H + C3.HAZARD_GAP : 0;
18566
+ const cy = C3.PAGE_PAD + titleZone + hazardReserve + aboveCy;
18567
+ const topEvent = { cx, cy, r: C3.TOPEVENT_R, label: ast.topEvent };
18557
18568
  let hazardTie;
18558
18569
  if (ast.hazard) {
18559
- const hcy = C2.PAGE_PAD + titleZone + C2.NODE_H / 2;
18560
- boxes.push({ id: "hazard", role: "hazard", label: ast.hazard, cx, cy: hcy, width: C2.HAZARD_W, height: C2.NODE_H });
18561
- hazardTie = { x: cx, y1: hcy + C2.NODE_H / 2, y2: cy - C2.TOPEVENT_R };
18570
+ const hcy = C3.PAGE_PAD + titleZone + C3.NODE_H / 2;
18571
+ boxes.push({ id: "hazard", role: "hazard", label: ast.hazard, cx, cy: hcy, width: C3.HAZARD_W, height: C3.NODE_H });
18572
+ hazardTie = { x: cx, y1: hcy + C3.NODE_H / 2, y2: cy - C3.TOPEVENT_R };
18562
18573
  }
18563
18574
  const emitWing = (wing, band, side) => {
18564
- const innerX = side === "prevent" ? cx - C2.TOPEVENT_R - C2.CENTER_GUTTER - C2.BARRIER_W / 2 : cx + C2.TOPEVENT_R + C2.CENTER_GUTTER + C2.BARRIER_W / 2;
18575
+ const innerX = side === "prevent" ? cx - C3.TOPEVENT_R - C3.CENTER_GUTTER - C3.BARRIER_W / 2 : cx + C3.TOPEVENT_R + C3.CENTER_GUTTER + C3.BARRIER_W / 2;
18565
18576
  wing.forEach((line2, k) => {
18566
18577
  const by = cy + (band.rel[k] - band.blockMid);
18567
18578
  const n = line2.barriers.length;
18568
18579
  const barrierX = line2.barriers.map((_b, j) => {
18569
18580
  if (side === "prevent") {
18570
18581
  const stepsFromInner = n - 1 - j;
18571
- return innerX - stepsFromInner * C2.WING_X_STEP;
18582
+ return innerX - stepsFromInner * C3.WING_X_STEP;
18572
18583
  }
18573
- return innerX + j * C2.WING_X_STEP;
18584
+ return innerX + j * C3.WING_X_STEP;
18574
18585
  });
18575
18586
  const outerBarrierX = side === "prevent" ? Math.min(...barrierX) : Math.max(...barrierX);
18576
- const headX = side === "prevent" ? outerBarrierX - C2.WING_X_STEP : outerBarrierX + C2.WING_X_STEP;
18587
+ const headX = side === "prevent" ? outerBarrierX - C3.WING_X_STEP : outerBarrierX + C3.WING_X_STEP;
18577
18588
  boxes.push({
18578
18589
  id: line2.id,
18579
18590
  role: side === "prevent" ? "threat" : "consequence",
18580
18591
  label: line2.label,
18581
18592
  cx: headX,
18582
18593
  cy: by,
18583
- width: C2.NODE_W,
18584
- height: C2.NODE_H
18594
+ width: C3.NODE_W,
18595
+ height: C3.NODE_H
18585
18596
  });
18586
18597
  line2.barriers.forEach((b, j) => {
18587
18598
  const bx = barrierX[j];
@@ -18591,71 +18602,71 @@ function layoutBowtie(ast) {
18591
18602
  label: b.label,
18592
18603
  cx: bx,
18593
18604
  cy: by,
18594
- width: C2.BARRIER_W,
18595
- height: C2.NODE_H,
18605
+ width: C3.BARRIER_W,
18606
+ height: C3.NODE_H,
18596
18607
  side,
18597
18608
  lineId: line2.id,
18598
18609
  order: j
18599
18610
  });
18600
18611
  if (b.escalations.length) {
18601
- let cursor = C2.EF_DROP;
18602
- let connectFromY = by + C2.NODE_H / 2;
18612
+ let cursor = C3.EF_DROP;
18613
+ let connectFromY = by + C3.NODE_H / 2;
18603
18614
  for (const esc of b.escalations) {
18604
18615
  const escCy = by + cursor;
18605
- escalationLines.push({ x: bx, y1: connectFromY, y2: escCy - C2.NODE_H / 2 });
18616
+ escalationLines.push({ x: bx, y1: connectFromY, y2: escCy - C3.NODE_H / 2 });
18606
18617
  boxes.push({
18607
18618
  id: esc.id,
18608
18619
  role: "escalation",
18609
18620
  label: esc.label,
18610
18621
  cx: bx,
18611
18622
  cy: escCy,
18612
- width: C2.NODE_W,
18613
- height: C2.NODE_H,
18623
+ width: C3.NODE_W,
18624
+ height: C3.NODE_H,
18614
18625
  lineId: line2.id,
18615
18626
  barrierId: b.id
18616
18627
  });
18617
- connectFromY = escCy + C2.NODE_H / 2;
18618
- cursor += C2.NODE_H + C2.EF_GAP;
18628
+ connectFromY = escCy + C3.NODE_H / 2;
18629
+ cursor += C3.NODE_H + C3.EF_GAP;
18619
18630
  for (const ef of esc.barriers) {
18620
18631
  const efCy = by + cursor;
18621
- escalationLines.push({ x: bx, y1: connectFromY, y2: efCy - C2.NODE_H / 2 });
18632
+ escalationLines.push({ x: bx, y1: connectFromY, y2: efCy - C3.NODE_H / 2 });
18622
18633
  boxes.push({
18623
18634
  id: ef.id,
18624
18635
  role: "ef-barrier",
18625
18636
  label: ef.label,
18626
18637
  cx: bx,
18627
18638
  cy: efCy,
18628
- width: C2.BARRIER_W,
18629
- height: C2.NODE_H,
18639
+ width: C3.BARRIER_W,
18640
+ height: C3.NODE_H,
18630
18641
  lineId: line2.id,
18631
18642
  escalationId: esc.id
18632
18643
  });
18633
- connectFromY = efCy + C2.NODE_H / 2;
18634
- cursor += C2.NODE_H + C2.EF_GAP;
18644
+ connectFromY = efCy + C3.NODE_H / 2;
18645
+ cursor += C3.NODE_H + C3.EF_GAP;
18635
18646
  }
18636
18647
  }
18637
18648
  }
18638
18649
  });
18639
18650
  const dy = by - cy;
18640
- const clampedDy = Math.max(-48, Math.min(C2.TOPEVENT_R - 4, dy));
18641
- const knotDx = Math.sqrt(Math.max(0, C2.TOPEVENT_R * C2.TOPEVENT_R - clampedDy * clampedDy));
18651
+ const clampedDy = Math.max(-48, Math.min(C3.TOPEVENT_R - 4, dy));
18652
+ const knotDx = Math.sqrt(Math.max(0, C3.TOPEVENT_R * C3.TOPEVENT_R - clampedDy * clampedDy));
18642
18653
  const pts = [];
18643
18654
  if (side === "prevent") {
18644
- pts.push([headX + C2.NODE_W / 2, by]);
18655
+ pts.push([headX + C3.NODE_W / 2, by]);
18645
18656
  const ordered = [...line2.barriers].map((_b, j) => barrierX[j]).sort((a, b) => a - b);
18646
18657
  for (const bx of ordered) {
18647
- pts.push([bx - C2.BARRIER_W / 2, by]);
18648
- pts.push([bx + C2.BARRIER_W / 2, by]);
18658
+ pts.push([bx - C3.BARRIER_W / 2, by]);
18659
+ pts.push([bx + C3.BARRIER_W / 2, by]);
18649
18660
  }
18650
18661
  pts.push([cx - knotDx, cy + clampedDy]);
18651
18662
  } else {
18652
18663
  pts.push([cx + knotDx, cy + clampedDy]);
18653
18664
  const ordered = [...line2.barriers].map((_b, j) => barrierX[j]).sort((a, b) => a - b);
18654
18665
  for (const bx of ordered) {
18655
- pts.push([bx - C2.BARRIER_W / 2, by]);
18656
- pts.push([bx + C2.BARRIER_W / 2, by]);
18666
+ pts.push([bx - C3.BARRIER_W / 2, by]);
18667
+ pts.push([bx + C3.BARRIER_W / 2, by]);
18657
18668
  }
18658
- pts.push([headX - C2.NODE_W / 2, by]);
18669
+ pts.push([headX - C3.NODE_W / 2, by]);
18659
18670
  }
18660
18671
  const path2 = pts.map((p, idx) => `${idx === 0 ? "M" : "L"} ${r3(p[0])} ${r3(p[1])}`).join(" ");
18661
18672
  const ax = side === "prevent" ? cx - knotDx : cx + knotDx;
@@ -18670,9 +18681,9 @@ function layoutBowtie(ast) {
18670
18681
  maxY = Math.max(maxY, y);
18671
18682
  };
18672
18683
  for (const b of boxes) bump(b.cx + b.width / 2, b.cy + b.height / 2);
18673
- bump(cx + C2.TOPEVENT_R, cy + C2.TOPEVENT_R);
18674
- if (ast.title) bump(C2.PAGE_PAD + ast.title.length * 9, 0);
18675
- const legendBand = ast.legend === "off" ? 0 : C2.LEGEND_H;
18684
+ bump(cx + C3.TOPEVENT_R, cy + C3.TOPEVENT_R);
18685
+ if (ast.title) bump(C3.PAGE_PAD + ast.title.length * 9, 0);
18686
+ const legendBand = ast.legend === "off" ? 0 : C3.LEGEND_H;
18676
18687
  return {
18677
18688
  ast,
18678
18689
  topEvent,
@@ -18680,8 +18691,8 @@ function layoutBowtie(ast) {
18680
18691
  lines,
18681
18692
  escalationLines,
18682
18693
  ...hazardTie ? { hazardTie } : {},
18683
- width: Math.ceil(maxX + C2.PAGE_PAD),
18684
- height: Math.ceil(maxY + C2.PAGE_PAD + legendBand)
18694
+ width: Math.ceil(maxX + C3.PAGE_PAD),
18695
+ height: Math.ceil(maxY + C3.PAGE_PAD + legendBand)
18685
18696
  };
18686
18697
  }
18687
18698
  function r3(n) {
@@ -19172,7 +19183,7 @@ var EVENTTREE_CONST = {
19172
19183
  LEAF_LINE_H: 14
19173
19184
  };
19174
19185
  function layoutEventTree(ast) {
19175
- const C2 = EVENTTREE_CONST;
19186
+ const C3 = EVENTTREE_CONST;
19176
19187
  const analysis = analyseEventTree(ast);
19177
19188
  const seqs = analysis.sequences;
19178
19189
  const root = { children: [], y: 0, rowLo: 0, rowHi: 0 };
@@ -19204,15 +19215,15 @@ function layoutEventTree(ast) {
19204
19215
  };
19205
19216
  assignRows(root);
19206
19217
  const rowCount = Math.max(nextRow, 1);
19207
- const titleH = ast.title ? C2.TITLE_H : 0;
19208
- const headerY = C2.CANVAS_PAD + titleH + C2.HEADER_H * 0.6;
19209
- const bodyTopY = C2.CANVAS_PAD + titleH + C2.HEADER_H;
19210
- const rowY = (row) => bodyTopY + C2.ROW_H / 2 + row * C2.ROW_H;
19211
- const ieX2 = C2.IE_LEFT + C2.IE_STUB;
19212
- const gridX = (col) => ieX2 + (col + 1) * C2.COL_W;
19218
+ const titleH = ast.title ? C3.TITLE_H : 0;
19219
+ const headerY = C3.CANVAS_PAD + titleH + C3.HEADER_H * 0.6;
19220
+ const bodyTopY = C3.CANVAS_PAD + titleH + C3.HEADER_H;
19221
+ const rowY = (row) => bodyTopY + C3.ROW_H / 2 + row * C3.ROW_H;
19222
+ const ieX2 = C3.IE_LEFT + C3.IE_STUB;
19223
+ const gridX = (col) => ieX2 + (col + 1) * C3.COL_W;
19213
19224
  const nFns = ast.functions.length;
19214
19225
  const lastGridX = nFns > 0 ? gridX(nFns - 1) : ieX2;
19215
- const outcomeX = lastGridX + C2.OUTCOME_GAP;
19226
+ const outcomeX = lastGridX + C3.OUTCOME_GAP;
19216
19227
  const assignY = (n) => {
19217
19228
  for (const c of n.children) assignY(c);
19218
19229
  n.y = (rowY(n.rowLo) + rowY(n.rowHi)) / 2;
@@ -19235,7 +19246,7 @@ function layoutEventTree(ast) {
19235
19246
  path: path2,
19236
19247
  // Label sits above the horizontal run leading into this node.
19237
19248
  labelX: (riserX + parentX) / 2,
19238
- labelY: c.y + C2.FORK_LABEL_DY
19249
+ labelY: c.y + C3.FORK_LABEL_DY
19239
19250
  });
19240
19251
  walk(c, x, c.y);
19241
19252
  }
@@ -19269,7 +19280,7 @@ function layoutEventTree(ast) {
19269
19280
  headers.push({
19270
19281
  kind: "initiating",
19271
19282
  label: "Initiating Event",
19272
- cx: C2.IE_LEFT + C2.IE_STUB / 2
19283
+ cx: C3.IE_LEFT + C3.IE_STUB / 2
19273
19284
  });
19274
19285
  ast.functions.forEach((fn, col) => {
19275
19286
  headers.push({
@@ -19279,16 +19290,16 @@ function layoutEventTree(ast) {
19279
19290
  gridX: gridX(col)
19280
19291
  });
19281
19292
  });
19282
- headers.push({ kind: "outcome", label: "Outcome", cx: outcomeX + C2.OUTCOME_W * 0.32 });
19283
- headers.push({ kind: "frequency", label: "Frequency", cx: outcomeX + C2.OUTCOME_W * 0.82 });
19284
- const gridBottom = rowY(rowCount - 1) + C2.ROW_H / 2;
19293
+ headers.push({ kind: "outcome", label: "Outcome", cx: outcomeX + C3.OUTCOME_W * 0.32 });
19294
+ headers.push({ kind: "frequency", label: "Frequency", cx: outcomeX + C3.OUTCOME_W * 0.82 });
19295
+ const gridBottom = rowY(rowCount - 1) + C3.ROW_H / 2;
19285
19296
  const gridLines = ast.functions.map((_, col) => ({
19286
19297
  x: gridX(col),
19287
19298
  y1: bodyTopY,
19288
19299
  y2: gridBottom
19289
19300
  }));
19290
- const width = outcomeX + C2.OUTCOME_W + C2.CANVAS_PAD;
19291
- const height = gridBottom + C2.CANVAS_PAD;
19301
+ const width = outcomeX + C3.OUTCOME_W + C3.CANVAS_PAD;
19302
+ const height = gridBottom + C3.CANVAS_PAD;
19292
19303
  return {
19293
19304
  ast,
19294
19305
  analysis,
@@ -19296,10 +19307,10 @@ function layoutEventTree(ast) {
19296
19307
  forks,
19297
19308
  leaves,
19298
19309
  initiating: {
19299
- x1: C2.IE_LEFT,
19310
+ x1: C3.IE_LEFT,
19300
19311
  x2: ieX2,
19301
19312
  y: root.y,
19302
- labelX: C2.IE_LEFT,
19313
+ labelX: C3.IE_LEFT,
19303
19314
  labelY: root.y - 10,
19304
19315
  freqY: root.y + 16
19305
19316
  },
@@ -20050,7 +20061,7 @@ var FMEA_CONST = {
20050
20061
  AP_COL_W: 46
20051
20062
  };
20052
20063
  function buildColumnSpecs(hasActions, rank) {
20053
- const C2 = FMEA_CONST;
20064
+ const C3 = FMEA_CONST;
20054
20065
  const specs = [
20055
20066
  { key: "no", label: "#", width: 28, align: "middle", numeric: true, field: (r7) => String(r7.index) },
20056
20067
  {
@@ -20071,9 +20082,9 @@ function buildColumnSpecs(hasActions, rank) {
20071
20082
  numeric: false,
20072
20083
  field: (r7) => r7.effects.length > 1 ? r7.effects.join("; ") : r7.effect
20073
20084
  },
20074
- { key: "sev", label: "S", width: C2.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.sev) },
20085
+ { key: "sev", label: "S", width: C3.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.sev) },
20075
20086
  { key: "cause", label: "Cause(s)", width: 120, align: "start", numeric: false, field: (r7) => r7.cause },
20076
- { key: "occ", label: "O", width: C2.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.occ) },
20087
+ { key: "occ", label: "O", width: C3.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.occ) },
20077
20088
  {
20078
20089
  key: "controls",
20079
20090
  label: "Current Controls",
@@ -20082,9 +20093,9 @@ function buildColumnSpecs(hasActions, rank) {
20082
20093
  numeric: false,
20083
20094
  field: (r7) => controlsText(r7)
20084
20095
  },
20085
- { key: "det", label: "D", width: C2.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.det) },
20086
- { key: "rpn", label: "RPN", width: C2.RPN_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.rpn) },
20087
- { key: "ap", label: "AP", width: C2.AP_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => r7.ap }
20096
+ { key: "det", label: "D", width: C3.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.det) },
20097
+ { key: "rpn", label: "RPN", width: C3.RPN_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.rpn) },
20098
+ { key: "ap", label: "AP", width: C3.AP_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => r7.ap }
20088
20099
  ];
20089
20100
  if (hasActions) {
20090
20101
  specs.push(
@@ -20100,7 +20111,7 @@ function buildColumnSpecs(hasActions, rank) {
20100
20111
  {
20101
20112
  key: "rsev",
20102
20113
  label: "S",
20103
- width: C2.NUM_COL_W,
20114
+ width: C3.NUM_COL_W,
20104
20115
  align: "middle",
20105
20116
  band: "after",
20106
20117
  numeric: true,
@@ -20110,7 +20121,7 @@ function buildColumnSpecs(hasActions, rank) {
20110
20121
  {
20111
20122
  key: "rocc",
20112
20123
  label: "O",
20113
- width: C2.NUM_COL_W,
20124
+ width: C3.NUM_COL_W,
20114
20125
  align: "middle",
20115
20126
  band: "after",
20116
20127
  numeric: true,
@@ -20120,7 +20131,7 @@ function buildColumnSpecs(hasActions, rank) {
20120
20131
  {
20121
20132
  key: "rdet",
20122
20133
  label: "D",
20123
- width: C2.NUM_COL_W,
20134
+ width: C3.NUM_COL_W,
20124
20135
  align: "middle",
20125
20136
  band: "after",
20126
20137
  numeric: true,
@@ -20130,7 +20141,7 @@ function buildColumnSpecs(hasActions, rank) {
20130
20141
  {
20131
20142
  key: "rrpn",
20132
20143
  label: "RPN",
20133
- width: C2.RPN_COL_W,
20144
+ width: C3.RPN_COL_W,
20134
20145
  align: "middle",
20135
20146
  band: "after",
20136
20147
  numeric: true,
@@ -20140,7 +20151,7 @@ function buildColumnSpecs(hasActions, rank) {
20140
20151
  {
20141
20152
  key: "rap",
20142
20153
  label: "AP",
20143
- width: C2.AP_COL_W,
20154
+ width: C3.AP_COL_W,
20144
20155
  align: "middle",
20145
20156
  band: "after",
20146
20157
  numeric: true,
@@ -20212,15 +20223,15 @@ function apRiskClass(ap) {
20212
20223
  return "ap-low";
20213
20224
  }
20214
20225
  function layoutFmea(ast, analysisIn) {
20215
- const C2 = FMEA_CONST;
20226
+ const C3 = FMEA_CONST;
20216
20227
  const analysis = analysisIn ?? analyseFmea(ast);
20217
20228
  const specs = buildColumnSpecs(analysis.hasActions, ast.rank);
20218
20229
  const metaKeys = Object.keys(ast.metadata);
20219
20230
  const legendLines = (ast.target !== void 0 || ast.acceptable !== void 0 ? 1 : 0) + (ast.flag ? 1 : 0);
20220
20231
  const metaRows = Math.ceil(metaKeys.length / 2) + legendLines;
20221
- const titleH = ast.title ? C2.TITLE_H : 0;
20222
- const metaH = metaRows > 0 ? metaRows * C2.META_LINE_H + 6 : 0;
20223
- const startX = C2.CANVAS_PAD;
20232
+ const titleH = ast.title ? C3.TITLE_H : 0;
20233
+ const metaH = metaRows > 0 ? metaRows * C3.META_LINE_H + 6 : 0;
20234
+ const startX = C3.CANVAS_PAD;
20224
20235
  let x = startX;
20225
20236
  const columns = [];
20226
20237
  const colX = {};
@@ -20239,15 +20250,15 @@ function layoutFmea(ast, analysisIn) {
20239
20250
  }
20240
20251
  const tableW = x - startX;
20241
20252
  const hasBands = analysis.hasActions;
20242
- const bandH = hasBands ? C2.BAND_H : 0;
20243
- const topY = C2.CANVAS_PAD + titleH + metaH;
20253
+ const bandH = hasBands ? C3.BAND_H : 0;
20254
+ const topY = C3.CANVAS_PAD + titleH + metaH;
20244
20255
  const bandY = topY;
20245
20256
  const headerY = topY + bandH;
20246
- const bodyY = headerY + C2.HEADER_H;
20257
+ const bodyY = headerY + C3.HEADER_H;
20247
20258
  const cells = [];
20248
20259
  const rowHeights = [];
20249
20260
  const rowY = [];
20250
- const innerW = (s) => s.width - C2.CELL_PAD_X * 2;
20261
+ const innerW = (s) => s.width - C3.CELL_PAD_X * 2;
20251
20262
  const wrapped = analysis.rows.map(
20252
20263
  (row) => specs.map((s) => ({ spec: s, row, lines: wrapText3(s.field(row), innerW(s)) }))
20253
20264
  );
@@ -20263,7 +20274,7 @@ function layoutFmea(ast, analysisIn) {
20263
20274
  return w.lines.length;
20264
20275
  });
20265
20276
  const maxLines = Math.max(1, ...lineCounts);
20266
- const h = Math.max(C2.ROW_MIN_H, maxLines * C2.LINE_H + C2.CELL_PAD_Y * 2);
20277
+ const h = Math.max(C3.ROW_MIN_H, maxLines * C3.LINE_H + C3.CELL_PAD_Y * 2);
20267
20278
  rowHeights.push(h);
20268
20279
  });
20269
20280
  let yCursor = bodyY;
@@ -20313,14 +20324,14 @@ function layoutFmea(ast, analysisIn) {
20313
20324
  if (before) bands.push({ label: "BEFORE ACTION", x: before.x, width: before.w, y: bandY, height: bandH });
20314
20325
  if (after) bands.push({ label: "AFTER ACTION", x: after.x, width: after.w, y: bandY, height: bandH });
20315
20326
  }
20316
- const totalH = (rowY.length ? rowY[rowY.length - 1] + rowHeights[rowHeights.length - 1] : bodyY) + C2.CANVAS_PAD;
20317
- const width = tableW + C2.CANVAS_PAD * 2;
20327
+ const totalH = (rowY.length ? rowY[rowY.length - 1] + rowHeights[rowHeights.length - 1] : bodyY) + C3.CANVAS_PAD;
20328
+ const width = tableW + C3.CANVAS_PAD * 2;
20318
20329
  return {
20319
20330
  ast,
20320
20331
  analysis,
20321
20332
  columns,
20322
20333
  headerY,
20323
- headerH: C2.HEADER_H,
20334
+ headerH: C3.HEADER_H,
20324
20335
  bodyY,
20325
20336
  rowHeights,
20326
20337
  rowY,
@@ -20682,6 +20693,7 @@ function parseRbd(text2) {
20682
20693
  seenIds.add(id);
20683
20694
  let label;
20684
20695
  let R;
20696
+ let dist;
20685
20697
  if (peek()?.t === "string") {
20686
20698
  label = tokens[pos++].v;
20687
20699
  }
@@ -20690,10 +20702,16 @@ function parseRbd(text2) {
20690
20702
  const attr = parseAttr(w);
20691
20703
  if (!attr) break;
20692
20704
  pos++;
20693
- if (attr.key === "p") R = clamp01(1 - attr.value, w, warnings);
20694
- else R = clamp01(attr.value, w, warnings);
20705
+ if (attr.kind === "dist") dist = attr.dist;
20706
+ else R = clamp01(attr.failure ? 1 - attr.value : attr.value, w, warnings);
20695
20707
  }
20696
- return { kind: "block", id, ...label !== void 0 ? { label } : {}, ...R !== void 0 ? { R } : {} };
20708
+ return {
20709
+ kind: "block",
20710
+ id,
20711
+ ...label !== void 0 ? { label } : {},
20712
+ ...R !== void 0 ? { R } : {},
20713
+ ...dist !== void 0 ? { dist } : {}
20714
+ };
20697
20715
  };
20698
20716
  const parseGroup = (kwRaw) => {
20699
20717
  const kw = kwRaw.toLowerCase();
@@ -20767,10 +20785,19 @@ function parseRbd(text2) {
20767
20785
  } else {
20768
20786
  root = { kind: "series", children: top };
20769
20787
  }
20788
+ let mission;
20789
+ if (metadata.mission !== void 0) {
20790
+ const v = parseFloat(metadata.mission);
20791
+ if (!Number.isFinite(v) || v < 0) {
20792
+ throw new RbdParseError(`mission time must be a non-negative number (got '${metadata.mission}')`);
20793
+ }
20794
+ mission = v;
20795
+ }
20770
20796
  return {
20771
20797
  type: "rbd",
20772
20798
  ...title2 ? { title: title2 } : {},
20773
20799
  root,
20800
+ ...mission !== void 0 ? { mission } : {},
20774
20801
  warnings,
20775
20802
  ...Object.keys(metadata).length > 0 ? { metadata } : {}
20776
20803
  };
@@ -20823,11 +20850,10 @@ function tokenize6(src) {
20823
20850
  }
20824
20851
  function stripBodyDirectives(body, metadata) {
20825
20852
  return body.split("\n").filter((line2) => {
20826
- const m = line2.match(/^\s*(title|standard|note)\s*:\s*(.+)$/i);
20853
+ const m = line2.match(/^\s*(title|standard|note|mission)\s*:\s*(.+)$/i);
20827
20854
  if (m) {
20828
20855
  const key = m[1].toLowerCase();
20829
- if (key !== "title") metadata[key] = m[2].trim();
20830
- else metadata.title = m[2].trim();
20856
+ metadata[key] = m[2].trim();
20831
20857
  return false;
20832
20858
  }
20833
20859
  return true;
@@ -20839,15 +20865,33 @@ function extractQuoted(s) {
20839
20865
  return s.length > 0 ? s.trim() : void 0;
20840
20866
  }
20841
20867
  function parseAttr(w) {
20868
+ const wb = w.match(/^weibull\s*[=:]\s*(.+)$/i);
20869
+ if (wb) {
20870
+ const parts = wb[1].split(",").map((s) => parseFloat(s.trim()));
20871
+ if (parts.length === 2 && parts.every((x) => Number.isFinite(x) && x > 0)) {
20872
+ return { kind: "dist", dist: { kind: "weibull", beta: parts[0], eta: parts[1] } };
20873
+ }
20874
+ return null;
20875
+ }
20876
+ const rt = w.match(/^rate\s*[=:]\s*(.+)$/i);
20877
+ if (rt) {
20878
+ const v = parseFloat(rt[1].trim());
20879
+ return Number.isFinite(v) && v >= 0 ? { kind: "dist", dist: { kind: "exp", rate: v } } : null;
20880
+ }
20881
+ const mt = w.match(/^(mtbf|mttf)\s*[=:]\s*(.+)$/i);
20882
+ if (mt) {
20883
+ const v = parseFloat(mt[2].trim());
20884
+ return Number.isFinite(v) && v > 0 ? { kind: "dist", dist: { kind: "exp", rate: 1 / v } } : null;
20885
+ }
20842
20886
  const m = w.match(/^(R|r|p|prob|q)\s*[=:]\s*(.+)$/);
20843
20887
  if (m) {
20844
20888
  const key = m[1].toLowerCase();
20845
20889
  const value = parseNum(m[2]);
20846
20890
  if (value === void 0) return null;
20847
- return { key: key === "p" || key === "q" ? "p" : "R", value };
20891
+ return { kind: "R", value, failure: key === "p" || key === "q" };
20848
20892
  }
20849
20893
  const bare = parseNum(w);
20850
- if (bare !== void 0) return { key: "R", value: bare };
20894
+ if (bare !== void 0) return { kind: "R", value: bare, failure: false };
20851
20895
  return null;
20852
20896
  }
20853
20897
  function parseNum(s) {
@@ -20876,8 +20920,11 @@ var KOFN_ENUM_CAP = 18;
20876
20920
  function analyseRbd(ast) {
20877
20921
  const notes = [];
20878
20922
  const warnings = [...ast.warnings];
20923
+ if (ast.mission !== void 0) {
20924
+ notes.push(`Mission time t = ${ast.mission}; block reliabilities with a rate/MTBF/Weibull are evaluated as R(t).`);
20925
+ }
20879
20926
  const blocks = [];
20880
- collectBlocks(ast.root, blocks);
20927
+ collectBlocks(ast.root, blocks, ast.mission, warnings);
20881
20928
  const missing = blocks.filter((b) => b.R === void 0).map((b) => b.id);
20882
20929
  const baseEnv = new Map(blocks.map((b) => [b.id, b.R]));
20883
20930
  const systemReliability = evalStructure(ast.root, baseEnv, notes);
@@ -20893,10 +20940,15 @@ function analyseRbd(ast) {
20893
20940
  const rDown = evalStructure(ast.root, down, notes);
20894
20941
  const importance = rUp !== void 0 && rDown !== void 0 ? rUp - rDown : void 0;
20895
20942
  const isSpof = rDown === 0;
20943
+ let criticality;
20944
+ if (importance !== void 0 && b.R !== void 0 && systemReliability < 1) {
20945
+ criticality = importance * (1 - b.R) / (1 - systemReliability);
20946
+ }
20896
20947
  return {
20897
20948
  id: b.id,
20898
20949
  ...b.R !== void 0 ? { R: b.R } : {},
20899
20950
  ...importance !== void 0 ? { importance } : {},
20951
+ ...criticality !== void 0 ? { criticality } : {},
20900
20952
  isSpof
20901
20953
  };
20902
20954
  });
@@ -20921,12 +20973,25 @@ function analyseRbd(ast) {
20921
20973
  notes
20922
20974
  };
20923
20975
  }
20924
- function collectBlocks(s, out) {
20976
+ function collectBlocks(s, out, mission, warnings) {
20925
20977
  if (s.kind === "block") {
20926
- out.push({ id: s.id, ...s.R !== void 0 ? { R: s.R } : {} });
20978
+ const R = resolveBlockR(s, mission, warnings);
20979
+ out.push({ id: s.id, ...R !== void 0 ? { R } : {} });
20927
20980
  return;
20928
20981
  }
20929
- for (const c of s.children) collectBlocks(c, out);
20982
+ for (const c of s.children) collectBlocks(c, out, mission, warnings);
20983
+ }
20984
+ function resolveBlockR(b, mission, warnings) {
20985
+ if (b.dist) {
20986
+ if (mission === void 0) {
20987
+ warnings.push(`Block "${b.id}" has a failure distribution but no mission time \u2014 add 'mission: <t>' to evaluate R(t)${b.R !== void 0 ? ", falling back to its constant R" : ""}.`);
20988
+ return b.R;
20989
+ }
20990
+ const t = mission;
20991
+ if (b.dist.kind === "exp") return Math.exp(-b.dist.rate * t);
20992
+ return Math.exp(-Math.pow(t / b.dist.eta, b.dist.beta));
20993
+ }
20994
+ return b.R;
20930
20995
  }
20931
20996
  function evalStructure(s, env, notes) {
20932
20997
  if (s.kind === "block") return env.get(s.id);
@@ -20989,11 +21054,11 @@ var RBD_CONST = {
20989
21054
  HEADER_H: 26
20990
21055
  };
20991
21056
  function blockWidth(label) {
20992
- const C2 = RBD_CONST;
20993
- return Math.min(C2.BLOCK_MAX_W, Math.max(C2.BLOCK_MIN_W, Math.ceil(label.length * C2.CHAR_W) + 2 * C2.PAD_X));
21057
+ const C3 = RBD_CONST;
21058
+ return Math.min(C3.BLOCK_MAX_W, Math.max(C3.BLOCK_MIN_W, Math.ceil(label.length * C3.CHAR_W) + 2 * C3.PAD_X));
20994
21059
  }
20995
21060
  function layoutRbd(ast) {
20996
- const C2 = RBD_CONST;
21061
+ const C3 = RBD_CONST;
20997
21062
  const analysis = analyseRbd(ast);
20998
21063
  const spof = new Set(analysis.blocks.filter((b) => b.isSpof).map((b) => b.id));
20999
21064
  const rById = new Map(analysis.blocks.map((b) => [b.id, b.R]));
@@ -21003,18 +21068,18 @@ function layoutRbd(ast) {
21003
21068
  const marks = [];
21004
21069
  const measure = (s) => {
21005
21070
  if (s.kind === "block") {
21006
- return { s, w: blockWidth(s.label ?? s.id), h: C2.BLOCK_H, children: [] };
21071
+ return { s, w: blockWidth(s.label ?? s.id), h: C3.BLOCK_H, children: [] };
21007
21072
  }
21008
21073
  const children = s.children.map(measure);
21009
- if (children.length === 0) return { s, w: C2.BLOCK_MIN_W, h: C2.BLOCK_H, children };
21074
+ if (children.length === 0) return { s, w: C3.BLOCK_MIN_W, h: C3.BLOCK_H, children };
21010
21075
  if (s.kind === "series") {
21011
- const w2 = children.reduce((acc, c) => acc + c.w, 0) + C2.H_GAP * (children.length - 1);
21076
+ const w2 = children.reduce((acc, c) => acc + c.w, 0) + C3.H_GAP * (children.length - 1);
21012
21077
  const h2 = Math.max(...children.map((c) => c.h));
21013
21078
  return { s, w: w2, h: h2, children };
21014
21079
  }
21015
21080
  const innerW = Math.max(...children.map((c) => c.w));
21016
- const w = innerW + 2 * C2.SPLIT_STUB;
21017
- const h = children.reduce((acc, c) => acc + c.h, 0) + C2.V_GAP * (children.length - 1);
21081
+ const w = innerW + 2 * C3.SPLIT_STUB;
21082
+ const h = children.reduce((acc, c) => acc + c.h, 0) + C3.V_GAP * (children.length - 1);
21018
21083
  return { s, w, h, children };
21019
21084
  };
21020
21085
  const place = (m, x, yc2) => {
@@ -21024,9 +21089,9 @@ function layoutRbd(ast) {
21024
21089
  blocks.push({
21025
21090
  block: s,
21026
21091
  x,
21027
- y: yc2 - C2.BLOCK_H / 2,
21092
+ y: yc2 - C3.BLOCK_H / 2,
21028
21093
  width: m.w,
21029
- height: C2.BLOCK_H,
21094
+ height: C3.BLOCK_H,
21030
21095
  ...r7 !== void 0 ? { R: r7 } : {},
21031
21096
  isSpof: spof.has(s.id),
21032
21097
  critical: analysis.criticalBlock === s.id
@@ -21044,14 +21109,14 @@ function layoutRbd(ast) {
21044
21109
  if (prevExit !== null) wires.push({ path: `M ${r6(prevExit)} ${r6(yc2)} L ${r6(ep2.entryX)} ${r6(yc2)}` });
21045
21110
  prevExit = ep2.exitX;
21046
21111
  lastExit = ep2.exitX;
21047
- cursor = ep2.exitX + C2.H_GAP;
21112
+ cursor = ep2.exitX + C3.H_GAP;
21048
21113
  });
21049
21114
  return { entryX: firstEntry, exitX: lastExit };
21050
21115
  }
21051
21116
  const innerW = Math.max(...m.children.map((c) => c.w));
21052
- const splitX = x + C2.NODE_R;
21053
- const mergeX = x + m.w - C2.NODE_R;
21054
- const childBandX = x + C2.SPLIT_STUB;
21117
+ const splitX = x + C3.NODE_R;
21118
+ const mergeX = x + m.w - C3.NODE_R;
21119
+ const childBandX = x + C3.SPLIT_STUB;
21055
21120
  nodes.push({ kind: "split", x: splitX, y: yc2 });
21056
21121
  nodes.push({ kind: "join", x: mergeX, y: yc2 });
21057
21122
  let runY = yc2 - m.h / 2;
@@ -21061,7 +21126,7 @@ function layoutRbd(ast) {
21061
21126
  const ep2 = place(cm, childStartX, childYc);
21062
21127
  wires.push({ path: `M ${r6(splitX)} ${r6(yc2)} L ${r6(splitX)} ${r6(childYc)} L ${r6(ep2.entryX)} ${r6(childYc)}` });
21063
21128
  wires.push({ path: `M ${r6(ep2.exitX)} ${r6(childYc)} L ${r6(mergeX)} ${r6(childYc)} L ${r6(mergeX)} ${r6(yc2)}` });
21064
- runY += cm.h + C2.V_GAP;
21129
+ runY += cm.h + C3.V_GAP;
21065
21130
  }
21066
21131
  if (s.kind === "kofn") {
21067
21132
  marks.push({ x: mergeX + 6, y: yc2 - m.h / 2 - 6, text: `${s.k}/${s.n ?? m.children.length}` });
@@ -21069,12 +21134,12 @@ function layoutRbd(ast) {
21069
21134
  return { entryX: splitX, exitX: mergeX };
21070
21135
  };
21071
21136
  const rootM = measure(ast.root);
21072
- const headerH = (ast.title ? C2.TITLE_H : 0) + C2.HEADER_H;
21073
- const yc = C2.CANVAS_PAD + headerH + rootM.h / 2;
21074
- const originX = C2.CANVAS_PAD + C2.TERM_STUB;
21137
+ const headerH = (ast.title ? C3.TITLE_H : 0) + C3.HEADER_H;
21138
+ const yc = C3.CANVAS_PAD + headerH + rootM.h / 2;
21139
+ const originX = C3.CANVAS_PAD + C3.TERM_STUB;
21075
21140
  const ep = place(rootM, originX, yc);
21076
- const inX = C2.CANVAS_PAD;
21077
- const outX = ep.exitX + C2.TERM_STUB;
21141
+ const inX = C3.CANVAS_PAD;
21142
+ const outX = ep.exitX + C3.TERM_STUB;
21078
21143
  nodes.push({ kind: "in", x: inX, y: yc });
21079
21144
  nodes.push({ kind: "out", x: outX, y: yc });
21080
21145
  wires.push({ path: `M ${r6(inX)} ${r6(yc)} L ${r6(ep.entryX)} ${r6(yc)}` });
@@ -21084,7 +21149,7 @@ function layoutRbd(ast) {
21084
21149
  for (const b of blocks) {
21085
21150
  maxX = Math.max(maxX, b.x + b.width);
21086
21151
  const capLines = (b.R !== void 0 ? 1 : 0) + (b.block.label && b.block.label !== b.block.id ? 1 : 0);
21087
- maxY = Math.max(maxY, b.y + b.height + (capLines > 0 ? C2.CAP_GAP + capLines * C2.CAP_LINE_H : 0));
21152
+ maxY = Math.max(maxY, b.y + b.height + (capLines > 0 ? C3.CAP_GAP + capLines * C3.CAP_LINE_H : 0));
21088
21153
  }
21089
21154
  for (const mk of marks) maxX = Math.max(maxX, mk.x + 24);
21090
21155
  return {
@@ -21094,8 +21159,8 @@ function layoutRbd(ast) {
21094
21159
  nodes,
21095
21160
  wires,
21096
21161
  marks,
21097
- width: Math.ceil(maxX + C2.CANVAS_PAD),
21098
- height: Math.ceil(maxY + C2.CANVAS_PAD)
21162
+ width: Math.ceil(maxX + C3.CANVAS_PAD),
21163
+ height: Math.ceil(maxY + C3.CANVAS_PAD)
21099
21164
  };
21100
21165
  }
21101
21166
  function r6(n) {
@@ -21157,7 +21222,7 @@ function renderRbdLayout(layout, config) {
21157
21222
  class: "sx-rbd-rsys",
21158
21223
  "text-anchor": "middle"
21159
21224
  },
21160
- systemLabel(analysis)
21225
+ systemLabel(analysis, ast.mission)
21161
21226
  )
21162
21227
  );
21163
21228
  for (const w of layout.wires) inner.push(path({ d: w.path, class: "sx-rbd-wire" }));
@@ -21227,12 +21292,16 @@ function renderBlock(b) {
21227
21292
  parts
21228
21293
  );
21229
21294
  }
21230
- function systemLabel(analysis) {
21295
+ function systemLabel(analysis, mission) {
21231
21296
  if (analysis.systemReliability === void 0) {
21232
21297
  const miss = analysis.missing.length > 0 ? ` \u2014 missing R on ${analysis.missing.join(", ")}` : "";
21233
21298
  return `System reliability: n/a${miss}`;
21234
21299
  }
21235
- return `System reliability R = ${fmtR(analysis.systemReliability)}`;
21300
+ const arg = mission !== void 0 ? `(t=${fmtVal3(mission)})` : "";
21301
+ return `System reliability R${arg} = ${fmtR(analysis.systemReliability)}`;
21302
+ }
21303
+ function fmtVal3(n) {
21304
+ return String(parseFloat(n.toFixed(2)));
21236
21305
  }
21237
21306
  function fmtR(n) {
21238
21307
  if (n >= 1) return "1";
@@ -21290,6 +21359,1245 @@ var rbd = {
21290
21359
  }
21291
21360
  };
21292
21361
 
21362
+ // src/diagrams/comparison/parser.ts
21363
+ var ComparisonParseError = class extends Error {
21364
+ constructor(message, line2) {
21365
+ super(line2 ? `Line ${line2}: ${message}` : message);
21366
+ this.line = line2;
21367
+ this.name = "ComparisonParseError";
21368
+ }
21369
+ line;
21370
+ };
21371
+ var MODES = [
21372
+ "tchart",
21373
+ "pros-cons",
21374
+ "matrix",
21375
+ "decision",
21376
+ "double-bubble"
21377
+ ];
21378
+ function parseComparison(text2) {
21379
+ const ast = {
21380
+ type: "comparison",
21381
+ mode: "tchart",
21382
+ columns: [],
21383
+ pros: [],
21384
+ cons: [],
21385
+ options: [],
21386
+ criteria: [],
21387
+ legend: "on",
21388
+ warnings: []
21389
+ };
21390
+ const rawLines = text2.split(/\r?\n/);
21391
+ let i = 0;
21392
+ let explicitMode;
21393
+ while (i < rawLines.length) {
21394
+ const t = stripComment8(rawLines[i] ?? "").trim();
21395
+ if (t === "") {
21396
+ i++;
21397
+ continue;
21398
+ }
21399
+ const h = /^(comparison|compare|vs|tchart|t-chart|pugh|decision-matrix|decisionmatrix)\b(.*)$/i.exec(t);
21400
+ if (h) {
21401
+ const head = h[1].toLowerCase();
21402
+ if (head === "tchart" || head === "t-chart") explicitMode = "tchart";
21403
+ else if (head === "pugh" || head === "decision-matrix" || head === "decisionmatrix")
21404
+ explicitMode = "decision";
21405
+ const q = matchQuoted6(h[2].trim());
21406
+ if (q) ast.title = q.value;
21407
+ i++;
21408
+ }
21409
+ break;
21410
+ }
21411
+ let curColumn = null;
21412
+ let curCriterion = null;
21413
+ let colCount = 0;
21414
+ let optCount = 0;
21415
+ let critCount = 0;
21416
+ const bubble = { left: "", right: "", shared: [], leftOnly: [], rightOnly: [] };
21417
+ for (; i < rawLines.length; i++) {
21418
+ const t = stripComment8(rawLines[i] ?? "").trim();
21419
+ if (t === "") continue;
21420
+ const lineNo = i + 1;
21421
+ if (/^mode\s*:/i.test(t)) {
21422
+ const v = afterColon6(t).toLowerCase().replace(/\s+/g, "-");
21423
+ const m = normaliseMode(v);
21424
+ if (m) explicitMode = m;
21425
+ else ast.warnings.push(`Line ${lineNo}: unknown mode "${afterColon6(t)}" \u2014 using ${explicitMode ?? "inferred"}.`);
21426
+ continue;
21427
+ }
21428
+ if (/^legend\s*:/i.test(t)) {
21429
+ const v = afterColon6(t).toLowerCase();
21430
+ if (v === "on" || v === "off") ast.legend = v;
21431
+ continue;
21432
+ }
21433
+ if (/^baseline\s*:/i.test(t)) {
21434
+ const q = matchQuoted6(afterColon6(t));
21435
+ ast.baseline = q ? q.value : afterColon6(t);
21436
+ continue;
21437
+ }
21438
+ if (/^(title|subject)\s*:/i.test(t)) {
21439
+ const q = matchQuoted6(afterColon6(t));
21440
+ const val = q ? q.value : afterColon6(t);
21441
+ if (/^subject/i.test(t)) ast.subject = val;
21442
+ else if (!ast.title) ast.title = val;
21443
+ continue;
21444
+ }
21445
+ if (/^theme\s*:/i.test(t)) continue;
21446
+ if (curCriterion) {
21447
+ const ref = cellPrefix(t);
21448
+ if (ref !== null) {
21449
+ const valTok = t.slice(t.indexOf(":") + 1).trim();
21450
+ const opt = findOption(ast.options, ref);
21451
+ if (!opt) {
21452
+ ast.warnings.push(
21453
+ `Line ${lineNo}: "${ref}" is not a declared option \u2014 add \`option "${ref}"\` or fix the name.`
21454
+ );
21455
+ } else {
21456
+ curCriterion.cells[opt.id] = parseCellValue(valTok);
21457
+ }
21458
+ continue;
21459
+ }
21460
+ }
21461
+ const kw = /^([a-z][a-z-]*)\b/i.exec(t);
21462
+ const keyword = kw ? kw[1].toLowerCase() : "";
21463
+ const rest = kw ? t.slice(kw[0].length).trim() : t;
21464
+ switch (keyword) {
21465
+ case "column":
21466
+ case "col": {
21467
+ const label = requireLabel2(rest, keyword, lineNo);
21468
+ curColumn = { id: `col${++colCount}`, label, items: [] };
21469
+ ast.columns.push(curColumn);
21470
+ curCriterion = null;
21471
+ break;
21472
+ }
21473
+ case "item": {
21474
+ const label = requireLabel2(rest, keyword, lineNo);
21475
+ if (!curColumn) {
21476
+ ast.warnings.push(`Line ${lineNo}: \`item\` before any \`column\` \u2014 ignored.`);
21477
+ } else curColumn.items.push(label);
21478
+ break;
21479
+ }
21480
+ case "pro": {
21481
+ ast.pros.push(requireLabel2(rest, keyword, lineNo));
21482
+ break;
21483
+ }
21484
+ case "con": {
21485
+ ast.cons.push(requireLabel2(rest, keyword, lineNo));
21486
+ break;
21487
+ }
21488
+ case "option":
21489
+ case "opt": {
21490
+ const label = requireLabel2(rest, keyword, lineNo);
21491
+ ast.options.push({ id: `o${++optCount}`, label });
21492
+ curCriterion = null;
21493
+ break;
21494
+ }
21495
+ case "criterion":
21496
+ case "criteria":
21497
+ case "row": {
21498
+ curCriterion = parseCriterion(rest, `c${++critCount}`, keyword, lineNo, ast.options, ast.warnings, lineNo);
21499
+ ast.criteria.push(curCriterion);
21500
+ curColumn = null;
21501
+ break;
21502
+ }
21503
+ case "left":
21504
+ bubble.left = requireLabel2(rest, keyword, lineNo);
21505
+ break;
21506
+ case "right":
21507
+ bubble.right = requireLabel2(rest, keyword, lineNo);
21508
+ break;
21509
+ case "shared":
21510
+ case "both":
21511
+ bubble.shared.push(requireLabel2(rest, keyword, lineNo));
21512
+ break;
21513
+ case "left-only":
21514
+ case "leftonly":
21515
+ bubble.leftOnly.push(requireLabel2(rest, keyword, lineNo));
21516
+ break;
21517
+ case "right-only":
21518
+ case "rightonly":
21519
+ bubble.rightOnly.push(requireLabel2(rest, keyword, lineNo));
21520
+ break;
21521
+ default: {
21522
+ const bullet = /^[-*•]\s+(.*)$/.exec(t);
21523
+ if (bullet && curColumn) {
21524
+ curColumn.items.push(unquoteLoose(bullet[1].trim()));
21525
+ } else if (bullet) {
21526
+ ast.warnings.push(`Line ${lineNo}: bullet "${truncate7(t, 60)}" before any \`column\` \u2014 ignored.`);
21527
+ } else {
21528
+ ast.warnings.push(`Line ${lineNo}: unrecognised line: "${truncate7(t, 80)}"`);
21529
+ }
21530
+ }
21531
+ }
21532
+ }
21533
+ if (bubble.left || bubble.right || bubble.shared.length) {
21534
+ ast.bubble = bubble;
21535
+ }
21536
+ ast.mode = explicitMode ?? inferMode(ast);
21537
+ validate4(ast);
21538
+ return ast;
21539
+ }
21540
+ function parseCriterion(rest, id, keyword, lineNo, options, warnings, ln) {
21541
+ const pipeIdx = rest.indexOf("|");
21542
+ let head = pipeIdx >= 0 ? rest.slice(0, pipeIdx).trim() : rest;
21543
+ const cells = {};
21544
+ let weight;
21545
+ const wm = /\b(?:weight|w)\s*[:=]\s*(\d+(?:\.\d+)?)/i.exec(head);
21546
+ if (wm) {
21547
+ weight = Number(wm[1]);
21548
+ head = head.slice(0, wm.index).trim() + head.slice(wm.index + wm[0].length).trim();
21549
+ head = head.trim();
21550
+ }
21551
+ const label = requireLabel2(head, keyword, lineNo);
21552
+ if (pipeIdx >= 0) {
21553
+ const parts = rest.slice(pipeIdx + 1).split("|").map((p) => p.trim());
21554
+ parts.forEach((p, k) => {
21555
+ const opt = options[k];
21556
+ if (!opt) {
21557
+ if (p) warnings.push(`Line ${ln}: pipe value "${p}" has no matching option (only ${options.length} declared).`);
21558
+ return;
21559
+ }
21560
+ if (p) cells[opt.id] = parseCellValue(p);
21561
+ });
21562
+ }
21563
+ const crit = { id, label, cells };
21564
+ if (weight !== void 0) crit.weight = weight;
21565
+ return crit;
21566
+ }
21567
+ function parseCellValue(tok) {
21568
+ const raw = tok;
21569
+ const q = matchQuoted6(tok);
21570
+ if (q) return { text: q.value, raw };
21571
+ const low = tok.toLowerCase();
21572
+ if (/^(yes|y|true|✓|✔|check)$/.test(low)) return { glyph: "yes", raw };
21573
+ if (/^(no|n|false|✗|✘|x|cross)$/.test(low)) return { glyph: "no", raw };
21574
+ if (/^(partial|part|~|maybe|some|half)$/.test(low)) return { glyph: "partial", raw };
21575
+ if (/^(na|n\/a|-|—|none)$/.test(low)) return { glyph: "na", raw };
21576
+ const num4 = Number(tok);
21577
+ if (tok !== "" && !Number.isNaN(num4)) return { score: num4, raw };
21578
+ return { text: tok, raw };
21579
+ }
21580
+ function inferMode(ast) {
21581
+ if (ast.bubble) return "double-bubble";
21582
+ if (ast.pros.length || ast.cons.length) return "pros-cons";
21583
+ if (ast.options.length || ast.criteria.length) {
21584
+ const anyScore = ast.criteria.some(
21585
+ (c) => Object.values(c.cells).some((v) => typeof v.score === "number")
21586
+ );
21587
+ const anyWeight = ast.criteria.some((c) => c.weight !== void 0);
21588
+ return anyScore || anyWeight || ast.baseline ? "decision" : "matrix";
21589
+ }
21590
+ return "tchart";
21591
+ }
21592
+ function normaliseMode(v) {
21593
+ if (v === "ychart" || v === "y-chart") return "tchart";
21594
+ if (v === "proscons" || v === "pro-con" || v === "pros-and-cons") return "pros-cons";
21595
+ if (v === "pugh" || v === "decision-matrix") return "decision";
21596
+ if (v === "doublebubble" || v === "double-bubble" || v === "compare-contrast") return "double-bubble";
21597
+ return MODES.includes(v) ? v : void 0;
21598
+ }
21599
+ function validate4(ast) {
21600
+ switch (ast.mode) {
21601
+ case "tchart": {
21602
+ if (ast.columns.length === 0) {
21603
+ throw new ComparisonParseError(
21604
+ `a tchart needs at least one \`column "\u2026"\` \u2014 declare the columns you want to compare.`
21605
+ );
21606
+ }
21607
+ break;
21608
+ }
21609
+ case "pros-cons": {
21610
+ if (ast.pros.length === 0 && ast.cons.length === 0) {
21611
+ throw new ComparisonParseError(
21612
+ `a pros-cons needs at least one \`pro "\u2026"\` or \`con "\u2026"\` line.`
21613
+ );
21614
+ }
21615
+ break;
21616
+ }
21617
+ case "matrix":
21618
+ case "decision": {
21619
+ if (ast.options.length === 0) {
21620
+ throw new ComparisonParseError(
21621
+ `a ${ast.mode} matrix needs at least one \`option "\u2026"\` \u2014 declare the options (columns) you are comparing.`
21622
+ );
21623
+ }
21624
+ if (ast.criteria.length === 0) {
21625
+ throw new ComparisonParseError(
21626
+ `a ${ast.mode} matrix needs at least one \`criterion "\u2026"\` \u2014 declare the criteria (rows) to compare on.`
21627
+ );
21628
+ }
21629
+ if (ast.mode === "decision") {
21630
+ const anyScore = ast.criteria.some(
21631
+ (c) => Object.values(c.cells).some((v) => typeof v.score === "number")
21632
+ );
21633
+ if (!anyScore) {
21634
+ ast.warnings.push(
21635
+ `decision mode but no numeric scores found \u2014 add \`Option: <number>\` lines under each criterion, or switch to \`mode: matrix\`.`
21636
+ );
21637
+ }
21638
+ if (ast.baseline) {
21639
+ const ok = ast.options.some((o) => o.label === ast.baseline || o.id === ast.baseline);
21640
+ if (!ok) {
21641
+ ast.warnings.push(
21642
+ `baseline "${ast.baseline}" is not one of the declared options \u2014 ignored.`
21643
+ );
21644
+ delete ast.baseline;
21645
+ }
21646
+ }
21647
+ }
21648
+ break;
21649
+ }
21650
+ case "double-bubble": {
21651
+ if (!ast.bubble || !ast.bubble.left || !ast.bubble.right) {
21652
+ throw new ComparisonParseError(
21653
+ `a double-bubble needs both a \`left "\u2026"\` and a \`right "\u2026"\` centre to compare.`
21654
+ );
21655
+ }
21656
+ break;
21657
+ }
21658
+ }
21659
+ }
21660
+ var RESERVED_KEYWORDS = /* @__PURE__ */ new Set([
21661
+ "comparison",
21662
+ "compare",
21663
+ "vs",
21664
+ "tchart",
21665
+ "t-chart",
21666
+ "pugh",
21667
+ "decision-matrix",
21668
+ "decisionmatrix",
21669
+ "mode",
21670
+ "legend",
21671
+ "baseline",
21672
+ "title",
21673
+ "subject",
21674
+ "theme",
21675
+ "column",
21676
+ "col",
21677
+ "item",
21678
+ "pro",
21679
+ "con",
21680
+ "option",
21681
+ "opt",
21682
+ "criterion",
21683
+ "criteria",
21684
+ "row",
21685
+ "left",
21686
+ "right",
21687
+ "shared",
21688
+ "both",
21689
+ "left-only",
21690
+ "leftonly",
21691
+ "right-only",
21692
+ "rightonly"
21693
+ ]);
21694
+ function cellPrefix(t) {
21695
+ const ci = t.indexOf(":");
21696
+ if (ci <= 0) return null;
21697
+ const pre = t.slice(0, ci).trim();
21698
+ if (!pre) return null;
21699
+ const firstWord2 = (pre.split(/\s+/)[0] ?? "").toLowerCase();
21700
+ if (RESERVED_KEYWORDS.has(firstWord2)) return null;
21701
+ return pre;
21702
+ }
21703
+ function findOption(options, ref) {
21704
+ const r7 = ref.toLowerCase();
21705
+ return options.find((o) => o.label.toLowerCase() === r7 || o.id.toLowerCase() === r7);
21706
+ }
21707
+ function requireLabel2(s, keyword, lineNo) {
21708
+ const q = matchQuoted6(s);
21709
+ if (q) return q.value;
21710
+ const bare = s.trim();
21711
+ if (!bare) throw new ComparisonParseError(`\`${keyword}\` needs a label`, lineNo);
21712
+ return bare;
21713
+ }
21714
+ function unquoteLoose(s) {
21715
+ const q = matchQuoted6(s);
21716
+ return q && q.length === s.length ? q.value : s;
21717
+ }
21718
+ function matchQuoted6(s) {
21719
+ if (!s) return void 0;
21720
+ const open = s[0];
21721
+ if (open !== '"' && open !== "\u300C" && open !== "\u201C" && open !== "\u300E") return void 0;
21722
+ const close = closingQuote6(open);
21723
+ const end = s.indexOf(close, 1);
21724
+ if (end < 0) return void 0;
21725
+ return { value: s.slice(1, end), length: end + 1 };
21726
+ }
21727
+ function closingQuote6(open) {
21728
+ return open === "\u300C" ? "\u300D" : open === "\u300E" ? "\u300F" : open === "\u201C" ? "\u201D" : '"';
21729
+ }
21730
+ function afterColon6(s) {
21731
+ const i = s.indexOf(":");
21732
+ return i < 0 ? "" : s.slice(i + 1).trim();
21733
+ }
21734
+ function stripComment8(line2) {
21735
+ let inQ = false;
21736
+ let qc = "";
21737
+ for (let i = 0; i < line2.length; i++) {
21738
+ const ch = line2[i];
21739
+ if (inQ) {
21740
+ if (ch === qc) inQ = false;
21741
+ continue;
21742
+ }
21743
+ if (ch === '"' || ch === "\u300C" || ch === "\u201C" || ch === "\u300E") {
21744
+ inQ = true;
21745
+ qc = closingQuote6(ch);
21746
+ continue;
21747
+ }
21748
+ if (ch === "#") return line2.slice(0, i);
21749
+ if (ch === "/" && line2[i + 1] === "/") return line2.slice(0, i);
21750
+ }
21751
+ return line2;
21752
+ }
21753
+ function truncate7(s, n) {
21754
+ return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
21755
+ }
21756
+
21757
+ // src/diagrams/comparison/compute.ts
21758
+ function scoreOf(v) {
21759
+ if (!v) return 0;
21760
+ if (typeof v.score === "number") return v.score;
21761
+ if (v.glyph === "yes") return 1;
21762
+ if (v.glyph === "partial") return 0.5;
21763
+ if (v.glyph === "no" || v.glyph === "na") return 0;
21764
+ return 0;
21765
+ }
21766
+ function computeDecision(ast) {
21767
+ const totals = {};
21768
+ const totalWeight = ast.criteria.reduce((s, c) => s + (c.weight ?? 1), 0);
21769
+ for (const opt of ast.options) {
21770
+ let sum = 0;
21771
+ for (const crit of ast.criteria) {
21772
+ const w = crit.weight ?? 1;
21773
+ sum += w * scoreOf(crit.cells[opt.id]);
21774
+ }
21775
+ totals[opt.id] = round7(sum);
21776
+ }
21777
+ const sorted = [...ast.options].sort((a, b) => totals[b.id] - totals[a.id]);
21778
+ const ranks = {};
21779
+ let lastTotal = Number.POSITIVE_INFINITY;
21780
+ let lastRank = 0;
21781
+ sorted.forEach((opt, i) => {
21782
+ const t = totals[opt.id];
21783
+ if (t < lastTotal) {
21784
+ lastRank = i + 1;
21785
+ lastTotal = t;
21786
+ }
21787
+ ranks[opt.id] = lastRank;
21788
+ });
21789
+ const winnerId = sorted.length ? sorted[0].id : "";
21790
+ const maxTotal = sorted.length ? totals[winnerId] : 0;
21791
+ const result = { totals, ranks, winnerId, maxTotal, totalWeight };
21792
+ if (ast.baseline) {
21793
+ const base = ast.options.find(
21794
+ (o) => o.id === ast.baseline || o.label === ast.baseline
21795
+ );
21796
+ if (base) {
21797
+ const baseTotal = totals[base.id];
21798
+ const deltas = {};
21799
+ for (const opt of ast.options) deltas[opt.id] = round7(totals[opt.id] - baseTotal);
21800
+ result.deltas = deltas;
21801
+ }
21802
+ }
21803
+ return result;
21804
+ }
21805
+ function decisionCaption(ast, r7) {
21806
+ if (!ast.options.length) return "Decision matrix: no options.";
21807
+ const winner = ast.options.find((o) => o.id === r7.winnerId);
21808
+ const tiedIds = ast.options.filter((o) => r7.ranks[o.id] === 1).map((o) => o.id);
21809
+ if (tiedIds.length > 1) {
21810
+ const names = tiedIds.map((id) => ast.options.find((o) => o.id === id)?.label).filter(Boolean).map((n) => `"${n}"`).join(" / ");
21811
+ return `Tie at the top: ${names} (weighted score ${fmt3(r7.maxTotal)} of ${ast.options.length} options).`;
21812
+ }
21813
+ return `Winner: "${winner?.label ?? r7.winnerId}" \u2014 weighted score ${fmt3(
21814
+ r7.maxTotal
21815
+ )}, highest of ${ast.options.length} option${ast.options.length === 1 ? "" : "s"}.`;
21816
+ }
21817
+ function round7(n) {
21818
+ return Math.round(n * 1e3) / 1e3;
21819
+ }
21820
+ function fmt3(n) {
21821
+ const r7 = Math.round(n * 100) / 100;
21822
+ return Number.isInteger(r7) ? String(r7) : String(r7);
21823
+ }
21824
+
21825
+ // src/diagrams/comparison/layout.ts
21826
+ var COMPARISON_CONST = {
21827
+ PAGE_PAD: 24,
21828
+ TITLE_H: 40,
21829
+ CAPTION_H: 30,
21830
+ HEADER_MIN_H: 36,
21831
+ ROW_MIN_H: 34,
21832
+ CELL_PAD_X: 12,
21833
+ CELL_PAD_Y: 8,
21834
+ LINE_H: 16,
21835
+ COL_MIN_W: 140,
21836
+ COL_MAX_W: 264,
21837
+ MARK_COL_MIN_W: 92,
21838
+ MARK_COL_MAX_W: 190,
21839
+ ROWHEAD_MIN_W: 120,
21840
+ ROWHEAD_MAX_W: 230,
21841
+ FONT: 12,
21842
+ HEADER_FONT: 13,
21843
+ // double-bubble — larger, rounder bubbles with generous spacing
21844
+ CENTER_RX: 70,
21845
+ CENTER_RY: 58,
21846
+ SHARED_RX: 60,
21847
+ SHARED_RY: 46,
21848
+ UNIQUE_RX: 70,
21849
+ UNIQUE_RY: 46,
21850
+ BUBBLE_VGAP: 22,
21851
+ // tchart
21852
+ TCHART_COL_GAP: 22,
21853
+ // pros-cons
21854
+ PC_COL_W: 322,
21855
+ PC_COL_GAP: 30,
21856
+ PC_PILL_H: 40,
21857
+ PC_ROW_MIN_H: 40,
21858
+ PC_BADGE_R: 11
21859
+ };
21860
+ function charW(ch, fontSize) {
21861
+ const cp = ch.codePointAt(0) ?? 0;
21862
+ if (cp >= 11904 && cp <= 40959) return fontSize;
21863
+ if (cp >= 44032 && cp <= 55203) return fontSize;
21864
+ if (cp >= 65280 && cp <= 65519) return fontSize;
21865
+ if (ch === " ") return fontSize * 0.3;
21866
+ if (/[ilj.,:'!|]/.test(ch)) return fontSize * 0.3;
21867
+ if (/[mwMW]/.test(ch)) return fontSize * 0.85;
21868
+ return fontSize * 0.56;
21869
+ }
21870
+ function measureText(s, fontSize) {
21871
+ let w = 0;
21872
+ for (const ch of s) w += charW(ch, fontSize);
21873
+ return w;
21874
+ }
21875
+ function wrapToWidth(s, maxW, fontSize) {
21876
+ if (!s) return [""];
21877
+ const hasSpaces = /\s/.test(s.trim());
21878
+ const tokens = hasSpaces ? s.split(/\s+/).filter(Boolean) : [...s];
21879
+ const sep = hasSpaces ? " " : "";
21880
+ const lines = [];
21881
+ let cur = "";
21882
+ for (const tok of tokens) {
21883
+ const trial = cur ? cur + sep + tok : tok;
21884
+ if (cur && measureText(trial, fontSize) > maxW) {
21885
+ lines.push(cur);
21886
+ cur = tok;
21887
+ } else {
21888
+ cur = trial;
21889
+ }
21890
+ }
21891
+ if (cur) lines.push(cur);
21892
+ return lines.length ? lines : [""];
21893
+ }
21894
+ var C2 = COMPARISON_CONST;
21895
+ function layoutComparison(ast) {
21896
+ switch (ast.mode) {
21897
+ case "tchart":
21898
+ return layoutColumns(ast);
21899
+ case "pros-cons":
21900
+ return layoutProsCons(ast);
21901
+ case "matrix":
21902
+ case "decision":
21903
+ return layoutGrid(ast);
21904
+ case "double-bubble":
21905
+ return layoutDoubleBubble(ast);
21906
+ }
21907
+ }
21908
+ function frame(ast) {
21909
+ const pad = C2.PAGE_PAD;
21910
+ const top = pad + (ast.title ? C2.TITLE_H : 0);
21911
+ return { top, pad };
21912
+ }
21913
+ function layoutColumns(ast) {
21914
+ const { top, pad } = frame(ast);
21915
+ const cells = [];
21916
+ const connectors = [];
21917
+ const frames = [];
21918
+ const gap = C2.TCHART_COL_GAP;
21919
+ const headGap = 10;
21920
+ const cardPadBottom = 12;
21921
+ const textLeft = 16;
21922
+ const colWidths = ast.columns.map((col) => {
21923
+ const headW = measureText(col.label, C2.HEADER_FONT) + 2 * C2.CELL_PAD_X;
21924
+ const itemW = Math.max(
21925
+ 0,
21926
+ ...col.items.map((it) => measureText(it, C2.FONT) + textLeft + 16)
21927
+ );
21928
+ return clamp(Math.max(headW, itemW, C2.COL_MIN_W), C2.COL_MIN_W, C2.COL_MAX_W);
21929
+ });
21930
+ const headerLines = ast.columns.map(
21931
+ (col, i) => wrapToWidth(col.label, colWidths[i] - 2 * C2.CELL_PAD_X, C2.HEADER_FONT)
21932
+ );
21933
+ const headerH = Math.max(
21934
+ C2.HEADER_MIN_H,
21935
+ ...headerLines.map((l) => l.length * C2.LINE_H + 2 * C2.CELL_PAD_Y)
21936
+ );
21937
+ const colRows = ast.columns.map(
21938
+ (col, i) => col.items.map((it) => {
21939
+ const lines = wrapToWidth(it, colWidths[i] - textLeft - 14, C2.FONT);
21940
+ return { lines, h: Math.max(C2.ROW_MIN_H, lines.length * C2.LINE_H + 2 * C2.CELL_PAD_Y) };
21941
+ })
21942
+ );
21943
+ const itemsTop = top + headerH + headGap;
21944
+ const naturalH = colRows.map(
21945
+ (rows) => headerH + headGap + rows.reduce((s, r7) => s + r7.h, 0) + cardPadBottom
21946
+ );
21947
+ const cardH = Math.max(headerH + 44, ...naturalH);
21948
+ let x = pad;
21949
+ ast.columns.forEach((_col, i) => {
21950
+ const w = colWidths[i];
21951
+ frames.push({ x, y: top, w, h: cardH, rx: 12, variant: "card" });
21952
+ cells.push({
21953
+ x,
21954
+ y: top,
21955
+ w,
21956
+ h: headerH,
21957
+ lines: headerLines[i],
21958
+ variant: "colHeader",
21959
+ align: "middle",
21960
+ bold: true,
21961
+ paletteIndex: i,
21962
+ roundedTop: true
21963
+ });
21964
+ let cy = itemsTop;
21965
+ colRows[i].forEach((r7, k) => {
21966
+ cells.push({ x, y: cy, w, h: r7.h, lines: r7.lines, variant: "body", align: "start", bare: true });
21967
+ if (k < colRows[i].length - 1) {
21968
+ connectors.push({ x1: x + 14, y1: cy + r7.h, x2: x + w - 14, y2: cy + r7.h, light: true });
21969
+ }
21970
+ cy += r7.h;
21971
+ });
21972
+ x += w + gap;
21973
+ });
21974
+ const totalW = x - pad - gap;
21975
+ return {
21976
+ ast,
21977
+ mode: ast.mode,
21978
+ cells,
21979
+ ellipses: [],
21980
+ connectors,
21981
+ frames,
21982
+ width: Math.ceil(totalW + 2 * pad),
21983
+ height: Math.ceil(top + cardH + pad)
21984
+ };
21985
+ }
21986
+ function layoutProsCons(ast) {
21987
+ const { top, pad } = frame(ast);
21988
+ const cells = [];
21989
+ const connectors = [];
21990
+ const colW = C2.PC_COL_W;
21991
+ const leftX = pad;
21992
+ const rightX = pad + colW + C2.PC_COL_GAP;
21993
+ const badgeRoom = 2 * C2.PC_BADGE_R + 14;
21994
+ const pillH = C2.PC_PILL_H;
21995
+ const pill = (label, colX, kind) => {
21996
+ const pw = clamp(measureText(label, C2.HEADER_FONT) + badgeRoom + 30, 130, colW);
21997
+ cells.push({
21998
+ x: colX + (colW - pw) / 2,
21999
+ y: top,
22000
+ w: pw,
22001
+ h: pillH,
22002
+ lines: [label],
22003
+ variant: kind === "pro" ? "pillPos" : "pillNeg",
22004
+ align: "middle",
22005
+ bold: true,
22006
+ rx: pillH / 2,
22007
+ badge: { glyph: kind === "pro" ? "yes" : "no", tone: kind === "pro" ? "pos" : "neg" }
22008
+ });
22009
+ };
22010
+ pill("PROS", leftX, "pro");
22011
+ pill("CONS", rightX, "con");
22012
+ const itemsTop = top + pillH + 14;
22013
+ const itemCell = (txt, x, y, kind) => {
22014
+ const lines = wrapToWidth(txt, colW - badgeRoom - 14, C2.FONT);
22015
+ const h = Math.max(C2.PC_ROW_MIN_H, lines.length * C2.LINE_H + 2 * C2.CELL_PAD_Y);
22016
+ return {
22017
+ x,
22018
+ y,
22019
+ w: colW,
22020
+ h,
22021
+ lines,
22022
+ variant: kind,
22023
+ align: "start",
22024
+ bare: true,
22025
+ badge: { glyph: kind === "pro" ? "yes" : "no", tone: kind === "pro" ? "pos" : "neg" }
22026
+ };
22027
+ };
22028
+ let ly = itemsTop;
22029
+ for (const p of ast.pros) {
22030
+ const cell = itemCell(p, leftX, ly, "pro");
22031
+ cells.push(cell);
22032
+ ly += cell.h;
22033
+ }
22034
+ let ry = itemsTop;
22035
+ for (const c of ast.cons) {
22036
+ const cell = itemCell(c, rightX, ry, "con");
22037
+ cells.push(cell);
22038
+ ry += cell.h;
22039
+ }
22040
+ const bottom = Math.max(ly, ry);
22041
+ const dx = leftX + colW + C2.PC_COL_GAP / 2;
22042
+ connectors.push({ x1: dx, y1: itemsTop, x2: dx, y2: bottom - 6 });
22043
+ return {
22044
+ ast,
22045
+ mode: ast.mode,
22046
+ cells,
22047
+ ellipses: [],
22048
+ connectors,
22049
+ width: colW * 2 + C2.PC_COL_GAP + 2 * pad,
22050
+ height: Math.ceil(bottom + pad)
22051
+ };
22052
+ }
22053
+ function layoutGrid(ast) {
22054
+ const { top, pad } = frame(ast);
22055
+ const cells = [];
22056
+ const isDecision = ast.mode === "decision";
22057
+ const decision = isDecision ? computeDecision(ast) : void 0;
22058
+ const cellText = (oid, cid) => {
22059
+ const v = ast.criteria.find((c) => c.id === cid).cells[oid];
22060
+ if (!v) return { lines: [], variant: "body" };
22061
+ if (v.glyph) {
22062
+ const variant = v.glyph === "yes" ? "pos" : v.glyph === "no" ? "neg" : v.glyph === "partial" ? "warn" : "body";
22063
+ return { lines: v.glyph === "na" ? ["\u2014"] : [], glyph: v.glyph === "na" ? void 0 : v.glyph, variant };
22064
+ }
22065
+ if (typeof v.score === "number") return { lines: [fmt3(v.score)], variant: "body" };
22066
+ return { lines: v.text ? [v.text] : [], variant: "body" };
22067
+ };
22068
+ const rowHeadW = clamp(
22069
+ Math.max(
22070
+ C2.ROWHEAD_MIN_W,
22071
+ ...ast.criteria.map((c) => measureText(c.label, C2.FONT) + 2 * C2.CELL_PAD_X + (isDecision ? 30 : 0)),
22072
+ measureText(isDecision ? "Weighted total" : "", C2.FONT) + 2 * C2.CELL_PAD_X
22073
+ ),
22074
+ C2.ROWHEAD_MIN_W,
22075
+ C2.ROWHEAD_MAX_W
22076
+ );
22077
+ const optW = ast.options.map((o) => {
22078
+ const headW = measureText(o.label, C2.HEADER_FONT) + 2 * C2.CELL_PAD_X;
22079
+ const bodyW = Math.max(
22080
+ 0,
22081
+ ...ast.criteria.map((c) => {
22082
+ const ct = cellText(o.id, c.id);
22083
+ return Math.max(0, ...ct.lines.map((l) => measureText(l, C2.FONT))) + 2 * C2.CELL_PAD_X;
22084
+ })
22085
+ );
22086
+ return clamp(Math.max(headW, bodyW, C2.MARK_COL_MIN_W), C2.MARK_COL_MIN_W, C2.MARK_COL_MAX_W);
22087
+ });
22088
+ const headLines = ast.options.map(
22089
+ (o, i) => wrapToWidth(o.label, optW[i] - 2 * C2.CELL_PAD_X, C2.HEADER_FONT)
22090
+ );
22091
+ const headerH = Math.max(C2.HEADER_MIN_H, ...headLines.map((l) => l.length * C2.LINE_H + 2 * C2.CELL_PAD_Y));
22092
+ cells.push({
22093
+ x: pad,
22094
+ y: top,
22095
+ w: rowHeadW,
22096
+ h: headerH,
22097
+ lines: ast.title ? [] : [],
22098
+ variant: "corner",
22099
+ align: "start"
22100
+ });
22101
+ let hx = pad + rowHeadW;
22102
+ const colX = [];
22103
+ ast.options.forEach((o, i) => {
22104
+ colX.push(hx);
22105
+ const isBase = isDecision && ast.baseline && (o.label === ast.baseline || o.id === ast.baseline);
22106
+ cells.push({
22107
+ x: hx,
22108
+ y: top,
22109
+ w: optW[i],
22110
+ h: headerH,
22111
+ lines: headLines[i],
22112
+ variant: isBase ? "baseline" : "colHeader",
22113
+ align: "middle",
22114
+ bold: true,
22115
+ tag: isBase ? "datum" : void 0
22116
+ });
22117
+ hx += optW[i];
22118
+ });
22119
+ const gridW = rowHeadW + optW.reduce((a, b) => a + b, 0);
22120
+ let ry = top + headerH;
22121
+ for (const crit of ast.criteria) {
22122
+ const labelLines = wrapToWidth(crit.label, rowHeadW - 2 * C2.CELL_PAD_X - (isDecision ? 26 : 0), C2.FONT);
22123
+ const bodyLineCounts = ast.options.map((o) => {
22124
+ const ct = cellText(o.id, crit.id);
22125
+ const wrapped = ct.lines.flatMap(
22126
+ (l, idx) => idx === 0 ? wrapToWidth(l, optW[ast.options.indexOf(o)] - 2 * C2.CELL_PAD_X, C2.FONT) : [l]
22127
+ );
22128
+ return wrapped.length;
22129
+ });
22130
+ const rowH = Math.max(
22131
+ C2.ROW_MIN_H,
22132
+ labelLines.length * C2.LINE_H + 2 * C2.CELL_PAD_Y,
22133
+ ...bodyLineCounts.map((n) => n * C2.LINE_H + 2 * C2.CELL_PAD_Y)
22134
+ );
22135
+ cells.push({
22136
+ x: pad,
22137
+ y: ry,
22138
+ w: rowHeadW,
22139
+ h: rowH,
22140
+ lines: labelLines,
22141
+ variant: "rowHeader",
22142
+ align: "start",
22143
+ tag: isDecision ? `\xD7${fmt3(crit.weight ?? 1)}` : void 0
22144
+ });
22145
+ ast.options.forEach((o, i) => {
22146
+ const ct = cellText(o.id, crit.id);
22147
+ const wrapped = ct.lines.length ? wrapToWidth(ct.lines[0], optW[i] - 2 * C2.CELL_PAD_X, C2.FONT) : [];
22148
+ cells.push({
22149
+ x: colX[i],
22150
+ y: ry,
22151
+ w: optW[i],
22152
+ h: rowH,
22153
+ lines: wrapped,
22154
+ variant: ct.variant,
22155
+ glyph: ct.glyph,
22156
+ align: "middle"
22157
+ });
22158
+ });
22159
+ ry += rowH;
22160
+ }
22161
+ let caption;
22162
+ if (isDecision && decision) {
22163
+ const totalH = C2.ROW_MIN_H;
22164
+ cells.push({
22165
+ x: pad,
22166
+ y: ry,
22167
+ w: rowHeadW,
22168
+ h: totalH,
22169
+ lines: ["Weighted total"],
22170
+ variant: "rowHeader",
22171
+ align: "start",
22172
+ bold: true
22173
+ });
22174
+ ast.options.forEach((o, i) => {
22175
+ const isWin = decision.ranks[o.id] === 1;
22176
+ cells.push({
22177
+ x: colX[i],
22178
+ y: ry,
22179
+ w: optW[i],
22180
+ h: totalH,
22181
+ lines: [fmt3(decision.totals[o.id])],
22182
+ variant: isWin ? "winner" : "total",
22183
+ align: "middle",
22184
+ bold: true,
22185
+ tag: `#${decision.ranks[o.id]}`
22186
+ });
22187
+ });
22188
+ ry += totalH;
22189
+ if (decision.deltas) {
22190
+ const dH = C2.ROW_MIN_H;
22191
+ cells.push({
22192
+ x: pad,
22193
+ y: ry,
22194
+ w: rowHeadW,
22195
+ h: dH,
22196
+ lines: ["vs datum"],
22197
+ variant: "rowHeader",
22198
+ align: "start"
22199
+ });
22200
+ ast.options.forEach((o, i) => {
22201
+ const d = decision.deltas[o.id];
22202
+ const s = d > 0 ? `+${fmt3(d)}` : fmt3(d);
22203
+ cells.push({
22204
+ x: colX[i],
22205
+ y: ry,
22206
+ w: optW[i],
22207
+ h: dH,
22208
+ lines: [s],
22209
+ variant: d > 0 ? "pos" : d < 0 ? "neg" : "body",
22210
+ align: "middle"
22211
+ });
22212
+ });
22213
+ ry += dH;
22214
+ }
22215
+ caption = decisionCaption(ast, decision);
22216
+ }
22217
+ const captionH = caption ? C2.CAPTION_H : 0;
22218
+ const result = {
22219
+ ast,
22220
+ mode: ast.mode,
22221
+ cells,
22222
+ ellipses: [],
22223
+ connectors: [],
22224
+ width: gridW + 2 * pad,
22225
+ height: ry + captionH + pad
22226
+ };
22227
+ if (decision) result.decision = decision;
22228
+ if (caption) result.caption = caption;
22229
+ return result;
22230
+ }
22231
+ function layoutDoubleBubble(ast) {
22232
+ const { top, pad } = frame(ast);
22233
+ const b = ast.bubble;
22234
+ const rawE = [];
22235
+ const rawC = [];
22236
+ const dxCS = C2.CENTER_RX + 72 + C2.SHARED_RX;
22237
+ const lcx = -dxCS;
22238
+ const rcx = dxCS;
22239
+ rawE.push({ cx: lcx, cy: 0, rx: C2.CENTER_RX, ry: C2.CENTER_RY, lines: wrapToWidth(b.left, C2.CENTER_RX * 1.4, C2.HEADER_FONT), variant: "center", side: "left" });
22240
+ rawE.push({ cx: rcx, cy: 0, rx: C2.CENTER_RX, ry: C2.CENTER_RY, lines: wrapToWidth(b.right, C2.CENTER_RX * 1.4, C2.HEADER_FONT), variant: "center", side: "right" });
22241
+ const sN = b.shared.length;
22242
+ const sStep = 2 * C2.SHARED_RY + C2.BUBBLE_VGAP;
22243
+ const sTotal = sN > 0 ? (sN - 1) * sStep : 0;
22244
+ b.shared.forEach((s, i) => {
22245
+ const sy = -sTotal / 2 + i * sStep;
22246
+ rawE.push({ cx: 0, cy: sy, rx: C2.SHARED_RX, ry: C2.SHARED_RY, lines: wrapToWidth(s, C2.SHARED_RX * 1.6, C2.FONT), variant: "shared" });
22247
+ rawC.push({ x1: lcx, y1: 0, x2: 0, y2: sy });
22248
+ rawC.push({ x1: rcx, y1: 0, x2: 0, y2: sy });
22249
+ });
22250
+ const placeFan = (items, cx, centreDeg, side) => {
22251
+ const n = items.length;
22252
+ if (n === 0) return;
22253
+ const half = Math.min(82, 30 + 17 * (n - 1));
22254
+ const stepDeg = n > 1 ? 2 * half / (n - 1) : 0;
22255
+ const stepRad = stepDeg * Math.PI / 180;
22256
+ const needChord = 2 * C2.UNIQUE_RY + 18;
22257
+ const rOrbit = Math.max(
22258
+ C2.CENTER_RX + 104,
22259
+ n > 1 ? needChord / (2 * Math.sin(stepRad / 2)) : C2.CENTER_RX + 104
22260
+ );
22261
+ items.forEach((it, i) => {
22262
+ const aDeg = n > 1 ? centreDeg - half + stepDeg * i : centreDeg;
22263
+ const a = aDeg * Math.PI / 180;
22264
+ const bx = cx + rOrbit * Math.cos(a);
22265
+ const by = rOrbit * Math.sin(a);
22266
+ rawE.push({ cx: bx, cy: by, rx: C2.UNIQUE_RX, ry: C2.UNIQUE_RY, lines: wrapToWidth(it, C2.UNIQUE_RX * 1.5, C2.FONT), variant: "unique", side });
22267
+ rawC.push({ x1: cx, y1: 0, x2: bx, y2: by });
22268
+ });
22269
+ };
22270
+ placeFan(b.leftOnly, lcx, 180, "left");
22271
+ placeFan(b.rightOnly, rcx, 0, "right");
22272
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
22273
+ for (const e of rawE) {
22274
+ minX = Math.min(minX, e.cx - e.rx);
22275
+ maxX = Math.max(maxX, e.cx + e.rx);
22276
+ minY = Math.min(minY, e.cy - e.ry);
22277
+ maxY = Math.max(maxY, e.cy + e.ry);
22278
+ }
22279
+ const offX = pad - minX;
22280
+ const offY = top - minY;
22281
+ const ellipses = rawE.map((e) => ({
22282
+ cx: round8(e.cx + offX),
22283
+ cy: round8(e.cy + offY),
22284
+ rx: e.rx,
22285
+ ry: e.ry,
22286
+ lines: e.lines,
22287
+ variant: e.variant,
22288
+ ...e.side ? { side: e.side } : {}
22289
+ }));
22290
+ const connectors = rawC.map((c) => ({
22291
+ x1: round8(c.x1 + offX),
22292
+ y1: round8(c.y1 + offY),
22293
+ x2: round8(c.x2 + offX),
22294
+ y2: round8(c.y2 + offY)
22295
+ }));
22296
+ return {
22297
+ ast,
22298
+ mode: ast.mode,
22299
+ cells: [],
22300
+ ellipses,
22301
+ connectors,
22302
+ width: Math.ceil(maxX - minX + 2 * pad),
22303
+ height: Math.ceil(maxY - minY + top + pad)
22304
+ };
22305
+ }
22306
+ function clamp(v, lo, hi) {
22307
+ return Math.max(lo, Math.min(hi, v));
22308
+ }
22309
+ function round8(n) {
22310
+ return Math.round(n * 10) / 10;
22311
+ }
22312
+
22313
+ // src/diagrams/comparison/renderer.ts
22314
+ function ellipse(attrs) {
22315
+ return el("ellipse", attrs);
22316
+ }
22317
+ function renderComparison(text2, config) {
22318
+ return renderComparisonLayout(layoutComparison(parseComparison(text2)), config);
22319
+ }
22320
+ function renderComparisonLayout(layout, config) {
22321
+ const themeName = config?.theme ?? "default";
22322
+ const t = resolveComparisonTheme(themeName);
22323
+ const fontFamily = config?.fontFamily ?? DEFAULT_FONT_FAMILY;
22324
+ const pad = config?.padding ?? 0;
22325
+ const { ast } = layout;
22326
+ const width = layout.width + pad * 2;
22327
+ const height = layout.height + pad * 2;
22328
+ const a11y = ast.title ?? `Comparison (${ast.mode})`;
22329
+ const style = el(
22330
+ "style",
22331
+ {},
22332
+ `
22333
+ .sx-cmp-bg { fill: ${t.bg}; }
22334
+ .sx-cmp-title { fill: ${t.text}; font-size: ${TITLE.size}px; font-weight: ${TITLE.weight}; }
22335
+ .sx-cmp-caption { fill: ${t.captionText}; font-size: ${FONT_SIZE.label}px; font-style: italic; }
22336
+ .sx-cmp-tag { fill: ${t.tagText}; font-size: ${FONT_SIZE.small}px; }
22337
+ .sx-cmp-rect { stroke: ${t.gridStroke}; stroke-width: ${STROKE_WIDTH.thin}; }
22338
+ .sx-cmp-txt { font-size: ${FONT_SIZE.label}px; }
22339
+ .sx-cmp-rect-corner { fill: ${t.rowHeaderFill}; stroke: ${t.gridStroke}; }
22340
+ .sx-cmp-rect-colHeader { fill: ${t.headerFill}; stroke: ${t.headerStroke}; }
22341
+ .sx-cmp-txt-colHeader { fill: ${t.headerText}; font-size: ${FONT_SIZE.label}px; font-weight: 700; }
22342
+ ${t.columnColors.map((c, i) => `.sx-cmp-ch-${i} { fill: ${c}; stroke: none; }`).join("\n")}
22343
+ .sx-cmp-cht { fill: ${t.columnText}; font-size: ${FONT_SIZE.label}px; font-weight: 700; }
22344
+ .sx-cmp-nostroke { stroke: none; }
22345
+ .sx-cmp-rect-baseline { fill: ${t.baselineFill}; stroke: ${t.gridStroke}; }
22346
+ .sx-cmp-txt-baseline { fill: ${t.cellText}; font-weight: 700; }
22347
+ .sx-cmp-rect-rowHeader { fill: ${t.rowHeaderFill}; stroke: ${t.gridStroke}; }
22348
+ .sx-cmp-txt-rowHeader { fill: ${t.cellText}; font-weight: 600; }
22349
+ .sx-cmp-rect-body { fill: ${t.cellFill}; stroke: ${t.gridStroke}; }
22350
+ .sx-cmp-rect-body-z { fill: ${t.cellAltFill}; stroke: ${t.gridStroke}; }
22351
+ .sx-cmp-txt-body { fill: ${t.cellText}; }
22352
+ .sx-cmp-bullet { fill: ${t.headerFill}; }
22353
+ .sx-cmp-rect-pos { fill: ${t.posFill}; stroke: ${t.gridStroke}; }
22354
+ .sx-cmp-txt-pos { fill: ${t.posText}; font-weight: 600; }
22355
+ .sx-cmp-rect-neg { fill: ${t.negFill}; stroke: ${t.gridStroke}; }
22356
+ .sx-cmp-txt-neg { fill: ${t.negText}; font-weight: 600; }
22357
+ .sx-cmp-rect-warn { fill: ${t.warnFill}; stroke: ${t.gridStroke}; }
22358
+ .sx-cmp-txt-warn { fill: ${t.warnText}; font-weight: 600; }
22359
+ .sx-cmp-txt-pro { fill: ${t.cellText}; }
22360
+ .sx-cmp-txt-con { fill: ${t.cellText}; }
22361
+ .sx-cmp-rect-pillPos { fill: ${t.pillPosFill}; stroke: none; }
22362
+ .sx-cmp-rect-pillNeg { fill: ${t.pillNegFill}; stroke: none; }
22363
+ .sx-cmp-txt-pillPos, .sx-cmp-txt-pillNeg { fill: ${t.pillText}; font-weight: 700; letter-spacing: 0.5px; }
22364
+ .sx-cmp-badge-pos { fill: ${t.pillPosFill}; }
22365
+ .sx-cmp-badge-neg { fill: ${t.pillNegFill}; }
22366
+ .sx-cmp-badge-glyph { fill: ${t.badgeText}; font-size: 13px; font-weight: 700; }
22367
+ .sx-cmp-rect-total { fill: ${t.totalFill}; stroke: ${t.gridStroke}; }
22368
+ .sx-cmp-txt-total { fill: ${t.cellText}; font-weight: 700; }
22369
+ .sx-cmp-rect-winner { fill: ${t.winnerFill}; stroke: ${t.winnerStroke}; stroke-width: ${STROKE_WIDTH.thick}; }
22370
+ .sx-cmp-txt-winner { fill: ${t.winnerText}; font-weight: 700; }
22371
+ .sx-cmp-glyph { font-size: 15px; font-weight: 700; }
22372
+ .sx-cmp-card { fill: ${t.cardFill}; stroke: ${t.cardStroke}; stroke-width: ${STROKE_WIDTH.thin}; }
22373
+ .sx-cmp-conn { fill: none; stroke: ${t.connectorStroke}; stroke-width: ${STROKE_WIDTH.normal}; }
22374
+ .sx-cmp-conn-light { fill: none; stroke: ${t.rowDivider}; stroke-width: ${STROKE_WIDTH.thin}; }
22375
+ .sx-cmp-ell { stroke: ${t.dbStroke}; stroke-width: ${STROKE_WIDTH.normal}; }
22376
+ .sx-cmp-ell-center-left { fill: ${t.dbLeftCenterFill}; }
22377
+ .sx-cmp-ell-center-right { fill: ${t.dbRightCenterFill}; }
22378
+ .sx-cmp-ell-shared { fill: ${t.dbSharedFill}; }
22379
+ .sx-cmp-ell-unique-left { fill: ${t.dbLeftFill}; }
22380
+ .sx-cmp-ell-unique-right { fill: ${t.dbRightFill}; }
22381
+ .sx-cmp-ltxt-center-left { fill: ${t.dbLeftCenterText}; font-size: ${FONT_SIZE.label}px; font-weight: 700; }
22382
+ .sx-cmp-ltxt-center-right { fill: ${t.dbRightCenterText}; font-size: ${FONT_SIZE.label}px; font-weight: 700; }
22383
+ .sx-cmp-ltxt-shared { fill: ${t.dbSharedText}; font-size: ${FONT_SIZE.label}px; font-weight: 600; }
22384
+ .sx-cmp-ltxt-unique-left { fill: ${t.dbLeftText}; font-size: ${FONT_SIZE.small}px; }
22385
+ .sx-cmp-ltxt-unique-right { fill: ${t.dbRightText}; font-size: ${FONT_SIZE.small}px; }
22386
+ `.trim()
22387
+ );
22388
+ const children = [
22389
+ title(a11y),
22390
+ desc(summarise7(layout)),
22391
+ style,
22392
+ rect({ x: 0, y: 0, width, height, class: "sx-cmp-bg" })
22393
+ ];
22394
+ const inner = [];
22395
+ if (ast.title) {
22396
+ inner.push(
22397
+ text(
22398
+ { x: layout.width / 2, y: TITLE.y, class: "sx-cmp-title", "font-family": fontFamily, "text-anchor": "middle" },
22399
+ ast.title
22400
+ )
22401
+ );
22402
+ }
22403
+ for (const f of layout.frames ?? []) {
22404
+ inner.push(rect({ x: f.x, y: f.y, width: f.w, height: f.h, rx: f.rx, class: "sx-cmp-card" }));
22405
+ }
22406
+ for (const c of layout.connectors) {
22407
+ inner.push(line({ x1: c.x1, y1: c.y1, x2: c.x2, y2: c.y2, class: c.light ? "sx-cmp-conn-light" : "sx-cmp-conn" }));
22408
+ }
22409
+ const colN = t.columnColors.length;
22410
+ for (const cell of layout.cells) {
22411
+ inner.push(renderCell(cell, fontFamily, colN));
22412
+ }
22413
+ for (const e of layout.ellipses) {
22414
+ const key = e.variant === "center" || e.variant === "unique" ? `${e.variant}-${e.side ?? "left"}` : e.variant;
22415
+ const cls = `sx-cmp-ell sx-cmp-ell-${key}`;
22416
+ const txtCls = `sx-cmp-ltxt-${key}`;
22417
+ inner.push(
22418
+ group({ class: "sx-cmp-bubble", "data-role": e.variant, ...e.side ? { "data-side": e.side } : {} }, [
22419
+ ellipse({ cx: e.cx, cy: e.cy, rx: e.rx, ry: e.ry, class: cls }),
22420
+ multilineText(
22421
+ { x: e.cx, y: e.cy, class: txtCls, "font-family": fontFamily, "text-anchor": "middle", "dominant-baseline": "middle" },
22422
+ e.lines.join("<br/>"),
22423
+ C_LINE_H
22424
+ )
22425
+ ])
22426
+ );
22427
+ }
22428
+ if (layout.caption) {
22429
+ inner.push(
22430
+ text(
22431
+ { x: layout.width / 2, y: layout.height - 12, class: "sx-cmp-caption", "font-family": fontFamily, "text-anchor": "middle" },
22432
+ layout.caption
22433
+ )
22434
+ );
22435
+ }
22436
+ children.push(
22437
+ group({ transform: pad ? `translate(${pad}, ${pad})` : void 0, "font-family": fontFamily }, inner)
22438
+ );
22439
+ return svgRoot(
22440
+ {
22441
+ width,
22442
+ height,
22443
+ viewBox: `0 0 ${width} ${height}`,
22444
+ role: "img",
22445
+ "aria-label": a11y,
22446
+ "data-diagram-type": "comparison",
22447
+ "data-mode": ast.mode
22448
+ },
22449
+ children
22450
+ );
22451
+ }
22452
+ var C_LINE_H = 14;
22453
+ function renderCell(cell, fontFamily, colN) {
22454
+ const parts = [];
22455
+ const colHeaderClass = cell.variant === "colHeader" && cell.paletteIndex !== void 0 ? `sx-cmp-ch-${cell.paletteIndex % Math.max(1, colN)}` : void 0;
22456
+ if (!cell.bare) {
22457
+ if (cell.roundedTop) {
22458
+ parts.push(
22459
+ path({
22460
+ d: roundedTopRectPath(cell.x, cell.y, cell.w, cell.h, cell.rx ?? 12),
22461
+ class: colHeaderClass ?? "sx-cmp-rect-colHeader"
22462
+ })
22463
+ );
22464
+ } else {
22465
+ const rectVariant = cell.zebra && cell.variant === "body" ? "body-z" : cell.variant;
22466
+ const rectClass = colHeaderClass ? `sx-cmp-rect ${colHeaderClass}` : `sx-cmp-rect sx-cmp-rect-${rectVariant}${cell.noStroke ? " sx-cmp-nostroke" : ""}`;
22467
+ parts.push(
22468
+ rect({ x: cell.x, y: cell.y, width: cell.w, height: cell.h, rx: cell.rx, class: rectClass })
22469
+ );
22470
+ }
22471
+ }
22472
+ const txtClass = colHeaderClass ? "sx-cmp-txt sx-cmp-cht" : `sx-cmp-txt sx-cmp-txt-${cell.variant}`;
22473
+ const cy = cell.y + cell.h / 2;
22474
+ const br = 11;
22475
+ const drawBadge = (bcx) => {
22476
+ parts.push(circle({ cx: bcx, cy, r: br, class: `sx-cmp-badge-${cell.badge.tone}` }));
22477
+ parts.push(
22478
+ text(
22479
+ { x: bcx, y: cy + 0.5, class: "sx-cmp-badge-glyph", "font-family": fontFamily, "text-anchor": "middle", "dominant-baseline": "middle" },
22480
+ cell.badge.glyph === "yes" ? "\u2713" : "\u2717"
22481
+ )
22482
+ );
22483
+ };
22484
+ if (cell.align === "start") {
22485
+ let tx = cell.x + 12;
22486
+ if (cell.badge) {
22487
+ const bcx = cell.x + 12 + br;
22488
+ drawBadge(bcx);
22489
+ tx = bcx + br + 10;
22490
+ } else if (cell.tag === "\u2022") {
22491
+ parts.push(circle({ cx: cell.x + 14, cy, r: 2.6, class: "sx-cmp-bullet" }));
22492
+ tx = cell.x + 24;
22493
+ }
22494
+ if (cell.lines.length) {
22495
+ parts.push(
22496
+ multilineText(
22497
+ { x: tx, y: cy, class: txtClass, "font-family": fontFamily, "dominant-baseline": "middle" },
22498
+ cell.lines.join("<br/>"),
22499
+ C_LINE_H
22500
+ )
22501
+ );
22502
+ }
22503
+ } else if (cell.badge) {
22504
+ const bcx = cell.x + 18 + br;
22505
+ drawBadge(bcx);
22506
+ const labelCx = (bcx + br + 6 + (cell.x + cell.w - 12)) / 2;
22507
+ parts.push(
22508
+ multilineText(
22509
+ { x: labelCx, y: cy, class: txtClass, "font-family": fontFamily, "text-anchor": "middle", "dominant-baseline": "middle" },
22510
+ cell.lines.join("<br/>"),
22511
+ C_LINE_H
22512
+ )
22513
+ );
22514
+ } else if (cell.glyph && cell.lines.length === 0) {
22515
+ parts.push(
22516
+ text(
22517
+ { x: cell.x + cell.w / 2, y: cy, class: `sx-cmp-glyph ${glyphTextClass(cell.glyph)}`, "font-family": fontFamily, "text-anchor": "middle", "dominant-baseline": "middle" },
22518
+ glyphChar(cell.glyph)
22519
+ )
22520
+ );
22521
+ } else if (cell.lines.length) {
22522
+ parts.push(
22523
+ multilineText(
22524
+ { x: cell.x + cell.w / 2, y: cy, class: txtClass, "font-family": fontFamily, "text-anchor": "middle", "dominant-baseline": "middle" },
22525
+ cell.lines.join("<br/>"),
22526
+ C_LINE_H
22527
+ )
22528
+ );
22529
+ }
22530
+ if (cell.tag && cell.tag !== "\u2022") {
22531
+ if (cell.variant === "baseline") {
22532
+ parts.push(
22533
+ text(
22534
+ { x: cell.x + cell.w / 2, y: cell.y + cell.h - 5, class: "sx-cmp-tag", "font-family": fontFamily, "text-anchor": "middle" },
22535
+ cell.tag
22536
+ )
22537
+ );
22538
+ } else {
22539
+ parts.push(
22540
+ text(
22541
+ { x: cell.x + cell.w - 5, y: cell.y + 13, class: "sx-cmp-tag", "font-family": fontFamily, "text-anchor": "end" },
22542
+ cell.tag
22543
+ )
22544
+ );
22545
+ }
22546
+ }
22547
+ const attrs = { class: "sx-cmp-cell-g", "data-variant": cell.variant };
22548
+ if (cell.glyph) attrs["data-glyph"] = cell.glyph;
22549
+ return group(attrs, parts);
22550
+ }
22551
+ function roundedTopRectPath(x, y, w, h, r7) {
22552
+ const rr = Math.max(0, Math.min(r7, w / 2, h));
22553
+ return `M ${x} ${y + h} L ${x} ${y + rr} Q ${x} ${y} ${x + rr} ${y} L ${x + w - rr} ${y} Q ${x + w} ${y} ${x + w} ${y + rr} L ${x + w} ${y + h} Z`;
22554
+ }
22555
+ function glyphChar(g) {
22556
+ return g === "yes" ? "\u2713" : g === "no" ? "\u2717" : g === "partial" ? "~" : "\u2014";
22557
+ }
22558
+ function glyphTextClass(g) {
22559
+ return g === "yes" ? "sx-cmp-txt-pos" : g === "no" ? "sx-cmp-txt-neg" : g === "partial" ? "sx-cmp-txt-warn" : "sx-cmp-txt-body";
22560
+ }
22561
+ function summarise7(layout) {
22562
+ const { ast } = layout;
22563
+ const parts = [];
22564
+ switch (ast.mode) {
22565
+ case "tchart":
22566
+ parts.push(`T-chart comparing ${ast.columns.length} column${plural2(ast.columns.length)}: ${ast.columns.map((c) => `"${c.label}"`).join(", ")}.`);
22567
+ break;
22568
+ case "pros-cons":
22569
+ parts.push(`Pros/cons${ast.subject ? ` for "${ast.subject}"` : ""}: ${ast.pros.length} pro${plural2(ast.pros.length)}, ${ast.cons.length} con${plural2(ast.cons.length)}.`);
22570
+ break;
22571
+ case "matrix":
22572
+ parts.push(`Comparison matrix: ${ast.options.length} option${plural2(ast.options.length)} \xD7 ${ast.criteria.length} criteria.`);
22573
+ break;
22574
+ case "decision":
22575
+ parts.push(`Decision matrix: ${ast.options.length} option${plural2(ast.options.length)} \xD7 ${ast.criteria.length} weighted criteria.`);
22576
+ if (layout.caption) parts.push(layout.caption);
22577
+ break;
22578
+ case "double-bubble":
22579
+ parts.push(`Double-bubble comparing "${ast.bubble?.left}" and "${ast.bubble?.right}": ${ast.bubble?.shared.length ?? 0} shared, ${ast.bubble?.leftOnly.length ?? 0}/${ast.bubble?.rightOnly.length ?? 0} unique.`);
22580
+ break;
22581
+ }
22582
+ for (const w of ast.warnings) parts.push(w);
22583
+ return parts.join(" ");
22584
+ }
22585
+ function plural2(n) {
22586
+ return n === 1 ? "" : "s";
22587
+ }
22588
+
22589
+ // src/diagrams/comparison/index.ts
22590
+ var comparison = {
22591
+ type: "comparison",
22592
+ detect(text2) {
22593
+ return /^\s*(comparison|compare|vs|tchart|t-chart|pugh|decision-matrix|decisionmatrix)\b/i.test(text2);
22594
+ },
22595
+ parse: parseComparison,
22596
+ render(text2, config) {
22597
+ return renderComparison(text2, config);
22598
+ }
22599
+ };
22600
+
21293
22601
  // src/diagrams/causalloop/parser.ts
21294
22602
  var CausalLoopParseError = class extends Error {
21295
22603
  constructor(message, line2) {
@@ -21312,7 +22620,7 @@ function parseCausalLoop(text2) {
21312
22620
  let i = 0;
21313
22621
  let headerSeen = false;
21314
22622
  for (; i < lines.length; i++) {
21315
- const t = stripComment8(lines[i] ?? "").trim();
22623
+ const t = stripComment9(lines[i] ?? "").trim();
21316
22624
  if (t === "") continue;
21317
22625
  const h = /^(causalloop|cld)\b(.*)$/i.exec(t);
21318
22626
  if (h) {
@@ -21333,7 +22641,7 @@ function parseCausalLoop(text2) {
21333
22641
  );
21334
22642
  }
21335
22643
  for (; i < lines.length; i++) {
21336
- const t = stripComment8(lines[i] ?? "").trim();
22644
+ const t = stripComment9(lines[i] ?? "").trim();
21337
22645
  if (t === "") continue;
21338
22646
  const lineNo = i + 1;
21339
22647
  const lm = /^layout\s*:\s*(\S+)/i.exec(t);
@@ -21355,9 +22663,9 @@ function parseCausalLoop(text2) {
21355
22663
  parseLinkLine(ast, t, lineNo);
21356
22664
  continue;
21357
22665
  }
21358
- ast.warnings.push(`Line ${lineNo}: unrecognised line: "${truncate7(t, 80)}"`);
22666
+ ast.warnings.push(`Line ${lineNo}: unrecognised line: "${truncate8(t, 80)}"`);
21359
22667
  }
21360
- validate4(ast);
22668
+ validate5(ast);
21361
22669
  return ast;
21362
22670
  }
21363
22671
  function parseVarLine(ast, rest, lineNo) {
@@ -21369,7 +22677,7 @@ function parseLoopLine(ast, rest, lineNo) {
21369
22677
  const m = /^([RB]\d+)\s+(.+)$/i.exec(rest);
21370
22678
  if (!m) {
21371
22679
  throw new CausalLoopParseError(
21372
- `'loop' needs a loop id (e.g. R1, B1) and a phrase, got "${truncate7(rest, 60)}"`,
22680
+ `'loop' needs a loop id (e.g. R1, B1) and a phrase, got "${truncate8(rest, 60)}"`,
21373
22681
  lineNo
21374
22682
  );
21375
22683
  }
@@ -21380,7 +22688,7 @@ function parseLoopLine(ast, rest, lineNo) {
21380
22688
  function parseLinkLine(ast, t, lineNo) {
21381
22689
  const arrowIdx = topLevelArrow(t);
21382
22690
  if (arrowIdx < 0) {
21383
- throw new CausalLoopParseError(`malformed link (expected '->'): "${truncate7(t, 60)}"`, lineNo);
22691
+ throw new CausalLoopParseError(`malformed link (expected '->'): "${truncate8(t, 60)}"`, lineNo);
21384
22692
  }
21385
22693
  const fromRaw = t.slice(0, arrowIdx).trim();
21386
22694
  let rhs = t.slice(arrowIdx + 2).trim();
@@ -21422,7 +22730,7 @@ function parseLinkLine(ast, t, lineNo) {
21422
22730
  if (label) link.label = label;
21423
22731
  ast.links.push(link);
21424
22732
  }
21425
- function validate4(ast) {
22733
+ function validate5(ast) {
21426
22734
  if (ast.links.length === 0) {
21427
22735
  throw new CausalLoopParseError(
21428
22736
  "a causal loop diagram needs at least one causal link (A -> B : +)"
@@ -21502,7 +22810,7 @@ function stripLeadingQuoted(s) {
21502
22810
  return void 0;
21503
22811
  }
21504
22812
  }
21505
- function stripComment8(line2) {
22813
+ function stripComment9(line2) {
21506
22814
  let i = 0;
21507
22815
  while (i < line2.length) {
21508
22816
  const ch = line2[i];
@@ -21518,7 +22826,7 @@ function stripComment8(line2) {
21518
22826
  }
21519
22827
  return line2;
21520
22828
  }
21521
- function truncate7(s, n) {
22829
+ function truncate8(s, n) {
21522
22830
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
21523
22831
  }
21524
22832
 
@@ -21675,17 +22983,17 @@ var CAUSALLOOP_CONST = {
21675
22983
  };
21676
22984
  function layoutCausalLoop(ast) {
21677
22985
  const analysis = analyseCausalLoop(ast);
21678
- const C2 = CAUSALLOOP_CONST;
22986
+ const C3 = CAUSALLOOP_CONST;
21679
22987
  const nodes = /* @__PURE__ */ new Map();
21680
22988
  for (const v of ast.variables) {
21681
- const halfW = Math.max(20, v.label.length * C2.CHAR_W / 2);
22989
+ const halfW = Math.max(20, v.label.length * C3.CHAR_W / 2);
21682
22990
  nodes.set(v.id, {
21683
22991
  id: v.id,
21684
22992
  label: v.label,
21685
22993
  cx: 0,
21686
22994
  cy: 0,
21687
22995
  halfW,
21688
- halfH: C2.LABEL_H / 2
22996
+ halfH: C3.LABEL_H / 2
21689
22997
  });
21690
22998
  }
21691
22999
  const ringIds = ringOrder(ast, analysis);
@@ -21695,9 +23003,9 @@ function layoutCausalLoop(ast) {
21695
23003
  let cy0 = 0;
21696
23004
  let ringR = 0;
21697
23005
  if (ringIds.length > 0) {
21698
- ringR = Math.max(C2.MIN_RING_R, C2.RING_GAP * ringIds.length / (2 * Math.PI));
21699
- cx0 = C2.CANVAS_PAD + ringR + maxHalfW(ringIds, nodes);
21700
- cy0 = C2.CANVAS_PAD + ringR + C2.LABEL_H;
23006
+ ringR = Math.max(C3.MIN_RING_R, C3.RING_GAP * ringIds.length / (2 * Math.PI));
23007
+ cx0 = C3.CANVAS_PAD + ringR + maxHalfW(ringIds, nodes);
23008
+ cy0 = C3.CANVAS_PAD + ringR + C3.LABEL_H;
21701
23009
  const step = 2 * Math.PI / ringIds.length;
21702
23010
  ringIds.forEach((id, i) => {
21703
23011
  const ang = -Math.PI / 2 + i * step;
@@ -21707,14 +23015,14 @@ function layoutCausalLoop(ast) {
21707
23015
  });
21708
23016
  }
21709
23017
  if (openIds.length > 0) {
21710
- const rowY = ringIds.length > 0 ? cy0 + ringR + C2.OPEN_ROW_GAP : C2.CANVAS_PAD + C2.LABEL_H;
21711
- let x = C2.CANVAS_PAD;
23018
+ const rowY = ringIds.length > 0 ? cy0 + ringR + C3.OPEN_ROW_GAP : C3.CANVAS_PAD + C3.LABEL_H;
23019
+ let x = C3.CANVAS_PAD;
21712
23020
  for (const id of openIds) {
21713
23021
  const node = nodes.get(id);
21714
23022
  x += node.halfW;
21715
23023
  node.cx = x;
21716
23024
  node.cy = rowY;
21717
- x += node.halfW + C2.OPEN_ROW_GAP;
23025
+ x += node.halfW + C3.OPEN_ROW_GAP;
21718
23026
  }
21719
23027
  }
21720
23028
  const center = { x: cx0, y: cy0 };
@@ -21742,8 +23050,8 @@ function layoutCausalLoop(ast) {
21742
23050
  maxX = Math.max(maxX, l.polarityX + 12);
21743
23051
  maxY = Math.max(maxY, l.polarityY + 12);
21744
23052
  }
21745
- const width = Math.ceil(maxX + C2.CANVAS_PAD);
21746
- const height = Math.ceil(maxY + C2.CANVAS_PAD);
23053
+ const width = Math.ceil(maxX + C3.CANVAS_PAD);
23054
+ const height = Math.ceil(maxY + C3.CANVAS_PAD);
21747
23055
  return {
21748
23056
  ast,
21749
23057
  analysis,
@@ -21781,7 +23089,7 @@ function ringOrder(ast, analysis) {
21781
23089
  return order;
21782
23090
  }
21783
23091
  function layoutLink(l, idx, nodes, center, ringSet, pairIndex) {
21784
- const C2 = CAUSALLOOP_CONST;
23092
+ const C3 = CAUSALLOOP_CONST;
21785
23093
  const a = nodes.get(l.from);
21786
23094
  const b = nodes.get(l.to);
21787
23095
  if (l.from === l.to) {
@@ -21809,17 +23117,17 @@ function layoutLink(l, idx, nodes, center, ringSet, pairIndex) {
21809
23117
  ny = ux;
21810
23118
  }
21811
23119
  const side = pairIndex % 2 === 0 ? 1 : -1;
21812
- const bow = dist * C2.CURVE_BOW * side;
23120
+ const bow = dist * C3.CURVE_BOW * side;
21813
23121
  const ctrlX = mx + nx * bow;
21814
23122
  const ctrlY = my + ny * bow;
21815
- const path2 = `M ${fmt3(start.x)} ${fmt3(start.y)} Q ${fmt3(ctrlX)} ${fmt3(ctrlY)} ${fmt3(end.x)} ${fmt3(end.y)}`;
23123
+ const path2 = `M ${fmt4(start.x)} ${fmt4(start.y)} Q ${fmt4(ctrlX)} ${fmt4(ctrlY)} ${fmt4(end.x)} ${fmt4(end.y)}`;
21816
23124
  let tx = end.x - ctrlX;
21817
23125
  let ty = end.y - ctrlY;
21818
23126
  const tn = Math.hypot(tx, ty) || 1;
21819
23127
  tx /= tn;
21820
23128
  ty /= tn;
21821
- const polarityX = end.x - tx * C2.HEAD_OFFSET + nx * side * 10;
21822
- const polarityY = end.y - ty * C2.HEAD_OFFSET + ny * side * 10;
23129
+ const polarityX = end.x - tx * C3.HEAD_OFFSET + nx * side * 10;
23130
+ const polarityY = end.y - ty * C3.HEAD_OFFSET + ny * side * 10;
21823
23131
  const result = {
21824
23132
  linkIndex: idx,
21825
23133
  from: l.from,
@@ -21856,9 +23164,9 @@ function selfLink(l, idx, a) {
21856
23164
  const x1 = a.cx - a.halfW * 0.4;
21857
23165
  const x2 = a.cx + a.halfW * 0.4;
21858
23166
  const loopTop = topY - 34;
21859
- const path2 = `M ${fmt3(x1)} ${fmt3(topY)} C ${fmt3(x1 - 12)} ${fmt3(loopTop)} ${fmt3(
23167
+ const path2 = `M ${fmt4(x1)} ${fmt4(topY)} C ${fmt4(x1 - 12)} ${fmt4(loopTop)} ${fmt4(
21860
23168
  x2 + 12
21861
- )} ${fmt3(loopTop)} ${fmt3(x2)} ${fmt3(topY)}`;
23169
+ )} ${fmt4(loopTop)} ${fmt4(x2)} ${fmt4(topY)}`;
21862
23170
  const result = {
21863
23171
  linkIndex: idx,
21864
23172
  from: l.from,
@@ -21885,7 +23193,7 @@ function boxExit(node, ux, uy) {
21885
23193
  return { x: node.cx + ux * t, y: node.cy + uy * t };
21886
23194
  }
21887
23195
  function layoutGlyph(loop, nodes, center) {
21888
- const C2 = CAUSALLOOP_CONST;
23196
+ const C3 = CAUSALLOOP_CONST;
21889
23197
  const pts = loop.variables.map((id) => nodes.get(id));
21890
23198
  let sx = 0;
21891
23199
  let sy = 0;
@@ -21925,10 +23233,10 @@ function layoutGlyph(loop, nodes, center) {
21925
23233
  loop,
21926
23234
  cx: gx,
21927
23235
  cy: gy,
21928
- r: C2.GLYPH_R,
23236
+ r: C3.GLYPH_R,
21929
23237
  clockwise,
21930
23238
  phraseX: gx,
21931
- phraseY: gy + C2.GLYPH_R + 13
23239
+ phraseY: gy + C3.GLYPH_R + 13
21932
23240
  };
21933
23241
  }
21934
23242
  function maxHalfW(ids, nodes) {
@@ -21936,7 +23244,7 @@ function maxHalfW(ids, nodes) {
21936
23244
  for (const id of ids) m = Math.max(m, nodes.get(id).halfW);
21937
23245
  return m;
21938
23246
  }
21939
- function fmt3(n) {
23247
+ function fmt4(n) {
21940
23248
  return (Math.round(n * 100) / 100).toString();
21941
23249
  }
21942
23250
 
@@ -21983,7 +23291,7 @@ function renderCausalLoopLayout(layout, config) {
21983
23291
  );
21984
23292
  const children = [
21985
23293
  title(a11y),
21986
- desc(summarise7(layout)),
23294
+ desc(summarise8(layout)),
21987
23295
  styleBlock,
21988
23296
  el("rect", { x: 0, y: 0, width, height, class: "sx-cld-bg" })
21989
23297
  ];
@@ -22091,9 +23399,9 @@ function arrowhead(x, y, tx, ty) {
22091
23399
  const by = y - ty * len;
22092
23400
  const px = -ty;
22093
23401
  const py = tx;
22094
- const p1 = `${fmt4(bx + px * wide)},${fmt4(by + py * wide)}`;
22095
- const p2 = `${fmt4(bx - px * wide)},${fmt4(by - py * wide)}`;
22096
- const tip = `${fmt4(x)},${fmt4(y)}`;
23402
+ const p1 = `${fmt5(bx + px * wide)},${fmt5(by + py * wide)}`;
23403
+ const p2 = `${fmt5(bx - px * wide)},${fmt5(by - py * wide)}`;
23404
+ const tip = `${fmt5(x)},${fmt5(y)}`;
22097
23405
  return polygon({ points: `${tip} ${p1} ${p2}`, class: "sx-cld-arrow" });
22098
23406
  }
22099
23407
  function renderGlyph(g) {
@@ -22107,7 +23415,7 @@ function renderGlyph(g) {
22107
23415
  const ey = g.cy + r7 * Math.sin(endAng);
22108
23416
  const largeArc = 1;
22109
23417
  const sweepFlag = g.clockwise ? 1 : 0;
22110
- const arc = `M ${fmt4(sx)} ${fmt4(sy)} A ${r7} ${r7} 0 ${largeArc} ${sweepFlag} ${fmt4(ex)} ${fmt4(ey)}`;
23418
+ const arc = `M ${fmt5(sx)} ${fmt5(sy)} A ${r7} ${r7} 0 ${largeArc} ${sweepFlag} ${fmt5(ex)} ${fmt5(ey)}`;
22111
23419
  const dir = g.clockwise ? 1 : -1;
22112
23420
  const tx = -Math.sin(endAng) * dir;
22113
23421
  const ty = Math.cos(endAng) * dir;
@@ -22148,11 +23456,11 @@ function glyphArrow(x, y, tx, ty) {
22148
23456
  const by = y - ty * len;
22149
23457
  const px = -ty;
22150
23458
  const py = tx;
22151
- const p1 = `${fmt4(bx + px * wide)},${fmt4(by + py * wide)}`;
22152
- const p2 = `${fmt4(bx - px * wide)},${fmt4(by - py * wide)}`;
22153
- return polygon({ points: `${fmt4(x)},${fmt4(y)} ${p1} ${p2}`, class: "sx-cld-glyph-head" });
23459
+ const p1 = `${fmt5(bx + px * wide)},${fmt5(by + py * wide)}`;
23460
+ const p2 = `${fmt5(bx - px * wide)},${fmt5(by - py * wide)}`;
23461
+ return polygon({ points: `${fmt5(x)},${fmt5(y)} ${p1} ${p2}`, class: "sx-cld-glyph-head" });
22154
23462
  }
22155
- function summarise7(layout) {
23463
+ function summarise8(layout) {
22156
23464
  const { ast, analysis } = layout;
22157
23465
  const parts = [
22158
23466
  `Causal loop diagram${ast.title ? ` "${ast.title}"` : ""}: ${ast.variables.length} variable${ast.variables.length === 1 ? "" : "s"}, ${ast.links.length} causal link${ast.links.length === 1 ? "" : "s"}.`
@@ -22178,7 +23486,7 @@ function summarise7(layout) {
22178
23486
  for (const w of ast.warnings) parts.push(w);
22179
23487
  return parts.join(" ");
22180
23488
  }
22181
- function fmt4(n) {
23489
+ function fmt5(n) {
22182
23490
  return (Math.round(n * 100) / 100).toString();
22183
23491
  }
22184
23492
 
@@ -22406,11 +23714,11 @@ function analyseMarkov(ast) {
22406
23714
  if (Math.abs(sum - 1) > ROW_SUM_TOL) {
22407
23715
  if (ast.normalize) {
22408
23716
  for (let j = 0; j < n; j++) P[i][j] /= sum;
22409
- notes.push(`State "${order[i]}" out-edges summed to ${round7(sum)}; normalised to 1 (normalize: true).`);
23717
+ notes.push(`State "${order[i]}" out-edges summed to ${round9(sum)}; normalised to 1 (normalize: true).`);
22410
23718
  } else {
22411
23719
  const st = ast.states[i];
22412
23720
  throw new MarkovParseError(
22413
- `state "${order[i]}": outgoing probabilities sum to ${round7(sum)}, must be 1.0 \u2014 fix the values or set "normalize: true"`,
23721
+ `state "${order[i]}": outgoing probabilities sum to ${round9(sum)}, must be 1.0 \u2014 fix the values or set "normalize: true"`,
22414
23722
  st.line
22415
23723
  );
22416
23724
  }
@@ -22454,17 +23762,17 @@ function classifyStates(P, order, ast) {
22454
23762
  if (indexOf[s] !== -1) continue;
22455
23763
  const work = [{ v: s, pi: 0 }];
22456
23764
  while (work.length > 0) {
22457
- const frame = work[work.length - 1];
22458
- const v = frame.v;
22459
- if (frame.pi === 0) {
23765
+ const frame2 = work[work.length - 1];
23766
+ const v = frame2.v;
23767
+ if (frame2.pi === 0) {
22460
23768
  indexOf[v] = lowlink[v] = counter++;
22461
23769
  stack.push(v);
22462
23770
  onStack[v] = true;
22463
23771
  }
22464
23772
  let recursed = false;
22465
- while (frame.pi < adj[v].length) {
22466
- const w = adj[v][frame.pi];
22467
- frame.pi++;
23773
+ while (frame2.pi < adj[v].length) {
23774
+ const w = adj[v][frame2.pi];
23775
+ frame2.pi++;
22468
23776
  if (indexOf[w] === -1) {
22469
23777
  work.push({ v: w, pi: 0 });
22470
23778
  recursed = true;
@@ -22743,7 +24051,7 @@ function invert(mat) {
22743
24051
  }
22744
24052
  return A.map((row) => row.slice(m));
22745
24053
  }
22746
- function round7(x) {
24054
+ function round9(x) {
22747
24055
  return Math.round(x * 1e6) / 1e6;
22748
24056
  }
22749
24057
 
@@ -22767,7 +24075,7 @@ var MARKOV_CONST = {
22767
24075
  };
22768
24076
  function layoutMarkov(ast) {
22769
24077
  const analysis = analyseMarkov(ast);
22770
- const C2 = MARKOV_CONST;
24078
+ const C3 = MARKOV_CONST;
22771
24079
  const states = ast.states;
22772
24080
  states.length;
22773
24081
  const classOf = analysis.classification?.byState;
@@ -22780,9 +24088,9 @@ function layoutMarkov(ast) {
22780
24088
  let width = 0;
22781
24089
  let height = 0;
22782
24090
  if (ast.layout === "layered" && analysis.classification) {
22783
- ({ width, height } = placeLayered(ast, analysis.classification, centres, C2));
24091
+ ({ width, height } = placeLayered(ast, analysis.classification, centres, C3));
22784
24092
  } else {
22785
- ({ width, height } = placeRing(states.map((s) => s.id), centres, C2));
24093
+ ({ width, height } = placeRing(states.map((s) => s.id), centres, C3));
22786
24094
  }
22787
24095
  const ringCenter = { x: width / 2, y: height / 2 };
22788
24096
  const boxes = states.map((st) => {
@@ -22794,7 +24102,7 @@ function layoutMarkov(ast) {
22794
24102
  state: st,
22795
24103
  cx: c.x,
22796
24104
  cy: c.y,
22797
- r: C2.STATE_R,
24105
+ r: C3.STATE_R,
22798
24106
  isAbsorbing
22799
24107
  };
22800
24108
  if (tag) box2.classTag = tag;
@@ -22806,18 +24114,18 @@ function layoutMarkov(ast) {
22806
24114
  for (const tr of ast.transitions) present.add(arcKey(tr.from, tr.to));
22807
24115
  const arcs = ast.transitions.map((tr) => {
22808
24116
  if (tr.self) {
22809
- return selfLoopGeom(tr, centres.get(tr.from), ringCenter, ast.layout, C2);
24117
+ return selfLoopGeom(tr, centres.get(tr.from), ringCenter, ast.layout, C3);
22810
24118
  }
22811
24119
  const a = centres.get(tr.from);
22812
24120
  const b = centres.get(tr.to);
22813
24121
  const hasReverse = present.has(arcKey(tr.to, tr.from));
22814
24122
  const sign = hasReverse ? tr.from < tr.to ? 1 : -1 : 1;
22815
- const bow = hasReverse ? C2.BOW : C2.SOLO_BOW;
22816
- return curvedArcGeom(tr, a, b, sign * bow, C2);
24123
+ const bow = hasReverse ? C3.BOW : C3.SOLO_BOW;
24124
+ return curvedArcGeom(tr, a, b, sign * bow, C3);
22817
24125
  });
22818
24126
  return {
22819
24127
  width,
22820
- height: height + (ast.title ? C2.TITLE_BAND : 0),
24128
+ height: height + (ast.title ? C3.TITLE_BAND : 0),
22821
24129
  ...ast.title ? { title: ast.title } : {},
22822
24130
  states: boxes,
22823
24131
  arcs,
@@ -22825,28 +24133,28 @@ function layoutMarkov(ast) {
22825
24133
  ast
22826
24134
  };
22827
24135
  }
22828
- function placeRing(ids, centres, C2) {
24136
+ function placeRing(ids, centres, C3) {
22829
24137
  const n = ids.length;
22830
24138
  if (n === 1) {
22831
- const cx = C2.PADDING + C2.STATE_R + C2.LOOP_OUT;
22832
- const cy = C2.PADDING + C2.STATE_R + C2.LOOP_OUT;
24139
+ const cx = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
24140
+ const cy = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
22833
24141
  centres.set(ids[0], { x: cx, y: cy });
22834
24142
  const dim2 = 2 * cx;
22835
24143
  return { width: dim2, height: dim2 };
22836
24144
  }
22837
24145
  if (n === 2) {
22838
- const cy = C2.PADDING + C2.STATE_R + C2.LOOP_OUT;
22839
- const dx = 2 * C2.STATE_R + C2.RING_GAP + 60;
22840
- const cx02 = C2.PADDING + C2.STATE_R + C2.LOOP_OUT;
24146
+ const cy = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
24147
+ const dx = 2 * C3.STATE_R + C3.RING_GAP + 60;
24148
+ const cx02 = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
22841
24149
  centres.set(ids[0], { x: cx02, y: cy });
22842
24150
  centres.set(ids[1], { x: cx02 + dx, y: cy });
22843
- const width = cx02 + dx + C2.STATE_R + C2.LOOP_OUT + C2.PADDING;
22844
- const height = cy + C2.STATE_R + C2.LOOP_OUT + C2.PADDING;
24151
+ const width = cx02 + dx + C3.STATE_R + C3.LOOP_OUT + C3.PADDING;
24152
+ const height = cy + C3.STATE_R + C3.LOOP_OUT + C3.PADDING;
22845
24153
  return { width, height };
22846
24154
  }
22847
- const minArc = 2 * C2.STATE_R + C2.RING_GAP;
22848
- const radius = Math.max(minArc / (2 * Math.sin(Math.PI / n)), 2 * C2.STATE_R);
22849
- const margin = C2.PADDING + C2.STATE_R + C2.LOOP_OUT;
24155
+ const minArc = 2 * C3.STATE_R + C3.RING_GAP;
24156
+ const radius = Math.max(minArc / (2 * Math.sin(Math.PI / n)), 2 * C3.STATE_R);
24157
+ const margin = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
22850
24158
  const cx0 = margin + radius;
22851
24159
  const cy0 = margin + radius;
22852
24160
  ids.forEach((id, i) => {
@@ -22859,7 +24167,7 @@ function placeRing(ids, centres, C2) {
22859
24167
  const dim = 2 * (radius + margin);
22860
24168
  return { width: dim, height: dim };
22861
24169
  }
22862
- function placeLayered(ast, classification, centres, C2) {
24170
+ function placeLayered(ast, classification, centres, C3) {
22863
24171
  const tier = (id) => {
22864
24172
  const k = classification.byState[id];
22865
24173
  if (k === "absorbing") return 2;
@@ -22869,18 +24177,18 @@ function placeLayered(ast, classification, centres, C2) {
22869
24177
  const cols = [[], [], []];
22870
24178
  for (const st of ast.states) cols[tier(st.id)].push(st.id);
22871
24179
  const maxRows = Math.max(1, ...cols.map((c) => c.length));
22872
- const margin = C2.PADDING + C2.STATE_R + C2.LOOP_OUT;
24180
+ const margin = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
22873
24181
  cols.forEach((col, ci) => {
22874
- const x = margin + ci * C2.TIER_DX;
22875
- const totalH = (col.length - 1) * C2.TIER_DY;
22876
- const startY = margin + ((maxRows - 1) * C2.TIER_DY - totalH) / 2;
22877
- col.forEach((id, ri) => centres.set(id, { x, y: startY + ri * C2.TIER_DY }));
24182
+ const x = margin + ci * C3.TIER_DX;
24183
+ const totalH = (col.length - 1) * C3.TIER_DY;
24184
+ const startY = margin + ((maxRows - 1) * C3.TIER_DY - totalH) / 2;
24185
+ col.forEach((id, ri) => centres.set(id, { x, y: startY + ri * C3.TIER_DY }));
22878
24186
  });
22879
- const width = margin + 2 * C2.TIER_DX + C2.STATE_R + C2.LOOP_OUT + C2.PADDING;
22880
- const height = margin + (maxRows - 1) * C2.TIER_DY + C2.STATE_R + C2.LOOP_OUT + C2.PADDING;
24187
+ const width = margin + 2 * C3.TIER_DX + C3.STATE_R + C3.LOOP_OUT + C3.PADDING;
24188
+ const height = margin + (maxRows - 1) * C3.TIER_DY + C3.STATE_R + C3.LOOP_OUT + C3.PADDING;
22881
24189
  return { width, height };
22882
24190
  }
22883
- function curvedArcGeom(tr, a, b, bow, C2) {
24191
+ function curvedArcGeom(tr, a, b, bow, C3) {
22884
24192
  const dx = b.x - a.x;
22885
24193
  const dy = b.y - a.y;
22886
24194
  const len = Math.hypot(dx, dy) || 1;
@@ -22893,8 +24201,8 @@ function curvedArcGeom(tr, a, b, bow, C2) {
22893
24201
  x: (a.x + b.x) / 2 + nx * bow,
22894
24202
  y: (a.y + b.y) / 2 + ny * bow
22895
24203
  };
22896
- const start = aimToBoundary(a, mid, C2.STATE_R);
22897
- const end = aimToBoundary(b, mid, C2.STATE_R);
24204
+ const start = aimToBoundary(a, mid, C3.STATE_R);
24205
+ const end = aimToBoundary(b, mid, C3.STATE_R);
22898
24206
  const c1 = { x: (start.x + mid.x) / 2, y: (start.y + mid.y) / 2 };
22899
24207
  const c2 = { x: (end.x + mid.x) / 2, y: (end.y + mid.y) / 2 };
22900
24208
  return {
@@ -22911,7 +24219,7 @@ function aimToBoundary(centre, target, r7) {
22911
24219
  const len = Math.hypot(dx, dy) || 1;
22912
24220
  return { x: centre.x + dx / len * r7, y: centre.y + dy / len * r7 };
22913
24221
  }
22914
- function selfLoopGeom(tr, c, ringCenter, layout, C2) {
24222
+ function selfLoopGeom(tr, c, ringCenter, layout, C3) {
22915
24223
  let ox = c.x - ringCenter.x;
22916
24224
  let oy = c.y - ringCenter.y;
22917
24225
  if (layout === "layered" || ox === 0 && oy === 0) {
@@ -22923,26 +24231,26 @@ function selfLoopGeom(tr, c, ringCenter, layout, C2) {
22923
24231
  const uy = oy / ol;
22924
24232
  const tx = -uy;
22925
24233
  const ty = ux;
22926
- const spread = C2.STATE_R * 0.6;
24234
+ const spread = C3.STATE_R * 0.6;
22927
24235
  const foot1 = {
22928
- x: c.x + ux * C2.STATE_R * 0.85 - tx * spread,
22929
- y: c.y + uy * C2.STATE_R * 0.85 - ty * spread
24236
+ x: c.x + ux * C3.STATE_R * 0.85 - tx * spread,
24237
+ y: c.y + uy * C3.STATE_R * 0.85 - ty * spread
22930
24238
  };
22931
24239
  const foot2 = {
22932
- x: c.x + ux * C2.STATE_R * 0.85 + tx * spread,
22933
- y: c.y + uy * C2.STATE_R * 0.85 + ty * spread
24240
+ x: c.x + ux * C3.STATE_R * 0.85 + tx * spread,
24241
+ y: c.y + uy * C3.STATE_R * 0.85 + ty * spread
22934
24242
  };
22935
24243
  const apex = {
22936
- x: c.x + ux * (C2.STATE_R + C2.LOOP_OUT),
22937
- y: c.y + uy * (C2.STATE_R + C2.LOOP_OUT)
24244
+ x: c.x + ux * (C3.STATE_R + C3.LOOP_OUT),
24245
+ y: c.y + uy * (C3.STATE_R + C3.LOOP_OUT)
22938
24246
  };
22939
24247
  const ctrl1 = {
22940
- x: foot1.x + ux * C2.LOOP_OUT - tx * C2.LOOP_R,
22941
- y: foot1.y + uy * C2.LOOP_OUT - ty * C2.LOOP_R
24248
+ x: foot1.x + ux * C3.LOOP_OUT - tx * C3.LOOP_R,
24249
+ y: foot1.y + uy * C3.LOOP_OUT - ty * C3.LOOP_R
22942
24250
  };
22943
24251
  const ctrl2 = {
22944
- x: foot2.x + ux * C2.LOOP_OUT + tx * C2.LOOP_R,
22945
- y: foot2.y + uy * C2.LOOP_OUT + ty * C2.LOOP_R
24252
+ x: foot2.x + ux * C3.LOOP_OUT + tx * C3.LOOP_R,
24253
+ y: foot2.y + uy * C3.LOOP_OUT + ty * C3.LOOP_R
22946
24254
  };
22947
24255
  return {
22948
24256
  transition: tr,
@@ -23019,7 +24327,7 @@ function renderState2(sb) {
23019
24327
  parts.push(
23020
24328
  text(
23021
24329
  { class: "sx-markov-pi", x: sb.cx, y: sb.cy + sb.r + 14, "text-anchor": "middle" },
23022
- `\u03C0=${fmt5(sb.pi)}`
24330
+ `\u03C0=${fmt6(sb.pi)}`
23023
24331
  )
23024
24332
  );
23025
24333
  }
@@ -23028,7 +24336,7 @@ function renderState2(sb) {
23028
24336
  "data-id": sb.state.id
23029
24337
  };
23030
24338
  if (sb.classTag) attrs["data-class"] = sb.classTag;
23031
- if (sb.pi !== void 0) attrs["data-pi"] = fmt5(sb.pi);
24339
+ if (sb.pi !== void 0) attrs["data-pi"] = fmt6(sb.pi);
23032
24340
  return group(attrs, parts);
23033
24341
  }
23034
24342
  function arcPath2(ag) {
@@ -23041,7 +24349,7 @@ function renderArc3(ag) {
23041
24349
  path({ class: cls, d: arcPath2(ag), "marker-end": "url(#sx-markov-head)" }),
23042
24350
  text(
23043
24351
  { class: "sx-markov-prob", x: ag.labelX, y: ag.labelY + 3, "text-anchor": "middle" },
23044
- fmt5(ag.transition.probability)
24352
+ fmt6(ag.transition.probability)
23045
24353
  )
23046
24354
  ];
23047
24355
  return group(
@@ -23049,7 +24357,7 @@ function renderArc3(ag) {
23049
24357
  class: ag.self ? "sx-markov-arc-g sx-markov-arc-self-g" : "sx-markov-arc-g",
23050
24358
  "data-from": ag.transition.from,
23051
24359
  "data-to": ag.transition.to,
23052
- "data-prob": fmt5(ag.transition.probability)
24360
+ "data-prob": fmt6(ag.transition.probability)
23053
24361
  },
23054
24362
  parts
23055
24363
  );
@@ -23070,11 +24378,11 @@ function buildDesc(layout) {
23070
24378
  }
23071
24379
  if (a.stationary) {
23072
24380
  if (a.stationary.unique) {
23073
- const entries = layout.analysis.order.filter((id) => a.stationary.pi[id] !== void 0).map((id) => `${id}=${fmt5(a.stationary.pi[id])}`);
24381
+ const entries = layout.analysis.order.filter((id) => a.stationary.pi[id] !== void 0).map((id) => `${id}=${fmt6(a.stationary.pi[id])}`);
23074
24382
  out.push(`Stationary \u03C0: { ${entries.join(", ")} }.`);
23075
24383
  } else if (a.stationary.perClass.length) {
23076
24384
  const blocks = a.stationary.perClass.map((pc2) => {
23077
- const e = pc2.states.map((id) => `${id}=${fmt5(pc2.pi[id])}`).join(", ");
24385
+ const e = pc2.states.map((id) => `${id}=${fmt6(pc2.pi[id])}`).join(", ");
23078
24386
  return `{ ${e} }`;
23079
24387
  });
23080
24388
  out.push(`Stationary \u03C0 (per recurrent class, not globally unique): ${blocks.join("; ")}.`);
@@ -23082,10 +24390,10 @@ function buildDesc(layout) {
23082
24390
  }
23083
24391
  if (a.absorbing) {
23084
24392
  const ab = a.absorbing;
23085
- const tParts = ab.transient.map((id, i) => `${id}=${fmt5(ab.t[i])}`);
24393
+ const tParts = ab.transient.map((id, i) => `${id}=${fmt6(ab.t[i])}`);
23086
24394
  out.push(`Expected steps to absorption t: { ${tParts.join(", ")} }.`);
23087
24395
  const bRows = ab.transient.map((from, i) => {
23088
- const probs = ab.absorbing.map((to, j) => `${to}=${fmt5(ab.B[i][j])}`).join(", ");
24396
+ const probs = ab.absorbing.map((to, j) => `${to}=${fmt6(ab.B[i][j])}`).join(", ");
23089
24397
  return `${from}\u2192(${probs})`;
23090
24398
  });
23091
24399
  out.push(`Absorption probabilities B: ${bRows.join("; ")}.`);
@@ -23141,7 +24449,7 @@ function renderMarkov(textOrAst, config) {
23141
24449
  const layout = layoutMarkov(ast);
23142
24450
  return renderMarkovLayout(layout, config);
23143
24451
  }
23144
- function fmt5(x) {
24452
+ function fmt6(x) {
23145
24453
  if (!Number.isFinite(x)) return String(x);
23146
24454
  const r7 = Math.round(x * 1e3) / 1e3;
23147
24455
  return String(r7);
@@ -23187,7 +24495,7 @@ function parseGitGraph(text2) {
23187
24495
  i = skipBlankAndDirectives(rawLines, i, ast);
23188
24496
  let headerSeen = false;
23189
24497
  while (i < rawLines.length) {
23190
- const t = stripComment9(rawLines[i] ?? "").trim();
24498
+ const t = stripComment10(rawLines[i] ?? "").trim();
23191
24499
  if (t === "") {
23192
24500
  i++;
23193
24501
  continue;
@@ -23195,7 +24503,7 @@ function parseGitGraph(text2) {
23195
24503
  const h = /^gitgraph\b\s*:?\s*(.*)$/i.exec(t);
23196
24504
  if (!h) {
23197
24505
  throw new GitGraphParseError(
23198
- `expected a 'gitGraph' header, got: ${truncate8(t)}`,
24506
+ `expected a 'gitGraph' header, got: ${truncate9(t)}`,
23199
24507
  i + 1
23200
24508
  );
23201
24509
  }
@@ -23214,7 +24522,7 @@ function parseGitGraph(text2) {
23214
24522
  throw new GitGraphParseError("empty gitGraph (no header)");
23215
24523
  }
23216
24524
  for (; i < rawLines.length; i++) {
23217
- const t = stripComment9(rawLines[i] ?? "").trim();
24525
+ const t = stripComment10(rawLines[i] ?? "").trim();
23218
24526
  if (t === "") continue;
23219
24527
  if (/^%%\{/.test(t)) {
23220
24528
  applyInit(t, ast);
@@ -23223,7 +24531,7 @@ function parseGitGraph(text2) {
23223
24531
  const op = parseOperation2(t, i + 1);
23224
24532
  if (op) ast.operations.push(op);
23225
24533
  }
23226
- validate5(ast);
24534
+ validate6(ast);
23227
24535
  return ast;
23228
24536
  }
23229
24537
  function parseOperation2(line2, lineNo) {
@@ -23265,7 +24573,7 @@ function parseOptions(rest, lineNo) {
23265
24573
  const keyMatch = /^([A-Za-z]+)\s*:/.exec(s.slice(i));
23266
24574
  if (!keyMatch) {
23267
24575
  throw new GitGraphParseError(
23268
- `unexpected token near '${truncate8(s.slice(i))}' (expected key: value)`,
24576
+ `unexpected token near '${truncate9(s.slice(i))}' (expected key: value)`,
23269
24577
  lineNo
23270
24578
  );
23271
24579
  }
@@ -23380,7 +24688,7 @@ function parseCherryPick(rest, lineNo) {
23380
24688
  }
23381
24689
  return { kind: "cherry-pick", id: o.id, tag: o.tag, parent: o.parent, line: lineNo };
23382
24690
  }
23383
- function validate5(ast) {
24691
+ function validate6(ast) {
23384
24692
  const firstOp = ast.operations[0];
23385
24693
  if (firstOp && firstOp.kind !== "commit" && firstOp.kind !== "branch") ;
23386
24694
  }
@@ -23401,7 +24709,7 @@ function parseFrontmatter2(lines, start, ast) {
23401
24709
  function skipBlankAndDirectives(lines, start, ast) {
23402
24710
  let i = start;
23403
24711
  for (; i < lines.length; i++) {
23404
- const t = stripComment9(lines[i] ?? "").trim();
24712
+ const t = stripComment10(lines[i] ?? "").trim();
23405
24713
  if (t === "") continue;
23406
24714
  if (/^%%\{/.test(t)) {
23407
24715
  applyInit(t, ast);
@@ -23434,7 +24742,7 @@ function applyConfigLines(lines, ast) {
23434
24742
  if (tv && !/^(LR|TB|BT)$/i.test(tv)) ast.title = tv;
23435
24743
  }
23436
24744
  }
23437
- function stripComment9(line2) {
24745
+ function stripComment10(line2) {
23438
24746
  const idx = line2.indexOf("%%");
23439
24747
  if (idx >= 0 && line2.slice(idx, idx + 3) !== "%%{") {
23440
24748
  return line2.slice(0, idx);
@@ -23444,7 +24752,7 @@ function stripComment9(line2) {
23444
24752
  function isQuote(ch) {
23445
24753
  return ch === '"' || ch === "'" || ch === "\u201C" || ch === "\u2018" || ch === "\u300C" || ch === "\u300E" || ch === "\xAB";
23446
24754
  }
23447
- function truncate8(s) {
24755
+ function truncate9(s) {
23448
24756
  return s.length > 40 ? `${s.slice(0, 40)}\u2026` : s;
23449
24757
  }
23450
24758
 
@@ -23650,18 +24958,18 @@ function assignLanes(ast, state2) {
23650
24958
  }
23651
24959
  function layoutGitGraph(ast) {
23652
24960
  const replay = replayGitGraph(ast);
23653
- const C2 = GITGRAPH_CONST;
24961
+ const C3 = GITGRAPH_CONST;
23654
24962
  const branchByName = new Map(replay.branches.map((b) => [b.name, b]));
23655
24963
  const laneCount = replay.branches.length;
23656
24964
  const commitCount = replay.commits.length;
23657
- const headBand = ast.showBranches ? C2.PILL_GUTTER : C2.LEAD_IN;
23658
- const timeAt = (s) => headBand + C2.LEAD_IN + s * C2.TIME_STEP;
23659
- const crossAt = (l) => C2.PAD + C2.TAG_BAND + C2.LANE_GAP / 2 + l * C2.LANE_GAP;
24965
+ const headBand = ast.showBranches ? C3.PILL_GUTTER : C3.LEAD_IN;
24966
+ const timeAt = (s) => headBand + C3.LEAD_IN + s * C3.TIME_STEP;
24967
+ const crossAt = (l) => C3.PAD + C3.TAG_BAND + C3.LANE_GAP / 2 + l * C3.LANE_GAP;
23660
24968
  const timeSpan = commitCount > 0 ? timeAt(commitCount - 1) : timeAt(0);
23661
24969
  const crossSpan = crossAt(Math.max(0, laneCount - 1));
23662
24970
  const isVertical = ast.orientation === "TB" || ast.orientation === "BT";
23663
- const timeMax = timeSpan + C2.TIME_STEP / 2 + (ast.showCommitLabel ? C2.LABEL_BAND : C2.PAD);
23664
- const crossMax = crossSpan + C2.LANE_GAP / 2 + C2.PAD;
24971
+ const timeMax = timeSpan + C3.TIME_STEP / 2 + (ast.showCommitLabel ? C3.LABEL_BAND : C3.PAD);
24972
+ const crossMax = crossSpan + C3.LANE_GAP / 2 + C3.PAD;
23665
24973
  const width = isVertical ? crossMax : timeMax;
23666
24974
  const height = isVertical ? timeMax : crossMax;
23667
24975
  const place = (t, c) => {
@@ -23692,12 +25000,12 @@ function layoutGitGraph(ast) {
23692
25000
  }
23693
25001
  const firstOwn = own[0];
23694
25002
  const isTrunk = !firstOwn || firstOwn.parents.length === 0;
23695
- const startT = isTrunk ? timeAt(startSeq) - C2.TIME_STEP / 2 : timeAt(startSeq);
25003
+ const startT = isTrunk ? timeAt(startSeq) - C3.TIME_STEP / 2 : timeAt(startSeq);
23696
25004
  const endT = timeAt(endSeq);
23697
25005
  const c = crossAt(info.lane);
23698
25006
  const head = place(startT, c);
23699
25007
  const tail = place(endT, c);
23700
- const pillT = headBand - C2.LEAD_IN / 2;
25008
+ const pillT = headBand - C3.LEAD_IN / 2;
23701
25009
  const pillPos = place(pillT, c);
23702
25010
  return {
23703
25011
  info,
@@ -23821,7 +25129,7 @@ function renderGitGraphLayout(layout, config) {
23821
25129
  const styleBlock = buildStyle2(pal, ast.showBranches);
23822
25130
  const children = [
23823
25131
  title(a11y),
23824
- desc(summarise8(layout)),
25132
+ desc(summarise9(layout)),
23825
25133
  styleBlock,
23826
25134
  rect({ x: 0, y: 0, width, height, class: "sx-gg-bg" })
23827
25135
  ];
@@ -24071,7 +25379,7 @@ ${laneRules}
24071
25379
  function num2(n) {
24072
25380
  return Number.isInteger(n) ? String(n) : n.toFixed(2);
24073
25381
  }
24074
- function summarise8(layout) {
25382
+ function summarise9(layout) {
24075
25383
  const c = layout.replay.commits.length;
24076
25384
  const b = layout.replay.branches.length;
24077
25385
  const merges = layout.replay.commits.filter((n) => n.isMerge).length;
@@ -24363,7 +25671,7 @@ function parseEpc(text2) {
24363
25671
  let i = 0;
24364
25672
  let headerSeen = false;
24365
25673
  while (i < rawLines.length) {
24366
- const t = stripComment10(rawLines[i] ?? "").trim();
25674
+ const t = stripComment11(rawLines[i] ?? "").trim();
24367
25675
  if (t === "") {
24368
25676
  i++;
24369
25677
  continue;
@@ -24371,7 +25679,7 @@ function parseEpc(text2) {
24371
25679
  const h = /^epc\b(.*)$/i.exec(t);
24372
25680
  if (h) {
24373
25681
  const after = h[1].trim();
24374
- const q = matchQuoted6(after);
25682
+ const q = matchQuoted7(after);
24375
25683
  if (q) ast.title = q.value;
24376
25684
  headerSeen = true;
24377
25685
  i++;
@@ -24382,11 +25690,11 @@ function parseEpc(text2) {
24382
25690
  }
24383
25691
  if (!headerSeen) return finish(ast);
24384
25692
  for (; i < rawLines.length; i++) {
24385
- const t = stripComment10(rawLines[i] ?? "").trim();
25693
+ const t = stripComment11(rawLines[i] ?? "").trim();
24386
25694
  if (t === "") continue;
24387
25695
  const lineNo = i + 1;
24388
25696
  if (/^layout\s*:/i.test(t)) {
24389
- const v = afterColon6(t).toLowerCase();
25697
+ const v = afterColon7(t).toLowerCase();
24390
25698
  if (v === "tb" || v === "lr") ast.direction = v;
24391
25699
  else ast.warnings.push(`Line ${lineNo}: unknown layout "${v}" \u2014 using "tb".`);
24392
25700
  continue;
@@ -24400,7 +25708,7 @@ function parseEpc(text2) {
24400
25708
  parseDeclLine(ast, kw[1].toLowerCase(), t.slice(kw[0].length).trim(), lineNo);
24401
25709
  continue;
24402
25710
  }
24403
- ast.warnings.push(`Line ${lineNo}: unrecognised line: "${truncate9(t, 80)}"`);
25711
+ ast.warnings.push(`Line ${lineNo}: unrecognised line: "${truncate10(t, 80)}"`);
24404
25712
  }
24405
25713
  return finish(ast);
24406
25714
  }
@@ -24434,13 +25742,13 @@ function parseEdgeLine(ast, line2, lineNo) {
24434
25742
  const colon = topLevelColon(body);
24435
25743
  if (colon >= 0) {
24436
25744
  const labelPart = body.slice(colon + 1).trim();
24437
- const q = matchQuoted6(labelPart);
25745
+ const q = matchQuoted7(labelPart);
24438
25746
  edgeLabel2 = q ? q.value : labelPart;
24439
25747
  body = body.slice(0, colon).trim();
24440
25748
  }
24441
25749
  const parts = splitArrow(body).map((p) => p.trim()).filter((p) => p.length > 0);
24442
25750
  if (parts.length < 2) {
24443
- throw new EpcParseError(`an edge needs at least two nodes around '->', got "${truncate9(line2, 60)}"`, lineNo);
25751
+ throw new EpcParseError(`an edge needs at least two nodes around '->', got "${truncate10(line2, 60)}"`, lineNo);
24444
25752
  }
24445
25753
  for (const p of parts) {
24446
25754
  if (!isId2(p)) throw new EpcParseError(`invalid node reference "${p}" in edge`, lineNo);
@@ -24477,11 +25785,11 @@ function ensureRef(ast, id, _lineNo) {
24477
25785
  }
24478
25786
  function parseIdAndLabel3(s, lineNo) {
24479
25787
  const m = /^([A-Za-z_]\w*)/.exec(s.trim());
24480
- if (!m) throw new EpcParseError(`expected a node id, got "${truncate9(s, 40)}"`, lineNo);
25788
+ if (!m) throw new EpcParseError(`expected a node id, got "${truncate10(s, 40)}"`, lineNo);
24481
25789
  const id = m[1];
24482
25790
  const rest = s.trim().slice(id.length).trim();
24483
25791
  if (rest === "") return { id };
24484
- const q = matchQuoted6(rest);
25792
+ const q = matchQuoted7(rest);
24485
25793
  if (q) return { id, label: q.value };
24486
25794
  return { id, label: rest };
24487
25795
  }
@@ -24504,7 +25812,7 @@ function splitArrow(s) {
24504
25812
  }
24505
25813
  if (ch === '"' || ch === "\u300C" || ch === "\u201C") {
24506
25814
  inQ = true;
24507
- qc = closingQuote6(ch);
25815
+ qc = closingQuote7(ch);
24508
25816
  buf += ch;
24509
25817
  continue;
24510
25818
  }
@@ -24529,30 +25837,30 @@ function topLevelColon(s) {
24529
25837
  }
24530
25838
  if (ch === '"' || ch === "\u300C" || ch === "\u201C") {
24531
25839
  inQ = true;
24532
- qc = closingQuote6(ch);
25840
+ qc = closingQuote7(ch);
24533
25841
  continue;
24534
25842
  }
24535
25843
  if (ch === ":") return i;
24536
25844
  }
24537
25845
  return -1;
24538
25846
  }
24539
- function matchQuoted6(s) {
25847
+ function matchQuoted7(s) {
24540
25848
  if (!s) return void 0;
24541
25849
  const open = s[0];
24542
25850
  if (open !== '"' && open !== "\u300C" && open !== "\u201C") return void 0;
24543
- const close = closingQuote6(open);
25851
+ const close = closingQuote7(open);
24544
25852
  const end = s.indexOf(close, 1);
24545
25853
  if (end < 0) return void 0;
24546
25854
  return { value: s.slice(1, end), length: end + 1 };
24547
25855
  }
24548
- function closingQuote6(open) {
25856
+ function closingQuote7(open) {
24549
25857
  return open === "\u300C" ? "\u300D" : open === "\u201C" ? "\u201D" : '"';
24550
25858
  }
24551
- function afterColon6(s) {
25859
+ function afterColon7(s) {
24552
25860
  const i = s.indexOf(":");
24553
25861
  return i < 0 ? "" : s.slice(i + 1).trim();
24554
25862
  }
24555
- function stripComment10(line2) {
25863
+ function stripComment11(line2) {
24556
25864
  let inQ = false, qc = "";
24557
25865
  for (let i = 0; i < line2.length; i++) {
24558
25866
  const ch = line2[i];
@@ -24562,7 +25870,7 @@ function stripComment10(line2) {
24562
25870
  }
24563
25871
  if (ch === '"' || ch === "\u300C" || ch === "\u201C") {
24564
25872
  inQ = true;
24565
- qc = closingQuote6(ch);
25873
+ qc = closingQuote7(ch);
24566
25874
  continue;
24567
25875
  }
24568
25876
  if (ch === "#") return line2.slice(0, i);
@@ -24570,7 +25878,7 @@ function stripComment10(line2) {
24570
25878
  }
24571
25879
  return line2;
24572
25880
  }
24573
- function truncate9(s, n) {
25881
+ function truncate10(s, n) {
24574
25882
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
24575
25883
  }
24576
25884
 
@@ -24912,7 +26220,7 @@ function renderEpcLayout(layout, config) {
24912
26220
  );
24913
26221
  const children = [
24914
26222
  title(a11y),
24915
- desc(summarise9(layout)),
26223
+ desc(summarise10(layout)),
24916
26224
  styleBlock,
24917
26225
  defs([
24918
26226
  el("marker", {
@@ -25056,7 +26364,7 @@ function renderEdge6(e) {
25056
26364
  parts
25057
26365
  );
25058
26366
  }
25059
- function summarise9(layout) {
26367
+ function summarise10(layout) {
25060
26368
  const { ast, analysis } = layout;
25061
26369
  const counts = { event: 0, function: 0, connector: 0 };
25062
26370
  for (const n of ast.nodes) counts[n.kind]++;
@@ -25151,12 +26459,12 @@ function parseIdef0(text2) {
25151
26459
  let i = 0;
25152
26460
  let headerSeen = false;
25153
26461
  for (; i < rawLines.length; i++) {
25154
- const t = stripComment11(rawLines[i] ?? "").trim();
26462
+ const t = stripComment12(rawLines[i] ?? "").trim();
25155
26463
  if (t === "") continue;
25156
26464
  const h = /^idef0\b(.*)$/i.exec(t);
25157
26465
  if (h) {
25158
26466
  const after = h[1].trim();
25159
- const q = matchQuoted7(after);
26467
+ const q = matchQuoted8(after);
25160
26468
  if (q) ast.title = q.value;
25161
26469
  headerSeen = true;
25162
26470
  i++;
@@ -25167,7 +26475,7 @@ function parseIdef0(text2) {
25167
26475
  throw new Idef0ParseError(`an idef0 diagram must start with the 'idef0' keyword`);
25168
26476
  }
25169
26477
  for (; i < rawLines.length; i++) {
25170
- const t = stripComment11(rawLines[i] ?? "").trim();
26478
+ const t = stripComment12(rawLines[i] ?? "").trim();
25171
26479
  if (t === "") continue;
25172
26480
  const lineNo = i + 1;
25173
26481
  const nodeM = /^node\s+(.+)$/i.exec(t);
@@ -25178,7 +26486,7 @@ function parseIdef0(text2) {
25178
26486
  const metaM = /^(purpose|viewpoint)\b\s*(.*)$/i.exec(t);
25179
26487
  if (metaM) {
25180
26488
  const key = metaM[1].toLowerCase();
25181
- const q = matchQuoted7(metaM[2].trim());
26489
+ const q = matchQuoted8(metaM[2].trim());
25182
26490
  ast[key] = q ? q.value : metaM[2].trim();
25183
26491
  continue;
25184
26492
  }
@@ -25196,17 +26504,17 @@ function parseIdef0(text2) {
25196
26504
  parseFlowArrow(ast, t, lineNo);
25197
26505
  continue;
25198
26506
  }
25199
- ast.warnings.push(`Line ${lineNo}: unrecognised line: "${truncate10(t, 80)}"`);
26507
+ ast.warnings.push(`Line ${lineNo}: unrecognised line: "${truncate11(t, 80)}"`);
25200
26508
  }
25201
26509
  return ast;
25202
26510
  }
25203
26511
  function parseFunction2(ast, rest, lineNo) {
25204
26512
  const idM = /^([A-Za-z_]\w*)/.exec(rest);
25205
- if (!idM) throw new Idef0ParseError(`function needs an id, got "${truncate10(rest, 40)}"`, lineNo);
26513
+ if (!idM) throw new Idef0ParseError(`function needs an id, got "${truncate11(rest, 40)}"`, lineNo);
25206
26514
  const id = idM[1];
25207
26515
  let tail = rest.slice(id.length).trim();
25208
26516
  let name = id;
25209
- const q = matchQuoted7(tail);
26517
+ const q = matchQuoted8(tail);
25210
26518
  if (q) {
25211
26519
  name = q.value;
25212
26520
  tail = tail.slice(q.length).trim();
@@ -25228,11 +26536,11 @@ function parseFunction2(ast, rest, lineNo) {
25228
26536
  }
25229
26537
  function parseRoleArrow(ast, role, rest, lineNo) {
25230
26538
  const idM = /^([A-Za-z_]\w*)/.exec(rest);
25231
- if (!idM) throw new Idef0ParseError(`${role} needs a box id, got "${truncate10(rest, 40)}"`, lineNo);
26539
+ if (!idM) throw new Idef0ParseError(`${role} needs a box id, got "${truncate11(rest, 40)}"`, lineNo);
25232
26540
  const boxId = idM[1];
25233
26541
  let tail = rest.slice(boxId.length).trim();
25234
26542
  let label = "";
25235
- const q = matchQuoted7(tail);
26543
+ const q = matchQuoted8(tail);
25236
26544
  if (q) {
25237
26545
  label = q.value;
25238
26546
  tail = tail.slice(q.length).trim();
@@ -25258,10 +26566,10 @@ function parseFlowArrow(ast, t, lineNo) {
25258
26566
  const lhs = t.slice(0, arrowIdx).trim();
25259
26567
  let rhs = t.slice(arrowIdx + 2).trim();
25260
26568
  const srcM = /^([A-Za-z_]\w*)$/.exec(lhs);
25261
- if (!srcM) throw new Idef0ParseError(`flow arrow source must be a box id, got "${truncate10(lhs, 40)}"`, lineNo);
26569
+ if (!srcM) throw new Idef0ParseError(`flow arrow source must be a box id, got "${truncate11(lhs, 40)}"`, lineNo);
25262
26570
  const srcId = srcM[1];
25263
26571
  const tgtM = /^([A-Za-z_]\w*)(?:\.([a-z]+))?/i.exec(rhs);
25264
- if (!tgtM) throw new Idef0ParseError(`flow arrow target must be a box id, got "${truncate10(rhs, 40)}"`, lineNo);
26572
+ if (!tgtM) throw new Idef0ParseError(`flow arrow target must be a box id, got "${truncate11(rhs, 40)}"`, lineNo);
25265
26573
  const tgtId = tgtM[1];
25266
26574
  const roleWord = tgtM[2]?.toLowerCase();
25267
26575
  let role = "input";
@@ -25282,7 +26590,7 @@ function parseFlowArrow(ast, t, lineNo) {
25282
26590
  }
25283
26591
  rhs = rhs.slice(tgtM[0].length).trim();
25284
26592
  let label = "";
25285
- const q = matchQuoted7(rhs);
26593
+ const q = matchQuoted8(rhs);
25286
26594
  if (q) {
25287
26595
  label = q.value;
25288
26596
  rhs = rhs.slice(q.length).trim();
@@ -25305,19 +26613,19 @@ function parseFlowArrow(ast, t, lineNo) {
25305
26613
  function consumeTunnel(s) {
25306
26614
  return /\(\s*tunnel\s*\)/i.test(s);
25307
26615
  }
25308
- function matchQuoted7(s) {
26616
+ function matchQuoted8(s) {
25309
26617
  if (!s) return void 0;
25310
26618
  const open = s[0];
25311
26619
  if (open !== '"' && open !== "\u300C" && open !== "\u201C") return void 0;
25312
- const close = closingQuote7(open);
26620
+ const close = closingQuote8(open);
25313
26621
  const end = s.indexOf(close, 1);
25314
26622
  if (end < 0) return void 0;
25315
26623
  return { value: s.slice(1, end), length: end + 1 };
25316
26624
  }
25317
- function closingQuote7(open) {
26625
+ function closingQuote8(open) {
25318
26626
  return open === "\u300C" ? "\u300D" : open === "\u201C" ? "\u201D" : '"';
25319
26627
  }
25320
- function stripComment11(line2) {
26628
+ function stripComment12(line2) {
25321
26629
  let inQ = false;
25322
26630
  let qc = "";
25323
26631
  for (let i = 0; i < line2.length; i++) {
@@ -25328,14 +26636,14 @@ function stripComment11(line2) {
25328
26636
  }
25329
26637
  if (ch === '"' || ch === "\u300C" || ch === "\u201C") {
25330
26638
  inQ = true;
25331
- qc = closingQuote7(ch);
26639
+ qc = closingQuote8(ch);
25332
26640
  continue;
25333
26641
  }
25334
26642
  if (ch === "#") return line2.slice(0, i);
25335
26643
  }
25336
26644
  return line2;
25337
26645
  }
25338
- function truncate10(s, n) {
26646
+ function truncate11(s, n) {
25339
26647
  return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
25340
26648
  }
25341
26649
 
@@ -25493,22 +26801,22 @@ var IDEF0_CONST = {
25493
26801
  };
25494
26802
  function layoutIdef0(astIn) {
25495
26803
  const ast = analyseIdef0(astIn);
25496
- const C2 = IDEF0_CONST;
25497
- const ox = C2.MARGIN;
25498
- const oy = C2.MARGIN + C2.TITLE_H;
26804
+ const C3 = IDEF0_CONST;
26805
+ const ox = C3.MARGIN;
26806
+ const oy = C3.MARGIN + C3.TITLE_H;
25499
26807
  const boxes = ast.boxes.map((box2, idx) => ({
25500
26808
  box: box2,
25501
- x: ox + idx * C2.STEP_X,
25502
- y: oy + idx * C2.STEP_Y,
25503
- width: C2.BOX_W,
25504
- height: C2.BOX_H
26809
+ x: ox + idx * C3.STEP_X,
26810
+ y: oy + idx * C3.STEP_Y,
26811
+ width: C3.BOX_W,
26812
+ height: C3.BOX_H
25505
26813
  }));
25506
26814
  const boxIndex = new Map(boxes.map((b, i) => [b.box.id, i]));
25507
26815
  const lastBox = boxes[boxes.length - 1];
25508
- const contentRight = lastBox.x + C2.BOX_W;
25509
- const contentBottom = lastBox.y + C2.BOX_H;
25510
- const width = contentRight + C2.MARGIN;
25511
- const height = contentBottom + C2.MARGIN + C2.TITLEBLOCK_H;
26816
+ const contentRight = lastBox.x + C3.BOX_W;
26817
+ const contentBottom = lastBox.y + C3.BOX_H;
26818
+ const width = contentRight + C3.MARGIN;
26819
+ const height = contentBottom + C3.MARGIN + C3.TITLEBLOCK_H;
25512
26820
  const arrows = ast.arrows.map(
25513
26821
  (arrow2) => routeArrow(arrow2, boxes, boxIndex)
25514
26822
  );
@@ -25527,7 +26835,7 @@ function sidePoint(b, side) {
25527
26835
  }
25528
26836
  }
25529
26837
  function routeArrow(arrow2, boxes, boxIndex) {
25530
- const C2 = IDEF0_CONST;
26838
+ const C3 = IDEF0_CONST;
25531
26839
  const targetSide = ICOM_SIDE[arrow2.role];
25532
26840
  const fromBoundary = arrow2.from.kind === "boundary";
25533
26841
  const toBoundary = arrow2.to.kind === "boundary";
@@ -25560,10 +26868,10 @@ function routeArrow(arrow2, boxes, boxIndex) {
25560
26868
  margin: false
25561
26869
  };
25562
26870
  }
25563
- const marginY = C2.MARGIN / 2 + C2.TITLE_H;
26871
+ const marginY = C3.MARGIN / 2 + C3.TITLE_H;
25564
26872
  let d;
25565
26873
  if (targetSide === "left") {
25566
- const approachX = end.x - C2.FEEDBACK_LEADIN;
26874
+ const approachX = end.x - C3.FEEDBACK_LEADIN;
25567
26875
  d = `M ${start.x} ${start.y} L ${start.x + 20} ${start.y} L ${start.x + 20} ${marginY} L ${approachX} ${marginY} L ${approachX} ${end.y} L ${end.x} ${end.y}`;
25568
26876
  } else {
25569
26877
  d = `M ${start.x} ${start.y} L ${start.x + 20} ${start.y} L ${start.x + 20} ${marginY} L ${end.x} ${marginY} L ${end.x} ${end.y}`;
@@ -25577,7 +26885,7 @@ function routeArrow(arrow2, boxes, boxIndex) {
25577
26885
  };
25578
26886
  }
25579
26887
  function routeBoundary(arrow2, boxes, boxIndex, targetSide, fromBoundary) {
25580
- const C2 = IDEF0_CONST;
26888
+ const C3 = IDEF0_CONST;
25581
26889
  const boxEnd = fromBoundary ? arrow2.to : arrow2.from;
25582
26890
  const b = boxes[boxIndex.get(boxEnd.boxId)];
25583
26891
  const side = fromBoundary ? targetSide : "right";
@@ -25585,16 +26893,16 @@ function routeBoundary(arrow2, boxes, boxIndex, targetSide, fromBoundary) {
25585
26893
  let stub;
25586
26894
  switch (side) {
25587
26895
  case "left":
25588
- stub = { x: edge.x - C2.STUB, y: edge.y };
26896
+ stub = { x: edge.x - C3.STUB, y: edge.y };
25589
26897
  break;
25590
26898
  case "top":
25591
- stub = { x: edge.x, y: edge.y - C2.STUB };
26899
+ stub = { x: edge.x, y: edge.y - C3.STUB };
25592
26900
  break;
25593
26901
  case "right":
25594
- stub = { x: edge.x + C2.STUB, y: edge.y };
26902
+ stub = { x: edge.x + C3.STUB, y: edge.y };
25595
26903
  break;
25596
26904
  case "bottom":
25597
- stub = { x: edge.x, y: edge.y + C2.STUB };
26905
+ stub = { x: edge.x, y: edge.y + C3.STUB };
25598
26906
  break;
25599
26907
  }
25600
26908
  let path2;
@@ -25669,7 +26977,7 @@ function renderIdef0Layout(layout, config) {
25669
26977
  );
25670
26978
  const children = [
25671
26979
  title(a11y),
25672
- desc(summarise10(layout)),
26980
+ desc(summarise11(layout)),
25673
26981
  styleBlock,
25674
26982
  rect({ x: 0, y: 0, width, height, class: "sx-idef0-bg" })
25675
26983
  ];
@@ -25827,7 +27135,7 @@ function renderTitleBlock(width, height, node, title2) {
25827
27135
  text({ x: c2 + 6, y: y + 13, class: "sx-idef0-tb-key" }, "NUMBER")
25828
27136
  ]);
25829
27137
  }
25830
- function summarise10(layout) {
27138
+ function summarise11(layout) {
25831
27139
  const { ast } = layout;
25832
27140
  const counts = {};
25833
27141
  for (const a of ast.arrows) counts[a.role] = (counts[a.role] ?? 0) + 1;
@@ -25897,7 +27205,7 @@ function normalizeQuotes3(text2) {
25897
27205
  for (const ch of text2) out += QUOTE_FOLD.get(ch) ?? ch;
25898
27206
  return out;
25899
27207
  }
25900
- function stripComment12(line2) {
27208
+ function stripComment13(line2) {
25901
27209
  let inQuote = false;
25902
27210
  for (let i = 0; i < line2.length; i++) {
25903
27211
  const ch = line2[i];
@@ -25941,7 +27249,7 @@ function parseThreatModel(text2) {
25941
27249
  let i = 0;
25942
27250
  let headerSeen = false;
25943
27251
  for (; i < rawLines.length; i++) {
25944
- const t = stripComment12(rawLines[i] ?? "").trim();
27252
+ const t = stripComment13(rawLines[i] ?? "").trim();
25945
27253
  if (t === "") continue;
25946
27254
  const h = /^(threatmodel|stride)\b(.*)$/i.exec(t);
25947
27255
  if (h) {
@@ -25960,7 +27268,7 @@ function parseThreatModel(text2) {
25960
27268
  }
25961
27269
  for (; i < rawLines.length; i++) {
25962
27270
  const lineNo = i + 1;
25963
- const t = stripComment12(rawLines[i] ?? "").trim();
27271
+ const t = stripComment13(rawLines[i] ?? "").trim();
25964
27272
  if (t === "") continue;
25965
27273
  const titleM = /^title\s*:\s*(.+)$/i.exec(t);
25966
27274
  if (titleM) {
@@ -26054,7 +27362,7 @@ function parseThreatModel(text2) {
26054
27362
  );
26055
27363
  }
26056
27364
  resolveEndpoints(ast, byId);
26057
- validate6(ast, byId);
27365
+ validate7(ast, byId);
26058
27366
  return ast;
26059
27367
  }
26060
27368
  function resolveEndpoints(ast, byId) {
@@ -26077,7 +27385,7 @@ function resolveEndpoints(ast, byId) {
26077
27385
  b.members = b.members.map(canon);
26078
27386
  }
26079
27387
  }
26080
- function validate6(ast, byId) {
27388
+ function validate7(ast, byId) {
26081
27389
  for (const f of ast.flows) {
26082
27390
  const s = byId.get(f.source)?.node;
26083
27391
  const tg = byId.get(f.target)?.node;
@@ -26488,7 +27796,7 @@ function renderThreatModelLayout(layout, config) {
26488
27796
  ]);
26489
27797
  const children = [
26490
27798
  title(a11y),
26491
- desc(summarise11(layout)),
27799
+ desc(summarise12(layout)),
26492
27800
  styleBlock,
26493
27801
  markerDefs,
26494
27802
  rect({ x: 0, y: 0, width, height, class: "sx-tm-bg" })
@@ -26604,8 +27912,8 @@ ${n.label}` : n.label;
26604
27912
  }
26605
27913
  function strideBadge(n, fontFamily) {
26606
27914
  const letters = n.stride.categories.join("");
26607
- const charW = 7;
26608
- const bw = letters.length * charW + 10;
27915
+ const charW2 = 7;
27916
+ const bw = letters.length * charW2 + 10;
26609
27917
  const bh = 15;
26610
27918
  const bx = n.cx - bw / 2;
26611
27919
  const by = n.y - bh - 4;
@@ -26634,7 +27942,7 @@ function strideBadge(n, fontFamily) {
26634
27942
  }
26635
27943
  function renderFlow(f, fontFamily) {
26636
27944
  const pts = f.points;
26637
- const d = "M " + pts.map((p) => `${round8(p.x)} ${round8(p.y)}`).join(" L ");
27945
+ const d = "M " + pts.map((p) => `${round10(p.x)} ${round10(p.y)}`).join(" L ");
26638
27946
  const crossing = f.crossesBoundary ? "true" : void 0;
26639
27947
  const marker = f.crossesBoundary ? "url(#sx-tm-mk-x)" : "url(#sx-tm-mk)";
26640
27948
  const labelHaloW = f.label.length * 5.4 + 8;
@@ -26702,10 +28010,10 @@ function arrowMarker2(id, cls, crossing) {
26702
28010
  ]
26703
28011
  );
26704
28012
  }
26705
- function round8(n) {
28013
+ function round10(n) {
26706
28014
  return Math.round(n * 100) / 100;
26707
28015
  }
26708
- function summarise11(layout) {
28016
+ function summarise12(layout) {
26709
28017
  const a = layout.analysis;
26710
28018
  const counts = {
26711
28019
  external: layout.nodes.filter((n) => n.kind === "external").length,
@@ -26917,7 +28225,7 @@ function parseWeldSpec(raw) {
26917
28225
  function emptyJoint() {
26918
28226
  return { around: false, field: false };
26919
28227
  }
26920
- function stripComment13(line2) {
28228
+ function stripComment14(line2) {
26921
28229
  const hash = line2.indexOf("#");
26922
28230
  if (hash >= 0 && (line2.slice(0, hash).match(/["'“‘]/g)?.length ?? 0) % 2 === 0) {
26923
28231
  return line2.slice(0, hash);
@@ -26946,7 +28254,7 @@ function parseJointBody(body, joint) {
26946
28254
  }
26947
28255
  function parseWelding(text2) {
26948
28256
  const ast = { type: "welding", standard: "aws", joints: [], warnings: [] };
26949
- const src = text2.split(/\r?\n/).map(stripComment13).join("\n");
28257
+ const src = text2.split(/\r?\n/).map(stripComment14).join("\n");
26950
28258
  const headEnd = src.search(/\bjoint\b/i);
26951
28259
  const headerScope = headEnd >= 0 ? src.slice(0, headEnd) : src;
26952
28260
  const header = headerScope.match(/welding\b([^\n]*)/i);
@@ -27014,9 +28322,9 @@ function layoutWelding(ast) {
27014
28322
  var W = 18;
27015
28323
  var H = 15;
27016
28324
  function pl(points, cls) {
27017
- return polygon({ points: points.map((p) => `${round9(p[0])},${round9(p[1])}`).join(" "), class: cls, fill: "none" });
28325
+ return polygon({ points: points.map((p) => `${round11(p[0])},${round11(p[1])}`).join(" "), class: cls, fill: "none" });
27018
28326
  }
27019
- function round9(n) {
28327
+ function round11(n) {
27020
28328
  return Math.round(n * 100) / 100;
27021
28329
  }
27022
28330
  function weldGlyph(type, cx, y, dir, cls) {
@@ -27032,7 +28340,7 @@ function weldGlyph(type, cx, y, dir, cls) {
27032
28340
  line({ x1: cx + 3, y1: y, x2: cx + 3, y2: yb, class: cls })
27033
28341
  ];
27034
28342
  case "vgroove":
27035
- return [path({ d: `M ${round9(x0)} ${round9(yb)} L ${round9(cx)} ${round9(y)} L ${round9(x1)} ${round9(yb)}`, class: cls, fill: "none" })];
28343
+ return [path({ d: `M ${round11(x0)} ${round11(yb)} L ${round11(cx)} ${round11(y)} L ${round11(x1)} ${round11(yb)}`, class: cls, fill: "none" })];
27036
28344
  case "bevel":
27037
28345
  return [
27038
28346
  line({ x1: cx - 4, y1: y, x2: cx - 4, y2: yb, class: cls }),
@@ -27041,7 +28349,7 @@ function weldGlyph(type, cx, y, dir, cls) {
27041
28349
  case "ugroove":
27042
28350
  return [
27043
28351
  path({
27044
- d: `M ${round9(x0)} ${round9(y)} L ${round9(x0)} ${round9(y + dir * H * 0.45)} Q ${round9(x0)} ${round9(yb)} ${round9(cx)} ${round9(yb)} Q ${round9(x1)} ${round9(yb)} ${round9(x1)} ${round9(y + dir * H * 0.45)} L ${round9(x1)} ${round9(y)}`,
28352
+ d: `M ${round11(x0)} ${round11(y)} L ${round11(x0)} ${round11(y + dir * H * 0.45)} Q ${round11(x0)} ${round11(yb)} ${round11(cx)} ${round11(yb)} Q ${round11(x1)} ${round11(yb)} ${round11(x1)} ${round11(y + dir * H * 0.45)} L ${round11(x1)} ${round11(y)}`,
27045
28353
  class: cls,
27046
28354
  fill: "none"
27047
28355
  })
@@ -27049,20 +28357,20 @@ function weldGlyph(type, cx, y, dir, cls) {
27049
28357
  case "jgroove":
27050
28358
  return [
27051
28359
  path({
27052
- d: `M ${round9(cx - 4)} ${round9(y)} L ${round9(cx - 4)} ${round9(y + dir * H * 0.45)} Q ${round9(cx - 4)} ${round9(yb)} ${round9(x1)} ${round9(yb)}`,
28360
+ d: `M ${round11(cx - 4)} ${round11(y)} L ${round11(cx - 4)} ${round11(y + dir * H * 0.45)} Q ${round11(cx - 4)} ${round11(yb)} ${round11(x1)} ${round11(yb)}`,
27053
28361
  class: cls,
27054
28362
  fill: "none"
27055
28363
  })
27056
28364
  ];
27057
28365
  case "flarev":
27058
28366
  return [
27059
- path({ d: `M ${round9(x0)} ${round9(yb)} Q ${round9(cx - 2)} ${round9(yb)} ${round9(cx)} ${round9(y)}`, class: cls, fill: "none" }),
27060
- path({ d: `M ${round9(x1)} ${round9(yb)} Q ${round9(cx + 2)} ${round9(yb)} ${round9(cx)} ${round9(y)}`, class: cls, fill: "none" })
28367
+ path({ d: `M ${round11(x0)} ${round11(yb)} Q ${round11(cx - 2)} ${round11(yb)} ${round11(cx)} ${round11(y)}`, class: cls, fill: "none" }),
28368
+ path({ d: `M ${round11(x1)} ${round11(yb)} Q ${round11(cx + 2)} ${round11(yb)} ${round11(cx)} ${round11(y)}`, class: cls, fill: "none" })
27061
28369
  ];
27062
28370
  case "flarebevel":
27063
28371
  return [
27064
28372
  line({ x1: cx - 4, y1: y, x2: cx - 4, y2: yb, class: cls }),
27065
- path({ d: `M ${round9(cx - 4)} ${round9(y)} Q ${round9(x1)} ${round9(y)} ${round9(x1)} ${round9(yb)}`, class: cls, fill: "none" })
28373
+ path({ d: `M ${round11(cx - 4)} ${round11(y)} Q ${round11(x1)} ${round11(y)} ${round11(x1)} ${round11(yb)}`, class: cls, fill: "none" })
27066
28374
  ];
27067
28375
  case "plug":
27068
28376
  case "slot": {
@@ -27080,12 +28388,12 @@ function weldGlyph(type, cx, y, dir, cls) {
27080
28388
  case "backing": {
27081
28389
  const rr = W * 0.45;
27082
28390
  const sweep = dir > 0 ? 1 : 0;
27083
- return [path({ d: `M ${round9(cx - rr)} ${round9(y)} A ${round9(rr)} ${round9(rr)} 0 0 ${sweep} ${round9(cx + rr)} ${round9(y)}`, class: cls, fill: "none" })];
28391
+ return [path({ d: `M ${round11(cx - rr)} ${round11(y)} A ${round11(rr)} ${round11(rr)} 0 0 ${sweep} ${round11(cx + rr)} ${round11(y)}`, class: cls, fill: "none" })];
27084
28392
  }
27085
28393
  case "surfacing": {
27086
28394
  const r7 = W / 4;
27087
28395
  const yy = y + dir * 3;
27088
- const bump = (off) => path({ d: `M ${round9(cx - W / 2)} ${round9(off)} a ${round9(r7)} ${round9(r7)} 0 0 ${dir > 0 ? 1 : 0} ${round9(W / 2)} 0 a ${round9(r7)} ${round9(r7)} 0 0 ${dir > 0 ? 1 : 0} ${round9(W / 2)} 0`, class: cls, fill: "none" });
28396
+ const bump = (off) => path({ d: `M ${round11(cx - W / 2)} ${round11(off)} a ${round11(r7)} ${round11(r7)} 0 0 ${dir > 0 ? 1 : 0} ${round11(W / 2)} 0 a ${round11(r7)} ${round11(r7)} 0 0 ${dir > 0 ? 1 : 0} ${round11(W / 2)} 0`, class: cls, fill: "none" });
27089
28397
  return [bump(y), bump(yy)];
27090
28398
  }
27091
28399
  case "edge":
@@ -27103,7 +28411,7 @@ function contourGlyph(contour, cx, y, dir, cls) {
27103
28411
  }
27104
28412
  const bulge = contour === "convex" ? dir : -dir;
27105
28413
  return path({
27106
- d: `M ${round9(cx - half)} ${round9(yy)} Q ${round9(cx)} ${round9(yy + bulge * 5)} ${round9(cx + half)} ${round9(yy)}`,
28414
+ d: `M ${round11(cx - half)} ${round11(yy)} Q ${round11(cx)} ${round11(yy + bulge * 5)} ${round11(cx + half)} ${round11(yy)}`,
27107
28415
  class: cls,
27108
28416
  fill: "none"
27109
28417
  });
@@ -30948,7 +32256,7 @@ var ErdParseError = class extends Error {
30948
32256
  }
30949
32257
  lineNumber;
30950
32258
  };
30951
- function stripComment14(s) {
32259
+ function stripComment15(s) {
30952
32260
  let out = "";
30953
32261
  let inQuote = false;
30954
32262
  for (let i = 0; i < s.length; i++) {
@@ -31002,7 +32310,7 @@ function parseCardToken(raw, side) {
31002
32310
  }
31003
32311
  function lex(text2) {
31004
32312
  return text2.split(/\r?\n/).map((raw, i) => ({
31005
- text: stripComment14(raw).trim(),
32313
+ text: stripComment15(raw).trim(),
31006
32314
  lineNumber: i + 1
31007
32315
  })).filter((l) => l.text.length > 0);
31008
32316
  }
@@ -31380,8 +32688,8 @@ var ERD_CONST = {
31380
32688
  EDGE_BEND_STAGGER: 10
31381
32689
  };
31382
32690
  function measureEntity(ent) {
31383
- const C2 = ERD_CONST;
31384
- const headerWidth = C2.ENTITY_PADDING_X * 2 + ent.name.length * C2.CHAR_W_HEADER;
32691
+ const C3 = ERD_CONST;
32692
+ const headerWidth = C3.ENTITY_PADDING_X * 2 + ent.name.length * C3.CHAR_W_HEADER;
31385
32693
  let widest = headerWidth;
31386
32694
  const rows = [];
31387
32695
  for (let i = 0; i < ent.attributes.length; i++) {
@@ -31389,14 +32697,14 @@ function measureEntity(ent) {
31389
32697
  const namePart = a.name;
31390
32698
  const typePart = a.type ?? "";
31391
32699
  const markerCount = (a.pk ? 1 : 0) + (a.fk ? 1 : 0) + (a.uk ? 1 : 0) + (a.notNull && !a.pk ? 1 : 0);
31392
- const markerWidth = markerCount * (C2.CHAR_W_MARKER * 2.4 + 4);
31393
- const w = C2.ENTITY_PADDING_X * 2 + namePart.length * C2.CHAR_W_ROW + (typePart ? C2.TYPE_GAP + typePart.length * C2.CHAR_W_ROW : 0) + markerWidth;
32700
+ const markerWidth = markerCount * (C3.CHAR_W_MARKER * 2.4 + 4);
32701
+ const w = C3.ENTITY_PADDING_X * 2 + namePart.length * C3.CHAR_W_ROW + (typePart ? C3.TYPE_GAP + typePart.length * C3.CHAR_W_ROW : 0) + markerWidth;
31394
32702
  if (w > widest) widest = w;
31395
- const yCenter = C2.HEADER_HEIGHT + i * C2.ROW_HEIGHT + C2.ROW_HEIGHT / 2;
32703
+ const yCenter = C3.HEADER_HEIGHT + i * C3.ROW_HEIGHT + C3.ROW_HEIGHT / 2;
31396
32704
  rows.push({ attribute: a, yCenter });
31397
32705
  }
31398
- const width = Math.max(widest, C2.ENTITY_MIN_WIDTH);
31399
- const height = C2.HEADER_HEIGHT + ent.attributes.length * C2.ROW_HEIGHT + C2.ROW_PAD_Y;
32706
+ const width = Math.max(widest, C3.ENTITY_MIN_WIDTH);
32707
+ const height = C3.HEADER_HEIGHT + ent.attributes.length * C3.ROW_HEIGHT + C3.ROW_PAD_Y;
31400
32708
  return { width, height, rows };
31401
32709
  }
31402
32710
  function buildColumnAssignment(ast) {
@@ -31493,15 +32801,15 @@ function reorderByBarycenter(layerToEnts, layers, refs) {
31493
32801
  sweep("down");
31494
32802
  }
31495
32803
  function assignYCoordinates(orderedLayers, measured, neighbors) {
31496
- const C2 = ERD_CONST;
32804
+ const C3 = ERD_CONST;
31497
32805
  const placed = /* @__PURE__ */ new Map();
31498
32806
  for (const ls of orderedLayers) {
31499
- let prevBottom = C2.PADDING - C2.ROW_GAP;
32807
+ let prevBottom = C3.PADDING - C3.ROW_GAP;
31500
32808
  for (let i = 0; i < ls.ids.length; i++) {
31501
32809
  const id = ls.ids[i];
31502
32810
  const m = measured.get(id);
31503
32811
  const ns = neighbors.get(id);
31504
- let target = C2.PADDING;
32812
+ let target = C3.PADDING;
31505
32813
  if (ns) {
31506
32814
  const placedNeighborCenters = [];
31507
32815
  for (const n of ns) {
@@ -31515,7 +32823,7 @@ function assignYCoordinates(orderedLayers, measured, neighbors) {
31515
32823
  target = med - m.height / 2;
31516
32824
  }
31517
32825
  }
31518
- const y = Math.max(target, prevBottom + C2.ROW_GAP);
32826
+ const y = Math.max(target, prevBottom + C3.ROW_GAP);
31519
32827
  placed.set(id, {
31520
32828
  id,
31521
32829
  y,
@@ -31528,7 +32836,7 @@ function assignYCoordinates(orderedLayers, measured, neighbors) {
31528
32836
  }
31529
32837
  for (let li = orderedLayers.length - 1; li >= 0; li--) {
31530
32838
  const ls = orderedLayers[li];
31531
- let prevBottom = C2.PADDING - C2.ROW_GAP;
32839
+ let prevBottom = C3.PADDING - C3.ROW_GAP;
31532
32840
  for (let i = 0; i < ls.ids.length; i++) {
31533
32841
  const id = ls.ids[i];
31534
32842
  const slot = placed.get(id);
@@ -31547,7 +32855,7 @@ function assignYCoordinates(orderedLayers, measured, neighbors) {
31547
32855
  target = med - slot.height / 2;
31548
32856
  }
31549
32857
  }
31550
- const lower = prevBottom + C2.ROW_GAP;
32858
+ const lower = prevBottom + C3.ROW_GAP;
31551
32859
  const newY = Math.max(lower, Math.min(slot.y, target));
31552
32860
  slot.y = newY;
31553
32861
  prevBottom = newY + slot.height;
@@ -31558,7 +32866,7 @@ function assignYCoordinates(orderedLayers, measured, neighbors) {
31558
32866
  return out;
31559
32867
  }
31560
32868
  function layoutErd(ast) {
31561
- const C2 = ERD_CONST;
32869
+ const C3 = ERD_CONST;
31562
32870
  const isLR = ast.direction === "LR";
31563
32871
  const measured = /* @__PURE__ */ new Map();
31564
32872
  for (const e of ast.entities) {
@@ -31606,30 +32914,30 @@ function layoutErd(ast) {
31606
32914
  const orderingCoord = assignYCoordinates(orderedLayers, measureForOrdering, neighbors);
31607
32915
  const placed = [];
31608
32916
  if (isLR) {
31609
- let cursorX = C2.PADDING;
32917
+ let cursorX = C3.PADDING;
31610
32918
  for (const ls of layerSizes) {
31611
32919
  for (const id of ls.ids) {
31612
32920
  const m = measured.get(id);
31613
32921
  const x = cursorX + (ls.maxWidth - m.width) / 2;
31614
- const y = orderingCoord.get(id) ?? C2.PADDING;
32922
+ const y = orderingCoord.get(id) ?? C3.PADDING;
31615
32923
  placed.push({
31616
32924
  entity: m.ent,
31617
32925
  x,
31618
32926
  y,
31619
32927
  width: m.width,
31620
32928
  height: m.height,
31621
- headerHeight: C2.HEADER_HEIGHT,
32929
+ headerHeight: C3.HEADER_HEIGHT,
31622
32930
  rows: m.rows
31623
32931
  });
31624
32932
  }
31625
- cursorX += ls.maxWidth + C2.COL_GAP;
32933
+ cursorX += ls.maxWidth + C3.COL_GAP;
31626
32934
  }
31627
32935
  } else {
31628
- let cursorY = C2.PADDING;
32936
+ let cursorY = C3.PADDING;
31629
32937
  for (const ls of layerSizes) {
31630
32938
  for (const id of ls.ids) {
31631
32939
  const m = measured.get(id);
31632
- const x = orderingCoord.get(id) ?? C2.PADDING;
32940
+ const x = orderingCoord.get(id) ?? C3.PADDING;
31633
32941
  const y = cursorY + (ls.maxHeight - m.height) / 2;
31634
32942
  placed.push({
31635
32943
  entity: m.ent,
@@ -31637,11 +32945,11 @@ function layoutErd(ast) {
31637
32945
  y,
31638
32946
  width: m.width,
31639
32947
  height: m.height,
31640
- headerHeight: C2.HEADER_HEIGHT,
32948
+ headerHeight: C3.HEADER_HEIGHT,
31641
32949
  rows: m.rows
31642
32950
  });
31643
32951
  }
31644
- cursorY += ls.maxHeight + C2.ROW_GAP;
32952
+ cursorY += ls.maxHeight + C3.ROW_GAP;
31645
32953
  }
31646
32954
  }
31647
32955
  let maxX = 0;
@@ -31650,8 +32958,8 @@ function layoutErd(ast) {
31650
32958
  if (e.x + e.width > maxX) maxX = e.x + e.width;
31651
32959
  if (e.y + e.height > maxY) maxY = e.y + e.height;
31652
32960
  }
31653
- const width = maxX + C2.PADDING;
31654
- const height = maxY + C2.PADDING;
32961
+ const width = maxX + C3.PADDING;
32962
+ const height = maxY + C3.PADDING;
31655
32963
  const placedById = new Map(placed.map((p) => [p.entity.id, p]));
31656
32964
  const edges = [];
31657
32965
  const bendBucketUses = /* @__PURE__ */ new Map();
@@ -31688,7 +32996,7 @@ function rowYByColumn(e, col) {
31688
32996
  return e.y + e.height / 2;
31689
32997
  }
31690
32998
  function routeOrthogonal(a, b, fromCol, toCol, bendBucketUses) {
31691
- const C2 = ERD_CONST;
32999
+ const C3 = ERD_CONST;
31692
33000
  const aCenterX = a.x + a.width / 2;
31693
33001
  const bCenterX = b.x + b.width / 2;
31694
33002
  const aCenterY = a.y + a.height / 2;
@@ -31712,14 +33020,14 @@ function routeOrthogonal(a, b, fromCol, toCol, bendBucketUses) {
31712
33020
  const useIdx = bendBucketUses.get(bucketKey) ?? 0;
31713
33021
  bendBucketUses.set(bucketKey, useIdx + 1);
31714
33022
  const sign = useIdx % 2 === 0 ? 1 : -1;
31715
- const stagger = Math.ceil(useIdx / 2) * C2.EDGE_BEND_STAGGER * sign;
33023
+ const stagger = Math.ceil(useIdx / 2) * C3.EDGE_BEND_STAGGER * sign;
31716
33024
  const midX = baseMidX + stagger;
31717
33025
  const path2 = `M ${aAnchor.x} ${aAnchor.y} L ${midX} ${aAnchor.y} L ${midX} ${bAnchor.y} L ${bAnchor.x} ${bAnchor.y}`;
31718
33026
  return {
31719
33027
  path: path2,
31720
33028
  fromAnchor: { x: aAnchor.x, y: aAnchor.y, side: aSide },
31721
33029
  toAnchor: { x: bAnchor.x, y: bAnchor.y, side: bSide },
31722
- labelAt: { x: midX, y: (aAnchor.y + bAnchor.y) / 2 - C2.LABEL_OFFSET }
33030
+ labelAt: { x: midX, y: (aAnchor.y + bAnchor.y) / 2 - C3.LABEL_OFFSET }
31723
33031
  };
31724
33032
  } else {
31725
33033
  const baseMidY = (aAnchor.y + bAnchor.y) / 2;
@@ -31727,14 +33035,14 @@ function routeOrthogonal(a, b, fromCol, toCol, bendBucketUses) {
31727
33035
  const useIdx = bendBucketUses.get(bucketKey) ?? 0;
31728
33036
  bendBucketUses.set(bucketKey, useIdx + 1);
31729
33037
  const sign = useIdx % 2 === 0 ? 1 : -1;
31730
- const stagger = Math.ceil(useIdx / 2) * C2.EDGE_BEND_STAGGER * sign;
33038
+ const stagger = Math.ceil(useIdx / 2) * C3.EDGE_BEND_STAGGER * sign;
31731
33039
  const midY = baseMidY + stagger;
31732
33040
  const path2 = `M ${aAnchor.x} ${aAnchor.y} L ${aAnchor.x} ${midY} L ${bAnchor.x} ${midY} L ${bAnchor.x} ${bAnchor.y}`;
31733
33041
  return {
31734
33042
  path: path2,
31735
33043
  fromAnchor: { x: aAnchor.x, y: aAnchor.y, side: aSide },
31736
33044
  toAnchor: { x: bAnchor.x, y: bAnchor.y, side: bSide },
31737
- labelAt: { x: (aAnchor.x + bAnchor.x) / 2, y: midY - C2.LABEL_OFFSET }
33045
+ labelAt: { x: (aAnchor.x + bAnchor.x) / 2, y: midY - C3.LABEL_OFFSET }
31738
33046
  };
31739
33047
  }
31740
33048
  }
@@ -31785,7 +33093,7 @@ function attrMarkers(a) {
31785
33093
  return out;
31786
33094
  }
31787
33095
  function renderEntity(e) {
31788
- const C2 = ERD_CONST;
33096
+ const C3 = ERD_CONST;
31789
33097
  const body = [];
31790
33098
  body.push(
31791
33099
  rect({
@@ -31821,9 +33129,9 @@ function renderEntity(e) {
31821
33129
  body.push(
31822
33130
  line({
31823
33131
  x1: e.x,
31824
- y1: e.y + e.headerHeight + i * C2.ROW_HEIGHT,
33132
+ y1: e.y + e.headerHeight + i * C3.ROW_HEIGHT,
31825
33133
  x2: e.x + e.width,
31826
- y2: e.y + e.headerHeight + i * C2.ROW_HEIGHT,
33134
+ y2: e.y + e.headerHeight + i * C3.ROW_HEIGHT,
31827
33135
  class: "lt-erd-row-divider"
31828
33136
  })
31829
33137
  );
@@ -31831,7 +33139,7 @@ function renderEntity(e) {
31831
33139
  body.push(
31832
33140
  text(
31833
33141
  {
31834
- x: e.x + C2.ENTITY_PADDING_X,
33142
+ x: e.x + C3.ENTITY_PADDING_X,
31835
33143
  y: cy,
31836
33144
  class: a.pk ? "lt-erd-attr-name-pk" : "lt-erd-attr-name"
31837
33145
  },
@@ -31842,7 +33150,7 @@ function renderEntity(e) {
31842
33150
  const markerW = 26;
31843
33151
  const markerGap = 4;
31844
33152
  const markersBlockW = markers6.length * markerW + (markers6.length - 1) * markerGap;
31845
- const markersStartX = e.x + e.width - C2.ENTITY_PADDING_X - markersBlockW;
33153
+ const markersStartX = e.x + e.width - C3.ENTITY_PADDING_X - markersBlockW;
31846
33154
  if (a.type) {
31847
33155
  body.push(
31848
33156
  text(
@@ -31890,25 +33198,25 @@ function renderEntity(e) {
31890
33198
  );
31891
33199
  }
31892
33200
  function renderGlyph2(ax, ay, dirX, dirY, card) {
31893
- const C2 = ERD_CONST;
33201
+ const C3 = ERD_CONST;
31894
33202
  const px = -dirY;
31895
33203
  const py = dirX;
31896
- const barDist = C2.GLYPH_OFFSET;
33204
+ const barDist = C3.GLYPH_OFFSET;
31897
33205
  const barX = ax + dirX * barDist;
31898
33206
  const barY = ay + dirY * barDist;
31899
33207
  const footTipX = ax;
31900
33208
  const footTipY = ay;
31901
- const footBaseX = ax + dirX * C2.GLYPH_FOOT_LEN;
31902
- const footBaseY = ay + dirY * C2.GLYPH_FOOT_LEN;
33209
+ const footBaseX = ax + dirX * C3.GLYPH_FOOT_LEN;
33210
+ const footBaseY = ay + dirY * C3.GLYPH_FOOT_LEN;
31903
33211
  const parts = [];
31904
33212
  switch (card) {
31905
33213
  case "one-mandatory": {
31906
33214
  parts.push(
31907
33215
  line({
31908
- x1: barX + px * C2.GLYPH_BAR_HALF,
31909
- y1: barY + py * C2.GLYPH_BAR_HALF,
31910
- x2: barX - px * C2.GLYPH_BAR_HALF,
31911
- y2: barY - py * C2.GLYPH_BAR_HALF,
33216
+ x1: barX + px * C3.GLYPH_BAR_HALF,
33217
+ y1: barY + py * C3.GLYPH_BAR_HALF,
33218
+ x2: barX - px * C3.GLYPH_BAR_HALF,
33219
+ y2: barY - py * C3.GLYPH_BAR_HALF,
31912
33220
  class: "lt-erd-glyph"
31913
33221
  })
31914
33222
  );
@@ -31919,7 +33227,7 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
31919
33227
  circle({
31920
33228
  cx: barX,
31921
33229
  cy: barY,
31922
- r: C2.GLYPH_CIRCLE_R,
33230
+ r: C3.GLYPH_CIRCLE_R,
31923
33231
  class: "lt-erd-glyph-circle"
31924
33232
  })
31925
33233
  );
@@ -31928,10 +33236,10 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
31928
33236
  case "many-mandatory": {
31929
33237
  parts.push(
31930
33238
  line({
31931
- x1: barX + px * C2.GLYPH_BAR_HALF,
31932
- y1: barY + py * C2.GLYPH_BAR_HALF,
31933
- x2: barX - px * C2.GLYPH_BAR_HALF,
31934
- y2: barY - py * C2.GLYPH_BAR_HALF,
33239
+ x1: barX + px * C3.GLYPH_BAR_HALF,
33240
+ y1: barY + py * C3.GLYPH_BAR_HALF,
33241
+ x2: barX - px * C3.GLYPH_BAR_HALF,
33242
+ y2: barY - py * C3.GLYPH_BAR_HALF,
31935
33243
  class: "lt-erd-glyph"
31936
33244
  })
31937
33245
  );
@@ -31942,8 +33250,8 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
31942
33250
  line({
31943
33251
  x1: footBaseX,
31944
33252
  y1: footBaseY,
31945
- x2: footTipX + px * C2.GLYPH_BAR_HALF,
31946
- y2: footTipY + py * C2.GLYPH_BAR_HALF,
33253
+ x2: footTipX + px * C3.GLYPH_BAR_HALF,
33254
+ y2: footTipY + py * C3.GLYPH_BAR_HALF,
31947
33255
  class: "lt-erd-glyph"
31948
33256
  })
31949
33257
  );
@@ -31951,8 +33259,8 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
31951
33259
  line({
31952
33260
  x1: footBaseX,
31953
33261
  y1: footBaseY,
31954
- x2: footTipX - px * C2.GLYPH_BAR_HALF,
31955
- y2: footTipY - py * C2.GLYPH_BAR_HALF,
33262
+ x2: footTipX - px * C3.GLYPH_BAR_HALF,
33263
+ y2: footTipY - py * C3.GLYPH_BAR_HALF,
31956
33264
  class: "lt-erd-glyph"
31957
33265
  })
31958
33266
  );
@@ -31963,7 +33271,7 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
31963
33271
  circle({
31964
33272
  cx: barX,
31965
33273
  cy: barY,
31966
- r: C2.GLYPH_CIRCLE_R,
33274
+ r: C3.GLYPH_CIRCLE_R,
31967
33275
  class: "lt-erd-glyph-circle"
31968
33276
  })
31969
33277
  );
@@ -31974,8 +33282,8 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
31974
33282
  line({
31975
33283
  x1: footBaseX,
31976
33284
  y1: footBaseY,
31977
- x2: footTipX + px * C2.GLYPH_BAR_HALF,
31978
- y2: footTipY + py * C2.GLYPH_BAR_HALF,
33285
+ x2: footTipX + px * C3.GLYPH_BAR_HALF,
33286
+ y2: footTipY + py * C3.GLYPH_BAR_HALF,
31979
33287
  class: "lt-erd-glyph"
31980
33288
  })
31981
33289
  );
@@ -31983,8 +33291,8 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
31983
33291
  line({
31984
33292
  x1: footBaseX,
31985
33293
  y1: footBaseY,
31986
- x2: footTipX - px * C2.GLYPH_BAR_HALF,
31987
- y2: footTipY - py * C2.GLYPH_BAR_HALF,
33294
+ x2: footTipX - px * C3.GLYPH_BAR_HALF,
33295
+ y2: footTipY - py * C3.GLYPH_BAR_HALF,
31988
33296
  class: "lt-erd-glyph"
31989
33297
  })
31990
33298
  );
@@ -32129,7 +33437,7 @@ var BreadboardParseError = class extends Error {
32129
33437
  }
32130
33438
  lineNumber;
32131
33439
  };
32132
- function stripComment15(s) {
33440
+ function stripComment16(s) {
32133
33441
  let out = "";
32134
33442
  let inQuote = false;
32135
33443
  for (let i = 0; i < s.length; i++) {
@@ -32150,7 +33458,7 @@ function unquote8(v) {
32150
33458
  }
32151
33459
  function lex2(text2) {
32152
33460
  return text2.split(/\r?\n/).map((raw, i) => ({
32153
- text: stripComment15(raw).trimEnd().replace(/^\s+/, ""),
33461
+ text: stripComment16(raw).trimEnd().replace(/^\s+/, ""),
32154
33462
  lineNumber: i + 1
32155
33463
  })).filter((l) => l.text.length > 0);
32156
33464
  }
@@ -34091,7 +35399,7 @@ function layerPool(ast, pool, colByObj) {
34091
35399
  }
34092
35400
  }
34093
35401
  }
34094
- function fmt6(n) {
35402
+ function fmt7(n) {
34095
35403
  return (Math.round(n * 100) / 100).toString();
34096
35404
  }
34097
35405
  function routeSequenceFlow(f, objCenter, objById) {
@@ -34112,11 +35420,11 @@ function routeSequenceFlow(f, objCenter, objById) {
34112
35420
  let labelAnchor;
34113
35421
  if (Math.abs(dx) >= Math.abs(dy)) {
34114
35422
  const midX = (from.x + to.x) / 2;
34115
- path2 = `M ${fmt6(from.x)} ${fmt6(from.y)} L ${fmt6(midX)} ${fmt6(from.y)} L ${fmt6(midX)} ${fmt6(to.y)} L ${fmt6(to.x)} ${fmt6(to.y)}`;
35423
+ path2 = `M ${fmt7(from.x)} ${fmt7(from.y)} L ${fmt7(midX)} ${fmt7(from.y)} L ${fmt7(midX)} ${fmt7(to.y)} L ${fmt7(to.x)} ${fmt7(to.y)}`;
34116
35424
  labelAnchor = { x: midX, y: (from.y + to.y) / 2 - 6 };
34117
35425
  } else {
34118
35426
  const midY = (from.y + to.y) / 2;
34119
- path2 = `M ${fmt6(from.x)} ${fmt6(from.y)} L ${fmt6(from.x)} ${fmt6(midY)} L ${fmt6(to.x)} ${fmt6(midY)} L ${fmt6(to.x)} ${fmt6(to.y)}`;
35427
+ path2 = `M ${fmt7(from.x)} ${fmt7(from.y)} L ${fmt7(from.x)} ${fmt7(midY)} L ${fmt7(to.x)} ${fmt7(midY)} L ${fmt7(to.x)} ${fmt7(to.y)}`;
34120
35428
  labelAnchor = { x: (from.x + to.x) / 2, y: midY - 6 };
34121
35429
  }
34122
35430
  return { flow: f, path: path2, labelAnchor };
@@ -34139,7 +35447,7 @@ function routeMessageFlow(f, objCenter, poolByLabel) {
34139
35447
  const A = endpoint(f.from);
34140
35448
  const B = endpoint(f.to);
34141
35449
  const midY = (A.y + B.y) / 2;
34142
- const path2 = `M ${fmt6(A.x)} ${fmt6(A.y)} L ${fmt6(A.x)} ${fmt6(midY)} L ${fmt6(B.x)} ${fmt6(midY)} L ${fmt6(B.x)} ${fmt6(B.y)}`;
35450
+ const path2 = `M ${fmt7(A.x)} ${fmt7(A.y)} L ${fmt7(A.x)} ${fmt7(midY)} L ${fmt7(B.x)} ${fmt7(midY)} L ${fmt7(B.x)} ${fmt7(B.y)}`;
34143
35451
  return { flow: f, path: path2, labelAnchor: { x: (A.x + B.x) / 2, y: midY - 6 } };
34144
35452
  }
34145
35453
 
@@ -41089,6 +42397,7 @@ var plugins = [
41089
42397
  eventtree,
41090
42398
  fmea,
41091
42399
  rbd,
42400
+ comparison,
41092
42401
  causalloop,
41093
42402
  markov,
41094
42403
  gitgraph,
@@ -41245,6 +42554,6 @@ function renderWithPlugin(prepared, plugin, config) {
41245
42554
  return plugin.render(prepared, renderConfig);
41246
42555
  }
41247
42556
 
41248
- export { FLOORPLAN_SYMBOLS, GEOMETRY, bowtie2 as bowtie, causalloop, decisiontree, drawDeviceIcon, epc, eventtree, faulttree, fmea, gitgraph, iconSize, idef0, markov, network, parse, parseResult, pert, petri, pid, prisma, rbd, render, renderEquip, renderPreview, renderResult, sequence, state, threatmodel, timeline, umlclass, usecase, welding };
41249
- //# sourceMappingURL=chunk-4W75FGWO.js.map
41250
- //# sourceMappingURL=chunk-4W75FGWO.js.map
42557
+ export { FLOORPLAN_SYMBOLS, GEOMETRY, bowtie2 as bowtie, causalloop, comparison, decisiontree, drawDeviceIcon, epc, eventtree, faulttree, fmea, gitgraph, iconSize, idef0, markov, network, parse, parseResult, pert, petri, pid, prisma, rbd, render, renderEquip, renderPreview, renderResult, sequence, state, threatmodel, timeline, umlclass, usecase, welding };
42558
+ //# sourceMappingURL=chunk-4QLIFOKH.js.map
42559
+ //# sourceMappingURL=chunk-4QLIFOKH.js.map