@zenuml/core 3.46.0 → 3.46.2

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 (60) hide show
  1. package/.claude/skills/dia-scoring/SKILL.md +139 -0
  2. package/.claude/skills/dia-scoring/agents/openai.yaml +7 -0
  3. package/.claude/skills/dia-scoring/references/selectors-and-keys.md +253 -0
  4. package/.claude/skills/land-pr/SKILL.md +98 -0
  5. package/.claude/skills/ship-branch/SKILL.md +81 -0
  6. package/.claude/skills/submit-branch/SKILL.md +76 -0
  7. package/.claude/skills/validate-branch/SKILL.md +54 -0
  8. package/CLAUDE.md +1 -1
  9. package/bun.lock +25 -11
  10. package/cy/canonical-history.html +908 -0
  11. package/cy/compare-case.html +357 -0
  12. package/cy/compare-cases.js +824 -0
  13. package/cy/compare.html +35 -0
  14. package/cy/diff-algorithm.js +199 -0
  15. package/cy/element-report.html +705 -0
  16. package/cy/icons-test.html +29 -0
  17. package/cy/legacy-vs-html.html +291 -0
  18. package/cy/native-diff-ext/background.js +60 -0
  19. package/cy/native-diff-ext/bridge.js +26 -0
  20. package/cy/native-diff-ext/content.js +194 -0
  21. package/cy/parity-test.html +122 -0
  22. package/cy/return-in-nested-if.html +29 -0
  23. package/cy/svg-preview.html +56 -0
  24. package/cy/svg-test.html +21 -0
  25. package/cy/theme-default-test.html +28 -0
  26. package/dist/stats.html +1 -1
  27. package/dist/zenuml.esm.mjs +16352 -15223
  28. package/dist/zenuml.js +701 -575
  29. package/docs/ship-branch-skill-plan.md +134 -0
  30. package/docs/superpowers/plans/2026-03-23-svg-parity-features.md +283 -0
  31. package/index.html +568 -73
  32. package/package.json +15 -4
  33. package/scripts/analyze-compare-case/collect-data.mjs +991 -0
  34. package/scripts/analyze-compare-case/config.mjs +102 -0
  35. package/scripts/analyze-compare-case/geometry.mjs +101 -0
  36. package/scripts/analyze-compare-case/native-diff.mjs +224 -0
  37. package/scripts/analyze-compare-case/output.mjs +74 -0
  38. package/scripts/analyze-compare-case/panel-diff.mjs +114 -0
  39. package/scripts/analyze-compare-case/report.mjs +157 -0
  40. package/scripts/analyze-compare-case/residual-scopes.mjs +325 -0
  41. package/scripts/analyze-compare-case/scoring.mjs +816 -0
  42. package/scripts/analyze-compare-case.mjs +149 -0
  43. package/scripts/snapshot-dual.js +34 -34
  44. package/skills/dia-scoring/SKILL.md +129 -0
  45. package/skills/dia-scoring/agents/openai.yaml +7 -0
  46. package/skills/dia-scoring/references/selectors-and-keys.md +253 -0
  47. package/test-setup.ts +8 -0
  48. package/types/index.d.ts +56 -0
  49. package/vite.config.ts +4 -0
  50. package/dist/10029-icon-service-Function-Apps-ObflOLuF.js +0 -5
  51. package/dist/Res_AWS-Identity-Access-Management_IAM-Access-Analyzer_48-BPq60XMY.js +0 -11
  52. package/dist/Res_AWS-Lambda_Lambda-Function_48-Co38UB_2.js +0 -12
  53. package/dist/Res_Amazon-EC2_Instance_48-CRaqbNUl.js +0 -12
  54. package/dist/Res_Amazon-Simple-Notification-Service_Topic_48-q13mxUeM.js +0 -11
  55. package/dist/Res_Amazon-Simple-Queue-Service_Queue_48-D2-8gbFw.js +0 -11
  56. package/dist/Robustness_Diagram_Boundary-nYnmTPs8.js +0 -10
  57. package/dist/Robustness_Diagram_Control-DLNLoMxd.js +0 -11
  58. package/dist/Robustness_Diagram_Entity-Be3kcbIE.js +0 -11
  59. package/dist/actor-BMj_HFpo.js +0 -11
  60. package/dist/database-BKHQQWQK.js +0 -8
@@ -0,0 +1,824 @@
1
+ // Single source of truth for all comparison test cases.
2
+ // Used by both compare.html (homepage) and compare-case.html (diff viewer).
3
+
4
+ export const CASES = {
5
+ // --- Basics ---
6
+ "empty": ``,
7
+ "single-participant": `A`,
8
+ "sync-call": `A.m`,
9
+ "simple-messages": `A -> B: hello
10
+ B -> C: process
11
+ C -> B: result
12
+ B -> A: done`,
13
+ "named-params": `A.method(userId=123, name="John")
14
+ B.create(type="User", active=true)`,
15
+
16
+ // --- Sync calls & self-calls ---
17
+ "nested-sync": `A.method() {
18
+ B.method
19
+ }`,
20
+ "self-sync": `selfSync() {
21
+ A.method {
22
+ B.method
23
+ }
24
+ }`,
25
+ "demo5-self-named": `A.methodA() { A.methodA1() }`,
26
+ "nested-occurrence": `title Order Service
27
+ A.method1{
28
+ B.method2 {
29
+ A->B.method3
30
+ }
31
+ }`,
32
+ "interaction": `if(x) {
33
+ A.method() {
34
+ B.method() {
35
+ BSelfMethod00000000000
36
+ A.method()
37
+ }
38
+ ASelf {
39
+ B->A.method
40
+ }
41
+ }
42
+ }`,
43
+ "nested-fragment": `title Nested Interaction
44
+ A.Read() {
45
+ B.Submit() {
46
+ Process() {
47
+ if (true) {
48
+ ProcessCallback() {
49
+ A.method
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }`,
55
+ "nested-outbound": `title Nested Interaction with Outbound
56
+ A.Read() {
57
+ B.Submit() {
58
+ C->B.method {
59
+ if (true) {
60
+ ProcessCallback() {
61
+ A.method
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }`,
67
+ "if-then-continue": `A.m {
68
+ if(x) {
69
+ B.m
70
+ }
71
+ C.m
72
+ }`,
73
+ "participant-width": `LongParticipantName.method`,
74
+
75
+ // --- Async messages ---
76
+ "async-1": `A->A: selfA
77
+ A->B: aToB
78
+ A->C: aToC
79
+ B->B: selfB
80
+ B->C: bToC
81
+ B->A: bToA
82
+ C->C: selfC
83
+ C->B: cToB
84
+ C->A: cToA`,
85
+ "async-2a": `A.method {
86
+ A->A: selfPing
87
+ A->B: send
88
+ A->C: broadcast
89
+ B->B: selfCheck
90
+ B->C: forward
91
+ B->A: reply
92
+ C->C: selfLog
93
+ C->B: respond
94
+ C->A: callback
95
+ }`,
96
+ "async-2b": `A.method {
97
+ A->B: init
98
+ B.method {
99
+ A->B: request
100
+ B->C: delegate
101
+ C->A: complete
102
+ }
103
+ }`,
104
+ "async-3": `A B C
105
+ C.method {
106
+ A->C: notify
107
+ C->A: respond
108
+ C->B: forward
109
+ B->C: ack
110
+ }`,
111
+ "async-self": `A->A: selfAsync`,
112
+ "async-self-nested": `A.method {
113
+ A->A: async
114
+ }`,
115
+ "demo6-async-styled": `A->A:: Hello
116
+ A->B:: Hello B
117
+ B->A: So what`,
118
+
119
+ // --- Fragments ---
120
+ "repro-alt-simple": `if(cond) {
121
+ A -> B: inIf
122
+ } else {
123
+ A -> B: inElse
124
+ }`,
125
+ "repro-alt-branches": `if(cond) {
126
+ A -> B: msg1
127
+ } else if(cond2) {
128
+ A -> B: elseIfMsg
129
+ } else {
130
+ A -> B: elseMsg
131
+ }`,
132
+ "repro-alt-tcf-only": `if(cond) {
133
+ A -> B: msg1
134
+ try {
135
+ B -> C: tryMsg
136
+ } catch(e) {
137
+ C -> B: catchMsg
138
+ } finally {
139
+ B -> A: finallyMsg
140
+ }
141
+ }`,
142
+ "repro-alt-nested-tcf": `if(cond) {
143
+ A -> B: msg1
144
+ try {
145
+ B -> C: tryMsg
146
+ } catch(e) {
147
+ C -> B: catchMsg
148
+ } finally {
149
+ B -> A: finallyMsg
150
+ }
151
+ } else if(cond2) {
152
+ A -> B: elseIfMsg
153
+ } else {
154
+ A -> B: elseMsg
155
+ }`,
156
+ "if-fragment": `title Issue 232
157
+ Client -> Server:SendRequest
158
+ if(true){
159
+ Server -> Server: processRequest
160
+ }`,
161
+ "fragment-loop": `A -> B: request
162
+ loop(condition) {
163
+ B -> C: process
164
+ }`,
165
+ "fragment-tcf": `A.method {
166
+ try {
167
+ B.process
168
+ } catch(error) {
169
+ C.handle
170
+ } finally {
171
+ D.cleanup
172
+ }
173
+ }`,
174
+ "fragment": `A
175
+ B
176
+ C
177
+ if(x) {
178
+ loop(y) {
179
+ try {
180
+ par {
181
+ A.m();
182
+ B.m();
183
+ }
184
+ } catch(e) {
185
+ opt {
186
+ new C
187
+ }
188
+ } finally {
189
+ C.m
190
+ }
191
+ }
192
+ }`,
193
+ "fragments-return": `A.method {
194
+ if(x) {
195
+ return x
196
+ } else {
197
+ return y
198
+ }
199
+ try {
200
+ return 1
201
+ } catch {
202
+ return 2
203
+ } finally {
204
+ return 3
205
+ }
206
+ }`,
207
+ "fragment-issue": `// This sample is carefully crafted. It shows a known issues: fragment stretched to
208
+ // svc (should not), because parser thinks the return statement returns to svc.
209
+ group Backend {@VPC svc @RDS rep}
210
+ group { Client }
211
+ Client->SGW."Get order by id" {
212
+ svc.Get(id) {
213
+ rep."load order" {
214
+ if(order == null) {
215
+ @return
216
+ SGW->Client:401
217
+ }
218
+ }
219
+ }
220
+ }`,
221
+ "nested-fragment-indent": `A.m {
222
+ try {
223
+ loop(x) {
224
+ B.m
225
+ }
226
+ } catch(e) {
227
+ B.m
228
+ }
229
+ }`,
230
+
231
+ // --- Creation ---
232
+ "creation": `title Title 1
233
+ A.m {
234
+ new B(1,2,3,4)
235
+ }`,
236
+ "creation-return": `A.method() {
237
+ b = new B()
238
+ }`,
239
+ "creation-rtl": `"b:B"
240
+ a1 = A.method() {
241
+ // abcde
242
+ b = new B()
243
+ }`,
244
+ "creation-long-name": `new AHasAVeryLongNameLongNameLongNameLongName()`,
245
+ "comment-creation": `A.method() {
246
+ // abcde
247
+ new B()
248
+ }`,
249
+ "defect-406": `title Title 1
250
+ A.m1 {
251
+ new B(1,2,3,4) {
252
+ if(x) {
253
+ C.m2
254
+ }
255
+ while(y) {
256
+ D.m3
257
+ }
258
+ par {
259
+ E.m4
260
+ F.m5
261
+ }
262
+ opt {
263
+ G.m6
264
+ }
265
+ }
266
+ }`,
267
+
268
+ // --- Return ---
269
+ "return": `A B C D
270
+ A->B.method() {
271
+ ret0_assign_rtl =C.method_long_to_give_space {
272
+ @return C->D: ret1_annotation_ltr
273
+ ret5_assign_ltr = B.method
274
+ B.method2 {
275
+ return ret2_return_ltr
276
+ }
277
+ }
278
+ return ret2_return_rtl
279
+ @return B->A: ret4_annotation_rtl
280
+ }`,
281
+ // Minimal return isolation cases
282
+ "return-single-explicit": `A B
283
+ A->B.method() {
284
+ return ret1
285
+ }`,
286
+ "return-two-explicit": `A B
287
+ A->B.method() {
288
+ B.inner
289
+ return ret1
290
+ @return B->A: ret2
291
+ }`,
292
+ "return-nested-then-direct": `A B C
293
+ A->B.method() {
294
+ B->C.nested() {
295
+ return nested_ret
296
+ }
297
+ return direct_ret
298
+ }`,
299
+ "return-only-two": `A B
300
+ A->B.method() {
301
+ return ret1
302
+ @return B->A: ret2
303
+ }`,
304
+ "return-assign-rtl": `A B C
305
+ A->B.method() {
306
+ ret0 = C.inner {
307
+ B.work
308
+ }
309
+ }`,
310
+ "return-assign-ltr": `A B C
311
+ A->B.method() {
312
+ ret0 = B.inner
313
+ }`,
314
+ "return-keyword-ltr": `A B C
315
+ A->B.method() {
316
+ B->C.work {
317
+ return ret1
318
+ }
319
+ }`,
320
+ "repro-return-after-creation": `new B() {
321
+ return from_creation
322
+ }
323
+ return "back to caller"`,
324
+
325
+ // --- Vertical layout (comments & creation) ---
326
+ "vertical-1": `// red
327
+ // green
328
+ a = A.m111
329
+ new E`,
330
+ "vertical-2": `// [red]
331
+ new B`,
332
+ "vertical-3": `if(x) {
333
+ // comment
334
+ new A
335
+ } else {
336
+ new B
337
+ }
338
+ new C
339
+ try {
340
+ new D
341
+ } catch {
342
+ par {
343
+ new E
344
+ new F
345
+ }
346
+ }`,
347
+ "vertical-4": `if(x) {
348
+ // comment
349
+ new A
350
+ } else {
351
+ new B
352
+ }
353
+ new C
354
+ try {
355
+ new D
356
+ } catch {
357
+ par {
358
+ new E
359
+ new F
360
+ if(x) {
361
+ new X
362
+ } else {
363
+ new Y
364
+ }
365
+ }
366
+ }`,
367
+ "vertical-5": `par {
368
+ new F
369
+ if(x) {
370
+ new X
371
+ } else {
372
+ try {
373
+ new Y
374
+ } catch {
375
+ par {
376
+ new G
377
+ if(x) {
378
+ new H
379
+ } else {
380
+ new I
381
+ }
382
+ }
383
+ }
384
+ }
385
+ }`,
386
+ "vertical-6": `new a
387
+ if(x) {
388
+ \tnew b
389
+ } else {
390
+ \tnew c
391
+ \tnew e
392
+ }
393
+ new D`,
394
+ "vertical-7": `A.method
395
+ section(){
396
+ new B
397
+ }`,
398
+ "vertical-8": `new Creation() {
399
+ return from_creation
400
+ }
401
+ return "back to caller"
402
+ try {
403
+ new AHasAVeryLongNameLongNameLongNameLongName() {
404
+ new CreatWithinCreat()
405
+ }
406
+ }`,
407
+ "vertical-9": `A0->A0: self
408
+ new A`,
409
+ "vertical-10": `new E
410
+ E.messageA()
411
+ new A {
412
+ if (x) {
413
+ new D
414
+ }
415
+ new B {
416
+ new C
417
+ }
418
+ }`,
419
+ "vertical-11": `A.call {
420
+ // pre creation
421
+ A->B: prep
422
+ a = new A()
423
+ a->B: post
424
+ }`,
425
+
426
+ // --- Complex demos ---
427
+ "smoke": `title ABCD Title
428
+ // Generating Sequence Diagrams from Java code is experimental.
429
+ // Please report errors to https://github.com/ZenUml/jetbrains-zenuml/discussions
430
+ MarkdownJavaFxHtmlPanel
431
+ MarkdownJavaFxHtmlPanel.readFromInputStream(inputStream) {
432
+ StringBuilder resultStringBuilder = new StringBuilder();
433
+ try {
434
+ // String line;
435
+ while((line = br.readLine()) != null) {
436
+ resultStringBuilder.append(line);
437
+ }
438
+ }
439
+ catch(IOException) {
440
+ return "";
441
+ }
442
+ return "resultStringBuilder.toString()";
443
+ }`,
444
+ "demo1-smoke": `// comments at the beginning should be ignored
445
+ title This is a title
446
+ @Lambda <<stereotype>> ParticipantName
447
+ group "B C" {@EC2 B @ECS C}
448
+ "bg color" #FF0000
449
+ @Starter("OptionalStarter")
450
+ new B
451
+ ReturnType ret = ParticipantName.methodA(a, b) {
452
+ critical("This is a critical message") {
453
+ ReturnType ret2 = selfCall() {
454
+ B.syncCallWithinSelfCall() {
455
+ ParticipantName.rightToLeftCall()
456
+ return B
457
+ }
458
+ "space in name"->"bg color".syncMethod(from, to)
459
+ }
460
+ }
461
+ // A comment for alt
462
+ if (condition) {
463
+ // A comment for creation
464
+ ret = new CreatAndAssign()
465
+ "ret:CreatAndAssign".method(create, and, assign)
466
+ // A comment for async self
467
+ B->B: Self Async
468
+ // A comment for async message
469
+ B->C: Async Message within fragment
470
+ new Creation() {
471
+ return from_creation
472
+ }
473
+ return "back to caller"
474
+ try {
475
+ new AHasAVeryLongNameLongNameLongNameLongName() {
476
+ new CreatWithinCreat()
477
+ C.rightToLeftFromCreation() {
478
+ B.FurtherRightToLeftFromCreation()
479
+ }
480
+ }
481
+ } catch (Exception) {
482
+ self {
483
+ return C
484
+ }
485
+ } finally {
486
+ C: async call from implied source
487
+ }
488
+ =====divider can be anywhere=====
489
+ } else if ("another condition") {
490
+ par {
491
+ B.method
492
+ C.method
493
+ }
494
+ } else {
495
+ // A comment for loop
496
+ forEach(Z) {
497
+ Z.method() {
498
+ return Z
499
+ }
500
+ }
501
+ }
502
+ }`,
503
+ "demo3-nested-fragments": `ret = A.methodA() {
504
+ if (x) {
505
+ B.methodB()
506
+ if (y) {
507
+ C.methodC()
508
+ }
509
+ }
510
+ while (x) {
511
+ B.methodB()
512
+ while (y) {
513
+ C.methodC()
514
+ }
515
+ }
516
+ if (x) {
517
+ method()
518
+ if (y) {
519
+ method2()
520
+ }
521
+ }
522
+ while (x) {
523
+ method()
524
+ while (y) {
525
+ method2()
526
+ }
527
+ }
528
+ while (x) {
529
+ method()
530
+ if (y) {
531
+ method2()
532
+ }
533
+ }
534
+ if (x) {
535
+ method()
536
+ while (y) {
537
+ method2()
538
+ }
539
+ }
540
+ }`,
541
+ "demo4-fragment-span": `ret = A.methodA() {
542
+ B.method() {
543
+ if (X) {
544
+ C.methodC() {
545
+ a = A.methodA() {
546
+ D.method()
547
+ }
548
+ }
549
+ }
550
+ while (Y) {
551
+ C.methodC() {
552
+ A.methodA()
553
+ }
554
+ }
555
+ }
556
+ }`,
557
+
558
+ // --- Repro cases ---
559
+ "repro-participant-y": `A -> B: hello`,
560
+ "repro-occ-basics": `A.method()`,
561
+ "repro-occ-height": `A.B {
562
+ B.C {
563
+ C.D
564
+ }
565
+ B.E
566
+ }`,
567
+ "repro-creation-width": `A.m {
568
+ b = new LongParticipantName()
569
+ }`,
570
+ "repro-comment": `A.method {
571
+ try {
572
+ // String line;
573
+ B.process
574
+ } catch(e) {
575
+ C.handle
576
+ }
577
+ }`,
578
+ "repro-msg-y": `A -> B: msg`,
579
+ "repro-occ-depth2": `A.method() {
580
+ selfCall() {
581
+ B.call() {
582
+ A.rtl()
583
+ }
584
+ }
585
+ }`,
586
+ "repro-comment-async-self": `A.method() {
587
+ // A comment
588
+ A->A: Self Async
589
+ }`,
590
+ "repro-debt-drift": `A.method() {
591
+ selfCall() {
592
+ B.call() {
593
+ A.rtl()
594
+ return B
595
+ }
596
+ }
597
+ B.syncMethod(from,to)
598
+ }`,
599
+ "repro-fragment-section-debt": `A.method() {
600
+ if(x) {
601
+ B.call() {
602
+ return result
603
+ }
604
+ } else {
605
+ B.afterSection()
606
+ }
607
+ }`,
608
+ "repro-creation-in-try": `A.method() {
609
+ try {
610
+ b = new B() {
611
+ B.inner()
612
+ }
613
+ A.afterCreation()
614
+ } catch(Exception) {
615
+ A.inCatch()
616
+ } finally {
617
+ A.inFinally()
618
+ }
619
+ }`,
620
+
621
+ // --- Occurrence bar length ---
622
+ "occ-bar-length": `A->B.method {
623
+ B->C.inner {
624
+ @return C->B: ret1
625
+ B->C.call2 {
626
+ return ret2
627
+ }
628
+ }
629
+ return ret3
630
+ }`,
631
+
632
+ // --- Return Y after inner block ---
633
+ "return-after-block": `A->B.method {
634
+ B->C.inner {
635
+ @return C->B: ret_inside
636
+ C->B.call2
637
+ B->C.call3 {
638
+ return ret_nested
639
+ }
640
+ }
641
+ return ret_after
642
+ @return B->A: ret_annot
643
+ }`,
644
+
645
+ // --- Assignment return: block with inner return ---
646
+ "repro-assign-return": `A->B.method {
647
+ ret0 = B->C.inner {
648
+ @return C->B: ret_inside
649
+ }
650
+ }`,
651
+ // --- Occurrence height: empty block (no children) ---
652
+ "repro-occ-empty": `A->B.method {
653
+ B->C.inner {
654
+ }
655
+ }`,
656
+ // --- Occurrence height: block with one sync message ---
657
+ "repro-occ-sync": `A->B.method {
658
+ B->C.inner {
659
+ C->B.call
660
+ }
661
+ }`,
662
+ // --- Occurrence height: block with one non-self return ---
663
+ "repro-occ-return": `A->B.method {
664
+ B->C.inner {
665
+ @return C->B: ret
666
+ }
667
+ }`,
668
+ // --- Occurrence height: block with sync + return ---
669
+ "repro-occ-mixed": `A->B.method {
670
+ B->C.inner {
671
+ C->B.call
672
+ @return C->B: ret
673
+ }
674
+ }`,
675
+ // --- Occurrence height: sync + `return` keyword ---
676
+ "repro-occ-mixed-keyword": `A->B.method {
677
+ B->C.inner {
678
+ C->B.call
679
+ return ret_kw
680
+ }
681
+ }`,
682
+ // --- Occurrence height: sync + two @returns ---
683
+ "repro-occ-mixed-2ret": `A->B.method {
684
+ B->C.inner {
685
+ C->B.call
686
+ @return C->B: ret1
687
+ @return C->B: ret2
688
+ }
689
+ }`,
690
+ // --- Occurrence height: two syncs + one @return between them ---
691
+ "repro-occ-mixed-mid": `A->B.method {
692
+ B->C.inner {
693
+ C->B.call1
694
+ @return C->B: ret
695
+ C->B.call2
696
+ }
697
+ }`,
698
+ // --- Creation with params ---
699
+ "repro-creation-params": `new B(1)`,
700
+ // --- Just participant B (no creation) ---
701
+ "repro-just-B": `B`,
702
+ // --- Starter + B with message ---
703
+ "repro-starter-B": `B.m`,
704
+ // --- Starter + B with long method name ---
705
+ "repro-starter-B-long": `B.aVeryLongMethodThatShouldPushTheParticipant`,
706
+ // --- Participant colors on supported icons ---
707
+ "repro-color-boundary": `@Actor Client #FFEBE6
708
+ @Boundary OrderController #0747A6
709
+ Client->OrderController: post`,
710
+ // --- Stereotype + color + EC2 icon header layout ---
711
+ "repro-ec2-stereotype-color": `@EC2 <<BFF>> OrderService #E3FCEF
712
+ OrderService.create(payload)`,
713
+ // --- Cloud service icons without group geometry ---
714
+ "repro-service-icons": `@Lambda PurchaseService
715
+ @AzureFunction InvoiceService
716
+ PurchaseService->InvoiceService: createInvoice(order)`,
717
+ // --- Group container without unsupported icon noise ---
718
+ "repro-group-container": `group BusinessService {
719
+ @Actor Client
720
+ @Boundary OrderController
721
+ }
722
+ Client->OrderController: post`,
723
+
724
+ // --- Order Service (comments + nested fragments) ---
725
+ "order-service": `title Order Service
726
+ @Actor Client #FFEBE6
727
+ @Boundary OrderController #0747A6
728
+ @EC2 <<BFF>> OrderService #E3FCEF
729
+ group BusinessService {
730
+ @Lambda PurchaseService
731
+ @AzureFunction InvoiceService
732
+ }
733
+ @Starter(Client)
734
+ // \`POST /orders\`
735
+ OrderController.post(payload) {
736
+ // comment to
737
+ OrderService.create(payload) {
738
+ // comment3
739
+ order = new Order(payload)
740
+ // comment 4
741
+ if(order != null) {
742
+ par {
743
+ PurchaseService.createPO(order)
744
+ InvoiceService.createInvoice(order)
745
+ }
746
+ }
747
+ }
748
+ }`,
749
+
750
+ // --- Repro: order-service issue groups ---
751
+
752
+ // Group 1: message label dy=-0.5 (backtick comment triggers it)
753
+ "repro-label-dy": `@Starter(Client)
754
+ // \`POST /orders\`
755
+ A.post(payload) {
756
+ B.create(payload) {
757
+ c = new C(payload)
758
+ }
759
+ }`,
760
+
761
+ // Group 2: creation-return arrow geometry (ambiguous return arrows)
762
+ "repro-creation-return-arrow": `A.method() {
763
+ b = new B(payload)
764
+ return b
765
+ }`,
766
+
767
+ // Group 3: comment positioning (comments above messages and fragments)
768
+ "repro-comment-pos": `// comment above message
769
+ A -> B: doWork
770
+ // comment above fragment
771
+ if(cond) {
772
+ B -> C: inner
773
+ }`,
774
+
775
+ // Group 4: fragment body geometry (nested alt+par with comments)
776
+ "repro-nested-fragment": `A.call() {
777
+ B.process() {
778
+ // comment before if
779
+ if(x) {
780
+ par {
781
+ C.task1()
782
+ D.task2()
783
+ }
784
+ }
785
+ }
786
+ }`,
787
+
788
+ // Group 5: icon + stereotype + color + group (with occurrences)
789
+ "repro-icon-stereo-group": `@EC2 <<BFF>> OrderService #E3FCEF
790
+ group BusinessService {
791
+ @Lambda PurchaseService
792
+ @AzureFunction InvoiceService
793
+ }
794
+ OrderService.handle() {
795
+ PurchaseService.create()
796
+ InvoiceService.invoice()
797
+ }`,
798
+
799
+ // Group 6: par fragment divider (missing in SVG)
800
+ "repro-par-divider": `A.call() {
801
+ par {
802
+ B.task1()
803
+ C.task2()
804
+ }
805
+ }`,
806
+
807
+ // --- Divider ---
808
+ "divider": `A -> B: request
809
+ ==Phase 2==
810
+ B -> C: forward
811
+ ==Done==`,
812
+
813
+ // --- Icons ---
814
+ "icons": `@Actor User
815
+ @Database DB
816
+ @sqs MQ
817
+ @sns Topic
818
+
819
+ User.login() {
820
+ DB.verify()
821
+ MQ.enqueue()
822
+ Topic.publish()
823
+ }`,
824
+ };