1 package e2etests
2
3 import (
4 _ "embed"
5 "testing"
6 )
7
8
9
10
11 var testMarkdown string
12
13 func testStable(t *testing.T) {
14 tcs := []testCase{
15 {
16 name: "legend_with_near_key",
17 script: `
18 direction: right
19
20 x -> y: {
21 style.stroke: green
22 }
23
24 y -> z: {
25 style.stroke: red
26 }
27
28 legend: {
29 near: bottom-center
30 color1: foo {
31 shape: text
32 style.font-color: green
33 }
34
35 color2: bar {
36 shape: text
37 style.font-color: red
38 }
39 }
40 `,
41 },
42 {
43 name: "near_keys_for_container",
44 script: `title: |md
45 # Service-Cluster Provisioning ("Outside view")
46 | {near: top-center}`,
47 },
48 {
49 name: "near_keys_for_container",
50 script: `
51 x: {
52 near: top-left
53 a -> b
54 c -> d
55 }
56 y: {
57 near: top-right
58 a -> b
59 c -> d
60 }
61 z: {
62 near: bottom-center
63 a -> b
64 c -> d
65 }
66
67 a: {
68 near: top-center
69 b: {
70 c
71 }
72 }
73 b: {
74 near: bottom-right
75 a: {
76 c: {
77 d
78 }
79 }
80 }
81 `,
82 },
83 {
84 name: "class_and_sqlTable_border_radius",
85 script: `
86 a: {
87 shape: sql_table
88 id: int {constraint: primary_key}
89 disk: int {constraint: foreign_key}
90
91 json: jsonb {constraint: unique}
92 last_updated: timestamp with time zone
93
94 style: {
95 fill: red
96 border-radius: 10
97 }
98 }
99
100 b: {
101 shape: class
102
103 field: "[]string"
104 method(a uint64): (x, y int)
105
106 style: {
107 border-radius: 10
108 }
109 }
110
111 c: {
112 shape: class
113 style: {
114 border-radius: 5
115 }
116 }
117
118 d: {
119 shape: sql_table
120 style: {
121 border-radius: 5
122 }
123 }
124 `,
125 },
126 {
127 name: "elk_border_radius",
128 script: `
129 a -> b
130 a -> c: {
131 style: {
132 border-radius: 0
133 }
134 }
135 a -> e: {
136 style: {
137 border-radius: 5
138 }
139 }
140 a -> f: {
141 style: {
142 border-radius: 10
143 }
144 }
145 a -> g: {
146 style: {
147 border-radius: 20
148 }
149 }
150 `,
151 },
152 {
153 name: "elk_container_height",
154 script: `i can not see the title: {
155 shape: cylinder
156 x
157 }
158 `,
159 },
160 {
161 name: "elk_shim",
162 script: `network: {
163 cell tower: {
164 satellites: {
165 shape: stored_data
166 style.multiple: true
167 width: 140
168 }
169
170 transmitter: {
171 width: 140
172 }
173
174 satellites -> transmitter: send {
175 }
176 satellites -> transmitter: send {
177 }
178 satellites -> transmitter: send {
179 }
180 }
181
182 # long label to expand
183 online portal: ONLINE PORTALLLL {
184 ui: { shape: hexagon }
185 }
186
187 data processor: {
188 storage: {
189 shape: cylinder
190 style.multiple: true
191 }
192 }
193
194 cell tower.transmitter -> data processor.storage: phone logs
195 }
196
197 user: {
198 shape: person
199 width: 130
200 }
201
202 user -> network.cell tower: make call
203 user -> network.online portal.ui: access {
204 style.stroke-dash: 3
205 }
206
207 api server -> network.online portal.ui: display
208 api server -> logs: persist
209 logs: { shape: page; style.multiple: true }
210
211 network.data processor -> api server
212 `,
213 },
214 {
215 name: "edge-label-overflow",
216 script: `student -> committee chair: Apply for appeal
217 student <- committee chair: Deny. Need more information
218 committee chair -> committee: Accept appeal`,
219 },
220 {
221 name: "mono-edge",
222 script: `direction: right
223 x -> y: hi { style.font: mono }`,
224 },
225 {
226 name: "bold-mono",
227 script: `not bold mono.style.font: mono
228 not bold mono.style.bold: false
229 bold mono.style.font: mono`,
230 },
231 {
232 name: "mono-font",
233 script: `satellites: SATELLITES {
234 shape: stored_data
235 style: {
236 font: mono
237 fill: white
238 stroke: black
239 multiple: true
240 }
241 }
242
243 transmitter: TRANSMITTER {
244 style: {
245 font: mono
246 fill: white
247 stroke: black
248 }
249 }
250
251 satellites -> transmitter: SEND {
252 style.stroke: black
253 style.font: mono
254 }
255 satellites -> transmitter: SEND {
256 style.stroke: black
257 style.font: mono
258 }
259 satellites -> transmitter: SEND {
260 style.stroke: black
261 style.font: mono
262 }
263 `,
264 },
265 {
266 name: "connected_container",
267 script: `a.b -> c.d -> f.h.g
268 `,
269 },
270 {
271 name: "circular_dependency",
272 script: `a -> b -> c -> b -> a
273 `,
274 },
275 {
276 name: "all_shapes",
277 script: `
278 rectangle: {shape: "rectangle"}
279 square: {shape: "square"}
280 page: {shape: "page"}
281 parallelogram: {shape: "parallelogram"}
282 document: {shape: "document"}
283 cylinder: {shape: "cylinder"}
284 queue: {shape: "queue"}
285 package: {shape: "package"}
286 step: {shape: "step"}
287 callout: {shape: "callout"}
288 stored_data: {shape: "stored_data"}
289 person: {shape: "person"}
290 diamond: {shape: "diamond"}
291 oval: {shape: "oval"}
292 circle: {shape: "circle"}
293 hexagon: {shape: "hexagon"}
294 cloud: {shape: "cloud"}
295
296 rectangle -> square -> page
297 parallelogram -> document -> cylinder
298 queue -> package -> step
299 callout -> stored_data -> person
300 diamond -> oval -> circle
301 hexagon -> cloud
302 `,
303 },
304 {
305 name: "all_shapes_multiple",
306 script: `
307 rectangle: {shape: "rectangle"}
308 square: {shape: "square"}
309 page: {shape: "page"}
310 parallelogram: {shape: "parallelogram"}
311 document: {shape: "document"}
312 cylinder: {shape: "cylinder"}
313 queue: {shape: "queue"}
314 package: {shape: "package"}
315 step: {shape: "step"}
316 callout: {shape: "callout"}
317 stored_data: {shape: "stored_data"}
318 person: {shape: "person"}
319 diamond: {shape: "diamond"}
320 oval: {shape: "oval"}
321 circle: {shape: "circle"}
322 hexagon: {shape: "hexagon"}
323 cloud: {shape: "cloud"}
324
325 rectangle -> square -> page
326 parallelogram -> document -> cylinder
327 queue -> package -> step
328 callout -> stored_data -> person
329 diamond -> oval -> circle
330 hexagon -> cloud
331
332 rectangle.style.multiple: true
333 square.style.multiple: true
334 page.style.multiple: true
335 parallelogram.style.multiple: true
336 document.style.multiple: true
337 cylinder.style.multiple: true
338 queue.style.multiple: true
339 package.style.multiple: true
340 step.style.multiple: true
341 callout.style.multiple: true
342 stored_data.style.multiple: true
343 person.style.multiple: true
344 diamond.style.multiple: true
345 oval.style.multiple: true
346 circle.style.multiple: true
347 hexagon.style.multiple: true
348 cloud.style.multiple: true
349 `,
350 },
351 {
352 name: "all_shapes_shadow",
353 script: `
354 rectangle: {shape: "rectangle"}
355 square: {shape: "square"}
356 page: {shape: "page"}
357 parallelogram: {shape: "parallelogram"}
358 document: {shape: "document"}
359 cylinder: {shape: "cylinder"}
360 queue: {shape: "queue"}
361 package: {shape: "package"}
362 step: {shape: "step"}
363 callout: {shape: "callout"}
364 stored_data: {shape: "stored_data"}
365 person: {shape: "person"}
366 diamond: {shape: "diamond"}
367 oval: {shape: "oval"}
368 circle: {shape: "circle"}
369 hexagon: {shape: "hexagon"}
370 cloud: {shape: "cloud"}
371
372 rectangle -> square -> page
373 parallelogram -> document -> cylinder
374 queue -> package -> step
375 callout -> stored_data -> person
376 diamond -> oval -> circle
377 hexagon -> cloud
378
379 rectangle.style.shadow: true
380 square.style.shadow: true
381 page.style.shadow: true
382 parallelogram.style.shadow: true
383 document.style.shadow: true
384 cylinder.style.shadow: true
385 queue.style.shadow: true
386 package.style.shadow: true
387 step.style.shadow: true
388 callout.style.shadow: true
389 stored_data.style.shadow: true
390 person.style.shadow: true
391 diamond.style.shadow: true
392 oval.style.shadow: true
393 circle.style.shadow: true
394 hexagon.style.shadow: true
395 cloud.style.shadow: true
396 `,
397 },
398 {
399 name: "square_3d",
400 script: `
401 rectangle: {shape: "rectangle"}
402 square: {shape: "square"}
403
404 rectangle -> square
405
406 rectangle.style.3d: true
407 square.style.3d: true
408 `,
409 },
410 {
411 name: "hexagon_3d",
412 script: `
413 hexagon: {shape: "hexagon"}
414 hexagon.style.3d: true
415 `,
416 },
417 {
418 name: "3d_fill_and_stroke",
419 script: `
420 hexagon: {
421 shape: hexagon
422 style.3d: true
423 style.fill: honeydew
424 }
425
426
427 rect: {
428 shape: rectangle
429 style.3d: true
430 style.fill: honeydew
431 }
432
433 square: {
434 shape: square
435 style.3d: true
436 style.fill: honeydew
437 }
438 hexagon -> square -> rect
439 `,
440 },
441 {
442 name: "container_edges",
443 script: `a -> g.b -> d.h.c
444 d -> g.e -> f -> g -> d.h
445 `,
446 },
447 {
448 name: "one_three_one_container",
449 script: `top2.start -> a
450 top2.start -> b
451 top2.start -> c
452 a -> bottom.end
453 b -> bottom.end
454 c -> bottom.end
455 `,
456 },
457 {
458 name: "straight_hierarchy_container",
459 script: `a
460 c
461 b
462
463 l1: {
464 b
465 a
466 c
467 }
468
469 b -> l1.b
470 a -> l1.a
471 c -> l1.c
472
473 l2c1: {
474 a
475 }
476 l1.a -> l2c1.a
477
478 l2c3: {
479 c
480 }
481 l1.c -> l2c3.c
482
483 l2c2: {
484 b
485 }
486 l1.b -> l2c2.b
487
488 l3c1: {
489 a
490 b
491 }
492 l2c1.a -> l3c1.a
493 l2c2.b -> l3c1.b
494
495 l3c2: {
496 c
497 }
498 l2c3.c -> l3c2.c
499
500 l4: {
501 c1: {
502 a
503 }
504 c2: {
505 b
506 }
507 c3: {
508 c
509 }
510 }
511 l3c1.a -> l4.c1.a
512 l3c1.b -> l4.c2.b
513 l3c2.c -> l4.c3.c`,
514 },
515 {
516 name: "different_subgraphs",
517 script: `a -> tree
518 a -> and
519 a -> nodes
520 and -> some
521 tree -> more
522 tree -> many
523
524 then -> here
525 here -> you
526 have -> hierarchy
527 then -> hierarchy
528
529 finally -> another
530 another -> of
531 nesting -> trees
532 finally -> trees
533 finally: {
534 a -> tree
535 inside -> a
536 tree -> hierarchy
537 a -> root
538 }`,
539 },
540 {
541 name: "binary_tree",
542 script: `a -> b
543 a -> c
544 b -> d
545 b -> e
546 c -> f
547 c -> g
548 d -> h
549 d -> i
550 e -> j
551 e -> k
552 f -> l
553 f -> m
554 g -> n
555 g -> o`,
556 },
557 {
558 name: "dense",
559 script: `
560 a-> b
561 c -> b
562 d-> e
563 f-> e
564 b-> f
565 b-> g
566 g-> f
567 b-> h
568 b-> i
569 b-> d
570 j-> c
571 j-> a
572 b-> j
573 i-> k
574 d-> l
575 l-> e
576 m-> l
577 m-> n
578 n-> i
579 d-> n
580 f-> n
581 b-> o
582 p-> l
583 e-> q`,
584 },
585 {
586 name: "multiple_trees",
587 script: `
588 a-> b
589 a-> c
590 a-> d
591 a-> e
592 a-> f
593 g-> a
594 a-> h
595 i-> b
596 j-> b
597 k-> g
598 l-> g
599 c-> m
600 c-> n
601 d-> o
602 d-> p
603 e-> q
604 e-> r
605 p-> s
606 f-> t
607 f-> u
608 v-> h
609 w-> h
610 `,
611 },
612 {
613 name: "one_container_loop",
614 script: `
615 a.b-> c
616 d-> c
617 e-> c
618 f-> d
619 a-> e
620 g-> f
621 a.h-> g
622 `,
623 },
624 {
625 name: "large_arch",
626 script: `
627 a
628 b
629 c
630 d
631 e
632 f
633 g
634 h
635 i
636 i.j
637 i.j.k
638 i.j.l
639 i.m
640 i.n
641 i.o
642 i.o.p
643 q
644 r
645 r.s
646 r.s.t
647 r.s.u.v
648 r.s.w
649 r.s.x
650 r.s.y
651 r.z
652 r.aa
653 r.bb
654 r.bb.cc
655 r.bb.dd
656 r.ee
657 r.ff
658 r.gg
659
660 i.j.k-> i.m
661 i.j.l-> i.o.p
662 q-> i.m
663 i.m-> q
664 i.n-> q
665 i.m-> c
666 i.m-> d
667 i.m-> g
668 i.m-> f
669 d-> e
670 r.s.x-> r.s.t
671 r.s.x-> r.s.w
672 r.gg-> r.s.t
673 r.s.u.v-> r.z
674 r.aa-> r.s.t
675 r.s.w-> i.m
676 r.s.t-> g
677 r.s.t-> h
678 r.ee -> r.ff
679 `,
680 },
681 {
682 name: "n22_e32",
683 script: `
684 a-> b
685 c-> a
686 d-> a
687 d-> b
688 d-> e
689 e-> f
690 f-> b
691 c-> f
692 g-> c
693 g-> h
694 h-> i
695 i-> j
696 j-> k
697 k-> e
698 j-> f
699 l-> m
700 n-> l
701 n-> l
702 n-> m
703 n-> o
704 o-> p
705 p-> m
706 n-> p
707 q-> n
708 q-> r
709 r-> s
710 s-> t
711 t-> u
712 u-> o
713 t-> p
714 c-> t
715 s-> a
716 u-> a
717 `,
718 },
719 {
720 name: "chaos1",
721 script: `
722 aaa: {
723 bbb.shape: callout
724 }
725 aaa.ccc -- aaa
726 (aaa.ccc -- aaa)[0]: '111'
727 ddd.shape: cylinder
728 eee.shape: document
729 eee <- aaa.ccc
730 (eee <- aaa.ccc)[0]: '222'
731 `,
732 dagreFeatureError: `Connection "(aaa.ccc -- aaa)[0]" goes from a container to a descendant, but layout engine "dagre" does not support this. See https://d2lang.com/tour/layouts/#layout-specific-functionality for more.`,
733 },
734 {
735 name: "chaos2",
736 script: `
737 aa: {
738 bb: {
739 cc: {
740 dd: {
741 shape: rectangle
742 ee: {shape: text}
743 ff
744 }
745 gg: {shape: text}
746 hh
747 dd.ee -- gg: '11'
748 gg -- hh: '22'
749 }
750 ii: {
751 shape: package
752 jj: {shape: diamond}
753 }
754 ii -> cc.dd
755 kk: {shape: circle}
756 }
757 ll
758 mm: {shape: cylinder}
759 ll <-> bb: '33'
760 mm -> bb.cc: '44'
761 mm->ll
762 mm <-> bb: '55'
763 ll <-> bb.cc.gg
764 mm <- bb.ii: '66'
765 bb.cc <- ll: '77'
766 nn: {shape: text}
767 oo
768 bb.ii <-> ll: '88'
769 }
770 `,
771 },
772 {
773 name: "us_map",
774 script: `
775 AL -- FL -- GA -- MS -- TN
776 AK
777 AZ -- CA -- NV -- NM -- UT
778 AR -- LA -- MS -- MO -- OK -- TN -- TX
779 CA -- NV -- OR
780 CO -- KS -- NE -- NM -- OK -- UT -- WY
781 CT -- MA -- NY -- RI
782 DE -- MD -- NJ -- PA
783 FL -- GA
784 GA -- NC -- SC -- TN
785 HI
786 ID -- MT -- NV -- OR -- UT -- WA -- WY
787 IL -- IN -- IA -- MI -- KY -- MO -- WI
788 IN -- KY -- MI -- OH
789 IA -- MN -- MO -- NE -- SD -- WI
790 KS -- MO -- NE -- OK
791 KY -- MO -- OH -- TN -- VA -- WV
792 LA -- MS -- TX
793 ME -- NH
794 MD -- PA -- VA -- WV
795 MA -- NH -- NY -- RI -- VT
796 MI -- MN -- OH -- WI
797 MN -- ND -- SD -- WI
798 MS -- TN
799 MO -- NE -- OK -- TN
800 MT -- ND -- SD -- WY
801 NE -- SD -- WY
802 NV -- OR -- UT
803 NH -- VT
804 NJ -- NY -- PA
805 NM -- OK -- TX
806 NY -- PA -- RI -- VT
807 NC -- SC -- TN -- VA
808 ND -- SD
809 OH -- PA -- WV
810 OK -- TX
811 OR -- WA
812 PA -- WV
813 SD -- WY
814 TN -- VA
815 UT -- WY
816 VA -- WV
817 `,
818 },
819 {
820 name: "investigate",
821 script: `
822 aa.shape: step
823 bb.shape: step
824 cc.shape: step
825 aa -- bb -- cc
826
827 aa -> dd.ee: 1
828 bb -> ff.gg: 2
829 cc -> dd.hh: 3
830
831 dd.ee.shape: diamond
832 dd.ee -> ii
833
834 ii -- jj -> kk
835
836 ll.mm.shape: circle
837 ff.mm.shape: circle
838 kk -> ff.mm: 4
839 ff.mm -> ll.mm: 5
840 ll.mm -> nn.oo: 6
841
842 ff.gg.shape: diamond
843 ff.gg -> ff.pp -> ll.qq -> ll.rr
844
845 dd.hh.shape: diamond
846 dd.hh -> ss.tt -> uu.vv
847
848 kk -> ww
849 uu.vv -> ww
850 ww -> rm
851
852 ww: {
853 shape: queue
854 icon: https://icons.terrastruct.com/essentials/time.svg
855 }
856
857 rm -> nn.xx
858 ll.rr -> yy.zz
859
860 rm -> yy.zz
861 yy.zz.shape: queue
862 yy.zz.icon: https://icons.terrastruct.com/essentials/time.svg
863
864 yy.zz -> yy.ab -> nn.ac -> ad
865
866 ad.style.fill: red
867 ad.shape: parallelogram
868
869 nn.shape: cylinder
870
871 ww -> ff.gg
872 `,
873 },
874 {
875 name: "multiline_text",
876 script: `hey: this\ngoes\nmultiple lines`,
877 },
878 {
879 name: "markdown",
880 script: `hey: |md
881 # Every frustum longs to be a cone
882
883 - A continuing flow of paper is sufficient to continue the flow of paper
884 - Please remain calm, it's no use both of us being hysterical at the same time
885 - Visits always give pleasure: if not on arrival, then on the departure
886
887 *Festivity Level 1*: Your guests are chatting amiably with each other.
888
889 test ~~strikethrough~~ test
890 |
891
892 x -> hey -> y
893 `,
894 },
895 {
896 name: "md_fontsize_10",
897 script: `hey: |md
898 # Every frustum longs to be a cone
899
900 - A continuing flow of paper is sufficient to continue the flow of paper
901 - Please remain calm, it's no use both of us being hysterical at the same time
902 - Visits always give pleasure: if not on arrival, then on the departure
903
904 *Festivity Level 1*: Your guests are chatting amiably with each other.
905
906 test ~~strikethrough~~ test
907 |
908
909 hey.style.font-size: 10
910
911 x -> hey -> y
912 `,
913 },
914 {
915 name: "font_sizes_containers_large",
916 script: `
917 ninety nine: {
918 style.font-size: 99
919 sixty four: {
920 style.font-size: 64
921 thirty two:{
922 style.font-size: 32
923 sixteen: {
924 style.font-size: 16
925 eight: {
926 style.font-size: 8
927 }
928 }
929 }
930 }
931 }
932 `,
933 },
934 {
935 name: "font_sizes_containers_large_right",
936 script: `
937 direction: right
938
939 ninety nine: {
940 style.font-size: 99
941 sixty four: {
942 style.font-size: 64
943 thirty two:{
944 style.font-size: 32
945 sixteen: {
946 style.font-size: 16
947 eight: {
948 style.font-size: 8
949 }
950 }
951 }
952 }
953 }
954 `,
955 },
956 {
957 name: "lone_h1",
958 script: mdTestScript(`
959 # Markdown: Syntax
960 `),
961 },
962
963 {
964 name: "p",
965 script: mdTestScript(`
966 A paragraph is simply one or more consecutive lines of text, separated
967 by one or more blank lines. (A blank line is any line that looks like a
968 blank line -- a line containing nothing but spaces or tabs is considered
969 blank.) Normal paragraphs should not be indented with spaces or tabs.
970 `),
971 },
972 {
973 name: "li1",
974 script: mdTestScript(`
975 - [Overview](#overview)
976 - [Philosophy](#philosophy)
977 - [Inline HTML](#html)
978 - [Automatic Escaping for Special Characters](#autoescape)
979 `),
980 },
981 {
982 name: "li2",
983 script: mdTestScript(`
984 - [Overview](#overview) ok _this is all measured_
985 - [Philosophy](#philosophy)
986 - [Inline HTML](#html)
987 `),
988 },
989 {
990 name: "li3",
991 script: mdTestScript(`
992 - [Overview](#overview)
993 - [Philosophy](#philosophy)
994 - [Inline HTML](#html)
995 - [Automatic Escaping for Special Characters](#autoescape)
996 - [Block Elements](#block)
997 - [Paragraphs and Line Breaks](#p)
998 - [Headers](#header)
999 - [Blockquotes](#blockquote)
1000 - [Lists](#list)
1001 - [Code Blocks](#precode)
1002 - [Horizontal Rules](#hr)
1003 - [Span Elements](#span)
1004 - [Links](#link)
1005 - [Emphasis](#em)
1006 - [Code](#code)
1007 - [Images](#img)
1008 - [Miscellaneous](#misc)
1009 - [Backslash Escapes](#backslash)
1010 - [Automatic Links](#autolink)
1011 `),
1012 },
1013 {
1014 name: "li4",
1015 script: mdTestScript(`
1016 List items may consist of multiple paragraphs. Each subsequent
1017 paragraph in a list item must be indented by either 4 spaces
1018 or one tab:
1019
1020 1. This is a list item with two paragraphs. Lorem ipsum dolor
1021 sit amet, consectetuer adipiscing elit. Aliquam hendrerit
1022 mi posuere lectus.
1023
1024 Vestibulum enim wisi, viverra nec, fringilla in, laoreet
1025 vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
1026 sit amet velit.
1027
1028 2. Suspendisse id sem consectetuer libero luctus adipiscing.
1029
1030 It looks nice if you indent every line of the subsequent
1031 paragraphs, but here again, Markdown will allow you to be
1032 lazy:
1033
1034 - This is a list item with two paragraphs.
1035
1036 This is the second paragraph in the list item. You're
1037
1038 only required to indent the first line. Lorem ipsum dolor
1039 sit amet, consectetuer adipiscing elit.
1040
1041 - Another item in the same list.
1042 `),
1043 },
1044 {
1045 name: "hr",
1046 script: mdTestScript(`
1047 **Note:** This document is itself written using Markdown; you
1048 can [see the source for it by adding '.text' to the URL](/projects/markdown/syntax.text).
1049
1050 ---
1051
1052 ## Overview
1053 `),
1054 },
1055 {
1056 name: "pre",
1057 script: mdTestScript(`
1058 Here is an example of AppleScript:
1059
1060 tell application "Foo"
1061 beep
1062 end tell
1063
1064 A code block continues until it reaches a line that is not indented
1065 (or the end of the article).
1066 `),
1067 },
1068 {
1069 name: "br",
1070 script: `copy: |md
1071 # Headline 1
1072 ## Headline 2
1073 Lorem ipsum dolor
1074 <br />
1075 ## Headline 3
1076 Lorem ipsum dolor
1077 <br />
1078 <br />
1079 ## Headline 3
1080 This just disappears
1081 <br />
1082 |
1083 `,
1084 },
1085 {
1086 name: "giant_markdown_test",
1087 script: mdTestScript(testMarkdown),
1088 },
1089 {
1090 name: "code_snippet",
1091 script: `hey: |go
1092 // RegisterHash registers a function that returns a new instance of the given
1093 // hash function. This is intended to be called from the init function in
1094 // packages that implement hash functions.
1095 func RegisterHash(h Hash, f func() hash.Hash) {
1096 if h >= maxHash {
1097 panic("crypto: RegisterHash of unknown hash function")
1098 }
1099 hashes[h] = f
1100 }
1101 |
1102 x -> hey -> y`,
1103 }, {
1104 name: "arrowhead_adjustment",
1105 script: `a <-> b: {
1106 style.stroke-width: 6
1107 style.stroke-dash: 4
1108 source-arrowhead: {
1109 shape: arrow
1110 }
1111 }
1112
1113 c -> b: {
1114 style.stroke-width: 7
1115 style.stroke: "#20222a"
1116 }
1117 c.style.stroke-width: 7
1118 c.style.stroke: "#b2350d"
1119 c.shape: document
1120 b.style.stroke-width: 8
1121 b.style.stroke: "#0db254"
1122 a.style.border-radius: 10
1123 a.style.stroke-width: 8
1124 a.style.stroke: "#2bc3d8"
1125 Oval: "" {
1126 shape: oval
1127 style.stroke-width: 6
1128 style.stroke: "#a1a4af"
1129 }
1130 a <-> Oval: {
1131 style.stroke-width: 6
1132 source-arrowhead: {
1133 shape: diamond
1134 }
1135 target-arrowhead: * {
1136 shape: diamond
1137 style.filled: true
1138 }
1139 }
1140 c -- a: {style.stroke-width: 7}
1141 Oval <-> c`,
1142 },
1143 {
1144 name: "md_code_inline",
1145 script: `md: |md
1146 ` + "`code`" + `
1147 |
1148 a -> md -> b
1149 `,
1150 },
1151 {
1152 name: "md_code_block_fenced",
1153 script: `md: |md
1154 ` + "```" + `
1155 {
1156 fenced: "block",
1157 of: "json",
1158 }
1159 ` + "```" + `
1160 |
1161 a -> md -> b
1162 `,
1163 },
1164 {
1165 name: "md_code_block_indented",
1166 script: `md: |md
1167 a line of text and an
1168
1169 {
1170 indented: "block",
1171 of: "json",
1172 }
1173
1174 |
1175 a -> md -> b
1176 `,
1177 },
1178 {
1179 name: "class",
1180 script: `manager: BatchManager {
1181 shape: class
1182 -num: int
1183 -timeout: int
1184 -pid
1185
1186 +getStatus(): Enum
1187 +getJobs(): "Job[]"
1188 +setTimeout(seconds int)
1189 }
1190 `,
1191 }, {
1192 name: "sql_tables",
1193 script: `
1194 direction: left
1195
1196 users: {
1197 shape: sql_table
1198 id: int { constraint: primary_key }
1199 name: string
1200 email: string
1201 password: string
1202 last_login: datetime
1203 }
1204
1205 products: {
1206 shape: sql_table
1207 id: int { constraint: primary_key }
1208 price: decimal
1209 sku: string
1210 name: string
1211 }
1212
1213 orders: {
1214 shape: sql_table
1215 id: int { constraint: primary_key }
1216 user_id: int { constraint: foreign_key }
1217 product_id: int { constraint: foreign_key }
1218 }
1219
1220 shipments: {
1221 shape: sql_table
1222 id: int { constraint: primary_key }
1223 order_id: int { constraint: foreign_key }
1224 tracking_number: string
1225 status: string
1226 }
1227
1228 orders.user_id -> users.id
1229 orders.product_id -> products.id
1230 shipments.order_id -> orders.id`,
1231 }, {
1232 name: "sql_table_row_connections",
1233 script: `
1234 direction: left
1235
1236 a: {
1237 shape: sql_table
1238 id: int { constraint: primary_key }
1239 }
1240
1241 b: {
1242 shape: sql_table
1243 id: int { constraint: primary_key }
1244 a_1: int { constraint: foreign_key }
1245 a_2: int { constraint: foreign_key }
1246 }
1247
1248 b.a_1 -> a.id
1249 b.a_2 -> a.id`,
1250 }, {
1251 name: "images",
1252 script: `a: {
1253 shape: image
1254 icon: https://icons.terrastruct.com/essentials/004-picture.svg
1255 }
1256
1257 b: {
1258 shape: image
1259 icon: https://icons.terrastruct.com/essentials/004-picture.svg
1260 }
1261 a -> b
1262 `,
1263 },
1264 {
1265 name: "icon-containers",
1266 script: `vpc: VPC 1 10.1.0.0./16 {
1267 icon: https://icons.terrastruct.com/aws%2F_Group%20Icons%2FVirtual-private-cloud-VPC_light-bg.svg
1268 style: {
1269 stroke: green
1270 font-color: green
1271 fill: white
1272 }
1273 az: Availability Zone A {
1274 style: {
1275 stroke: blue
1276 font-color: blue
1277 stroke-dash: 3
1278 fill: white
1279 }
1280 firewall: Firewall Subnet A {
1281 icon: https://icons.terrastruct.com/aws%2FNetworking%20&%20Content%20Delivery%2FAmazon-Route-53_Hosted-Zone_light-bg.svg
1282 style: {
1283 stroke: purple
1284 font-color: purple
1285 fill: "#e1d5e7"
1286 }
1287 ec2: EC2 Instance {
1288 icon: https://icons.terrastruct.com/aws%2FCompute%2F_Instance%2FAmazon-EC2_C4-Instance_light-bg.svg
1289 }
1290 }
1291 }
1292 }
1293 `,
1294 },
1295 {
1296 name: "arrowhead_labels",
1297 script: `
1298 a -> b: To err is human, to moo bovine {
1299 source-arrowhead: 1
1300 target-arrowhead: * {
1301 shape: diamond
1302 }
1303 }
1304 `,
1305 },
1306 {
1307 name: "stylish",
1308 script: `
1309 x: {
1310 style: {
1311 opacity: 0.6
1312 fill: orange
1313 stroke: "#53C0D8"
1314 stroke-width: 5
1315 shadow: true
1316 }
1317 }
1318
1319 y: {
1320 style: {
1321 stroke-dash: 5
1322 opacity: 0.6
1323 fill: red
1324 3d: true
1325 stroke: black
1326 }
1327 }
1328
1329 x -> y: in style {
1330 style: {
1331 stroke: green
1332 opacity: 0.5
1333 stroke-width: 2
1334 stroke-dash: 5
1335 fill: lavender
1336 }
1337 }
1338 `,
1339 },
1340 {
1341 name: "md_2space_newline",
1342 script: `
1343 markdown: {
1344 md: |md
1345 Lorem ipsum dolor sit amet, consectetur adipiscing elit, ` + `
1346 sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1347 |
1348 }
1349 `,
1350 },
1351 {
1352 name: "md_backslash_newline",
1353 script: `
1354 markdown: {
1355 md: |md
1356 Lorem ipsum dolor sit amet, consectetur adipiscing elit,\
1357 sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1358 |
1359 }
1360 `,
1361 },
1362 {
1363 name: "font_colors",
1364 script: `
1365 alpha: {
1366 style.font-color: '#4A6FF3'
1367 }
1368 beta: {
1369 style.font-color: red
1370 }
1371 alpha -> beta: gamma {
1372 style.font-color: green
1373 }
1374 c: |md
1375 colored
1376 | {
1377 style.font-color: blue
1378 }
1379 `,
1380 },
1381 {
1382 name: "latex",
1383 script: `a: |latex
1384 \\Huge{\\frac{\\alpha g^2}{\\omega^5} e^{[ -0.74\\bigl\\{\\frac{\\omega U_\\omega 19.5}{g}\\bigr\\}^{\\!-4}\\,]}}
1385 |
1386
1387 b: |latex
1388 e = mc^2
1389 |
1390
1391 z: |latex
1392 gibberish\\; math:\\sum_{i=0}^\\infty i^2
1393 |
1394
1395 z -> a
1396 z -> b
1397
1398 a -> c
1399 b -> c
1400 sugar -> c
1401 c: mixed together
1402
1403 c -> solution: we get
1404
1405 Linear program: {
1406 formula: |latex
1407 \\min_{ \\mathclap{\\substack{ x \\in \\mathbb{R}^n \\ x \\geq 0 \\ Ax \\leq b }}} c^T x
1408 |
1409 }
1410 `,
1411 },
1412 {
1413 name: "direction",
1414 script: `a -> b -> c -> d -> e
1415 b: {
1416 direction: right
1417 1 -> 2 -> 3 -> 4 -> 5
1418
1419 2: {
1420 direction: up
1421 a -> b -> c -> d -> e
1422 }
1423 }
1424 `,
1425 },
1426 {
1427 name: "transparent_3d",
1428 script: `
1429 cube: {
1430 style: {
1431 3d: true
1432 opacity: 0.5
1433 fill: orange
1434 stroke: "#53C0D8"
1435 stroke-width: 7
1436 }
1437 }
1438 `,
1439 },
1440 {
1441 name: "font_sizes",
1442 script: `
1443 size XS.style.font-size: 13
1444 size S.style.font-size: 14
1445 size M.style.font-size: 16
1446 size L.style.font-size: 20
1447 size XL.style.font-size: 24
1448 size XXL.style.font-size: 28
1449 size XXXL.style.font-size: 32
1450
1451 custom 8.style.font-size: 8
1452 custom 12.style.font-size: 12
1453 custom 18.style.font-size: 18
1454 custom 21.style.font-size: 21
1455 custom 64.style.font-size: 64
1456
1457 custom 8 -> size XS: custom 10 {
1458 style.font-size: 10
1459 }
1460 size S -> size M: custom 15 {
1461 style.font-size: 15
1462 }
1463 size XXXL -> custom 64: custom 48 {
1464 style.font-size: 48
1465 style.fill: lavender
1466 }
1467 `,
1468 }, {
1469 name: "sequence_diagram_simple",
1470 script: `shape: sequence_diagram
1471 alice: "Alice\nline\nbreaker" {
1472 shape: person
1473 style.stroke: red
1474 }
1475 bob: "Bob" {
1476 shape: person
1477 style.stroke-width: 5
1478 }
1479 db: {
1480 shape: cylinder
1481 }
1482 queue: {
1483 shape: queue
1484 }
1485 service: "an\nodd\nservice\nwith\na\nname\nin\nmultiple lines"
1486
1487 alice -> bob: "Authentication Request"
1488 bob -> service: "make request for something that is quite far away and requires a really long label to take all the space between the objects"
1489 service -> db: "validate credentials"
1490 db -> service: {
1491 style.stroke-dash: 4
1492 }
1493 service -> bob: {
1494 style.stroke-dash: 4
1495 }
1496 bob -> alice: "Authentication Response"
1497 alice -> bob: "Another authentication Request"
1498 bob -> queue: "do it later"
1499 queue -> bob: "stored" {
1500 style.stroke-dash: 3
1501 style.stroke-width: 5
1502 style.stroke: green
1503 }
1504
1505 bob -> alice: "Another authentication Response"`,
1506 }, {
1507 name: "sequence_diagram_span",
1508 script: `shape: sequence_diagram
1509
1510 scorer.t -> itemResponse.t: getItem()
1511 scorer.t <- itemResponse.t: item
1512
1513 scorer.t -> item.t1: getRubric()
1514 scorer.t <- item.t1: rubric
1515
1516 scorer.t -> essayRubric.t: applyTo(essayResp)
1517 itemResponse -> essayRubric.t.c
1518 essayRubric.t.c -> concept.t: match(essayResponse)
1519 scorer <- essayRubric.t: score
1520
1521 scorer.t -> itemOutcome.t1: new
1522 scorer.t -> item.t2: getNormalMinimum()
1523 scorer.t -> item.t3: getNormalMaximum()
1524
1525 scorer.t -> itemOutcome.t2: setScore(score)
1526 scorer.t -> itemOutcome.t3: setFeedback(missingConcepts)`,
1527 }, {
1528 name: "sequence_diagram_nested_span",
1529 script: `shape: sequence_diagram
1530
1531 scorer: {
1532 style.stroke: red
1533 style.stroke-width: 5
1534 }
1535
1536 scorer.abc: {
1537 style.fill: yellow
1538 style.stroke-width: 7
1539 }
1540
1541 scorer -> itemResponse.a: {
1542 style.stroke-width: 10
1543 }
1544 itemResponse.a -> item.a.b
1545 item.a.b -> essayRubric.a.b.c
1546 essayRubric.a.b.c -> concept.a.b.c.d
1547 item.a -> essayRubric.a.b
1548 concept.a.b.c.d -> itemOutcome.a.b.c.d.e
1549
1550 scorer.abc -> item.a
1551
1552 itemOutcome.a.b.c.d.e -> scorer
1553 scorer -> itemResponse.c`,
1554 }, {
1555 name: "sequence_diagrams",
1556 script: `a_shape.shape: circle
1557 a_sequence: {
1558 shape: sequence_diagram
1559
1560 scorer.t -> itemResponse.t: getItem()
1561 scorer.t <- itemResponse.t: item
1562
1563 scorer.t -> item.t1: getRubric()
1564 scorer.t <- item.t1: rubric
1565
1566 scorer.t -> essayRubric.t: applyTo(essayResp)
1567 itemResponse -> essayRubric.t.c
1568 essayRubric.t.c -> concept.t: match(essayResponse)
1569 scorer <- essayRubric.t: score
1570
1571 scorer.t <-> itemOutcome.t1: new
1572 scorer.t <-> item.t2: getNormalMinimum()
1573 scorer.t -> item.t3: getNormalMaximum()
1574
1575 scorer.t -- itemOutcome.t2: setScore(score)
1576 scorer.t -- itemOutcome.t3: setFeedback(missingConcepts)
1577 }
1578
1579 another: {
1580 sequence: {
1581 shape: sequence_diagram
1582
1583 # scoped edges
1584 scorer.t -> itemResponse.t: getItem()
1585 scorer.t <- itemResponse.t: item
1586
1587 scorer.t -> item.t1: getRubric()
1588 scorer.t <- item.t1: rubric
1589
1590 scorer.t -> essayRubric.t: applyTo(essayResp)
1591 itemResponse -> essayRubric.t.c
1592 essayRubric.t.c -> concept.t: match(essayResponse)
1593 scorer <- essayRubric.t: score
1594
1595 scorer.t -> itemOutcome.t1: new
1596 scorer.t <-> item.t2: getNormalMinimum()
1597 scorer.t -> item.t3: getNormalMaximum()
1598
1599 scorer.t -> itemOutcome.t2: setScore(score)
1600 scorer.t -> itemOutcome.t3: setFeedback(missingConcepts)
1601 }
1602 }
1603
1604 a_shape -> a_sequence
1605 a_shape -> another.sequence
1606 a_sequence -> sequence
1607 another.sequence <-> finally.sequence
1608 a_shape -- finally
1609
1610
1611 finally: {
1612 shape: queue
1613 sequence: {
1614 shape: sequence_diagram
1615 # items appear in this order
1616 scorer {
1617 style.stroke: red
1618 style.stroke-dash: 2
1619 }
1620 concept {
1621 style.stroke-width: 6
1622 }
1623 essayRubric
1624 item
1625 itemOutcome
1626 itemResponse
1627 }
1628 }
1629
1630 # full path edges
1631 finally.sequence.itemResponse.a -> finally.sequence.item.a.b
1632 finally.sequence.item.a.b -> finally.sequence.essayRubric.a.b.c
1633 finally.sequence.essayRubric.a.b.c -> finally.sequence.concept.a.b.c.d
1634 finally.sequence.item.a -> finally.sequence.essayRubric.a.b
1635 finally.sequence.concept.a.b.c.d -> finally.sequence.itemOutcome.a.b.c.d.e
1636 finally.sequence.scorer.abc -> finally.sequence.item.a
1637 finally.sequence.itemOutcome.a.b.c.d.e -> finally.sequence.scorer
1638 finally.sequence.scorer -> finally.sequence.itemResponse.c`,
1639 },
1640 {
1641 name: "number_connections",
1642 script: `1 -> 2
1643 foo baz: Foo Baz
1644
1645 foo baz -> hello
1646 `,
1647 }, {
1648 name: "sequence_diagram_all_shapes",
1649 script: `shape: sequence_diagram
1650
1651 a: "a label" {
1652 shape: callout
1653 }
1654 b: "b\nlabels" {
1655 shape: circle
1656 }
1657 c: "a class" {
1658 shape: class
1659 +public() bool
1660 -private() int
1661 }
1662 d: "cloudyyyy" {
1663 shape: cloud
1664 }
1665 e: |go
1666 a := 5
1667 b := a + 7
1668 fmt.Printf("%d", b)
1669 |
1670 f: "cyl" {
1671 shape: cylinder
1672 }
1673 g: "dia" {
1674 shape: diamond
1675 }
1676 h: "docs" {
1677 shape: document
1678 }
1679 i: "six corners" {
1680 shape: hexagon
1681 }
1682 j: "a random icon" {
1683 shape: image
1684 icon: https://icons.terrastruct.com/essentials/004-picture.svg
1685 }
1686 k: "over" {
1687 shape: oval
1688 }
1689 l: "pack" {
1690 shape: package
1691 }
1692 m: "docs page" {
1693 shape: page
1694 }
1695 n: "too\nhard\to say" {
1696 shape: parallelogram
1697 }
1698 o: "single\nperson" {
1699 shape: person
1700 }
1701 p: "a queue" {
1702 shape: queue
1703 }
1704 q: "a square" {
1705 shape: square
1706 }
1707 r: "a step at a time" {
1708 shape: step
1709 }
1710 s: "data" {
1711 shape: stored_data
1712 }
1713
1714 t: "users" {
1715 shape: sql_table
1716 id: int
1717 name: varchar
1718 }
1719
1720 a -> b: |go
1721 result := callThisFunction(obj, 5)
1722 |
1723 b <-> c: "mid" {
1724 source-arrowhead: "this side" {
1725 shape: diamond
1726 }
1727 target-arrowhead: "other side" {
1728 shape: triangle
1729 }
1730 }
1731 c -> d
1732 d -> e
1733 e -> f
1734 f -> g
1735 g -> h
1736 h -> i
1737 i -> j
1738 j -> k
1739 k -> l
1740 l -> m
1741 m -> n
1742 n -> o
1743 o -> p
1744 p -> q
1745 q -> r
1746 r -> s
1747 s -> t`,
1748 },
1749 {
1750 name: "self-referencing",
1751 script: `x -> x -> x -> y
1752 z -> y
1753 z -> z: hello
1754 `,
1755 }, {
1756 name: "sequence_diagram_self_edges",
1757 script: `shape: sequence_diagram
1758 a -> a: a self edge here
1759 a -> b: between actors
1760 b -> b.1: to descendant
1761 b.1 -> b.1.2: to deeper descendant
1762 b.1.2 -> b: to parent
1763 b -> a.1.2: actor
1764 a.1 -> b.3`,
1765 },
1766 {
1767 name: "icon-label",
1768 script: `ww: {
1769 label: hello
1770 icon: https://icons.terrastruct.com/essentials/time.svg
1771 }
1772 `,
1773 },
1774 {
1775 name: "sequence_diagram_note",
1776 script: `shape: sequence_diagram
1777 a; b; c; d
1778 a -> b
1779 a.explanation
1780 a.another explanation
1781 b -> c
1782 b."Some one who believes imaginary things\n appear right before your i's."
1783 c -> b: okay
1784 d."The earth is like a tiny grain of sand, only much, much heavier"
1785 `,
1786 },
1787 {
1788 name: "sequence_diagram_groups",
1789 script: `shape: sequence_diagram
1790 a;b;c;d
1791 a -> b
1792 ggg: {
1793 a -> b: lala
1794 }
1795 group 1: {
1796 b -> c
1797 c -> b: ey
1798 nested guy: {
1799 c -> b: okay
1800 }
1801 b.t1 -> c.t1
1802 b.t1.t2 -> c.t1
1803 c.t1 -> b.t1
1804 }
1805 group b: {
1806 b -> c
1807 c."what would arnold say"
1808 c -> b: okay
1809 }
1810 choo: {
1811 d."this note"
1812 }
1813 `,
1814 },
1815 {
1816 name: "sequence_diagram_nested_groups",
1817 script: `shape: sequence_diagram
1818
1819 a; b; c
1820
1821 this is a message group: {
1822 a -> b
1823 and this is a nested message group: {
1824 a -> b
1825 what about more nesting: {
1826 a -> b
1827 crazy town: {
1828 a."a note"
1829 a -> b
1830 whoa: {
1831 a -> b
1832 }
1833 }
1834 }
1835 }
1836 }
1837
1838 alt: {
1839 case 1: {
1840 b -> c
1841 }
1842 case 2: {
1843 b -> c
1844 }
1845 case 3: {
1846 b -> c
1847 }
1848 case 4: {
1849 b -> c
1850 }
1851 }
1852
1853 b.note: "a note here to remember that padding must consider notes too"
1854 a.note: "just\na\nlong\nnote\nhere"
1855 c: "just an actor"
1856 `,
1857 },
1858 {
1859 name: "sequence_diagram_real",
1860 script: `How this is rendered: {
1861 shape: sequence_diagram
1862
1863 CLI; d2ast; d2compiler; d2layout; d2exporter; d2themes; d2renderer; d2sequencelayout; d2dagrelayout
1864
1865 CLI -> d2ast: "'How this is rendered: {...}'"
1866 d2ast -> CLI: tokenized AST
1867 CLI -> d2compiler: compile AST
1868 d2compiler."measurements also take place"
1869 d2compiler -> CLI: objects and edges
1870 CLI -> d2layout.layout: run layout engines
1871 d2layout.layout -> d2sequencelayout: run engine on shape: sequence_diagram, temporarily remove
1872 only if root is not sequence: {
1873 d2layout.layout -> d2dagrelayout: run core engine on rest
1874 }
1875 d2layout.layout <- d2sequencelayout: add back in sequence diagrams
1876 d2layout -> CLI: diagram with correct positions and dimensions
1877 CLI -> d2exporter: export diagram with chosen theme and renderer
1878 d2exporter.export -> d2themes: get theme styles
1879 d2exporter.export -> d2renderer: render to SVG
1880 d2exporter.export -> CLI: resulting SVG
1881 }
1882 `,
1883 },
1884 {
1885 name: "sequence_diagram_actor_distance",
1886 script: `shape: sequence_diagram
1887 a: "an actor with a really long label that will break everything"
1888 c: "an\nactor\nwith\na\nreally\nlong\nlabel\nthat\nwill\nbreak\neverything"
1889 d: "simple"
1890 e: "a short one"
1891 b: "far away"
1892 f: "what if there were no labels between this actor and the previous one"
1893 a -> b: "short"
1894 a -> b: "long label for testing purposes and it must be really, really long"
1895 c -> d: "short"
1896 a -> d: "this should span many actors lifelines so we know how it will look like when redering a long label over many actors"
1897 d -> e: "long label for testing purposes and it must be really, really long"
1898 a -> f`,
1899 }, {
1900 name: "sequence_diagram_long_note",
1901 script: `shape: sequence_diagram
1902 a -> b
1903 b.note: "a note here to remember that padding must consider notes too"
1904 a.note: "just\na\nlong\nnote\nhere"`,
1905 },
1906 {
1907 name: "sequence_diagram_distance",
1908 script: `shape: sequence_diagram
1909 alice -> bob: what does it mean to be well-adjusted
1910 bob -> alice: The ability to play bridge or golf as if they were games
1911 `,
1912 },
1913 {
1914 name: "markdown_stroke_fill",
1915 script: `
1916 container.md: |md
1917 # a header
1918
1919 a line of text and an
1920
1921 {
1922 indented: "block",
1923 of: "json",
1924 }
1925
1926 walk into a bar.
1927 | {
1928 style.stroke: darkorange
1929 }
1930
1931 container -> no container
1932
1933 no container: |md
1934 they did it in style
1935 |
1936
1937 no container.style: {
1938 stroke: red
1939 fill: "#CEEDEE"
1940 }
1941 `,
1942 },
1943 {
1944 name: "overlapping_image_container_labels",
1945 script: `
1946 root: {
1947 shape: image
1948 icon: https://icons.terrastruct.com/essentials/004-picture.svg
1949 }
1950
1951 root -> container.root
1952
1953 container: {
1954 root: {
1955 shape: image
1956 icon: https://icons.terrastruct.com/essentials/004-picture.svg
1957 }
1958
1959 left2: {
1960 root: {
1961 shape: image
1962 icon: https://icons.terrastruct.com/essentials/004-picture.svg
1963 }
1964 inner: {
1965 left2: {
1966 shape: image
1967 icon: https://icons.terrastruct.com/essentials/004-picture.svg
1968 }
1969 right: {
1970 shape: image
1971 icon: https://icons.terrastruct.com/essentials/004-picture.svg
1972 }
1973 }
1974 root -> inner.left2: {
1975 label: to inner left2
1976 }
1977 root -> inner.right: {
1978 label: to inner right
1979 }
1980 }
1981
1982 right: {
1983 root: {
1984 shape: image
1985 icon: https://icons.terrastruct.com/essentials/004-picture.svg
1986 }
1987 inner: {
1988 left2: {
1989 shape: image
1990 icon: https://icons.terrastruct.com/essentials/004-picture.svg
1991 }
1992 right: {
1993 shape: image
1994 icon: https://icons.terrastruct.com/essentials/004-picture.svg
1995 }
1996 }
1997 root -> inner.left2: {
1998 label: to inner left2
1999 }
2000 root -> inner.right: {
2001 label: to inner right
2002 }
2003 }
2004
2005 root -> left2.root: {
2006 label: to left2 container root
2007 }
2008
2009 root -> right.root: {
2010 label: to right container root
2011 }
2012 }
2013 `,
2014 },
2015 {
2016 name: "constant_near_stress",
2017 script: `x -> y
2018 The top of the mountain: { shape: text; near: top-center }
2019 Joe: { shape: person; near: center-left }
2020 Donald: { shape: person; near: center-right }
2021 bottom: |md
2022 # Cats, no less liquid than their shadows, offer no angles to the wind.
2023
2024 If we can't fix it, it ain't broke.
2025
2026 Dieters live life in the fasting lane.
2027 | { near: bottom-center }
2028 i am top left: { shape: text; near: top-left }
2029 i am top right: { shape: text; near: top-right }
2030 i am bottom left: { shape: text; near: bottom-left }
2031 i am bottom right: { shape: text; near: bottom-right }
2032 `,
2033 },
2034 {
2035 name: "md_mixed",
2036 script: `example: {
2037 explanation: |md
2038 *one* __two__ three!
2039 |
2040 }
2041 `,
2042 },
2043 {
2044 name: "constant_near_title",
2045 script: `title: |md
2046 # A winning strategy
2047 | { near: top-center }
2048
2049 poll the people -> results
2050 results -> unfavorable -> poll the people
2051 results -> favorable -> will of the people
2052 `,
2053 },
2054 {
2055 name: "text_font_sizes",
2056 script: `bear: { shape: text; style.font-size: 22; style.bold: true }
2057 mama bear: { shape: text; style.font-size: 28; style.italic: true }
2058 papa bear: { shape: text; style.font-size: 32; style.underline: true }
2059 mama bear -> bear
2060 papa bear -> bear
2061 `,
2062 },
2063 {
2064 name: "basic-tooltips",
2065 script: `x: { tooltip: Total abstinence is easier than perfect moderation }
2066 y: { tooltip: Gee, I feel kind of LIGHT in the head now,\nknowing I can't make my satellite dish PAYMENTS! }
2067 x -> y
2068 `,
2069 },
2070 {
2071 name: "links",
2072 script: `x: { link: https://d2lang.com }
2073 y: { link: https://terrastruct.com; tooltip: Gee, I feel kind of LIGHT in the head now,\nknowing I can't make my satellite dish PAYMENTS! }
2074 x -> y
2075 `,
2076 },
2077 {
2078 name: "unnamed_only_width",
2079 script: `
2080
2081 class2 -> users -> code -> package -> no width
2082
2083 class2: "" {
2084 shape: class
2085 -num: int
2086 -timeout: int
2087 -pid
2088
2089 +getStatus(): Enum
2090 +getJobs(): "Job[]"
2091 +setTimeout(seconds int)
2092 }
2093
2094 users: "" {
2095 shape: sql_table
2096 id: int
2097 name: string
2098 email: string
2099 password: string
2100 last_login: datetime
2101 }
2102
2103 code: |go
2104 a := 5
2105 b := a + 7
2106 fmt.Printf("%d", b)
2107 |
2108
2109 package: "" { shape: package }
2110 no width: ""
2111
2112
2113 class2.width: 512
2114 users.width: 512
2115 code.width: 512
2116 package.width: 512
2117 `,
2118 },
2119 {
2120 name: "unnamed_only_height",
2121 script: `
2122
2123 class2 -> users -> code -> package -> no height
2124
2125 class2: "" {
2126 shape: class
2127 -num: int
2128 -timeout: int
2129 -pid
2130
2131 +getStatus(): Enum
2132 +getJobs(): "Job[]"
2133 +setTimeout(seconds int)
2134 }
2135
2136 users: "" {
2137 shape: sql_table
2138 id: int
2139 name: string
2140 email: string
2141 password: string
2142 last_login: datetime
2143 }
2144
2145 code: |go
2146 a := 5
2147 b := a + 7
2148 fmt.Printf("%d", b)
2149 |
2150
2151 package: "" { shape: package }
2152 no height: ""
2153
2154
2155 class2.height: 512
2156 users.height: 512
2157 code.height: 512
2158 package.height: 512
2159 `,
2160 },
2161 {
2162 name: "container_dimensions",
2163 script: `a: {
2164 width: 500
2165 b -> c
2166 b.width: 400
2167 c.width: 600
2168 }
2169
2170 b: {
2171 width: 700
2172 b -> c
2173 e: {
2174 height: 300
2175 }
2176 }
2177
2178 c: {
2179 width: 200
2180 height: 300
2181 a
2182 }
2183 `,
2184 dagreFeatureError: `Object "a" has attribute "width" and/or "height" set, but layout engine "dagre" does not support dimensions set on containers. See https://d2lang.com/tour/layouts/#layout-specific-functionality for more.`,
2185 },
2186 {
2187 name: "crow_foot_arrowhead",
2188 script: `
2189 a1 <-> b1: {
2190 style.stroke-width: 1
2191 source-arrowhead: {
2192 shape: cf-many
2193 }
2194 target-arrowhead: {
2195 shape: cf-many
2196 }
2197 }
2198 a2 <-> b2: {
2199 style.stroke-width: 3
2200 source-arrowhead: {
2201 shape: cf-many
2202 }
2203 target-arrowhead: {
2204 shape: cf-many
2205 }
2206 }
2207 a3 <-> b3: {
2208 style.stroke-width: 6
2209 source-arrowhead: {
2210 shape: cf-many
2211 }
2212 target-arrowhead: {
2213 shape: cf-many
2214 }
2215 }
2216
2217 c1 <-> d1: {
2218 style.stroke-width: 1
2219 source-arrowhead: {
2220 shape: cf-many-required
2221 }
2222 target-arrowhead: {
2223 shape: cf-many-required
2224 }
2225 }
2226 c2 <-> d2: {
2227 style.stroke-width: 3
2228 source-arrowhead: {
2229 shape: cf-many-required
2230 }
2231 target-arrowhead: {
2232 shape: cf-many-required
2233 }
2234 }
2235 c3 <-> d3: {
2236 style.stroke-width: 6
2237 source-arrowhead: {
2238 shape: cf-many-required
2239 }
2240 target-arrowhead: {
2241 shape: cf-many-required
2242 }
2243 }
2244
2245 e1 <-> f1: {
2246 style.stroke-width: 1
2247 source-arrowhead: {
2248 shape: cf-one
2249 }
2250 target-arrowhead: {
2251 shape: cf-one
2252 }
2253 }
2254 e2 <-> f2: {
2255 style.stroke-width: 3
2256 source-arrowhead: {
2257 shape: cf-one
2258 }
2259 target-arrowhead: {
2260 shape: cf-one
2261 }
2262 }
2263 e3 <-> f3: {
2264 style.stroke-width: 6
2265 source-arrowhead: {
2266 shape: cf-one
2267 }
2268 target-arrowhead: {
2269 shape: cf-one
2270 }
2271 }
2272
2273 g1 <-> h1: {
2274 style.stroke-width: 1
2275 source-arrowhead: {
2276 shape: cf-one-required
2277 }
2278 target-arrowhead: {
2279 shape: cf-one-required
2280 }
2281 }
2282 g2 <-> h2: {
2283 style.stroke-width: 3
2284 source-arrowhead: {
2285 shape: cf-one-required
2286 }
2287 target-arrowhead: {
2288 shape: cf-one-required
2289 }
2290 }
2291 g3 <-> h3: {
2292 style.stroke-width: 6
2293 source-arrowhead: {
2294 shape: cf-one-required
2295 }
2296 target-arrowhead: {
2297 shape: cf-one-required
2298 }
2299 }
2300
2301 c <-> d <-> f: {
2302 style.stroke-width: 1
2303 style.stroke: "orange"
2304 source-arrowhead: {
2305 shape: cf-many-required
2306 }
2307 target-arrowhead: {
2308 shape: cf-one
2309 }
2310 }
2311 `,
2312 },
2313 {
2314 name: "circle_arrowhead",
2315 script: `
2316 a <-> b: circle {
2317 source-arrowhead: {
2318 shape: circle
2319 }
2320 target-arrowhead: {
2321 shape: circle
2322 }
2323 }
2324
2325 c <-> d: filled-circle {
2326 source-arrowhead: {
2327 shape: circle
2328 style.filled: true
2329 }
2330 target-arrowhead: {
2331 shape: circle
2332 style.filled: true
2333 }
2334 }`,
2335 },
2336 {
2337 name: "animated",
2338 script: `
2339 your love life will be -> happy: { style.animated: true }
2340 your love life will be -> harmonious: { style.animated: true }
2341
2342 boredom <- immortality: { style.animated: true }
2343
2344 Friday <-> Monday: { style.animated: true }
2345
2346 Insomnia -- Sleep: { style.animated: true }
2347 Insomnia -- Wake: {
2348 style: {
2349 animated: true
2350 stroke-width: 2
2351 }
2352 }
2353
2354 Insomnia -- Dream: {
2355 style: {
2356 animated: true
2357 stroke-width: 8
2358 }
2359 }
2360
2361 Listen <-> Talk: {
2362 style.animated: true
2363 source-arrowhead.shape: cf-one
2364 target-arrowhead.shape: diamond
2365 label: hear
2366 }
2367 `,
2368 },
2369 {
2370 name: "dagre-container",
2371 script: `a: {
2372 a
2373 b
2374 c
2375 }
2376
2377 b: {
2378 a
2379 b
2380 c
2381 }
2382
2383 a -> b
2384 `,
2385 },
2386 {
2387 name: "sql_table_tooltip_animated",
2388 script: `
2389 direction: left
2390
2391 x: {
2392 shape: sql_table
2393 y { constraint: primary_key }
2394 tooltip: I like turtles
2395 }
2396
2397 a: {
2398 shape: sql_table
2399 b { constraint: foreign_key }
2400 }
2401
2402 a.b <-> x.y: {
2403 style.animated: true
2404 source-arrowhead: {
2405 shape: cf-many
2406 }
2407 target-arrowhead: {
2408 shape: cf-one
2409 }
2410 }
2411 `,
2412 },
2413 {
2414 name: "sql_table_column_styles",
2415 script: `Humor in the Court: {
2416 shape: sql_table
2417 Could you see him from where you were standing?: "I could see his head."
2418 And where was his head?: Just above his shoulders.
2419 style.fill: red
2420 style.stroke: lightgray
2421 style.font-color: orange
2422 style.font-size: 20
2423 }
2424
2425 Humor in the Court2: {
2426 shape: sql_table
2427 Could you see him from where you were standing?: "I could see his head."
2428 And where was his head?: Just above his shoulders.
2429 style.fill: red
2430 style.stroke: lightgray
2431 style.font-color: orange
2432 style.font-size: 30
2433 }
2434
2435 manager: BatchManager {
2436 shape: class
2437 style.font-size: 20
2438
2439 -num: int
2440 -timeout: int
2441 -pid
2442
2443 +getStatus(): Enum
2444 +getJobs(): "Job[]"
2445 +setTimeout(seconds int)
2446 }
2447
2448 manager2: BatchManager {
2449 shape: class
2450 style.font-size: 30
2451
2452 -num: int
2453 -timeout: int
2454 -pid
2455
2456 +getStatus(): Enum
2457 +getJobs(): "Job[]"
2458 +setTimeout(seconds int)
2459 }
2460 `,
2461 },
2462 {
2463 name: "sql_table_constraints_width",
2464 script: `
2465 a: {
2466 shape: sql_table
2467 x: INT {constraint: unique}
2468 }
2469
2470 b: {
2471 shape: sql_table
2472 x: INT {constraint: [primary_key; foreign_key]}
2473 }
2474
2475 c: {
2476 shape: sql_table
2477 x: INT {constraint: [foreign_key; unique]}
2478 }
2479
2480 d: {
2481 shape: sql_table
2482 x: INT {constraint: [primary_key; foreign_key; unique]}
2483 }
2484 e: {
2485 shape: sql_table
2486 x: INT {constraint: [no_abbrev; foreign_key; hello]}
2487 y: string
2488 z: STRING {constraint: yo}
2489 }
2490 f: {
2491 shape: sql_table
2492 x: INT
2493 }
2494 `,
2495 },
2496 {
2497 name: "near-alone",
2498 script: `
2499 x: {
2500 near: top-center
2501 }
2502 y: {
2503 near: bottom-center
2504 }
2505 z: {
2506 near: center-left
2507 }
2508 `,
2509 },
2510 {
2511 name: "classes",
2512 script: `classes: {
2513 dragon_ball: {
2514 label: ""
2515 shape: circle
2516 style.fill: orange
2517 style.stroke-width: 0
2518 width: 50
2519 }
2520 path: {
2521 label: "then"
2522 style.stroke-width: 4
2523 }
2524 }
2525 nostar: { class: dragon_ball }
2526 1star: { label: "*"; class: dragon_ball }
2527 2star: { label: "**"; class: dragon_ball }
2528
2529 nostar -> 1star: { class: path }
2530 1star -> 2star: { class: path }
2531 `,
2532 },
2533 {
2534 name: "array-classes",
2535 script: `classes: {
2536 button: {
2537 style.border-radius: 999
2538 style.stroke: black
2539 }
2540 success: {
2541 style.fill: "#90EE90"
2542 }
2543 error: {
2544 style.fill: "#EA9999"
2545 }
2546 }
2547 yay: Successful { class: [button; success] }
2548 nay: Failure { class: [button; error] }
2549 `,
2550 },
2551 {
2552 name: "border-radius",
2553 script: `
2554 x: {
2555 style.border-radius: 4
2556 }
2557 y: {
2558 style.border-radius: 10
2559 }
2560 multiple2: {
2561 style.border-radius: 6
2562 style.multiple: true
2563 }
2564 double: {
2565 style.border-radius: 6
2566 style.double-border: true
2567 }
2568 three-dee: {
2569 style.border-radius: 6
2570 style.3d: true
2571 }
2572 `,
2573 },
2574 {
2575 name: "border-radius-pill-shape",
2576 script: `
2577 x: {
2578 style.border-radius: 999
2579 }
2580 y: {
2581 style.border-radius: 999
2582 }
2583 multiple2: {
2584 style.border-radius: 999
2585 style.multiple: true
2586 }
2587 double: {
2588 style.border-radius: 999
2589 style.double-border: true
2590 }
2591 three-dee: {
2592 style.border-radius: 999
2593 style.3d: true
2594 }
2595 `,
2596 },
2597 {
2598 name: "cycle-order",
2599 script: `direction: right
2600 classes: {
2601 group: {
2602 style: {
2603 fill: transparent
2604 stroke-dash: 5
2605 }
2606 }
2607 icon: {
2608 shape: image
2609 height: 70
2610 width: 70
2611 }
2612 }
2613
2614 Plan -> Code -> Build -> Test -> Check -> Release -> Deploy -> Operate -> Monitor -> Plan
2615
2616 Plan: {
2617 class: group
2618 ClickUp: {
2619 class: icon
2620 icon: https://avatars.githubusercontent.com/u/27873294?s=200&v=4
2621 }
2622 }
2623 Code: {
2624 class: group
2625 Git: {
2626 class: icon
2627 icon: https://icons.terrastruct.com/dev%2Fgit.svg
2628 }
2629 }
2630 Build: {
2631 class: group
2632 Docker: {
2633 class: icon
2634 icon: https://icons.terrastruct.com/dev%2Fdocker.svg
2635 }
2636 }
2637 Test: {
2638 class: group
2639 Playwright: {
2640 class: icon
2641 icon: https://playwright.dev/img/playwright-logo.svg
2642 }
2643 }
2644 Check: {
2645 class: group
2646 TruffleHog: {
2647 class: icon
2648 icon: https://avatars.githubusercontent.com/u/79229934?s=200&v=4
2649 }
2650 }
2651 Release: {
2652 class: group
2653 Github Action: {
2654 class: icon
2655 icon: https://icons.terrastruct.com/dev%2Fgithub.svg
2656 }
2657 }
2658 Deploy: {
2659 class: group
2660 "AWS Copilot": {
2661 class: icon
2662 icon: https://icons.terrastruct.com/aws%2FDeveloper%20Tools%2FAWS-CodeDeploy.svg
2663 }
2664 }
2665 Operate: {
2666 class: group
2667 "AWS ECS": {
2668 class: icon
2669 icon: https://icons.terrastruct.com/aws%2FCompute%2FAWS-Fargate.svg
2670 }
2671 }
2672 Monitor: {
2673 class: group
2674 Grafana: {
2675 class: icon
2676 icon: https://avatars.githubusercontent.com/u/7195757?s=200&v=4
2677 }
2678 }
2679 `,
2680 },
2681 {
2682 name: "sequence-inter-span-self",
2683 script: `
2684 shape: sequence_diagram
2685 a: A
2686 b: B
2687
2688 a.sp1 -> b: foo
2689 a.sp1 -> a.sp2: redirect
2690 a.sp2 -> b: bar
2691 `,
2692 },
2693 {
2694 name: "people",
2695 script: `
2696 a.shape: person
2697 b.shape: person
2698 c.shape: person
2699 d.shape: person
2700 e.shape: person
2701 f.shape: person
2702 g.shape: person
2703
2704 a: -
2705 b: --
2706 c: ----
2707 d: --------
2708 e: ----------------
2709 f: --------------------------------
2710 g: ----------------------------------------------------------------
2711
2712 1.shape: person
2713 2.shape: person
2714 3.shape: person
2715 4.shape: person
2716 5.shape: person
2717
2718 1.width: 16
2719 2.width: 64
2720 3.width: 128
2721 4.width: 512
2722
2723 # entering both width and height overrides aspect ratio limit
2724 5.height: 256
2725 5.width: 32
2726 `,
2727 },
2728 {
2729 name: "ovals",
2730 script: `
2731 a.shape: oval
2732 b.shape: oval
2733 c.shape: oval
2734 d.shape: oval
2735 e.shape: oval
2736 f.shape: oval
2737 g.shape: oval
2738
2739 a: -
2740 b: --
2741 c: ----
2742 d: --------
2743 e: ----------------
2744 f: --------------------------------
2745 g: ----------------------------------------------------------------
2746
2747 1.shape: oval
2748 2.shape: oval
2749 3.shape: oval
2750 4.shape: oval
2751 5.shape: oval
2752
2753 1.width: 16
2754 2.width: 64
2755 3.width: 128
2756 4.width: 512
2757
2758 # entering both width and height overrides aspect ratio limit
2759 5.height: 256
2760 5.width: 32
2761 `,
2762 },
2763 {
2764 name: "complex-layers",
2765 script: `
2766 desc: Multi-layer diagram of a home.
2767
2768 window: {
2769 style.double-border: true
2770 }
2771 roof
2772 garage
2773
2774 layers: {
2775 window: {
2776 blinds
2777 glass
2778 }
2779 roof: {
2780 shingles
2781 starlink
2782 utility hookup
2783 }
2784 garage: {
2785 tools
2786 vehicles
2787 }
2788 repair: {
2789 desc: How to repair a home.
2790
2791 steps: {
2792 1: {
2793 find contractors: {
2794 craigslist
2795 facebook
2796 }
2797 }
2798 2: {
2799 find contractors -> solicit quotes
2800 }
2801 3: {
2802 obtain quotes -> negotiate
2803 }
2804 4: {
2805 negotiate -> book the best bid
2806 }
2807 }
2808 }
2809 }
2810
2811 scenarios: {
2812 storm: {
2813 water
2814 rain
2815 thunder
2816 }
2817 }`,
2818 },
2819 {
2820 name: "label-near",
2821 script: `
2822 direction: right
2823 x -> y
2824
2825 x: worker {
2826 label.near: top-center
2827 icon: https://icons.terrastruct.com/essentials%2F005-programmer.svg
2828 icon.near: outside-top-right
2829 }
2830
2831 y: profits {
2832 label.near: bottom-right
2833 icon: https://icons.terrastruct.com/essentials%2Fprofits.svg
2834 icon.near: outside-bottom-center
2835 }
2836 `,
2837 },
2838 loadFromFile(t, "arrowhead_scaling"),
2839 loadFromFile(t, "teleport_grid"),
2840 loadFromFile(t, "dagger_grid"),
2841 loadFromFile(t, "grid_tests"),
2842 loadFromFile(t, "executive_grid"),
2843 loadFromFile(t, "grid_animated"),
2844 loadFromFile(t, "grid_gap"),
2845 loadFromFile(t, "grid_even"),
2846 loadFromFile(t, "ent2d2_basic"),
2847 loadFromFile(t, "ent2d2_right"),
2848 loadFromFile(t, "grid_large_checkered"),
2849 loadFromFile(t, "grid_nested"),
2850 loadFromFile(t, "grid_nested_gap0"),
2851 loadFromFile(t, "grid_icon"),
2852 loadFromFile(t, "multiple_offset"),
2853 loadFromFile(t, "multiple_offset_left"),
2854 loadFromFile(t, "multiple_box_selection"),
2855 loadFromFile(t, "multiple_person_label"),
2856 loadFromFile(t, "outside_bottom_labels"),
2857 loadFromFile(t, "label_positions"),
2858 loadFromFile(t, "icon_positions"),
2859 loadFromFile(t, "centered_horizontal_connections"),
2860 loadFromFile(t, "all_shapes_link"),
2861 loadFromFile(t, "nested_shape_labels"),
2862 loadFromFile(t, "overlapping_child_label"),
2863 loadFromFile(t, "dagre_spacing"),
2864 loadFromFile(t, "dagre_spacing_right"),
2865 loadFromFile(t, "simple_grid_edges"),
2866 loadFromFile(t, "grid_nested_simple_edges"),
2867 loadFromFile(t, "nested_diagram_types"),
2868 loadFromFile(t, "grid_outside_labels"),
2869 loadFromFile(t, "grid_edge_across_cell"),
2870 loadFromFile(t, "nesting_power"),
2871 loadFromFile(t, "unfilled_triangle"),
2872 loadFromFile(t, "grid_container_dimensions"),
2873 loadFromFile(t, "grid_label_positions"),
2874 }
2875
2876 runa(t, tcs)
2877 }
2878
View as plain text