mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-12-23 12:46:36 +01:00
Compare commits
1952 Commits
halo-layou
...
dev-tool
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f91ed32bc | ||
|
|
d5bc07dc0c | ||
|
|
80a686be03 | ||
|
|
d26f2c6043 | ||
|
|
8ca7a28bf3 | ||
|
|
6b77c9c4c7 | ||
|
|
7b167cf331 | ||
|
|
d435ac6fe1 | ||
|
|
ed96d067fc | ||
|
|
09c60be450 | ||
|
|
39d070fdea | ||
|
|
4f6f627e75 | ||
|
|
53570ee815 | ||
|
|
a3a5040d79 | ||
|
|
7ff9bf1a50 | ||
|
|
ffd38716d0 | ||
|
|
4313f233d2 | ||
|
|
56564f3807 | ||
|
|
7e1a1de5e9 | ||
|
|
b4b90417cf | ||
|
|
6bf2b2108c | ||
|
|
614129ca31 | ||
|
|
b115ad3cd7 | ||
|
|
73b8626ab0 | ||
|
|
88e8ad6f5b | ||
|
|
ac5fdb8121 | ||
|
|
a30b3bb3f8 | ||
|
|
87c561615e | ||
|
|
0843a2fa7a | ||
|
|
1aa4cd9847 | ||
|
|
8d1cdc41c2 | ||
|
|
bf50ce5237 | ||
|
|
8bfd47758a | ||
|
|
88fd141276 | ||
|
|
454238867b | ||
|
|
6025ec663c | ||
|
|
2346801c30 | ||
|
|
d7eb94dc89 | ||
|
|
db9c683316 | ||
|
|
c9b5c5fed6 | ||
|
|
324cf05afd | ||
|
|
a357c1079f | ||
|
|
e20b079707 | ||
|
|
b1fe4ffe97 | ||
|
|
61c18b99a0 | ||
|
|
04ac594f5b | ||
|
|
a6c2b1d85e | ||
|
|
96ca7c090f | ||
|
|
3c752421a2 | ||
|
|
bf7c532e43 | ||
|
|
8add133bbe | ||
|
|
8cf0d3373d | ||
|
|
ff3b194925 | ||
|
|
6e869ff8dc | ||
|
|
9df18da01c | ||
|
|
608d623641 | ||
|
|
ecf9ea1134 | ||
|
|
b33ce14932 | ||
|
|
283aef54e4 | ||
|
|
96f87fd597 | ||
|
|
03e8589818 | ||
|
|
6b9f26dac8 | ||
|
|
ea590cdafe | ||
|
|
f3769c70bc | ||
|
|
4cf4d15197 | ||
|
|
c02cf92656 | ||
|
|
3a1266892d | ||
|
|
67e81de557 | ||
|
|
847b3aa24e | ||
|
|
85a13da40f | ||
|
|
9ec0e8f932 | ||
|
|
9585ee7533 | ||
|
|
1269486124 | ||
|
|
f45ea0c60e | ||
|
|
d20955a56a | ||
|
|
fb66b3fbe3 | ||
|
|
82ea5d63bb | ||
|
|
881e74087a | ||
|
|
09920c0497 | ||
|
|
8065d65cd7 | ||
|
|
6bc6617ca6 | ||
|
|
29ed57ffec | ||
|
|
9fdc4b8005 | ||
|
|
09b841f781 | ||
|
|
d0f9dc0c9b | ||
|
|
15e2824d53 | ||
|
|
7eb582e860 | ||
|
|
6ca928f31f | ||
|
|
983120d945 | ||
|
|
61f74ffc5e | ||
|
|
74318f9337 | ||
|
|
dfd59470dc | ||
|
|
4aac6fa448 | ||
|
|
5f96f80efb | ||
|
|
545801e144 | ||
|
|
0bd74759cc | ||
|
|
e4cf266c1d | ||
|
|
c0e1662e50 | ||
|
|
6546aed482 | ||
|
|
b76ccae065 | ||
|
|
287a9a3fcb | ||
|
|
7f5160fa4d | ||
|
|
7b0763f262 | ||
|
|
38c289818c | ||
|
|
57530076aa | ||
|
|
f2d7877c7a | ||
|
|
62d2c6505e | ||
|
|
974236bbb8 | ||
|
|
cf0d1248a4 | ||
|
|
ebefbd87a8 | ||
|
|
1e7b71a085 | ||
|
|
f28f3c25aa | ||
|
|
58137aa631 | ||
|
|
e7719f14c5 | ||
|
|
35d9cead8a | ||
|
|
13baf51b35 | ||
|
|
9af985ba9b | ||
|
|
c7f8a11ded | ||
|
|
762b44cf33 | ||
|
|
02c0091106 | ||
|
|
16359adc33 | ||
|
|
061632c580 | ||
|
|
cbf89462ac | ||
|
|
700aa100f2 | ||
|
|
49103ea654 | ||
|
|
3f46c94ab2 | ||
|
|
b136acdc67 | ||
|
|
bba5e5938e | ||
|
|
fed8a523a4 | ||
|
|
33b4946e21 | ||
|
|
3d768f3adf | ||
|
|
76e17ffd20 | ||
|
|
835de0012d | ||
|
|
60f633101c | ||
|
|
18f51eb14e | ||
|
|
2bb57bf7d2 | ||
|
|
a6276daffd | ||
|
|
7def6eecbf | ||
|
|
96a766dcdb | ||
|
|
39d7ebd32e | ||
|
|
34f40f0794 | ||
|
|
32ac2c689d | ||
|
|
dbcadc1d0b | ||
|
|
ac411a7d7e | ||
|
|
d80a638e55 | ||
|
|
7a869c08a2 | ||
|
|
44e8cbb1de | ||
|
|
efe38b8425 | ||
|
|
6fecb985e8 | ||
|
|
69b338d8af | ||
|
|
fa15ce8502 | ||
|
|
6d0650918f | ||
|
|
c728d864c8 | ||
|
|
99f17bea3a | ||
|
|
ad82448084 | ||
|
|
9498619d3c | ||
|
|
7a8557a1a2 | ||
|
|
74863c94fb | ||
|
|
63df702146 | ||
|
|
421f8d4633 | ||
|
|
bf6e1a594c | ||
|
|
c1c14e401a | ||
|
|
8b3057f27c | ||
|
|
717d3b3bb2 | ||
|
|
2f8d9ba958 | ||
|
|
ace0367afd | ||
|
|
b983626587 | ||
|
|
7effdc147b | ||
|
|
6e67515f41 | ||
|
|
1a9d45abf0 | ||
|
|
09b74f1c29 | ||
|
|
880da21908 | ||
|
|
38191243be | ||
|
|
b75dcb8a82 | ||
|
|
4c1e170f4a | ||
|
|
d5c4eff251 | ||
|
|
5324fd8dfd | ||
|
|
bd25b88a01 | ||
|
|
0116b272b4 | ||
|
|
634f3367da | ||
|
|
37e3a6951b | ||
|
|
0de0b063e4 | ||
|
|
619515e5a9 | ||
|
|
59c8b07509 | ||
|
|
9e72bbf62d | ||
|
|
2a2c46f1e2 | ||
|
|
f25df353d4 | ||
|
|
398345a8bc | ||
|
|
7fd2d94ef7 | ||
|
|
bcc1472b9d | ||
|
|
ddc1cfe6c8 | ||
|
|
d3de3ecbbb | ||
|
|
18e9c1174d | ||
|
|
789018abf6 | ||
|
|
16569b295b | ||
|
|
11a35c11ee | ||
|
|
216be22801 | ||
|
|
e87f77a865 | ||
|
|
a9579083bf | ||
|
|
6fd78d0856 | ||
|
|
994f7df29a | ||
|
|
531f5e9380 | ||
|
|
dc11b8645c | ||
|
|
ad4c227477 | ||
|
|
3964ce0a0f | ||
|
|
181af8167b | ||
|
|
799d2ed547 | ||
|
|
a44e3e992c | ||
|
|
ca5b370ffb | ||
|
|
08160a74b4 | ||
|
|
6d221fb3ca | ||
|
|
8b20907141 | ||
|
|
4dbabba8e8 | ||
|
|
d318f1a13c | ||
|
|
525a7de8ae | ||
|
|
a459c436c9 | ||
|
|
bbb93b263d | ||
|
|
1c2a0020bd | ||
|
|
141c6b3808 | ||
|
|
8d4ffdf808 | ||
|
|
32106e259c | ||
|
|
450754221e | ||
|
|
7a4f5b62c9 | ||
|
|
e3ef5e4208 | ||
|
|
daeb85bac2 | ||
|
|
4240340a18 | ||
|
|
b36edd557e | ||
|
|
5e3b5e8f36 | ||
|
|
764b315dc1 | ||
|
|
47c0d2d040 | ||
|
|
ac3b777bf6 | ||
|
|
cf08ba0ef8 | ||
|
|
166782cd38 | ||
|
|
b37eb6d0d1 | ||
|
|
f759f5dcf7 | ||
|
|
80bcefe321 | ||
|
|
70cbbe69d8 | ||
|
|
baf4093e8d | ||
|
|
fd185f7694 | ||
|
|
027d7b6368 | ||
|
|
7986b66a88 | ||
|
|
edb0edc451 | ||
|
|
b511a2e9be | ||
|
|
4829dfa8c5 | ||
|
|
b80ea26a2b | ||
|
|
f88986a87d | ||
|
|
e16f0848ab | ||
|
|
e7811886c3 | ||
|
|
32eda8565c | ||
|
|
2812a0d12a | ||
|
|
25fa26d915 | ||
|
|
62915183b1 | ||
|
|
6874ab3fb6 | ||
|
|
040af4f545 | ||
|
|
65ca3eabfd | ||
|
|
8b9bbad842 | ||
|
|
d2773db7dc | ||
|
|
ca10a259fa | ||
|
|
3840451fda | ||
|
|
cfe9238882 | ||
|
|
0ed9c65572 | ||
|
|
56cc12690f | ||
|
|
2cdaf03ada | ||
|
|
9c85521e16 | ||
|
|
8a565bce92 | ||
|
|
baf510b935 | ||
|
|
c1f2d052be | ||
|
|
bce40e180a | ||
|
|
0dd46a3543 | ||
|
|
f81e63663c | ||
|
|
7109e3a17f | ||
|
|
e0bd51941e | ||
|
|
38f4e67ca7 | ||
|
|
681d829227 | ||
|
|
164e44c3d9 | ||
|
|
f6fa0260e7 | ||
|
|
f47dec3680 | ||
|
|
29aad6d23c | ||
|
|
88dc4beade | ||
|
|
e9232088c0 | ||
|
|
e96614ab86 | ||
|
|
73115cb416 | ||
|
|
480438bd52 | ||
|
|
34fc8bddc4 | ||
|
|
4dd89e439f | ||
|
|
150177c449 | ||
|
|
bf58ed2b53 | ||
|
|
827ced0014 | ||
|
|
133d46bde2 | ||
|
|
e1017266ac | ||
|
|
404fdaf2ff | ||
|
|
82ef7b5fdb | ||
|
|
11cd3f1262 | ||
|
|
2e1d156d66 | ||
|
|
e863ad1547 | ||
|
|
e231b692fd | ||
|
|
68c365f906 | ||
|
|
494c7294cb | ||
|
|
ac4aa94e78 | ||
|
|
fb20ee99eb | ||
|
|
1a22154a3a | ||
|
|
2972bf25bf | ||
|
|
6b1a7a9e1a | ||
|
|
33bc4a0b4e | ||
|
|
c6f25167a2 | ||
|
|
a150f92fb0 | ||
|
|
5d31ded7a0 | ||
|
|
0ed31bfa2c | ||
|
|
51b9185a6b | ||
|
|
b219497847 | ||
|
|
7e96c89be5 | ||
|
|
16a8d0e794 | ||
|
|
7bb9981d8a | ||
|
|
ea3d38bf64 | ||
|
|
8f628b85e5 | ||
|
|
defc922acd | ||
|
|
88ae8d1f2b | ||
|
|
8c7c9ac38a | ||
|
|
0e146d50f7 | ||
|
|
c40faac80d | ||
|
|
454e1e3927 | ||
|
|
4f9875fd4e | ||
|
|
82800a2c84 | ||
|
|
27e700debd | ||
|
|
01e47333d5 | ||
|
|
d47ba7c2d1 | ||
|
|
b1c4eb3f5c | ||
|
|
869709a75f | ||
|
|
310fcd2292 | ||
|
|
85e9ca2a0f | ||
|
|
65d225cb2c | ||
|
|
04b6fc1280 | ||
|
|
c530baed3f | ||
|
|
21eddc3f23 | ||
|
|
f46a151075 | ||
|
|
b7e9d02b7c | ||
|
|
0ef3130510 | ||
|
|
862d40cc3a | ||
|
|
4b63214a72 | ||
|
|
4937ebc058 | ||
|
|
00f5700320 | ||
|
|
e32dc8513f | ||
|
|
50127f3ffe | ||
|
|
29bb0e3dca | ||
|
|
1221de4c2d | ||
|
|
c41e08cb7a | ||
|
|
4760ed8893 | ||
|
|
31ecf31c2e | ||
|
|
b52766653c | ||
|
|
6d9fad01a9 | ||
|
|
8322a63598 | ||
|
|
075e1b5e1f | ||
|
|
045699de10 | ||
|
|
3c9bd7be29 | ||
|
|
6995248443 | ||
|
|
93467a6fce | ||
|
|
95d48e3497 | ||
|
|
202172135d | ||
|
|
b94ab243a8 | ||
|
|
11c8848e1f | ||
|
|
231fcc700f | ||
|
|
8ba7520acc | ||
|
|
e0a5a2489d | ||
|
|
bd400a5130 | ||
|
|
d35f84f337 | ||
|
|
af3bbdc591 | ||
|
|
1988d24227 | ||
|
|
8813cf2c94 | ||
|
|
d145c0e910 | ||
|
|
39f90debe7 | ||
|
|
8dadb853a0 | ||
|
|
29886b8dd4 | ||
|
|
e438e035bc | ||
|
|
2bc5b6d2fa | ||
|
|
e0b45c2d2b | ||
|
|
d4c76968e9 | ||
|
|
a700e8bf97 | ||
|
|
73e9849f99 | ||
|
|
5a05540a5f | ||
|
|
7091792694 | ||
|
|
efd94b705d | ||
|
|
2cfebef122 | ||
|
|
9ec989e633 | ||
|
|
61d9143acb | ||
|
|
c88f74a6ee | ||
|
|
6377d6f64d | ||
|
|
1b0bc05fc2 | ||
|
|
45edeb9307 | ||
|
|
211974b2b7 | ||
|
|
1f5ad3e315 | ||
|
|
d7848e8a3d | ||
|
|
c0e2d4a23b | ||
|
|
89b9f0df70 | ||
|
|
e9011567bd | ||
|
|
7171237b96 | ||
|
|
0429970d58 | ||
|
|
ecad9cee6c | ||
|
|
066883f4cd | ||
|
|
1e8a9f76a9 | ||
|
|
2b58df9665 | ||
|
|
e42fdf1c54 | ||
|
|
c75566ddc3 | ||
|
|
7bdcf93412 | ||
|
|
d86e46b705 | ||
|
|
96778f7789 | ||
|
|
d4c058bd56 | ||
|
|
b638a0a9c1 | ||
|
|
fd9aa36c77 | ||
|
|
46a9f1b31e | ||
|
|
83c6224cc0 | ||
|
|
d8161b1923 | ||
|
|
8223141af9 | ||
|
|
99f98a6876 | ||
|
|
ef28f548df | ||
|
|
e448c53b53 | ||
|
|
71e09bcaef | ||
|
|
cad144734d | ||
|
|
5e57f22e23 | ||
|
|
fc2c32603d | ||
|
|
8c7da5af56 | ||
|
|
4b89af3aca | ||
|
|
c534d3d364 | ||
|
|
4db72f5357 | ||
|
|
2aa8330279 | ||
|
|
803e2e14be | ||
|
|
685516a85e | ||
|
|
880f7454a3 | ||
|
|
7e9577dffd | ||
|
|
cba659d097 | ||
|
|
f7a0844a31 | ||
|
|
2817383714 | ||
|
|
1f46c9e9bb | ||
|
|
ec7099dc27 | ||
|
|
180dc7bdff | ||
|
|
cc9581842d | ||
|
|
a716a525c3 | ||
|
|
e6ee145edf | ||
|
|
d782e4bb17 | ||
|
|
5cc264feb7 | ||
|
|
690cc73259 | ||
|
|
ba9ad9385b | ||
|
|
b9ef683fb6 | ||
|
|
6a6289f2aa | ||
|
|
accb4c6369 | ||
|
|
52be254ad3 | ||
|
|
9c071a9064 | ||
|
|
91d7229f1b | ||
|
|
60feec465b | ||
|
|
d1ae687d1e | ||
|
|
7af6723ac0 | ||
|
|
da90f6760b | ||
|
|
91edfa40f7 | ||
|
|
c8b00bb929 | ||
|
|
d74013c642 | ||
|
|
ce996346f8 | ||
|
|
29edfa7f56 | ||
|
|
14a4ab81c9 | ||
|
|
13d72262d9 | ||
|
|
62dee0bad4 | ||
|
|
9e81e1146a | ||
|
|
57eadbf6af | ||
|
|
2260948b7b | ||
|
|
186429ae32 | ||
|
|
a906adce26 | ||
|
|
657a9ef785 | ||
|
|
4f24489d81 | ||
|
|
11abfc9ae5 | ||
|
|
227cef05b3 | ||
|
|
a6d26ef6c3 | ||
|
|
2a514fa69e | ||
|
|
80c6faf4d5 | ||
|
|
2b3f94eb7d | ||
|
|
81b0ffb92a | ||
|
|
9f6ee53382 | ||
|
|
3248bf3da4 | ||
|
|
bf3ca9d1ef | ||
|
|
e6fb4a84da | ||
|
|
32723b2de1 | ||
|
|
18703782ee | ||
|
|
0b42bdba07 | ||
|
|
dd36046e23 | ||
|
|
1507435e15 | ||
|
|
e7a7ff8a2a | ||
|
|
68fc68c239 | ||
|
|
e53c17a012 | ||
|
|
bb2d6973ba | ||
|
|
769b362005 | ||
|
|
e4d3aa4610 | ||
|
|
716548548a | ||
|
|
aeaf626bb5 | ||
|
|
9322771b5c | ||
|
|
2fe3063bf5 | ||
|
|
4e55a45b1b | ||
|
|
4bece53a3c | ||
|
|
3d319824a6 | ||
|
|
aa5d443a46 | ||
|
|
356da0b4d7 | ||
|
|
22530a8bdf | ||
|
|
e6574ef40c | ||
|
|
c4eb526162 | ||
|
|
68c01b76bf | ||
|
|
4d62d59632 | ||
|
|
5af489d8dd | ||
|
|
28717e108d | ||
|
|
297be4a868 | ||
|
|
fb6ace73b5 | ||
|
|
688d9b383d | ||
|
|
096fbe933e | ||
|
|
e539909e87 | ||
|
|
074701e316 | ||
|
|
e68424d748 | ||
|
|
cfc76ef1cb | ||
|
|
bf362673fc | ||
|
|
d042b21b12 | ||
|
|
677ff82d13 | ||
|
|
4b31361506 | ||
|
|
204a9a338f | ||
|
|
981829a426 | ||
|
|
327a5aa9fd | ||
|
|
6a6a39ff33 | ||
|
|
b296db9a33 | ||
|
|
01ce84d8ee | ||
|
|
f48e663d4c | ||
|
|
a4aa2bd355 | ||
|
|
20a18971ea | ||
|
|
e1e36dfcb3 | ||
|
|
b51b9d50c2 | ||
|
|
74c96db3e2 | ||
|
|
165ffefad5 | ||
|
|
9258b2933b | ||
|
|
f5445b266e | ||
|
|
7a1530d911 | ||
|
|
bd47c57eaf | ||
|
|
3e5d2db514 | ||
|
|
848f69a75c | ||
|
|
99dbeba407 | ||
|
|
d525acc05b | ||
|
|
b61780f735 | ||
|
|
d93d9a521d | ||
|
|
1d3681053b | ||
|
|
93df13898f | ||
|
|
e32e80ea7f | ||
|
|
c99bce6bab | ||
|
|
3256807d25 | ||
|
|
0133f1c0c5 | ||
|
|
12e01bdb5c | ||
|
|
a776b4f0ab | ||
|
|
8d79bc9b19 | ||
|
|
ecf7ab4355 | ||
|
|
c61a431e2d | ||
|
|
526b35c602 | ||
|
|
8090580c67 | ||
|
|
9d685178d2 | ||
|
|
074f18dfb8 | ||
|
|
b451c66d7c | ||
|
|
d7308b0f43 | ||
|
|
1dd11705d9 | ||
|
|
2f1860386a | ||
|
|
17142ef8d7 | ||
|
|
f0bca7da55 | ||
|
|
6fcdf5bfcc | ||
|
|
e2ce0450c1 | ||
|
|
29de40478f | ||
|
|
c95c64139d | ||
|
|
4ab98c2ec7 | ||
|
|
aeb51e56e2 | ||
|
|
a7f12f1baa | ||
|
|
2a8653de2b | ||
|
|
a92c3bb251 | ||
|
|
3677abe9e5 | ||
|
|
ddcd8a5e73 | ||
|
|
e464d080ef | ||
|
|
1a9b94ca2d | ||
|
|
95847ad236 | ||
|
|
e0152fb873 | ||
|
|
e4b33a1d99 | ||
|
|
2298b96d8e | ||
|
|
5db83365b6 | ||
|
|
e27a9da61d | ||
|
|
03cf10003f | ||
|
|
40990bb096 | ||
|
|
8e31fdb611 | ||
|
|
5dd748148f | ||
|
|
895f9d43ff | ||
|
|
4915545429 | ||
|
|
fb890a2be8 | ||
|
|
5986189a52 | ||
|
|
1988dfc956 | ||
|
|
e48b0ba61d | ||
|
|
1a4b8662cf | ||
|
|
6083463c8e | ||
|
|
1a14e331ea | ||
|
|
ebb6680eba | ||
|
|
6d1d46f88a | ||
|
|
435790f931 | ||
|
|
ffe9c1090e | ||
|
|
a476e99d4c | ||
|
|
0cc0b63e52 | ||
|
|
694844050a | ||
|
|
1be1620000 | ||
|
|
c36cd05c45 | ||
|
|
341a81a113 | ||
|
|
8a62b4cace | ||
|
|
b7a591b8d3 | ||
|
|
8bb29fc879 | ||
|
|
e073c80019 | ||
|
|
01aaef39b4 | ||
|
|
3d640fc620 | ||
|
|
7ca0665764 | ||
|
|
334fe87bc6 | ||
|
|
283e7810d2 | ||
|
|
81a6a361ab | ||
|
|
237d01d510 | ||
|
|
62faacdeeb | ||
|
|
0e40d8e8a8 | ||
|
|
e8d6daf4f6 | ||
|
|
724197c910 | ||
|
|
6180c5f2ff | ||
|
|
a9f7a94ae3 | ||
|
|
3ffe9618ae | ||
|
|
da539c1fa1 | ||
|
|
5e8aa2dccf | ||
|
|
ac04172cf8 | ||
|
|
cf5b4b89a8 | ||
|
|
1c269e0432 | ||
|
|
ccafc20917 | ||
|
|
999b836508 | ||
|
|
326e4e3693 | ||
|
|
9c92da487f | ||
|
|
10752f1357 | ||
|
|
1a80854242 | ||
|
|
fc9c600a31 | ||
|
|
da8ce0b93e | ||
|
|
00a79353fc | ||
|
|
1ceeca1ef1 | ||
|
|
94890390ef | ||
|
|
d5cb4eaa59 | ||
|
|
adfeb093cb | ||
|
|
425fb7ee33 | ||
|
|
cb4ed605b2 | ||
|
|
366d217928 | ||
|
|
b94f1336ab | ||
|
|
020c6d66e0 | ||
|
|
ba9db26bfa | ||
|
|
252b1837f7 | ||
|
|
6b9c15d7f0 | ||
|
|
fda640c90c | ||
|
|
cd6f8e5a24 | ||
|
|
584a789183 | ||
|
|
cfc2551bdc | ||
|
|
000308c8f5 | ||
|
|
6039a8b930 | ||
|
|
cd282f2245 | ||
|
|
a27d90fe9c | ||
|
|
64bf34b9ab | ||
|
|
bcd3e33243 | ||
|
|
9faf2f9fb2 | ||
|
|
f683b03645 | ||
|
|
9cef40d164 | ||
|
|
b2754bc553 | ||
|
|
04612e078a | ||
|
|
af585bdcc7 | ||
|
|
37bfa2aa75 | ||
|
|
54640ce476 | ||
|
|
47b4c56b2b | ||
|
|
6b1b0bf151 | ||
|
|
7ba332ad4a | ||
|
|
b65a73f432 | ||
|
|
412d2a09d3 | ||
|
|
7886fed8b2 | ||
|
|
af3d5b6528 | ||
|
|
404286a90d | ||
|
|
827a9af790 | ||
|
|
a14cd0e2a1 | ||
|
|
0823e08a54 | ||
|
|
95733b6295 | ||
|
|
5cafe241d0 | ||
|
|
c847817a54 | ||
|
|
8b86d617e7 | ||
|
|
3ab0961bdc | ||
|
|
cc2112c7aa | ||
|
|
0892870b5d | ||
|
|
500f90a105 | ||
|
|
14983158a2 | ||
|
|
767754f4fb | ||
|
|
cff59c58b4 | ||
|
|
3fea9e8759 | ||
|
|
e5ea2ed0b1 | ||
|
|
34e7f9704b | ||
|
|
ac976245ad | ||
|
|
1176d30668 | ||
|
|
5b241bbb97 | ||
|
|
7e5e47843b | ||
|
|
6728852b7a | ||
|
|
15e7c890ed | ||
|
|
9e2cd1a926 | ||
|
|
abf2227faf | ||
|
|
7db942b0e1 | ||
|
|
70041c806f | ||
|
|
77e2703f72 | ||
|
|
771801b366 | ||
|
|
a9a0a9b2de | ||
|
|
1e5e835c41 | ||
|
|
1f3f8da0f7 | ||
|
|
b11f40e8ce | ||
|
|
1fe045e638 | ||
|
|
1c750ffc70 | ||
|
|
b0ec93f29c | ||
|
|
6b071c135a | ||
|
|
42a3c3487f | ||
|
|
d7b8ed2c5a | ||
|
|
96c21c7e54 | ||
|
|
e95e4d155a | ||
|
|
688170558c | ||
|
|
832f012e10 | ||
|
|
2e2e8c4152 | ||
|
|
6ff6e08c4b | ||
|
|
d7f1f12549 | ||
|
|
6e56869566 | ||
|
|
d3e2be35be | ||
|
|
852cb35f0a | ||
|
|
260a045da0 | ||
|
|
a28965064d | ||
|
|
355eeeb9cc | ||
|
|
5449d6a447 | ||
|
|
34e91f8b65 | ||
|
|
627ee1f34d | ||
|
|
28840ebd84 | ||
|
|
4145879003 | ||
|
|
0451e343ef | ||
|
|
a2dbc8e4b3 | ||
|
|
e097b480d5 | ||
|
|
f76e27db70 | ||
|
|
3e3ae08930 | ||
|
|
966c112eb1 | ||
|
|
55527e70c2 | ||
|
|
447d1cf988 | ||
|
|
003d1c7a70 | ||
|
|
daf8d8d3be | ||
|
|
d7a55b422b | ||
|
|
12e3d31437 | ||
|
|
ad024b01d6 | ||
|
|
c12aea588c | ||
|
|
9dfbf1166d | ||
|
|
98bf9b4cb4 | ||
|
|
e9ce8cf4da | ||
|
|
d90634bf2b | ||
|
|
90707e8062 | ||
|
|
7e23f984e6 | ||
|
|
b3a12237c0 | ||
|
|
aea16eaf7e | ||
|
|
bb7cd70034 | ||
|
|
fad6676d18 | ||
|
|
637680d4d9 | ||
|
|
35a92efcdc | ||
|
|
5f6f5110fd | ||
|
|
af47269342 | ||
|
|
d3c0893937 | ||
|
|
75ef9bc681 | ||
|
|
45edc91591 | ||
|
|
f4edd19371 | ||
|
|
b611a13e04 | ||
|
|
7a38eb715d | ||
|
|
2715ddb338 | ||
|
|
ca2eca58c9 | ||
|
|
fce7cabb71 | ||
|
|
38e6dc497a | ||
|
|
5f0c53c8a7 | ||
|
|
f9da4433ff | ||
|
|
fc07f0d8ab | ||
|
|
b4fae2d096 | ||
|
|
ce7a487dfc | ||
|
|
6dd9af0dd4 | ||
|
|
3151241559 | ||
|
|
8c0d12027d | ||
|
|
afeb761296 | ||
|
|
3abcfbb8d2 | ||
|
|
ee82694645 | ||
|
|
dda9c9b46e | ||
|
|
cdd1a70b67 | ||
|
|
12c94a177b | ||
|
|
d8bd4dea93 | ||
|
|
6deb476182 | ||
|
|
ed297ee235 | ||
|
|
03c1201fcb | ||
|
|
3ca317c5a0 | ||
|
|
4d83263388 | ||
|
|
254e5cbd51 | ||
|
|
a58dd3c6ce | ||
|
|
10b7bb568f | ||
|
|
1aa2870224 | ||
|
|
8fbcbb6dc9 | ||
|
|
3e545d7925 | ||
|
|
75d2a259ed | ||
|
|
746280b3e2 | ||
|
|
fa4e30bb15 | ||
|
|
950b107dd4 | ||
|
|
35b84761a9 | ||
|
|
0da2922ee7 | ||
|
|
85eba01663 | ||
|
|
ea72740d1f | ||
|
|
79ba50216a | ||
|
|
71b04f93b0 | ||
|
|
27185f62e4 | ||
|
|
9655d07adf | ||
|
|
2b3cb6a362 | ||
|
|
427dc38857 | ||
|
|
ec21042c53 | ||
|
|
89ac2932c4 | ||
|
|
e828609749 | ||
|
|
91f141f772 | ||
|
|
c77b968f1e | ||
|
|
ba13981905 | ||
|
|
a7a94b95e1 | ||
|
|
31f141c61a | ||
|
|
fb017bebfd | ||
|
|
648698a43a | ||
|
|
a5e4729c76 | ||
|
|
c884def5fc | ||
|
|
4a86b68e01 | ||
|
|
592c5bb880 | ||
|
|
da0c6c6c32 | ||
|
|
012530e98e | ||
|
|
a4a27611dd | ||
|
|
5055ade44e | ||
|
|
b61bec8faf | ||
|
|
1414380181 | ||
|
|
6686ee9253 | ||
|
|
7f109c7b94 | ||
|
|
b9c3375be3 | ||
|
|
4254bdd473 | ||
|
|
4012cbf013 | ||
|
|
939da082b2 | ||
|
|
d9396eedd6 | ||
|
|
76d073b027 | ||
|
|
5f9601b6a8 | ||
|
|
378f8ece0c | ||
|
|
8693be56ee | ||
|
|
148a42a31a | ||
|
|
8980ca4526 | ||
|
|
814b68b4a9 | ||
|
|
bfa0eefa32 | ||
|
|
caa04aad8b | ||
|
|
cc476d59d1 | ||
|
|
3dc06ea9bd | ||
|
|
c311c1ba5d | ||
|
|
11a86d9c06 | ||
|
|
037bec189c | ||
|
|
9b164dd185 | ||
|
|
4ee124bf91 | ||
|
|
e70be4f155 | ||
|
|
8314554eb5 | ||
|
|
b7c03dc27e | ||
|
|
6621f6ddb2 | ||
|
|
c7f2f609a9 | ||
|
|
579c22cf5d | ||
|
|
33e08daf17 | ||
|
|
24257de8a6 | ||
|
|
4c3de3a1ec | ||
|
|
42ac1848dd | ||
|
|
3920ad442d | ||
|
|
e7970c66ee | ||
|
|
c7b96be683 | ||
|
|
0623a87d70 | ||
|
|
c5f89eaa9a | ||
|
|
1fbe550285 | ||
|
|
b3724f04c4 | ||
|
|
2f58a0e188 | ||
|
|
6f1e0e4d17 | ||
|
|
7dd8ddc3eb | ||
|
|
222d7170f7 | ||
|
|
3137cff4a5 | ||
|
|
b45b1d7795 | ||
|
|
e1030b186e | ||
|
|
334c8c2962 | ||
|
|
bdaa3f693a | ||
|
|
be13fb0391 | ||
|
|
c120901744 | ||
|
|
1f07a781e4 | ||
|
|
3132387ede | ||
|
|
f41b4c96f9 | ||
|
|
26bd456c01 | ||
|
|
8ef7040a8d | ||
|
|
badb019d38 | ||
|
|
e7ec8ed527 | ||
|
|
d85a393bcd | ||
|
|
7c1e655675 | ||
|
|
df2ccaa14b | ||
|
|
797ba43d6e | ||
|
|
53d27b771d | ||
|
|
d628a971ef | ||
|
|
2c0931da46 | ||
|
|
8049b6aef8 | ||
|
|
84802118be | ||
|
|
e2ef425245 | ||
|
|
da98732961 | ||
|
|
efa11a7325 | ||
|
|
8224a81ab6 | ||
|
|
e5f6ea0b13 | ||
|
|
98442294ed | ||
|
|
a3d164fde8 | ||
|
|
9dc987b28b | ||
|
|
72c0d9df26 | ||
|
|
cfbce54638 | ||
|
|
6979aa1013 | ||
|
|
9562a769db | ||
|
|
5cfda33d04 | ||
|
|
ea60525988 | ||
|
|
9da6fb39ae | ||
|
|
83b9a17277 | ||
|
|
f0445b74d1 | ||
|
|
ba52eef257 | ||
|
|
c13ce2a5c0 | ||
|
|
d2463f41b5 | ||
|
|
e682172823 | ||
|
|
85c5b9b4c0 | ||
|
|
eadb343292 | ||
|
|
e7208622f7 | ||
|
|
fbae611406 | ||
|
|
34027bc589 | ||
|
|
f2eef37599 | ||
|
|
1e68ed9cc1 | ||
|
|
1337c60784 | ||
|
|
a12d1f731a | ||
|
|
b6ba9b79df | ||
|
|
ce227b5519 | ||
|
|
8a703bd09f | ||
|
|
c4de3cdc57 | ||
|
|
ef449a601b | ||
|
|
8e84a1a8af | ||
|
|
a3552e7936 | ||
|
|
646cdf0d32 | ||
|
|
99048bfa01 | ||
|
|
ca80f719ea | ||
|
|
0cabc6e8ed | ||
|
|
5fe0f53179 | ||
|
|
e2e3cd2bbd | ||
|
|
ffb9016d65 | ||
|
|
3c03f289b4 | ||
|
|
c6035936b6 | ||
|
|
818699f347 | ||
|
|
f23a26e528 | ||
|
|
48e6e60753 | ||
|
|
dc3ed65c18 | ||
|
|
43092e6e11 | ||
|
|
878e77acab | ||
|
|
2372cd7b21 | ||
|
|
51f0cb2892 | ||
|
|
14e3d77c75 | ||
|
|
875fef691b | ||
|
|
7075f833d0 | ||
|
|
d629c5eae5 | ||
|
|
80904da253 | ||
|
|
e6be1e9202 | ||
|
|
6f5d889f19 | ||
|
|
63827db60d | ||
|
|
41108358f6 | ||
|
|
ec0786a6fa | ||
|
|
2ea6695b4b | ||
|
|
6485d1fbca | ||
|
|
d0f1dafd49 | ||
|
|
f970fc8bea | ||
|
|
015afc53d5 | ||
|
|
1f44143936 | ||
|
|
db461a4c6c | ||
|
|
fe33d5fb53 | ||
|
|
64c4d4197b | ||
|
|
ed7bab76f2 | ||
|
|
f338802642 | ||
|
|
445595f942 | ||
|
|
66ce617bea | ||
|
|
3e07a5acff | ||
|
|
df1e739194 | ||
|
|
2def5a0768 | ||
|
|
2746bccef3 | ||
|
|
f0c3dfe3b3 | ||
|
|
942ae8dcbc | ||
|
|
cadcddd40c | ||
|
|
bca6ed67c3 | ||
|
|
f20c677982 | ||
|
|
e46fd145b2 | ||
|
|
b1cf291273 | ||
|
|
cac1779c22 | ||
|
|
96bd7de40d | ||
|
|
82874c6584 | ||
|
|
e79147dcfc | ||
|
|
28131bab98 | ||
|
|
9d6b9369e6 | ||
|
|
80351d9f59 | ||
|
|
7b307f812f | ||
|
|
071df09395 | ||
|
|
0d047ccbcc | ||
|
|
680d65114c | ||
|
|
d463f00160 | ||
|
|
941bc69835 | ||
|
|
107b6cae87 | ||
|
|
1b044a24fa | ||
|
|
17a156901a | ||
|
|
fa22ed137c | ||
|
|
6b886abf39 | ||
|
|
4fd64c5bc0 | ||
|
|
7e245f970f | ||
|
|
4f8f929340 | ||
|
|
3629e8e480 | ||
|
|
ff48c2e1da | ||
|
|
1bd13b50f1 | ||
|
|
bbe3489b4f | ||
|
|
31ba692f65 | ||
|
|
b073175fe9 | ||
|
|
e2e22de1d9 | ||
|
|
c370ebe520 | ||
|
|
d732fa5f86 | ||
|
|
ce1bfb2af5 | ||
|
|
c6d8590d8f | ||
|
|
10505a0392 | ||
|
|
e0a075ecca | ||
|
|
2a10143406 | ||
|
|
40eb0cc240 | ||
|
|
d702a7164e | ||
|
|
8a0bc64282 | ||
|
|
ac0283ff97 | ||
|
|
84faddc9e5 | ||
|
|
5e3f21f572 | ||
|
|
05c74ed9ce | ||
|
|
b106346119 | ||
|
|
c09232c44d | ||
|
|
714496af6d | ||
|
|
5d61a30237 | ||
|
|
02ff3c1216 | ||
|
|
1f897a851b | ||
|
|
8af636c58d | ||
|
|
954f6cc8fc | ||
|
|
a566353030 | ||
|
|
d396c6b760 | ||
|
|
8d9f027f40 | ||
|
|
560700eaf8 | ||
|
|
819843cf2a | ||
|
|
5e2870f6f2 | ||
|
|
c364ff463a | ||
|
|
8738288bc0 | ||
|
|
74ef4ce9c6 | ||
|
|
2b41bf083c | ||
|
|
249f22763b | ||
|
|
444d35b9b4 | ||
|
|
83543bc790 | ||
|
|
379559c992 | ||
|
|
c61b879711 | ||
|
|
67806022b9 | ||
|
|
f8c54317c5 | ||
|
|
65f778d183 | ||
|
|
ed67c36440 | ||
|
|
908043183e | ||
|
|
97b79c3578 | ||
|
|
8d4c5d5278 | ||
|
|
9988a61ec5 | ||
|
|
d4e737e451 | ||
|
|
b821454927 | ||
|
|
cee43a45f6 | ||
|
|
475532a839 | ||
|
|
c8daf9aa43 | ||
|
|
cf8fc2a541 | ||
|
|
08b6524a35 | ||
|
|
221aa3ed19 | ||
|
|
640a65f9a7 | ||
|
|
c17277e743 | ||
|
|
7b3fd044e8 | ||
|
|
566b3db15f | ||
|
|
2483e6e434 | ||
|
|
e7b39f3fa3 | ||
|
|
19884294bc | ||
|
|
e6b63fd70a | ||
|
|
1c1d7d0300 | ||
|
|
e8ee4bdb48 | ||
|
|
2afa96c2a8 | ||
|
|
7c42d08ef2 | ||
|
|
d0520e6a50 | ||
|
|
a703a195d4 | ||
|
|
05b5607265 | ||
|
|
2b28966f8d | ||
|
|
4077088f18 | ||
|
|
867484a2cc | ||
|
|
5ea7088e04 | ||
|
|
646230d603 | ||
|
|
5a7e734da4 | ||
|
|
2924b94fbc | ||
|
|
f8c6ae5d17 | ||
|
|
8d7330aeb3 | ||
|
|
6a6c9f6254 | ||
|
|
b0b76ef7a2 | ||
|
|
53e89d97a0 | ||
|
|
59b400652b | ||
|
|
e8124d8828 | ||
|
|
26e3bea2fe | ||
|
|
1fda77db13 | ||
|
|
5b2227b3be | ||
|
|
68670535bf | ||
|
|
7a6f13707f | ||
|
|
9d838d4e7a | ||
|
|
a92ae7a16c | ||
|
|
8800de9309 | ||
|
|
d2c53552ff | ||
|
|
91a7564db6 | ||
|
|
a037cdcf13 | ||
|
|
3753967c8f | ||
|
|
549dc86b21 | ||
|
|
e97f25f13e | ||
|
|
c3c609a965 | ||
|
|
c81a7d13e0 | ||
|
|
e561acac23 | ||
|
|
86a0a7fe3a | ||
|
|
5a8f32b8cb | ||
|
|
c6e640ab75 | ||
|
|
f6862c5af5 | ||
|
|
bd8b93327e | ||
|
|
4a63901af9 | ||
|
|
8c52edf3ef | ||
|
|
da610bff1d | ||
|
|
db389e589d | ||
|
|
24aec8c280 | ||
|
|
8c4fc3c6ff | ||
|
|
d72ee5fc95 | ||
|
|
b3ff80f211 | ||
|
|
8a34154efa | ||
|
|
79b47be35f | ||
|
|
054f5444d6 | ||
|
|
beb80db25a | ||
|
|
fbdbd9d0dd | ||
|
|
8ce1f70066 | ||
|
|
334294c6af | ||
|
|
e0f3f2bd5a | ||
|
|
6dad2ab327 | ||
|
|
4d2e424c30 | ||
|
|
ff217957fc | ||
|
|
866b29c050 | ||
|
|
a463d11e57 | ||
|
|
5267f7c6ea | ||
|
|
2bdecc2842 | ||
|
|
d8efe9a55d | ||
|
|
ae564f30af | ||
|
|
2a6da19956 | ||
|
|
de41669320 | ||
|
|
02b997f4e4 | ||
|
|
90c0908ed5 | ||
|
|
a7d76b2695 | ||
|
|
e46c7ae996 | ||
|
|
af7a5fe77d | ||
|
|
f9fbadbbe2 | ||
|
|
dec82de586 | ||
|
|
598c72853f | ||
|
|
b1e1a0c0d7 | ||
|
|
a9f3b432ff | ||
|
|
cd2ab38927 | ||
|
|
04448e3b6a | ||
|
|
2a12a64c06 | ||
|
|
586b528a16 | ||
|
|
36e6e6e1be | ||
|
|
1de7d31d90 | ||
|
|
34d91d0e88 | ||
|
|
101dc6d52c | ||
|
|
1fbe17e04c | ||
|
|
8fed1c86b0 | ||
|
|
b808801347 | ||
|
|
58ec4ca39f | ||
|
|
7e3d547094 | ||
|
|
79f010143a | ||
|
|
aa9df775cd | ||
|
|
2601ec89c8 | ||
|
|
566415c189 | ||
|
|
cbabc7b709 | ||
|
|
873962c739 | ||
|
|
2aeb435f19 | ||
|
|
e0818c9e47 | ||
|
|
a3753d8f4d | ||
|
|
308e2cc107 | ||
|
|
a578cb8def | ||
|
|
a823bf043b | ||
|
|
3980c99c22 | ||
|
|
c81f63b462 | ||
|
|
16167a64e5 | ||
|
|
cba4d733f0 | ||
|
|
6a0fb67ab7 | ||
|
|
4bfd0f753d | ||
|
|
bf83262d7c | ||
|
|
ccdd0f0146 | ||
|
|
82646432a1 | ||
|
|
c82579097c | ||
|
|
92132ad4f1 | ||
|
|
8564ebbdbd | ||
|
|
1ca6ff93ff | ||
|
|
20098b287b | ||
|
|
0474a8422b | ||
|
|
075f0f580f | ||
|
|
78ded6452f | ||
|
|
08085b8821 | ||
|
|
5f35d70ce2 | ||
|
|
08951dbbf0 | ||
|
|
7caf377963 | ||
|
|
0103da0179 | ||
|
|
a6c9ab04dc | ||
|
|
b9c472e091 | ||
|
|
4ed4756220 | ||
|
|
4b12ebee51 | ||
|
|
d6e1541bc8 | ||
|
|
0507fe114e | ||
|
|
2bb77406fb | ||
|
|
2215bf6aaa | ||
|
|
206cc51578 | ||
|
|
c4c55277cb | ||
|
|
0c2d222aa6 | ||
|
|
fc3d4859db | ||
|
|
c7714fd666 | ||
|
|
e2bf95c922 | ||
|
|
a79a50b77f | ||
|
|
9133fcb9a8 | ||
|
|
00e9ed2024 | ||
|
|
5919d39812 | ||
|
|
f5fa0ae876 | ||
|
|
de9eb67040 | ||
|
|
cb7518a960 | ||
|
|
34bf5c8be1 | ||
|
|
7d1319f97c | ||
|
|
9c46e960e7 | ||
|
|
cd956e1b60 | ||
|
|
78cf1706a9 | ||
|
|
607e9ab989 | ||
|
|
0cf0b684cf | ||
|
|
cb0cb5dfc7 | ||
|
|
330c48fa3f | ||
|
|
2ff6de11dc | ||
|
|
385fab8c67 | ||
|
|
e49911e748 | ||
|
|
8a84ede164 | ||
|
|
d79b7b2d97 | ||
|
|
844f879f63 | ||
|
|
cf789d2c91 | ||
|
|
4936ef5c30 | ||
|
|
f006718e56 | ||
|
|
d720776918 | ||
|
|
f43398dd44 | ||
|
|
43ad451940 | ||
|
|
94c099caa1 | ||
|
|
a3fed10d55 | ||
|
|
2a859f2739 | ||
|
|
dbbe014c5b | ||
|
|
c7fa906115 | ||
|
|
3c69bd34c7 | ||
|
|
ceef0558be | ||
|
|
63b90e8b9b | ||
|
|
f5d27bf7ef | ||
|
|
5a03f07853 | ||
|
|
8474cf43fe | ||
|
|
f56895832f | ||
|
|
8975a1907a | ||
|
|
62b4228df4 | ||
|
|
c552dc7551 | ||
|
|
e425a45755 | ||
|
|
d177211286 | ||
|
|
a07d365c1c | ||
|
|
1f512e9671 | ||
|
|
12b6371abf | ||
|
|
88ae4ef704 | ||
|
|
df9df9dc32 | ||
|
|
ea321168bd | ||
|
|
d7730aba46 | ||
|
|
5310d60e63 | ||
|
|
3ae87ca06a | ||
|
|
24f23efdad | ||
|
|
e2520dde20 | ||
|
|
3e8204aa21 | ||
|
|
0b57984d27 | ||
|
|
bcaa40f1d5 | ||
|
|
0107494b59 | ||
|
|
11c3ac58fd | ||
|
|
af2eb13932 | ||
|
|
41e84b726a | ||
|
|
a1ba65c0c0 | ||
|
|
5fe6e5dccc | ||
|
|
946452c7b4 | ||
|
|
4bb6351489 | ||
|
|
8c63a2e411 | ||
|
|
4467fd4363 | ||
|
|
7e567a8759 | ||
|
|
edf062720d | ||
|
|
3348eea6af | ||
|
|
ae7ffab9ac | ||
|
|
ecdbc676d2 | ||
|
|
6a01b04e3c | ||
|
|
aafe8de3d3 | ||
|
|
24287637b5 | ||
|
|
f69cc17795 | ||
|
|
f5c99a2a4f | ||
|
|
244703a904 | ||
|
|
59a9e1b300 | ||
|
|
167a625413 | ||
|
|
296cb64fa5 | ||
|
|
934f4da507 | ||
|
|
6957f35782 | ||
|
|
b00be59ea8 | ||
|
|
dff00f2c4f | ||
|
|
2009177375 | ||
|
|
eb9987435a | ||
|
|
a300d0db94 | ||
|
|
7e7f3c56c2 | ||
|
|
81fa2a675f | ||
|
|
2203792164 | ||
|
|
5bbc9b4f5b | ||
|
|
ea987861f3 | ||
|
|
8005262d76 | ||
|
|
463eb07979 | ||
|
|
a3cf9de01b | ||
|
|
9a90aca8e6 | ||
|
|
8c9b38ed90 | ||
|
|
963b1e3ec5 | ||
|
|
208d29e3d6 | ||
|
|
5c865e7b71 | ||
|
|
7ce9dbcece | ||
|
|
36fe04bd46 | ||
|
|
ff786b4ef8 | ||
|
|
b81b665137 | ||
|
|
178c7130c6 | ||
|
|
f87d0dd88a | ||
|
|
2396f90269 | ||
|
|
97e35fd30a | ||
|
|
7a5f999f42 | ||
|
|
cd8d74bb96 | ||
|
|
3e6f680df2 | ||
|
|
56c6853e05 | ||
|
|
2e5d955e77 | ||
|
|
7733faf6c4 | ||
|
|
b053a88993 | ||
|
|
01e2af0cfd | ||
|
|
f55ff99f74 | ||
|
|
d25770ee73 | ||
|
|
2b05d7e1ed | ||
|
|
7c77c46ede | ||
|
|
30735266a4 | ||
|
|
926862c196 | ||
|
|
44e668e704 | ||
|
|
404216273a | ||
|
|
5a6831ae7e | ||
|
|
da6937f474 | ||
|
|
cbb496da79 | ||
|
|
03119fea2c | ||
|
|
5351211256 | ||
|
|
92c0aa4331 | ||
|
|
7bd5c03d87 | ||
|
|
de72e18a7f | ||
|
|
3f493acc6a | ||
|
|
d2239549e6 | ||
|
|
f8d8f74f34 | ||
|
|
74a9336d42 | ||
|
|
ca2b16119d | ||
|
|
2d9034c983 | ||
|
|
aa6cb86899 | ||
|
|
99797632ab | ||
|
|
4fdb1d5906 | ||
|
|
43e66a6089 | ||
|
|
5acbd7e762 | ||
|
|
febae345fc | ||
|
|
28bdbbca1a | ||
|
|
4b896fa22e | ||
|
|
a25ee49edd | ||
|
|
695b5b2fb2 | ||
|
|
9b77af540b | ||
|
|
7829138fb2 | ||
|
|
7e7a4fc665 | ||
|
|
a2bf5103ce | ||
|
|
8b7a4db2ef | ||
|
|
a43965ac2c | ||
|
|
8eb2000b98 | ||
|
|
73f8dee643 | ||
|
|
8bdd7ec719 | ||
|
|
7e1cec95ef | ||
|
|
ec2c76a703 | ||
|
|
7facc8f50d | ||
|
|
52cd9e8e55 | ||
|
|
9208e7faaf | ||
|
|
d0ee6079b3 | ||
|
|
34e6112fea | ||
|
|
0c759d0075 | ||
|
|
5b7c1aad9e | ||
|
|
865c453547 | ||
|
|
c0b14021b7 | ||
|
|
2798e27b1e | ||
|
|
f4c08a0c6f | ||
|
|
c28c05780c | ||
|
|
6a538da07d | ||
|
|
b2dfa74865 | ||
|
|
930e917215 | ||
|
|
c8e87b113b | ||
|
|
8627fb0f62 | ||
|
|
cdbd3e58a3 | ||
|
|
630c4d6954 | ||
|
|
fd4493733f | ||
|
|
e588743bf4 | ||
|
|
04d68e7f9a | ||
|
|
9795b6e089 | ||
|
|
a9be1a4146 | ||
|
|
617c7393bf | ||
|
|
ceb8d4c7ef | ||
|
|
32c70a0f6a | ||
|
|
af2632f14a | ||
|
|
8f89ba1930 | ||
|
|
c1db4f2ed0 | ||
|
|
ad6f855f5e | ||
|
|
f2f2a1d275 | ||
|
|
17fcf43cdb | ||
|
|
4fff67e4af | ||
|
|
350543a5e2 | ||
|
|
99a2dc7c1f | ||
|
|
34e756fde6 | ||
|
|
f74fad057a | ||
|
|
32ea973b12 | ||
|
|
0104d19f66 | ||
|
|
e8986eb546 | ||
|
|
936d1074b2 | ||
|
|
7b2083926d | ||
|
|
bb9210c55e | ||
|
|
16d9b63457 | ||
|
|
bf3370fa5b | ||
|
|
9f9091e5e4 | ||
|
|
d1b1a67d99 | ||
|
|
ac625bdc7f | ||
|
|
40b85c3bbf | ||
|
|
f8e329f890 | ||
|
|
9b9cec9809 | ||
|
|
ad653138e1 | ||
|
|
a401a4ab49 | ||
|
|
2bc3a0f97c | ||
|
|
f5f3b08f12 | ||
|
|
ce68da3fee | ||
|
|
f7e31a978b | ||
|
|
2d583b186d | ||
|
|
b322392f97 | ||
|
|
573b6d9ba7 | ||
|
|
ea39254556 | ||
|
|
044a3d9686 | ||
|
|
f28f7b713d | ||
|
|
cfbd05515e | ||
|
|
1125f5a283 | ||
|
|
fa4d4806fa | ||
|
|
20927a1c8e | ||
|
|
b2ab34ca2b | ||
|
|
55e1dd0ead | ||
|
|
a403f78168 | ||
|
|
6c45aa3602 | ||
|
|
85ce310884 | ||
|
|
fac570cb8c | ||
|
|
a7bcd7dee5 | ||
|
|
91bcd2da8c | ||
|
|
ec2330875e | ||
|
|
bb5a7a585e | ||
|
|
5d1b27132a | ||
|
|
288abd01e0 | ||
|
|
95d73bc3f0 | ||
|
|
0f5125b5e3 | ||
|
|
12c120368d | ||
|
|
a7f2c0bc34 | ||
|
|
5e97b2f764 | ||
|
|
d53c66dde5 | ||
|
|
1fb91d14c9 | ||
|
|
d80cc38bb2 | ||
|
|
d6022408a9 | ||
|
|
41a737f682 | ||
|
|
0c2e1bc3fe | ||
|
|
f399561565 | ||
|
|
05bdf0e20e | ||
|
|
292cd83439 | ||
|
|
3848649bdd | ||
|
|
1341e3d156 | ||
|
|
1d6a55a311 | ||
|
|
4d25caba8e | ||
|
|
f6335571cc | ||
|
|
bb895d8cf4 | ||
|
|
c8f01b14a8 | ||
|
|
cdaea58096 | ||
|
|
b3d8fa917f | ||
|
|
91931531a6 | ||
|
|
50e4641666 | ||
|
|
1bed6432ac | ||
|
|
6cc192680a | ||
|
|
3dd6107e76 | ||
|
|
ee5dc5ae80 | ||
|
|
b7940b64cd | ||
|
|
1ddaf10b89 | ||
|
|
02b833f251 | ||
|
|
0ce0c3cd75 | ||
|
|
00ca7ac94f | ||
|
|
34cd280ae4 | ||
|
|
d0986ace8c | ||
|
|
11f7f426cb | ||
|
|
a31adc63a9 | ||
|
|
bc2bd3d769 | ||
|
|
f047b81bb9 | ||
|
|
7db1d672a9 | ||
|
|
91e2c04e56 | ||
|
|
a2f0d8e4d6 | ||
|
|
00a8dc47f5 | ||
|
|
47297f7c26 | ||
|
|
967aa0629e | ||
|
|
5caaf36a3b | ||
|
|
04b20a79b9 | ||
|
|
4128197468 | ||
|
|
40494b16f5 | ||
|
|
840a197044 | ||
|
|
ae0fcbfb8b | ||
|
|
f60ecfc2c4 | ||
|
|
a38a0ab869 | ||
|
|
06877dcc47 | ||
|
|
050fbd9da2 | ||
|
|
1b5672e73d | ||
|
|
1be1e34e72 | ||
|
|
b22103b769 | ||
|
|
9e29fd0c4a | ||
|
|
a2650adec2 | ||
|
|
33f9d8bdc9 | ||
|
|
446f6a7701 | ||
|
|
2ace92858f | ||
|
|
b0c1460940 | ||
|
|
510fd0fe71 | ||
|
|
9268cc2e07 | ||
|
|
7c7fd4bc5e | ||
|
|
baa261fdd1 | ||
|
|
aaf15fccc1 | ||
|
|
3724d11255 | ||
|
|
5510f18d33 | ||
|
|
edbf125c83 | ||
|
|
ad6248147c | ||
|
|
d47e4724cb | ||
|
|
4f592115e0 | ||
|
|
d2d78a5576 | ||
|
|
5447a9f4f9 | ||
|
|
dc698c0309 | ||
|
|
31665fbad8 | ||
|
|
a5561b9be0 | ||
|
|
e045e0b42d | ||
|
|
60db05b75c | ||
|
|
3be59a7b4d | ||
|
|
ff00141a0a | ||
|
|
374ebbb087 | ||
|
|
9d06d8f31e | ||
|
|
97b12e9718 | ||
|
|
50816a7f98 | ||
|
|
a318ea3692 | ||
|
|
1424127127 | ||
|
|
9c27125f2d | ||
|
|
6140be24da | ||
|
|
de40d80ef9 | ||
|
|
c9b8f034d5 | ||
|
|
2fb7bc2806 | ||
|
|
162e9e50ad | ||
|
|
225e5dde60 | ||
|
|
726b42ba00 | ||
|
|
c22b5701db | ||
|
|
c6b715f737 | ||
|
|
bc69180958 | ||
|
|
83a6e696c6 | ||
|
|
a64b14dbfd | ||
|
|
a89e001d01 | ||
|
|
6a81a907d1 | ||
|
|
1c8b996cbb | ||
|
|
eb8e4da5f6 | ||
|
|
16573d97f5 | ||
|
|
2fdd24ab15 | ||
|
|
c01aee842a | ||
|
|
2c22e80dba | ||
|
|
0518e9cfd7 | ||
|
|
fe2e73ed94 | ||
|
|
4f5c4b8349 | ||
|
|
ce99d968f4 | ||
|
|
877a7e288a | ||
|
|
4eeea1076c | ||
|
|
f43e35039f | ||
|
|
dbf885b077 | ||
|
|
78c1d97f0f | ||
|
|
5abda14809 | ||
|
|
ad2f17205a | ||
|
|
bb4b92a663 | ||
|
|
9bd599666b | ||
|
|
36894fe14a | ||
|
|
efe834e772 | ||
|
|
98fe7a6e03 | ||
|
|
8857e77495 | ||
|
|
5857953d51 | ||
|
|
5dab86a067 | ||
|
|
9ef35549f4 | ||
|
|
4beed963b8 | ||
|
|
3122c3b75c | ||
|
|
dffa689e2b | ||
|
|
5ed2278887 | ||
|
|
d6376ca1ff | ||
|
|
99bd0c48fa | ||
|
|
eb7289a65a | ||
|
|
80c6b945fa | ||
|
|
34a12103d0 | ||
|
|
46b8a75199 | ||
|
|
1dca45a76d | ||
|
|
d1d5bd14f6 | ||
|
|
974867a089 | ||
|
|
52532a7801 | ||
|
|
6eb56b9363 | ||
|
|
f7c91a72cb | ||
|
|
c53e044559 | ||
|
|
d846a8c65a | ||
|
|
c3ba23a4e9 | ||
|
|
c688c387a0 | ||
|
|
300fb85a73 | ||
|
|
9c6e554153 | ||
|
|
b5c78b7225 | ||
|
|
26bd8cb53c | ||
|
|
a81c3187ba | ||
|
|
da6361f652 | ||
|
|
167fef5cff | ||
|
|
3233c63fc0 | ||
|
|
1182aaaf4d | ||
|
|
b78c061a8f | ||
|
|
39a5abc714 | ||
|
|
6650efc1a6 | ||
|
|
a4754ad195 | ||
|
|
91cbe5bc01 | ||
|
|
d2996dd553 | ||
|
|
7a7836ad90 | ||
|
|
7ca9242b24 | ||
|
|
ebfcf3ea07 | ||
|
|
62edea6b33 | ||
|
|
72eda9ce52 | ||
|
|
cfd84e54d5 | ||
|
|
cfe710f42b | ||
|
|
438f388b5c | ||
|
|
e89c77a5ca | ||
|
|
87e76bbcf5 | ||
|
|
0b4754ed60 | ||
|
|
fe6f05eec9 | ||
|
|
31984acfe0 | ||
|
|
9badfe7489 | ||
|
|
548256507d | ||
|
|
d8ebf7a136 | ||
|
|
27912bee8c | ||
|
|
a758b24b75 | ||
|
|
3004d4d93a | ||
|
|
88abf46fc3 | ||
|
|
2eeba0e999 | ||
|
|
397684fe49 | ||
|
|
bc1f769f13 | ||
|
|
f6592235a2 | ||
|
|
57805dafa4 | ||
|
|
3b92f979e3 | ||
|
|
7a7e4b4e6f | ||
|
|
c5843bee23 | ||
|
|
7aef182fbf | ||
|
|
2fb6ea7b77 | ||
|
|
add48da4c8 | ||
|
|
ada42b892c | ||
|
|
62f9261c4e | ||
|
|
a19b42f3c2 | ||
|
|
9f90f4f23a | ||
|
|
451c886f50 | ||
|
|
0a1a112605 | ||
|
|
d63d3bf1e7 | ||
|
|
33e5694a75 | ||
|
|
302ba725ae | ||
|
|
63cf7cbd94 | ||
|
|
8ab60c3a7a | ||
|
|
0342579b9c | ||
|
|
348401c4f4 | ||
|
|
8145199203 | ||
|
|
f408e938d4 | ||
|
|
6471ae4d49 | ||
|
|
af6e2b4cb6 | ||
|
|
7a4a52b50a | ||
|
|
ee05d8588f | ||
|
|
58175f647e | ||
|
|
5f7c68def7 | ||
|
|
82d019234a | ||
|
|
d618b8398e | ||
|
|
ec0e3e4cd6 | ||
|
|
db4ea020ba | ||
|
|
72cf84cb40 | ||
|
|
5366e8b692 | ||
|
|
6ca8f46d37 | ||
|
|
b2dfbb6ffd | ||
|
|
ffa7804af0 | ||
|
|
f454865b97 | ||
|
|
d83b1a5dbc | ||
|
|
d07f85e6ac | ||
|
|
a79c0f4c00 | ||
|
|
4a19740aea | ||
|
|
fbac4c61bb | ||
|
|
4dbaa2b5d6 | ||
|
|
9cad3c7aea | ||
|
|
56d66cdabc | ||
|
|
a0e5408850 | ||
|
|
d155e414a0 | ||
|
|
d81ddf246c | ||
|
|
ffe1bb359f | ||
|
|
88a39f8e16 | ||
|
|
9fb46ae88f | ||
|
|
798fb98b2a | ||
|
|
7c0af381d1 | ||
|
|
384f59eee2 | ||
|
|
127390978a | ||
|
|
baf3adf1c0 | ||
|
|
d0768cbc37 | ||
|
|
f00507449b | ||
|
|
509793d5c2 | ||
|
|
8dd0e7a794 | ||
|
|
8a8d169e27 | ||
|
|
b53cf0a1fb | ||
|
|
58fa99787c | ||
|
|
1a9a9f43e6 | ||
|
|
aeec4b7f77 | ||
|
|
40686f198c | ||
|
|
295af02744 | ||
|
|
a3f35f6367 | ||
|
|
523286bbcb | ||
|
|
c296f48ebe | ||
|
|
9609aced14 | ||
|
|
97788df7e3 | ||
|
|
47d4d56fa6 | ||
|
|
5e9c887385 | ||
|
|
fdb8ae5b53 | ||
|
|
65ff22d94b | ||
|
|
5cf093ca9e | ||
|
|
03ff28e927 | ||
|
|
16a1a90705 | ||
|
|
3221cbfa0a | ||
|
|
f0a8ccb177 | ||
|
|
a30705cdcc | ||
|
|
e2de55202f | ||
|
|
b4043840ca | ||
|
|
8f3e17e386 | ||
|
|
4e950e7256 | ||
|
|
de3e381ccf | ||
|
|
b2fde76753 | ||
|
|
b5587d8b87 | ||
|
|
9b75aeb224 | ||
|
|
993858cdc8 | ||
|
|
f4e1f07412 | ||
|
|
09e0de6053 | ||
|
|
9a50bf5237 | ||
|
|
5747009c8f | ||
|
|
dc513ec211 | ||
|
|
5f58d4f7b0 | ||
|
|
3536ceb5d3 | ||
|
|
7ed33a91c0 | ||
|
|
f8bf03d365 | ||
|
|
4202ee521a | ||
|
|
0e25fd42f9 | ||
|
|
feee5d1c8c | ||
|
|
ab6d92c544 | ||
|
|
d27d4abab7 | ||
|
|
3162cff7a9 | ||
|
|
74edf7a027 | ||
|
|
9681a27b31 | ||
|
|
22091f6182 | ||
|
|
ba534985ec | ||
|
|
edc1ae1e0c | ||
|
|
c00f3fb090 | ||
|
|
23bc25ef94 | ||
|
|
42dfa20fd4 | ||
|
|
cc2373ea89 | ||
|
|
22bc234ff3 | ||
|
|
fa48f9580f | ||
|
|
38ca14da43 | ||
|
|
74a56fc58a | ||
|
|
08ffbb61e9 | ||
|
|
232e60c8cb | ||
|
|
cd9ca76e39 | ||
|
|
c13d988392 | ||
|
|
15ffe2021a | ||
|
|
4fbc19e0d7 | ||
|
|
02f661a103 | ||
|
|
130638f6e1 | ||
|
|
9ab2761c1d | ||
|
|
41d7a549b0 | ||
|
|
2b8998fdd1 | ||
|
|
202ef31071 | ||
|
|
b09f2e836a | ||
|
|
6a814a0d91 | ||
|
|
b07bb9b3ff | ||
|
|
5120ed09ab | ||
|
|
081681f05b | ||
|
|
f7648e85d9 | ||
|
|
fe833e6d16 | ||
|
|
809f4eb609 | ||
|
|
61f3fc5ede | ||
|
|
90bbf90a83 | ||
|
|
92efc24283 | ||
|
|
1c45df4567 | ||
|
|
1575a93136 | ||
|
|
bde653b1c2 | ||
|
|
e9e663ffa3 | ||
|
|
963efa64c7 | ||
|
|
e2e5101005 | ||
|
|
6ea13cded3 | ||
|
|
c063b92cc9 | ||
|
|
304f133227 | ||
|
|
54a0dd0af6 | ||
|
|
54ee6bd46d | ||
|
|
f0e47f29fd | ||
|
|
ab5b7694c6 | ||
|
|
eb76dfb1ca | ||
|
|
28d7ec092c | ||
|
|
84b03f3a08 | ||
|
|
f9ac9867c1 | ||
|
|
ee6fb83265 | ||
|
|
46c16c963b | ||
|
|
32a68d489e | ||
|
|
7bbebff583 | ||
|
|
c432aec2f6 | ||
|
|
64237fbaa7 | ||
|
|
d90609b26c | ||
|
|
adec6cd254 | ||
|
|
5ce60cacbf | ||
|
|
9ddedb0b49 | ||
|
|
e977deaf11 | ||
|
|
85a7771b70 | ||
|
|
3778fef1a1 | ||
|
|
0bff720e20 | ||
|
|
7ba415dad1 | ||
|
|
7f47678862 | ||
|
|
127bac1147 | ||
|
|
9a90d795ca | ||
|
|
f7fe8f2f59 | ||
|
|
1d9c2aab8d | ||
|
|
8fba9c1236 | ||
|
|
04800ff677 | ||
|
|
5d3d1047a4 | ||
|
|
0f08c3bc9c | ||
|
|
7809b5a93f | ||
|
|
ef9bb53e67 | ||
|
|
3e32332814 | ||
|
|
e1aab25144 | ||
|
|
c8697301ee | ||
|
|
fcb1de915b | ||
|
|
e345294658 | ||
|
|
9936099e25 | ||
|
|
59352ad4d8 | ||
|
|
ba70f15de5 | ||
|
|
e70b069576 | ||
|
|
28bab4a323 | ||
|
|
6cc31b7453 | ||
|
|
29ca1504dd | ||
|
|
16d2251e43 | ||
|
|
bc2cc61240 | ||
|
|
6836e9c7a8 | ||
|
|
8dc016e7f9 | ||
|
|
3cad7984a3 | ||
|
|
f5bae98098 | ||
|
|
0695893e30 | ||
|
|
9ef6090c8c | ||
|
|
fa6f3e5fff | ||
|
|
ec0d9c389a | ||
|
|
323b07a2e4 | ||
|
|
c153d0455f | ||
|
|
9b00f1f2fb | ||
|
|
a055ff7db3 | ||
|
|
d032723a47 | ||
|
|
d60b09cafc | ||
|
|
daf83f596d | ||
|
|
1e3ea13323 | ||
|
|
4c8c48cde9 | ||
|
|
c8e50276e8 | ||
|
|
1e6419a63f | ||
|
|
875827f59b | ||
|
|
c4e08261b5 | ||
|
|
70f679d2fa | ||
|
|
25c43fa439 | ||
|
|
ec1c6325d4 | ||
|
|
309ff6be38 | ||
|
|
02d368df05 | ||
|
|
4ee1fe2ca4 | ||
|
|
4ff2ae9f4e | ||
|
|
7a729e8f16 | ||
|
|
3c7fd95617 | ||
|
|
5a2a8f9bd4 | ||
|
|
9854748fc3 | ||
|
|
5ae5a0cea3 | ||
|
|
01e5346004 | ||
|
|
1b34077f55 | ||
|
|
87fa698c79 | ||
|
|
b49afeefc2 | ||
|
|
8ace44b428 | ||
|
|
39a6c308fb | ||
|
|
2771b14f65 | ||
|
|
9ff09f28e7 | ||
|
|
eddd8313c9 | ||
|
|
c828867852 | ||
|
|
5fca47c5ec | ||
|
|
4cd3f0a8bb | ||
|
|
73653c348d | ||
|
|
0bc07f356d | ||
|
|
6d33d93b15 | ||
|
|
d54eed9d62 | ||
|
|
0fdfd91069 | ||
|
|
93577619b2 | ||
|
|
b602f67abe | ||
|
|
b67cdb171d | ||
|
|
c789172b89 | ||
|
|
1d68c4f075 | ||
|
|
df22fb5e00 | ||
|
|
5d2b0f74af | ||
|
|
723b8f1d32 | ||
|
|
5be5aa3dfa | ||
|
|
69e12fd67d | ||
|
|
49e23c74bc | ||
|
|
8b169f3796 | ||
|
|
b5da91b29a | ||
|
|
1d4ea56740 | ||
|
|
0d664b1fd2 | ||
|
|
29c3293265 | ||
|
|
df110e5e11 | ||
|
|
6247bd5f89 | ||
|
|
cba4752433 | ||
|
|
d0dd4e6e5e | ||
|
|
d2892ea249 | ||
|
|
983c28686f | ||
|
|
f2f1ad4605 | ||
|
|
10562e72f4 | ||
|
|
2dd29bee25 | ||
|
|
259a508d8a | ||
|
|
1963064369 | ||
|
|
a101ce803c | ||
|
|
fc0c7936d1 | ||
|
|
2d2add5b44 | ||
|
|
58fd5ddbaf | ||
|
|
70038e90ce | ||
|
|
49f2de9547 | ||
|
|
80eaafa001 | ||
|
|
cedc1d4e28 | ||
|
|
882e4971eb | ||
|
|
3a12a63c32 | ||
|
|
c1d31476cd | ||
|
|
b23b97f612 | ||
|
|
bd1789c54b | ||
|
|
5feececff6 | ||
|
|
87b0025691 | ||
|
|
e32747dc6f | ||
|
|
6936f6cd02 | ||
|
|
841619a7d2 | ||
|
|
905cc365e7 | ||
|
|
55266c4085 | ||
|
|
5f95a26218 | ||
|
|
91b7d4234e | ||
|
|
0280316b03 | ||
|
|
7afe87bb52 | ||
|
|
9632049bf2 | ||
|
|
13a6f04945 | ||
|
|
58a744782a | ||
|
|
63d5808848 | ||
|
|
a1541aa6f5 | ||
|
|
5f3c4fccaf |
@@ -33,4 +33,14 @@ export const packageOptions = {
|
|||||||
packageName: 'mermaid-layout-elk',
|
packageName: 'mermaid-layout-elk',
|
||||||
file: 'layouts.ts',
|
file: 'layouts.ts',
|
||||||
},
|
},
|
||||||
|
'mermaid-layout-tidy-tree': {
|
||||||
|
name: 'mermaid-layout-tidy-tree',
|
||||||
|
packageName: 'mermaid-layout-tidy-tree',
|
||||||
|
file: 'index.ts',
|
||||||
|
},
|
||||||
|
examples: {
|
||||||
|
name: 'mermaid-examples',
|
||||||
|
packageName: 'examples',
|
||||||
|
file: 'index.ts',
|
||||||
|
},
|
||||||
} as const satisfies Record<string, PackageOptions>;
|
} as const satisfies Record<string, PackageOptions>;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
|
|||||||
'block',
|
'block',
|
||||||
'packet',
|
'packet',
|
||||||
'architecture',
|
'architecture',
|
||||||
|
'radar',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -10,13 +10,16 @@ const buildType = (packageName: string) => {
|
|||||||
console.log(out.toString());
|
console.log(out.toString());
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
|
||||||
if (e.stdout.length > 0) {
|
if (e.stdout.length > 0) {
|
||||||
console.error(e.stdout.toString());
|
console.error(e.stdout.toString());
|
||||||
}
|
}
|
||||||
if (e.stderr.length > 0) {
|
if (e.stderr.length > 0) {
|
||||||
console.error(e.stderr.toString());
|
console.error(e.stderr.toString());
|
||||||
}
|
}
|
||||||
|
// Exit the build process if we are in CI
|
||||||
|
if (process.env.CI) {
|
||||||
|
throw new Error(`Failed to build types for ${packageName}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
'mermaid': patch
|
|
||||||
---
|
|
||||||
|
|
||||||
fix: architecture diagrams no longer grow to extreme heights due to conflicting alignments
|
|
||||||
5
.changeset/brave-baths-behave.md
Normal file
5
.changeset/brave-baths-behave.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: Prevent HTML tags from being escaped in sandbox label rendering
|
||||||
5
.changeset/brave-memes-flash.md
Normal file
5
.changeset/brave-memes-flash.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: Support edge animation in hand drawn look
|
||||||
5
.changeset/busy-mirrors-try.md
Normal file
5
.changeset/busy-mirrors-try.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: Resolved parsing error where direction TD was not recognized within subgraphs
|
||||||
5
.changeset/chatty-insects-dream.md
Normal file
5
.changeset/chatty-insects-dream.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(treemap): Fixed treemap classDef style application to properly apply user-defined styles
|
||||||
5
.changeset/chilly-words-march.md
Normal file
5
.changeset/chilly-words-march.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: Correct viewBox casing and make SVGs responsive
|
||||||
5
.changeset/curly-apes-prove.md
Normal file
5
.changeset/curly-apes-prove.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: Improve participant parsing and prevent recursive loops on invalid syntax
|
||||||
5
.changeset/lazy-brooms-battle.md
Normal file
5
.changeset/lazy-brooms-battle.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: add alias support for new participant syntax of sequence diagrams
|
||||||
5
.changeset/loud-results-melt.md
Normal file
5
.changeset/loud-results-melt.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: Add half-arrowheads (solid & stick) and central connection support
|
||||||
5
.changeset/short-seals-sort.md
Normal file
5
.changeset/short-seals-sort.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: allow to put notes in namespaces on classDiagram
|
||||||
5
.changeset/slow-lemons-know.md
Normal file
5
.changeset/slow-lemons-know.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'@mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: Mindmap breaking in ELK layout
|
||||||
5
.changeset/sweet-games-build.md
Normal file
5
.changeset/sweet-games-build.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(er-diagram): prevent syntax error when using 'u', numbers, and decimals in node names
|
||||||
5
.changeset/ten-plums-bet.md
Normal file
5
.changeset/ten-plums-bet.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: Support ComponentQueue_Ext to prevent parsing error
|
||||||
5
.changeset/tricky-rivers-stand.md
Normal file
5
.changeset/tricky-rivers-stand.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: validate dates and tick interval to prevent UI freeze/crash in gantt diagramtype
|
||||||
5
.changeset/wide-lines-trade.md
Normal file
5
.changeset/wide-lines-trade.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: Mindmap rendering issue when the number of Level 2 nodes exceeds 11
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
!viewbox
|
||||||
|
# It should be viewBox
|
||||||
# This file contains coding related terms
|
# This file contains coding related terms
|
||||||
ALPHANUM
|
ALPHANUM
|
||||||
antiscript
|
antiscript
|
||||||
@@ -47,13 +49,13 @@ edgesep
|
|||||||
EMPTYSTR
|
EMPTYSTR
|
||||||
enddate
|
enddate
|
||||||
ERDIAGRAM
|
ERDIAGRAM
|
||||||
|
eslint
|
||||||
flatmap
|
flatmap
|
||||||
forwardable
|
forwardable
|
||||||
frontmatter
|
frontmatter
|
||||||
funs
|
funs
|
||||||
gantt
|
gantt
|
||||||
GENERICTYPE
|
GENERICTYPE
|
||||||
getBoundarys
|
|
||||||
grammr
|
grammr
|
||||||
graphtype
|
graphtype
|
||||||
halign
|
halign
|
||||||
@@ -88,6 +90,7 @@ NODIR
|
|||||||
NSTR
|
NSTR
|
||||||
outdir
|
outdir
|
||||||
Qcontrolx
|
Qcontrolx
|
||||||
|
QSTR
|
||||||
reinit
|
reinit
|
||||||
rels
|
rels
|
||||||
reqs
|
reqs
|
||||||
|
|||||||
@@ -2,8 +2,11 @@
|
|||||||
Ashish Jain
|
Ashish Jain
|
||||||
cpettitt
|
cpettitt
|
||||||
Dong Cai
|
Dong Cai
|
||||||
|
fourcube
|
||||||
|
knsv
|
||||||
|
Knut Sveidqvist
|
||||||
Nikolay Rozhkov
|
Nikolay Rozhkov
|
||||||
Peng Xiao
|
Peng Xiao
|
||||||
Per Brolin
|
Per Brolin
|
||||||
|
Sidharth Vinod
|
||||||
subhash-halder
|
subhash-halder
|
||||||
Vinod Sidharth
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ dompurify
|
|||||||
elkjs
|
elkjs
|
||||||
fcose
|
fcose
|
||||||
fontawesome
|
fontawesome
|
||||||
|
Fonticons
|
||||||
|
Forgejo
|
||||||
Foswiki
|
Foswiki
|
||||||
Gitea
|
Gitea
|
||||||
graphlib
|
graphlib
|
||||||
@@ -62,6 +64,7 @@ rscratch
|
|||||||
shiki
|
shiki
|
||||||
Slidev
|
Slidev
|
||||||
sparkline
|
sparkline
|
||||||
|
speccharts
|
||||||
sphinxcontrib
|
sphinxcontrib
|
||||||
ssim
|
ssim
|
||||||
stylis
|
stylis
|
||||||
|
|||||||
@@ -5,19 +5,20 @@ bmatrix
|
|||||||
braintree
|
braintree
|
||||||
catmull
|
catmull
|
||||||
compositTitleSize
|
compositTitleSize
|
||||||
|
cose
|
||||||
curv
|
curv
|
||||||
doublecircle
|
doublecircle
|
||||||
|
elem
|
||||||
elems
|
elems
|
||||||
gantt
|
gantt
|
||||||
gitgraph
|
gitgraph
|
||||||
gzipped
|
gzipped
|
||||||
handDrawn
|
handDrawn
|
||||||
kanban
|
kanban
|
||||||
knsv
|
|
||||||
Knut
|
|
||||||
marginx
|
marginx
|
||||||
marginy
|
marginy
|
||||||
Markdownish
|
Markdownish
|
||||||
|
mermaidchart
|
||||||
mermaidjs
|
mermaidjs
|
||||||
mindmap
|
mindmap
|
||||||
mindmaps
|
mindmaps
|
||||||
@@ -35,7 +36,6 @@ sandboxed
|
|||||||
siebling
|
siebling
|
||||||
statediagram
|
statediagram
|
||||||
substate
|
substate
|
||||||
Sveidqvist
|
|
||||||
unfixable
|
unfixable
|
||||||
Viewbox
|
Viewbox
|
||||||
viewports
|
viewports
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
BRANDES
|
BRANDES
|
||||||
|
Buzan
|
||||||
circo
|
circo
|
||||||
handDrawn
|
handDrawn
|
||||||
KOEPF
|
KOEPF
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { build } from 'esbuild';
|
import { build } from 'esbuild';
|
||||||
import { mkdir, writeFile } from 'node:fs/promises';
|
import { cp, mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
||||||
import { packageOptions } from '../.build/common.js';
|
import { packageOptions } from '../.build/common.js';
|
||||||
import { generateLangium } from '../.build/generateLangium.js';
|
import { generateLangium } from '../.build/generateLangium.js';
|
||||||
import type { MermaidBuildOptions } from './util.js';
|
import type { MermaidBuildOptions } from './util.js';
|
||||||
@@ -31,6 +31,27 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => {
|
|||||||
// mermaid.js
|
// mermaid.js
|
||||||
{ ...iifeOptions },
|
{ ...iifeOptions },
|
||||||
// mermaid.min.js
|
// mermaid.min.js
|
||||||
|
{ ...iifeOptions, minify: true, metafile: shouldVisualize },
|
||||||
|
// mermaid.tiny.min.js
|
||||||
|
{
|
||||||
|
...iifeOptions,
|
||||||
|
minify: true,
|
||||||
|
includeLargeFeatures: false,
|
||||||
|
metafile: shouldVisualize,
|
||||||
|
sourcemap: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (entryName === 'mermaid-zenuml') {
|
||||||
|
const iifeOptions: MermaidBuildOptions = {
|
||||||
|
...commonOptions,
|
||||||
|
format: 'iife',
|
||||||
|
globalName: 'mermaid-zenuml',
|
||||||
|
};
|
||||||
|
buildConfigs.push(
|
||||||
|
// mermaid-zenuml.js
|
||||||
|
{ ...iifeOptions },
|
||||||
|
// mermaid-zenuml.min.js
|
||||||
{ ...iifeOptions, minify: true, metafile: shouldVisualize }
|
{ ...iifeOptions, minify: true, metafile: shouldVisualize }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -57,6 +78,21 @@ const handler = (e) => {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const buildTinyMermaid = async () => {
|
||||||
|
await mkdir('./packages/tiny/dist', { recursive: true });
|
||||||
|
await rename(
|
||||||
|
'./packages/mermaid/dist/mermaid.tiny.min.js',
|
||||||
|
'./packages/tiny/dist/mermaid.tiny.js'
|
||||||
|
);
|
||||||
|
// Copy version from mermaid's package.json to tiny's package.json
|
||||||
|
const mermaidPkg = JSON.parse(await readFile('./packages/mermaid/package.json', 'utf8'));
|
||||||
|
const tinyPkg = JSON.parse(await readFile('./packages/tiny/package.json', 'utf8'));
|
||||||
|
tinyPkg.version = mermaidPkg.version;
|
||||||
|
|
||||||
|
await writeFile('./packages/tiny/package.json', JSON.stringify(tinyPkg, null, 2) + '\n');
|
||||||
|
await cp('./packages/mermaid/CHANGELOG.md', './packages/tiny/CHANGELOG.md');
|
||||||
|
};
|
||||||
|
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
await generateLangium();
|
await generateLangium();
|
||||||
await mkdir('stats', { recursive: true });
|
await mkdir('stats', { recursive: true });
|
||||||
@@ -65,6 +101,7 @@ const main = async () => {
|
|||||||
for (const pkg of packageNames) {
|
for (const pkg of packageNames) {
|
||||||
await buildPackage(pkg).catch(handler);
|
await buildPackage(pkg).catch(handler);
|
||||||
}
|
}
|
||||||
|
await buildTinyMermaid();
|
||||||
};
|
};
|
||||||
|
|
||||||
void main();
|
void main();
|
||||||
|
|||||||
53
.esbuild/dev-explorer/ARCHITECTURE.md
Normal file
53
.esbuild/dev-explorer/ARCHITECTURE.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Dev Explorer frontend: architecture + debugging notes
|
||||||
|
|
||||||
|
## Root cause of the “CSS changes do nothing” problem
|
||||||
|
|
||||||
|
The page loads `/dev/styles.css`, but **document-level CSS does not apply through a shadow DOM boundary**.
|
||||||
|
|
||||||
|
Historically, `dev-explorer-app` was a `LitElement` using Lit’s default `shadowRoot`, while the rest of the UI used light DOM. That meant:
|
||||||
|
|
||||||
|
- The browser showed the _right classes_ (`card`, `card-folder`, `card-file`) in Elements panel.
|
||||||
|
- `/dev/styles.css` was clearly being served/updated.
|
||||||
|
- Yet computed styles for `.card` looked like UA defaults because the selector never matched across the shadow root.
|
||||||
|
|
||||||
|
Fix: make `dev-explorer-app` light DOM too (`createRenderRoot() { return this; }`), so `/dev/styles.css` reliably styles the whole UI.
|
||||||
|
|
||||||
|
## Debugging traps (and fast detection)
|
||||||
|
|
||||||
|
- **Shadow DOM trap**
|
||||||
|
- Symptom: “CSS is loaded but doesn’t apply”, especially for simple class selectors.
|
||||||
|
- Fast check:
|
||||||
|
- DevTools console: `document.querySelector('dev-explorer-app')?.shadowRoot`
|
||||||
|
- If non-null, global CSS won’t style inside it.
|
||||||
|
- Or: right-click an element you expect styled → “Reveal in Elements” → see if it’s under `#shadow-root`.
|
||||||
|
|
||||||
|
- **“Light DOM child inside shadow DOM parent” trap**
|
||||||
|
- Even if a child component uses `createRenderRoot() { return this; }`,
|
||||||
|
if it’s _rendered inside the parent’s shadow root_, it’s still effectively in shadow for document styles.
|
||||||
|
|
||||||
|
- **Dev loop trap (CSS-only changes don’t trigger reload)**
|
||||||
|
- The server watches TypeScript bundle inputs + `.mmd` files; static `/dev/styles.css` previously didn’t emit SSE reload events.
|
||||||
|
- That makes CSS changes look flaky unless you manually refresh.
|
||||||
|
- Fix: watch `.esbuild/dev-explorer/public/**/*` and emit SSE on changes.
|
||||||
|
|
||||||
|
- **Caching trap (less common here, but real)**
|
||||||
|
- If a query param is constant (`?v=3`) and you don’t reload, the browser can keep a cached stylesheet.
|
||||||
|
- Fast check: DevTools → Network → disable cache + hard reload; or check “(from disk cache)” on the CSS request.
|
||||||
|
|
||||||
|
## Styling strategy recommendation (pragmatic)
|
||||||
|
|
||||||
|
For a dev-only explorer, keep it simple:
|
||||||
|
|
||||||
|
- **Light DOM everywhere**
|
||||||
|
- **One stylesheet**: `.esbuild/dev-explorer/public/styles.css` served as `/dev/styles.css`
|
||||||
|
- **Scoped selectors** under `dev-explorer-app` to avoid generic class collisions (`.header`, `.content`, etc.)
|
||||||
|
|
||||||
|
If you later _want_ Shadow DOM isolation, do it deliberately:
|
||||||
|
|
||||||
|
- Put UI styles in Lit `static styles` or adopt a `CSSStyleSheet` into `this.renderRoot.adoptedStyleSheets`.
|
||||||
|
- Avoid relying on document CSS selectors for component internals.
|
||||||
|
|
||||||
|
## Shoelace integration notes
|
||||||
|
|
||||||
|
- Current setup is correct for dev: `setBasePath('/dev/vendor/shoelace')` and `registerIconLibrary(...)`.
|
||||||
|
- Prefer theming via CSS variables (Shoelace tokens) rather than overriding internal parts everywhere.
|
||||||
187
.esbuild/dev-explorer/console-panel.ts
Normal file
187
.esbuild/dev-explorer/console-panel.ts
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
import { LitElement, html } from 'lit';
|
||||||
|
|
||||||
|
import '@shoelace-style/shoelace/dist/components/input/input.js';
|
||||||
|
|
||||||
|
export type LogLevel = 'info' | 'warn' | 'error';
|
||||||
|
|
||||||
|
export type LogEntry = {
|
||||||
|
ts: number;
|
||||||
|
level: LogLevel;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function formatTs(ts: number) {
|
||||||
|
const d = new Date(ts);
|
||||||
|
return (
|
||||||
|
d.toLocaleTimeString(undefined, { hour12: false }) +
|
||||||
|
'.' +
|
||||||
|
String(d.getMilliseconds()).padStart(3, '0')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function levelVariant(level: LogLevel) {
|
||||||
|
switch (level) {
|
||||||
|
case 'error':
|
||||||
|
return 'danger';
|
||||||
|
case 'warn':
|
||||||
|
return 'warning';
|
||||||
|
default:
|
||||||
|
return 'neutral';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type DisplayLevel = 'debug' | LogLevel;
|
||||||
|
|
||||||
|
function displayLevel(entry: LogEntry): DisplayLevel {
|
||||||
|
// Mermaid often emits debug lines through console.log/info with a marker.
|
||||||
|
if (entry.message.includes(': DEBUG :')) return 'debug';
|
||||||
|
return entry.level;
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayVariant(level: DisplayLevel) {
|
||||||
|
switch (level) {
|
||||||
|
case 'error':
|
||||||
|
return 'danger';
|
||||||
|
case 'warn':
|
||||||
|
return 'warning';
|
||||||
|
case 'debug':
|
||||||
|
return 'success';
|
||||||
|
default:
|
||||||
|
return 'neutral';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DevConsolePanel extends LitElement {
|
||||||
|
static properties = {
|
||||||
|
logs: { state: true },
|
||||||
|
showInfo: { state: true },
|
||||||
|
showWarn: { state: true },
|
||||||
|
showError: { state: true },
|
||||||
|
showDebug: { state: true },
|
||||||
|
filterText: { state: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
declare logs: LogEntry[];
|
||||||
|
declare showInfo: boolean;
|
||||||
|
declare showWarn: boolean;
|
||||||
|
declare showError: boolean;
|
||||||
|
declare showDebug: boolean;
|
||||||
|
declare filterText: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.logs = [];
|
||||||
|
this.showInfo = true;
|
||||||
|
this.showWarn = true;
|
||||||
|
this.showError = true;
|
||||||
|
this.showDebug = true;
|
||||||
|
this.filterText = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
createRenderRoot() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.logs = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
append(entry: LogEntry) {
|
||||||
|
this.logs = [...this.logs, entry];
|
||||||
|
}
|
||||||
|
|
||||||
|
async copyVisible() {
|
||||||
|
const visible = this.filteredLogs();
|
||||||
|
const text = visible
|
||||||
|
.map((l) => `[${formatTs(l.ts)}] ${l.level.toUpperCase()} ${l.message}`)
|
||||||
|
.join('\n');
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredLogs() {
|
||||||
|
const q = this.filterText.trim().toLowerCase();
|
||||||
|
return this.logs.filter((l) => {
|
||||||
|
const isDebugLine = l.message.includes(': DEBUG :');
|
||||||
|
// Treat debug-marked lines as their own independent toggle, since Mermaid often routes them through
|
||||||
|
// console.log/info with a marker rather than a distinct "debug" level.
|
||||||
|
if (isDebugLine && !this.showDebug) return false;
|
||||||
|
|
||||||
|
if (!isDebugLine) {
|
||||||
|
const levelOk =
|
||||||
|
l.level === 'info' ? this.showInfo : l.level === 'warn' ? this.showWarn : this.showError;
|
||||||
|
if (!levelOk) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!q) return true;
|
||||||
|
return l.message.toLowerCase().includes(q);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const visible = this.filteredLogs();
|
||||||
|
return html`
|
||||||
|
<div class="console">
|
||||||
|
<div class="console-toolbar">
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<sl-input
|
||||||
|
size="small"
|
||||||
|
placeholder="filter…"
|
||||||
|
clearable
|
||||||
|
value=${this.filterText}
|
||||||
|
@sl-input=${(e: any) => (this.filterText = e.target.value ?? '')}
|
||||||
|
></sl-input>
|
||||||
|
<sl-checkbox
|
||||||
|
size="small"
|
||||||
|
?checked=${this.showDebug}
|
||||||
|
@sl-change=${(e: any) => (this.showDebug = e.target.checked)}
|
||||||
|
>debug</sl-checkbox
|
||||||
|
>
|
||||||
|
<sl-checkbox
|
||||||
|
size="small"
|
||||||
|
?checked=${this.showInfo}
|
||||||
|
@sl-change=${(e: any) => (this.showInfo = e.target.checked)}
|
||||||
|
>info</sl-checkbox
|
||||||
|
>
|
||||||
|
<sl-checkbox
|
||||||
|
size="small"
|
||||||
|
?checked=${this.showWarn}
|
||||||
|
@sl-change=${(e: any) => (this.showWarn = e.target.checked)}
|
||||||
|
>warn</sl-checkbox
|
||||||
|
>
|
||||||
|
<sl-checkbox
|
||||||
|
size="small"
|
||||||
|
?checked=${this.showError}
|
||||||
|
@sl-change=${(e: any) => (this.showError = e.target.checked)}
|
||||||
|
>error</sl-checkbox
|
||||||
|
>
|
||||||
|
<sl-button size="small" variant="default" @click=${() => void this.copyVisible()}>
|
||||||
|
<sl-icon slot="prefix" name="clipboard"></sl-icon>
|
||||||
|
Copy
|
||||||
|
</sl-button>
|
||||||
|
<sl-button size="small" variant="default" @click=${() => this.clear()}>
|
||||||
|
<sl-icon slot="prefix" name="trash"></sl-icon>
|
||||||
|
Clear
|
||||||
|
</sl-button>
|
||||||
|
</div>
|
||||||
|
<div class="console-body">
|
||||||
|
${visible.length === 0
|
||||||
|
? html`<div class="empty">No logs yet.</div>`
|
||||||
|
: visible.map((l) => {
|
||||||
|
const lvl = displayLevel(l);
|
||||||
|
return html`
|
||||||
|
<div class="logline">
|
||||||
|
<div class="logmeta">
|
||||||
|
<sl-badge variant=${displayVariant(lvl)}>${lvl}</sl-badge>
|
||||||
|
<span class="path">${formatTs(l.ts)}</span>
|
||||||
|
</div>
|
||||||
|
<div>${l.message}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('dev-console-panel', DevConsolePanel);
|
||||||
551
.esbuild/dev-explorer/diagram-viewer.ts
Normal file
551
.esbuild/dev-explorer/diagram-viewer.ts
Normal file
@@ -0,0 +1,551 @@
|
|||||||
|
import { LitElement, html, nothing } from 'lit';
|
||||||
|
|
||||||
|
import '@shoelace-style/shoelace/dist/components/button/button.js';
|
||||||
|
import '@shoelace-style/shoelace/dist/components/icon/icon.js';
|
||||||
|
import '@shoelace-style/shoelace/dist/components/select/select.js';
|
||||||
|
import '@shoelace-style/shoelace/dist/components/option/option.js';
|
||||||
|
import '@shoelace-style/shoelace/dist/components/checkbox/checkbox.js';
|
||||||
|
import '@shoelace-style/shoelace/dist/components/split-panel/split-panel.js';
|
||||||
|
|
||||||
|
import './console-panel';
|
||||||
|
import type { LogEntry, LogLevel } from './console-panel';
|
||||||
|
|
||||||
|
type MermaidIife = {
|
||||||
|
initialize: (config: Record<string, unknown>) => void | Promise<void>;
|
||||||
|
render: (
|
||||||
|
id: string,
|
||||||
|
text: string,
|
||||||
|
container?: Element
|
||||||
|
) => Promise<{ svg: string; bindFunctions?: (el: Element) => void }>;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
mermaid?: MermaidIife;
|
||||||
|
mermaidReady?: Promise<MermaidIife>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyArgs(args: unknown[]) {
|
||||||
|
// Mermaid's internal logger frequently uses console formatting like:
|
||||||
|
// console.log('%c...message...', 'color: lightgreen', ...)
|
||||||
|
// For the log panel we want the human text, not the formatting tokens/styles.
|
||||||
|
let normalized = [...args];
|
||||||
|
if (typeof normalized[0] === 'string') {
|
||||||
|
const fmt = normalized[0];
|
||||||
|
const cssCount = (fmt.match(/%c/g) ?? []).length;
|
||||||
|
if (cssCount > 0) {
|
||||||
|
normalized[0] = fmt.replaceAll('%c', '');
|
||||||
|
// Drop the corresponding CSS args that follow the format string.
|
||||||
|
normalized.splice(1, cssCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized
|
||||||
|
.map((a) => {
|
||||||
|
if (typeof a === 'string') return a;
|
||||||
|
if (a instanceof Error) return a.stack ?? a.message;
|
||||||
|
try {
|
||||||
|
return JSON.stringify(a);
|
||||||
|
} catch {
|
||||||
|
return String(a);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.join(' ')
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
type MermaidTheme = 'default' | 'dark' | 'forest' | 'neutral' | 'base';
|
||||||
|
type MermaidLayout = 'dagre' | 'elk';
|
||||||
|
type MermaidLogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
||||||
|
|
||||||
|
const DEFAULT_THEME: MermaidTheme = 'default';
|
||||||
|
const DEFAULT_LAYOUT: MermaidLayout = 'dagre';
|
||||||
|
const DEFAULT_MERMAID_LOG_LEVEL: MermaidLogLevel = 'warn';
|
||||||
|
|
||||||
|
function readUrlParam(name: string) {
|
||||||
|
try {
|
||||||
|
return new URL(window.location.href).searchParams.get(name);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUrlParams(pairs: Record<string, string | null | undefined>) {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
for (const [k, v] of Object.entries(pairs)) {
|
||||||
|
if (!v) url.searchParams.delete(k);
|
||||||
|
else url.searchParams.set(k, v);
|
||||||
|
}
|
||||||
|
history.replaceState(null, '', url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readStorage(key: string) {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(key);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeStorage(key: string, value: string) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(key, value);
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTheme(v: unknown): v is MermaidTheme {
|
||||||
|
return v === 'default' || v === 'dark' || v === 'forest' || v === 'neutral' || v === 'base';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLayout(v: unknown): v is MermaidLayout {
|
||||||
|
return v === 'dagre' || v === 'elk';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMermaidLogLevel(v: unknown): v is MermaidLogLevel {
|
||||||
|
return (
|
||||||
|
v === 'trace' || v === 'debug' || v === 'info' || v === 'warn' || v === 'error' || v === 'fatal'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeLayout(v: unknown): MermaidLayout | null {
|
||||||
|
// Back-compat:
|
||||||
|
// - older UI used `renderer=dagre-d3|dagre-wrapper|elk`
|
||||||
|
// - new UI uses `layout=dagre|elk`
|
||||||
|
if (v === 'dagre' || v === 'elk') return v;
|
||||||
|
if (v === 'dagre-d3' || v === 'dagre-wrapper') return 'dagre';
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseBoolean(v: unknown): boolean | null {
|
||||||
|
if (typeof v !== 'string') return null;
|
||||||
|
const s = v.trim().toLowerCase();
|
||||||
|
if (['1', 'true', 'yes', 'on'].includes(s)) return true;
|
||||||
|
if (['0', 'false', 'no', 'off'].includes(s)) return false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DevDiagramViewer extends LitElement {
|
||||||
|
static properties = {
|
||||||
|
filePath: { type: String },
|
||||||
|
sseToken: { type: Number },
|
||||||
|
theme: { state: true },
|
||||||
|
layout: { state: true },
|
||||||
|
mermaidLogLevel: { state: true },
|
||||||
|
useMaxWidth: { state: true },
|
||||||
|
loading: { state: true },
|
||||||
|
error: { state: true },
|
||||||
|
source: { state: true },
|
||||||
|
svg: { state: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
declare filePath: string;
|
||||||
|
declare sseToken: number;
|
||||||
|
declare theme: MermaidTheme;
|
||||||
|
declare layout: MermaidLayout;
|
||||||
|
declare mermaidLogLevel: MermaidLogLevel;
|
||||||
|
declare useMaxWidth: boolean;
|
||||||
|
declare loading: boolean;
|
||||||
|
declare error: string;
|
||||||
|
declare source: string;
|
||||||
|
declare svg: string;
|
||||||
|
|
||||||
|
#renderSeq = 0;
|
||||||
|
#consolePatched = false;
|
||||||
|
#originalConsole?: {
|
||||||
|
log: typeof console.log;
|
||||||
|
info: typeof console.info;
|
||||||
|
debug: typeof console.debug;
|
||||||
|
warn: typeof console.warn;
|
||||||
|
error: typeof console.error;
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const themeParam = readUrlParam('theme');
|
||||||
|
const layoutParam = readUrlParam('layout');
|
||||||
|
const rendererParam = readUrlParam('renderer'); // legacy
|
||||||
|
const logParam = readUrlParam('logLevel');
|
||||||
|
const useMaxWidthParam = readUrlParam('useMaxWidth');
|
||||||
|
|
||||||
|
const storedTheme = readStorage('devExplorer.viewer.theme');
|
||||||
|
const storedLayout = readStorage('devExplorer.viewer.layout');
|
||||||
|
const storedRenderer = readStorage('devExplorer.viewer.renderer'); // legacy
|
||||||
|
const storedLog = readStorage('devExplorer.viewer.logLevel');
|
||||||
|
const storedUseMaxWidth = readStorage('devExplorer.viewer.useMaxWidth');
|
||||||
|
|
||||||
|
this.theme = isTheme(themeParam)
|
||||||
|
? themeParam
|
||||||
|
: isTheme(storedTheme)
|
||||||
|
? storedTheme
|
||||||
|
: DEFAULT_THEME;
|
||||||
|
this.layout =
|
||||||
|
normalizeLayout(layoutParam) ??
|
||||||
|
normalizeLayout(rendererParam) ??
|
||||||
|
normalizeLayout(storedLayout) ??
|
||||||
|
normalizeLayout(storedRenderer) ??
|
||||||
|
DEFAULT_LAYOUT;
|
||||||
|
this.mermaidLogLevel = isMermaidLogLevel(logParam)
|
||||||
|
? logParam
|
||||||
|
: isMermaidLogLevel(storedLog)
|
||||||
|
? storedLog
|
||||||
|
: DEFAULT_MERMAID_LOG_LEVEL;
|
||||||
|
|
||||||
|
this.useMaxWidth = parseBoolean(useMaxWidthParam) ?? parseBoolean(storedUseMaxWidth) ?? true;
|
||||||
|
|
||||||
|
this.filePath = '';
|
||||||
|
this.sseToken = 0;
|
||||||
|
this.loading = true;
|
||||||
|
this.error = '';
|
||||||
|
this.source = '';
|
||||||
|
this.svg = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
createRenderRoot() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.#installConsoleCapture();
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
this.#restoreConsoleCapture();
|
||||||
|
}
|
||||||
|
|
||||||
|
updated(changed: Map<string, unknown>) {
|
||||||
|
if (changed.has('filePath')) {
|
||||||
|
void this.#loadAndRender();
|
||||||
|
} else if (changed.has('sseToken')) {
|
||||||
|
// On rebuild events, re-fetch + re-render the currently open diagram.
|
||||||
|
if (this.filePath) void this.#loadAndRender();
|
||||||
|
} else if (
|
||||||
|
changed.has('theme') ||
|
||||||
|
changed.has('layout') ||
|
||||||
|
changed.has('mermaidLogLevel') ||
|
||||||
|
changed.has('useMaxWidth')
|
||||||
|
) {
|
||||||
|
// Re-render the currently loaded diagram with the new config without refetching.
|
||||||
|
if (this.source) void this.#renderCurrentSource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#back() {
|
||||||
|
this.dispatchEvent(new CustomEvent('back', { bubbles: true, composed: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
#persistSettings() {
|
||||||
|
writeStorage('devExplorer.viewer.theme', this.theme);
|
||||||
|
writeStorage('devExplorer.viewer.layout', this.layout);
|
||||||
|
writeStorage('devExplorer.viewer.logLevel', this.mermaidLogLevel);
|
||||||
|
writeStorage('devExplorer.viewer.useMaxWidth', String(this.useMaxWidth));
|
||||||
|
setUrlParams({
|
||||||
|
theme: this.theme,
|
||||||
|
layout: this.layout,
|
||||||
|
renderer: null, // drop legacy param
|
||||||
|
logLevel: this.mermaidLogLevel,
|
||||||
|
useMaxWidth: this.useMaxWidth ? '1' : '0',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#syncConsolePanelFilters() {
|
||||||
|
const panel = this.querySelector('dev-console-panel') as any;
|
||||||
|
if (!panel) return;
|
||||||
|
// This is intentionally opinionated: less noise by default as logLevel increases.
|
||||||
|
if (
|
||||||
|
this.mermaidLogLevel === 'trace' ||
|
||||||
|
this.mermaidLogLevel === 'debug' ||
|
||||||
|
this.mermaidLogLevel === 'info'
|
||||||
|
) {
|
||||||
|
panel.showInfo = true;
|
||||||
|
panel.showWarn = true;
|
||||||
|
panel.showError = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.mermaidLogLevel === 'warn') {
|
||||||
|
panel.showInfo = false;
|
||||||
|
panel.showWarn = true;
|
||||||
|
panel.showError = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// error / fatal
|
||||||
|
panel.showInfo = false;
|
||||||
|
panel.showWarn = false;
|
||||||
|
panel.showError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appendLog(entry: LogEntry) {
|
||||||
|
const panel = this.querySelector('dev-console-panel') as any;
|
||||||
|
panel?.append?.(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
#installConsoleCapture() {
|
||||||
|
if (this.#consolePatched) return;
|
||||||
|
this.#consolePatched = true;
|
||||||
|
|
||||||
|
this.#originalConsole = {
|
||||||
|
log: console.log,
|
||||||
|
info: console.info,
|
||||||
|
debug: console.debug,
|
||||||
|
warn: console.warn,
|
||||||
|
error: console.error,
|
||||||
|
};
|
||||||
|
|
||||||
|
const capture = (level: LogLevel, args: unknown[]) => {
|
||||||
|
this.#appendLog({
|
||||||
|
ts: Date.now(),
|
||||||
|
level,
|
||||||
|
message: stringifyArgs(args),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mermaid uses its own logger which routes to console.info/debug/warn/error.
|
||||||
|
// Capture those too (map debug/info/log -> panel "info").
|
||||||
|
console.log = (...args) => {
|
||||||
|
capture('info', args);
|
||||||
|
this.#originalConsole!.log.apply(console, args as any);
|
||||||
|
};
|
||||||
|
console.info = (...args) => {
|
||||||
|
capture('info', args);
|
||||||
|
this.#originalConsole!.info.apply(console, args as any);
|
||||||
|
};
|
||||||
|
console.debug = (...args) => {
|
||||||
|
capture('info', args);
|
||||||
|
this.#originalConsole!.debug.apply(console, args as any);
|
||||||
|
};
|
||||||
|
console.warn = (...args) => {
|
||||||
|
capture('warn', args);
|
||||||
|
this.#originalConsole!.warn.apply(console, args as any);
|
||||||
|
};
|
||||||
|
console.error = (...args) => {
|
||||||
|
capture('error', args);
|
||||||
|
this.#originalConsole!.error.apply(console, args as any);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#restoreConsoleCapture() {
|
||||||
|
if (!this.#consolePatched) return;
|
||||||
|
this.#consolePatched = false;
|
||||||
|
if (!this.#originalConsole) return;
|
||||||
|
console.log = this.#originalConsole.log;
|
||||||
|
console.info = this.#originalConsole.info;
|
||||||
|
console.debug = this.#originalConsole.debug;
|
||||||
|
console.warn = this.#originalConsole.warn;
|
||||||
|
console.error = this.#originalConsole.error;
|
||||||
|
this.#originalConsole = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
#clearLogs() {
|
||||||
|
const panel = this.querySelector('dev-console-panel') as any;
|
||||||
|
panel?.clear?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
async #fetchSource() {
|
||||||
|
const url = new URL('/dev/api/file', window.location.origin);
|
||||||
|
url.searchParams.set('path', this.filePath);
|
||||||
|
const res = await fetch(url);
|
||||||
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
|
return await res.text();
|
||||||
|
}
|
||||||
|
|
||||||
|
async #loadAndRender() {
|
||||||
|
const seq = ++this.#renderSeq;
|
||||||
|
this.loading = true;
|
||||||
|
this.error = '';
|
||||||
|
this.svg = '';
|
||||||
|
this.#clearLogs();
|
||||||
|
this.#syncConsolePanelFilters();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const source = await this.#fetchSource();
|
||||||
|
if (seq !== this.#renderSeq) return;
|
||||||
|
this.source = source;
|
||||||
|
await this.#renderMermaid(source);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e instanceof Error ? e.message : String(e);
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async #renderCurrentSource() {
|
||||||
|
const seq = ++this.#renderSeq;
|
||||||
|
this.loading = true;
|
||||||
|
this.error = '';
|
||||||
|
this.svg = '';
|
||||||
|
this.#clearLogs();
|
||||||
|
this.#syncConsolePanelFilters();
|
||||||
|
try {
|
||||||
|
const source = this.source;
|
||||||
|
if (!source) return;
|
||||||
|
if (seq !== this.#renderSeq) return;
|
||||||
|
await this.#renderMermaid(source);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e instanceof Error ? e.message : String(e);
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async #renderMermaid(text: string) {
|
||||||
|
const m = (await window.mermaidReady?.catch(() => undefined)) ?? window.mermaid;
|
||||||
|
if (!m) {
|
||||||
|
throw new Error(
|
||||||
|
'window.mermaid is not available (did /mermaid.esm.mjs load and did the bootstrap set window.mermaid?)'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const initConfig = {
|
||||||
|
startOnLoad: false,
|
||||||
|
securityLevel: 'strict',
|
||||||
|
theme: this.theme,
|
||||||
|
layout: this.layout,
|
||||||
|
logLevel: this.mermaidLogLevel,
|
||||||
|
flowchart: {
|
||||||
|
useMaxWidth: this.useMaxWidth,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Debugging aid: log exactly what we are about to initialize/render with.
|
||||||
|
// Do it *before* initialize so detector issues can be correlated.
|
||||||
|
const previewLimit = 4000;
|
||||||
|
const preview =
|
||||||
|
text.length > previewLimit
|
||||||
|
? `${text.slice(0, previewLimit)}\n… (${text.length - previewLimit} more chars)`
|
||||||
|
: text;
|
||||||
|
console.log('[dev-explorer] mermaid.initialize config:', initConfig);
|
||||||
|
console.log('[dev-explorer] diagram source preview:\n' + preview);
|
||||||
|
|
||||||
|
// Keep it deterministic-ish between reloads.
|
||||||
|
await m.initialize(initConfig);
|
||||||
|
|
||||||
|
const id = `dev-explorer-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
||||||
|
const { svg, bindFunctions } = await m.render(id, text);
|
||||||
|
this.svg = svg;
|
||||||
|
// Allow mermaid to attach event handlers (e.g. links).
|
||||||
|
await this.updateComplete;
|
||||||
|
// If the page ever ended up scrolled down due to a previous oversized render, snap back to top.
|
||||||
|
// (We intentionally removed vertical scrollbars in the viewer.)
|
||||||
|
try {
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
const container = this.querySelector('.diagram-inner');
|
||||||
|
if (container && bindFunctions) bindFunctions(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<div class="header">
|
||||||
|
<sl-button size="small" variant="default" @click=${() => this.#back()}>
|
||||||
|
<sl-icon slot="prefix" name="arrow-left"></sl-icon>
|
||||||
|
Back
|
||||||
|
</sl-button>
|
||||||
|
<div style="min-width: 0;">
|
||||||
|
<div class="title">Diagram</div>
|
||||||
|
<div class="path">${this.filePath}</div>
|
||||||
|
</div>
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<div class="viewer-controls">
|
||||||
|
<div class="control">
|
||||||
|
<span class="label">Theme</span>
|
||||||
|
<sl-select
|
||||||
|
size="small"
|
||||||
|
value=${this.theme}
|
||||||
|
@sl-change=${(e: any) => {
|
||||||
|
const v = e.target?.value;
|
||||||
|
if (isTheme(v)) {
|
||||||
|
this.theme = v;
|
||||||
|
this.#persistSettings();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<sl-option value="default">default</sl-option>
|
||||||
|
<sl-option value="dark">dark</sl-option>
|
||||||
|
<sl-option value="forest">forest</sl-option>
|
||||||
|
<sl-option value="neutral">neutral</sl-option>
|
||||||
|
<sl-option value="base">base</sl-option>
|
||||||
|
</sl-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control">
|
||||||
|
<span class="label">Layout</span>
|
||||||
|
<sl-select
|
||||||
|
size="small"
|
||||||
|
value=${this.layout}
|
||||||
|
@sl-change=${(e: any) => {
|
||||||
|
const v = e.target?.value;
|
||||||
|
if (isLayout(v)) {
|
||||||
|
this.layout = v;
|
||||||
|
this.#persistSettings();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<sl-option value="dagre">dagre</sl-option>
|
||||||
|
<sl-option value="elk">elk</sl-option>
|
||||||
|
</sl-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control">
|
||||||
|
<span class="label">Log</span>
|
||||||
|
<sl-select
|
||||||
|
size="small"
|
||||||
|
value=${this.mermaidLogLevel}
|
||||||
|
@sl-change=${(e: any) => {
|
||||||
|
const v = e.target?.value;
|
||||||
|
if (isMermaidLogLevel(v)) {
|
||||||
|
this.mermaidLogLevel = v;
|
||||||
|
this.#persistSettings();
|
||||||
|
this.#syncConsolePanelFilters();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<sl-option value="trace">trace</sl-option>
|
||||||
|
<sl-option value="debug">debug</sl-option>
|
||||||
|
<sl-option value="info">info</sl-option>
|
||||||
|
<sl-option value="warn">warn</sl-option>
|
||||||
|
<sl-option value="error">error</sl-option>
|
||||||
|
<sl-option value="fatal">fatal</sl-option>
|
||||||
|
</sl-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control">
|
||||||
|
<sl-checkbox
|
||||||
|
size="small"
|
||||||
|
?checked=${this.useMaxWidth}
|
||||||
|
@sl-change=${(e: any) => {
|
||||||
|
this.useMaxWidth = Boolean(e.target?.checked);
|
||||||
|
this.#persistSettings();
|
||||||
|
}}
|
||||||
|
>useMaxWidth</sl-checkbox
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
${this.loading ? html`<div class="subtle">rendering…</div>` : nothing}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${this.error
|
||||||
|
? html`<div class="empty">Error: <span class="path">${this.error}</span></div>`
|
||||||
|
: nothing}
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<sl-split-panel position="75" style="height: 100%;">
|
||||||
|
<div slot="start" class="diagram">
|
||||||
|
<div class="diagram-inner" data-theme=${this.theme} .innerHTML=${this.svg}></div>
|
||||||
|
</div>
|
||||||
|
<div slot="end" style="height: 100%;">
|
||||||
|
<dev-console-panel></dev-console-panel>
|
||||||
|
</div>
|
||||||
|
</sl-split-panel>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('dev-diagram-viewer', DevDiagramViewer);
|
||||||
143
.esbuild/dev-explorer/explorer-app.ts
Normal file
143
.esbuild/dev-explorer/explorer-app.ts
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
import { LitElement, html, nothing } from 'lit';
|
||||||
|
import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path.js';
|
||||||
|
import { registerIconLibrary } from '@shoelace-style/shoelace/dist/utilities/icon-library.js';
|
||||||
|
|
||||||
|
import '@shoelace-style/shoelace/dist/components/breadcrumb/breadcrumb.js';
|
||||||
|
import '@shoelace-style/shoelace/dist/components/breadcrumb-item/breadcrumb-item.js';
|
||||||
|
import '@shoelace-style/shoelace/dist/components/button/button.js';
|
||||||
|
import '@shoelace-style/shoelace/dist/components/icon/icon.js';
|
||||||
|
import '@shoelace-style/shoelace/dist/components/split-panel/split-panel.js';
|
||||||
|
import '@shoelace-style/shoelace/dist/components/badge/badge.js';
|
||||||
|
import '@shoelace-style/shoelace/dist/components/checkbox/checkbox.js';
|
||||||
|
|
||||||
|
import './file-explorer';
|
||||||
|
import './diagram-viewer';
|
||||||
|
|
||||||
|
type ViewMode = 'explorer' | 'viewer';
|
||||||
|
|
||||||
|
function getInitialStateFromUrl() {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const dir = url.searchParams.get('path') ?? '';
|
||||||
|
const file = url.searchParams.get('file') ?? '';
|
||||||
|
return { dir, file };
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUrlState({ dir, file }: { dir: string; file: string }) {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
url.searchParams.delete('path');
|
||||||
|
url.searchParams.delete('file');
|
||||||
|
if (dir) url.searchParams.set('path', dir);
|
||||||
|
if (file) url.searchParams.set('file', file);
|
||||||
|
history.replaceState(null, '', url);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DevExplorerApp extends LitElement {
|
||||||
|
static properties = {
|
||||||
|
mode: { state: true },
|
||||||
|
dirPath: { state: true },
|
||||||
|
lastDirPath: { state: true },
|
||||||
|
filePath: { state: true },
|
||||||
|
sseToken: { state: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
declare mode: ViewMode;
|
||||||
|
declare dirPath: string;
|
||||||
|
declare lastDirPath: string;
|
||||||
|
declare filePath: string;
|
||||||
|
declare sseToken: number;
|
||||||
|
|
||||||
|
#events?: EventSource;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const { dir, file } = getInitialStateFromUrl();
|
||||||
|
this.dirPath = dir;
|
||||||
|
this.lastDirPath = dir;
|
||||||
|
this.filePath = file;
|
||||||
|
this.mode = file ? 'viewer' : 'explorer';
|
||||||
|
this.sseToken = 0;
|
||||||
|
|
||||||
|
setBasePath('/dev/vendor/shoelace');
|
||||||
|
registerIconLibrary('default', {
|
||||||
|
resolver: (name) => `/dev/vendor/shoelace/assets/icons/${name}.svg`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createRenderRoot() {
|
||||||
|
// Use light DOM so document-level CSS (public/styles.css => /dev/styles.css) applies to the UI.
|
||||||
|
// Without this, Lit's default shadow root will block global selectors like `.list` / `button.card`.
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.#events = new EventSource('/events');
|
||||||
|
this.#events.onmessage = () => {
|
||||||
|
this.sseToken++;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('popstate', this.#onPopState);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
this.#events?.close();
|
||||||
|
window.removeEventListener('popstate', this.#onPopState);
|
||||||
|
}
|
||||||
|
|
||||||
|
#onPopState = () => {
|
||||||
|
const { dir, file } = getInitialStateFromUrl();
|
||||||
|
this.dirPath = dir;
|
||||||
|
this.lastDirPath = dir;
|
||||||
|
this.filePath = file;
|
||||||
|
this.mode = file ? 'viewer' : 'explorer';
|
||||||
|
};
|
||||||
|
|
||||||
|
#goToDir = (dir: string) => {
|
||||||
|
this.dirPath = dir;
|
||||||
|
this.lastDirPath = dir;
|
||||||
|
this.mode = 'explorer';
|
||||||
|
this.filePath = '';
|
||||||
|
setUrlState({ dir, file: '' });
|
||||||
|
};
|
||||||
|
|
||||||
|
#openFile = (filePath: string) => {
|
||||||
|
this.filePath = filePath;
|
||||||
|
this.mode = 'viewer';
|
||||||
|
setUrlState({ dir: this.lastDirPath, file: filePath });
|
||||||
|
};
|
||||||
|
|
||||||
|
#backToExplorer = () => {
|
||||||
|
this.mode = 'explorer';
|
||||||
|
this.filePath = '';
|
||||||
|
setUrlState({ dir: this.lastDirPath, file: '' });
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<div class="app">
|
||||||
|
${this.mode === 'explorer'
|
||||||
|
? html`
|
||||||
|
<dev-file-explorer
|
||||||
|
.path=${this.dirPath}
|
||||||
|
.sseToken=${this.sseToken}
|
||||||
|
@navigate=${(e: CustomEvent<{ path: string }>) => this.#goToDir(e.detail.path)}
|
||||||
|
@open-file=${(e: CustomEvent<{ path: string }>) => this.#openFile(e.detail.path)}
|
||||||
|
></dev-file-explorer>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
|
${this.mode === 'viewer'
|
||||||
|
? html`
|
||||||
|
<dev-diagram-viewer
|
||||||
|
.filePath=${this.filePath}
|
||||||
|
.sseToken=${this.sseToken}
|
||||||
|
@back=${this.#backToExplorer}
|
||||||
|
></dev-diagram-viewer>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('dev-explorer-app', DevExplorerApp);
|
||||||
182
.esbuild/dev-explorer/file-explorer.ts
Normal file
182
.esbuild/dev-explorer/file-explorer.ts
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
import { LitElement, html, nothing } from 'lit';
|
||||||
|
|
||||||
|
type Entry = {
|
||||||
|
name: string;
|
||||||
|
kind: 'dir' | 'file';
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type FilesResponse = {
|
||||||
|
root: string;
|
||||||
|
path: string;
|
||||||
|
entries: Entry[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function dirname(posixPath: string) {
|
||||||
|
const p = posixPath.replaceAll('\\', '/').replace(/\/+$/, '');
|
||||||
|
if (!p) return '';
|
||||||
|
const idx = p.lastIndexOf('/');
|
||||||
|
if (idx <= 0) return '';
|
||||||
|
return p.slice(0, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pathSegments(posixPath: string) {
|
||||||
|
const p = posixPath.replaceAll('\\', '/').replace(/^\/+/, '').replace(/\/+$/, '');
|
||||||
|
if (!p) return [];
|
||||||
|
return p.split('/').filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DevFileExplorer extends LitElement {
|
||||||
|
static properties = {
|
||||||
|
path: { type: String },
|
||||||
|
sseToken: { type: Number },
|
||||||
|
loading: { state: true },
|
||||||
|
error: { state: true },
|
||||||
|
root: { state: true },
|
||||||
|
entries: { state: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
declare path: string;
|
||||||
|
declare sseToken: number;
|
||||||
|
declare loading: boolean;
|
||||||
|
declare error: string;
|
||||||
|
declare root: string;
|
||||||
|
declare entries: Entry[];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.path = '';
|
||||||
|
this.sseToken = 0;
|
||||||
|
this.loading = true;
|
||||||
|
this.error = '';
|
||||||
|
this.root = '';
|
||||||
|
this.entries = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
createRenderRoot() {
|
||||||
|
// Use light DOM so global CSS in public/styles.css applies.
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
updated(changed: Map<string, unknown>) {
|
||||||
|
if (changed.has('path') || changed.has('sseToken')) {
|
||||||
|
void this.#load();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async #load() {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = '';
|
||||||
|
try {
|
||||||
|
const url = new URL('/dev/api/files', window.location.origin);
|
||||||
|
if (this.path) url.searchParams.set('path', this.path);
|
||||||
|
const res = await fetch(url);
|
||||||
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
|
const json = (await res.json()) as FilesResponse;
|
||||||
|
this.root = json.root ?? '';
|
||||||
|
this.entries = json.entries ?? [];
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e instanceof Error ? e.message : String(e);
|
||||||
|
this.entries = [];
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#emitNavigate(nextPath: string) {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('navigate', { detail: { path: nextPath }, bubbles: true, composed: true })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#emitOpenFile(filePath: string) {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('open-file', { detail: { path: filePath }, bubbles: true, composed: true })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#onActivate(kind: Entry['kind'], entryPath: string) {
|
||||||
|
if (kind === 'dir') {
|
||||||
|
this.#emitNavigate(entryPath);
|
||||||
|
} else {
|
||||||
|
this.#emitOpenFile(entryPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const segments = pathSegments(this.path);
|
||||||
|
const itemLabel = this.entries.length === 1 ? 'item' : 'items';
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="header">
|
||||||
|
<div style="min-width: 0;">
|
||||||
|
<div class="title">Dev Explorer</div>
|
||||||
|
<div class="subtle">
|
||||||
|
root:
|
||||||
|
<span class="path">${this.root || 'cypress/platform/dev-diagrams'}</span>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 6px;">
|
||||||
|
<sl-breadcrumb>
|
||||||
|
<sl-breadcrumb-item @click=${() => this.#emitNavigate('')}>root</sl-breadcrumb-item>
|
||||||
|
${segments.map((seg, idx) => {
|
||||||
|
const to = segments.slice(0, idx + 1).join('/');
|
||||||
|
return html`<sl-breadcrumb-item @click=${() => this.#emitNavigate(to)}
|
||||||
|
>${seg}</sl-breadcrumb-item
|
||||||
|
>`;
|
||||||
|
})}
|
||||||
|
</sl-breadcrumb>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<div class="subtle">
|
||||||
|
${this.loading ? 'loading…' : html`<span>${this.entries.length} ${itemLabel}</span>`}
|
||||||
|
</div>
|
||||||
|
<sl-button
|
||||||
|
size="small"
|
||||||
|
variant="default"
|
||||||
|
?disabled=${!this.path}
|
||||||
|
@click=${() => this.#emitNavigate(dirname(this.path))}
|
||||||
|
>
|
||||||
|
<sl-icon slot="prefix" name="arrow-left"></sl-icon>
|
||||||
|
Up
|
||||||
|
</sl-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
${this.error
|
||||||
|
? html`<div class="empty">Error: <span class="path">${this.error}</span></div>`
|
||||||
|
: nothing}
|
||||||
|
${!this.error && !this.loading && this.entries.length === 0
|
||||||
|
? html`<div class="empty">No folders or <span class="path">.mmd</span> files here.</div>`
|
||||||
|
: nothing}
|
||||||
|
|
||||||
|
<div class="list">
|
||||||
|
${this.entries.map((e) => {
|
||||||
|
const icon = e.kind === 'dir' ? 'folder-fill' : 'file-earmark-code';
|
||||||
|
const cardClass = e.kind === 'dir' ? 'card card-folder' : 'card card-file';
|
||||||
|
const click =
|
||||||
|
e.kind === 'dir'
|
||||||
|
? () => this.#emitNavigate(e.path)
|
||||||
|
: () => this.#emitOpenFile(e.path);
|
||||||
|
const onKeyDown = (ev: KeyboardEvent) => {
|
||||||
|
if (ev.key === 'Enter' || ev.key === ' ') {
|
||||||
|
ev.preventDefault();
|
||||||
|
this.#onActivate(e.kind, e.path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return html`
|
||||||
|
<button class=${cardClass} type="button" @click=${click} @keydown=${onKeyDown}>
|
||||||
|
<div class="card-inner">
|
||||||
|
<sl-icon class="card-icon" name=${icon}></sl-icon>
|
||||||
|
<div class="card-title">${e.name}</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('dev-file-explorer', DevFileExplorer);
|
||||||
39
.esbuild/dev-explorer/public/index.html
Normal file
39
.esbuild/dev-explorer/public/index.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en" class="sl-theme-dark">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Mermaid Dev Explorer</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/dev/vendor/shoelace/themes/dark.css" />
|
||||||
|
<link rel="stylesheet" href="/dev/styles.css?v=6" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Mermaid ESM + ELK layout loaders (required for `layout: 'elk'`) -->
|
||||||
|
<script type="module">
|
||||||
|
// Expose a single async hook so the app can reliably await Mermaid "activation".
|
||||||
|
// This avoids races where the UI calls initialize/render before layouts/diagrams are ready.
|
||||||
|
window.mermaidReady = (async () => {
|
||||||
|
try {
|
||||||
|
const [{ default: mermaid }, { default: layouts }] = await Promise.all([
|
||||||
|
import('/mermaid.esm.mjs'),
|
||||||
|
import('/mermaid-layout-elk.esm.mjs'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
mermaid.registerLayoutLoaders(layouts);
|
||||||
|
|
||||||
|
// Keep the rest of the dev explorer simple: expose mermaid on window for the Lit components.
|
||||||
|
window.mermaid = mermaid;
|
||||||
|
return mermaid;
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[dev-explorer] Failed to initialize mermaid (ESM + elk loaders).', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<dev-explorer-app></dev-explorer-app>
|
||||||
|
|
||||||
|
<script type="module" src="/dev/assets/explorer-app.js?v=6"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
359
.esbuild/dev-explorer/public/styles.css
Normal file
359
.esbuild/dev-explorer/public/styles.css
Normal file
@@ -0,0 +1,359 @@
|
|||||||
|
/* Dev Explorer tokens. Keep on :root so the page background picks them up too. */
|
||||||
|
:root {
|
||||||
|
--app-bg: #0b1020;
|
||||||
|
--app-fg: #e8eefc;
|
||||||
|
--panel-bg: #0f1733;
|
||||||
|
--muted: rgba(232, 238, 252, 0.75);
|
||||||
|
--border: rgba(232, 238, 252, 0.12);
|
||||||
|
--mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
|
||||||
|
monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: var(--app-bg);
|
||||||
|
color: var(--app-fg);
|
||||||
|
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
/* Keep the page from becoming scrollable when components accidentally overflow. */
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scope app-level layout rules to avoid generic class collisions. */
|
||||||
|
dev-explorer-app {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .app {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let the top-level view components actually fill the available vertical space. */
|
||||||
|
dev-explorer-app dev-file-explorer,
|
||||||
|
dev-explorer-app dev-diagram-viewer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
background: var(--panel-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .viewer-controls {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .viewer-controls .control {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .viewer-controls .label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--muted);
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .viewer-controls sl-select {
|
||||||
|
width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .header .spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .title {
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .subtle {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .content {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Diagram view should behave like a full-height canvas; avoid nested scrollbars. */
|
||||||
|
dev-explorer-app dev-diagram-viewer .content {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shoelace split panel: ensure slot content can't overflow and push itself off-screen. */
|
||||||
|
dev-explorer-app sl-split-panel {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app sl-split-panel::part(base) {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app sl-split-panel::part(start),
|
||||||
|
dev-explorer-app sl-split-panel::part(end) {
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .list {
|
||||||
|
padding: 24px;
|
||||||
|
display: grid;
|
||||||
|
gap: 20px;
|
||||||
|
grid-template-columns: repeat(auto-fill, 260px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card base - use button element */
|
||||||
|
dev-explorer-app button.card {
|
||||||
|
all: unset;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 260px;
|
||||||
|
height: 200px;
|
||||||
|
border-radius: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Folder card style */
|
||||||
|
dev-explorer-app button.card.card-folder {
|
||||||
|
background: linear-gradient(160deg, #1a3052 0%, #0d1a2d 100%);
|
||||||
|
box-shadow:
|
||||||
|
0 8px 32px rgba(0, 0, 0, 0.4),
|
||||||
|
0 2px 8px rgba(0, 0, 0, 0.2),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app button.card.card-folder:hover {
|
||||||
|
transform: translateY(-6px) scale(1.02);
|
||||||
|
box-shadow:
|
||||||
|
0 16px 48px rgba(0, 0, 0, 0.5),
|
||||||
|
0 4px 12px rgba(0, 0, 0, 0.3),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* File card style */
|
||||||
|
dev-explorer-app button.card.card-file {
|
||||||
|
background: linear-gradient(160deg, #1e2d4a 0%, #111827 100%);
|
||||||
|
box-shadow:
|
||||||
|
0 8px 32px rgba(0, 0, 0, 0.4),
|
||||||
|
0 2px 8px rgba(0, 0, 0, 0.2),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app button.card.card-file:hover {
|
||||||
|
transform: translateY(-6px) scale(1.02);
|
||||||
|
box-shadow:
|
||||||
|
0 16px 48px rgba(0, 0, 0, 0.5),
|
||||||
|
0 4px 12px rgba(0, 0, 0, 0.3),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app button.card:focus-visible {
|
||||||
|
outline: 3px solid rgba(96, 165, 250, 0.7);
|
||||||
|
outline-offset: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subtle border overlay */
|
||||||
|
dev-explorer-app button.card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .card-inner {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
|
padding: 24px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icon styling */
|
||||||
|
dev-explorer-app .card-icon {
|
||||||
|
font-size: 56px !important;
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app button.card.card-folder .card-icon {
|
||||||
|
color: #f59e0b;
|
||||||
|
filter: drop-shadow(0 4px 12px rgba(245, 158, 11, 0.4));
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app button.card.card-file .card-icon {
|
||||||
|
color: #3b82f6;
|
||||||
|
filter: drop-shadow(0 4px 12px rgba(59, 130, 246, 0.35));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title styling */
|
||||||
|
dev-explorer-app .card-title {
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-weight: 500;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
max-width: 230px;
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
line-height: 1.4;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(255, 255, 255, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .row:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .row sl-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .path {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--muted);
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .diagram {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .diagram-inner {
|
||||||
|
/* Canvas background behind the rendered SVG (theme-dependent). */
|
||||||
|
background: #fff;
|
||||||
|
color: #111;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fit the rendered SVG within the available pane (no scrollbars). */
|
||||||
|
dev-explorer-app .diagram-inner > svg {
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
max-width: 100% !important;
|
||||||
|
max-height: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .diagram-inner[data-theme='dark'] {
|
||||||
|
background: #0b1020;
|
||||||
|
color: #e8eefc;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .console {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-left: 1px solid var(--border);
|
||||||
|
background: var(--panel-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .console-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .console-toolbar sl-input {
|
||||||
|
width: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .console-body {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .logline {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .logmeta {
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app .empty {
|
||||||
|
padding: 18px 12px;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-explorer-app sl-breadcrumb::part(base) {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2,12 +2,17 @@
|
|||||||
import chokidar from 'chokidar';
|
import chokidar from 'chokidar';
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import { context } from 'esbuild';
|
import { context } from 'esbuild';
|
||||||
|
import { promises as fs } from 'fs';
|
||||||
import type { Request, Response } from 'express';
|
import type { Request, Response } from 'express';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
|
import path, { resolve } from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
import { packageOptions } from '../.build/common.js';
|
import { packageOptions } from '../.build/common.js';
|
||||||
import { generateLangium } from '../.build/generateLangium.js';
|
import { generateLangium } from '../.build/generateLangium.js';
|
||||||
import { defaultOptions, getBuildConfig } from './util.js';
|
import { defaultOptions, getBuildConfig } from './util.js';
|
||||||
|
|
||||||
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||||
|
|
||||||
const configs = Object.values(packageOptions).map(({ packageName }) =>
|
const configs = Object.values(packageOptions).map(({ packageName }) =>
|
||||||
getBuildConfig({
|
getBuildConfig({
|
||||||
...defaultOptions,
|
...defaultOptions,
|
||||||
@@ -18,7 +23,7 @@ const configs = Object.values(packageOptions).map(({ packageName }) =>
|
|||||||
);
|
);
|
||||||
const mermaidIIFEConfig = getBuildConfig({
|
const mermaidIIFEConfig = getBuildConfig({
|
||||||
...defaultOptions,
|
...defaultOptions,
|
||||||
minify: false,
|
minify: true,
|
||||||
core: false,
|
core: false,
|
||||||
options: packageOptions.mermaid,
|
options: packageOptions.mermaid,
|
||||||
format: 'iife',
|
format: 'iife',
|
||||||
@@ -84,6 +89,81 @@ function sendEventsToAll() {
|
|||||||
clients.forEach(({ response }) => response.write(`data: ${Date.now()}\n\n`));
|
clients.forEach(({ response }) => response.write(`data: ${Date.now()}\n\n`));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface DevExplorerEntry {
|
||||||
|
name: string;
|
||||||
|
kind: 'dir' | 'file';
|
||||||
|
path: string; // posix-style, relative to root
|
||||||
|
}
|
||||||
|
|
||||||
|
const devExplorerRootAbs = resolve(
|
||||||
|
process.cwd(),
|
||||||
|
process.env.MERMAID_DEV_EXPLORER_ROOT ?? 'cypress/platform/dev-diagrams'
|
||||||
|
);
|
||||||
|
|
||||||
|
function toPosixPath(p: string) {
|
||||||
|
return p.split(path.sep).join('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveWithinDevExplorerRoot(requestedPath: unknown) {
|
||||||
|
const requested = typeof requestedPath === 'string' ? requestedPath : '';
|
||||||
|
if (requested.includes('\0')) {
|
||||||
|
throw new Error('Invalid path');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize slashes and avoid weird absolute-path cases.
|
||||||
|
const cleaned = requested.replaceAll('\\', '/').replace(/^\/+/, '');
|
||||||
|
const absPath = resolve(devExplorerRootAbs, cleaned);
|
||||||
|
const rel = path.relative(devExplorerRootAbs, absPath);
|
||||||
|
|
||||||
|
// Prevent traversal above root.
|
||||||
|
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
||||||
|
throw new Error('Path escapes configured root');
|
||||||
|
}
|
||||||
|
|
||||||
|
return { absPath, relPath: toPosixPath(rel) };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createDevExplorerBundle() {
|
||||||
|
const devExplorerDir = resolve(__dirname, 'dev-explorer');
|
||||||
|
const entryPoint = resolve(devExplorerDir, 'explorer-app.ts');
|
||||||
|
const outDir = resolve(devExplorerDir, 'dist');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const devExplorerCtx = await context({
|
||||||
|
absWorkingDir: process.cwd(),
|
||||||
|
entryPoints: [entryPoint],
|
||||||
|
bundle: true,
|
||||||
|
format: 'esm',
|
||||||
|
target: 'es2020',
|
||||||
|
sourcemap: true,
|
||||||
|
outdir: outDir,
|
||||||
|
logLevel: 'info',
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
name: 'dev-explorer-reload',
|
||||||
|
setup(build) {
|
||||||
|
build.onEnd(() => {
|
||||||
|
sendEventsToAll();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await devExplorerCtx.watch();
|
||||||
|
await devExplorerCtx.rebuild();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(
|
||||||
|
[
|
||||||
|
'Dev Explorer bundle build failed.',
|
||||||
|
'Install dependencies: pnpm add -D lit @shoelace-style/shoelace',
|
||||||
|
'Then restart the dev server.',
|
||||||
|
].join('\n')
|
||||||
|
);
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function createServer() {
|
async function createServer() {
|
||||||
await generateLangium();
|
await generateLangium();
|
||||||
handleFileChange();
|
handleFileChange();
|
||||||
@@ -106,8 +186,117 @@ async function createServer() {
|
|||||||
handleFileChange();
|
handleFileChange();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Rebuild the dev-explorer client bundle on changes (and emit SSE so the browser reloads).
|
||||||
|
await createDevExplorerBundle();
|
||||||
|
|
||||||
|
// Emit SSE when Dev Explorer static assets change (e.g. public/styles.css),
|
||||||
|
// otherwise CSS-only changes can look "ignored" unless the user manually refreshes.
|
||||||
|
chokidar
|
||||||
|
.watch(['.esbuild/dev-explorer/public/**/*'], {
|
||||||
|
ignoreInitial: true,
|
||||||
|
ignored: [/node_modules/, /dist/, /docs/, /coverage/],
|
||||||
|
})
|
||||||
|
.on('all', (event, changedPath) => {
|
||||||
|
if (!['add', 'change', 'unlink'].includes(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(`[dev-explorer] ${event}: ${changedPath}`);
|
||||||
|
sendEventsToAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Emit SSE when .mmd files inside the configured explorer root change.
|
||||||
|
chokidar
|
||||||
|
.watch('**/*.mmd', {
|
||||||
|
cwd: devExplorerRootAbs,
|
||||||
|
ignoreInitial: true,
|
||||||
|
})
|
||||||
|
.on('all', (event, changedPath) => {
|
||||||
|
if (!['add', 'change', 'unlink'].includes(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(`[dev-explorer] ${event}: ${changedPath}`);
|
||||||
|
sendEventsToAll();
|
||||||
|
});
|
||||||
|
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
app.get('/events', eventsHandler);
|
app.get('/events', eventsHandler);
|
||||||
|
|
||||||
|
// --- Dev Explorer API + UI -------------------------------------------------
|
||||||
|
const devExplorerDir = resolve(__dirname, 'dev-explorer');
|
||||||
|
const devExplorerPublicDir = resolve(devExplorerDir, 'public');
|
||||||
|
const devExplorerDistDir = resolve(devExplorerDir, 'dist');
|
||||||
|
|
||||||
|
// Shoelace assets (theme css + icons). Safe: only mounted in dev server.
|
||||||
|
app.use(
|
||||||
|
'/dev/vendor/shoelace',
|
||||||
|
express.static(resolve(process.cwd(), 'node_modules/@shoelace-style/shoelace/dist'))
|
||||||
|
);
|
||||||
|
|
||||||
|
app.get('/dev/api/files', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { absPath, relPath } = resolveWithinDevExplorerRoot(req.query.path);
|
||||||
|
const stats = await fs.stat(absPath);
|
||||||
|
if (!stats.isDirectory()) {
|
||||||
|
res.status(400).json({ error: 'Not a directory' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dirEntries = await fs.readdir(absPath, { withFileTypes: true });
|
||||||
|
const entries = dirEntries
|
||||||
|
.filter((d) => d.isDirectory() || (d.isFile() && d.name.endsWith('.mmd')))
|
||||||
|
.map<DevExplorerEntry>((d) => ({
|
||||||
|
name: d.name,
|
||||||
|
kind: d.isDirectory() ? 'dir' : 'file',
|
||||||
|
path: toPosixPath(path.join(relPath, d.name)),
|
||||||
|
}))
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (a.kind !== b.kind) {
|
||||||
|
return a.kind === 'dir' ? -1 : 1;
|
||||||
|
}
|
||||||
|
return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' });
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
root: toPosixPath(path.relative(process.cwd(), devExplorerRootAbs)),
|
||||||
|
path: relPath === '' ? '' : relPath,
|
||||||
|
entries,
|
||||||
|
});
|
||||||
|
} catch (_e) {
|
||||||
|
res.status(400).json({ error: 'Invalid path' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/dev/api/file', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { absPath, relPath } = resolveWithinDevExplorerRoot(req.query.path);
|
||||||
|
if (!absPath.endsWith('.mmd')) {
|
||||||
|
res.status(400).send('Only .mmd files are allowed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const stats = await fs.stat(absPath);
|
||||||
|
if (!stats.isFile()) {
|
||||||
|
res.status(400).send('Not a file');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const content = await fs.readFile(absPath, 'utf-8');
|
||||||
|
res.type('text/plain').send(content);
|
||||||
|
// Optional: include relPath for debugging.
|
||||||
|
void relPath;
|
||||||
|
} catch (_e) {
|
||||||
|
res.status(400).send('Invalid path');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Static assets for the dev-explorer UI.
|
||||||
|
app.use('/dev/assets', express.static(devExplorerDistDir));
|
||||||
|
// Serve `/dev/` (and `/dev`) from public/, including index.html.
|
||||||
|
app.use(
|
||||||
|
'/dev',
|
||||||
|
express.static(devExplorerPublicDir, {
|
||||||
|
index: ['index.html'],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
for (const { packageName } of Object.values(packageOptions)) {
|
for (const { packageName } of Object.values(packageOptions)) {
|
||||||
app.use(express.static(`./packages/${packageName}/dist`));
|
app.use(express.static(`./packages/${packageName}/dist`));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export interface MermaidBuildOptions extends BuildOptions {
|
|||||||
metafile: boolean;
|
metafile: boolean;
|
||||||
format: 'esm' | 'iife';
|
format: 'esm' | 'iife';
|
||||||
options: PackageOptions;
|
options: PackageOptions;
|
||||||
|
includeLargeFeatures: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultOptions: Omit<MermaidBuildOptions, 'entryName' | 'options'> = {
|
export const defaultOptions: Omit<MermaidBuildOptions, 'entryName' | 'options'> = {
|
||||||
@@ -21,6 +22,7 @@ export const defaultOptions: Omit<MermaidBuildOptions, 'entryName' | 'options'>
|
|||||||
metafile: false,
|
metafile: false,
|
||||||
core: false,
|
core: false,
|
||||||
format: 'esm',
|
format: 'esm',
|
||||||
|
includeLargeFeatures: true,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const buildOptions = (override: BuildOptions): BuildOptions => {
|
const buildOptions = (override: BuildOptions): BuildOptions => {
|
||||||
@@ -39,12 +41,18 @@ const buildOptions = (override: BuildOptions): BuildOptions => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFileName = (fileName: string, { core, format, minify }: MermaidBuildOptions) => {
|
const getFileName = (
|
||||||
|
fileName: string,
|
||||||
|
{ core, format, minify, includeLargeFeatures }: MermaidBuildOptions
|
||||||
|
) => {
|
||||||
if (core) {
|
if (core) {
|
||||||
fileName += '.core';
|
fileName += '.core';
|
||||||
} else if (format === 'esm') {
|
} else if (format === 'esm') {
|
||||||
fileName += '.esm';
|
fileName += '.esm';
|
||||||
}
|
}
|
||||||
|
if (!includeLargeFeatures) {
|
||||||
|
fileName += '.tiny';
|
||||||
|
}
|
||||||
if (minify) {
|
if (minify) {
|
||||||
fileName += '.min';
|
fileName += '.min';
|
||||||
}
|
}
|
||||||
@@ -54,31 +62,36 @@ const getFileName = (fileName: string, { core, format, minify }: MermaidBuildOpt
|
|||||||
export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
|
export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
|
||||||
const {
|
const {
|
||||||
core,
|
core,
|
||||||
metafile,
|
|
||||||
format,
|
format,
|
||||||
minify,
|
|
||||||
options: { name, file, packageName },
|
options: { name, file, packageName },
|
||||||
|
globalName = 'mermaid',
|
||||||
|
includeLargeFeatures,
|
||||||
|
...rest
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const external: string[] = ['require', 'fs', 'path'];
|
const external: string[] = ['require', 'fs', 'path'];
|
||||||
const outFileName = getFileName(name, options);
|
const outFileName = getFileName(name, options);
|
||||||
|
const { dependencies, version } = JSON.parse(
|
||||||
|
readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8')
|
||||||
|
);
|
||||||
const output: BuildOptions = buildOptions({
|
const output: BuildOptions = buildOptions({
|
||||||
|
...rest,
|
||||||
absWorkingDir: resolve(__dirname, `../packages/${packageName}`),
|
absWorkingDir: resolve(__dirname, `../packages/${packageName}`),
|
||||||
entryPoints: {
|
entryPoints: {
|
||||||
[outFileName]: `src/${file}`,
|
[outFileName]: `src/${file}`,
|
||||||
},
|
},
|
||||||
metafile,
|
globalName,
|
||||||
minify,
|
|
||||||
logLevel: 'info',
|
logLevel: 'info',
|
||||||
chunkNames: `chunks/${outFileName}/[name]-[hash]`,
|
chunkNames: `chunks/${outFileName}/[name]-[hash]`,
|
||||||
define: {
|
define: {
|
||||||
|
// This needs to be stringified for esbuild
|
||||||
|
'injected.includeLargeFeatures': `${includeLargeFeatures}`,
|
||||||
|
'injected.version': `'${version}'`,
|
||||||
'import.meta.vitest': 'undefined',
|
'import.meta.vitest': 'undefined',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (core) {
|
if (core) {
|
||||||
const { dependencies } = JSON.parse(
|
|
||||||
readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8')
|
|
||||||
);
|
|
||||||
// Core build is used to generate file without bundled dependencies.
|
// Core build is used to generate file without bundled dependencies.
|
||||||
// This is used by downstream projects to bundle dependencies themselves.
|
// This is used by downstream projects to bundle dependencies themselves.
|
||||||
// Ignore dependencies and any dependencies of dependencies
|
// Ignore dependencies and any dependencies of dependencies
|
||||||
@@ -89,11 +102,12 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
|
|||||||
if (format === 'iife') {
|
if (format === 'iife') {
|
||||||
output.format = 'iife';
|
output.format = 'iife';
|
||||||
output.splitting = false;
|
output.splitting = false;
|
||||||
output.globalName = '__esbuild_esm_mermaid';
|
const originalGlobalName = output.globalName ?? 'mermaid';
|
||||||
|
output.globalName = `__esbuild_esm_mermaid_nm[${JSON.stringify(originalGlobalName)}]`;
|
||||||
// Workaround for removing the .default access in esbuild IIFE.
|
// Workaround for removing the .default access in esbuild IIFE.
|
||||||
// https://github.com/mermaid-js/mermaid/pull/4109#discussion_r1292317396
|
// https://github.com/mermaid-js/mermaid/pull/4109#discussion_r1292317396
|
||||||
output.footer = {
|
output.footer = {
|
||||||
js: 'globalThis.mermaid = globalThis.__esbuild_esm_mermaid.default;',
|
js: `globalThis[${JSON.stringify(originalGlobalName)}] = globalThis.${output.globalName}.default;`,
|
||||||
};
|
};
|
||||||
output.outExtension = { '.js': '.js' };
|
output.outExtension = { '.js': '.js' };
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -4,7 +4,7 @@ contact_links:
|
|||||||
url: https://github.com/mermaid-js/mermaid/discussions
|
url: https://github.com/mermaid-js/mermaid/discussions
|
||||||
about: Ask the Community questions or share your own graphs in our discussions.
|
about: Ask the Community questions or share your own graphs in our discussions.
|
||||||
- name: Discord
|
- name: Discord
|
||||||
url: https://discord.gg/AgrbSrBer3
|
url: https://discord.gg/sKeNQX4Wtj
|
||||||
about: Join our Community on Discord for Help and a casual chat.
|
about: Join our Community on Discord for Help and a casual chat.
|
||||||
- name: Documentation
|
- name: Documentation
|
||||||
url: https://mermaid.js.org
|
url: https://mermaid.js.org
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/theme_proposal.yml
vendored
2
.github/ISSUE_TEMPLATE/theme_proposal.yml
vendored
@@ -29,7 +29,7 @@ body:
|
|||||||
label: Colors
|
label: Colors
|
||||||
description: |-
|
description: |-
|
||||||
A detailed list of the different colour values to use.
|
A detailed list of the different colour values to use.
|
||||||
A list of currently used variable names can be found [here](https://mermaid-js.github.io/mermaid/#/theming?id=theme-variables-reference-table)
|
See the [list of currently used variable names](https://mermaid-js.github.io/mermaid/#/theming?id=theme-variables-reference-table)
|
||||||
placeholder: |-
|
placeholder: |-
|
||||||
- background: #f4f4f4
|
- background: #f4f4f4
|
||||||
- primaryColor: #fff4dd
|
- primaryColor: #fff4dd
|
||||||
|
|||||||
17
.github/lychee.toml
vendored
17
.github/lychee.toml
vendored
@@ -46,8 +46,21 @@ exclude = [
|
|||||||
# Drupal 403
|
# Drupal 403
|
||||||
"https://(www.)?drupal.org",
|
"https://(www.)?drupal.org",
|
||||||
|
|
||||||
# Swimm returns 404, eventhough the link is valid
|
# Phbpp 403
|
||||||
"https://docs.swimm.io"
|
"https://(www.)?phpbb.com",
|
||||||
|
|
||||||
|
# Swimm returns 404, even though the link is valid
|
||||||
|
"https://docs.swimm.io",
|
||||||
|
|
||||||
|
# Certificate Error
|
||||||
|
"https://noteshub.app",
|
||||||
|
|
||||||
|
# Timeout
|
||||||
|
"https://huehive.co",
|
||||||
|
"https://foswiki.org",
|
||||||
|
"https://www.gnu.org",
|
||||||
|
"https://redmine.org",
|
||||||
|
"https://mermaid-preview.com"
|
||||||
]
|
]
|
||||||
|
|
||||||
# Exclude all private IPs from checking.
|
# Exclude all private IPs from checking.
|
||||||
|
|||||||
2
.github/stale.yml
vendored
2
.github/stale.yml
vendored
@@ -15,5 +15,5 @@ markComment: >
|
|||||||
If you are still interested in this issue and it is still relevant you can comment to revive it.
|
If you are still interested in this issue and it is still relevant you can comment to revive it.
|
||||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
closeComment: >
|
closeComment: >
|
||||||
This issue has been been automatically closed due to a lack of activity.
|
This issue has been automatically closed due to a lack of activity.
|
||||||
This is done to maintain a clean list of issues that the community is interested in developing.
|
This is done to maintain a clean list of issues that the community is interested in developing.
|
||||||
|
|||||||
8
.github/workflows/autofix.yml
vendored
8
.github/workflows/autofix.yml
vendored
@@ -13,13 +13,13 @@ jobs:
|
|||||||
autofix:
|
autofix:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
# uses version from "packageManager" field in package.json
|
# uses version from "packageManager" field in package.json
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
@@ -42,4 +42,4 @@ jobs:
|
|||||||
working-directory: ./packages/mermaid
|
working-directory: ./packages/mermaid
|
||||||
run: pnpm run docs:build
|
run: pnpm run docs:build
|
||||||
|
|
||||||
- uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c # main
|
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27 # main
|
||||||
|
|||||||
6
.github/workflows/build-docs.yml
vendored
6
.github/workflows/build-docs.yml
vendored
@@ -18,12 +18,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
|
|||||||
2
.github/workflows/check-readme-in-sync.yml
vendored
2
.github/workflows/check-readme-in-sync.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Check for difference in README.md and docs/README.md
|
- name: Check for difference in README.md and docs/README.md
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
12
.github/workflows/codeql.yml
vendored
12
.github/workflows/codeql.yml
vendored
@@ -26,17 +26,17 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
language: ['javascript']
|
language: ['javascript', 'actions']
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
# CodeQL supports [ 'actions', 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
|
uses: github/codeql-action/init@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||||
with:
|
with:
|
||||||
config-file: ./.github/codeql/codeql-config.yml
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
@@ -48,7 +48,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
|
uses: github/codeql-action/autobuild@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
@@ -62,4 +62,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
|
uses: github/codeql-action/analyze@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||||
|
|||||||
4
.github/workflows/dependency-review.yml
vendored
4
.github/workflows/dependency-review.yml
vendored
@@ -15,6 +15,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: 'Checkout Repository'
|
- name: 'Checkout Repository'
|
||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: 'Dependency Review'
|
- name: 'Dependency Review'
|
||||||
uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4
|
uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0
|
||||||
|
|||||||
15
.github/workflows/e2e-applitools.yml
vendored
15
.github/workflows/e2e-applitools.yml
vendored
@@ -23,38 +23,37 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
e2e-applitools:
|
e2e-applitools:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
|
||||||
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
|
||||||
options: --user 1001
|
|
||||||
steps:
|
steps:
|
||||||
- if: ${{ ! env.USE_APPLI }}
|
- if: ${{ ! env.USE_APPLI }}
|
||||||
name: Warn if not using Applitools
|
name: Warn if not using Applitools
|
||||||
run: |
|
run: |
|
||||||
echo "::error,title=Not using Applitools::APPLITOOLS_API_KEY is empty, disabling Applitools for this run."
|
echo "::error,title=Not using Applitools::APPLITOOLS_API_KEY is empty, disabling Applitools for this run."
|
||||||
|
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
# uses version from "packageManager" field in package.json
|
# uses version from "packageManager" field in package.json
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
|
|
||||||
- if: ${{ env.USE_APPLI }}
|
- if: ${{ env.USE_APPLI }}
|
||||||
name: Notify applitools of new batch
|
name: Notify applitools of new batch
|
||||||
# Copied from docs https://applitools.com/docs/topics/integrations/github-integration-ci-setup.html
|
# Copied from docs https://applitools.com/docs/topics/integrations/github-integration-ci-setup.html
|
||||||
run: curl -L -d '' -X POST "$APPLITOOLS_SERVER_URL/api/externals/github/push?apiKey=$APPLITOOLS_API_KEY&CommitSha=$GITHUB_SHA&BranchName=${APPLITOOLS_BRANCH}$&ParentBranchName=$APPLITOOLS_PARENT_BRANCH"
|
|
||||||
env:
|
env:
|
||||||
# e.g. mermaid-js/mermaid/my-branch
|
# e.g. mermaid-js/mermaid/my-branch
|
||||||
APPLITOOLS_BRANCH: ${{ github.repository }}/${{ github.ref_name }}
|
APPLITOOLS_BRANCH: ${{ github.repository }}/${{ github.ref_name }}
|
||||||
APPLITOOLS_PARENT_BRANCH: ${{ github.event.inputs.parent_branch }}
|
APPLITOOLS_PARENT_BRANCH: ${{ github.event.inputs.parent_branch }}
|
||||||
APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
|
APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
|
||||||
APPLITOOLS_SERVER_URL: 'https://eyesapi.applitools.com'
|
APPLITOOLS_SERVER_URL: 'https://eyesapi.applitools.com'
|
||||||
|
uses: wei/curl@012398a392d02480afa2720780031f8621d5f94c
|
||||||
|
with:
|
||||||
|
args: -X POST "$APPLITOOLS_SERVER_URL/api/externals/github/push?apiKey=$APPLITOOLS_API_KEY&CommitSha=$GITHUB_SHA&BranchName=${APPLITOOLS_BRANCH}$&ParentBranchName=$APPLITOOLS_PARENT_BRANCH"
|
||||||
|
|
||||||
- name: Cypress run
|
- name: Cypress run
|
||||||
uses: cypress-io/github-action@d79d2d530a66e641eb4a5f227e13bc985c60b964 # v4.2.2
|
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||||
id: cypress
|
id: cypress
|
||||||
with:
|
with:
|
||||||
start: pnpm run dev
|
start: pnpm run dev
|
||||||
|
|||||||
39
.github/workflows/e2e-timings.yml
vendored
39
.github/workflows/e2e-timings.yml
vendored
@@ -11,6 +11,7 @@ concurrency: ${{ github.workflow }}-${{ github.ref }}
|
|||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
timings:
|
timings:
|
||||||
@@ -19,18 +20,19 @@ jobs:
|
|||||||
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
||||||
options: --user 1001
|
options: --user 1001
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
|
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||||
with:
|
with:
|
||||||
runTests: false
|
runTests: false
|
||||||
|
|
||||||
- name: Cypress run
|
- name: Cypress run
|
||||||
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
|
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||||
id: cypress
|
id: cypress
|
||||||
with:
|
with:
|
||||||
install: false
|
install: false
|
||||||
@@ -44,10 +46,25 @@ jobs:
|
|||||||
SPLIT: 1
|
SPLIT: 1
|
||||||
SPLIT_INDEX: 0
|
SPLIT_INDEX: 0
|
||||||
SPLIT_FILE: 'cypress/timings.json'
|
SPLIT_FILE: 'cypress/timings.json'
|
||||||
- name: Commit changes
|
|
||||||
uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9.1.4
|
- name: Compare timings
|
||||||
|
id: compare
|
||||||
|
run: |
|
||||||
|
OUTPUT=$(pnpm tsx scripts/compare-timings.ts)
|
||||||
|
echo "$OUTPUT" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "$OUTPUT" >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Commit and create pull request
|
||||||
|
uses: peter-evans/create-pull-request@0979079bc20c05bbbb590a56c21c4e2b1d1f1bbe
|
||||||
with:
|
with:
|
||||||
add: 'cypress/timings.json'
|
add-paths: |
|
||||||
author_name: 'github-actions[bot]'
|
cypress/timings.json
|
||||||
author_email: '41898282+github-actions[bot]@users.noreply.github.com'
|
commit-message: 'chore: update E2E timings'
|
||||||
message: 'chore: update E2E timings'
|
branch: update-timings
|
||||||
|
title: Update E2E Timings
|
||||||
|
body: ${{ steps.compare.outputs.output }}
|
||||||
|
delete-branch: true
|
||||||
|
sign-commits: true
|
||||||
|
|||||||
42
.github/workflows/e2e.yml
vendored
42
.github/workflows/e2e.yml
vendored
@@ -28,6 +28,8 @@ env:
|
|||||||
) ||
|
) ||
|
||||||
github.event.before
|
github.event.before
|
||||||
}}
|
}}
|
||||||
|
RUN_VISUAL_TEST: >-
|
||||||
|
${{ github.repository == 'mermaid-js/mermaid' && (github.event_name != 'pull_request' || !startsWith(github.head_ref, 'renovate/')) }}
|
||||||
jobs:
|
jobs:
|
||||||
cache:
|
cache:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -35,30 +37,29 @@ jobs:
|
|||||||
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
||||||
options: --user 1001
|
options: --user 1001
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
- name: Cache snapshots
|
- name: Cache snapshots
|
||||||
id: cache-snapshot
|
id: cache-snapshot
|
||||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||||
with:
|
with:
|
||||||
save-always: true
|
|
||||||
path: ./cypress/snapshots
|
path: ./cypress/snapshots
|
||||||
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
||||||
|
|
||||||
# If a snapshot for a given Hash is not found, we checkout that commit, run the tests and cache the snapshots.
|
# If a snapshot for a given Hash is not found, we checkout that commit, run the tests and cache the snapshots.
|
||||||
- name: Switch to base branch
|
- name: Switch to base branch
|
||||||
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
|
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
|
||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
ref: ${{ env.targetHash }}
|
ref: ${{ env.targetHash }}
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
|
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
|
||||||
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
|
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||||
with:
|
with:
|
||||||
# just perform install
|
# just perform install
|
||||||
runTests: false
|
runTests: false
|
||||||
@@ -81,26 +82,26 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
containers: [1, 2, 3, 4, 5]
|
containers: [1, 2, 3, 4, 5]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
# uses version from "packageManager" field in package.json
|
# uses version from "packageManager" field in package.json
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
|
|
||||||
# These cached snapshots are downloaded, providing the reference snapshots.
|
# These cached snapshots are downloaded, providing the reference snapshots.
|
||||||
- name: Cache snapshots
|
- name: Cache snapshots
|
||||||
id: cache-snapshot
|
id: cache-snapshot
|
||||||
uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||||
with:
|
with:
|
||||||
path: ./cypress/snapshots
|
path: ./cypress/snapshots
|
||||||
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
|
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||||
with:
|
with:
|
||||||
runTests: false
|
runTests: false
|
||||||
|
|
||||||
@@ -116,7 +117,7 @@ jobs:
|
|||||||
# Install NPM dependencies, cache them correctly
|
# Install NPM dependencies, cache them correctly
|
||||||
# and run all Cypress tests
|
# and run all Cypress tests
|
||||||
- name: Cypress run
|
- name: Cypress run
|
||||||
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
|
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||||
id: cypress
|
id: cypress
|
||||||
with:
|
with:
|
||||||
install: false
|
install: false
|
||||||
@@ -125,21 +126,20 @@ jobs:
|
|||||||
browser: chrome
|
browser: chrome
|
||||||
# Disable recording if we don't have an API key
|
# Disable recording if we don't have an API key
|
||||||
# e.g. if this action was run from a fork
|
# e.g. if this action was run from a fork
|
||||||
record: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
|
record: ${{ env.RUN_VISUAL_TEST == 'true' && secrets.CYPRESS_RECORD_KEY != '' }}
|
||||||
env:
|
env:
|
||||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
ARGOS_PARALLEL: ${{ env.RUN_VISUAL_TEST == 'true' }}
|
||||||
VITEST_COVERAGE: true
|
ARGOS_PARALLEL_TOTAL: ${{ env.RUN_VISUAL_TEST == 'true' && strategy.job-total || 1 }}
|
||||||
|
ARGOS_PARALLEL_INDEX: ${{ env.RUN_VISUAL_TEST == 'true' && matrix.containers || 1 }}
|
||||||
CYPRESS_COMMIT: ${{ github.sha }}
|
CYPRESS_COMMIT: ${{ github.sha }}
|
||||||
ARGOS_TOKEN: ${{ secrets.ARGOS_TOKEN }}
|
CYPRESS_RECORD_KEY: ${{ env.RUN_VISUAL_TEST == 'true' && secrets.CYPRESS_RECORD_KEY || ''}}
|
||||||
ARGOS_PARALLEL: true
|
|
||||||
ARGOS_PARALLEL_TOTAL: ${{ strategy.job-total }}
|
|
||||||
ARGOS_PARALLEL_INDEX: ${{ matrix.containers }}
|
|
||||||
SPLIT: ${{ strategy.job-total }}
|
SPLIT: ${{ strategy.job-total }}
|
||||||
SPLIT_INDEX: ${{ strategy.job-index }}
|
SPLIT_INDEX: ${{ strategy.job-index }}
|
||||||
SPLIT_FILE: 'cypress/timings.json'
|
SPLIT_FILE: 'cypress/timings.json'
|
||||||
|
VITEST_COVERAGE: true
|
||||||
|
|
||||||
- name: Upload Coverage to Codecov
|
- name: Upload Coverage to Codecov
|
||||||
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
|
uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1
|
||||||
# Run step only pushes to develop and pull_requests
|
# Run step only pushes to develop and pull_requests
|
||||||
if: ${{ steps.cypress.conclusion == 'success' && (github.event_name == 'pull_request' || github.ref == 'refs/heads/develop')}}
|
if: ${{ steps.cypress.conclusion == 'success' && (github.event_name == 'pull_request' || github.ref == 'refs/heads/develop')}}
|
||||||
with:
|
with:
|
||||||
|
|||||||
6
.github/workflows/link-checker.yml
vendored
6
.github/workflows/link-checker.yml
vendored
@@ -29,17 +29,17 @@ jobs:
|
|||||||
# lychee only uses the GITHUB_TOKEN to avoid rate-limiting
|
# lychee only uses the GITHUB_TOKEN to avoid rate-limiting
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Restore lychee cache
|
- name: Restore lychee cache
|
||||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||||
with:
|
with:
|
||||||
path: .lycheecache
|
path: .lycheecache
|
||||||
key: cache-lychee-${{ github.sha }}
|
key: cache-lychee-${{ github.sha }}
|
||||||
restore-keys: cache-lychee-
|
restore-keys: cache-lychee-
|
||||||
|
|
||||||
- name: Link Checker
|
- name: Link Checker
|
||||||
uses: lycheeverse/lychee-action@c053181aa0c3d17606addfe97a9075a32723548a # v1.9.3
|
uses: lycheeverse/lychee-action@f613c4a64e50d792e0b31ec34bbcbba12263c6a6 # v2.3.0
|
||||||
with:
|
with:
|
||||||
args: >-
|
args: >-
|
||||||
--config .github/lychee.toml
|
--config .github/lychee.toml
|
||||||
|
|||||||
8
.github/workflows/lint.yml
vendored
8
.github/workflows/lint.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
docker-lint:
|
docker-lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0
|
- uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0
|
||||||
with:
|
with:
|
||||||
@@ -23,13 +23,13 @@ jobs:
|
|||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
# uses version from "packageManager" field in package.json
|
# uses version from "packageManager" field in package.json
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
|
|||||||
28
.github/workflows/pr-labeler.yml
vendored
28
.github/workflows/pr-labeler.yml
vendored
@@ -22,10 +22,36 @@ jobs:
|
|||||||
pull-requests: write # write permission is required to label PRs
|
pull-requests: write # write permission is required to label PRs
|
||||||
steps:
|
steps:
|
||||||
- name: Label PR
|
- name: Label PR
|
||||||
uses: release-drafter/release-drafter@3f0f87098bd6b5c5b9a36d49c41d998ea58f9348 # v6.0.0
|
uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0
|
||||||
with:
|
with:
|
||||||
config-name: pr-labeler.yml
|
config-name: pr-labeler.yml
|
||||||
disable-autolabeler: false
|
disable-autolabeler: false
|
||||||
disable-releaser: true
|
disable-releaser: true
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Add "Sponsored by MermaidChart" label
|
||||||
|
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const prNumber = context.payload.pull_request.number;
|
||||||
|
const { data: commits } = await github.rest.pulls.listCommits({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
pull_number: prNumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
const isSponsored = commits.every(
|
||||||
|
(c) => c.commit.author.email?.endsWith('@mermaidchart.com')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isSponsored) {
|
||||||
|
console.log('PR is sponsored. Adding label.');
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: prNumber,
|
||||||
|
labels: ['Sponsored by MermaidChart'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
8
.github/workflows/publish-docs.yml
vendored
8
.github/workflows/publish-docs.yml
vendored
@@ -23,12 +23,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Setup Pages
|
- name: Setup Pages
|
||||||
uses: actions/configure-pages@1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d # v4.0.0
|
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
|
||||||
|
|
||||||
- name: Run Build
|
- name: Run Build
|
||||||
run: pnpm --filter mermaid run docs:build:vitepress
|
run: pnpm --filter mermaid run docs:build:vitepress
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ jobs:
|
|||||||
publish-preview:
|
publish-preview:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
|
|||||||
6
.github/workflows/release-preview.yml
vendored
6
.github/workflows/release-preview.yml
vendored
@@ -26,12 +26,12 @@ jobs:
|
|||||||
timeout-minutes: 5
|
timeout-minutes: 5
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repo
|
- name: Checkout Repo
|
||||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
|
|||||||
9
.github/workflows/release.yml
vendored
9
.github/workflows/release.yml
vendored
@@ -21,12 +21,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repo
|
- name: Checkout Repo
|
||||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
@@ -36,11 +36,10 @@ jobs:
|
|||||||
|
|
||||||
- name: Create Release Pull Request or Publish to npm
|
- name: Create Release Pull Request or Publish to npm
|
||||||
id: changesets
|
id: changesets
|
||||||
uses: changesets/action@3de3850952bec538fde60aac71731376e57b9b57 # v1.4.8
|
uses: changesets/action@06245a4e0a36c064a573d4150030f5ec548e4fcc # v1.4.10
|
||||||
with:
|
with:
|
||||||
version: pnpm changeset:version
|
version: pnpm changeset:version
|
||||||
publish: pnpm changeset:publish
|
publish: pnpm changeset:publish
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
NPM_CONFIG_PROVENANCE: true
|
NPM_CONFIG_PROVENANCE: true
|
||||||
|
|||||||
8
.github/workflows/scorecard.yml
vendored
8
.github/workflows/scorecard.yml
vendored
@@ -16,22 +16,22 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Run analysis
|
- name: Run analysis
|
||||||
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
|
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
|
||||||
with:
|
with:
|
||||||
results_file: results.sarif
|
results_file: results.sarif
|
||||||
results_format: sarif
|
results_format: sarif
|
||||||
publish_results: true
|
publish_results: true
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@97a0fba1372883ab732affbe8f94b823f91727db # v3.pre.node20
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: SARIF file
|
name: SARIF file
|
||||||
path: results.sarif
|
path: results.sarif
|
||||||
retention-days: 5
|
retention-days: 5
|
||||||
- name: Upload to code-scanning
|
- name: Upload to code-scanning
|
||||||
uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
|
uses: github/codeql-action/upload-sarif@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|||||||
8
.github/workflows/test.yml
vendored
8
.github/workflows/test.yml
vendored
@@ -9,13 +9,13 @@ jobs:
|
|||||||
unit-test:
|
unit-test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
# uses version from "packageManager" field in package.json
|
# uses version from "packageManager" field in package.json
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
@@ -43,7 +43,7 @@ jobs:
|
|||||||
pnpm test:check:tsc
|
pnpm test:check:tsc
|
||||||
|
|
||||||
- name: Upload Coverage to Codecov
|
- name: Upload Coverage to Codecov
|
||||||
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
|
uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1
|
||||||
# Run step only pushes to develop and pull_requests
|
# Run step only pushes to develop and pull_requests
|
||||||
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/develop' }}
|
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/develop' }}
|
||||||
with:
|
with:
|
||||||
|
|||||||
6
.github/workflows/update-browserlist.yml
vendored
6
.github/workflows/update-browserlist.yml
vendored
@@ -8,8 +8,8 @@ jobs:
|
|||||||
update-browser-list:
|
update-browser-list:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||||
- run: npx update-browserslist-db@latest
|
- run: npx update-browserslist-db@latest
|
||||||
- name: Commit changes
|
- name: Commit changes
|
||||||
uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9.1.4
|
uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9.1.4
|
||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
message: 'chore: update browsers list'
|
message: 'chore: update browsers list'
|
||||||
push: false
|
push: false
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
|
uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412 # v7.0.9
|
||||||
with:
|
with:
|
||||||
branch: update-browserslist
|
branch: update-browserslist
|
||||||
title: Update Browserslist
|
title: Update Browserslist
|
||||||
|
|||||||
90
.github/workflows/validate-lockfile.yml
vendored
Normal file
90
.github/workflows/validate-lockfile.yml
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
name: Validate pnpm-lock.yaml
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
paths:
|
||||||
|
- 'pnpm-lock.yaml'
|
||||||
|
- '**/package.json'
|
||||||
|
- '.github/workflows/validate-lockfile.yml'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate-lockfile:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||||
|
|
||||||
|
- name: Validate pnpm-lock.yaml entries
|
||||||
|
id: validate # give this step an ID so we can reference its outputs
|
||||||
|
run: |
|
||||||
|
issues=()
|
||||||
|
|
||||||
|
# 1) No tarball references
|
||||||
|
if grep -qF 'tarball:' pnpm-lock.yaml; then
|
||||||
|
issues+=("• Tarball references found (forbidden)")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2) No unwanted vitepress paths
|
||||||
|
if grep -qF 'packages/mermaid/src/vitepress' pnpm-lock.yaml; then
|
||||||
|
issues+=("• Disallowed path 'packages/mermaid/src/vitepress' present. Run \`rm -rf packages/mermaid/src/vitepress && pnpm install\` to regenerate.")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3) Lockfile only changes when package.json changes
|
||||||
|
git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }} > changed.txt
|
||||||
|
if grep -q '^pnpm-lock.yaml$' changed.txt && ! grep -q 'package.json' changed.txt; then
|
||||||
|
issues+=("• pnpm-lock.yaml changed without any package.json modification")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If any issues, output them and fail
|
||||||
|
if [ ${#issues[@]} -gt 0 ]; then
|
||||||
|
# Use the new GITHUB_OUTPUT approach to set a multiline output
|
||||||
|
{
|
||||||
|
echo "errors<<EOF"
|
||||||
|
printf '%s\n' "${issues[@]}"
|
||||||
|
echo "EOF"
|
||||||
|
} >> $GITHUB_OUTPUT
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Find existing lockfile validation comment
|
||||||
|
if: always()
|
||||||
|
uses: peter-evans/find-comment@v3
|
||||||
|
id: find-comment
|
||||||
|
with:
|
||||||
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
|
comment-author: 'github-actions[bot]'
|
||||||
|
body-includes: 'Lockfile Validation Failed'
|
||||||
|
|
||||||
|
- name: Comment on PR if validation failed
|
||||||
|
if: failure()
|
||||||
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
|
comment-id: ${{ steps.find-comment.outputs.comment-id }}
|
||||||
|
edit-mode: replace
|
||||||
|
body: |
|
||||||
|
❌ **Lockfile Validation Failed**
|
||||||
|
|
||||||
|
The following issue(s) were detected:
|
||||||
|
${{ steps.validate.outputs.errors }}
|
||||||
|
|
||||||
|
Please address these and push an update.
|
||||||
|
|
||||||
|
_Posted automatically by GitHub Actions_
|
||||||
|
|
||||||
|
- name: Delete comment if validation passed
|
||||||
|
if: success() && steps.find-comment.outputs.comment-id != ''
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
await github.rest.issues.deleteComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
comment_id: ${{ steps.find-comment.outputs.comment-id }},
|
||||||
|
});
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@ node_modules/
|
|||||||
coverage/
|
coverage/
|
||||||
.idea/
|
.idea/
|
||||||
.pnpm-store/
|
.pnpm-store/
|
||||||
|
.instructions/
|
||||||
|
|
||||||
dist
|
dist
|
||||||
v8-compile-cache-0
|
v8-compile-cache-0
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
20.12.2
|
22.14.0
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
|
|||||||
},
|
},
|
||||||
define: {
|
define: {
|
||||||
'import.meta.vitest': 'undefined',
|
'import.meta.vitest': 'undefined',
|
||||||
|
'injected.includeLargeFeatures': 'true',
|
||||||
|
'injected.version': `'0.0.0'`,
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [],
|
extensions: [],
|
||||||
|
|||||||
1005
CHANGELOG.md
1005
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
1
CHANGELOG.md
Symbolic link
1
CHANGELOG.md
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
./packages/mermaid/CHANGELOG.md
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
FROM node:20.12.2-alpine3.19@sha256:7a91aa397f2e2dfbfcdad2e2d72599f374e0b0172be1d86eeb73f1d33f36a4b2
|
FROM node:22.12.0-alpine3.19@sha256:40dc4b415c17b85bea9be05314b4a753f45a4e1716bb31c01182e6c53d51a654
|
||||||
|
|
||||||
USER 0:0
|
USER 0:0
|
||||||
|
|
||||||
RUN corepack enable \
|
RUN corepack enable \
|
||||||
&& corepack enable pnpm
|
&& corepack enable pnpm
|
||||||
|
|
||||||
RUN apk add --no-cache git~=2.43.4 \
|
RUN apk add --no-cache git~=2.43 \
|
||||||
&& git config --add --system safe.directory /mermaid
|
&& git config --add --system safe.directory /mermaid
|
||||||
|
|
||||||
ENV NODE_OPTIONS="--max_old_space_size=8192"
|
ENV NODE_OPTIONS="--max_old_space_size=8192"
|
||||||
|
|||||||
38
README.md
38
README.md
@@ -15,7 +15,7 @@ Generate diagrams from markdown-like text.
|
|||||||
<a href="https://mermaid.live/"><b>Live Editor!</b></a>
|
<a href="https://mermaid.live/"><b>Live Editor!</b></a>
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mermaid.js.org">📖 Documentation</a> | <a href="https://mermaid.js.org/intro/">🚀 Getting Started</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/AgrbSrBer3" title="Discord invite">🙌 Join Us</a>
|
<a href="https://mermaid.js.org">📖 Documentation</a> | <a href="https://mermaid.js.org/intro/">🚀 Getting Started</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/sKeNQX4Wtj" title="Discord invite">🙌 Join Us</a>
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="./README.zh-CN.md">简体中文</a>
|
<a href="./README.zh-CN.md">简体中文</a>
|
||||||
@@ -33,7 +33,7 @@ Try Live Editor previews of future releases: <a href="https://develop.git.mermai
|
|||||||
[](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
|
[](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
|
||||||
[](https://www.jsdelivr.com/package/npm/mermaid)
|
[](https://www.jsdelivr.com/package/npm/mermaid)
|
||||||
[](https://www.npmjs.com/package/mermaid)
|
[](https://www.npmjs.com/package/mermaid)
|
||||||
[](https://discord.gg/AgrbSrBer3)
|
[](https://discord.gg/sKeNQX4Wtj)
|
||||||
[](https://twitter.com/mermaidjs_)
|
[](https://twitter.com/mermaidjs_)
|
||||||
[](https://argos-ci.com?utm_source=mermaid&utm_campaign=oss)
|
[](https://argos-ci.com?utm_source=mermaid&utm_campaign=oss)
|
||||||
[](https://securityscorecards.dev/viewer/?uri=github.com/mermaid-js/mermaid)
|
[](https://securityscorecards.dev/viewer/?uri=github.com/mermaid-js/mermaid)
|
||||||
@@ -44,7 +44,7 @@ Try Live Editor previews of future releases: <a href="https://develop.git.mermai
|
|||||||
|
|
||||||
**Thanks to all involved, people committing pull requests, people answering questions! 🙏**
|
**Thanks to all involved, people committing pull requests, people answering questions! 🙏**
|
||||||
|
|
||||||
<a href="https://mermaid.js.org/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
|
<a href="https://mermaid.js.org/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt='Banner for "The Official Guide to Mermaid.js" book'></a>
|
||||||
|
|
||||||
## Table of content
|
## Table of content
|
||||||
|
|
||||||
@@ -253,6 +253,34 @@ pie
|
|||||||
|
|
||||||
### Git graph [experimental - <a href="https://mermaid.live/edit#pako:eNqNkMFugzAMhl8F-VyVAR1tOW_aA-zKxSSGRCMJCk6lCvHuNZPKZdM0n-zf3_8r8QIqaIIGMqnB8kfEybQ--y4VnLP8-9RF9Mpkmm40hmlnDKmvkPiH_kfS7nFo_VN0FAf6XwocQGgxa_nGsm1bYEOOWmik1dRjGrmF1q-Cpkkj07u2HCI0PY4zHQATh8-7V9BwTPSE3iwOEd1OjQE1iWkBvk_bzQY7s0Sq4Hs7bHqKo8iGeZqbPN_WR7mpSd1RHpvPVhuMbG7XOq_L-oJlRfW5wteq0qorrpe-PBW9Pr8UJcK6rg-BLYPQ">live editor</a>]
|
### Git graph [experimental - <a href="https://mermaid.live/edit#pako:eNqNkMFugzAMhl8F-VyVAR1tOW_aA-zKxSSGRCMJCk6lCvHuNZPKZdM0n-zf3_8r8QIqaIIGMqnB8kfEybQ--y4VnLP8-9RF9Mpkmm40hmlnDKmvkPiH_kfS7nFo_VN0FAf6XwocQGgxa_nGsm1bYEOOWmik1dRjGrmF1q-Cpkkj07u2HCI0PY4zHQATh8-7V9BwTPSE3iwOEd1OjQE1iWkBvk_bzQY7s0Sq4Hs7bHqKo8iGeZqbPN_WR7mpSd1RHpvPVhuMbG7XOq_L-oJlRfW5wteq0qorrpe-PBW9Pr8UJcK6rg-BLYPQ">live editor</a>]
|
||||||
|
|
||||||
|
```
|
||||||
|
gitGraph
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
branch develop
|
||||||
|
checkout develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
merge develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
gitGraph
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
branch develop
|
||||||
|
checkout develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
merge develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
```
|
||||||
|
|
||||||
### Bar chart (using gantt chart) [<a href="https://mermaid.js.org/syntax/gantt.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNptkU1vhCAQhv8KIenNugiI4rkf6bmXpvEyFVxJFDYyNt1u9r8X63Z7WQ9m5pknLzieaBeMpQ3dg0dsPUkPOhwteXZIXmJcbCT3xMAxkuh8Z8kIEclyMIB209fqKcwTICFvG4IvFy_oLrZ-g9F26ILfQgvNFN94VaRXQ1iWqpumZBcu1J8p1E1TXDx59eQNr5LyEqjJn6hv5QnGNlxevZJmdLLpy5xJSzut45biYCfb0iaVxvawjNjS1p-TCguG16PvaIPzYjO67e3BwX6GiTY9jPFKH43DMF_hGMDY1J4oHg-_f8hFTJFd8L3br3yZx4QHxENsdrt1nO8dDstH3oVpF50ZYMbhU6ud4qoGLqyqBJRCmO6j0HXPZdGbihUc6Pmc0QP49xD-b5X69ZQv2gjO81IwzWqhC1lKrjJ6pA3nVS7SMiVjrKirWlYp5fs3osgrWeo00lorLWvOzz8JVbXm">live editor</a>]
|
### Bar chart (using gantt chart) [<a href="https://mermaid.js.org/syntax/gantt.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNptkU1vhCAQhv8KIenNugiI4rkf6bmXpvEyFVxJFDYyNt1u9r8X63Z7WQ9m5pknLzieaBeMpQ3dg0dsPUkPOhwteXZIXmJcbCT3xMAxkuh8Z8kIEclyMIB209fqKcwTICFvG4IvFy_oLrZ-g9F26ILfQgvNFN94VaRXQ1iWqpumZBcu1J8p1E1TXDx59eQNr5LyEqjJn6hv5QnGNlxevZJmdLLpy5xJSzut45biYCfb0iaVxvawjNjS1p-TCguG16PvaIPzYjO67e3BwX6GiTY9jPFKH43DMF_hGMDY1J4oHg-_f8hFTJFd8L3br3yZx4QHxENsdrt1nO8dDstH3oVpF50ZYMbhU6ud4qoGLqyqBJRCmO6j0HXPZdGbihUc6Pmc0QP49xD-b5X69ZQv2gjO81IwzWqhC1lKrjJ6pA3nVS7SMiVjrKirWlYp5fs3osgrWeo00lorLWvOzz8JVbXm">live editor</a>]
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -419,7 +447,7 @@ For public sites, it can be precarious to retrieve text from users on the intern
|
|||||||
|
|
||||||
As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing javascript in the code from being executed. This is a great step forward for better security.
|
As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing javascript in the code from being executed. This is a great step forward for better security.
|
||||||
|
|
||||||
_Unfortunately you can not have a cake and eat it at the same time which in this case means that some of the interactive functionality gets blocked along with the possible malicious code._
|
_Unfortunately you cannot have a cake and eat it at the same time which in this case means that some of the interactive functionality gets blocked along with the possible malicious code._
|
||||||
|
|
||||||
## Reporting vulnerabilities
|
## Reporting vulnerabilities
|
||||||
|
|
||||||
@@ -435,7 +463,7 @@ A quick note from Knut Sveidqvist:
|
|||||||
>
|
>
|
||||||
> _Thank you to [Tyler Long](https://github.com/tylerlong) who has been a collaborator since April 2017._
|
> _Thank you to [Tyler Long](https://github.com/tylerlong) who has been a collaborator since April 2017._
|
||||||
>
|
>
|
||||||
> _Thank you to the ever-growing list of [contributors](https://github.com/knsv/mermaid/graphs/contributors) that brought the project this far!_
|
> _Thank you to the ever-growing list of [contributors](https://github.com/mermaid-js/mermaid/graphs/contributors) that brought the project this far!_
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Mermaid
|
|||||||
<a href="https://mermaid.live/"><b>实时编辑器!</b></a>
|
<a href="https://mermaid.live/"><b>实时编辑器!</b></a>
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/AgrbSrBer3" title="Discord invite">🙌 加入我们</a>
|
<a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/sKeNQX4Wtj" title="Discord invite">🙌 加入我们</a>
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="./README.md">English</a>
|
<a href="./README.md">English</a>
|
||||||
@@ -34,7 +34,7 @@ Mermaid
|
|||||||
[](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
|
[](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
|
||||||
[](https://www.jsdelivr.com/package/npm/mermaid)
|
[](https://www.jsdelivr.com/package/npm/mermaid)
|
||||||
[](https://www.npmjs.com/package/mermaid)
|
[](https://www.npmjs.com/package/mermaid)
|
||||||
[](https://discord.gg/AgrbSrBer3)
|
[](https://discord.gg/sKeNQX4Wtj)
|
||||||
[](https://twitter.com/mermaidjs_)
|
[](https://twitter.com/mermaidjs_)
|
||||||
|
|
||||||
<img src="./img/header.png" alt="" />
|
<img src="./img/header.png" alt="" />
|
||||||
@@ -43,13 +43,13 @@ Mermaid
|
|||||||
|
|
||||||
**感谢所有参与进来提交 PR,解答疑问的人们! 🙏**
|
**感谢所有参与进来提交 PR,解答疑问的人们! 🙏**
|
||||||
|
|
||||||
<a href="https://mermaid.js.org/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
|
<a href="https://mermaid.js.org/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt='Banner for "The Official Guide to Mermaid.js" book'></a>
|
||||||
|
|
||||||
## 关于 Mermaid
|
## 关于 Mermaid
|
||||||
|
|
||||||
<!-- <Main description> -->
|
<!-- <Main description> -->
|
||||||
|
|
||||||
Mermaid 是一个基于 Javascript 的图表绘制工具,通过解析类 Markdown 的文本语法来实现图表的创建和动态修改。Mermaid 诞生的主要目的是让文档的更新能够及时跟上开发进度。
|
Mermaid 是一个基于 JavaScript 的图表绘制工具,通过解析类 Markdown 的文本语法来实现图表的创建和动态修改。Mermaid 诞生的主要目的是让文档的更新能够及时跟上开发进度。
|
||||||
|
|
||||||
> Doc-Rot 是 Mermaid 致力于解决的一个难题。
|
> Doc-Rot 是 Mermaid 致力于解决的一个难题。
|
||||||
|
|
||||||
@@ -358,7 +358,7 @@ _很不幸的是,鱼与熊掌不可兼得,在这个场景下它意味着在
|
|||||||
|
|
||||||
> _特别感谢 [d3](https://d3js.org/) 和 [dagre-d3](https://github.com/cpettitt/dagre-d3) 这两个优秀的项目,它们提供了图形布局和绘图工具库!_ > _同样感谢 [js-sequence-diagram](https://bramp.github.io/js-sequence-diagrams) 提供了时序图语法的使用。 感谢 Jessica Peter 提供了甘特图渲染的灵感。_ > _感谢 [Tyler Long](https://github.com/tylerlong) 从 2017 年四月开始成为了项目的合作者。_
|
> _特别感谢 [d3](https://d3js.org/) 和 [dagre-d3](https://github.com/cpettitt/dagre-d3) 这两个优秀的项目,它们提供了图形布局和绘图工具库!_ > _同样感谢 [js-sequence-diagram](https://bramp.github.io/js-sequence-diagrams) 提供了时序图语法的使用。 感谢 Jessica Peter 提供了甘特图渲染的灵感。_ > _感谢 [Tyler Long](https://github.com/tylerlong) 从 2017 年四月开始成为了项目的合作者。_
|
||||||
>
|
>
|
||||||
> _感谢越来越多的 [贡献者们](https://github.com/knsv/mermaid/graphs/contributors),没有你们,就没有这个项目的今天!_
|
> _感谢越来越多的 [贡献者们](https://github.com/mermaid-js/mermaid/graphs/contributors),没有你们,就没有这个项目的今天!_
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { MockedD3 } from '../packages/mermaid/src/tests/MockedD3.js';
|
|
||||||
|
|
||||||
export const select = function () {
|
|
||||||
return new MockedD3();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const selectAll = function () {
|
|
||||||
return new MockedD3();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const curveBasis = 'basis';
|
|
||||||
export const curveLinear = 'linear';
|
|
||||||
export const curveCardinal = 'cardinal';
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import eyesPlugin from '@applitools/eyes-cypress';
|
import eyesPlugin from '@applitools/eyes-cypress';
|
||||||
import { registerArgosTask } from '@argos-ci/cypress/task';
|
import { registerArgosTask } from '@argos-ci/cypress/task';
|
||||||
import coverage from '@cypress/code-coverage/task';
|
import coverage from '@cypress/code-coverage/task.js';
|
||||||
import { defineConfig } from 'cypress';
|
import { defineConfig } from 'cypress';
|
||||||
import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';
|
import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin.js';
|
||||||
import cypressSplit from 'cypress-split';
|
import cypressSplit from 'cypress-split';
|
||||||
|
|
||||||
export default eyesPlugin(
|
export default eyesPlugin(
|
||||||
@@ -23,11 +23,12 @@ export default eyesPlugin(
|
|||||||
});
|
});
|
||||||
// copy any needed variables from process.env to config.env
|
// copy any needed variables from process.env to config.env
|
||||||
config.env.useAppli = process.env.USE_APPLI ? true : false;
|
config.env.useAppli = process.env.USE_APPLI ? true : false;
|
||||||
config.env.useArgos = !!process.env.CI;
|
config.env.useArgos = process.env.RUN_VISUAL_TEST === 'true';
|
||||||
|
|
||||||
if (config.env.useArgos) {
|
if (config.env.useArgos) {
|
||||||
registerArgosTask(on, config, {
|
registerArgosTask(on, config, {
|
||||||
token: 'fc3a35cf5200db928d65b2047861582d9444032b',
|
// Enable upload to Argos only when it runs on CI.
|
||||||
|
uploadToArgos: !!process.env.CI,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
addMatchImageSnapshotPlugin(on, config);
|
addMatchImageSnapshotPlugin(on, config);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ interface CypressConfig {
|
|||||||
listUrl?: boolean;
|
listUrl?: boolean;
|
||||||
listId?: string;
|
listId?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
screenshot?: boolean;
|
||||||
}
|
}
|
||||||
type CypressMermaidConfig = MermaidConfig & CypressConfig;
|
type CypressMermaidConfig = MermaidConfig & CypressConfig;
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ interface CodeObject {
|
|||||||
mermaid: CypressMermaidConfig;
|
mermaid: CypressMermaidConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
const utf8ToB64 = (str: string): string => {
|
export const utf8ToB64 = (str: string): string => {
|
||||||
return Buffer.from(decodeURIComponent(encodeURIComponent(str))).toString('base64');
|
return Buffer.from(decodeURIComponent(encodeURIComponent(str))).toString('base64');
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ const batchId: string =
|
|||||||
'mermaid-batch-' +
|
'mermaid-batch-' +
|
||||||
(Cypress.env('useAppli')
|
(Cypress.env('useAppli')
|
||||||
? Date.now().toString()
|
? Date.now().toString()
|
||||||
: Cypress.env('CYPRESS_COMMIT') || Date.now().toString());
|
: (Cypress.env('CYPRESS_COMMIT') ?? Date.now().toString()));
|
||||||
|
|
||||||
export const mermaidUrl = (
|
export const mermaidUrl = (
|
||||||
graphStr: string | string[],
|
graphStr: string | string[],
|
||||||
@@ -61,9 +62,7 @@ export const imgSnapshotTest = (
|
|||||||
sequence: {
|
sequence: {
|
||||||
...(_options.sequence ?? {}),
|
...(_options.sequence ?? {}),
|
||||||
actorFontFamily: 'courier',
|
actorFontFamily: 'courier',
|
||||||
noteFontFamily: _options.sequence?.noteFontFamily
|
noteFontFamily: _options.sequence?.noteFontFamily ?? 'courier',
|
||||||
? _options.sequence.noteFontFamily
|
|
||||||
: 'courier',
|
|
||||||
messageFontFamily: 'courier',
|
messageFontFamily: 'courier',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -92,20 +91,33 @@ export const renderGraph = (
|
|||||||
|
|
||||||
export const openURLAndVerifyRendering = (
|
export const openURLAndVerifyRendering = (
|
||||||
url: string,
|
url: string,
|
||||||
options: CypressMermaidConfig,
|
{ screenshot = true, ...options }: CypressMermaidConfig,
|
||||||
validation?: any
|
validation?: any
|
||||||
): void => {
|
): void => {
|
||||||
const name: string = (options.name ?? cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
const name: string = (options.name ?? cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||||
|
|
||||||
cy.visit(url);
|
cy.visit(url);
|
||||||
cy.window().should('have.property', 'rendered', true);
|
cy.window().should('have.property', 'rendered', true);
|
||||||
cy.get('svg').should('be.visible');
|
|
||||||
|
|
||||||
if (validation) {
|
// Handle sandbox mode where SVG is inside an iframe
|
||||||
cy.get('svg').should(validation);
|
if (options.securityLevel === 'sandbox') {
|
||||||
|
cy.get('iframe').should('be.visible');
|
||||||
|
if (validation) {
|
||||||
|
cy.get('iframe').should(validation);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cy.get('svg').should('be.visible');
|
||||||
|
// cspell:ignore viewbox
|
||||||
|
cy.get('svg').should('not.have.attr', 'viewbox');
|
||||||
|
|
||||||
|
if (validation) {
|
||||||
|
cy.get('svg').should(validation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyScreenshot(name);
|
if (screenshot) {
|
||||||
|
verifyScreenshot(name);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const verifyScreenshot = (name: string): void => {
|
export const verifyScreenshot = (name: string): void => {
|
||||||
@@ -132,3 +144,10 @@ export const verifyScreenshot = (name: string): void => {
|
|||||||
cy.matchImageSnapshot(name);
|
cy.matchImageSnapshot(name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const verifyNumber = (value: number, expected: number, deltaPercent = 10): void => {
|
||||||
|
expect(value).to.be.within(
|
||||||
|
expected * (1 - deltaPercent / 100),
|
||||||
|
expected * (1 + deltaPercent / 100)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ describe('Configuration', () => {
|
|||||||
.and('include', 'url(#');
|
.and('include', 'url(#');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should handle arrowMarkerAbsolute explicitly set to "false" as false', () => {
|
// This has been broken for a long time, but something about the Cypress environment was
|
||||||
|
// rewriting the URL to be relative, causing the test to incorrectly pass.
|
||||||
|
it.skip('should handle arrowMarkerAbsolute explicitly set to "false" as false', () => {
|
||||||
renderGraph(
|
renderGraph(
|
||||||
`graph TD
|
`graph TD
|
||||||
A[Christmas] -->|Get money| B(Go shopping)
|
A[Christmas] -->|Get money| B(Go shopping)
|
||||||
@@ -96,12 +98,12 @@ describe('Configuration', () => {
|
|||||||
it('should handle arrowMarkerAbsolute set to true', () => {
|
it('should handle arrowMarkerAbsolute set to true', () => {
|
||||||
renderGraph(
|
renderGraph(
|
||||||
`flowchart TD
|
`flowchart TD
|
||||||
A[Christmas] -->|Get money| B(Go shopping)
|
A[Christmas] -->|Get money| B(Go shopping)
|
||||||
B --> C{Let me think}
|
B --> C{Let me think}
|
||||||
C -->|One| D[Laptop]
|
C -->|One| D[Laptop]
|
||||||
C -->|Two| E[iPhone]
|
C -->|Two| E[iPhone]
|
||||||
C -->|Three| F[fa:fa-car Car]
|
C -->|Three| F[fa:fa-car Car]
|
||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
arrowMarkerAbsolute: true,
|
arrowMarkerAbsolute: true,
|
||||||
}
|
}
|
||||||
@@ -111,7 +113,6 @@ describe('Configuration', () => {
|
|||||||
cy.get('path')
|
cy.get('path')
|
||||||
.first()
|
.first()
|
||||||
.should('have.attr', 'marker-end')
|
.should('have.attr', 'marker-end')
|
||||||
.should('exist')
|
|
||||||
.and('include', 'url(http://localhost');
|
.and('include', 'url(http://localhost');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ describe('Interaction', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Graph: should handle a click on a node with a bound url', () => {
|
it('Graph: should handle a click on a node with a bound url', () => {
|
||||||
// When there is a URL, cy.contains selects the a tag instead of the span. The .node is a child of a, so we have to use find instead of parent.
|
// When there is a URL, `cy.contains()` selects the `a` tag instead of the `span` tag. The .node is a child of `a`, so we have to use `find()` instead of `parent`.
|
||||||
cy.contains('URLTest1').find('.node').click();
|
cy.contains('URLTest1').find('.node').click();
|
||||||
cy.location().should(({ href }) => {
|
cy.location().should(({ href }) => {
|
||||||
expect(href).to.eq('http://localhost:9000/empty.html');
|
expect(href).to.eq('http://localhost:9000/empty.html');
|
||||||
@@ -146,7 +146,7 @@ describe('Interaction', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Interaction - security level other, missspelling', () => {
|
describe('Interaction - security level other, misspelling', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.visit('http://localhost:9000/click_security_other.html');
|
cy.visit('http://localhost:9000/click_security_other.html');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { mermaidUrl } from '../../helpers/util.ts';
|
import { imgSnapshotTest, mermaidUrl, utf8ToB64 } from '../../helpers/util.ts';
|
||||||
describe('XSS', () => {
|
describe('XSS', () => {
|
||||||
it('should handle xss in tags', () => {
|
it('should handle xss in tags', () => {
|
||||||
const str =
|
const str =
|
||||||
@@ -141,4 +141,37 @@ describe('XSS', () => {
|
|||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
cy.get('#the-malware').should('not.exist');
|
cy.get('#the-malware').should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should sanitize icon labels in architecture diagrams', () => {
|
||||||
|
const str = JSON.stringify({
|
||||||
|
code: `architecture-beta
|
||||||
|
group api(cloud)[API]
|
||||||
|
service db "<img src=x onerror=\\"xssAttack()\\">" [Database] in api`,
|
||||||
|
});
|
||||||
|
imgSnapshotTest(utf8ToB64(str), {}, true);
|
||||||
|
cy.wait(1000);
|
||||||
|
cy.get('#the-malware').should('not.exist');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sanitize katex blocks', () => {
|
||||||
|
const str = JSON.stringify({
|
||||||
|
code: `sequenceDiagram
|
||||||
|
participant A as Alice<img src="x" onerror="xssAttack()">$$\\text{Alice}$$
|
||||||
|
A->>John: Hello John, how are you?`,
|
||||||
|
});
|
||||||
|
imgSnapshotTest(utf8ToB64(str), {}, true);
|
||||||
|
cy.wait(1000);
|
||||||
|
cy.get('#the-malware').should('not.exist');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sanitize labels', () => {
|
||||||
|
const str = JSON.stringify({
|
||||||
|
code: `erDiagram
|
||||||
|
"<img src=x onerror=xssAttack()>" ||--|| ENTITY2 : "<img src=x onerror=xssAttack()>"
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
imgSnapshotTest(utf8ToB64(str), {}, true);
|
||||||
|
cy.wait(1000);
|
||||||
|
cy.get('#the-malware').should('not.exist');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,6 +19,25 @@ describe.skip('architecture diagram', () => {
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should render a simple architecture diagram with titleAndAccessibilities', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`architecture-beta
|
||||||
|
title Simple Architecture Diagram
|
||||||
|
accTitle: Accessibility Title
|
||||||
|
accDescr: Accessibility Description
|
||||||
|
group api(cloud)[API]
|
||||||
|
|
||||||
|
service db(database)[Database] in api
|
||||||
|
service disk1(disk)[Storage] in api
|
||||||
|
service disk2(disk)[Storage] in api
|
||||||
|
service server(server)[Server] in api
|
||||||
|
|
||||||
|
db:L -- R:server
|
||||||
|
disk1:T -- B:server
|
||||||
|
disk2:T -- B:db
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
it('should render an architecture diagram with groups within groups', () => {
|
it('should render an architecture diagram with groups within groups', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`architecture-beta
|
`architecture-beta
|
||||||
@@ -172,7 +191,7 @@ describe.skip('architecture diagram', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render an architecture diagram with a resonable height', () => {
|
it('should render an architecture diagram with a reasonable height', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`architecture-beta
|
`architecture-beta
|
||||||
group federated(cloud)[Federated Environment]
|
group federated(cloud)[Federated Environment]
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ describe('Block diagram', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('BL2: should handle colums statement in sub-blocks', () => {
|
it('BL2: should handle columns statement in sub-blocks', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
id1["Hello"]
|
id1["Hello"]
|
||||||
block
|
block
|
||||||
columns 3
|
columns 3
|
||||||
@@ -30,9 +30,9 @@ describe('Block diagram', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('BL3: should align block widths and handle colums statement in sub-blocks', () => {
|
it('BL3: should align block widths and handle columns statement in sub-blocks', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
block
|
block
|
||||||
columns 1
|
columns 1
|
||||||
id1
|
id1
|
||||||
@@ -46,9 +46,9 @@ describe('Block diagram', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('BL4: should align block widths and handle colums statements in deeper sub-blocks then 1 level', () => {
|
it('BL4: should align block widths and handle columns statements in deeper sub-blocks then 1 level', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 1
|
columns 1
|
||||||
block
|
block
|
||||||
columns 1
|
columns 1
|
||||||
@@ -66,9 +66,9 @@ describe('Block diagram', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('BL5: should align block widths and handle colums statements in deeper sub-blocks then 1 level (alt)', () => {
|
it('BL5: should align block widths and handle columns statements in deeper sub-blocks then 1 level (alt)', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 1
|
columns 1
|
||||||
block
|
block
|
||||||
id1
|
id1
|
||||||
@@ -87,7 +87,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL6: should handle block arrows and spece statements', () => {
|
it('BL6: should handle block arrows and spece statements', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 3
|
columns 3
|
||||||
space:3
|
space:3
|
||||||
ida idb idc
|
ida idb idc
|
||||||
@@ -106,7 +106,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL7: should handle different types of edges', () => {
|
it('BL7: should handle different types of edges', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 3
|
columns 3
|
||||||
A space:5
|
A space:5
|
||||||
A --o B
|
A --o B
|
||||||
@@ -119,7 +119,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL8: should handle sub-blocks without columns statements', () => {
|
it('BL8: should handle sub-blocks without columns statements', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 2
|
columns 2
|
||||||
C A B
|
C A B
|
||||||
block
|
block
|
||||||
@@ -133,7 +133,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL9: should handle edges from blocks in sub blocks to other blocks', () => {
|
it('BL9: should handle edges from blocks in sub blocks to other blocks', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 3
|
columns 3
|
||||||
B space
|
B space
|
||||||
block
|
block
|
||||||
@@ -147,7 +147,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL10: should handle edges from composite blocks', () => {
|
it('BL10: should handle edges from composite blocks', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 3
|
columns 3
|
||||||
B space
|
B space
|
||||||
block BL
|
block BL
|
||||||
@@ -161,7 +161,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL11: should handle edges to composite blocks', () => {
|
it('BL11: should handle edges to composite blocks', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 3
|
columns 3
|
||||||
B space
|
B space
|
||||||
block BL
|
block BL
|
||||||
@@ -175,7 +175,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL12: edges should handle labels', () => {
|
it('BL12: edges should handle labels', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
A
|
A
|
||||||
space
|
space
|
||||||
A -- "apa" --> E
|
A -- "apa" --> E
|
||||||
@@ -186,7 +186,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL13: should handle block arrows in different directions', () => {
|
it('BL13: should handle block arrows in different directions', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 3
|
columns 3
|
||||||
space blockArrowId1<["down"]>(down) space
|
space blockArrowId1<["down"]>(down) space
|
||||||
blockArrowId2<["right"]>(right) blockArrowId3<["Sync"]>(x, y) blockArrowId4<["left"]>(left)
|
blockArrowId2<["right"]>(right) blockArrowId3<["Sync"]>(x, y) blockArrowId4<["left"]>(left)
|
||||||
@@ -199,7 +199,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL14: should style statements and class statements', () => {
|
it('BL14: should style statements and class statements', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
A
|
A
|
||||||
B
|
B
|
||||||
classDef blue fill:#66f,stroke:#333,stroke-width:2px;
|
classDef blue fill:#66f,stroke:#333,stroke-width:2px;
|
||||||
@@ -212,7 +212,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL15: width alignment - D and E should share available space', () => {
|
it('BL15: width alignment - D and E should share available space', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
block
|
block
|
||||||
D
|
D
|
||||||
E
|
E
|
||||||
@@ -225,7 +225,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL16: width alignment - C should be as wide as the composite block', () => {
|
it('BL16: width alignment - C should be as wide as the composite block', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
block
|
block
|
||||||
A("This is the text")
|
A("This is the text")
|
||||||
B
|
B
|
||||||
@@ -236,9 +236,9 @@ describe('Block diagram', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('BL17: width alignment - blocks shold be equal in width', () => {
|
it('BL17: width alignment - blocks should be equal in width', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
A("This is the text")
|
A("This is the text")
|
||||||
B
|
B
|
||||||
C
|
C
|
||||||
@@ -249,7 +249,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL18: block types 1 - square, rounded and circle', () => {
|
it('BL18: block types 1 - square, rounded and circle', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
A["square"]
|
A["square"]
|
||||||
B("rounded")
|
B("rounded")
|
||||||
C(("circle"))
|
C(("circle"))
|
||||||
@@ -260,7 +260,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL19: block types 2 - odd, diamond and hexagon', () => {
|
it('BL19: block types 2 - odd, diamond and hexagon', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
A>"rect_left_inv_arrow"]
|
A>"rect_left_inv_arrow"]
|
||||||
B{"diamond"}
|
B{"diamond"}
|
||||||
C{{"hexagon"}}
|
C{{"hexagon"}}
|
||||||
@@ -271,7 +271,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL20: block types 3 - stadium', () => {
|
it('BL20: block types 3 - stadium', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
A(["stadium"])
|
A(["stadium"])
|
||||||
`,
|
`,
|
||||||
{}
|
{}
|
||||||
@@ -280,7 +280,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL21: block types 4 - lean right, lean left, trapezoid and inv trapezoid', () => {
|
it('BL21: block types 4 - lean right, lean left, trapezoid and inv trapezoid', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
A[/"lean right"/]
|
A[/"lean right"/]
|
||||||
B[\"lean left"\]
|
B[\"lean left"\]
|
||||||
C[/"trapezoid"\]
|
C[/"trapezoid"\]
|
||||||
@@ -292,7 +292,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL22: block types 1 - square, rounded and circle', () => {
|
it('BL22: block types 1 - square, rounded and circle', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
A["square"]
|
A["square"]
|
||||||
B("rounded")
|
B("rounded")
|
||||||
C(("circle"))
|
C(("circle"))
|
||||||
@@ -303,7 +303,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL23: sizing - it should be possible to make a block wider', () => {
|
it('BL23: sizing - it should be possible to make a block wider', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
A("rounded"):2
|
A("rounded"):2
|
||||||
B:2
|
B:2
|
||||||
C
|
C
|
||||||
@@ -314,7 +314,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL24: sizing - it should be possible to make a composite block wider', () => {
|
it('BL24: sizing - it should be possible to make a composite block wider', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
block:2
|
block:2
|
||||||
A
|
A
|
||||||
end
|
end
|
||||||
@@ -326,7 +326,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL25: block in the middle with space on each side', () => {
|
it('BL25: block in the middle with space on each side', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 3
|
columns 3
|
||||||
space
|
space
|
||||||
middle["In the middle"]
|
middle["In the middle"]
|
||||||
@@ -337,7 +337,7 @@ describe('Block diagram', () => {
|
|||||||
});
|
});
|
||||||
it('BL26: space and an edge', () => {
|
it('BL26: space and an edge', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 5
|
columns 5
|
||||||
A space B
|
A space B
|
||||||
A --x B
|
A --x B
|
||||||
@@ -347,7 +347,7 @@ describe('Block diagram', () => {
|
|||||||
});
|
});
|
||||||
it('BL27: block sizes for regular blocks', () => {
|
it('BL27: block sizes for regular blocks', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 3
|
columns 3
|
||||||
a["A wide one"] b:2 c:2 d
|
a["A wide one"] b:2 c:2 d
|
||||||
`,
|
`,
|
||||||
@@ -356,7 +356,7 @@ describe('Block diagram', () => {
|
|||||||
});
|
});
|
||||||
it('BL28: composite block with a set width - f should use the available space', () => {
|
it('BL28: composite block with a set width - f should use the available space', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 3
|
columns 3
|
||||||
a:3
|
a:3
|
||||||
block:e:3
|
block:e:3
|
||||||
@@ -370,7 +370,7 @@ describe('Block diagram', () => {
|
|||||||
|
|
||||||
it('BL29: composite block with a set width - f and g should split the available space', () => {
|
it('BL29: composite block with a set width - f and g should split the available space', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`block-beta
|
`block
|
||||||
columns 3
|
columns 3
|
||||||
a:3
|
a:3
|
||||||
block:e:3
|
block:e:3
|
||||||
@@ -384,4 +384,28 @@ describe('Block diagram', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('BL30: block should overflow if too wide for columns', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`block-beta
|
||||||
|
columns 2
|
||||||
|
fit:2
|
||||||
|
overflow:3
|
||||||
|
short:1
|
||||||
|
also_overflow:2
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('BL31: edge without arrow syntax should render with no arrowheads', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`block-beta
|
||||||
|
a
|
||||||
|
b
|
||||||
|
a --- b
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -114,4 +114,28 @@ describe('C4 diagram', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('C4.6 should render C4Context diagram with ComponentQueue_Ext', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
C4Context
|
||||||
|
title System Context diagram with ComponentQueue_Ext
|
||||||
|
|
||||||
|
Enterprise_Boundary(b0, "BankBoundary0") {
|
||||||
|
Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")
|
||||||
|
|
||||||
|
System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.")
|
||||||
|
|
||||||
|
Enterprise_Boundary(b1, "BankBoundary") {
|
||||||
|
ComponentQueue_Ext(msgQueue, "Message Queue", "RabbitMQ", "External message queue system for processing banking transactions")
|
||||||
|
System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BiRel(customerA, SystemAA, "Uses")
|
||||||
|
Rel(SystemAA, msgQueue, "Sends messages to")
|
||||||
|
Rel(SystemAA, SystemC, "Sends e-mails", "SMTP")
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -562,6 +562,20 @@ class C13["With Città foreign language"]
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should add notes in namespaces', function () {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
classDiagram
|
||||||
|
note "This is a outer note"
|
||||||
|
note for C1 "This is a outer note for C1"
|
||||||
|
namespace Namespace1 {
|
||||||
|
note "This is a inner note"
|
||||||
|
note for C1 "This is a inner note for C1"
|
||||||
|
class C1
|
||||||
|
}
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
it('should render a simple class diagram with no members', () => {
|
it('should render a simple class diagram with no members', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -709,6 +709,20 @@ class C13["With Città foreign language"]
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should add notes in namespaces', function () {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
classDiagram
|
||||||
|
note "This is a outer note"
|
||||||
|
note for C1 "This is a outer note for C1"
|
||||||
|
namespace Namespace1 {
|
||||||
|
note "This is a inner note"
|
||||||
|
note for C1 "This is a inner note for C1"
|
||||||
|
class C1
|
||||||
|
}
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
it('should render a simple class diagram with no members', () => {
|
it('should render a simple class diagram with no members', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ describe('Class diagram', () => {
|
|||||||
classDiagram
|
classDiagram
|
||||||
class \`This\nTitle\nHas\nMany\nNewlines\` {
|
class \`This\nTitle\nHas\nMany\nNewlines\` {
|
||||||
+String Also
|
+String Also
|
||||||
-Stirng Many
|
-String Many
|
||||||
#int Members
|
#int Members
|
||||||
+And()
|
+And()
|
||||||
-Many()
|
-Many()
|
||||||
@@ -443,7 +443,7 @@ describe('Class diagram', () => {
|
|||||||
classDiagram
|
classDiagram
|
||||||
class \`This\nTitle\nHas\nMany\nNewlines\` {
|
class \`This\nTitle\nHas\nMany\nNewlines\` {
|
||||||
+String Also
|
+String Also
|
||||||
-Stirng Many
|
-String Many
|
||||||
#int Members
|
#int Members
|
||||||
+And()
|
+And()
|
||||||
-Many()
|
-Many()
|
||||||
@@ -459,7 +459,7 @@ describe('Class diagram', () => {
|
|||||||
namespace testingNamespace {
|
namespace testingNamespace {
|
||||||
class \`This\nTitle\nHas\nMany\nNewlines\` {
|
class \`This\nTitle\nHas\nMany\nNewlines\` {
|
||||||
+String Also
|
+String Also
|
||||||
-Stirng Many
|
-String Many
|
||||||
#int Members
|
#int Members
|
||||||
+And()
|
+And()
|
||||||
-Many()
|
-Many()
|
||||||
@@ -495,4 +495,47 @@ describe('Class diagram', () => {
|
|||||||
cy.get('a').should('have.attr', 'target', '_blank').should('have.attr', 'rel', 'noopener');
|
cy.get('a').should('have.attr', 'target', '_blank').should('have.attr', 'rel', 'noopener');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Include char sequence "graph" in text (#6795)', () => {
|
||||||
|
it('has a label with char sequence "graph"', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
classDiagram
|
||||||
|
class Person {
|
||||||
|
+String name
|
||||||
|
-Int id
|
||||||
|
#double age
|
||||||
|
+Text demographicProfile
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ flowchart: { defaultRenderer: 'elk' } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle backticks for namespace and class names', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
classDiagram
|
||||||
|
namespace \`A::B\` {
|
||||||
|
class \`IPC::Sender\`
|
||||||
|
}
|
||||||
|
RenderProcessHost --|> \`IPC::Sender\`
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
it('should handle an empty class body with empty braces', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
` classDiagram
|
||||||
|
class FooBase~T~ {}
|
||||||
|
class Bar {
|
||||||
|
+Zip
|
||||||
|
+Zap()
|
||||||
|
}
|
||||||
|
FooBase <|-- Ba
|
||||||
|
`,
|
||||||
|
{ flowchart: { defaultRenderer: 'elk' } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
652
cypress/integration/rendering/erDiagram-unified.spec.js
Normal file
652
cypress/integration/rendering/erDiagram-unified.spec.js
Normal file
@@ -0,0 +1,652 @@
|
|||||||
|
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||||
|
|
||||||
|
const testOptions = [
|
||||||
|
{ description: '', options: { logLevel: 1 } },
|
||||||
|
{ description: 'ELK: ', options: { logLevel: 1, layout: 'elk' } },
|
||||||
|
{ description: 'HD: ', options: { logLevel: 1, look: 'handDrawn' } },
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('Entity Relationship Diagram Unified', () => {
|
||||||
|
testOptions.forEach(({ description, options }) => {
|
||||||
|
it(`${description}should render a simple ER diagram`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER ||--o{ ORDER : places
|
||||||
|
ORDER ||--|{ LINE-ITEM : contains
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a simple ER diagram without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER ||--o{ ORDER : places
|
||||||
|
ORDER ||--|{ LINE-ITEM : contains
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render an ER diagram with a recursive relationship`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER ||..o{ CUSTOMER : refers
|
||||||
|
CUSTOMER ||--o{ ORDER : places
|
||||||
|
ORDER ||--|{ LINE-ITEM : contains
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render an ER diagram with multiple relationships between the same two entities`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER ||--|{ ADDRESS : "invoiced at"
|
||||||
|
CUSTOMER ||--|{ ADDRESS : "receives goods at"
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a cyclical ER diagram`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
A ||--|{ B : likes
|
||||||
|
B ||--|{ C : likes
|
||||||
|
C ||--|{ A : likes
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a not-so-simple ER diagram`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER }|..|{ DELIVERY-ADDRESS : has
|
||||||
|
CUSTOMER ||--o{ ORDER : places
|
||||||
|
CUSTOMER ||--o{ INVOICE : "liable for"
|
||||||
|
DELIVERY-ADDRESS ||--o{ ORDER : receives
|
||||||
|
INVOICE ||--|{ ORDER : covers
|
||||||
|
ORDER ||--|{ ORDER-ITEM : includes
|
||||||
|
PRODUCT-CATEGORY ||--|{ PRODUCT : contains
|
||||||
|
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a not-so-simple ER diagram without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER }|..|{ DELIVERY-ADDRESS : has
|
||||||
|
CUSTOMER ||--o{ ORDER : places
|
||||||
|
CUSTOMER ||--o{ INVOICE : "liable for"
|
||||||
|
DELIVERY-ADDRESS ||--o{ ORDER : receives
|
||||||
|
INVOICE ||--|{ ORDER : covers
|
||||||
|
ORDER ||--|{ ORDER-ITEM : includes
|
||||||
|
PRODUCT-CATEGORY ||--|{ PRODUCT : contains
|
||||||
|
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render multiple ER diagrams`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
[
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER ||--o{ ORDER : places
|
||||||
|
ORDER ||--|{ LINE-ITEM : contains
|
||||||
|
`,
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER ||--o{ ORDER : places
|
||||||
|
ORDER ||--|{ LINE-ITEM : contains
|
||||||
|
`,
|
||||||
|
],
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render an ER diagram with blank or empty labels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
BOOK }|..|{ AUTHOR : ""
|
||||||
|
BOOK }|..|{ GENRE : " "
|
||||||
|
AUTHOR }|..|{ GENRE : " "
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities that have no relationships`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
DEAD_PARROT
|
||||||
|
HERMIT
|
||||||
|
RECLUSE
|
||||||
|
SOCIALITE }o--o{ SOCIALITE : "interacts with"
|
||||||
|
RECLUSE }o--o{ SOCIALITE : avoids
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with and without attributes`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
BOOK { string title }
|
||||||
|
AUTHOR }|..|{ BOOK : writes
|
||||||
|
BOOK { float price }
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with generic and array attributes`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
BOOK {
|
||||||
|
string title
|
||||||
|
string[] authors
|
||||||
|
type~T~ type
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with generic and array attributes without htmlLabels`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
BOOK {
|
||||||
|
string title
|
||||||
|
string[] authors
|
||||||
|
type~T~ type
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with length in attributes type`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CLUSTER {
|
||||||
|
varchar(99) name
|
||||||
|
string(255) description
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with length in attributes type without htmlLabels`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CLUSTER {
|
||||||
|
varchar(99) name
|
||||||
|
string(255) description
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities and attributes with big and small entity names`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
PRIVATE_FINANCIAL_INSTITUTION {
|
||||||
|
string name
|
||||||
|
int turnover
|
||||||
|
}
|
||||||
|
PRIVATE_FINANCIAL_INSTITUTION ||..|{ EMPLOYEE : employs
|
||||||
|
EMPLOYEE { bool officer_of_firm }
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities and attributes with big and small entity names without htmlLabels`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
PRIVATE_FINANCIAL_INSTITUTION {
|
||||||
|
string name
|
||||||
|
int turnover
|
||||||
|
}
|
||||||
|
PRIVATE_FINANCIAL_INSTITUTION ||..|{ EMPLOYEE : employs
|
||||||
|
EMPLOYEE { bool officer_of_firm }
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with attributes that begin with asterisk`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
BOOK {
|
||||||
|
int *id
|
||||||
|
string name
|
||||||
|
varchar(99) summary
|
||||||
|
}
|
||||||
|
BOOK }o..o{ STORE : soldBy
|
||||||
|
STORE {
|
||||||
|
int *id
|
||||||
|
string name
|
||||||
|
varchar(50) address
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with attributes that begin with asterisk without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
BOOK {
|
||||||
|
int *id
|
||||||
|
string name
|
||||||
|
varchar(99) summary
|
||||||
|
}
|
||||||
|
BOOK }o..o{ STORE : soldBy
|
||||||
|
STORE {
|
||||||
|
int *id
|
||||||
|
string name
|
||||||
|
varchar(50) address
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with keys`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME {
|
||||||
|
string name PK
|
||||||
|
}
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
|
||||||
|
BOOK {
|
||||||
|
float price
|
||||||
|
string author FK
|
||||||
|
string title PK
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with keys without htmlLabels`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME {
|
||||||
|
string name PK
|
||||||
|
}
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
|
||||||
|
BOOK {
|
||||||
|
float price
|
||||||
|
string author FK
|
||||||
|
string title PK
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with comments`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME {
|
||||||
|
string name "comment"
|
||||||
|
}
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
|
||||||
|
BOOK {
|
||||||
|
string author
|
||||||
|
string title "author comment"
|
||||||
|
float price "price comment"
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with comments without htmlLabels`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME {
|
||||||
|
string name "comment"
|
||||||
|
}
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
|
||||||
|
BOOK {
|
||||||
|
string author
|
||||||
|
string title "author comment"
|
||||||
|
float price "price comment"
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with keys and comments`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME {
|
||||||
|
string name PK "comment"
|
||||||
|
}
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
|
||||||
|
BOOK {
|
||||||
|
string description
|
||||||
|
float price "price comment"
|
||||||
|
string title PK "title comment"
|
||||||
|
string author FK
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with keys and comments without htmlLabels`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME {
|
||||||
|
string name PK "comment"
|
||||||
|
}
|
||||||
|
AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
|
||||||
|
BOOK {
|
||||||
|
string description
|
||||||
|
float price "price comment"
|
||||||
|
string title PK "title comment"
|
||||||
|
string author FK
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with aliases`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
T1 one or zero to one or more T2 : test
|
||||||
|
T2 one or many optionally to zero or one T3 : test
|
||||||
|
T3 zero or more to zero or many T4 : test
|
||||||
|
T4 many(0) to many(1) T5 : test
|
||||||
|
T5 many optionally to one T6 : test
|
||||||
|
T6 only one optionally to only one T1 : test
|
||||||
|
T4 0+ to 1+ T6 : test
|
||||||
|
T1 1 to 1 T3 : test
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a simple ER diagram with a title`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`---
|
||||||
|
title: simple ER diagram
|
||||||
|
---
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER ||--o{ ORDER : places
|
||||||
|
ORDER ||--|{ LINE-ITEM : contains
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with entity name aliases`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
p[Person] {
|
||||||
|
varchar(64) firstName
|
||||||
|
varchar(64) lastName
|
||||||
|
}
|
||||||
|
c["Customer Account"] {
|
||||||
|
varchar(128) email
|
||||||
|
}
|
||||||
|
p ||--o| c : has
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render relationship labels with line breaks`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
p[Person] {
|
||||||
|
string firstName
|
||||||
|
string lastName
|
||||||
|
}
|
||||||
|
a["Customer Account"] {
|
||||||
|
string email
|
||||||
|
}
|
||||||
|
|
||||||
|
b["Customer Account Secondary"] {
|
||||||
|
string email
|
||||||
|
}
|
||||||
|
|
||||||
|
c["Customer Account Tertiary"] {
|
||||||
|
string email
|
||||||
|
}
|
||||||
|
|
||||||
|
d["Customer Account Nth"] {
|
||||||
|
string email
|
||||||
|
}
|
||||||
|
|
||||||
|
p ||--o| a : "has<br />one"
|
||||||
|
p ||--o| b : "has<br />one<br />two"
|
||||||
|
p ||--o| c : "has<br />one<br/>two<br />three"
|
||||||
|
p ||--o| d : "has<br />one<br />two<br/>three<br />...<br/>Nth"
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render an ER diagram with unicode text`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
_**testẽζ➕Ø😀㌕ぼ**_ {
|
||||||
|
*__List~List~int~~sdfds__* **driversLicense** PK "***The l😀icense #***"
|
||||||
|
*string(99)~T~~~~~~* firstName "Only __99__ <br>characters are a<br>llowed dsfsdfsdfsdfs"
|
||||||
|
string last*Name*
|
||||||
|
string __phone__ UK
|
||||||
|
int _age_
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render an ER diagram with unicode text without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
_**testẽζ➕Ø😀㌕ぼ**_ {
|
||||||
|
*__List~List~int~~sdfds__* **driversLicense** PK "***The l😀icense #***"
|
||||||
|
*string(99)~T~~~~~~* firstName "Only __99__ <br>characters are a<br>llowed dsfsdfsdfsdfs"
|
||||||
|
string last*Name*
|
||||||
|
string __phone__ UK
|
||||||
|
int _age_
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render an ER diagram with relationships with unicode text`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
person[😀] {
|
||||||
|
string *first*Name
|
||||||
|
string _**last**Name_
|
||||||
|
}
|
||||||
|
a["*Customer Account*"] {
|
||||||
|
**string** ema*i*l
|
||||||
|
}
|
||||||
|
person ||--o| a : __hẽ😀__
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render an ER diagram with relationships with unicode text without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
person[😀] {
|
||||||
|
string *first*Name
|
||||||
|
string _**last**Name_
|
||||||
|
}
|
||||||
|
a["*Customer Account*"] {
|
||||||
|
**string** ema*i*l
|
||||||
|
}
|
||||||
|
person ||--o| a : __hẽ😀__
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render an ER diagram with TB direction`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
direction TB
|
||||||
|
CAR ||--|{ NAMED-DRIVER : allows
|
||||||
|
PERSON ||..o{ NAMED-DRIVER : is
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render an ER diagram with BT direction`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
direction BT
|
||||||
|
CAR ||--|{ NAMED-DRIVER : allows
|
||||||
|
PERSON ||..o{ NAMED-DRIVER : is
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render an ER diagram with LR direction`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
direction LR
|
||||||
|
CAR ||--|{ NAMED-DRIVER : allows
|
||||||
|
PERSON ||..o{ NAMED-DRIVER : is
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render an ER diagram with RL direction`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
direction RL
|
||||||
|
CAR ||--|{ NAMED-DRIVER : allows
|
||||||
|
PERSON ||..o{ NAMED-DRIVER : is
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with styles applied from style statement`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
c[CUSTOMER]
|
||||||
|
p[PERSON]
|
||||||
|
style c,p fill:#f9f,stroke:blue, color:grey, font-size:24px,font-weight:bold
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with styles applied from style statement without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
c[CUSTOMER]
|
||||||
|
p[PERSON]
|
||||||
|
style c,p fill:#f9f,stroke:blue, color:grey, font-size:24px,font-weight:bold
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with styles applied from class statement`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
c[CUSTOMER]
|
||||||
|
p[PERSON]:::blue
|
||||||
|
classDef bold font-size:24px, font-weight: bold
|
||||||
|
classDef blue stroke:lightblue, color: #0000FF
|
||||||
|
class c,p bold
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with styles applied from class statement without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
c[CUSTOMER]
|
||||||
|
p[PERSON]:::blue
|
||||||
|
classDef bold font-size:24px, font-weight: bold
|
||||||
|
classDef blue stroke:lightblue, color: #0000FF
|
||||||
|
class c,p bold
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render entities with styles applied from the default class and other styles`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
c[CUSTOMER]
|
||||||
|
p[PERSON]:::blue
|
||||||
|
classDef blue stroke:lightblue, color: #0000FF
|
||||||
|
classDef default fill:pink
|
||||||
|
style c color:green
|
||||||
|
`,
|
||||||
|
{ ...options }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -109,8 +109,8 @@ describe('Entity Relationship Diagram', () => {
|
|||||||
const style = svg.attr('style');
|
const style = svg.attr('style');
|
||||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
// use within because the absolute value can be slightly different depending on the environment ±6%
|
||||||
expect(maxWidthValue).to.be.within(140 * 0.95, 140 * 1.05);
|
expect(maxWidthValue).to.be.within(140 * 0.96, 140 * 1.06);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -125,8 +125,8 @@ describe('Entity Relationship Diagram', () => {
|
|||||||
);
|
);
|
||||||
cy.get('svg').should((svg) => {
|
cy.get('svg').should((svg) => {
|
||||||
const width = parseFloat(svg.attr('width'));
|
const width = parseFloat(svg.attr('width'));
|
||||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
// use within because the absolute value can be slightly different depending on the environment ±6%
|
||||||
expect(width).to.be.within(140 * 0.95, 140 * 1.05);
|
expect(width).to.be.within(140 * 0.96, 140 * 1.06);
|
||||||
// expect(svg).to.have.attr('height', '465');
|
// expect(svg).to.have.attr('height', '465');
|
||||||
expect(svg).to.not.have.attr('style');
|
expect(svg).to.not.have.attr('style');
|
||||||
});
|
});
|
||||||
@@ -354,4 +354,107 @@ ORDER ||--|{ LINE-ITEM : contains
|
|||||||
{ logLevel: 1 }
|
{ logLevel: 1 }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Include char sequence "graph" in text (#6795)', () => {
|
||||||
|
it('has a label with char sequence "graph"', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
p[Photograph] {
|
||||||
|
varchar(12) jobId
|
||||||
|
date dateCreated
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ flowchart: { defaultRenderer: 'elk' } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Special characters and numbers syntax', () => {
|
||||||
|
it('should render ER diagram with numeric entity names', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
1 ||--|| ORDER : places
|
||||||
|
ORDER ||--|{ 2 : contains
|
||||||
|
2 ||--o{ 3.5 : references
|
||||||
|
`,
|
||||||
|
{ logLevel: 1 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render ER diagram with "u" character in entity names and cardinality', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER ||--|| u : has
|
||||||
|
u ||--|| ORDER : places
|
||||||
|
PROJECT u--o{ TEAM_MEMBER : "parent"
|
||||||
|
`,
|
||||||
|
{ logLevel: 1 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render ER diagram with decimal numbers in relationships', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
2.5 ||--|| 1.5 : has
|
||||||
|
CUSTOMER ||--o{ 3.14 : references
|
||||||
|
1.0 ||--|{ ORDER : contains
|
||||||
|
`,
|
||||||
|
{ logLevel: 1 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render ER diagram with numeric entity names and attributes', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
1 {
|
||||||
|
string name
|
||||||
|
int value
|
||||||
|
}
|
||||||
|
1 ||--|| ORDER : places
|
||||||
|
ORDER {
|
||||||
|
float price
|
||||||
|
string description
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ logLevel: 1 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render complex ER diagram with mixed special entity names', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER ||--o{ 1 : places
|
||||||
|
1 ||--|{ u : contains
|
||||||
|
1.5
|
||||||
|
u ||--|| 2.5 : processes
|
||||||
|
2.5 {
|
||||||
|
string id
|
||||||
|
float value
|
||||||
|
}
|
||||||
|
u {
|
||||||
|
varchar(50) name
|
||||||
|
int count
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ logLevel: 1 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should render ER diagram with standalone numeric entities', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`erDiagram
|
||||||
|
PRODUCT ||--o{ ORDER-ITEM : has
|
||||||
|
1.5
|
||||||
|
u
|
||||||
|
1
|
||||||
|
`,
|
||||||
|
{ logLevel: 1 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
import { imgSnapshotTest, renderGraph, verifyNumber } from '../../helpers/util.ts';
|
||||||
|
|
||||||
describe('Flowchart ELK', () => {
|
describe('Flowchart ELK', () => {
|
||||||
it('1-elk: should render a simple flowchart', () => {
|
it('1-elk: should render a simple flowchart', () => {
|
||||||
@@ -109,7 +109,7 @@ describe('Flowchart ELK', () => {
|
|||||||
const style = svg.attr('style');
|
const style = svg.attr('style');
|
||||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||||
expect(maxWidthValue).to.be.within(230 * 0.95, 230 * 1.05);
|
verifyNumber(maxWidthValue, 380, 15);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('8-elk: should render a flowchart when useMaxWidth is false', () => {
|
it('8-elk: should render a flowchart when useMaxWidth is false', () => {
|
||||||
@@ -128,7 +128,7 @@ describe('Flowchart ELK', () => {
|
|||||||
const width = parseFloat(svg.attr('width'));
|
const width = parseFloat(svg.attr('width'));
|
||||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||||
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
||||||
expect(width).to.be.within(230 * 0.95, 230 * 1.05);
|
verifyNumber(width, 380, 15);
|
||||||
expect(svg).to.not.have.attr('style');
|
expect(svg).to.not.have.attr('style');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -208,13 +208,13 @@ describe('Flowchart ELK', () => {
|
|||||||
`flowchart-elk TB
|
`flowchart-elk TB
|
||||||
internet
|
internet
|
||||||
nat
|
nat
|
||||||
routeur
|
router
|
||||||
lb1
|
lb1
|
||||||
lb2
|
lb2
|
||||||
compute1
|
compute1
|
||||||
compute2
|
compute2
|
||||||
subgraph project
|
subgraph project
|
||||||
routeur
|
router
|
||||||
nat
|
nat
|
||||||
subgraph subnet1
|
subgraph subnet1
|
||||||
compute1
|
compute1
|
||||||
@@ -225,8 +225,8 @@ describe('Flowchart ELK', () => {
|
|||||||
lb2
|
lb2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
internet --> routeur
|
internet --> router
|
||||||
routeur --> subnet1 & subnet2
|
router --> subnet1 & subnet2
|
||||||
subnet1 & subnet2 --> nat --> internet
|
subnet1 & subnet2 --> nat --> internet
|
||||||
`,
|
`,
|
||||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||||
@@ -443,7 +443,7 @@ flowchart-elk TD
|
|||||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('63-elk: title on subgraphs should be themable', () => {
|
it('63-elk: title on subgraphs should be themeable', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
%%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
|
%%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
|
||||||
@@ -692,7 +692,7 @@ A --> B
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
cy.get('svg').should((svg) => {
|
cy.get('svg').should((svg) => {
|
||||||
const edges = svg.querySelectorAll('.edges > path');
|
const edges = svg[0].querySelectorAll('.edges > path');
|
||||||
edges.forEach((edge) => {
|
edges.forEach((edge) => {
|
||||||
expect(edge).to.have.class('flowchart-link');
|
expect(edge).to.have.class('flowchart-link');
|
||||||
});
|
});
|
||||||
@@ -739,7 +739,7 @@ NL\`") --"\`1o **bold**\`"--> c
|
|||||||
{ flowchart: { titleTopMargin: 0 } }
|
{ flowchart: { titleTopMargin: 0 } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('Wrapping long text with a new line', () => {
|
it.skip('Wrapping long text with a new line', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
|
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
|
||||||
flowchart-elk LR
|
flowchart-elk LR
|
||||||
@@ -841,7 +841,7 @@ end
|
|||||||
{ flowchart: { titleTopMargin: 0 } }
|
{ flowchart: { titleTopMargin: 0 } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('Sub graphs and markdown strings', () => {
|
it('Sub graphs', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`---
|
`---
|
||||||
config:
|
config:
|
||||||
@@ -1053,6 +1053,21 @@ flowchart LR
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('6647-elk: should keep node order when using elk layout unless it would add crossings', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
---
|
||||||
|
flowchart TB
|
||||||
|
a --> a1 & a2 & a3 & a4
|
||||||
|
b --> b1 & b2
|
||||||
|
b2 --> b3
|
||||||
|
b1 --> b4
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Title and arrow styling #4813', () => {
|
describe('Title and arrow styling #4813', () => {
|
||||||
|
|||||||
@@ -1029,4 +1029,19 @@ graph TD
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('FDH49: should add edge animation', () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
flowchart TD
|
||||||
|
A(["Start"]) L_A_B_0@--> B{"Decision"}
|
||||||
|
B --> C["Option A"] & D["Option B"]
|
||||||
|
style C stroke-width:4px,stroke-dasharray: 5
|
||||||
|
L_A_B_0@{ animation: slow }
|
||||||
|
L_B_D_0@{ animation: fast }`,
|
||||||
|
{ look: 'handDrawn', screenshot: false }
|
||||||
|
);
|
||||||
|
cy.get('path#L_A_B_0').should('have.class', 'edge-animation-slow');
|
||||||
|
cy.get('path#L_B_D_0').should('have.class', 'edge-animation-fast');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
28
cypress/integration/rendering/flowchart-icon.spec.js
Normal file
28
cypress/integration/rendering/flowchart-icon.spec.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { imgSnapshotTest } from '../../helpers/util.ts';
|
||||||
|
|
||||||
|
const themes = ['default', 'forest', 'dark', 'base', 'neutral'];
|
||||||
|
|
||||||
|
describe('when rendering flowchart with icons', () => {
|
||||||
|
for (const theme of themes) {
|
||||||
|
it(`should render icons from fontawesome library on theme ${theme}`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart TD
|
||||||
|
A("fab:fa-twitter Twitter") --> B("fab:fa-facebook Facebook")
|
||||||
|
B --> C("fa:fa-coffee Coffee")
|
||||||
|
C --> D("fa:fa-car Car")
|
||||||
|
D --> E("fab:fa-github GitHub")
|
||||||
|
`,
|
||||||
|
{ theme }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should render registered icons on theme ${theme}`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart TD
|
||||||
|
A("fa:fa-bell Bell")
|
||||||
|
`,
|
||||||
|
{ theme }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -79,6 +79,18 @@ describe('Flowchart v2', () => {
|
|||||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('6a: should render complex HTML in labels with sandbox security', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart TD
|
||||||
|
A[Christmas] -->|Get money| B(Go shopping)
|
||||||
|
B --> C{Let me think}
|
||||||
|
C -->|One| D[Laptop]
|
||||||
|
C -->|Two| E[iPhone]
|
||||||
|
C -->|Three| F[fa:fa-car Car]
|
||||||
|
`,
|
||||||
|
{ securityLevel: 'sandbox', flowchart: { htmlLabels: true } }
|
||||||
|
);
|
||||||
|
});
|
||||||
it('7: should render a flowchart when useMaxWidth is true (default)', () => {
|
it('7: should render a flowchart when useMaxWidth is true (default)', () => {
|
||||||
renderGraph(
|
renderGraph(
|
||||||
`flowchart TD
|
`flowchart TD
|
||||||
@@ -99,7 +111,7 @@ describe('Flowchart v2', () => {
|
|||||||
const style = svg.attr('style');
|
const style = svg.attr('style');
|
||||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||||
expect(maxWidthValue).to.be.within(417 * 0.95, 417 * 1.05);
|
expect(maxWidthValue).to.be.within(440 * 0.95, 440 * 1.05);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('8: should render a flowchart when useMaxWidth is false', () => {
|
it('8: should render a flowchart when useMaxWidth is false', () => {
|
||||||
@@ -118,7 +130,7 @@ describe('Flowchart v2', () => {
|
|||||||
const width = parseFloat(svg.attr('width'));
|
const width = parseFloat(svg.attr('width'));
|
||||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||||
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
||||||
expect(width).to.be.within(417 * 0.95, 417 * 1.05);
|
expect(width).to.be.within(440 * 0.95, 440 * 1.05);
|
||||||
expect(svg).to.not.have.attr('style');
|
expect(svg).to.not.have.attr('style');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -198,13 +210,13 @@ describe('Flowchart v2', () => {
|
|||||||
`flowchart TB
|
`flowchart TB
|
||||||
internet
|
internet
|
||||||
nat
|
nat
|
||||||
routeur
|
router
|
||||||
lb1
|
lb1
|
||||||
lb2
|
lb2
|
||||||
compute1
|
compute1
|
||||||
compute2
|
compute2
|
||||||
subgraph project
|
subgraph project
|
||||||
routeur
|
router
|
||||||
nat
|
nat
|
||||||
subgraph subnet1
|
subgraph subnet1
|
||||||
compute1
|
compute1
|
||||||
@@ -215,8 +227,8 @@ describe('Flowchart v2', () => {
|
|||||||
lb2
|
lb2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
internet --> routeur
|
internet --> router
|
||||||
routeur --> subnet1 & subnet2
|
router --> subnet1 & subnet2
|
||||||
subnet1 & subnet2 --> nat --> internet
|
subnet1 & subnet2 --> nat --> internet
|
||||||
`,
|
`,
|
||||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||||
@@ -433,7 +445,7 @@ flowchart TD
|
|||||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('63: title on subgraphs should be themable', () => {
|
it('63: title on subgraphs should be themeable', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
%%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
|
%%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
|
||||||
@@ -699,7 +711,7 @@ A --> B
|
|||||||
{ flowchart: { titleTopMargin: 10 } }
|
{ flowchart: { titleTopMargin: 10 } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('3192: It should be possieble to render flowcharts with invisible edges', () => {
|
it('3192: It should be possible to render flowcharts with invisible edges', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`---
|
`---
|
||||||
title: Simple flowchart with invisible edges
|
title: Simple flowchart with invisible edges
|
||||||
@@ -1076,4 +1088,127 @@ end
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('New @ syntax for node metadata edge cases', () => {
|
||||||
|
it('should be possible to use @ syntax to add labels on multi nodes', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart TB
|
||||||
|
n2["label for n2"] & n4@{ label: "label for n4"} & n5@{ label: "label for n5"}
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should be possible to use @ syntax to add labels with trail spaces and &', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart TB
|
||||||
|
n2["label for n2"] & n4@{ label: "label for n4"} & n5@{ label: "label for n5"}
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should be possible to use @ syntax to add labels with trail spaces', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart TB
|
||||||
|
n2["label for n2"]
|
||||||
|
n4@{ label: "label for n4"}
|
||||||
|
n5@{ label: "label for n5"}
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should be possible to use @ syntax to add labels with trail spaces and edge/link', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart TD
|
||||||
|
A["A"] --> B["for B"] & C@{ label: "for c"} & E@{label : "for E"}
|
||||||
|
D@{label: "for D"}
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('Flowchart Node Shape Rendering', () => {
|
||||||
|
it('should render a stadium-shaped node', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart TB
|
||||||
|
A(["Start"]) --> n1["Untitled Node"]
|
||||||
|
A --> n2["Untitled Node"]
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should render a diamond-shaped node using shape config', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart BT
|
||||||
|
n2["Untitled Node"] --> n1["Diamond"]
|
||||||
|
n1@{ shape: diam}
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should render a rounded rectangle and a normal rectangle', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart BT
|
||||||
|
n2["Untitled Node"] --> n1["Rounded Rectangle"]
|
||||||
|
n3["Untitled Node"] --> n1
|
||||||
|
n1@{ shape: rounded}
|
||||||
|
n3@{ shape: rect}
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('6617: Per Link Curve Styling using edge Ids', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart TD
|
||||||
|
A e1@-->B e5@--> E
|
||||||
|
E e7@--> D
|
||||||
|
B e3@-->D
|
||||||
|
A e2@-->C e4@-->D
|
||||||
|
C e6@--> F
|
||||||
|
F e8@--> D
|
||||||
|
e1@{ curve: natural }
|
||||||
|
e2@{ curve: stepAfter }
|
||||||
|
e3@{ curve: monotoneY }
|
||||||
|
e4@{ curve: bumpY }
|
||||||
|
e5@{ curve: linear }
|
||||||
|
e6@{ curve: catmullRom }
|
||||||
|
e7@{ curve: cardinal }
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when rendering unsuported markdown', () => {
|
||||||
|
const graph = `flowchart TB
|
||||||
|
mermaid{"What is\nyourmermaid version?"} --> v10["<11"] --"\`<**1**1\`"--> fine["No bug"]
|
||||||
|
mermaid --> v11[">= v11"] -- ">= v11" --> broken["Affected by https://github.com/mermaid-js/mermaid/issues/5824"]
|
||||||
|
subgraph subgraph1["\`How to fix **fix**\`"]
|
||||||
|
broken --> B["B"]
|
||||||
|
end
|
||||||
|
githost["Github, Gitlab, BitBucket, etc."]
|
||||||
|
githost2["\`Github, Gitlab, BitBucket, etc.\`"]
|
||||||
|
a["1."]
|
||||||
|
b["- x"]
|
||||||
|
`;
|
||||||
|
|
||||||
|
it('should render raw strings', () => {
|
||||||
|
imgSnapshotTest(graph);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render raw strings with htmlLabels: false', () => {
|
||||||
|
imgSnapshotTest(graph, { htmlLabels: false });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('V2 - 17: should apply class def colour to edge label', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
` graph LR
|
||||||
|
id1(Start) link@-- "Label" -->id2(Stop)
|
||||||
|
style id1 fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
|
|
||||||
|
class id2 myClass
|
||||||
|
classDef myClass fill:#bbf,stroke:#f66,stroke-width:2px,color:white,stroke-dasharray: 5 5
|
||||||
|
class link myClass
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -774,6 +774,21 @@ describe('Graph', () => {
|
|||||||
expect(svg).to.not.have.attr('style');
|
expect(svg).to.not.have.attr('style');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('40: should add edge animation', () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
flowchart TD
|
||||||
|
A(["Start"]) L_A_B_0@--> B{"Decision"}
|
||||||
|
B --> C["Option A"] & D["Option B"]
|
||||||
|
style C stroke-width:4px,stroke-dasharray: 5
|
||||||
|
L_A_B_0@{ animation: slow }
|
||||||
|
L_B_D_0@{ animation: fast }`,
|
||||||
|
{ screenshot: false }
|
||||||
|
);
|
||||||
|
// Verify animation classes are applied to both edges
|
||||||
|
cy.get('path#L_A_B_0').should('have.class', 'edge-animation-slow');
|
||||||
|
cy.get('path#L_B_D_0').should('have.class', 'edge-animation-fast');
|
||||||
|
});
|
||||||
it('58: handle styling with style expressions', () => {
|
it('58: handle styling with style expressions', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
@@ -895,7 +910,7 @@ graph TD
|
|||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
graph TD
|
graph TD
|
||||||
classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff
|
classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff
|
||||||
hello --> default
|
hello --> default
|
||||||
`,
|
`,
|
||||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||||
@@ -917,4 +932,75 @@ graph TD
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('#6369: edge color should affect arrow head', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
flowchart LR
|
||||||
|
A --> B
|
||||||
|
A --> C
|
||||||
|
C --> D
|
||||||
|
|
||||||
|
linkStyle 0 stroke:#D50000
|
||||||
|
linkStyle 2 stroke:#D50000
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
flowchart: { htmlLabels: true },
|
||||||
|
securityLevel: 'loose',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('68: should honor subgraph direction when inheritDir is false', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
%%{init: {"flowchart": { "inheritDir": false }}}%%
|
||||||
|
flowchart TB
|
||||||
|
direction LR
|
||||||
|
subgraph A
|
||||||
|
direction TB
|
||||||
|
a --> b
|
||||||
|
end
|
||||||
|
subgraph B
|
||||||
|
c --> d
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
fontFamily: 'courier',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('69: should inherit global direction when inheritDir is true', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
%%{init: {"flowchart": { "inheritDir": true }}}%%
|
||||||
|
flowchart TB
|
||||||
|
direction LR
|
||||||
|
subgraph A
|
||||||
|
direction TB
|
||||||
|
a --> b
|
||||||
|
end
|
||||||
|
subgraph B
|
||||||
|
c --> d
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
fontFamily: 'courier',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('70: should render a subgraph with direction TD', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
flowchart LR
|
||||||
|
subgraph A
|
||||||
|
direction TD
|
||||||
|
a --> b
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
fontFamily: 'courier',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ describe('Gantt diagram', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should FAIL redering a gantt chart for issue #1060 with invalid date', () => {
|
it('should FAIL rendering a gantt chart for issue #1060 with invalid date', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
gantt
|
gantt
|
||||||
@@ -358,6 +358,23 @@ describe('Gantt diagram', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render a gantt diagram with a vert tag', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gantt
|
||||||
|
title A Gantt Diagram
|
||||||
|
dateFormat ss
|
||||||
|
axisFormat %Ss
|
||||||
|
|
||||||
|
section Section
|
||||||
|
A task : a1, 00, 6s
|
||||||
|
Milestone : vert, 01,
|
||||||
|
section Another
|
||||||
|
Task in sec : 06, 3s
|
||||||
|
another task : 3s
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
it('should render a gantt diagram with tick is 2 milliseconds', () => {
|
it('should render a gantt diagram with tick is 2 milliseconds', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
@@ -548,6 +565,18 @@ describe('Gantt diagram', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render only the day when using dateFormat D', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gantt
|
||||||
|
title Test
|
||||||
|
dateFormat D
|
||||||
|
A :a, 1, 1d
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: fix it
|
// TODO: fix it
|
||||||
//
|
//
|
||||||
// This test is skipped deliberately
|
// This test is skipped deliberately
|
||||||
@@ -573,7 +602,7 @@ describe('Gantt diagram', () => {
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should render a gantt diagram exculding friday and saturday', () => {
|
it('should render a gantt diagram excluding friday and saturday', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`gantt
|
`gantt
|
||||||
title A Gantt Diagram
|
title A Gantt Diagram
|
||||||
@@ -584,7 +613,7 @@ describe('Gantt diagram', () => {
|
|||||||
A task :a1, 2024-02-28, 10d`
|
A task :a1, 2024-02-28, 10d`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should render a gantt diagram exculding saturday and sunday', () => {
|
it('should render a gantt diagram excluding saturday and sunday', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`gantt
|
`gantt
|
||||||
title A Gantt Diagram
|
title A Gantt Diagram
|
||||||
@@ -630,6 +659,49 @@ describe('Gantt diagram', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render a gantt diagram excluding a specific date in YYYY-MM-DD HH:mm:ss format', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gantt
|
||||||
|
dateFormat YYYY-MM-DD HH:mm:ss
|
||||||
|
excludes 2025-07-07
|
||||||
|
section Section
|
||||||
|
A task :a1, 2025-07-04 20:30:30, 2025-07-08 10:30:30
|
||||||
|
Another task:after a1, 20h
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render a gantt diagram excluding saturday and sunday in YYYY-MM-DD HH:mm:ss format', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gantt
|
||||||
|
dateFormat YYYY-MM-DD HH:mm:ss
|
||||||
|
excludes weekends
|
||||||
|
weekend saturday
|
||||||
|
section Section
|
||||||
|
A task :a1, 2025-07-04 20:30:30, 2025-07-08 10:30:30
|
||||||
|
Another task:after a1, 20h
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should render a gantt diagram excluding friday and saturday in YYYY-MM-DD HH:mm:ss format', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gantt
|
||||||
|
dateFormat YYYY-MM-DD HH:mm:ss
|
||||||
|
excludes weekends
|
||||||
|
weekend friday
|
||||||
|
section Section
|
||||||
|
A task :a1, 2025-07-04 20:30:30, 2025-07-08 10:30:30
|
||||||
|
Another task:after a1, 20h
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("should render when there's a semicolon in the title", () => {
|
it("should render when there's a semicolon in the title", () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
@@ -671,7 +743,7 @@ describe('Gantt diagram', () => {
|
|||||||
title Gantt Digram
|
title Gantt Digram
|
||||||
dateFormat YYYY-MM-DD
|
dateFormat YYYY-MM-DD
|
||||||
section Section
|
section Section
|
||||||
;A task with a semiclon :a1, 2014-01-01, 30d
|
;A task with a semicolon :a1, 2014-01-01, 30d
|
||||||
Another task :after a1 , 20d
|
Another task :after a1 , 20d
|
||||||
section Another
|
section Another
|
||||||
Task in sec :2014-01-12 , 12d
|
Task in sec :2014-01-12 , 12d
|
||||||
@@ -731,4 +803,64 @@ describe('Gantt diagram', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should handle numeric timestamps with dateFormat x', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gantt
|
||||||
|
title Process time profile (ms)
|
||||||
|
dateFormat x
|
||||||
|
axisFormat %L
|
||||||
|
tickInterval 250millisecond
|
||||||
|
|
||||||
|
section Pipeline
|
||||||
|
Parse JSON p1: 000, 120
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should handle numeric timestamps with dateFormat X', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gantt
|
||||||
|
title Process time profile (ms)
|
||||||
|
dateFormat X
|
||||||
|
axisFormat %L
|
||||||
|
tickInterval 250millisecond
|
||||||
|
|
||||||
|
section Pipeline
|
||||||
|
Parse JSON p1: 000, 120
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should handle seconds-only format with tickInterval (issue #5496)', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gantt
|
||||||
|
tickInterval 1second
|
||||||
|
dateFormat ss
|
||||||
|
axisFormat %s
|
||||||
|
|
||||||
|
section Network Request
|
||||||
|
RTT : rtt, 0, 20
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should handle dates with year typo like 202 instead of 2024 (issue #5496)', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gantt
|
||||||
|
title Schedule
|
||||||
|
dateFormat YYYY-MM-DD
|
||||||
|
tickInterval 1week
|
||||||
|
axisFormat %m-%d
|
||||||
|
|
||||||
|
section Vacation
|
||||||
|
London : 2024-12-01, 7d
|
||||||
|
London : 202-12-01, 7d
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ describe('Git Graph diagram', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('2: should render a simple gitgraph with commit on main branch with Id', () => {
|
it('2: should render a simple gitgraph with commit on main branch with id', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`gitGraph
|
`gitGraph
|
||||||
commit id: "One"
|
commit id: "One"
|
||||||
@@ -253,7 +253,7 @@ describe('Git Graph diagram', () => {
|
|||||||
`
|
`
|
||||||
gitGraph
|
gitGraph
|
||||||
checkout main
|
checkout main
|
||||||
%% Make sure to manually set the ID of all commits, for consistent visual tests
|
%% Make sure to manually set the id of all commits, for consistent visual tests
|
||||||
commit id: "1-abcdefg"
|
commit id: "1-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
branch branch1
|
branch branch1
|
||||||
@@ -343,7 +343,7 @@ gitGraph
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('16: should render a simple gitgraph with commit on main branch with Id | Vertical Branch', () => {
|
it('16: should render a simple gitgraph with commit on main branch with id | Vertical Branch', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`gitGraph TB:
|
`gitGraph TB:
|
||||||
commit id: "One"
|
commit id: "One"
|
||||||
@@ -585,7 +585,7 @@ gitGraph
|
|||||||
`
|
`
|
||||||
gitGraph TB:
|
gitGraph TB:
|
||||||
checkout main
|
checkout main
|
||||||
%% Make sure to manually set the ID of all commits, for consistent visual tests
|
%% Make sure to manually set the id of all commits, for consistent visual tests
|
||||||
commit id: "1-abcdefg"
|
commit id: "1-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
branch branch1
|
branch branch1
|
||||||
@@ -1024,7 +1024,7 @@ gitGraph TB:
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('51: should render a simple gitgraph with commit on main branch with Id | Vertical Branch - Bottom-to-top', () => {
|
it('51: should render a simple gitgraph with commit on main branch with id | Vertical Branch - Bottom-to-top', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`gitGraph BT:
|
`gitGraph BT:
|
||||||
commit id: "One"
|
commit id: "One"
|
||||||
@@ -1266,7 +1266,7 @@ gitGraph TB:
|
|||||||
`
|
`
|
||||||
gitGraph BT:
|
gitGraph BT:
|
||||||
checkout main
|
checkout main
|
||||||
%% Make sure to manually set the ID of all commits, for consistent visual tests
|
%% Make sure to manually set the id of all commits, for consistent visual tests
|
||||||
commit id: "1-abcdefg"
|
commit id: "1-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
branch branch1
|
branch branch1
|
||||||
@@ -1491,7 +1491,7 @@ gitGraph TB:
|
|||||||
`
|
`
|
||||||
gitGraph
|
gitGraph
|
||||||
switch main
|
switch main
|
||||||
%% Make sure to manually set the ID of all commits, for consistent visual tests
|
%% Make sure to manually set the id of all commits, for consistent visual tests
|
||||||
commit id: "1-abcdefg"
|
commit id: "1-abcdefg"
|
||||||
switch main
|
switch main
|
||||||
branch branch1
|
branch branch1
|
||||||
|
|||||||
@@ -63,4 +63,199 @@ section Checkout from website
|
|||||||
{ journey: { useMaxWidth: false } }
|
{ journey: { useMaxWidth: false } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should initialize with a left margin of 150px for user journeys', () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
journey:
|
||||||
|
maxLabelWidth: 320
|
||||||
|
---
|
||||||
|
journey
|
||||||
|
title User Journey Example
|
||||||
|
section Onboarding
|
||||||
|
Sign Up: 5:
|
||||||
|
Browse Features: 3:
|
||||||
|
Use Core Functionality: 4:
|
||||||
|
section Engagement
|
||||||
|
Browse Features: 3
|
||||||
|
Use Core Functionality: 4
|
||||||
|
`,
|
||||||
|
{ journey: { useMaxWidth: true } }
|
||||||
|
);
|
||||||
|
|
||||||
|
let diagramStartX;
|
||||||
|
|
||||||
|
cy.contains('foreignobject', 'Sign Up').then(($diagram) => {
|
||||||
|
diagramStartX = parseFloat($diagram.attr('x'));
|
||||||
|
expect(diagramStartX).to.be.closeTo(150, 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should maintain sufficient space between legend and diagram when legend labels are longer', () => {
|
||||||
|
renderGraph(
|
||||||
|
`journey
|
||||||
|
title Web hook life cycle
|
||||||
|
section Darkoob
|
||||||
|
Make preBuilt:5: Darkoob user
|
||||||
|
register slug : 5: Darkoob userf deliberately increasing the size of this label to check if distance between legend and diagram is maintained
|
||||||
|
Map slug to a Prebuilt Job:5: Darkoob user
|
||||||
|
section External Service
|
||||||
|
set Darkoob slug as hook for an Event : 5 : admin Exjjjnjjjj qwerty
|
||||||
|
listen to the events : 5 : External Service
|
||||||
|
call darkoob endpoint : 5 : External Service
|
||||||
|
section Darkoob
|
||||||
|
check for inputs : 5 : DarkoobAPI
|
||||||
|
run the prebuilt job : 5 : DarkoobAPI
|
||||||
|
`,
|
||||||
|
{ journey: { useMaxWidth: true } }
|
||||||
|
);
|
||||||
|
|
||||||
|
let LabelEndX, diagramStartX;
|
||||||
|
|
||||||
|
// Get right edge of the legend
|
||||||
|
cy.contains('tspan', 'Darkoob userf').then((textBox) => {
|
||||||
|
const bbox = textBox[0].getBBox();
|
||||||
|
LabelEndX = bbox.x + bbox.width;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get left edge of the diagram
|
||||||
|
cy.contains('foreignobject', 'Make preBuilt').then((rect) => {
|
||||||
|
diagramStartX = parseFloat(rect.attr('x'));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert right edge of the diagram is greater than or equal to the right edge of the label
|
||||||
|
cy.then(() => {
|
||||||
|
expect(diagramStartX).to.be.gte(LabelEndX);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should wrap a single long word with hyphenation', () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
journey:
|
||||||
|
maxLabelWidth: 100
|
||||||
|
---
|
||||||
|
journey
|
||||||
|
title Long Word Test
|
||||||
|
section Test
|
||||||
|
VeryLongWord: 5: Supercalifragilisticexpialidocious
|
||||||
|
`,
|
||||||
|
{ journey: { useMaxWidth: true } }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that the line ends with a hyphen, indicating proper hyphenation for words exceeding maxLabelWidth.
|
||||||
|
cy.get('tspan').then((tspans) => {
|
||||||
|
const hasHyphen = [...tspans].some((t) => t.textContent.trim().endsWith('-'));
|
||||||
|
return expect(hasHyphen).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should wrap text on whitespace without adding hyphens', () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
journey:
|
||||||
|
maxLabelWidth: 200
|
||||||
|
---
|
||||||
|
journey
|
||||||
|
title Whitespace Test
|
||||||
|
section Test
|
||||||
|
TextWithSpaces: 5: Gustavo Fring is played by Giancarlo Esposito and is a character in Breaking Bad.
|
||||||
|
`,
|
||||||
|
{ journey: { useMaxWidth: true } }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that none of the text spans end with a hyphen.
|
||||||
|
cy.get('tspan').each(($el) => {
|
||||||
|
const text = $el.text();
|
||||||
|
expect(text.trim()).not.to.match(/-$/);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should wrap long labels into multiple lines, keep them under max width, and maintain margins', () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
journey:
|
||||||
|
maxLabelWidth: 320
|
||||||
|
---
|
||||||
|
journey
|
||||||
|
title User Journey Example
|
||||||
|
section Onboarding
|
||||||
|
Sign Up: 5: This is a long label that will be split into multiple lines to test the wrapping functionality
|
||||||
|
Browse Features: 3: This is another long label that will be split into multiple lines to test the wrapping functionality
|
||||||
|
Use Core Functionality: 4: This is yet another long label that will be split into multiple lines to test the wrapping functionality
|
||||||
|
section Engagement
|
||||||
|
Browse Features: 3
|
||||||
|
Use Core Functionality: 4
|
||||||
|
`,
|
||||||
|
{ journey: { useMaxWidth: true } }
|
||||||
|
);
|
||||||
|
|
||||||
|
let diagramStartX, maxLineWidth;
|
||||||
|
|
||||||
|
// Get the diagram's left edge x-coordinate
|
||||||
|
cy.contains('foreignobject', 'Sign Up')
|
||||||
|
.then(($diagram) => {
|
||||||
|
diagramStartX = parseFloat($diagram.attr('x'));
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
cy.get('text.legend').then(($lines) => {
|
||||||
|
// Check that there are multiple lines
|
||||||
|
expect($lines.length).to.be.equal(9);
|
||||||
|
|
||||||
|
// Check that all lines are under the maxLabelWidth
|
||||||
|
$lines.each((index, el) => {
|
||||||
|
const bbox = el.getBBox();
|
||||||
|
expect(bbox.width).to.be.lte(320);
|
||||||
|
maxLineWidth = Math.max(maxLineWidth || 0, bbox.width);
|
||||||
|
});
|
||||||
|
|
||||||
|
/** The expected margin between the diagram and the legend is 150px, as defined by
|
||||||
|
* conf.leftMargin in user-journey-config.js
|
||||||
|
*/
|
||||||
|
expect(diagramStartX - maxLineWidth).to.be.closeTo(150, 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly render the user journey diagram title with the specified styling', () => {
|
||||||
|
renderGraph(
|
||||||
|
`---
|
||||||
|
config:
|
||||||
|
journey:
|
||||||
|
titleColor: "#2900A5"
|
||||||
|
titleFontFamily: "Times New Roman"
|
||||||
|
titleFontSize: "5rem"
|
||||||
|
---
|
||||||
|
|
||||||
|
journey
|
||||||
|
title User Journey Example
|
||||||
|
section Onboarding
|
||||||
|
Sign Up: 5: John, Shahir
|
||||||
|
Complete Profile: 4: John
|
||||||
|
section Engagement
|
||||||
|
Browse Features: 3: John
|
||||||
|
Use Core Functionality: 4: John
|
||||||
|
section Retention
|
||||||
|
Revisit Application: 5: John
|
||||||
|
Invite Friends: 3: John
|
||||||
|
|
||||||
|
size: 2rem
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
cy.get('text').contains('User Journey Example').as('title');
|
||||||
|
cy.get('@title').then(($title) => {
|
||||||
|
expect($title).to.have.attr('fill', '#2900A5');
|
||||||
|
expect($title).to.have.attr('font-family', 'Times New Roman');
|
||||||
|
expect($title).to.have.attr('font-size', '5rem');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ describe('Kanban diagram', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('6: should handle assigments', () => {
|
it('6: should handle assignments', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`kanban
|
`kanban
|
||||||
id1[Todo]
|
id1[Todo]
|
||||||
@@ -118,7 +118,7 @@ kanban
|
|||||||
docs[Create Documentation]
|
docs[Create Documentation]
|
||||||
docs[Create Blog about the new diagram]
|
docs[Create Blog about the new diagram]
|
||||||
id7[In progress]
|
id7[In progress]
|
||||||
id6[Create renderer so that it works in all cases. We also add som extra text here for testing purposes. And some more just for the extra flare.]
|
id6[Create renderer so that it works in all cases. We also add some extra text here for testing purposes. And some more just for the extra flare.]
|
||||||
id8[Design grammar]@{ assigned: 'knsv' }
|
id8[Design grammar]@{ assigned: 'knsv' }
|
||||||
id9[Ready for deploy]
|
id9[Ready for deploy]
|
||||||
id10[Ready for test]
|
id10[Ready for test]
|
||||||
|
|||||||
79
cypress/integration/rendering/mindmap-tidy-tree.spec.js
Normal file
79
cypress/integration/rendering/mindmap-tidy-tree.spec.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import { imgSnapshotTest } from '../../helpers/util.ts';
|
||||||
|
|
||||||
|
describe('Mindmap Tidy Tree', () => {
|
||||||
|
it('1-tidy-tree: should render a simple mindmap without children', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
` ---
|
||||||
|
config:
|
||||||
|
layout: tidy-tree
|
||||||
|
---
|
||||||
|
mindmap
|
||||||
|
root((mindmap))
|
||||||
|
A
|
||||||
|
B
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('2-tidy-tree: should render a simple mindmap', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
` ---
|
||||||
|
config:
|
||||||
|
layout: tidy-tree
|
||||||
|
---
|
||||||
|
mindmap
|
||||||
|
root((mindmap is a long thing))
|
||||||
|
A
|
||||||
|
B
|
||||||
|
C
|
||||||
|
D
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('3-tidy-tree: should render a mindmap with different shapes', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
` ---
|
||||||
|
config:
|
||||||
|
layout: tidy-tree
|
||||||
|
---
|
||||||
|
mindmap
|
||||||
|
root((mindmap))
|
||||||
|
Origins
|
||||||
|
Long history
|
||||||
|
::icon(fa fa-book)
|
||||||
|
Popularisation
|
||||||
|
British popular psychology author Tony Buzan
|
||||||
|
Research
|
||||||
|
On effectiveness<br/>and features
|
||||||
|
On Automatic creation
|
||||||
|
Uses
|
||||||
|
Creative techniques
|
||||||
|
Strategic planning
|
||||||
|
Argument mapping
|
||||||
|
Tools
|
||||||
|
id)I am a cloud(
|
||||||
|
id))I am a bang((
|
||||||
|
Tools
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('4-tidy-tree: should render a mindmap with children', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
` ---
|
||||||
|
config:
|
||||||
|
layout: tidy-tree
|
||||||
|
---
|
||||||
|
mindmap
|
||||||
|
((This is a mindmap))
|
||||||
|
child1
|
||||||
|
grandchild 1
|
||||||
|
grandchild 2
|
||||||
|
child2
|
||||||
|
grandchild 3
|
||||||
|
grandchild 4
|
||||||
|
child3
|
||||||
|
grandchild 5
|
||||||
|
grandchild 6
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -146,7 +146,7 @@ root
|
|||||||
shouldHaveRoot
|
shouldHaveRoot
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('text shouhld wrap with icon', () => {
|
it('text should wrap with icon', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`mindmap
|
`mindmap
|
||||||
root
|
root
|
||||||
@@ -159,12 +159,10 @@ root
|
|||||||
});
|
});
|
||||||
it('square shape', () => {
|
it('square shape', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`mindmap
|
||||||
mindmap
|
|
||||||
root[
|
root[
|
||||||
The root
|
The root
|
||||||
]
|
]`,
|
||||||
`,
|
|
||||||
{},
|
{},
|
||||||
undefined,
|
undefined,
|
||||||
shouldHaveRoot
|
shouldHaveRoot
|
||||||
@@ -172,12 +170,10 @@ mindmap
|
|||||||
});
|
});
|
||||||
it('rounded rect shape', () => {
|
it('rounded rect shape', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`mindmap
|
||||||
mindmap
|
|
||||||
root((
|
root((
|
||||||
The root
|
The root
|
||||||
))
|
))`,
|
||||||
`,
|
|
||||||
{},
|
{},
|
||||||
undefined,
|
undefined,
|
||||||
shouldHaveRoot
|
shouldHaveRoot
|
||||||
@@ -185,12 +181,10 @@ mindmap
|
|||||||
});
|
});
|
||||||
it('circle shape', () => {
|
it('circle shape', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`mindmap
|
||||||
mindmap
|
|
||||||
root(
|
root(
|
||||||
The root
|
The root
|
||||||
)
|
)`,
|
||||||
`,
|
|
||||||
{},
|
{},
|
||||||
undefined,
|
undefined,
|
||||||
shouldHaveRoot
|
shouldHaveRoot
|
||||||
@@ -198,10 +192,8 @@ mindmap
|
|||||||
});
|
});
|
||||||
it('default shape', () => {
|
it('default shape', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`mindmap
|
||||||
mindmap
|
The root`,
|
||||||
The root
|
|
||||||
`,
|
|
||||||
{},
|
{},
|
||||||
undefined,
|
undefined,
|
||||||
shouldHaveRoot
|
shouldHaveRoot
|
||||||
@@ -209,12 +201,10 @@ mindmap
|
|||||||
});
|
});
|
||||||
it('adding children', () => {
|
it('adding children', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`mindmap
|
||||||
mindmap
|
|
||||||
The root
|
The root
|
||||||
child1
|
child1
|
||||||
child2
|
child2`,
|
||||||
`,
|
|
||||||
{},
|
{},
|
||||||
undefined,
|
undefined,
|
||||||
shouldHaveRoot
|
shouldHaveRoot
|
||||||
@@ -222,13 +212,11 @@ mindmap
|
|||||||
});
|
});
|
||||||
it('adding grand children', () => {
|
it('adding grand children', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`mindmap
|
||||||
mindmap
|
|
||||||
The root
|
The root
|
||||||
child1
|
child1
|
||||||
child2
|
child2
|
||||||
child3
|
child3`,
|
||||||
`,
|
|
||||||
{},
|
{},
|
||||||
undefined,
|
undefined,
|
||||||
shouldHaveRoot
|
shouldHaveRoot
|
||||||
@@ -240,9 +228,48 @@ mindmap
|
|||||||
`mindmap
|
`mindmap
|
||||||
id1[\`**Start** with
|
id1[\`**Start** with
|
||||||
a second line 😎\`]
|
a second line 😎\`]
|
||||||
id2[\`The dog in **the** hog... a *very long text* about it
|
id2[\`The dog in **the** hog... a *very long text* about it Word!\`]`
|
||||||
Word!\`]
|
);
|
||||||
`
|
});
|
||||||
|
});
|
||||||
|
describe('Include char sequence "graph" in text (#6795)', () => {
|
||||||
|
it('has a label with char sequence "graph"', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
` mindmap
|
||||||
|
root
|
||||||
|
Photograph
|
||||||
|
Waterfall
|
||||||
|
Landscape
|
||||||
|
Geography
|
||||||
|
Mountains
|
||||||
|
Rocks`,
|
||||||
|
{ flowchart: { defaultRenderer: 'elk' } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('Level 2 nodes exceeding 11', () => {
|
||||||
|
it('should render all Level 2 nodes correctly when there are more than 11', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`mindmap
|
||||||
|
root
|
||||||
|
Node1
|
||||||
|
Node2
|
||||||
|
Node3
|
||||||
|
Node4
|
||||||
|
Node5
|
||||||
|
Node6
|
||||||
|
Node7
|
||||||
|
Node8
|
||||||
|
Node9
|
||||||
|
Node10
|
||||||
|
Node11
|
||||||
|
Node12
|
||||||
|
Node13
|
||||||
|
Node14
|
||||||
|
Node15`,
|
||||||
|
{},
|
||||||
|
undefined,
|
||||||
|
shouldHaveRoot
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { imgSnapshotTest } from '../../helpers/util';
|
import { imgSnapshotTest } from '../../helpers/util';
|
||||||
|
|
||||||
describe('packet structure', () => {
|
describe('packet structure', () => {
|
||||||
it('should render a simple packet diagram', () => {
|
it('should render a simple packet-beta diagram', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`packet-beta
|
`packet-beta
|
||||||
title Hello world
|
title Hello world
|
||||||
@@ -10,9 +10,18 @@ describe('packet structure', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render a simple packet diagram', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`packet
|
||||||
|
title Hello world
|
||||||
|
0-10: "hello"
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('should render a simple packet diagram without ranges', () => {
|
it('should render a simple packet diagram without ranges', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`packet-beta
|
`packet
|
||||||
0: "h"
|
0: "h"
|
||||||
1: "i"
|
1: "i"
|
||||||
`
|
`
|
||||||
@@ -21,7 +30,7 @@ describe('packet structure', () => {
|
|||||||
|
|
||||||
it('should render a complex packet diagram', () => {
|
it('should render a complex packet diagram', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`packet-beta
|
`packet
|
||||||
0-15: "Source Port"
|
0-15: "Source Port"
|
||||||
16-31: "Destination Port"
|
16-31: "Destination Port"
|
||||||
32-63: "Sequence Number"
|
32-63: "Sequence Number"
|
||||||
@@ -52,7 +61,7 @@ describe('packet structure', () => {
|
|||||||
packet:
|
packet:
|
||||||
showBits: false
|
showBits: false
|
||||||
---
|
---
|
||||||
packet-beta
|
packet
|
||||||
0-15: "Source Port"
|
0-15: "Source Port"
|
||||||
16-31: "Destination Port"
|
16-31: "Destination Port"
|
||||||
32-63: "Sequence Number"
|
32-63: "Sequence Number"
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ describe('pie chart', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render a pie diagram when textPosition is setted', () => {
|
it('should render a pie diagram when textPosition is set', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`pie
|
`pie
|
||||||
"Dogs": 50
|
"Dogs": 50
|
||||||
@@ -82,4 +82,13 @@ describe('pie chart', () => {
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should render pie slices only for non-zero values but shows all legends', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
` pie title Pets adopted by volunteers
|
||||||
|
"Dogs" : 386
|
||||||
|
"Cats" : 85
|
||||||
|
"Rats" : 1
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ describe('Quadrant Chart', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should able to render y-axix on right side', () => {
|
it('should able to render y-axis on right side', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
%%{init: {"quadrantChart": {"yAxisPosition": "right"}}}%%
|
%%{init: {"quadrantChart": {"yAxisPosition": "right"}}}%%
|
||||||
@@ -61,7 +61,7 @@ describe('Quadrant Chart', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should able to render x-axix on bottom', () => {
|
it('should able to render x-axis on bottom', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
%%{init: {"quadrantChart": {"xAxisPosition": "bottom"}}}%%
|
%%{init: {"quadrantChart": {"xAxisPosition": "bottom"}}}%%
|
||||||
@@ -77,7 +77,7 @@ describe('Quadrant Chart', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should able to render x-axix on bottom and y-axis on right', () => {
|
it('should able to render x-axis on bottom and y-axis on right', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
%%{init: {"quadrantChart": {"xAxisPosition": "bottom", "yAxisPosition": "right"}}}%%
|
%%{init: {"quadrantChart": {"xAxisPosition": "bottom", "yAxisPosition": "right"}}}%%
|
||||||
|
|||||||
79
cypress/integration/rendering/radar.spec.js
Normal file
79
cypress/integration/rendering/radar.spec.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import { imgSnapshotTest } from '../../helpers/util';
|
||||||
|
|
||||||
|
describe('radar structure', () => {
|
||||||
|
it('should render a simple radar diagram', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`radar-beta
|
||||||
|
title Best Radar Ever
|
||||||
|
axis A, B, C
|
||||||
|
curve c1{1, 2, 3}
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render a radar diagram with multiple curves', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`radar-beta
|
||||||
|
title Best Radar Ever
|
||||||
|
axis A, B, C
|
||||||
|
curve c1{1, 2, 3}
|
||||||
|
curve c2{2, 3, 1}
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render a complex radar diagram', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`radar-beta
|
||||||
|
title My favorite ninjas
|
||||||
|
axis Agility, Speed, Strength
|
||||||
|
axis Stam["Stamina"] , Intel["Intelligence"]
|
||||||
|
|
||||||
|
curve Ninja1["Naruto Uzumaki"]{
|
||||||
|
Agility 2, Speed 2,
|
||||||
|
Strength 3, Stam 5,
|
||||||
|
Intel 0
|
||||||
|
}
|
||||||
|
curve Ninja2["Sasuke"]{2, 3, 4, 1, 5}
|
||||||
|
curve Ninja3 {3, 2, 1, 5, 4}
|
||||||
|
|
||||||
|
showLegend true
|
||||||
|
ticks 3
|
||||||
|
max 8
|
||||||
|
min 0
|
||||||
|
graticule polygon
|
||||||
|
`
|
||||||
|
);
|
||||||
|
cy.get('svg').should((svg) => {
|
||||||
|
expect(svg).to.have.length(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render radar diagram with config override', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`radar-beta
|
||||||
|
title Best Radar Ever
|
||||||
|
axis A,B,C
|
||||||
|
curve mycurve{1,2,3}`,
|
||||||
|
{ radar: { marginTop: 100, axisScaleFactor: 0.5 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse radar diagram with theme override', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`radar-beta
|
||||||
|
axis A,B,C
|
||||||
|
curve mycurve{1,2,3}`,
|
||||||
|
{ theme: 'base', themeVariables: { fontSize: 80, cScale0: '#FF0000' } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle radar diagram with radar style override', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`radar-beta
|
||||||
|
axis A,B,C
|
||||||
|
curve mycurve{1,2,3}`,
|
||||||
|
{ theme: 'base', themeVariables: { radar: { axisColor: '#FF0000' } } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
703
cypress/integration/rendering/requirementDiagram-unified.spec.js
Normal file
703
cypress/integration/rendering/requirementDiagram-unified.spec.js
Normal file
@@ -0,0 +1,703 @@
|
|||||||
|
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||||
|
|
||||||
|
const testOptions = [
|
||||||
|
{ description: '', options: { logLevel: 1 } },
|
||||||
|
{ description: 'ELK: ', options: { logLevel: 1, layout: 'elk' } },
|
||||||
|
{ description: 'HD: ', options: { logLevel: 1, look: 'handDrawn' } },
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('Requirement Diagram Unified', () => {
|
||||||
|
testOptions.forEach(({ description, options }) => {
|
||||||
|
it(`${description}should render a simple Requirement diagram`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a simple Requirement diagram without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a not-so-simple Requirement diagram`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
functionalRequirement test_req2 {
|
||||||
|
id: 1.1
|
||||||
|
text: the second test text.
|
||||||
|
risk: low
|
||||||
|
verifymethod: inspection
|
||||||
|
}
|
||||||
|
|
||||||
|
performanceRequirement test_req3 {
|
||||||
|
id: 1.2
|
||||||
|
text: the third test text.
|
||||||
|
risk: medium
|
||||||
|
verifymethod: demonstration
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceRequirement test_req4 {
|
||||||
|
id: 1.2.1
|
||||||
|
text: the fourth test text.
|
||||||
|
risk: medium
|
||||||
|
verifymethod: analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
physicalRequirement test_req5 {
|
||||||
|
id: 1.2.2
|
||||||
|
text: the fifth test text.
|
||||||
|
risk: medium
|
||||||
|
verifymethod: analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
designConstraint test_req6 {
|
||||||
|
id: 1.2.3
|
||||||
|
text: the sixth test text.
|
||||||
|
risk: medium
|
||||||
|
verifymethod: analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity2 {
|
||||||
|
type: word doc
|
||||||
|
docRef: reqs/test_entity
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity3 {
|
||||||
|
type: "test suite"
|
||||||
|
docRef: github.com/all_the_tests
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req2
|
||||||
|
test_req - traces -> test_req2
|
||||||
|
test_req - contains -> test_req3
|
||||||
|
test_req3 - contains -> test_req4
|
||||||
|
test_req4 - derives -> test_req5
|
||||||
|
test_req5 - refines -> test_req6
|
||||||
|
test_entity3 - verifies -> test_req5
|
||||||
|
test_req <- copies - test_entity2
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a not-so-simple Requirement diagram without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
functionalRequirement test_req2 {
|
||||||
|
id: 1.1
|
||||||
|
text: the second test text.
|
||||||
|
risk: low
|
||||||
|
verifymethod: inspection
|
||||||
|
}
|
||||||
|
|
||||||
|
performanceRequirement test_req3 {
|
||||||
|
id: 1.2
|
||||||
|
text: the third test text.
|
||||||
|
risk: medium
|
||||||
|
verifymethod: demonstration
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceRequirement test_req4 {
|
||||||
|
id: 1.2.1
|
||||||
|
text: the fourth test text.
|
||||||
|
risk: medium
|
||||||
|
verifymethod: analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
physicalRequirement test_req5 {
|
||||||
|
id: 1.2.2
|
||||||
|
text: the fifth test text.
|
||||||
|
risk: medium
|
||||||
|
verifymethod: analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
designConstraint test_req6 {
|
||||||
|
id: 1.2.3
|
||||||
|
text: the sixth test text.
|
||||||
|
risk: medium
|
||||||
|
verifymethod: analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity2 {
|
||||||
|
type: word doc
|
||||||
|
docRef: reqs/test_entity
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity3 {
|
||||||
|
type: "test suite"
|
||||||
|
docRef: github.com/all_the_tests
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req2
|
||||||
|
test_req - traces -> test_req2
|
||||||
|
test_req - contains -> test_req3
|
||||||
|
test_req3 - contains -> test_req4
|
||||||
|
test_req4 - derives -> test_req5
|
||||||
|
test_req5 - refines -> test_req6
|
||||||
|
test_entity3 - verifies -> test_req5
|
||||||
|
test_req <- copies - test_entity2
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render multiple Requirement diagrams`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
[
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
`,
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
`,
|
||||||
|
],
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a Requirement diagram with empty information`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
requirement test_req {
|
||||||
|
}
|
||||||
|
element test_entity {
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with and without information`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
element test_entity {
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with long and short text`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text that is long and takes up a lot of space.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
element test_entity_name_that_is_extra_long {
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with long and short text without htmlLabels`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text that is long and takes up a lot of space.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
element test_entity_name_that_is_extra_long {
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with quoted text for spaces`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
requirement "test req name with spaces" {
|
||||||
|
id: 1
|
||||||
|
text: the test text that is long and takes up a lot of space.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
element "test entity name that is extra long with spaces" {
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with markdown text`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
requirement "__my bolded name__" {
|
||||||
|
id: 1
|
||||||
|
text: "**Bolded text** _italicized text_"
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
element "*my italicized name*" {
|
||||||
|
type: "**Bolded type** _italicized type_"
|
||||||
|
docref: "*Italicized* __Bolded__"
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with markdown text without htmlLabels`, () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
requirement "__my bolded name__" {
|
||||||
|
id: 1
|
||||||
|
text: "**Bolded text** _italicized text_"
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
element "*my italicized name*" {
|
||||||
|
type: "**Bolded type** _italicized type_"
|
||||||
|
docref: "*Italicized* __Bolded__"
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a simple Requirement diagram with a title`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`---
|
||||||
|
title: simple Requirement diagram
|
||||||
|
---
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a Requirement diagram with TB direction`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
direction TB
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a Requirement diagram with BT direction`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
direction BT
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a Requirement diagram with LR direction`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
direction LR
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a Requirement diagram with RL direction`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
direction RL
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with styles applied from style statement`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
|
||||||
|
style test_req,test_entity fill:#f9f,stroke:blue, color:grey, font-weight:bold
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with styles applied from style statement without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
|
||||||
|
style test_req,test_entity fill:#f9f,stroke:blue, color:grey, font-weight:bold
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with styles applied from class statement`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
classDef bold font-weight: bold
|
||||||
|
classDef blue stroke:lightblue, color: #0000FF
|
||||||
|
class test_entity bold
|
||||||
|
class test_req blue, bold
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with styles applied from class statement without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
classDef bold font-weight: bold
|
||||||
|
classDef blue stroke:lightblue, color: #0000FF
|
||||||
|
class test_entity bold
|
||||||
|
class test_req blue, bold
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with styles applied from classes with shorthand syntax`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req:::blue {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
classDef bold font-weight: bold
|
||||||
|
classDef blue stroke:lightblue, color: #0000FF
|
||||||
|
test_entity:::bold
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with styles applied from classes with shorthand syntax without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req:::blue {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
classDef bold font-weight: bold
|
||||||
|
classDef blue stroke:lightblue, color: #0000FF
|
||||||
|
test_entity:::bold
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with styles applied from the default class and other styles`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req:::blue {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
classDef blue stroke:lightblue, color:blue
|
||||||
|
classDef default fill:pink
|
||||||
|
style test_entity color:green
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render requirements and elements with styles applied from the default class and other styles without htmlLabels`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req:::blue {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
classDef blue stroke:lightblue, color:blue
|
||||||
|
classDef default fill:pink
|
||||||
|
style test_entity color:green
|
||||||
|
`,
|
||||||
|
{ ...options, htmlLabels: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`${description}should render a Requirement diagram with a theme`, () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
---
|
||||||
|
theme: forest
|
||||||
|
---
|
||||||
|
requirementDiagram
|
||||||
|
|
||||||
|
requirement test_req:::blue {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
`,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -15,7 +15,7 @@ describe('Sankey Diagram', () => {
|
|||||||
describe('when given a linkColor', function () {
|
describe('when given a linkColor', function () {
|
||||||
this.beforeAll(() => {
|
this.beforeAll(() => {
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
`sankey-beta
|
`sankey
|
||||||
a,b,10
|
a,b,10
|
||||||
`
|
`
|
||||||
).as('graph');
|
).as('graph');
|
||||||
@@ -62,7 +62,7 @@ describe('Sankey Diagram', () => {
|
|||||||
this.beforeAll(() => {
|
this.beforeAll(() => {
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
`
|
`
|
||||||
sankey-beta
|
sankey
|
||||||
|
|
||||||
a,b,8
|
a,b,8
|
||||||
b,c,8
|
b,c,8
|
||||||
|
|||||||
969
cypress/integration/rendering/sequencediagram-v2.spec.js
Normal file
969
cypress/integration/rendering/sequencediagram-v2.spec.js
Normal file
@@ -0,0 +1,969 @@
|
|||||||
|
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||||
|
|
||||||
|
const looks = ['classic'];
|
||||||
|
const participantTypes = [
|
||||||
|
{ type: 'participant', display: 'participant' },
|
||||||
|
{ type: 'actor', display: 'actor' },
|
||||||
|
{ type: 'boundary', display: 'boundary' },
|
||||||
|
{ type: 'control', display: 'control' },
|
||||||
|
{ type: 'entity', display: 'entity' },
|
||||||
|
{ type: 'database', display: 'database' },
|
||||||
|
{ type: 'collections', display: 'collections' },
|
||||||
|
{ type: 'queue', display: 'queue' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const restrictedTypes = ['boundary', 'control', 'entity', 'database', 'collections', 'queue'];
|
||||||
|
|
||||||
|
const interactionTypes = ['->>', '-->>', '->', '-->', '-x', '--x', '->>+', '-->>+'];
|
||||||
|
|
||||||
|
const notePositions = ['left of', 'right of', 'over'];
|
||||||
|
|
||||||
|
function getParticipantLine(name, type, alias) {
|
||||||
|
if (restrictedTypes.includes(type)) {
|
||||||
|
return ` participant ${name}@{ "type" : "${type}" }\n`;
|
||||||
|
} else if (alias) {
|
||||||
|
return ` participant ${name}@{ "type" : "${type}" } \n`;
|
||||||
|
} else {
|
||||||
|
return ` participant ${name}@{ "type" : "${type}" }\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
looks.forEach((look) => {
|
||||||
|
describe(`Sequence Diagram Tests - ${look} look`, () => {
|
||||||
|
it('should render all participant types', () => {
|
||||||
|
let diagramCode = `sequenceDiagram\n`;
|
||||||
|
participantTypes.forEach((pt, index) => {
|
||||||
|
const name = `${pt.display}${index}`;
|
||||||
|
diagramCode += getParticipantLine(name, pt.type);
|
||||||
|
});
|
||||||
|
for (let i = 0; i < participantTypes.length - 1; i++) {
|
||||||
|
diagramCode += ` ${participantTypes[i].display}${i} ->> ${participantTypes[i + 1].display}${i + 1}: Message ${i}\n`;
|
||||||
|
}
|
||||||
|
imgSnapshotTest(diagramCode, { look, sequence: { diagramMarginX: 50, diagramMarginY: 10 } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render all interaction types', () => {
|
||||||
|
let diagramCode = `sequenceDiagram\n`;
|
||||||
|
diagramCode += getParticipantLine('A', 'actor');
|
||||||
|
diagramCode += getParticipantLine('B', 'boundary');
|
||||||
|
interactionTypes.forEach((interaction, index) => {
|
||||||
|
diagramCode += ` A ${interaction} B: ${interaction} message ${index}\n`;
|
||||||
|
});
|
||||||
|
imgSnapshotTest(diagramCode, { look });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render participant creation and destruction', () => {
|
||||||
|
let diagramCode = `sequenceDiagram\n`;
|
||||||
|
participantTypes.forEach((pt, index) => {
|
||||||
|
const name = `${pt.display}${index}`;
|
||||||
|
diagramCode += getParticipantLine('A', pt.type);
|
||||||
|
diagramCode += getParticipantLine('B', pt.type);
|
||||||
|
diagramCode += ` create participant ${name}@{ "type" : "${pt.type}" }\n`;
|
||||||
|
diagramCode += ` A ->> ${name}: Hello ${pt.display}\n`;
|
||||||
|
if (index % 2 === 0) {
|
||||||
|
diagramCode += ` destroy ${name}\n`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
imgSnapshotTest(diagramCode, { look });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render notes in all positions', () => {
|
||||||
|
let diagramCode = `sequenceDiagram\n`;
|
||||||
|
diagramCode += getParticipantLine('A', 'actor');
|
||||||
|
diagramCode += getParticipantLine('B', 'boundary');
|
||||||
|
notePositions.forEach((position, index) => {
|
||||||
|
diagramCode += ` Note ${position} A: Note ${position} ${index}\n`;
|
||||||
|
});
|
||||||
|
diagramCode += ` A ->> B: Message with notes\n`;
|
||||||
|
imgSnapshotTest(diagramCode, { look });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render parallel interactions', () => {
|
||||||
|
let diagramCode = `sequenceDiagram\n`;
|
||||||
|
participantTypes.slice(0, 4).forEach((pt, index) => {
|
||||||
|
diagramCode += getParticipantLine(`${pt.display}${index}`, pt.type);
|
||||||
|
});
|
||||||
|
diagramCode += ` par Parallel actions\n`;
|
||||||
|
for (let i = 0; i < 3; i += 2) {
|
||||||
|
diagramCode += ` ${participantTypes[i].display}${i} ->> ${participantTypes[i + 1].display}${i + 1}: Message ${i}\n`;
|
||||||
|
if (i < participantTypes.length - 2) {
|
||||||
|
diagramCode += ` and\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diagramCode += ` end\n`;
|
||||||
|
imgSnapshotTest(diagramCode, { look });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render alternative flows', () => {
|
||||||
|
let diagramCode = `sequenceDiagram\n`;
|
||||||
|
diagramCode += getParticipantLine('A', 'actor');
|
||||||
|
diagramCode += getParticipantLine('B', 'boundary');
|
||||||
|
diagramCode += ` alt Successful case\n`;
|
||||||
|
diagramCode += ` A ->> B: Request\n`;
|
||||||
|
diagramCode += ` B -->> A: Success\n`;
|
||||||
|
diagramCode += ` else Failure case\n`;
|
||||||
|
diagramCode += ` A ->> B: Request\n`;
|
||||||
|
diagramCode += ` B --x A: Failure\n`;
|
||||||
|
diagramCode += ` end\n`;
|
||||||
|
imgSnapshotTest(diagramCode, { look });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render loops', () => {
|
||||||
|
let diagramCode = `sequenceDiagram\n`;
|
||||||
|
participantTypes.slice(0, 3).forEach((pt, index) => {
|
||||||
|
diagramCode += getParticipantLine(`${pt.display}${index}`, pt.type);
|
||||||
|
});
|
||||||
|
diagramCode += ` loop For each participant\n`;
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
diagramCode += ` ${participantTypes[0].display}0 ->> ${participantTypes[1].display}1: Message ${i}\n`;
|
||||||
|
}
|
||||||
|
diagramCode += ` end\n`;
|
||||||
|
imgSnapshotTest(diagramCode, { look });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render boxes around groups', () => {
|
||||||
|
let diagramCode = `sequenceDiagram\n`;
|
||||||
|
diagramCode += ` box Group 1\n`;
|
||||||
|
participantTypes.slice(0, 3).forEach((pt, index) => {
|
||||||
|
diagramCode += ` ${getParticipantLine(`${pt.display}${index}`, pt.type)}`;
|
||||||
|
});
|
||||||
|
diagramCode += ` end\n`;
|
||||||
|
diagramCode += ` box rgb(200,220,255) Group 2\n`;
|
||||||
|
participantTypes.slice(3, 6).forEach((pt, index) => {
|
||||||
|
diagramCode += ` ${getParticipantLine(`${pt.display}${index}`, pt.type)}`;
|
||||||
|
});
|
||||||
|
diagramCode += ` end\n`;
|
||||||
|
diagramCode += ` ${participantTypes[0].display}0 ->> ${participantTypes[3].display}0: Cross-group message\n`;
|
||||||
|
imgSnapshotTest(diagramCode, { look });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render with different font settings', () => {
|
||||||
|
let diagramCode = `sequenceDiagram\n`;
|
||||||
|
participantTypes.slice(0, 3).forEach((pt, index) => {
|
||||||
|
diagramCode += getParticipantLine(`${pt.display}${index}`, pt.type);
|
||||||
|
});
|
||||||
|
diagramCode += ` ${participantTypes[0].display}0 ->> ${participantTypes[1].display}1: Regular message\n`;
|
||||||
|
diagramCode += ` Note right of ${participantTypes[1].display}1: Regular note\n`;
|
||||||
|
imgSnapshotTest(diagramCode, {
|
||||||
|
look,
|
||||||
|
sequence: {
|
||||||
|
actorFontFamily: 'courier',
|
||||||
|
actorFontSize: 14,
|
||||||
|
messageFontFamily: 'Arial',
|
||||||
|
messageFontSize: 12,
|
||||||
|
noteFontFamily: 'times',
|
||||||
|
noteFontSize: 16,
|
||||||
|
noteAlign: 'left',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Additional tests for specific combinations
|
||||||
|
describe('Sequence Diagram Special Cases', () => {
|
||||||
|
it('should render complex sequence with all features', () => {
|
||||||
|
const diagramCode = `
|
||||||
|
sequenceDiagram
|
||||||
|
box rgb(200,220,255) Authentication
|
||||||
|
actor User
|
||||||
|
participant LoginUI@{ "type": "boundary" }
|
||||||
|
participant AuthService@{ "type": "control" }
|
||||||
|
participant UserDB@{ "type": "database" }
|
||||||
|
end
|
||||||
|
|
||||||
|
box rgb(200,255,220) Order Processing
|
||||||
|
participant Order@{ "type": "entity" }
|
||||||
|
participant OrderQueue@{ "type": "queue" }
|
||||||
|
participant AuditLogs@{ "type": "collections" }
|
||||||
|
end
|
||||||
|
|
||||||
|
User ->> LoginUI: Enter credentials
|
||||||
|
LoginUI ->> AuthService: Validate
|
||||||
|
AuthService ->> UserDB: Query user
|
||||||
|
UserDB -->> AuthService: User data
|
||||||
|
alt Valid credentials
|
||||||
|
AuthService -->> LoginUI: Success
|
||||||
|
LoginUI -->> User: Welcome
|
||||||
|
|
||||||
|
par Place order
|
||||||
|
User ->> Order: New order
|
||||||
|
Order ->> OrderQueue: Process
|
||||||
|
and
|
||||||
|
Order ->> AuditLogs: Record
|
||||||
|
end
|
||||||
|
|
||||||
|
loop Until confirmed
|
||||||
|
OrderQueue ->> Order: Update status
|
||||||
|
Order -->> User: Notification
|
||||||
|
end
|
||||||
|
else Invalid credentials
|
||||||
|
AuthService --x LoginUI: Failure
|
||||||
|
LoginUI --x User: Retry
|
||||||
|
end
|
||||||
|
`;
|
||||||
|
imgSnapshotTest(diagramCode, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render with wrapped messages and notes', () => {
|
||||||
|
const diagramCode = `
|
||||||
|
sequenceDiagram
|
||||||
|
participant A
|
||||||
|
participant B
|
||||||
|
|
||||||
|
A ->> B: This is a very long message that should wrap properly in the diagram rendering
|
||||||
|
Note over A,B: This is a very long note that should also wrap properly when rendered in the diagram
|
||||||
|
|
||||||
|
par Wrapped parallel
|
||||||
|
A ->> B: Parallel message 1<br>with explicit line break
|
||||||
|
and
|
||||||
|
B ->> A: Parallel message 2<br>with explicit line break
|
||||||
|
end
|
||||||
|
|
||||||
|
loop Wrapped loop
|
||||||
|
Note right of B: This is a long note<br>in a loop
|
||||||
|
A ->> B: Message in loop
|
||||||
|
end
|
||||||
|
`;
|
||||||
|
imgSnapshotTest(diagramCode, { sequence: { wrap: true } });
|
||||||
|
});
|
||||||
|
describe('Sequence Diagram Rendering with Different Participant Types', () => {
|
||||||
|
it('should render a sequence diagram with various participant types', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant User@{ "type": "actor" }
|
||||||
|
participant AuthService@{ "type": "control" }
|
||||||
|
participant UI@{ "type": "boundary" }
|
||||||
|
participant OrderController@{ "type": "control" }
|
||||||
|
participant Product@{ "type": "entity" }
|
||||||
|
participant MongoDB@{ "type": "database" }
|
||||||
|
participant Products@{ "type": "collections" }
|
||||||
|
participant OrderQueue@{ "type": "queue" }
|
||||||
|
User ->> UI: Login request
|
||||||
|
UI ->> AuthService: Validate credentials
|
||||||
|
AuthService -->> UI: Authentication token
|
||||||
|
UI ->> OrderController: Place order
|
||||||
|
OrderController ->> Product: Check availability
|
||||||
|
Product -->> OrderController: Available
|
||||||
|
OrderController ->> MongoDB: Save order
|
||||||
|
MongoDB -->> OrderController: Order saved
|
||||||
|
OrderController ->> OrderQueue: Process payment
|
||||||
|
OrderQueue -->> User: Order confirmation
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render participant creation and destruction with different types', () => {
|
||||||
|
imgSnapshotTest(`
|
||||||
|
sequenceDiagram
|
||||||
|
participant Alice@{ "type" : "boundary" }
|
||||||
|
Alice->>Bob: Hello Bob, how are you ?
|
||||||
|
Bob->>Alice: Fine, thank you. And you?
|
||||||
|
create participant Carl@{ "type" : "control" }
|
||||||
|
Alice->>Carl: Hi Carl!
|
||||||
|
create actor D as Donald
|
||||||
|
Carl->>D: Hi!
|
||||||
|
destroy Carl
|
||||||
|
Alice-xCarl: We are too many
|
||||||
|
destroy Bob
|
||||||
|
Bob->>Alice: I agree
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle complex interactions between different participant types', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
box rgb(200,220,255) Authentication
|
||||||
|
participant User@{ "type": "actor" }
|
||||||
|
participant LoginUI@{ "type": "boundary" }
|
||||||
|
participant AuthService@{ "type": "control" }
|
||||||
|
participant UserDB@{ "type": "database" }
|
||||||
|
end
|
||||||
|
|
||||||
|
box rgb(200,255,220) Order Processing
|
||||||
|
participant Order@{ "type": "entity" }
|
||||||
|
participant OrderQueue@{ "type": "queue" }
|
||||||
|
participant AuditLogs@{ "type": "collections" }
|
||||||
|
end
|
||||||
|
|
||||||
|
User ->> LoginUI: Enter credentials
|
||||||
|
LoginUI ->> AuthService: Validate
|
||||||
|
AuthService ->> UserDB: Query user
|
||||||
|
UserDB -->> AuthService: User data
|
||||||
|
|
||||||
|
alt Valid credentials
|
||||||
|
AuthService -->> LoginUI: Success
|
||||||
|
LoginUI -->> User: Welcome
|
||||||
|
|
||||||
|
par Place order
|
||||||
|
User ->> Order: New order
|
||||||
|
Order ->> OrderQueue: Process
|
||||||
|
and
|
||||||
|
Order ->> AuditLogs: Record
|
||||||
|
end
|
||||||
|
|
||||||
|
loop Until confirmed
|
||||||
|
OrderQueue ->> Order: Update status
|
||||||
|
Order -->> User: Notification
|
||||||
|
end
|
||||||
|
else Invalid credentials
|
||||||
|
AuthService --x LoginUI: Failure
|
||||||
|
LoginUI --x User: Retry
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
{ sequence: { useMaxWidth: false } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render parallel processes with different participant types', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant Customer@{ "type": "actor" }
|
||||||
|
participant Frontend@{ "type": "participant" }
|
||||||
|
participant PaymentService@{ "type": "boundary" }
|
||||||
|
participant InventoryManager@{ "type": "control" }
|
||||||
|
participant Order@{ "type": "entity" }
|
||||||
|
participant OrdersDB@{ "type": "database" }
|
||||||
|
participant NotificationQueue@{ "type": "queue" }
|
||||||
|
|
||||||
|
Customer ->> Frontend: Place order
|
||||||
|
Frontend ->> Order: Create order
|
||||||
|
par Parallel Processing
|
||||||
|
Order ->> PaymentService: Process payment
|
||||||
|
and
|
||||||
|
Order ->> InventoryManager: Reserve items
|
||||||
|
end
|
||||||
|
PaymentService -->> Order: Payment confirmed
|
||||||
|
InventoryManager -->> Order: Items reserved
|
||||||
|
Order ->> OrdersDB: Save finalized order
|
||||||
|
OrdersDB -->> Order: Order saved
|
||||||
|
Order ->> NotificationQueue: Send confirmation
|
||||||
|
NotificationQueue -->> Customer: Order confirmation
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should render different participant types with notes and loops', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
actor Admin
|
||||||
|
participant Dashboard
|
||||||
|
participant AuthService@{ "type" : "boundary" }
|
||||||
|
participant UserManager@{ "type" : "control" }
|
||||||
|
participant UserProfile@{ "type" : "entity" }
|
||||||
|
participant UserDB@{ "type" : "database" }
|
||||||
|
participant Logs@{ "type" : "database" }
|
||||||
|
|
||||||
|
Admin ->> Dashboard: Open user management
|
||||||
|
loop Authentication check
|
||||||
|
Dashboard ->> AuthService: Verify admin rights
|
||||||
|
AuthService ->> Dashboard: Access granted
|
||||||
|
end
|
||||||
|
Dashboard ->> UserManager: List users
|
||||||
|
UserManager ->> UserDB: Query users
|
||||||
|
UserDB ->> UserManager: Return user data
|
||||||
|
Note right of UserDB: Encrypted data<br/>requires decryption
|
||||||
|
UserManager ->> UserProfile: Format profiles
|
||||||
|
UserProfile ->> UserManager: Formatted data
|
||||||
|
UserManager ->> Dashboard: Display users
|
||||||
|
Dashboard ->> Logs: Record access
|
||||||
|
Logs ->> Admin: Audit trail
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render different participant types with alternative flows', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
actor Client
|
||||||
|
participant MobileApp
|
||||||
|
participant CloudService@{ "type" : "boundary" }
|
||||||
|
participant DataProcessor@{ "type" : "control" }
|
||||||
|
participant Transaction@{ "type" : "entity" }
|
||||||
|
participant TransactionsDB@{ "type" : "database" }
|
||||||
|
participant EventBus@{ "type" : "queue" }
|
||||||
|
|
||||||
|
Client ->> MobileApp: Initiate transaction
|
||||||
|
MobileApp ->> CloudService: Authenticate
|
||||||
|
alt Authentication successful
|
||||||
|
CloudService -->> MobileApp: Auth token
|
||||||
|
MobileApp ->> DataProcessor: Process data
|
||||||
|
DataProcessor ->> Transaction: Create transaction
|
||||||
|
Transaction ->> TransactionsDB: Save record
|
||||||
|
TransactionsDB -->> Transaction: Confirmation
|
||||||
|
Transaction ->> EventBus: Publish event
|
||||||
|
EventBus -->> Client: Notification
|
||||||
|
else Authentication failed
|
||||||
|
CloudService -->> MobileApp: Error
|
||||||
|
MobileApp -->> Client: Show error
|
||||||
|
end
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render different participant types with wrapping text', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant B@{ "type" : "boundary" }
|
||||||
|
participant C@{ "type" : "control" }
|
||||||
|
participant E@{ "type" : "entity" }
|
||||||
|
participant DB@{ "type" : "database" }
|
||||||
|
participant COL@{ "type" : "collections" }
|
||||||
|
participant Q@{ "type" : "queue" }
|
||||||
|
|
||||||
|
FE ->> B: Another long message<br/>with explicit<br/>line breaks
|
||||||
|
B -->> FE: Response message that is also quite long and needs to wrap
|
||||||
|
FE ->> C: Process data
|
||||||
|
C ->> E: Validate
|
||||||
|
E -->> C: Validation result
|
||||||
|
C ->> DB: Save
|
||||||
|
DB -->> C: Save result
|
||||||
|
C ->> COL: Log
|
||||||
|
COL -->> Q: Forward
|
||||||
|
Q -->> LongNameUser: Final response with confirmation of all actions taken
|
||||||
|
`,
|
||||||
|
{ sequence: { wrap: true } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Sequence Diagram - New Participant Types with Long Notes and Messages', () => {
|
||||||
|
it('should render long notes left of boundary', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant Alice@{ "type" : "boundary" }
|
||||||
|
actor Bob
|
||||||
|
Alice->>Bob: Hola
|
||||||
|
Note left of Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||||
|
Bob->>Alice: I'm short though
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render wrapped long notes left of control', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant Alice@{ "type" : "control" }
|
||||||
|
actor Bob
|
||||||
|
Alice->>Bob: Hola
|
||||||
|
Note left of Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||||
|
Bob->>Alice: I'm short though
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render long notes right of entity', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant Alice@{ "type" : "entity" }
|
||||||
|
actor Bob
|
||||||
|
Alice->>Bob: Hola
|
||||||
|
Note right of Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||||
|
Bob->>Alice: I'm short though
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render wrapped long notes right of database', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant Alice@{ "type" : "database" }
|
||||||
|
actor Bob
|
||||||
|
Alice->>Bob: Hola
|
||||||
|
Note right of Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||||
|
Bob->>Alice: I'm short though
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render long notes over collections', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant Alice@{ "type" : "collections" }
|
||||||
|
actor Bob
|
||||||
|
Alice->>Bob: Hola
|
||||||
|
Note over Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||||
|
Bob->>Alice: I'm short though
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render wrapped long notes over queue', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant Alice@{ "type" : "queue" }
|
||||||
|
actor Bob
|
||||||
|
Alice->>Bob: Hola
|
||||||
|
Note over Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||||
|
Bob->>Alice: I'm short though
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render notes over actor and boundary', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
actor Alice
|
||||||
|
participant Charlie@{ "type" : "boundary" }
|
||||||
|
note over Alice: Some note
|
||||||
|
note over Charlie: Other note
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render long messages from database to collections', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant Alice@{ "type" : "database" }
|
||||||
|
participant Bob@{ "type" : "collections" }
|
||||||
|
Alice->>Bob: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||||
|
Bob->>Alice: I'm short though
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render wrapped long messages from control to entity', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant Alice@{ "type" : "control" }
|
||||||
|
participant Bob@{ "type" : "entity" }
|
||||||
|
Alice->>Bob:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||||
|
Bob->>Alice: I'm short though
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render long messages from queue to boundary', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
participant Alice@{ "type" : "queue" }
|
||||||
|
participant Bob@{ "type" : "boundary" }
|
||||||
|
Alice->>Bob: I'm short
|
||||||
|
Bob->>Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render wrapped long messages from actor to database', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
actor Alice
|
||||||
|
participant Bob@{ "type" : "database" }
|
||||||
|
Alice->>Bob: I'm short
|
||||||
|
Bob->>Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('svg size', () => {
|
||||||
|
it('should render a sequence diagram when useMaxWidth is true (default)', () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
actor Alice
|
||||||
|
participant Bob@{ "type" : "boundary" }
|
||||||
|
participant John@{ "type" : "control" }
|
||||||
|
Alice ->> Bob: Hello Bob, how are you?
|
||||||
|
Bob-->>John: How about you John?
|
||||||
|
Bob--x Alice: I am good thanks!
|
||||||
|
Bob-x John: I am good thanks!
|
||||||
|
Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
|
||||||
|
Bob-->Alice: Checking with John...
|
||||||
|
alt either this
|
||||||
|
Alice->>John: Yes
|
||||||
|
else or this
|
||||||
|
Alice->>John: No
|
||||||
|
else or this will happen
|
||||||
|
Alice->John: Maybe
|
||||||
|
end
|
||||||
|
par this happens in parallel
|
||||||
|
Alice -->> Bob: Parallel message 1
|
||||||
|
and
|
||||||
|
Alice -->> John: Parallel message 2
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
{ sequence: { useMaxWidth: true } }
|
||||||
|
);
|
||||||
|
cy.get('svg').should((svg) => {
|
||||||
|
expect(svg).to.have.attr('width', '100%');
|
||||||
|
const style = svg.attr('style');
|
||||||
|
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||||
|
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||||
|
expect(maxWidthValue).to.be.within(820 * 0.95, 820 * 1.05);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render a sequence diagram when useMaxWidth is false', () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
actor Alice
|
||||||
|
participant Bob@{ "type" : "boundary" }
|
||||||
|
participant John@{ "type" : "control" }
|
||||||
|
Alice ->> Bob: Hello Bob, how are you?
|
||||||
|
Bob-->>John: How about you John?
|
||||||
|
Bob--x Alice: I am good thanks!
|
||||||
|
Bob-x John: I am good thanks!
|
||||||
|
Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
|
||||||
|
Bob-->Alice: Checking with John...
|
||||||
|
alt either this
|
||||||
|
Alice->>John: Yes
|
||||||
|
else or this
|
||||||
|
Alice->>John: No
|
||||||
|
else or this will happen
|
||||||
|
Alice->John: Maybe
|
||||||
|
end
|
||||||
|
par this happens in parallel
|
||||||
|
Alice -->> Bob: Parallel message 1
|
||||||
|
and
|
||||||
|
Alice -->> John: Parallel message 2
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
{ sequence: { useMaxWidth: false } }
|
||||||
|
);
|
||||||
|
cy.get('svg').should((svg) => {
|
||||||
|
const width = parseFloat(svg.attr('width'));
|
||||||
|
expect(width).to.be.within(820 * 0.95, 820 * 1.05);
|
||||||
|
expect(svg).to.not.have.attr('style');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Central Connection Rendering Tests', () => {
|
||||||
|
it('should render central connection circles on actor vertical lines', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant Alice
|
||||||
|
participant Bob
|
||||||
|
participant Charlie
|
||||||
|
Alice ()->>() Bob: Central connection
|
||||||
|
Bob ()-->> Charlie: Reverse central connection
|
||||||
|
Charlie ()<<-->>() Alice: Dual central connection`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render central connections with different arrow types', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant Alice
|
||||||
|
participant Bob
|
||||||
|
Alice ()->>() Bob: Solid open arrow
|
||||||
|
Alice ()-->>() Bob: Dotted open arrow
|
||||||
|
Alice ()-x() Bob: Solid cross
|
||||||
|
Alice ()--x() Bob: Dotted cross
|
||||||
|
Alice ()->() Bob: Solid arrow`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render central connections with bidirectional arrows', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant Alice
|
||||||
|
participant Bob
|
||||||
|
Alice ()<<->>() Bob: Bidirectional solid
|
||||||
|
Alice ()<<-->>() Bob: Bidirectional dotted`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render central connections with activations', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant Alice
|
||||||
|
participant Bob
|
||||||
|
participant Charlie
|
||||||
|
Alice ()->>() Bob: Activate Bob
|
||||||
|
activate Bob
|
||||||
|
Bob ()-->> Charlie: Message to Charlie
|
||||||
|
Bob ()->>() Alice: Response to Alice
|
||||||
|
deactivate Bob`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render central connections mixed with normal messages', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant Alice
|
||||||
|
participant Bob
|
||||||
|
participant Charlie
|
||||||
|
Alice ->> Bob: Normal message
|
||||||
|
Bob ()->>() Charlie: Central connection
|
||||||
|
Charlie -->> Alice: Normal dotted message
|
||||||
|
Alice ()<<-->>() Bob: Dual central connection
|
||||||
|
Bob -x Charlie: Normal cross message`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render central connections with notes', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant Alice
|
||||||
|
participant Bob
|
||||||
|
participant Charlie
|
||||||
|
Alice ()->>() Bob: Central connection
|
||||||
|
Note over Alice,Bob: Central connection note
|
||||||
|
Bob ()-->> Charlie: Reverse central connection
|
||||||
|
Note right of Charlie: Response note
|
||||||
|
Charlie ()<<-->>() Alice: Dual central connection`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render central connections with loops and alternatives', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant Alice
|
||||||
|
participant Bob
|
||||||
|
participant Charlie
|
||||||
|
loop Every minute
|
||||||
|
Alice ()->>() Bob: Central heartbeat
|
||||||
|
Bob ()-->> Charlie: Forward heartbeat
|
||||||
|
end
|
||||||
|
alt Success
|
||||||
|
Charlie ()<<-->>() Alice: Success response
|
||||||
|
else Failure
|
||||||
|
Charlie ()-x() Alice: Failure response
|
||||||
|
end`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render central connections with different participant types', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant Alice
|
||||||
|
actor Bob
|
||||||
|
participant Charlie@{"type":"boundary"}
|
||||||
|
participant David@{"type":"control"}
|
||||||
|
participant Eve@{"type":"entity"}
|
||||||
|
Alice ()->>() Bob: To actor
|
||||||
|
Bob ()-->> Charlie: To boundary
|
||||||
|
Charlie ()->>() David: To control
|
||||||
|
David ()<<-->>() Eve: To entity
|
||||||
|
Eve ()-x() Alice: Back to participant`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Participant Stereotypes with Aliases', () => {
|
||||||
|
it('should render participants with stereotypes and aliases', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant API@{ "type" : "boundary" } as Public API
|
||||||
|
participant Auth@{ "type" : "control" } as Auth Controller
|
||||||
|
participant DB@{ "type" : "database" } as User Database
|
||||||
|
participant Cache@{ "type" : "entity" } as Cache Layer
|
||||||
|
API ->> Auth: Authenticate request
|
||||||
|
Auth ->> DB: Query user
|
||||||
|
DB -->> Auth: User data
|
||||||
|
Auth ->> Cache: Store session
|
||||||
|
Cache -->> Auth: Confirmed
|
||||||
|
Auth -->> API: Token`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render actors with stereotypes and aliases', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
actor U@{ "type" : "actor" } as End User
|
||||||
|
actor A@{ "type" : "boundary" } as API Gateway
|
||||||
|
actor S@{ "type" : "control" } as Service Layer
|
||||||
|
actor D@{ "type" : "database" } as Data Store
|
||||||
|
U ->> A: Send request
|
||||||
|
A ->> S: Process
|
||||||
|
S ->> D: Persist
|
||||||
|
D -->> S: Success
|
||||||
|
S -->> A: Response
|
||||||
|
A -->> U: Result`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render mixed participants and actors with stereotypes and aliases', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
actor Client@{ "type" : "actor" } AS Mobile Client
|
||||||
|
participant Gateway@{ "type" : "boundary" } as API Gateway
|
||||||
|
participant OrderSvc@{ "type" : "control" } as Order Service
|
||||||
|
participant Queue@{ "type" : "queue" } as Message Queue
|
||||||
|
participant DB@{ "type" : "database" } as Order Database
|
||||||
|
participant Logs@{ "type" : "collections" } as Audit Logs
|
||||||
|
Client ->> Gateway: Place order
|
||||||
|
Gateway ->> OrderSvc: Validate order
|
||||||
|
OrderSvc ->> Queue: Queue for processing as well
|
||||||
|
OrderSvc ->> DB: Save order
|
||||||
|
OrderSvc ->> Logs: Log transaction
|
||||||
|
Queue -->> OrderSvc: Processing started AS Well
|
||||||
|
DB -->> OrderSvc: Order saved
|
||||||
|
Logs -->> OrderSvc: Logged
|
||||||
|
OrderSvc -->> Gateway: Order confirmed
|
||||||
|
Gateway -->> Client: Confirmation`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render stereotypes with aliases in boxes', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
box rgb(200,220,255) Frontend Layer
|
||||||
|
actor User@{ "type" : "actor" } as End User
|
||||||
|
participant UI@{ "type" : "boundary" } as User Interface
|
||||||
|
end
|
||||||
|
box rgb(255,220,200) Backend Layer
|
||||||
|
participant API@{ "type" : "boundary" } as REST API
|
||||||
|
participant Svc@{ "type" : "control" } as Business Logic
|
||||||
|
end
|
||||||
|
box rgb(220,255,200) Data Layer
|
||||||
|
participant DB@{ "type" : "database" } as Primary DB
|
||||||
|
participant Cache@{ "type" : "entity" } as Cache Store
|
||||||
|
end
|
||||||
|
User ->> UI: Click button
|
||||||
|
UI ->> API: HTTP request
|
||||||
|
API ->> Svc: Process
|
||||||
|
Svc ->> Cache: Check cache
|
||||||
|
Cache -->> Svc: Cache miss
|
||||||
|
Svc ->> DB: Query data
|
||||||
|
DB -->> Svc: Data
|
||||||
|
Svc ->> Cache: Update cache
|
||||||
|
Svc -->> API: Response
|
||||||
|
API -->> UI: Data
|
||||||
|
UI -->> User: Display`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render stereotypes with aliases and complex interactions', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant Web@{ "type" : "boundary" } as Web Portal
|
||||||
|
participant Auth@{ "type" : "control" } as Auth Service
|
||||||
|
participant UserDB@{ "type" : "database" } as User DB
|
||||||
|
participant Queue@{ "type" : "queue" } as Event Queue
|
||||||
|
participant Audit@{ "type" : "collections" } as Audit Trail
|
||||||
|
Web ->> Auth: Login request
|
||||||
|
activate Auth
|
||||||
|
Auth ->> UserDB: Verify credentials
|
||||||
|
activate UserDB
|
||||||
|
UserDB -->> Auth: User found
|
||||||
|
deactivate UserDB
|
||||||
|
alt Valid credentials
|
||||||
|
Auth ->> Queue: Publish login event
|
||||||
|
Auth ->> Audit: Log success
|
||||||
|
par Parallel processing
|
||||||
|
Queue -->> Auth: Event queued
|
||||||
|
and
|
||||||
|
Audit -->> Auth: Logged
|
||||||
|
end
|
||||||
|
Auth -->> Web: Success token
|
||||||
|
else Invalid credentials
|
||||||
|
Auth ->> Audit: Log failure
|
||||||
|
Audit -->> Auth: Logged
|
||||||
|
Auth --x Web: Access denied
|
||||||
|
end
|
||||||
|
deactivate Auth
|
||||||
|
Note over Web,Audit: All interactions logged`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Participant Inline Alias in Config', () => {
|
||||||
|
it('should render participants with inline alias in config object', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant API@{ "type" : "boundary", "alias": "Public API" }
|
||||||
|
participant Auth@{ "type" : "control", "alias": "Auth Service" }
|
||||||
|
participant DB@{ "type" : "database", "alias": "User DB" }
|
||||||
|
API ->> Auth: Login request
|
||||||
|
Auth ->> DB: Query user
|
||||||
|
DB -->> Auth: User data
|
||||||
|
Auth -->> API: Token`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render actors with inline alias in config object', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
actor U@{ "type" : "actor", "alias": "End User" }
|
||||||
|
actor G@{ "type" : "boundary", "alias": "Gateway" }
|
||||||
|
actor S@{ "type" : "control", "alias": "Service" }
|
||||||
|
U ->> G: Request
|
||||||
|
G ->> S: Process
|
||||||
|
S -->> G: Response
|
||||||
|
G -->> U: Result`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle mixed inline and external alias syntax', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant A@{ "type" : "boundary", "alias": "Service A" }
|
||||||
|
participant B@{ "type" : "control" } as Service B
|
||||||
|
participant C@{ "type" : "database" }
|
||||||
|
A ->> B: Request
|
||||||
|
B ->> C: Query
|
||||||
|
C -->> B: Data
|
||||||
|
B -->> A: Response`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prioritize external alias over inline alias', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant API@{ "type" : "boundary", "alias": "Internal Name" } as External Name
|
||||||
|
participant DB@{ "type" : "database", "alias": "Internal DB" } AS External DB
|
||||||
|
API ->> DB: Query
|
||||||
|
DB -->> API: Result`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render inline alias with only alias field (no type)', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
participant API@{ "alias": "Public API" }
|
||||||
|
participant Auth@{ "alias": "Auth Service" }
|
||||||
|
API ->> Auth: Request
|
||||||
|
Auth -->> API: Response`,
|
||||||
|
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -893,6 +893,17 @@ describe('Sequence diagram', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle bidirectional arrows with autonumber', () => {
|
||||||
|
imgSnapshotTest(`
|
||||||
|
sequenceDiagram
|
||||||
|
autonumber
|
||||||
|
participant A
|
||||||
|
participant B
|
||||||
|
A<<->>B: This is a bidirectional message
|
||||||
|
A->B: This is a normal message`);
|
||||||
|
});
|
||||||
|
|
||||||
it('should support actor links and properties when not mirrored EXPERIMENTAL: USE WITH CAUTION', () => {
|
it('should support actor links and properties when not mirrored EXPERIMENTAL: USE WITH CAUTION', () => {
|
||||||
//Be aware that the syntax for "properties" is likely to be changed.
|
//Be aware that the syntax for "properties" is likely to be changed.
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
@@ -1042,4 +1053,167 @@ describe('Sequence diagram', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('render new arrow type', () => {
|
||||||
|
it('should render Solid half arrow top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice -|\\ John: Hello John, how are you?
|
||||||
|
Alice-|\\ John: Hi Alice, I can hear you!
|
||||||
|
Alice -|\\ John: Test
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should render Solid half arrow bottom', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice-|/John: Hello John, how are you?
|
||||||
|
Alice-|/John: Hi Alice, I can hear you!
|
||||||
|
Alice-|/John: Test
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Stick half arrow top ', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice-\\\\John: Hello John, how are you?
|
||||||
|
Alice-\\\\John: Hi Alice, I can hear you!
|
||||||
|
Alice-\\\\John: Test
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should render Stick half arrow bottom ', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice-//John: Hello John, how are you?
|
||||||
|
Alice-//John: Hi Alice, I can hear you!
|
||||||
|
Alice-//John: Test
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should render Solid half arrow top reverse ', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice/|-John: Hello Alice, how are you?
|
||||||
|
Alice/|-John: Hi Alice, I can hear you!
|
||||||
|
Alice/|-John: Test
|
||||||
|
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Solid half arrow bottom reverse ', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`sequenceDiagram
|
||||||
|
Alice \\|- John: Hello Alice, how are you?
|
||||||
|
Alice \\|- John: Hi Alice, I can hear you!
|
||||||
|
Alice \\|- John: Test`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Stick half arrow top reverse ', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice //-John: Hello Alice, how are you?
|
||||||
|
Alice //-John: Hi Alice, I can hear you!
|
||||||
|
Alice //-John: Test`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Stick half arrow bottom reverse ', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice \\\\-John: Hello Alice, how are you?
|
||||||
|
Alice \\\\-John: Hi Alice, I can hear you!
|
||||||
|
Alice \\\\-John: Test`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Solid half arrow top dotted', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice --|\\John: Hello John, how are you?
|
||||||
|
Alice --|\\John: Hi Alice, I can hear you!
|
||||||
|
Alice --|\\John: Test`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Solid half arrow bottom dotted', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice --|/John: Hello John, how are you?
|
||||||
|
Alice --|/John: Hi Alice, I can hear you!
|
||||||
|
Alice --|/John: Test`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Stick half arrow top dotted', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice--\\\\John: Hello John, how are you?
|
||||||
|
Alice--\\\\John: Hi Alice, I can hear you!
|
||||||
|
Alice--\\\\John: Test`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Stick half arrow bottom dotted', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice--//John: Hello John, how are you?
|
||||||
|
Alice--//John: Hi Alice, I can hear you!
|
||||||
|
Alice--//John: Test`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Solid half arrow top reverse dotted', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice/|--John: Hello Alice, how are you?
|
||||||
|
Alice/|--John: Hi Alice, I can hear you!
|
||||||
|
Alice/|--John: Test`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Solid half arrow bottom reverse dotted', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice\\|--John: Hello Alice, how are you?
|
||||||
|
Alice\\|--John: Hi Alice, I can hear you!
|
||||||
|
Alice\\|--John: Test`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Stick half arrow top reverse dotted ', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice//--John: Hello Alice, how are you?
|
||||||
|
Alice//--John: Hi Alice, I can hear you!
|
||||||
|
Alice//--John: Test`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Stick half arrow bottom reverse dotted ', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice\\\\--John: Hello Alice, how are you?
|
||||||
|
Alice\\\\--John: Hi Alice, I can hear you!
|
||||||
|
Alice\\\\--John: Test`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -138,8 +138,8 @@ describe('State diagram', () => {
|
|||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
State1: This a a single line description
|
State1: This a single line description
|
||||||
State2: This a a multi line description
|
State2: This a multi line description
|
||||||
State2: here comes the multi part
|
State2: here comes the multi part
|
||||||
[*] --> State1
|
[*] --> State1
|
||||||
State1 --> State2
|
State1 --> State2
|
||||||
@@ -345,7 +345,7 @@ stateDiagram
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('v2 width of compond state should grow with title if title is wider', () => {
|
it('v2 width of compound state should grow with title if title is wider', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
@@ -402,8 +402,8 @@ stateDiagram-v2
|
|||||||
`
|
`
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
MyState
|
MyState
|
||||||
note left of MyState : I am a leftie
|
note left of MyState : I am a lefty
|
||||||
note right of MyState : I am a rightie
|
note right of MyState : I am a righty
|
||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
logLevel: 0,
|
logLevel: 0,
|
||||||
@@ -552,7 +552,7 @@ style AState fill:#636,border:1px solid red,color:white;
|
|||||||
{ logLevel: 0, fontFamily: 'courier' }
|
{ logLevel: 0, fontFamily: 'courier' }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it(' should let styles take preceedence over classes', () => {
|
it(' should let styles take precedence over classes', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
@@ -565,7 +565,7 @@ style AState fill:#636,border:1px solid red,color:white;
|
|||||||
{ logLevel: 0, fontFamily: 'courier' }
|
{ logLevel: 0, fontFamily: 'courier' }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it(' should allow styles to take effect in stubgraphs', () => {
|
it(' should allow styles to take effect in subgraphs', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
stateDiagram
|
stateDiagram
|
||||||
@@ -602,6 +602,231 @@ State1 --> [*]
|
|||||||
--
|
--
|
||||||
55
|
55
|
||||||
}
|
}
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should render edge labels correctly', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`---
|
||||||
|
title: On The Way To Something Something DarkSide
|
||||||
|
config:
|
||||||
|
look: default
|
||||||
|
theme: default
|
||||||
|
---
|
||||||
|
|
||||||
|
stateDiagram-v2
|
||||||
|
|
||||||
|
state State1_____________
|
||||||
|
{
|
||||||
|
c0
|
||||||
|
}
|
||||||
|
|
||||||
|
state State2_____________
|
||||||
|
{
|
||||||
|
c1
|
||||||
|
}
|
||||||
|
|
||||||
|
state State3_____________
|
||||||
|
{
|
||||||
|
c7
|
||||||
|
}
|
||||||
|
|
||||||
|
state State4_____________
|
||||||
|
{
|
||||||
|
c2
|
||||||
|
}
|
||||||
|
|
||||||
|
state State5_____________
|
||||||
|
{
|
||||||
|
c3
|
||||||
|
}
|
||||||
|
|
||||||
|
state State6_____________
|
||||||
|
{
|
||||||
|
c4
|
||||||
|
}
|
||||||
|
|
||||||
|
state State7_____________
|
||||||
|
{
|
||||||
|
c5
|
||||||
|
}
|
||||||
|
|
||||||
|
state State8_____________
|
||||||
|
{
|
||||||
|
c6
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[*] --> State1_____________
|
||||||
|
State1_____________ --> State2_____________ : Transition1_____
|
||||||
|
State2_____________ --> State4_____________ : Transition2_____
|
||||||
|
State2_____________ --> State3_____________ : Transition3_____
|
||||||
|
State3_____________ --> State2_____________
|
||||||
|
State4_____________ --> State2_____________ : Transition5_____
|
||||||
|
State4_____________ --> State5_____________ : Transition6_____
|
||||||
|
State5_____________ --> State6_____________ : Transition7_____
|
||||||
|
State6_____________ --> State4_____________ : Transition8_____
|
||||||
|
State2_____________ --> State7_____________ : Transition4_____
|
||||||
|
State4_____________ --> State7_____________ : Transition4_____
|
||||||
|
State5_____________ --> State7_____________ : Transition4_____
|
||||||
|
State6_____________ --> State7_____________ : Transition4_____
|
||||||
|
State7_____________ --> State1_____________ : Transition9_____
|
||||||
|
State5_____________ --> State8_____________ : Transition10____
|
||||||
|
State8_____________ --> State5_____________ : Transition11____
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should render edge labels correctly with multiple transitions', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`---
|
||||||
|
title: Multiple Transitions
|
||||||
|
config:
|
||||||
|
look: default
|
||||||
|
theme: default
|
||||||
|
---
|
||||||
|
|
||||||
|
stateDiagram-v2
|
||||||
|
|
||||||
|
state State1_____________
|
||||||
|
{
|
||||||
|
c0
|
||||||
|
}
|
||||||
|
|
||||||
|
state State2_____________
|
||||||
|
{
|
||||||
|
c1
|
||||||
|
}
|
||||||
|
|
||||||
|
state State3_____________
|
||||||
|
{
|
||||||
|
c7
|
||||||
|
}
|
||||||
|
|
||||||
|
state State4_____________
|
||||||
|
{
|
||||||
|
c2
|
||||||
|
}
|
||||||
|
|
||||||
|
state State5_____________
|
||||||
|
{
|
||||||
|
c3
|
||||||
|
}
|
||||||
|
|
||||||
|
state State6_____________
|
||||||
|
{
|
||||||
|
c4
|
||||||
|
}
|
||||||
|
|
||||||
|
state State7_____________
|
||||||
|
{
|
||||||
|
c5
|
||||||
|
}
|
||||||
|
|
||||||
|
state State8_____________
|
||||||
|
{
|
||||||
|
c6
|
||||||
|
}
|
||||||
|
|
||||||
|
state State9_____________
|
||||||
|
{
|
||||||
|
c9
|
||||||
|
}
|
||||||
|
|
||||||
|
[*] --> State1_____________
|
||||||
|
State1_____________ --> State2_____________ : Transition1_____
|
||||||
|
State2_____________ --> State4_____________ : Transition2_____
|
||||||
|
State2_____________ --> State3_____________ : Transition3_____
|
||||||
|
State3_____________ --> State2_____________
|
||||||
|
State4_____________ --> State2_____________ : Transition5_____
|
||||||
|
State4_____________ --> State5_____________ : Transition6_____
|
||||||
|
State5_____________ --> State6_____________ : Transition7_____
|
||||||
|
State6_____________ --> State4_____________ : Transition8_____
|
||||||
|
State2_____________ --> State7_____________ : Transition4_____
|
||||||
|
State4_____________ --> State7_____________ : Transition4_____
|
||||||
|
State5_____________ --> State7_____________ : Transition4_____
|
||||||
|
State6_____________ --> State7_____________ : Transition4_____
|
||||||
|
State7_____________ --> State1_____________ : Transition9_____
|
||||||
|
State5_____________ --> State8_____________ : Transition10____
|
||||||
|
State8_____________ --> State5_____________ : Transition11____
|
||||||
|
State9_____________ --> State8_____________ : Transition12____
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render edge labels correctly with multiple states', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`---
|
||||||
|
title: Multiple States
|
||||||
|
config:
|
||||||
|
look: default
|
||||||
|
theme: default
|
||||||
|
---
|
||||||
|
|
||||||
|
stateDiagram-v2
|
||||||
|
|
||||||
|
state State1_____________
|
||||||
|
{
|
||||||
|
c0
|
||||||
|
}
|
||||||
|
|
||||||
|
state State2_____________
|
||||||
|
{
|
||||||
|
c1
|
||||||
|
}
|
||||||
|
|
||||||
|
state State3_____________
|
||||||
|
{
|
||||||
|
c7
|
||||||
|
}
|
||||||
|
|
||||||
|
state State4_____________
|
||||||
|
{
|
||||||
|
c2
|
||||||
|
}
|
||||||
|
|
||||||
|
state State5_____________
|
||||||
|
{
|
||||||
|
c3
|
||||||
|
}
|
||||||
|
|
||||||
|
state State6_____________
|
||||||
|
{
|
||||||
|
c4
|
||||||
|
}
|
||||||
|
|
||||||
|
state State7_____________
|
||||||
|
{
|
||||||
|
c5
|
||||||
|
}
|
||||||
|
|
||||||
|
state State8_____________
|
||||||
|
{
|
||||||
|
c6
|
||||||
|
}
|
||||||
|
|
||||||
|
state State9_____________
|
||||||
|
{
|
||||||
|
c9
|
||||||
|
}
|
||||||
|
|
||||||
|
state State10_____________
|
||||||
|
{
|
||||||
|
c10
|
||||||
|
}
|
||||||
|
|
||||||
|
[*] --> State1_____________
|
||||||
|
State1_____________ --> State2_____________ : Transition1_____
|
||||||
|
State2_____________ --> State3_____________ : Transition2_____
|
||||||
|
State3_____________ --> State4_____________ : Transition3_____
|
||||||
|
State4_____________ --> State5_____________ : Transition4_____
|
||||||
|
State5_____________ --> State6_____________ : Transition5_____
|
||||||
|
State6_____________ --> State7_____________ : Transition6_____
|
||||||
|
State7_____________ --> State8_____________ : Transition7_____
|
||||||
|
State8_____________ --> State9_____________ : Transition8_____
|
||||||
|
State9_____________ --> State10_____________ : Transition9_____
|
||||||
`,
|
`,
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -129,8 +129,8 @@ describe('State diagram', () => {
|
|||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
stateDiagram
|
stateDiagram
|
||||||
State1: This a a single line description
|
State1: This a single line description
|
||||||
State2: This a a multi line description
|
State2: This a multi line description
|
||||||
State2: here comes the multi part
|
State2: here comes the multi part
|
||||||
[*] --> State1
|
[*] --> State1
|
||||||
State1 --> State2
|
State1 --> State2
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ describe('Timeline diagram', () => {
|
|||||||
title History of Social Media Platform
|
title History of Social Media Platform
|
||||||
2002 : LinkedIn
|
2002 : LinkedIn
|
||||||
2004 : Facebook : Google
|
2004 : Facebook : Google
|
||||||
2005 : Youtube
|
2005 : YouTube
|
||||||
2006 : Twitter
|
2006 : Twitter
|
||||||
`,
|
`,
|
||||||
{}
|
{}
|
||||||
@@ -35,7 +35,7 @@ describe('Timeline diagram', () => {
|
|||||||
section Stone Age
|
section Stone Age
|
||||||
7600 BC : Britain's oldest known house was built in Orkney, Scotland
|
7600 BC : Britain's oldest known house was built in Orkney, Scotland
|
||||||
6000 BC : Sea levels rise and Britain becomes an island.<br> The people who live here are hunter-gatherers.
|
6000 BC : Sea levels rise and Britain becomes an island.<br> The people who live here are hunter-gatherers.
|
||||||
section Broze Age
|
section Bronze Age
|
||||||
2300 BC : People arrive from Europe and settle in Britain. <br>They bring farming and metalworking.
|
2300 BC : People arrive from Europe and settle in Britain. <br>They bring farming and metalworking.
|
||||||
: New styles of pottery and ways of burying the dead appear.
|
: New styles of pottery and ways of burying the dead appear.
|
||||||
2200 BC : The last major building works are completed at Stonehenge.<br> People now bury their dead in stone circles.
|
2200 BC : The last major building works are completed at Stonehenge.<br> People now bury their dead in stone circles.
|
||||||
@@ -51,7 +51,7 @@ describe('Timeline diagram', () => {
|
|||||||
title History of Social Media Platform
|
title History of Social Media Platform
|
||||||
2002 : LinkedIn
|
2002 : LinkedIn
|
||||||
2004 : Facebook : Google
|
2004 : Facebook : Google
|
||||||
2005 : Youtube
|
2005 : YouTube
|
||||||
2006 : Twitter
|
2006 : Twitter
|
||||||
`,
|
`,
|
||||||
{}
|
{}
|
||||||
@@ -68,7 +68,7 @@ describe('Timeline diagram', () => {
|
|||||||
title History of Social Media Platform
|
title History of Social Media Platform
|
||||||
2002 : LinkedIn
|
2002 : LinkedIn
|
||||||
2004 : Facebook : Google
|
2004 : Facebook : Google
|
||||||
2005 : Youtube
|
2005 : YouTube
|
||||||
2006 : Twitter
|
2006 : Twitter
|
||||||
2007 : Tumblr
|
2007 : Tumblr
|
||||||
2008 : Instagram
|
2008 : Instagram
|
||||||
@@ -84,7 +84,7 @@ describe('Timeline diagram', () => {
|
|||||||
title History of Social Media Platform
|
title History of Social Media Platform
|
||||||
2002 : LinkedIn
|
2002 : LinkedIn
|
||||||
2004 : Facebook : Google
|
2004 : Facebook : Google
|
||||||
2005 : Youtube
|
2005 : YouTube
|
||||||
2006 : Twitter
|
2006 : Twitter
|
||||||
2007 : Tumblr
|
2007 : Tumblr
|
||||||
2008 : Instagram
|
2008 : Instagram
|
||||||
@@ -101,7 +101,7 @@ describe('Timeline diagram', () => {
|
|||||||
title History of Social Media Platform
|
title History of Social Media Platform
|
||||||
2002 : LinkedIn
|
2002 : LinkedIn
|
||||||
2004 : Facebook : Google
|
2004 : Facebook : Google
|
||||||
2005 : Youtube
|
2005 : YouTube
|
||||||
2006 : Twitter
|
2006 : Twitter
|
||||||
2007 : Tumblr
|
2007 : Tumblr
|
||||||
2008 : Instagram
|
2008 : Instagram
|
||||||
@@ -118,7 +118,7 @@ describe('Timeline diagram', () => {
|
|||||||
title History of Social Media Platform
|
title History of Social Media Platform
|
||||||
2002 : LinkedIn
|
2002 : LinkedIn
|
||||||
2004 : Facebook : Google
|
2004 : Facebook : Google
|
||||||
2005 : Youtube
|
2005 : YouTube
|
||||||
2006 : Twitter
|
2006 : Twitter
|
||||||
2007 : Tumblr
|
2007 : Tumblr
|
||||||
2008 : Instagram
|
2008 : Instagram
|
||||||
@@ -135,7 +135,7 @@ describe('Timeline diagram', () => {
|
|||||||
title History of Social Media Platform
|
title History of Social Media Platform
|
||||||
2002 : LinkedIn
|
2002 : LinkedIn
|
||||||
2004 : Facebook : Google
|
2004 : Facebook : Google
|
||||||
2005 : Youtube
|
2005 : YouTube
|
||||||
2006 : Twitter
|
2006 : Twitter
|
||||||
2007 : Tumblr
|
2007 : Tumblr
|
||||||
2008 : Instagram
|
2008 : Instagram
|
||||||
@@ -152,7 +152,7 @@ describe('Timeline diagram', () => {
|
|||||||
title History of Social Media Platform
|
title History of Social Media Platform
|
||||||
2002 : LinkedIn
|
2002 : LinkedIn
|
||||||
2004 : Facebook : Google
|
2004 : Facebook : Google
|
||||||
2005 : Youtube
|
2005 : YouTube
|
||||||
2006 : Twitter
|
2006 : Twitter
|
||||||
2007 : Tumblr
|
2007 : Tumblr
|
||||||
2008 : Instagram
|
2008 : Instagram
|
||||||
@@ -161,4 +161,68 @@ describe('Timeline diagram', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('11: should render timeline with many stacked events and proper timeline line length', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`timeline
|
||||||
|
title Medical Device Lifecycle
|
||||||
|
section Pre-Development
|
||||||
|
Quality Management System : Regulatory Compliance : Risk Management
|
||||||
|
section Development
|
||||||
|
Management Responsibility : Planning Activities : Human Resources
|
||||||
|
Resource Management : Management Reviews : Infrastructure
|
||||||
|
section Post-Development
|
||||||
|
Product Realization Activities : Planning Activities : Customer-related Processes
|
||||||
|
Post-Production Activities : Feedback : Complaints : Adverse Events
|
||||||
|
: Research and Development : Purchasing Activities
|
||||||
|
: Production Activities : Installation Activities
|
||||||
|
: Servicing Activities : Post-Market Surveillance
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('12: should render timeline with proper vertical line lengths for all columns', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`---
|
||||||
|
config:
|
||||||
|
theme: base
|
||||||
|
themeVariables:
|
||||||
|
fontFamily: Fira Sans
|
||||||
|
fontSize: 17px
|
||||||
|
cScale0: '#b3cde0'
|
||||||
|
cScale1: '#f49090'
|
||||||
|
cScale2: '#85d5b8'
|
||||||
|
---
|
||||||
|
|
||||||
|
timeline
|
||||||
|
title Medical Device Lifecycle
|
||||||
|
section Planning
|
||||||
|
Quality Management System (4): Regulatory Compliance (4.1.1)
|
||||||
|
: Risk Management (4.1.2)
|
||||||
|
Management Resposibility (5): Planning Activities (5.4)
|
||||||
|
: Management Reviews (5.6)
|
||||||
|
Resource Management (6): Human Resources (6.2)
|
||||||
|
: Infrastructure (6.3)
|
||||||
|
section Realization
|
||||||
|
Research and Development (7.3): RnD Planning (7.3.2)
|
||||||
|
: Inputs (7.3.3)
|
||||||
|
: Outputs (7.3.4)
|
||||||
|
: Review (7.3.5)
|
||||||
|
: Verification (7.3.6)
|
||||||
|
: Validation (7.3.7)
|
||||||
|
Purchasing (7.4): Purchasing Process (7.4.1)
|
||||||
|
: Purchasing Information (7.4.2)
|
||||||
|
Production (7.5): Production Activities (7.5.1)
|
||||||
|
: Production Feedback (8.2.1)
|
||||||
|
Installation (7.5.3): Installation Activities (7.5.3)
|
||||||
|
Servicing (7.5.4): Servicing Activities (7.5.4)
|
||||||
|
section Post-Production
|
||||||
|
Post-Market Activities (8): Feedback (8.2.1)
|
||||||
|
: Complaints (8.2.2)
|
||||||
|
: Adverse Events (8.2.3)
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user