@diagrammo/dgmo 0.84.0 → 0.86.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/advanced.d.ts +74 -9
  2. package/dist/advanced.js +70 -52
  3. package/dist/block.js +9 -9
  4. package/dist/chart-meta.js +4 -4
  5. package/dist/{chunk-LRNIYQ6Y.js → chunk-33FQ6HNV.js} +1 -1
  6. package/dist/{chunk-REUEU5PU.js → chunk-3CQS3CIO.js} +2 -2
  7. package/dist/{chunk-LQSNWE3W.js → chunk-4ELXLATB.js} +1 -1
  8. package/dist/{chunk-QZRYCRT7.js → chunk-4YA5XW43.js} +40 -40
  9. package/dist/{chunk-23RWHHI5.js → chunk-5NU7NII2.js} +14 -2
  10. package/dist/{chunk-HMWZQ53A.js → chunk-7WGCQE2E.js} +1 -1
  11. package/dist/{chunk-NSS2EF5B.js → chunk-AAMCXQPP.js} +1 -1
  12. package/dist/{chunk-XD7XL3SF.js → chunk-AGO3PFGS.js} +1 -1
  13. package/dist/{chunk-ECIXBEG2.js → chunk-AQIBKTPG.js} +2 -2
  14. package/dist/{chunk-ITLPDLBH.js → chunk-BF7JAFJI.js} +1 -1
  15. package/dist/{chunk-RMAJIB6S.js → chunk-BHZE36F7.js} +3 -3
  16. package/dist/{chunk-6HOVLE3H.js → chunk-BT2WH2XT.js} +1 -1
  17. package/dist/{chunk-3MXJMZAN.js → chunk-BV6PKJUS.js} +105 -28
  18. package/dist/{chunk-PSH5DT26.js → chunk-C6FZZFYD.js} +2 -2
  19. package/dist/{chunk-7256EOAE.js → chunk-CFBY77QJ.js} +129 -10
  20. package/dist/{chunk-VKGQX6P2.js → chunk-D4M25W6R.js} +1 -1
  21. package/dist/{chunk-A4PHPKNR.js → chunk-DAX42XVH.js} +1 -1
  22. package/dist/{chunk-V3LJIPS4.js → chunk-E6S2K6O2.js} +1 -1
  23. package/dist/{chunk-BIQYWWJ2.js → chunk-ERYHC4KJ.js} +1 -1
  24. package/dist/{chunk-JLGN6S4B.js → chunk-EWSESGC2.js} +32 -3
  25. package/dist/{chunk-MIZ46MOF.js → chunk-GYORDNOM.js} +1 -1
  26. package/dist/{chunk-D7D5YK4J.js → chunk-H6AFNCN3.js} +14 -2
  27. package/dist/{chunk-PEFPTQ3Z.js → chunk-HUMQIRJK.js} +1 -1
  28. package/dist/{chunk-XXAZ5C4K.js → chunk-IJ27L3R4.js} +1 -1
  29. package/dist/{chunk-VDMG3MM4.js → chunk-JD4RHBNX.js} +1 -1
  30. package/dist/{chunk-J2ICADUM.js → chunk-LHBMQJC3.js} +1 -1
  31. package/dist/{chunk-Y7FTHOMD.js → chunk-LIYWJ6DV.js} +32 -223
  32. package/dist/{chunk-HATTVAWX.js → chunk-LJFXC3IP.js} +1 -1
  33. package/dist/{chunk-KABGWUND.js → chunk-MSXRNVHB.js} +5 -3
  34. package/dist/{chunk-2QIGN7KL.js → chunk-MYHPRQHR.js} +6 -2
  35. package/dist/{chunk-UJRMARNX.js → chunk-NJIGYGZS.js} +19 -1
  36. package/dist/{chunk-RYZNNXUV.js → chunk-PKXKWHDW.js} +1 -1
  37. package/dist/{chunk-C5FEPGSJ.js → chunk-QJFT5MAH.js} +1 -1
  38. package/dist/{chunk-ULCB4BLF.js → chunk-QPE646M2.js} +1 -1
  39. package/dist/{chunk-UNSN56OJ.js → chunk-R2K5L4UA.js} +1 -1
  40. package/dist/{chunk-SLMAAJPE.js → chunk-RGI64U3A.js} +1 -1
  41. package/dist/chunk-TW6WMZFW.js +287 -0
  42. package/dist/{chunk-ZUUNTOMG.js → chunk-UIUXIDBX.js} +1 -1
  43. package/dist/{chunk-XIYVGO24.js → chunk-UMRZPRAN.js} +3 -3
  44. package/dist/{chunk-67USWFFE.js → chunk-UY6TEJJH.js} +1 -1
  45. package/dist/{chunk-YWHGWLY6.js → chunk-VEE777MD.js} +3 -3
  46. package/dist/{chunk-UGYZ5Q5Y.js → chunk-VJ2KROJ5.js} +1 -1
  47. package/dist/{chunk-6EV2F6W7.js → chunk-VPASQOR3.js} +68 -46
  48. package/dist/{chunk-OGKP2XGJ.js → chunk-VPVWG2GH.js} +1 -1
  49. package/dist/{chunk-IIEI7VK5.js → chunk-XCKNFFKM.js} +2 -0
  50. package/dist/{chunk-AYA6C64M.js → chunk-XFMQSFS4.js} +84 -27
  51. package/dist/cloud-reference.d.ts +11 -1
  52. package/dist/cloud-reference.js +1 -1
  53. package/dist/{dgmo-router-YW4SBNYB.js → dgmo-router-F2DSURTR.js} +5 -5
  54. package/dist/{dimensions-F3Y5T54V.js → dimensions-6QAWEGIR.js} +2 -2
  55. package/dist/{flowchart-renderer-TGQL4S4L.js → flowchart-renderer-H72L7BEC.js} +2 -2
  56. package/dist/index.js +9 -9
  57. package/dist/{layout-WZCXK7DF.js → layout-5NPBHV5F.js} +2 -2
  58. package/dist/{layout-WXVGMSI3.js → layout-5VSMZPMG.js} +2 -2
  59. package/dist/{layout-K6NI4VCS.js → layout-CUFA7XJD.js} +2 -2
  60. package/dist/{layout-NB7TKAWN.js → layout-LUQKAGGT.js} +2 -2
  61. package/dist/{layout-CFTB7GKV.js → layout-QIPCNUSB.js} +2 -2
  62. package/dist/{layout-PT7IKVCV.js → layout-QX5T6ZNE.js} +2 -2
  63. package/dist/layout-T6TAB5OI.js +10 -0
  64. package/dist/{layout-search-GRJEBAUF.js → layout-search-AW5VBDCV.js} +13 -8
  65. package/dist/live-link-resolve.d.ts +21 -3
  66. package/dist/live-link-resolve.js +47 -17
  67. package/dist/{parser-6PHQJO42.js → parser-PVIWHVGY.js} +1 -1
  68. package/dist/{parser-6TXNMXNB.js → parser-XYY5NHP4.js} +2 -2
  69. package/dist/{renderer-FXX3XSNW.js → renderer-2BWRW23Z.js} +2 -2
  70. package/dist/{renderer-OV3GUJRR.js → renderer-36JH4OMC.js} +4 -4
  71. package/dist/{renderer-EU27D4S6.js → renderer-425QUIYO.js} +2 -2
  72. package/dist/{renderer-HV6ZYJMC.js → renderer-4NZZ5J2F.js} +2 -2
  73. package/dist/{renderer-UGA5DGKR.js → renderer-5JVVJBAS.js} +2 -2
  74. package/dist/{renderer-YSH5EX54.js → renderer-AI2MD52D.js} +1 -1
  75. package/dist/{renderer-HWEGM72C.js → renderer-BICLPGAH.js} +2 -2
  76. package/dist/{renderer-XS42HEXW.js → renderer-CZJ4AMYV.js} +2 -2
  77. package/dist/{renderer-WUDVV363.js → renderer-E7WF75GY.js} +2 -2
  78. package/dist/{renderer-3XRDFNYF.js → renderer-EWJS2RAZ.js} +3 -3
  79. package/dist/{renderer-5YOF2AHJ.js → renderer-JEEGPLMM.js} +2 -2
  80. package/dist/{renderer-OXSLLQQC.js → renderer-KVAQE7PQ.js} +2 -2
  81. package/dist/{renderer-TF3NTKP3.js → renderer-NX4YKWCJ.js} +2 -2
  82. package/dist/{renderer-P7LQBDU2.js → renderer-QM23SWAM.js} +2 -2
  83. package/dist/{renderer-FBAFYSIQ.js → renderer-RAATRF6W.js} +3 -3
  84. package/dist/{renderer-X4KFEKUK.js → renderer-RH4U3UVM.js} +3 -3
  85. package/dist/{renderer-G72GMBKA.js → renderer-RLSR7N6I.js} +4 -4
  86. package/dist/{renderer-3F4K2X57.js → renderer-RMGN3Q7D.js} +2 -2
  87. package/dist/{renderer-OVDVFPAI.js → renderer-RUGMKHX5.js} +3 -3
  88. package/dist/{renderer-GWNSV76V.js → renderer-UUWR7NGF.js} +3 -3
  89. package/dist/{renderer-J3O2KVTL.js → renderer-V6LLASGN.js} +2 -2
  90. package/dist/{renderer-FQAZ3KNU.js → renderer-VKAJ52UO.js} +2 -2
  91. package/dist/{renderer-WRWVFEX7.js → renderer-XRALFCIN.js} +6 -4
  92. package/dist/{renderer-QZW4RCZW.js → renderer-YIZ7G4HU.js} +6 -6
  93. package/dist/{state-renderer-B4ZF6ESS.js → state-renderer-DDVJ43HR.js} +2 -2
  94. package/docs/language-reference.md +24 -12
  95. package/gallery/fixtures/sequence-groups-nested.dgmo +50 -0
  96. package/package.json +2 -2
  97. package/dist/chunk-WTTIODDV.js +0 -9
  98. package/dist/layout-JQ3IPJYR.js +0 -9
@@ -0,0 +1,287 @@
1
+ import {
2
+ measureText,
3
+ truncateText,
4
+ wrapTextToWidth
5
+ } from "./chunk-KAO7JL4I.js";
6
+
7
+ // src/boxes-and-lines/node-metrics.ts
8
+ var PHI = 1.618;
9
+ var NODE_HEIGHT = 60;
10
+ var NODE_WIDTH = Math.round(NODE_HEIGHT * PHI);
11
+
12
+ // src/boxes-and-lines/label-placement.ts
13
+ var EDGE_LABEL_FONT_SIZE = 11;
14
+ var LABEL_MAX_WIDTH = 160;
15
+ var MAX_LABEL_LINES = 3;
16
+ var LABEL_LINE_HEIGHT = 1.3;
17
+ var H_PAD = 6;
18
+ var V_PAD = 3;
19
+ var BOX_CLEAR_PAD = 4;
20
+ var PERP_STEP = 8;
21
+ var LABEL_REACH_NEAR = 40;
22
+ var LABEL_REACH_WIDE = 56;
23
+ var SLIDE_SAMPLES = 9;
24
+ function measureEdgeLabel(label, fontSize = EDGE_LABEL_FONT_SIZE, maxWidth = LABEL_MAX_WIDTH) {
25
+ let lines = wrapTextToWidth(label, fontSize, maxWidth, { hardBreak: true });
26
+ if (lines.length > MAX_LABEL_LINES) {
27
+ const kept = lines.slice(0, MAX_LABEL_LINES - 1);
28
+ const rest = lines.slice(MAX_LABEL_LINES - 1).join(" ");
29
+ kept.push(truncateText(rest, fontSize, maxWidth));
30
+ lines = kept;
31
+ }
32
+ let textW = 0;
33
+ for (const ln of lines) {
34
+ const w = measureText(ln, fontSize);
35
+ if (w > textW) textW = w;
36
+ }
37
+ return {
38
+ lines,
39
+ width: textW + 2 * H_PAD,
40
+ height: lines.length * fontSize * LABEL_LINE_HEIGHT + 2 * V_PAD
41
+ };
42
+ }
43
+ function edgePolylineMidpoint(points) {
44
+ return pointAtArcFraction(points, 0.5).p;
45
+ }
46
+ function pointAtArcFraction(points, t) {
47
+ if (points.length === 0) return { p: { x: 0, y: 0 }, nx: 0, ny: 1 };
48
+ if (points.length === 1)
49
+ return { p: { x: points[0].x, y: points[0].y }, nx: 0, ny: 1 };
50
+ const segLen = [];
51
+ let total = 0;
52
+ for (let k = 1; k < points.length; k++) {
53
+ const len = Math.hypot(
54
+ points[k].x - points[k - 1].x,
55
+ points[k].y - points[k - 1].y
56
+ );
57
+ segLen.push(len);
58
+ total += len;
59
+ }
60
+ let want = total * Math.max(0, Math.min(1, t));
61
+ for (let k = 1; k < points.length; k++) {
62
+ const len = segLen[k - 1];
63
+ if (want <= len || k === points.length - 1) {
64
+ const f = len === 0 ? 0 : Math.min(1, want / len);
65
+ const ax = points[k - 1].x;
66
+ const ay = points[k - 1].y;
67
+ const bx = points[k].x;
68
+ const by = points[k].y;
69
+ const dx = bx - ax;
70
+ const dy = by - ay;
71
+ const dlen = Math.hypot(dx, dy) || 1;
72
+ return {
73
+ p: { x: ax + dx * f, y: ay + dy * f },
74
+ nx: -dy / dlen,
75
+ ny: dx / dlen
76
+ };
77
+ }
78
+ want -= len;
79
+ }
80
+ const last = points[points.length - 1];
81
+ return { p: { x: last.x, y: last.y }, nx: 0, ny: 1 };
82
+ }
83
+ function rectFromCenter(cx, cy, w, h) {
84
+ return {
85
+ minX: cx - w / 2,
86
+ minY: cy - h / 2,
87
+ maxX: cx + w / 2,
88
+ maxY: cy + h / 2
89
+ };
90
+ }
91
+ function overlapsAny(cx, cy, w, h, obstacles, pad) {
92
+ const minX = cx - w / 2 - pad;
93
+ const minY = cy - h / 2 - pad;
94
+ const maxX = cx + w / 2 + pad;
95
+ const maxY = cy + h / 2 + pad;
96
+ for (const o of obstacles) {
97
+ if (minX < o.maxX && maxX > o.minX && minY < o.maxY && maxY > o.minY)
98
+ return true;
99
+ }
100
+ return false;
101
+ }
102
+ function slideFractions() {
103
+ const out = [0.5];
104
+ for (let k = 1; k <= SLIDE_SAMPLES; k++) {
105
+ const off = k * 0.08;
106
+ if (0.5 - off >= 0.12) out.push(0.5 - off);
107
+ if (0.5 + off <= 0.88) out.push(0.5 + off);
108
+ }
109
+ return out;
110
+ }
111
+ function findClearPosition(w, h, points, obstacles, perpMax) {
112
+ const ts = slideFractions();
113
+ for (const t of ts) {
114
+ const { p } = pointAtArcFraction(points, t);
115
+ if (!overlapsAny(p.x, p.y, w, h, obstacles, BOX_CLEAR_PAD)) return p;
116
+ }
117
+ for (let mag = PERP_STEP; mag <= perpMax; mag += PERP_STEP) {
118
+ for (const t of ts) {
119
+ const { p, nx, ny } = pointAtArcFraction(points, t);
120
+ for (const sign of [-1, 1]) {
121
+ const x = p.x + nx * mag * sign;
122
+ const y = p.y + ny * mag * sign;
123
+ if (!overlapsAny(x, y, w, h, obstacles, BOX_CLEAR_PAD)) return { x, y };
124
+ }
125
+ }
126
+ }
127
+ return null;
128
+ }
129
+ function buildGroupContainers(groups) {
130
+ const byLabel = new Map(groups.map((g) => [g.label, g]));
131
+ const parent = /* @__PURE__ */ new Map();
132
+ for (const g of groups)
133
+ for (const c of g.children) if (byLabel.has(c)) parent.set(c, g.label);
134
+ for (const g of groups) if (g.parentGroup) parent.set(g.label, g.parentGroup);
135
+ const chainOf = (label) => {
136
+ const out = [];
137
+ const seen = /* @__PURE__ */ new Set();
138
+ let cur = label;
139
+ while (cur !== void 0 && byLabel.has(cur) && !seen.has(cur)) {
140
+ seen.add(cur);
141
+ out.push(cur);
142
+ cur = parent.get(cur);
143
+ }
144
+ return out;
145
+ };
146
+ const containers = /* @__PURE__ */ new Map();
147
+ for (const g of groups) containers.set(g.label, new Set(chainOf(g.label)));
148
+ for (const g of groups) {
149
+ const chain = chainOf(g.label);
150
+ for (const c of g.children) {
151
+ if (byLabel.has(c)) continue;
152
+ let set = containers.get(c);
153
+ if (!set) {
154
+ set = /* @__PURE__ */ new Set();
155
+ containers.set(c, set);
156
+ }
157
+ for (const a of chain) set.add(a);
158
+ }
159
+ }
160
+ return containers;
161
+ }
162
+ function resolveLabelOverlaps(boxes) {
163
+ const MAX_PASSES = 8;
164
+ const PAD = 4;
165
+ for (let pass = 0; pass < MAX_PASSES; pass++) {
166
+ let moved = false;
167
+ for (let i = 0; i < boxes.length; i++) {
168
+ for (let j = i + 1; j < boxes.length; j++) {
169
+ const a = boxes[i];
170
+ const b = boxes[j];
171
+ const dx = Math.abs(a.cx - b.cx);
172
+ const dy = Math.abs(a.cy - b.cy);
173
+ const overlapX = (a.w + b.w) / 2 + PAD - dx;
174
+ const overlapY = (a.h + b.h) / 2 + PAD - dy;
175
+ if (overlapX > 0 && overlapY > 0) {
176
+ const shift = overlapY / 2 + 1;
177
+ if (a.cy < b.cy) {
178
+ a.cy -= shift;
179
+ b.cy += shift;
180
+ } else {
181
+ a.cy += shift;
182
+ b.cy -= shift;
183
+ }
184
+ moved = true;
185
+ }
186
+ }
187
+ }
188
+ if (!moved) break;
189
+ }
190
+ }
191
+ function placeEdgeLabels(layout, opts) {
192
+ const fontSize = opts?.fontSize ?? EDGE_LABEL_FONT_SIZE;
193
+ const maxWidth = opts?.maxWidth ?? LABEL_MAX_WIDTH;
194
+ const perpMax = opts?.perpMax ?? LABEL_REACH_NEAR;
195
+ const baseObstacles = [];
196
+ for (const n of layout.nodes)
197
+ baseObstacles.push(rectFromCenter(n.x, n.y, n.width, n.height));
198
+ const expandedGroups = [];
199
+ for (const g of layout.groups) {
200
+ const r = rectFromCenter(g.x, g.y, g.width, g.height);
201
+ if (g.collapsed) baseObstacles.push(r);
202
+ else expandedGroups.push({ label: g.label, rect: r });
203
+ }
204
+ const containers = buildGroupContainers(opts?.groups ?? []);
205
+ const noContainers = /* @__PURE__ */ new Set();
206
+ const obstacleCache = /* @__PURE__ */ new Map();
207
+ const obstaclesFor = (edgeIdx) => {
208
+ const cached = obstacleCache.get(edgeIdx);
209
+ if (cached !== void 0) return cached;
210
+ let out = baseObstacles;
211
+ if (expandedGroups.length > 0) {
212
+ const e = layout.edges[edgeIdx];
213
+ const src = containers.get(e.source) ?? noContainers;
214
+ const tgt = containers.get(e.target) ?? noContainers;
215
+ const foreign = expandedGroups.filter((g) => !(src.has(g.label) && tgt.has(g.label))).map((g) => g.rect);
216
+ if (foreign.length > 0) out = [...baseObstacles, ...foreign];
217
+ }
218
+ obstacleCache.set(edgeIdx, out);
219
+ return out;
220
+ };
221
+ const boxes = [];
222
+ layout.edges.forEach((e, idx) => {
223
+ if (!e.label || e.points.length < 2) return;
224
+ const m = measureEdgeLabel(e.label, fontSize, maxWidth);
225
+ const mid = edgePolylineMidpoint(e.points);
226
+ let cy = mid.y;
227
+ if (e.parallelCount > 1 && e.yOffset !== 0)
228
+ cy += (e.yOffset < 0 ? -1 : 1) * (m.height / 2);
229
+ boxes.push({
230
+ edgeIdx: idx,
231
+ cx: mid.x,
232
+ cy,
233
+ w: m.width,
234
+ h: m.height,
235
+ lines: m.lines,
236
+ resolved: true
237
+ });
238
+ });
239
+ for (const box of boxes) {
240
+ const obstacles = obstaclesFor(box.edgeIdx);
241
+ if (!overlapsAny(box.cx, box.cy, box.w, box.h, obstacles, BOX_CLEAR_PAD))
242
+ continue;
243
+ const e = layout.edges[box.edgeIdx];
244
+ const clear = findClearPosition(box.w, box.h, e.points, obstacles, perpMax) ?? findClearPosition(box.w, box.h, e.points, baseObstacles, perpMax);
245
+ if (clear) {
246
+ box.cx = clear.x;
247
+ box.cy = clear.y;
248
+ }
249
+ if (overlapsAny(box.cx, box.cy, box.w, box.h, obstacles, BOX_CLEAR_PAD))
250
+ box.resolved = false;
251
+ }
252
+ resolveLabelOverlaps(boxes);
253
+ for (const box of boxes) {
254
+ const obstacles = obstaclesFor(box.edgeIdx);
255
+ if (overlapsAny(box.cx, box.cy, box.w, box.h, obstacles, BOX_CLEAR_PAD))
256
+ box.resolved = false;
257
+ }
258
+ const boxByIdx = /* @__PURE__ */ new Map();
259
+ for (const b of boxes) boxByIdx.set(b.edgeIdx, b);
260
+ const edges = layout.edges.map((e, idx) => {
261
+ const b = boxByIdx.get(idx);
262
+ if (!b) return e;
263
+ return {
264
+ ...e,
265
+ labelX: b.cx,
266
+ labelY: b.cy,
267
+ labelWidth: b.w,
268
+ labelHeight: b.h,
269
+ labelLines: b.lines,
270
+ labelResolved: b.resolved
271
+ };
272
+ });
273
+ return {
274
+ layout: { ...layout, edges },
275
+ unresolved: boxes.filter((b) => !b.resolved).map((b) => b.edgeIdx)
276
+ };
277
+ }
278
+
279
+ export {
280
+ NODE_HEIGHT,
281
+ NODE_WIDTH,
282
+ EDGE_LABEL_FONT_SIZE,
283
+ BOX_CLEAR_PAD,
284
+ LABEL_REACH_WIDE,
285
+ measureEdgeLabel,
286
+ placeEdgeLabels
287
+ };
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-24YPR5EH.js";
4
4
  import {
5
5
  HEADER_HEIGHT
6
- } from "./chunk-IIEI7VK5.js";
6
+ } from "./chunk-XCKNFFKM.js";
7
7
  import {
8
8
  measureText,
9
9
  truncateText
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  layoutOrg
3
- } from "./chunk-LRNIYQ6Y.js";
3
+ } from "./chunk-33FQ6HNV.js";
4
4
  import {
5
5
  renderCollapseBar,
6
6
  renderNodeCard
7
- } from "./chunk-UNSN56OJ.js";
7
+ } from "./chunk-R2K5L4UA.js";
8
8
  import {
9
9
  ScaleContext
10
10
  } from "./chunk-24YPR5EH.js";
@@ -24,7 +24,7 @@ import {
24
24
  META_LINE_HEIGHT,
25
25
  NODE_STROKE_WIDTH,
26
26
  SEPARATOR_GAP
27
- } from "./chunk-IIEI7VK5.js";
27
+ } from "./chunk-XCKNFFKM.js";
28
28
  import {
29
29
  extractExportSvg,
30
30
  runInExportContainer
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  EDGE_DASH,
3
3
  HAIRLINE_DASH
4
- } from "./chunk-IIEI7VK5.js";
4
+ } from "./chunk-XCKNFFKM.js";
5
5
  import {
6
6
  TITLE_FONT_SIZE,
7
7
  TITLE_FONT_WEIGHT,
@@ -3,13 +3,13 @@ import {
3
3
  } from "./chunk-WMIKC5XO.js";
4
4
  import {
5
5
  renderNodeCard
6
- } from "./chunk-UNSN56OJ.js";
6
+ } from "./chunk-R2K5L4UA.js";
7
7
  import {
8
8
  renderInlineText
9
9
  } from "./chunk-FWNJDD4U.js";
10
10
  import {
11
11
  formatDateLabel
12
- } from "./chunk-ULCB4BLF.js";
12
+ } from "./chunk-QPE646M2.js";
13
13
  import {
14
14
  CARD_RADIUS,
15
15
  HAIRLINE_DASH,
@@ -17,7 +17,7 @@ import {
17
17
  LABEL_FONT_SIZE,
18
18
  NODE_STROKE_WIDTH,
19
19
  SEPARATOR_GAP
20
- } from "./chunk-IIEI7VK5.js";
20
+ } from "./chunk-XCKNFFKM.js";
21
21
  import {
22
22
  layoutInlineHeader
23
23
  } from "./chunk-3DOQOXXI.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildMapProjection
3
- } from "./chunk-3MXJMZAN.js";
3
+ } from "./chunk-BV6PKJUS.js";
4
4
  import {
5
5
  TITLE_FONT_SIZE,
6
6
  TITLE_Y
@@ -41,6 +41,22 @@ import {
41
41
  suggest
42
42
  } from "./chunk-BYU54C3S.js";
43
43
 
44
+ // src/sequence/diagnostics.ts
45
+ var SEQUENCE_DIAGNOSTIC_CODES = {
46
+ GROUP_DEPTH: "E_SEQ_GROUP_DEPTH"
47
+ };
48
+ var SEQUENCE_DIAGNOSTICS = [
49
+ {
50
+ code: SEQUENCE_DIAGNOSTIC_CODES.GROUP_DEPTH,
51
+ severity: "error",
52
+ chartType: "sequence",
53
+ title: "Group nested too deep",
54
+ message: (p) => `Group "${String(p.label ?? "?")}" is nested ${String(p.depth ?? "?")} levels deep \u2014 participant groups nest to depth ${String(p.max ?? "?")}; its participants join the group above it`,
55
+ hint: "Move the inner [Group] up a level \u2014 two levels of bracket is the bound.",
56
+ example: "sequence\n[Monolith]\n [Linux]\n [Container]\n App"
57
+ }
58
+ ];
59
+
44
60
  // src/sequence/parser.ts
45
61
  var KNOWN_SEQ_OPTIONS = /* @__PURE__ */ new Set(["active-tag"]);
46
62
  var KNOWN_SEQ_BOOLEANS = /* @__PURE__ */ new Set([
@@ -70,6 +86,7 @@ function isSequenceNote(el) {
70
86
  }
71
87
  var IS_A_PATTERN = /^([^:]+?)\s+is\s+an?\s+(\w+)(?:\s+(.+))?$/i;
72
88
  var COLORED_PARTICIPANT_PATTERN = /^(\S+?)\((red|orange|yellow|green|blue|purple|teal|cyan|gray|black|white)\)\s*$/;
89
+ var MAX_GROUP_DEPTH = 2;
73
90
  var GROUP_HEADING_PATTERN = /^\[([^\]|]+?)(?:\(([^)]+)\))?\]\s*(.*)$/;
74
91
  var GROUP_HEADING_FALLBACK = /^\[([^\]]+)\]\s*(.*)$/;
75
92
  var SECTION_PATTERN = /^==\s+(.+?)(?:\s*==)?\s*$/;
@@ -218,8 +235,8 @@ function parseSequenceDgmo(content, palette) {
218
235
  return nameAliasMap.resolve(trimmed) ?? trimmed;
219
236
  };
220
237
  const fail = makeFail(result);
221
- const pushError = (line, message) => {
222
- const diag = makeDgmoError(line, message);
238
+ const pushError = (line, message, code) => {
239
+ const diag = makeDgmoError(line, message, "error", code);
223
240
  result.diagnostics.push(diag);
224
241
  if (!result.error) result.error = formatDgmoError(diag);
225
242
  };
@@ -249,7 +266,31 @@ function parseSequenceDgmo(content, palette) {
249
266
  }
250
267
  break;
251
268
  }
252
- let activeGroup = null;
269
+ const groupStack = [];
270
+ const activeGroup = () => groupStack.length > 0 ? groupStack[groupStack.length - 1].group : null;
271
+ const closeGroupsTo = (indent) => {
272
+ while (groupStack.length > 0 && groupStack[groupStack.length - 1].indent >= indent) {
273
+ groupStack.pop();
274
+ }
275
+ };
276
+ const joinActiveGroup = (key, id, lineNumber) => {
277
+ const innermost = activeGroup();
278
+ if (!innermost || innermost.participantIds.includes(key)) return;
279
+ const existingGroup = participantGroupMap.get(key);
280
+ if (existingGroup) {
281
+ pushError(
282
+ lineNumber,
283
+ `Participant '${id}' is already in group '${existingGroup}' \u2014 participants can only belong to one group`
284
+ );
285
+ return;
286
+ }
287
+ for (const frame of groupStack) {
288
+ if (!frame.group.participantIds.includes(key)) {
289
+ frame.group.participantIds.push(key);
290
+ }
291
+ }
292
+ participantGroupMap.set(key, innermost.name);
293
+ };
253
294
  const participantIds = /* @__PURE__ */ new Set();
254
295
  const idByKey = /* @__PURE__ */ new Map();
255
296
  const addParticipant = (name, lineNumber, extras) => {
@@ -364,7 +405,7 @@ function parseSequenceDgmo(content, palette) {
364
405
  const lineNumber = i + 1;
365
406
  nameAliasMap.at(lineNumber);
366
407
  if (!trimmed) {
367
- activeGroup = null;
408
+ closeGroupsTo(0);
368
409
  currentTagGroup = null;
369
410
  continue;
370
411
  }
@@ -407,14 +448,29 @@ function parseSequenceDgmo(content, palette) {
407
448
  );
408
449
  }
409
450
  contentStarted = true;
410
- activeGroup = {
451
+ const headingIndent = measureIndent(raw);
452
+ closeGroupsTo(headingIndent);
453
+ const depth = groupStack.length;
454
+ if (depth >= MAX_GROUP_DEPTH) {
455
+ pushError(
456
+ lineNumber,
457
+ `Group '${groupName}' is nested ${String(depth + 1)} levels deep \u2014 participant groups nest to depth ${String(MAX_GROUP_DEPTH)}; its participants join the group above it`,
458
+ SEQUENCE_DIAGNOSTIC_CODES.GROUP_DEPTH
459
+ );
460
+ continue;
461
+ }
462
+ const parentGroup = activeGroup();
463
+ const group = {
411
464
  name: groupName,
412
465
  participantIds: [],
413
466
  lineNumber,
467
+ depth,
468
+ ...parentGroup ? { parent: parentGroup.name } : {},
414
469
  ...groupMeta ? { metadata: groupMeta } : {},
415
470
  ...isCollapsed ? { collapsed: true } : {}
416
471
  };
417
- result.groups.push(activeGroup);
472
+ result.groups.push(group);
473
+ groupStack.push({ group, indent: headingIndent });
418
474
  continue;
419
475
  }
420
476
  if (trimmed.startsWith("[")) {
@@ -431,9 +487,7 @@ function parseSequenceDgmo(content, palette) {
431
487
  continue;
432
488
  }
433
489
  }
434
- if (activeGroup && measureIndent(raw) === 0) {
435
- activeGroup = null;
436
- }
490
+ closeGroupsTo(measureIndent(raw));
437
491
  if (trimmed.startsWith("//")) continue;
438
492
  if (trimmed.startsWith("#")) {
439
493
  pushError(lineNumber, "Use // for comments");
@@ -623,18 +677,7 @@ function parseSequenceDgmo(content, palette) {
623
677
  ...position !== void 0 && { position },
624
678
  ...isAMeta !== void 0 && { metadata: isAMeta }
625
679
  });
626
- if (activeGroup && !activeGroup.participantIds.includes(key)) {
627
- const existingGroup = participantGroupMap.get(key);
628
- if (existingGroup) {
629
- pushError(
630
- lineNumber,
631
- `Participant '${id}' is already in group '${existingGroup}' \u2014 participants can only belong to one group`
632
- );
633
- } else {
634
- activeGroup.participantIds.push(key);
635
- participantGroupMap.set(key, activeGroup.name);
636
- }
637
- }
680
+ joinActiveGroup(key, id, lineNumber);
638
681
  continue;
639
682
  }
640
683
  const { core: colorCore, meta: colorMeta } = splitPipe(trimmed, lineNumber);
@@ -650,18 +693,7 @@ function parseSequenceDgmo(content, palette) {
650
693
  const key = addParticipant(id, lineNumber, {
651
694
  ...colorMeta !== void 0 && { metadata: colorMeta }
652
695
  });
653
- if (activeGroup && !activeGroup.participantIds.includes(key)) {
654
- const existingGroup = participantGroupMap.get(key);
655
- if (existingGroup) {
656
- pushError(
657
- lineNumber,
658
- `Participant '${id}' is already in group '${existingGroup}' \u2014 participants can only belong to one group`
659
- );
660
- } else {
661
- activeGroup.participantIds.push(key);
662
- participantGroupMap.set(key, activeGroup.name);
663
- }
664
- }
696
+ joinActiveGroup(key, id, lineNumber);
665
697
  continue;
666
698
  }
667
699
  {
@@ -670,7 +702,7 @@ function parseSequenceDgmo(content, palette) {
670
702
  meta: bareMeta,
671
703
  alias: bareAlias
672
704
  } = splitPipe(trimmed, lineNumber);
673
- const inGroup = activeGroup && measureIndent(raw) > 0;
705
+ const inGroup = activeGroup() !== null && measureIndent(raw) > 0;
674
706
  if (/^\S+$/.test(bareCore) && !ARROW_PATTERN.test(bareCore) && (inGroup || !bodyStarted || bareMeta)) {
675
707
  contentStarted = true;
676
708
  const id = bareCore;
@@ -682,18 +714,7 @@ function parseSequenceDgmo(content, palette) {
682
714
  ...position !== void 0 && { position },
683
715
  ...bareMeta !== void 0 && { metadata: bareMeta }
684
716
  });
685
- if (activeGroup && !activeGroup.participantIds.includes(key)) {
686
- const existingGroup = participantGroupMap.get(key);
687
- if (existingGroup) {
688
- pushError(
689
- lineNumber,
690
- `Participant '${id}' is already in group '${existingGroup}' \u2014 participants can only belong to one group`
691
- );
692
- } else {
693
- activeGroup.participantIds.push(key);
694
- participantGroupMap.set(key, activeGroup.name);
695
- }
696
- }
717
+ joinActiveGroup(key, id, lineNumber);
697
718
  continue;
698
719
  }
699
720
  }
@@ -1066,6 +1087,7 @@ function looksLikeSequence(content) {
1066
1087
  }
1067
1088
 
1068
1089
  export {
1090
+ SEQUENCE_DIAGNOSTICS,
1069
1091
  isSequenceBlock,
1070
1092
  isSequenceSection,
1071
1093
  isSequenceNote,
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-24YPR5EH.js";
7
7
  import {
8
8
  CARD_RADIUS
9
- } from "./chunk-IIEI7VK5.js";
9
+ } from "./chunk-XCKNFFKM.js";
10
10
  import {
11
11
  serializeSvg
12
12
  } from "./chunk-LD2JSKU3.js";
@@ -5,6 +5,7 @@ var CARD_RADIUS = 6;
5
5
  var CONTAINER_RADIUS = 8;
6
6
  var COLLAPSE_BAR_INSET = 0;
7
7
  var EDGE_LABEL_KNOCKOUT_OPACITY = 0.9;
8
+ var EDGE_LABEL_UNRESOLVED_KNOCKOUT_OPACITY = 1;
8
9
  var ARROWHEAD_WIDTH = 10;
9
10
  var ARROWHEAD_HEIGHT = 7;
10
11
  var EDGE_DASH = "6 3";
@@ -31,6 +32,7 @@ export {
31
32
  CONTAINER_RADIUS,
32
33
  COLLAPSE_BAR_INSET,
33
34
  EDGE_LABEL_KNOCKOUT_OPACITY,
35
+ EDGE_LABEL_UNRESOLVED_KNOCKOUT_OPACITY,
34
36
  ARROWHEAD_WIDTH,
35
37
  ARROWHEAD_HEIGHT,
36
38
  EDGE_DASH,