@diagrammo/dgmo 0.8.23 → 0.8.25

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 (72) hide show
  1. package/.claude/commands/dgmo.md +60 -72
  2. package/dist/cli.cjs +119 -114
  3. package/dist/editor.cjs +0 -2
  4. package/dist/editor.cjs.map +1 -1
  5. package/dist/editor.js +0 -2
  6. package/dist/editor.js.map +1 -1
  7. package/dist/highlight.cjs +0 -2
  8. package/dist/highlight.cjs.map +1 -1
  9. package/dist/highlight.js +0 -2
  10. package/dist/highlight.js.map +1 -1
  11. package/dist/index.cjs +690 -278
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +105 -18
  14. package/dist/index.d.ts +105 -18
  15. package/dist/index.js +680 -277
  16. package/dist/index.js.map +1 -1
  17. package/dist/internal.cjs +348 -51
  18. package/dist/internal.cjs.map +1 -1
  19. package/dist/internal.d.cts +93 -5
  20. package/dist/internal.d.ts +93 -5
  21. package/dist/internal.js +334 -38
  22. package/dist/internal.js.map +1 -1
  23. package/docs/guide/chart-area.md +17 -17
  24. package/docs/guide/chart-bar-stacked.md +12 -12
  25. package/docs/guide/chart-doughnut.md +10 -10
  26. package/docs/guide/chart-funnel.md +9 -9
  27. package/docs/guide/chart-heatmap.md +10 -10
  28. package/docs/guide/chart-kanban.md +2 -0
  29. package/docs/guide/chart-line.md +19 -19
  30. package/docs/guide/chart-multi-line.md +16 -16
  31. package/docs/guide/chart-pie.md +11 -11
  32. package/docs/guide/chart-polar-area.md +10 -10
  33. package/docs/guide/chart-radar.md +9 -9
  34. package/docs/guide/chart-scatter.md +24 -27
  35. package/docs/guide/index.md +3 -3
  36. package/docs/language-reference.md +46 -25
  37. package/fonts/Inter-Bold.ttf +0 -0
  38. package/fonts/Inter-Regular.ttf +0 -0
  39. package/fonts/LICENSE-Inter.txt +92 -0
  40. package/gallery/fixtures/bar-stacked.dgmo +12 -6
  41. package/gallery/fixtures/heatmap.dgmo +12 -6
  42. package/gallery/fixtures/multi-line.dgmo +11 -7
  43. package/gallery/fixtures/quadrant.dgmo +8 -8
  44. package/gallery/fixtures/scatter.dgmo +12 -12
  45. package/package.json +4 -2
  46. package/src/boxes-and-lines/parser.ts +13 -2
  47. package/src/boxes-and-lines/renderer.ts +22 -13
  48. package/src/chart-type-scoring.ts +162 -0
  49. package/src/chart-types.ts +437 -0
  50. package/src/cli.ts +147 -66
  51. package/src/completion.ts +0 -4
  52. package/src/d3.ts +9 -2
  53. package/src/dgmo-router.ts +85 -130
  54. package/src/editor/keywords.ts +0 -2
  55. package/src/fonts.ts +3 -2
  56. package/src/gantt/parser.ts +5 -1
  57. package/src/index.ts +24 -1
  58. package/src/infra/parser.ts +1 -1
  59. package/src/internal.ts +6 -2
  60. package/src/journey-map/layout.ts +7 -3
  61. package/src/journey-map/parser.ts +5 -1
  62. package/src/kanban/parser.ts +5 -1
  63. package/src/org/collapse.ts +1 -4
  64. package/src/org/parser.ts +1 -1
  65. package/src/org/renderer.ts +26 -17
  66. package/src/sequence/parser.ts +2 -2
  67. package/src/sequence/participant-inference.ts +0 -1
  68. package/src/sequence/renderer.ts +95 -263
  69. package/src/sharing.ts +0 -1
  70. package/src/sitemap/parser.ts +1 -1
  71. package/src/utils/tag-groups.ts +35 -5
  72. package/src/wireframe/parser.ts +3 -1
@@ -103,6 +103,27 @@ declare function computeCardArchive(content: string, parsed: ParsedKanban, cardI
103
103
  /** Check if a column name is the archive column (case-insensitive). */
104
104
  declare function isArchiveColumn(name: string): boolean;
105
105
 
106
+ /**
107
+ * Participant types that can be declared via "Name is a type" syntax.
108
+ */
109
+ type ParticipantType = 'default' | 'service' | 'database' | 'actor' | 'queue' | 'cache' | 'gateway' | 'external' | 'networking' | 'frontend';
110
+ /**
111
+ * A declared or inferred participant in the sequence diagram.
112
+ */
113
+ interface SequenceParticipant {
114
+ /** Internal identifier (e.g. "AuthService") */
115
+ id: string;
116
+ /** Display label — uses aka alias if provided, otherwise id */
117
+ label: string;
118
+ /** Participant shape type */
119
+ type: ParticipantType;
120
+ /** Source line number (1-based) */
121
+ lineNumber: number;
122
+ /** Explicit layout position override (0-based from left, negative from right) */
123
+ position?: number;
124
+ /** Pipe-delimited tag metadata (e.g. `| role: Gateway`) */
125
+ metadata?: Record<string, string>;
126
+ }
106
127
  /**
107
128
  * A message between two participants.
108
129
  */
@@ -153,6 +174,18 @@ interface SequenceNote {
153
174
  endLineNumber: number;
154
175
  }
155
176
  type SequenceElement = SequenceMessage | SequenceBlock | SequenceSection | SequenceNote;
177
+ /**
178
+ * A named group of participants rendered as a labeled box.
179
+ */
180
+ interface SequenceGroup {
181
+ name: string;
182
+ participantIds: string[];
183
+ lineNumber: number;
184
+ /** Pipe-delimited tag metadata (e.g. `[Backend | t: Product]`) */
185
+ metadata?: Record<string, string>;
186
+ /** Whether this group is collapsed by default */
187
+ collapsed?: boolean;
188
+ }
156
189
 
157
190
  interface SectionMessageGroup {
158
191
  section: SequenceSection;
@@ -164,16 +197,71 @@ interface SectionMessageGroup {
164
197
  * Only top-level sections are collapsible — sections inside blocks are excluded.
165
198
  */
166
199
  declare function groupMessagesBySection(elements: SequenceElement[], messages: SequenceMessage[]): SectionMessageGroup[];
200
+ interface RenderStep {
201
+ type: 'call' | 'return';
202
+ from: string;
203
+ to: string;
204
+ label: string;
205
+ messageIndex: number;
206
+ async?: boolean;
207
+ }
208
+ /**
209
+ * Build an ordered render sequence from flat messages.
210
+ * Uses a call stack to infer where returns should be placed:
211
+ * returns appear after all nested sub-calls complete.
212
+ */
213
+ declare function buildRenderSequence(messages: SequenceMessage[]): RenderStep[];
214
+ interface Activation {
215
+ participantId: string;
216
+ startStep: number;
217
+ endStep: number;
218
+ depth: number;
219
+ }
220
+ /**
221
+ * Compute activation rectangles from render steps.
222
+ * Each call pushes onto the callee's stack; each return pops it.
223
+ */
224
+ declare function computeActivations(steps: RenderStep[]): Activation[];
225
+ /**
226
+ * Reorder participants based on explicit `position` overrides.
227
+ * Positive positions are 0-based from the left; negative positions count from the right (-1 = last).
228
+ * Unpositioned participants maintain their relative order, filling remaining slots.
229
+ */
230
+ declare function applyPositionOverrides(participants: SequenceParticipant[]): SequenceParticipant[];
231
+ /**
232
+ * Reorder participants so that members of the same group are adjacent.
233
+ * Groups are positioned at the point where their first member would naturally
234
+ * appear based on message order (first-occurrence positioning). This prevents
235
+ * groups declared at the top of the file from being placed before participants
236
+ * that appear in messages earlier.
237
+ *
238
+ * Explicit `position` overrides are handled separately by `applyPositionOverrides`.
239
+ */
240
+ declare function applyGroupOrdering(participants: SequenceParticipant[], groups: SequenceGroup[], messages?: SequenceMessage[]): SequenceParticipant[];
167
241
  /**
168
242
  * Build a mapping from each note's lineNumber to the lineNumber of its
169
243
  * associated message (the last message before the note in document order).
170
- * Used by the app to expand notes when cursor is on the associated message.
244
+ * Used by the app to highlight the associated message when cursor is on a note.
171
245
  */
172
246
  declare function buildNoteMessageMap(elements: SequenceElement[]): Map<number, number>;
247
+
248
+ interface ArcLink {
249
+ source: string;
250
+ target: string;
251
+ value: number;
252
+ color: string | null;
253
+ lineNumber: number;
254
+ }
255
+ type ArcOrder = 'appearance' | 'name' | 'group' | 'degree';
256
+ interface ArcNodeGroup {
257
+ name: string;
258
+ nodes: string[];
259
+ color: string | null;
260
+ lineNumber: number;
261
+ }
173
262
  /**
174
- * Collect all note line numbers from a sequence diagram's elements.
175
- * Used by the app to compute the "expand all" set.
263
+ * Orders arc diagram nodes based on the selected ordering strategy.
176
264
  */
177
- declare function collectNoteLineNumbers(elements: SequenceElement[]): number[];
265
+ declare function orderArcNodes(links: ArcLink[], order: ArcOrder, groups: ArcNodeGroup[]): string[];
178
266
 
179
- export { buildNoteMessageMap, collectNoteLineNumbers, computeCardArchive, computeCardMove, groupMessagesBySection, isArchiveColumn, parseDataRowValues };
267
+ export { applyGroupOrdering, applyPositionOverrides, buildNoteMessageMap, buildRenderSequence, computeActivations, computeCardArchive, computeCardMove, groupMessagesBySection, isArchiveColumn, orderArcNodes, parseDataRowValues };
@@ -103,6 +103,27 @@ declare function computeCardArchive(content: string, parsed: ParsedKanban, cardI
103
103
  /** Check if a column name is the archive column (case-insensitive). */
104
104
  declare function isArchiveColumn(name: string): boolean;
105
105
 
106
+ /**
107
+ * Participant types that can be declared via "Name is a type" syntax.
108
+ */
109
+ type ParticipantType = 'default' | 'service' | 'database' | 'actor' | 'queue' | 'cache' | 'gateway' | 'external' | 'networking' | 'frontend';
110
+ /**
111
+ * A declared or inferred participant in the sequence diagram.
112
+ */
113
+ interface SequenceParticipant {
114
+ /** Internal identifier (e.g. "AuthService") */
115
+ id: string;
116
+ /** Display label — uses aka alias if provided, otherwise id */
117
+ label: string;
118
+ /** Participant shape type */
119
+ type: ParticipantType;
120
+ /** Source line number (1-based) */
121
+ lineNumber: number;
122
+ /** Explicit layout position override (0-based from left, negative from right) */
123
+ position?: number;
124
+ /** Pipe-delimited tag metadata (e.g. `| role: Gateway`) */
125
+ metadata?: Record<string, string>;
126
+ }
106
127
  /**
107
128
  * A message between two participants.
108
129
  */
@@ -153,6 +174,18 @@ interface SequenceNote {
153
174
  endLineNumber: number;
154
175
  }
155
176
  type SequenceElement = SequenceMessage | SequenceBlock | SequenceSection | SequenceNote;
177
+ /**
178
+ * A named group of participants rendered as a labeled box.
179
+ */
180
+ interface SequenceGroup {
181
+ name: string;
182
+ participantIds: string[];
183
+ lineNumber: number;
184
+ /** Pipe-delimited tag metadata (e.g. `[Backend | t: Product]`) */
185
+ metadata?: Record<string, string>;
186
+ /** Whether this group is collapsed by default */
187
+ collapsed?: boolean;
188
+ }
156
189
 
157
190
  interface SectionMessageGroup {
158
191
  section: SequenceSection;
@@ -164,16 +197,71 @@ interface SectionMessageGroup {
164
197
  * Only top-level sections are collapsible — sections inside blocks are excluded.
165
198
  */
166
199
  declare function groupMessagesBySection(elements: SequenceElement[], messages: SequenceMessage[]): SectionMessageGroup[];
200
+ interface RenderStep {
201
+ type: 'call' | 'return';
202
+ from: string;
203
+ to: string;
204
+ label: string;
205
+ messageIndex: number;
206
+ async?: boolean;
207
+ }
208
+ /**
209
+ * Build an ordered render sequence from flat messages.
210
+ * Uses a call stack to infer where returns should be placed:
211
+ * returns appear after all nested sub-calls complete.
212
+ */
213
+ declare function buildRenderSequence(messages: SequenceMessage[]): RenderStep[];
214
+ interface Activation {
215
+ participantId: string;
216
+ startStep: number;
217
+ endStep: number;
218
+ depth: number;
219
+ }
220
+ /**
221
+ * Compute activation rectangles from render steps.
222
+ * Each call pushes onto the callee's stack; each return pops it.
223
+ */
224
+ declare function computeActivations(steps: RenderStep[]): Activation[];
225
+ /**
226
+ * Reorder participants based on explicit `position` overrides.
227
+ * Positive positions are 0-based from the left; negative positions count from the right (-1 = last).
228
+ * Unpositioned participants maintain their relative order, filling remaining slots.
229
+ */
230
+ declare function applyPositionOverrides(participants: SequenceParticipant[]): SequenceParticipant[];
231
+ /**
232
+ * Reorder participants so that members of the same group are adjacent.
233
+ * Groups are positioned at the point where their first member would naturally
234
+ * appear based on message order (first-occurrence positioning). This prevents
235
+ * groups declared at the top of the file from being placed before participants
236
+ * that appear in messages earlier.
237
+ *
238
+ * Explicit `position` overrides are handled separately by `applyPositionOverrides`.
239
+ */
240
+ declare function applyGroupOrdering(participants: SequenceParticipant[], groups: SequenceGroup[], messages?: SequenceMessage[]): SequenceParticipant[];
167
241
  /**
168
242
  * Build a mapping from each note's lineNumber to the lineNumber of its
169
243
  * associated message (the last message before the note in document order).
170
- * Used by the app to expand notes when cursor is on the associated message.
244
+ * Used by the app to highlight the associated message when cursor is on a note.
171
245
  */
172
246
  declare function buildNoteMessageMap(elements: SequenceElement[]): Map<number, number>;
247
+
248
+ interface ArcLink {
249
+ source: string;
250
+ target: string;
251
+ value: number;
252
+ color: string | null;
253
+ lineNumber: number;
254
+ }
255
+ type ArcOrder = 'appearance' | 'name' | 'group' | 'degree';
256
+ interface ArcNodeGroup {
257
+ name: string;
258
+ nodes: string[];
259
+ color: string | null;
260
+ lineNumber: number;
261
+ }
173
262
  /**
174
- * Collect all note line numbers from a sequence diagram's elements.
175
- * Used by the app to compute the "expand all" set.
263
+ * Orders arc diagram nodes based on the selected ordering strategy.
176
264
  */
177
- declare function collectNoteLineNumbers(elements: SequenceElement[]): number[];
265
+ declare function orderArcNodes(links: ArcLink[], order: ArcOrder, groups: ArcNodeGroup[]): string[];
178
266
 
179
- export { buildNoteMessageMap, collectNoteLineNumbers, computeCardArchive, computeCardMove, groupMessagesBySection, isArchiveColumn, parseDataRowValues };
267
+ export { applyGroupOrdering, applyPositionOverrides, buildNoteMessageMap, buildRenderSequence, computeActivations, computeCardArchive, computeCardMove, groupMessagesBySection, isArchiveColumn, orderArcNodes, parseDataRowValues };
package/dist/internal.js CHANGED
@@ -1,3 +1,8 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
5
+
1
6
  // src/utils/parsing.ts
2
7
  function normalizeNumericToken(token) {
3
8
  if (!token.includes(",") && !token.includes("_")) return null;
@@ -21,10 +26,15 @@ function normalizeNumericToken(token) {
21
26
  return sign + unsigned.replace(/_/g, "");
22
27
  return null;
23
28
  }
29
+ var init_parsing = __esm({
30
+ "src/utils/parsing.ts"() {
31
+ "use strict";
32
+ }
33
+ });
24
34
 
25
35
  // src/chart.ts
26
- function parseDataRowValues(line, options) {
27
- const segments = line.split(",");
36
+ function parseDataRowValues(line2, options) {
37
+ const segments = line2.split(",");
28
38
  const normalized = [];
29
39
  for (let i = 0; i < segments.length; i++) {
30
40
  const seg = segments[i].trim();
@@ -101,9 +111,14 @@ function parseDataRowValues(line, options) {
101
111
  if (!label) return null;
102
112
  return { label, values: [num] };
103
113
  }
114
+ var init_chart = __esm({
115
+ "src/chart.ts"() {
116
+ "use strict";
117
+ init_parsing();
118
+ }
119
+ });
104
120
 
105
121
  // src/kanban/mutations.ts
106
- var ARCHIVE_COLUMN_NAME = "archive";
107
122
  function computeCardMove(content, parsed, cardId, targetColumnId, targetIndex) {
108
123
  let sourceCard = null;
109
124
  let sourceColumn = null;
@@ -207,9 +222,13 @@ function computeCardArchive(content, parsed, cardId) {
207
222
  function isArchiveColumn(name) {
208
223
  return name.toLowerCase() === ARCHIVE_COLUMN_NAME;
209
224
  }
210
-
211
- // src/sequence/renderer.ts
212
- import * as d3Selection from "d3-selection";
225
+ var ARCHIVE_COLUMN_NAME;
226
+ var init_mutations = __esm({
227
+ "src/kanban/mutations.ts"() {
228
+ "use strict";
229
+ ARCHIVE_COLUMN_NAME = "archive";
230
+ }
231
+ });
213
232
 
214
233
  // src/sequence/parser.ts
215
234
  function isSequenceBlock(el) {
@@ -221,24 +240,14 @@ function isSequenceSection(el) {
221
240
  function isSequenceNote(el) {
222
241
  return "kind" in el && el.kind === "note";
223
242
  }
243
+ var init_parser = __esm({
244
+ "src/sequence/parser.ts"() {
245
+ "use strict";
246
+ }
247
+ });
224
248
 
225
249
  // src/sequence/renderer.ts
226
- var PARTICIPANT_GAP = 160;
227
- var PARTICIPANT_BOX_WIDTH = 120;
228
- var NOTE_MAX_W = 200;
229
- var NOTE_FOLD = 10;
230
- var NOTE_PAD_H = 8;
231
- var NOTE_GAP = 15;
232
- var NOTE_CHAR_W = 6;
233
- var NOTE_CHARS_PER_LINE = Math.floor(
234
- (NOTE_MAX_W - NOTE_PAD_H * 2 - NOTE_FOLD) / NOTE_CHAR_W
235
- );
236
- var ACTIVATION_WIDTH = 10;
237
- var NOTE_LANE_MAX = PARTICIPANT_GAP - ACTIVATION_WIDTH - NOTE_GAP;
238
- var LABEL_CHAR_WIDTH = 7.5;
239
- var LABEL_MAX_CHARS = Math.floor(
240
- (PARTICIPANT_BOX_WIDTH - 10) / LABEL_CHAR_WIDTH
241
- );
250
+ import * as d3Selection from "d3-selection";
242
251
  function groupMessagesBySection(elements, messages) {
243
252
  const groups = [];
244
253
  let currentGroup = null;
@@ -279,6 +288,180 @@ function groupMessagesBySection(elements, messages) {
279
288
  }
280
289
  return groups;
281
290
  }
291
+ function buildRenderSequence(messages) {
292
+ const steps = [];
293
+ const stack = [];
294
+ for (let mi = 0; mi < messages.length; mi++) {
295
+ const msg = messages[mi];
296
+ while (stack.length > 0) {
297
+ const top = stack[stack.length - 1];
298
+ if (top.to === msg.from) break;
299
+ stack.pop();
300
+ steps.push({
301
+ type: "return",
302
+ from: top.to,
303
+ to: top.from,
304
+ label: "",
305
+ messageIndex: top.messageIndex
306
+ });
307
+ }
308
+ steps.push({
309
+ type: "call",
310
+ from: msg.from,
311
+ to: msg.to,
312
+ label: msg.label,
313
+ messageIndex: mi,
314
+ ...msg.async ? { async: true } : {}
315
+ });
316
+ if (msg.async) {
317
+ continue;
318
+ }
319
+ if (msg.from === msg.to) {
320
+ steps.push({
321
+ type: "return",
322
+ from: msg.to,
323
+ to: msg.from,
324
+ label: "",
325
+ messageIndex: mi
326
+ });
327
+ } else {
328
+ stack.push({
329
+ from: msg.from,
330
+ to: msg.to,
331
+ messageIndex: mi
332
+ });
333
+ }
334
+ }
335
+ while (stack.length > 0) {
336
+ const top = stack.pop();
337
+ steps.push({
338
+ type: "return",
339
+ from: top.to,
340
+ to: top.from,
341
+ label: "",
342
+ messageIndex: top.messageIndex
343
+ });
344
+ }
345
+ return steps;
346
+ }
347
+ function computeActivations(steps) {
348
+ const activations = [];
349
+ const stacks = /* @__PURE__ */ new Map();
350
+ const getStack = (id) => {
351
+ if (!stacks.has(id)) stacks.set(id, []);
352
+ return stacks.get(id);
353
+ };
354
+ for (let i = 0; i < steps.length; i++) {
355
+ const step = steps[i];
356
+ if (step.type === "call") {
357
+ const s = getStack(step.to);
358
+ s.push(i);
359
+ } else {
360
+ const s = getStack(step.from);
361
+ if (s.length > 0) {
362
+ const startIdx = s.pop();
363
+ activations.push({
364
+ participantId: step.from,
365
+ startStep: startIdx,
366
+ endStep: i,
367
+ depth: s.length
368
+ });
369
+ }
370
+ }
371
+ }
372
+ return activations;
373
+ }
374
+ function applyPositionOverrides(participants) {
375
+ if (!participants.some((p) => p.position !== void 0)) return participants;
376
+ const total = participants.length;
377
+ const positioned = [];
378
+ const unpositioned = [];
379
+ for (const p of participants) {
380
+ if (p.position !== void 0) {
381
+ let idx = p.position < 0 ? total + p.position : p.position;
382
+ idx = Math.max(0, Math.min(total - 1, idx));
383
+ positioned.push({ participant: p, index: idx });
384
+ } else {
385
+ unpositioned.push(p);
386
+ }
387
+ }
388
+ positioned.sort((a, b) => a.index - b.index);
389
+ const result = new Array(total).fill(null);
390
+ const usedIndices = /* @__PURE__ */ new Set();
391
+ for (const { participant, index } of positioned) {
392
+ let idx = index;
393
+ if (usedIndices.has(idx)) {
394
+ for (let offset = 1; offset < total; offset++) {
395
+ if (idx + offset < total && !usedIndices.has(idx + offset)) {
396
+ idx = idx + offset;
397
+ break;
398
+ }
399
+ if (idx - offset >= 0 && !usedIndices.has(idx - offset)) {
400
+ idx = idx - offset;
401
+ break;
402
+ }
403
+ }
404
+ }
405
+ result[idx] = participant;
406
+ usedIndices.add(idx);
407
+ }
408
+ let uIdx = 0;
409
+ for (let i = 0; i < total; i++) {
410
+ if (result[i] === null) {
411
+ result[i] = unpositioned[uIdx++];
412
+ }
413
+ }
414
+ return result;
415
+ }
416
+ function applyGroupOrdering(participants, groups, messages = []) {
417
+ if (groups.length === 0) return participants;
418
+ const idToGroup = /* @__PURE__ */ new Map();
419
+ for (const group of groups) {
420
+ for (const id of group.participantIds) {
421
+ idToGroup.set(id, group);
422
+ }
423
+ }
424
+ const appearanceOrder = [];
425
+ const seen = /* @__PURE__ */ new Set();
426
+ for (const msg of messages) {
427
+ for (const id of [msg.from, msg.to]) {
428
+ if (!seen.has(id)) {
429
+ seen.add(id);
430
+ appearanceOrder.push(id);
431
+ }
432
+ }
433
+ }
434
+ for (const p of participants) {
435
+ if (!seen.has(p.id)) {
436
+ seen.add(p.id);
437
+ appearanceOrder.push(p.id);
438
+ }
439
+ }
440
+ const result = [];
441
+ const placed = /* @__PURE__ */ new Set();
442
+ const placedGroups = /* @__PURE__ */ new Set();
443
+ for (const id of appearanceOrder) {
444
+ if (placed.has(id)) continue;
445
+ const group = idToGroup.get(id);
446
+ if (group && !placedGroups.has(group)) {
447
+ placedGroups.add(group);
448
+ for (const gid of group.participantIds) {
449
+ const p = participants.find((pp) => pp.id === gid);
450
+ if (p && !placed.has(gid)) {
451
+ result.push(p);
452
+ placed.add(gid);
453
+ }
454
+ }
455
+ } else if (!group) {
456
+ const p = participants.find((pp) => pp.id === id);
457
+ if (p) {
458
+ result.push(p);
459
+ placed.add(id);
460
+ }
461
+ }
462
+ }
463
+ return result;
464
+ }
282
465
  function buildNoteMessageMap(elements) {
283
466
  const map = /* @__PURE__ */ new Map();
284
467
  let lastMessageLine = -1;
@@ -305,33 +488,146 @@ function buildNoteMessageMap(elements) {
305
488
  walk(elements);
306
489
  return map;
307
490
  }
308
- function collectNoteLineNumbers(elements) {
309
- const result = [];
310
- const walk = (els) => {
311
- for (const el of els) {
312
- if (isSequenceNote(el)) {
313
- result.push(el.lineNumber);
314
- } else if (isSequenceBlock(el)) {
315
- walk(el.children);
316
- if (el.elseIfBranches) {
317
- for (const branch of el.elseIfBranches) {
318
- walk(branch.children);
491
+ var PARTICIPANT_GAP, PARTICIPANT_BOX_WIDTH, NOTE_MAX_W, NOTE_FOLD, NOTE_PAD_H, NOTE_GAP, NOTE_CHAR_W, NOTE_CHARS_PER_LINE, ACTIVATION_WIDTH, NOTE_LANE_MAX, LABEL_CHAR_WIDTH, LABEL_MAX_CHARS;
492
+ var init_renderer = __esm({
493
+ "src/sequence/renderer.ts"() {
494
+ "use strict";
495
+ init_parser();
496
+ PARTICIPANT_GAP = 160;
497
+ PARTICIPANT_BOX_WIDTH = 120;
498
+ NOTE_MAX_W = 200;
499
+ NOTE_FOLD = 10;
500
+ NOTE_PAD_H = 8;
501
+ NOTE_GAP = 15;
502
+ NOTE_CHAR_W = 6;
503
+ NOTE_CHARS_PER_LINE = Math.floor(
504
+ (NOTE_MAX_W - NOTE_PAD_H * 2 - NOTE_FOLD) / NOTE_CHAR_W
505
+ );
506
+ ACTIVATION_WIDTH = 10;
507
+ NOTE_LANE_MAX = PARTICIPANT_GAP - ACTIVATION_WIDTH - NOTE_GAP;
508
+ LABEL_CHAR_WIDTH = 7.5;
509
+ LABEL_MAX_CHARS = Math.floor(
510
+ (PARTICIPANT_BOX_WIDTH - 10) / LABEL_CHAR_WIDTH
511
+ );
512
+ }
513
+ });
514
+
515
+ // src/d3.ts
516
+ import * as d3Scale from "d3-scale";
517
+ import * as d3Selection2 from "d3-selection";
518
+ import * as d3Shape from "d3-shape";
519
+ import * as d3Array from "d3-array";
520
+ import cloud from "d3-cloud";
521
+ function orderArcNodes(links, order, groups) {
522
+ const nodeSet = /* @__PURE__ */ new Set();
523
+ for (const link of links) {
524
+ nodeSet.add(link.source);
525
+ nodeSet.add(link.target);
526
+ }
527
+ const allNodes = Array.from(nodeSet);
528
+ if (order === "name") {
529
+ return allNodes.slice().sort((a, b) => a.localeCompare(b));
530
+ }
531
+ if (order === "degree") {
532
+ const degree = /* @__PURE__ */ new Map();
533
+ for (const node of allNodes) degree.set(node, 0);
534
+ for (const link of links) {
535
+ degree.set(link.source, degree.get(link.source) + link.value);
536
+ degree.set(link.target, degree.get(link.target) + link.value);
537
+ }
538
+ return allNodes.slice().sort((a, b) => {
539
+ const diff = degree.get(b) - degree.get(a);
540
+ return diff !== 0 ? diff : a.localeCompare(b);
541
+ });
542
+ }
543
+ if (order === "group") {
544
+ if (groups.length > 0) {
545
+ const ordered = [];
546
+ const placed = /* @__PURE__ */ new Set();
547
+ for (const group of groups) {
548
+ for (const node of group.nodes) {
549
+ if (!placed.has(node)) {
550
+ ordered.push(node);
551
+ placed.add(node);
319
552
  }
320
553
  }
321
- walk(el.elseChildren);
322
554
  }
555
+ for (const node of allNodes) {
556
+ if (!placed.has(node)) {
557
+ ordered.push(node);
558
+ placed.add(node);
559
+ }
560
+ }
561
+ return ordered;
323
562
  }
324
- };
325
- walk(elements);
326
- return result;
563
+ const adj = /* @__PURE__ */ new Map();
564
+ for (const node of allNodes) adj.set(node, /* @__PURE__ */ new Set());
565
+ for (const link of links) {
566
+ adj.get(link.source).add(link.target);
567
+ adj.get(link.target).add(link.source);
568
+ }
569
+ const degree = /* @__PURE__ */ new Map();
570
+ for (const node of allNodes) degree.set(node, 0);
571
+ for (const link of links) {
572
+ degree.set(link.source, degree.get(link.source) + link.value);
573
+ degree.set(link.target, degree.get(link.target) + link.value);
574
+ }
575
+ const visited = /* @__PURE__ */ new Set();
576
+ const components = [];
577
+ const remaining = new Set(allNodes);
578
+ while (remaining.size > 0) {
579
+ let root = "";
580
+ let maxDeg = -1;
581
+ for (const node of remaining) {
582
+ if (degree.get(node) > maxDeg) {
583
+ maxDeg = degree.get(node);
584
+ root = node;
585
+ }
586
+ }
587
+ const component = [];
588
+ const queue = [root];
589
+ visited.add(root);
590
+ remaining.delete(root);
591
+ while (queue.length > 0) {
592
+ const curr = queue.shift();
593
+ component.push(curr);
594
+ for (const neighbor of adj.get(curr)) {
595
+ if (!visited.has(neighbor)) {
596
+ visited.add(neighbor);
597
+ remaining.delete(neighbor);
598
+ queue.push(neighbor);
599
+ }
600
+ }
601
+ }
602
+ components.push(component);
603
+ }
604
+ components.sort((a, b) => b.length - a.length);
605
+ return components.flat();
606
+ }
607
+ return allNodes;
327
608
  }
609
+ var init_d3 = __esm({
610
+ "src/d3.ts"() {
611
+ "use strict";
612
+ }
613
+ });
614
+
615
+ // src/internal.ts
616
+ init_chart();
617
+ init_mutations();
618
+ init_renderer();
619
+ init_d3();
328
620
  export {
621
+ applyGroupOrdering,
622
+ applyPositionOverrides,
329
623
  buildNoteMessageMap,
330
- collectNoteLineNumbers,
624
+ buildRenderSequence,
625
+ computeActivations,
331
626
  computeCardArchive,
332
627
  computeCardMove,
333
628
  groupMessagesBySection,
334
629
  isArchiveColumn,
630
+ orderArcNodes,
335
631
  parseDataRowValues
336
632
  };
337
633
  //# sourceMappingURL=internal.js.map