mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-24 00:14:10 +02:00
Compare commits
569 Commits
mermaid@11
...
swimlanes-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
820603e475 | ||
|
|
4636305783 | ||
|
|
2247bc583f | ||
|
|
fa51a37d8c | ||
|
|
e6e88cef15 | ||
|
|
2e47e17d28 | ||
|
|
79218398ee | ||
|
|
01010465dd | ||
|
|
c3b78a37a6 | ||
|
|
7e9a29f486 | ||
|
|
5d1c619ca5 | ||
|
|
23c00bf7ca | ||
|
|
b3a2794f1f | ||
|
|
7513d0e39a | ||
|
|
571bbab859 | ||
|
|
88b28e8fc3 | ||
|
|
579d1ee33c | ||
|
|
13e3d7293e | ||
|
|
db2295db24 | ||
|
|
aa28880be7 | ||
|
|
463d42b86d | ||
|
|
ba0b945821 | ||
|
|
bf39ae7369 | ||
|
|
4911b63e44 | ||
|
|
d52e3d1931 | ||
|
|
0d308fdffe | ||
|
|
fb19255f10 | ||
|
|
2ef6760cbc | ||
|
|
2f525434fd | ||
|
|
49bdd11011 | ||
|
|
f785b47b1d | ||
|
|
f7772b440d | ||
|
|
5bee403c33 | ||
|
|
d7535a9e4d | ||
|
|
fd8f95b628 | ||
|
|
78c63d3dc1 | ||
|
|
9c89d3401a | ||
|
|
7fbc873fd0 | ||
|
|
1089ec0963 | ||
|
|
7df125ab59 | ||
|
|
7425430b80 | ||
|
|
2674bb80ab | ||
|
|
d4441e0200 | ||
|
|
8bc898ddf1 | ||
|
|
7afd7a9729 | ||
|
|
fa4d93483a | ||
|
|
7d11a9578a | ||
|
|
5b6c5412cd | ||
|
|
51756edefc | ||
|
|
4e685b74a7 | ||
|
|
259af0fb77 | ||
|
|
6e3c37c98b | ||
|
|
9114f65dbe | ||
|
|
6d73220348 | ||
|
|
e07fd6d98c | ||
|
|
e6d45da81e | ||
|
|
619a1df26e | ||
|
|
7491c78c8c | ||
|
|
f0fdf91379 | ||
|
|
0bf4aa3e82 | ||
|
|
9bf2bda539 | ||
|
|
35aa869adc | ||
|
|
bf20e0615a | ||
|
|
2352b422db | ||
|
|
48a0d41a81 | ||
|
|
e75260ac07 | ||
|
|
b5ef6d2e23 | ||
|
|
8277579259 | ||
|
|
8336d1cf2d | ||
|
|
3c93e4640a | ||
|
|
0c28593ea5 | ||
|
|
33d8b1a78d | ||
|
|
1e3ea13323 | ||
|
|
4c8c48cde9 | ||
|
|
38250af678 | ||
|
|
c8e50276e8 | ||
|
|
1e6419a63f | ||
|
|
de08b8244f | ||
|
|
41fdfd4c5c | ||
|
|
81c2f0f7a9 | ||
|
|
fee2ad565d | ||
|
|
725e25ad88 | ||
|
|
cb03af5214 | ||
|
|
4a812a964d | ||
|
|
c4d06cd4fd | ||
|
|
ae2c533aca | ||
|
|
1598ac713f | ||
|
|
45d8a815dc | ||
|
|
82b421696b | ||
|
|
e98ab130cc | ||
|
|
ddeab2f705 | ||
|
|
b08cd5dbba | ||
|
|
e842cf582b | ||
|
|
6db6beca4b | ||
|
|
35fea81209 | ||
|
|
13d4a238d4 | ||
|
|
c7171fa7b1 | ||
|
|
861599245d | ||
|
|
f550f17dc0 | ||
|
|
191cd27b2b | ||
|
|
4ad85974c6 | ||
|
|
91ed9bb9c2 | ||
|
|
18fd67300f | ||
|
|
93239b5f34 | ||
|
|
807820f199 | ||
|
|
030aeb8c88 | ||
|
|
0d1212e463 | ||
|
|
92d706f677 | ||
|
|
44e7e68e0b | ||
|
|
7d59a624d7 | ||
|
|
e2dc9e557c | ||
|
|
c7adb37a1f | ||
|
|
3b5ca1c638 | ||
|
|
ff9fffef90 | ||
|
|
71d6ded224 | ||
|
|
5ecd12de1c | ||
|
|
ee4991f3e7 | ||
|
|
1028ca2ffc | ||
|
|
edce46b305 | ||
|
|
2509511135 | ||
|
|
c76a513417 | ||
|
|
3968010d6b | ||
|
|
122a44024c | ||
|
|
654c00f88c | ||
|
|
c5acf870de | ||
|
|
c73f8d0990 | ||
|
|
aa91874d9e | ||
|
|
42fe55e2bc | ||
|
|
3bcbad7fa1 | ||
|
|
32ff6ec50f | ||
|
|
0198f0e798 | ||
|
|
9aded56538 | ||
|
|
b52b54086e | ||
|
|
31c01b1795 | ||
|
|
90b200ed2e | ||
|
|
971a166073 | ||
|
|
4e25bf5db9 | ||
|
|
962fcb8ba8 | ||
|
|
b3f2ba8bb8 | ||
|
|
bda37516b8 | ||
|
|
0aebb941e9 | ||
|
|
36df0e340e | ||
|
|
1d8c4fd279 | ||
|
|
c1377f9075 | ||
|
|
c6fd62ab7d | ||
|
|
2abdece0f2 | ||
|
|
ed1427ed31 | ||
|
|
36f1dc8541 | ||
|
|
7a7d161a61 | ||
|
|
a2d64a82c5 | ||
|
|
f1674b8b04 | ||
|
|
eb346e1c51 | ||
|
|
d2dfb639c8 | ||
|
|
5363e9545e | ||
|
|
42fd9836f0 | ||
|
|
bda3bfd2a7 | ||
|
|
834fa07991 | ||
|
|
491aa7d9ff | ||
|
|
6cf07067e2 | ||
|
|
d0881534c1 | ||
|
|
f10d148097 | ||
|
|
f5545d094f | ||
|
|
c36bdf12a0 | ||
|
|
92f67af6af | ||
|
|
d175e9a403 | ||
|
|
2ce57e4cf4 | ||
|
|
a7a9185222 | ||
|
|
edc2ac7fea | ||
|
|
221d59cbfc | ||
|
|
e8472c3647 | ||
|
|
414f666417 | ||
|
|
5ad1a6082b | ||
|
|
32d7f470dc | ||
|
|
9b269ecf3b | ||
|
|
8fa8fd6abd | ||
|
|
9957d3101f | ||
|
|
22982baf1a | ||
|
|
d3b51e2282 | ||
|
|
d9b2220085 | ||
|
|
e2ecb8e180 | ||
|
|
68ba79259a | ||
|
|
0f7e14ba70 | ||
|
|
59f28810d5 | ||
|
|
00b32d07fe | ||
|
|
bf57a283d3 | ||
|
|
ee2e6a2c2c | ||
|
|
9caa46cfd2 | ||
|
|
2566f1cab8 | ||
|
|
aae4e6f048 | ||
|
|
b32acb619c | ||
|
|
1510939196 | ||
|
|
a8db94fd1a | ||
|
|
c72d774519 | ||
|
|
437f2c0be2 | ||
|
|
82e8eb97cc | ||
|
|
c7a2023661 | ||
|
|
0b0c0fc1f1 | ||
|
|
ba51f4ab38 | ||
|
|
c3838305b3 | ||
|
|
5b7dfbad94 | ||
|
|
b47168b064 | ||
|
|
2c0d48eef5 | ||
|
|
1ef4c42bcf | ||
|
|
9da6321c4b | ||
|
|
b99e080337 | ||
|
|
7a9ec739d9 | ||
|
|
390025c085 | ||
|
|
e4abc39572 | ||
|
|
b0abb44928 | ||
|
|
0afd83a0c3 | ||
|
|
0a355968c4 | ||
|
|
2a05b479ae | ||
|
|
9e3bd1fb19 | ||
|
|
0ba4265bc3 | ||
|
|
a94ad012c4 | ||
|
|
bcfc5e0ce4 | ||
|
|
210cd35422 | ||
|
|
2aaf1b9619 | ||
|
|
e63f533f3c | ||
|
|
3a3ea06413 | ||
|
|
5a1640ee34 | ||
|
|
633328c9da | ||
|
|
51aba30620 | ||
|
|
f720f2cb13 | ||
|
|
02a03e3d60 | ||
|
|
97dec4e4cb | ||
|
|
bb755c6e99 | ||
|
|
65d47dea24 | ||
|
|
6934c3eb5a | ||
|
|
4d2ffc46d0 | ||
|
|
2f2fc1b4f1 | ||
|
|
7dcd2758b2 | ||
|
|
1a974eeb39 | ||
|
|
7272e7297c | ||
|
|
c94c3d7c86 | ||
|
|
3fc723003c | ||
|
|
6d64c75121 | ||
|
|
62bcfefa7c | ||
|
|
401590c010 | ||
|
|
b301138d93 | ||
|
|
cf53340672 | ||
|
|
a07b61fdf1 | ||
|
|
e67894fbb3 | ||
|
|
fa638da9fc | ||
|
|
b9ae52e1c2 | ||
|
|
5348e74475 | ||
|
|
aa41c67266 | ||
|
|
6184510439 | ||
|
|
faed69c86e | ||
|
|
16a75de518 | ||
|
|
a23132e1f2 | ||
|
|
2bc6ac4a76 | ||
|
|
776cb92e3e | ||
|
|
2a7c3dc436 | ||
|
|
032a8cbbee | ||
|
|
3d767cbc06 | ||
|
|
eee669f1ee | ||
|
|
d85889c200 | ||
|
|
ff3418c520 | ||
|
|
7b0b548d05 | ||
|
|
48791aac13 | ||
|
|
c8381d0fca | ||
|
|
2bb1a2c4f2 | ||
|
|
3730f1afbb | ||
|
|
e0c2b832a9 | ||
|
|
4cbb0004be | ||
|
|
19e79fda73 | ||
|
|
05989d06fa | ||
|
|
71889fd135 | ||
|
|
eca19efa32 | ||
|
|
4841b7d3d9 | ||
|
|
dd01f3d52c | ||
|
|
dc642fb5bc | ||
|
|
ef428dc555 | ||
|
|
d964893a5d | ||
|
|
7ef296a9cf | ||
|
|
acd66a5eb4 | ||
|
|
db6242590e | ||
|
|
1efc794056 | ||
|
|
d1395d05e2 | ||
|
|
888f668f5e | ||
|
|
d0caa2b3e0 | ||
|
|
900c8a4209 | ||
|
|
5ab955b6b3 | ||
|
|
fd8542080d | ||
|
|
040a989c3d | ||
|
|
638be1992d | ||
|
|
13b96ad6c0 | ||
|
|
f9d5128c91 | ||
|
|
35f2e4f5fa | ||
|
|
2244c1fa87 | ||
|
|
791b442089 | ||
|
|
e180ad0666 | ||
|
|
1b67997da2 | ||
|
|
c18ee0381c | ||
|
|
8d91622235 | ||
|
|
19f98c1c72 | ||
|
|
afe32f2f8c | ||
|
|
b214f30e96 | ||
|
|
415eb26335 | ||
|
|
8fd57abc81 | ||
|
|
165a4f6825 | ||
|
|
1e7a5a4408 | ||
|
|
acb569193b | ||
|
|
1b6d627bd3 | ||
|
|
ea987171b2 | ||
|
|
b84617c915 | ||
|
|
0e2753814a | ||
|
|
11bb1a4a17 | ||
|
|
46aba3dfe9 | ||
|
|
0764dca3ce | ||
|
|
83493f26b7 | ||
|
|
5673dd7ebc | ||
|
|
fabecc4abd | ||
|
|
7603a51302 | ||
|
|
dedf2d25e3 | ||
|
|
b011b628ad | ||
|
|
db3541047a | ||
|
|
bd5a9cc21e | ||
|
|
62f887b3c3 | ||
|
|
9c2d7b1dad | ||
|
|
fd47e4eb2f | ||
|
|
327ea728ac | ||
|
|
96974c9007 | ||
|
|
c00707165f | ||
|
|
dc2ecc9f19 | ||
|
|
41b8a1e6f4 | ||
|
|
d421cfb1fd | ||
|
|
ba978e86ae | ||
|
|
1483e9245e | ||
|
|
6a53d87742 | ||
|
|
a7b771a622 | ||
|
|
c6acf84e43 | ||
|
|
e9b91485f4 | ||
|
|
a0a03b932d | ||
|
|
9acf55069c | ||
|
|
4878cb9356 | ||
|
|
b6725eae94 | ||
|
|
2415e8652a | ||
|
|
941a1723d8 | ||
|
|
43b038547e | ||
|
|
8a22615dbf | ||
|
|
947b59d392 | ||
|
|
58694ecd29 | ||
|
|
8e3cb5fb1b | ||
|
|
534cf32231 | ||
|
|
41484b2272 | ||
|
|
992095d0f8 | ||
|
|
3321f6472f | ||
|
|
2ee94eb9ae | ||
|
|
2114e3e0fc | ||
|
|
87011c6ab4 | ||
|
|
3dc66a64c7 | ||
|
|
64cc767dd5 | ||
|
|
04a704c068 | ||
|
|
cef45c023f | ||
|
|
61100d81b1 | ||
|
|
29a9c16ab6 | ||
|
|
ba20d6c627 | ||
|
|
ca7ddbfe8a | ||
|
|
c33aa50916 | ||
|
|
b153203338 | ||
|
|
f834dba3ff | ||
|
|
640c502346 | ||
|
|
34ecbba275 | ||
|
|
930a33d351 | ||
|
|
fda930ec64 | ||
|
|
f93e331be5 | ||
|
|
7396c485db | ||
|
|
85e7af566e | ||
|
|
36c90cf90e | ||
|
|
6346e29f6a | ||
|
|
04b31b8672 | ||
|
|
2eddee90e0 | ||
|
|
63f9043d40 | ||
|
|
e019a60bdd | ||
|
|
0a4ace5128 | ||
|
|
7156735394 | ||
|
|
64a5c11318 | ||
|
|
05abfd132b | ||
|
|
31370ed240 | ||
|
|
e6722bc7f6 | ||
|
|
3f0e18cb94 | ||
|
|
cc0dcd68f8 | ||
|
|
9a2865c64a | ||
|
|
2c25197d65 | ||
|
|
2d6a5ade9d | ||
|
|
7ad9b84319 | ||
|
|
ff0322a5dd | ||
|
|
9aa01d8a39 | ||
|
|
04ad2ae3dd | ||
|
|
d7497c179e | ||
|
|
df7de0e796 | ||
|
|
55d4e83732 | ||
|
|
9e01da0d04 | ||
|
|
476b7a12d7 | ||
|
|
40063d0982 | ||
|
|
25703ea8c1 | ||
|
|
87f333b0d5 | ||
|
|
ae046ff4dd | ||
|
|
5f35f6c37d | ||
|
|
3b7fb45ee6 | ||
|
|
0ab49e1e3d | ||
|
|
442d5077d3 | ||
|
|
834afef2c0 | ||
|
|
0b4dbeda8c | ||
|
|
84fc95d7cf | ||
|
|
bbe71f5367 | ||
|
|
9528b5f391 | ||
|
|
23180d35ac | ||
|
|
35ae14681e | ||
|
|
9bfd6517ac | ||
|
|
bebc2ba4e9 | ||
|
|
93b4699189 | ||
|
|
5feb3beb8b | ||
|
|
11c3ef1c8b | ||
|
|
f967ee935d | ||
|
|
20a273a853 | ||
|
|
e451f83b08 | ||
|
|
948781cbce | ||
|
|
cdf75558b5 | ||
|
|
f8c16f577b | ||
|
|
823035abd8 | ||
|
|
82f1344af6 | ||
|
|
ab626fac9e | ||
|
|
4fa080df9d | ||
|
|
c5186b0df2 | ||
|
|
b9dda2797a | ||
|
|
d898cc6a67 | ||
|
|
01b7074203 | ||
|
|
c4685fb0ff | ||
|
|
96c8e544ec | ||
|
|
c406e6cefe | ||
|
|
31936cf6cb | ||
|
|
d6e8419360 | ||
|
|
37e43c0be4 | ||
|
|
9510b2e138 | ||
|
|
4bd6e3a70c | ||
|
|
54a6a996aa | ||
|
|
ba6f2b26a6 | ||
|
|
9cac8cc472 | ||
|
|
416a9fa069 | ||
|
|
1c1dbe0eb7 | ||
|
|
0520226b5b | ||
|
|
e7d9e1b223 | ||
|
|
d5735fd721 | ||
|
|
1e47c8a70e | ||
|
|
838b2ce391 | ||
|
|
9b310df58a | ||
|
|
7f8ca0c77e | ||
|
|
444bad5f20 | ||
|
|
0d630862ee | ||
|
|
7297b9bc42 | ||
|
|
92e6f52168 | ||
|
|
2007cab5ee | ||
|
|
86d75373ca | ||
|
|
41a5f2dacd | ||
|
|
f431020b6b | ||
|
|
736181bf3d | ||
|
|
ace39a2154 | ||
|
|
959d8cb606 | ||
|
|
f96c6462de | ||
|
|
74ef8b53f1 | ||
|
|
3780659337 | ||
|
|
ea87596363 | ||
|
|
caff6662a0 | ||
|
|
ce7e738843 | ||
|
|
9591159901 | ||
|
|
ced34394bb | ||
|
|
1cdafaac80 | ||
|
|
0fc2f3c85f | ||
|
|
ea0b4f3e95 | ||
|
|
8aefe293b0 | ||
|
|
757f5c395c | ||
|
|
0a08cfd573 | ||
|
|
582035ef9b | ||
|
|
2f6d728123 | ||
|
|
61b8c9b639 | ||
|
|
729cbec78d | ||
|
|
ccdaa6333e | ||
|
|
bbb118547e | ||
|
|
04159a8427 | ||
|
|
4838023a0b | ||
|
|
d70ffe93bb | ||
|
|
10e9a30769 | ||
|
|
9d590bc587 | ||
|
|
69871c94c4 | ||
|
|
2c2b86dc9d | ||
|
|
8b278d483a | ||
|
|
9fbad9c9c1 | ||
|
|
2130839770 | ||
|
|
f22f319599 | ||
|
|
f17d788ac8 | ||
|
|
67cf57ae4f | ||
|
|
8ff462f01c | ||
|
|
183b83b1ff | ||
|
|
0dd6db67e8 | ||
|
|
7ff731163f | ||
|
|
7c851bc849 | ||
|
|
2df39e3658 | ||
|
|
29e73ed2dc | ||
|
|
32f6c9eefa | ||
|
|
3af2c29d8f | ||
|
|
6842b316ec | ||
|
|
979a9b08f9 | ||
|
|
d3ec33cfe7 | ||
|
|
80295c3cc2 | ||
|
|
a4777bd44d | ||
|
|
efe8573c06 | ||
|
|
a9aa8b7f1a | ||
|
|
58f5f4a35d | ||
|
|
6dcdec0126 | ||
|
|
4eea7ff5da | ||
|
|
15d35387a0 | ||
|
|
8b7001b8e3 | ||
|
|
4fe7e062b5 | ||
|
|
b41431b378 | ||
|
|
1bf4cca3a3 | ||
|
|
edd4457154 | ||
|
|
36de3dca62 | ||
|
|
51da34b831 | ||
|
|
59130ca107 | ||
|
|
544d17db95 | ||
|
|
ce6aa48511 | ||
|
|
03ba130764 | ||
|
|
a36f1d1656 | ||
|
|
8d1539f2d7 | ||
|
|
0393e4018b | ||
|
|
195ea6405a | ||
|
|
9fca13ca19 | ||
|
|
b9b678a429 | ||
|
|
648d804d03 | ||
|
|
344f7a9060 | ||
|
|
520e06d2eb | ||
|
|
8bb340182c | ||
|
|
a62239d9bc | ||
|
|
b390fbe1cb | ||
|
|
e416ac1c0b | ||
|
|
4538f5b8c6 | ||
|
|
b2ccec0efa | ||
|
|
e52ad8edc2 | ||
|
|
be604703aa | ||
|
|
2ba93dd30d | ||
|
|
a54e1a854b | ||
|
|
ea56c64c7b | ||
|
|
1089c4029c | ||
|
|
bca86cce52 | ||
|
|
d14a399801 | ||
|
|
949a06b00f | ||
|
|
0b88e0a8a9 | ||
|
|
ec4f0120ef | ||
|
|
51b1216a46 | ||
|
|
f353f3b28c | ||
|
|
f0f1bec9ce | ||
|
|
f5bd82461e | ||
|
|
b5f70cd45e | ||
|
|
c2b640aa86 | ||
|
|
f5bf2563cf | ||
|
|
26c7ee15e9 | ||
|
|
8f7fd8329d | ||
|
|
a41488a849 | ||
|
|
762daac854 | ||
|
|
f1e5bd37ae | ||
|
|
ae307831eb | ||
|
|
976a39ea54 | ||
|
|
0ff611b729 | ||
|
|
6c2ded389f | ||
|
|
5b3b73ba49 | ||
|
|
ce4318a419 |
5
.changeset/hungry-guests-drive.md
Normal file
5
.changeset/hungry-guests-drive.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@mermaid-js/layout-elk': patch
|
||||
---
|
||||
|
||||
fix: Updated offset calculations for diamond shape when handling intersections
|
||||
@@ -47,6 +47,7 @@ mdbook
|
||||
Mermerd
|
||||
mkdocs
|
||||
Nextra
|
||||
NODECOUNT
|
||||
nodenext
|
||||
npmjs
|
||||
pageview
|
||||
@@ -58,6 +59,7 @@ presetAttributify
|
||||
pyplot
|
||||
redmine
|
||||
rehype
|
||||
RIGHTDOWN
|
||||
roughjs
|
||||
rscratch
|
||||
shiki
|
||||
@@ -67,6 +69,7 @@ sphinxcontrib
|
||||
ssim
|
||||
stylis
|
||||
Swimm
|
||||
topdown
|
||||
tsbuildinfo
|
||||
tseslint
|
||||
Tuleap
|
||||
|
||||
1
.github/workflows/test.yml
vendored
1
.github/workflows/test.yml
vendored
@@ -39,6 +39,7 @@ jobs:
|
||||
pnpm exec vitest run ./packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts --coverage
|
||||
|
||||
- name: Verify out-of-tree build with TypeScript
|
||||
if: ${{ github.repository == 'mermaid-js/mermaid' }}
|
||||
run: |
|
||||
pnpm test:check:tsc
|
||||
|
||||
|
||||
24
.vscode/launch.json
vendored
24
.vscode/launch.json
vendored
@@ -12,18 +12,18 @@
|
||||
"args": ["run", "${relativeFile}"],
|
||||
"smartStep": true,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "Docs generation",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"args": ["scripts/docs.cli.mts"],
|
||||
// we'll need to change this to --import in Node.JS v20.6.0 and up
|
||||
"runtimeArgs": ["--loader", "tsx/esm"],
|
||||
"cwd": "${workspaceRoot}/packages/mermaid",
|
||||
"skipFiles": ["<node_internals>/**", "**/node_modules/**"],
|
||||
"smartStep": true,
|
||||
"internalConsoleOptions": "openOnSessionStart"
|
||||
}
|
||||
// {
|
||||
// "name": "Docs generation",
|
||||
// "type": "node",
|
||||
// "request": "launch",
|
||||
// "args": ["scripts/docs.cli.mts"],
|
||||
// // we'll need to change this to --import in Node.JS v20.6.0 and up
|
||||
// "runtimeArgs": ["--loader", "tsx/esm"],
|
||||
// "cwd": "${workspaceRoot}/packages/mermaid",
|
||||
// "skipFiles": ["<node_internals>/**", "**/node_modules/**"],
|
||||
// "smartStep": true,
|
||||
// "internalConsoleOptions": "openOnSessionStart"
|
||||
// }
|
||||
]
|
||||
}
|
||||
|
||||
9
Pulling-from-remote.md
Normal file
9
Pulling-from-remote.md
Normal file
@@ -0,0 +1,9 @@
|
||||
Pulling from remote repo
|
||||
|
||||
```
|
||||
git remote add os_repo git@github.com:mermaid-js/mermaid.git
|
||||
git pull os_repo main
|
||||
git pull os_repo
|
||||
git pull os_repo master
|
||||
git pull os_repo 5237-unified-layout-common-renderer
|
||||
```
|
||||
@@ -23,7 +23,11 @@ export default eyesPlugin(
|
||||
});
|
||||
// copy any needed variables from process.env to config.env
|
||||
config.env.useAppli = process.env.USE_APPLI ? true : false;
|
||||
config.env.useArgos = !!process.env.CI && !!process.env.ARGOS_TOKEN;
|
||||
// only use Argos on CI in the mermaid-js/mermaid repository
|
||||
config.env.useArgos =
|
||||
!!process.env.CI &&
|
||||
process.env.GITHUB_REPOSITORY === 'mermaid-js/mermaid' &&
|
||||
!!process.env.ARGOS_TOKEN;
|
||||
|
||||
if (config.env.useArgos) {
|
||||
registerArgosTask(on, config, {
|
||||
|
||||
@@ -460,7 +460,7 @@ stateDiagram-v2
|
||||
[*] --> State1
|
||||
State1 --> [*]
|
||||
`,
|
||||
{ state: { useMaxWidth: true } }
|
||||
{ state: { useMaxWidth: true }, look: 'classic' }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
@@ -482,7 +482,7 @@ stateDiagram-v2
|
||||
[*] --> State1
|
||||
State1 --> [*]
|
||||
`,
|
||||
{ state: { useMaxWidth: false } }
|
||||
{ state: { useMaxWidth: false }, look: 'classic' }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
// const height = parseFloat(svg.attr('height'));
|
||||
|
||||
@@ -338,7 +338,7 @@ describe('State diagram', () => {
|
||||
[*] --> State1
|
||||
State1 --> [*]
|
||||
`,
|
||||
{ state: { useMaxWidth: true } }
|
||||
{ state: { useMaxWidth: true }, look: 'classic', theme: 'default' }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
@@ -361,7 +361,7 @@ describe('State diagram', () => {
|
||||
[*] --> State1
|
||||
State1 --> [*]
|
||||
`,
|
||||
{ state: { useMaxWidth: false } }
|
||||
{ state: { useMaxWidth: false }, look: 'classic', theme: 'default' }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
// const height = parseFloat(svg.attr('height'));
|
||||
|
||||
221
cypress/platform/ash.html
Normal file
221
cypress/platform/ash.html
Normal file
@@ -0,0 +1,221 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background: #333; */
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
|
||||
/* background-color: #efefef;
|
||||
background-image: radial-gradient(#fff 51%, transparent 91%),
|
||||
radial-gradient(#fff 51%, transparent 91%);
|
||||
background-size: 20px 20px;
|
||||
background-position:
|
||||
0 0,
|
||||
10px 10px;
|
||||
background-repeat: repeat; */
|
||||
}
|
||||
|
||||
.malware {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 150px;
|
||||
background: red;
|
||||
color: black;
|
||||
display: flex;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
|
||||
/* tspan {
|
||||
font-size: 6px !important;
|
||||
} */
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart
|
||||
node
|
||||
rounded(rounded)
|
||||
id1([This is the text in the box])
|
||||
id2((circle))
|
||||
id3(((double circle)))
|
||||
id4>Asymetrical]
|
||||
id5{This is the text in the box}
|
||||
id6{{This is the text in the box}}
|
||||
id7[/This is the text in the box/]
|
||||
id8[\This is the text in the box\]
|
||||
A[/Christmas\]
|
||||
B[\Christmas/]
|
||||
sub[[subroutine]]
|
||||
db[(Database)]
|
||||
|
||||
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: default
|
||||
look: classic
|
||||
---
|
||||
flowchart
|
||||
node
|
||||
rounded(rounded)
|
||||
id1([This is the text in the box])
|
||||
id2((circle))
|
||||
id3(((double circle)))
|
||||
id4>Asymetrical]
|
||||
id5{This is the text in the box}
|
||||
id6{{This is the text in the box}}
|
||||
id7[/This is the text in the box/]
|
||||
id8[\This is the text in the box\]
|
||||
B[/Christmas\]
|
||||
sub[[subroutine]]
|
||||
db[(Database)]
|
||||
|
||||
|
||||
|
||||
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid">
|
||||
stateDiagram
|
||||
[*] --> Active
|
||||
Active --> Inactive
|
||||
Inactive --> Active
|
||||
Active --> [*]
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart
|
||||
a_a(Aftonbladet) --> b_b[gorilla]:::apa --> c_c{chimp}:::apa -->a_a
|
||||
a_a --> c --> d_d --> c_c
|
||||
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
|
||||
class a_a apa;
|
||||
click a_a "http://www.aftonbladet.se" "bookmark"
|
||||
click c_c callback "new tooltip"
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram2" class="mermaid2">
|
||||
flowchart LR
|
||||
id1(Start)-->id2(Stop)
|
||||
style id1 fill:#f9f,stroke:#333,stroke-width:4px
|
||||
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
|
||||
|
||||
|
||||
</pre>
|
||||
|
||||
<pre id="diagram3" class="mermaid2">
|
||||
flowchart LR
|
||||
A:::foo & B:::bar --> C:::foobar
|
||||
classDef foo stroke:#f00
|
||||
classDef bar stroke:#0f0
|
||||
classDef ash color:red
|
||||
class C ash
|
||||
style C stroke:#00f, fill:black
|
||||
|
||||
</pre>
|
||||
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
stateDiagram
|
||||
A:::foo
|
||||
B:::bar --> C:::foobar
|
||||
classDef foo stroke:#f00
|
||||
classDef bar stroke:#0f0
|
||||
style C stroke:#00f, fill:black, color:white
|
||||
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
window.callback = function () {
|
||||
alert('A callback was triggered');
|
||||
};
|
||||
mermaid.initialize({
|
||||
theme: 'neo',
|
||||
look: 'neo',
|
||||
// handdrawnSeed: 12,
|
||||
// look: 'handdrawn',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
// layout: 'dagre',
|
||||
// layout: 'elk',
|
||||
// layout: 'fixed',
|
||||
// htmlLabels: false,
|
||||
flowchart: { titleTopMargin: 10 },
|
||||
// fontFamily: 'Caveat',
|
||||
// fontFamily: 'Kalam',
|
||||
// fontFamily: 'courier',
|
||||
fontFamily: 'arial',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
fontSize: 12,
|
||||
logLevel: 0,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
164
cypress/platform/knsv-dark.html
Normal file
164
cypress/platform/knsv-dark.html
Normal file
@@ -0,0 +1,164 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
background: #333;
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
|
||||
/* background-color: #efefef;
|
||||
background-image: radial-gradient(#fff 51%, transparent 91%),
|
||||
radial-gradient(#fff 51%, transparent 91%);
|
||||
background-size: 20px 20px;
|
||||
background-position:
|
||||
0 0,
|
||||
10px 10px;
|
||||
background-repeat: repeat; */
|
||||
}
|
||||
|
||||
.malware {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 150px;
|
||||
background: red;
|
||||
color: black;
|
||||
display: flex;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
|
||||
/* tspan {
|
||||
font-size: 6px !important;
|
||||
} */
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart
|
||||
A --> B & C
|
||||
subgraph apa
|
||||
D --> E
|
||||
end
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram2" class="mermaid2">
|
||||
flowchart LR
|
||||
id1(Start)-->id2(Stop)
|
||||
style id1 fill:#f9f,stroke:#333,stroke-width:4px
|
||||
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
|
||||
|
||||
|
||||
</pre>
|
||||
|
||||
<pre id="diagram3" class="mermaid2">
|
||||
flowchart LR
|
||||
A:::foo & B:::bar --> C:::foobar
|
||||
classDef foo stroke:#f00
|
||||
classDef bar stroke:#0f0
|
||||
classDef ash color:red
|
||||
class C ash
|
||||
style C stroke:#00f, fill:black
|
||||
|
||||
</pre>
|
||||
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
stateDiagram
|
||||
A:::foo
|
||||
B:::bar --> C:::foobar
|
||||
classDef foo stroke:#f00
|
||||
classDef bar stroke:#0f0
|
||||
style C stroke:#00f, fill:black, color:white
|
||||
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
window.callback = function () {
|
||||
alert('A callback was triggered');
|
||||
};
|
||||
mermaid.initialize({
|
||||
theme: 'neo-dark',
|
||||
// handdrawnSeed: 12,
|
||||
look: 'neo',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
// layout: 'dagre',
|
||||
// layout: 'elk',
|
||||
// layout: 'fixed',
|
||||
// htmlLabels: false,
|
||||
flowchart: { titleTopMargin: 10 },
|
||||
// fontFamily: 'Caveat',
|
||||
// fontFamily: 'Kalam',
|
||||
// fontFamily: 'courier',
|
||||
fontFamily: 'arial',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
fontSize: 12,
|
||||
logLevel: 0,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
206
cypress/platform/knsv-pos.html
Normal file
206
cypress/platform/knsv-pos.html
Normal file
@@ -0,0 +1,206 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background: #333; */
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
|
||||
/* background-color: #efefef;
|
||||
background-image: radial-gradient(#fff 51%, transparent 91%),
|
||||
radial-gradient(#fff 51%, transparent 91%);
|
||||
background-size: 20px 20px;
|
||||
background-position:
|
||||
0 0,
|
||||
10px 10px;
|
||||
background-repeat: repeat; */
|
||||
}
|
||||
|
||||
.malware {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 150px;
|
||||
background: red;
|
||||
color: black;
|
||||
display: flex;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
|
||||
/* tspan {
|
||||
font-size: 6px !important;
|
||||
} */
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<pre id="diagram" class="mermaid"></pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
// look: 'handdrawn',
|
||||
// layout: 'elk',
|
||||
fontFamily: 'Kalam',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
flowchart: {
|
||||
// curve: 'cardinal',
|
||||
// edgeDebug: true,
|
||||
},
|
||||
logLevel: 0,
|
||||
});
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
let code = `---
|
||||
config:
|
||||
state:
|
||||
curve: line
|
||||
---
|
||||
stateDiagram
|
||||
S:S
|
||||
T:T
|
||||
U:U
|
||||
state Z {
|
||||
state X {
|
||||
Y:Ypsilon
|
||||
}
|
||||
}
|
||||
A
|
||||
|
||||
S --> T: angrepp
|
||||
T --> U
|
||||
T --> V
|
||||
C
|
||||
D
|
||||
E
|
||||
|
||||
`;
|
||||
code = `
|
||||
flowchart TB
|
||||
n3["Untitled Node"] --> n5["Untitled Node"] & n6["Untitled Node"] & n7["Untitled Node"] & n8["Untitled Node"] & n9["Untitled Node"]
|
||||
`;
|
||||
|
||||
let positions = {
|
||||
nodes: {
|
||||
S: { x: 0, y: 0 },
|
||||
T: { x: 100, y: 100, width: 100, height: 100 },
|
||||
U: { x: 250, y: 260 },
|
||||
V: { x: 300, y: 120 },
|
||||
Z: { x: 300, y: 10, width: 160, height: 100 },
|
||||
X: { x: 300, y: 20, width: 80, height: 60 },
|
||||
Y: { x: 300, y: 30, width: 50, height: 20 },
|
||||
A: { x: 300, y: 75, width: 20, height: 20 },
|
||||
},
|
||||
edges: {
|
||||
edge0: {
|
||||
points: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 50, y: 0 },
|
||||
{ x: 100, y: 100 },
|
||||
],
|
||||
},
|
||||
edge1: {
|
||||
// points: [
|
||||
// { x: 100, y: 100 },
|
||||
// { x: 200, y: 200 },
|
||||
// ],
|
||||
points: [
|
||||
{ x: 100, y: 100 },
|
||||
{ x: 150, y: 120 },
|
||||
{ x: 190.19453144073486, y: 120 },
|
||||
{ x: 190.19453144073486, y: 152.1556251525879 },
|
||||
{ x: 250, y: 152.1556251525879 },
|
||||
{ x: 250, y: 160 },
|
||||
],
|
||||
},
|
||||
edge2: {
|
||||
points: [
|
||||
{ x: 100, y: 100 },
|
||||
{ x: 175, y: 80 },
|
||||
{ x: 200, y: 120 },
|
||||
{ x: 300, y: 100 },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
positions = JSON.parse(
|
||||
'{"nodes":{"n3":{"x":360.885009765625,"y":7.677405834197998,"width":120.59375,"height":45.00000762939453},"n5":{"x":546.1309814453125,"y":190.24496459960938,"width":120.59375,"height":45},"n6":{"x":694.6719360351562,"y":167.00001525878906,"width":120.59375,"height":45},"n7":{"x":72.29684925079346,"y":167.00001525878906,"width":120.59370994567871,"height":45},"n8":{"x":250.27700805664062,"y":183.1090545654297,"width":120.59375,"height":45},"n9":{"x":393.2580871582031,"y":197.45834350585938,"width":120.59375,"height":45}},"edges":{"L_n3_n5_0":{"points":[{"x":383.71510673157036,"y":30.177409648895264},{"x":383.71510673157036,"y":98.96118712425232},{"x":523.300888350029,"y":98.96118712425232},{"x":523.300888350029,"y":167.74496459960938}],"start":"n3","end":"n5"},"L_n3_n6_1":{"points":[{"x":408.02337350122014,"y":30.177409648895264},{"x":408.02337350122014,"y":87.33871245384216},{"x":647.533580291497,"y":87.33871245384216},{"x":647.533580291497,"y":144.50001525878906}],"start":"n3","end":"n6"},"L_n3_n7_2":{"points":[{"x":320.12974762228504,"y":30.177409648895264},{"x":270.12974762228504,"y":87.33871245384216},{"x":113.05210448440184,"y":87.33871245384216},{"x":113.05210448440184,"y":144.50001525878906}],"start":"n3","end":"n7"},"L_n3_n8_3":{"points":[{"x":346.6989693425486,"y":30.177409648895264},{"x":346.6989693425486,"y":95.39323210716248},{"x":264.4630460745863,"y":95.39323210716248},{"x":264.4630460745863,"y":160.6090545654297}],"start":"n3","end":"n8"},"L_n3_n9_4":{"points":[{"x":364.7230894682698,"y":30.177409648895264},{"x":364.7230894682698,"y":102.56787657737732},{"x":389.42000810627434,"y":102.56787657737732},{"x":389.42000810627434,"y":174.95834350585938}],"start":"n3","end":"n9"}}}'
|
||||
);
|
||||
|
||||
// console.log('positions:', positions);
|
||||
const { svg } = await mermaid.render('the-id-of-the-svg', code, undefined, positions);
|
||||
// if (window?.calcIntersections2) {
|
||||
// const int = await calcIntersections2(
|
||||
// { id: 'a', shape: 'rect', x: 100, y: 100, width: 100, height: 100 },
|
||||
// { id: 'a', shape: 'rect', x: 300, y: 100, width: 100, height: 100 }
|
||||
// );
|
||||
// console.log('Intersections', int);
|
||||
// } else {
|
||||
// console.error('calcIntersections not found');
|
||||
// }
|
||||
// console.log(JSON.stringify(positions));
|
||||
const elem = document.querySelector('#diagram');
|
||||
elem.innerHTML = svg;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
272
cypress/platform/knsv-recursive.html
Normal file
272
cypress/platform/knsv-recursive.html
Normal file
@@ -0,0 +1,272 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Recursive:wght@300..1000&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
.recursive-500 {
|
||||
font-family: 'Recursive', serif;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-variation-settings:
|
||||
'slnt' 0,
|
||||
'CASL' 0,
|
||||
'CRSV' 0.5,
|
||||
'MONO' 0;
|
||||
}
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background: #333; */
|
||||
/* font-family: 'Arial'; */
|
||||
font-family: 'Recursive', serif;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-variation-settings:
|
||||
'slnt' 0,
|
||||
'CASL' 0,
|
||||
'CRSV' 0.5,
|
||||
'MONO' 0;
|
||||
/* color: white; */
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
.gridify.tiny {
|
||||
background-image: linear-gradient(
|
||||
transparent 11px,
|
||||
rgba(220, 220, 200, 0.8) 12px,
|
||||
transparent 12px
|
||||
),
|
||||
linear-gradient(90deg, transparent 11px, rgba(220, 220, 200, 0.8) 12px, transparent 12px);
|
||||
background-size:
|
||||
100% 12px,
|
||||
12px 100%;
|
||||
}
|
||||
|
||||
.gridify.dots {
|
||||
background-image: radial-gradient(
|
||||
circle at center,
|
||||
rgba(220, 220, 200, 0.8) 1px,
|
||||
transparent 1px
|
||||
);
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mermaid svg {
|
||||
font-size: 16px !important;
|
||||
font-family: 'Recursive', serif;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-variation-settings:
|
||||
'slnt' 0,
|
||||
'CASL' 0,
|
||||
'CRSV' 0.5,
|
||||
'MONO' 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
width: 100%;
|
||||
/*box-shadow: 4px 4px 0px 0px #0000000F;*/
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="gridify dots">
|
||||
<p class="mb-20">Test Diagram</p>
|
||||
<div class="w-full h-64">
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: neo
|
||||
layout: dagre
|
||||
---
|
||||
flowchart TD
|
||||
A{"Diamond"} --- n1["Rectangle"] & n2["Rounded"] & n3(["Stadium"])
|
||||
n1 --x n4["Rounded"]
|
||||
n2 --o n5["Hexagon"]
|
||||
n3 --> n6["Parallelogram"]
|
||||
n5 o--o n7["Trapezoid"]
|
||||
n4 x--x n8["Lean Right"]
|
||||
n6 <--> n9(("Circle"))
|
||||
n8 --> n10["Rose"]
|
||||
n7 --> n11["Pine"]
|
||||
n9 --> n12["Peach"]
|
||||
n2@{ shape: rounded}
|
||||
n4@{ shape: rounded}
|
||||
n5@{ shape: hex}
|
||||
n6@{ shape: lean-l}
|
||||
n7@{ shape: trap-b}
|
||||
n8@{ shape: lean-r}
|
||||
|
||||
n10:::Rose
|
||||
n11:::Pine
|
||||
n12:::Peach
|
||||
classDef Rose stroke-width:1px, stroke-dasharray:none, stroke:#FF5978, fill:#FFDFE5, color:#8E2236
|
||||
classDef Pine stroke-width:1px, stroke-dasharray:none, stroke:#254336, fill:#27654A, color:#FFFFFF
|
||||
classDef Peach stroke-width:1px, stroke-dasharray:none, stroke:#FBB35A, fill:#FFEFDB, color:#8F632D
|
||||
n10 --x End
|
||||
n11 --x End
|
||||
n12 --x End
|
||||
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
look: classic
|
||||
theme: forest
|
||||
layout: dagre
|
||||
---
|
||||
flowchart TD
|
||||
A{"Diamond"} --- n1["Rectangle"] & n2["Rounded"] & n3(["Stadium"])
|
||||
n1 --x n4["Rounded"]
|
||||
n2 --o n5["Hexagon"]
|
||||
n3 --> n6["Parallelogram"]
|
||||
n5 o--o n7["Trapezoid"]
|
||||
n4 x--x n8["Lean Right"]
|
||||
n6 <--> n9(("Circle"))
|
||||
n8 --> n10["Rose"]
|
||||
n7 --> n11["Pine"]
|
||||
n9 --> n12["Peach"]
|
||||
n2@{ shape: rounded}
|
||||
n4@{ shape: rounded}
|
||||
n5@{ shape: hex}
|
||||
n6@{ shape: lean-l}
|
||||
n7@{ shape: trap-b}
|
||||
n8@{ shape: lean-r}
|
||||
|
||||
n10:::Rose
|
||||
n11:::Pine
|
||||
n12:::Peach
|
||||
classDef Rose stroke-width:1px, stroke-dasharray:none, stroke:#FF5978, fill:#FFDFE5, color:#8E2236
|
||||
classDef Pine stroke-width:1px, stroke-dasharray:none, stroke:#254336, fill:#27654A, color:#FFFFFF
|
||||
classDef Peach stroke-width:1px, stroke-dasharray:none, stroke:#FBB35A, fill:#FFEFDB, color:#8F632D
|
||||
n10 --x End
|
||||
n11 --x End
|
||||
n12 --x End
|
||||
|
||||
</pre
|
||||
>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
|
||||
const staticBellIconPack = {
|
||||
prefix: 'fa6-regular',
|
||||
icons: {
|
||||
bell: {
|
||||
body: '<path fill="currentColor" d="M224 0c-17.7 0-32 14.3-32 32v19.2C119 66 64 130.6 64 208v25.4c0 45.4-15.5 89.5-43.8 124.9L5.3 377c-5.8 7.2-6.9 17.1-2.9 25.4S14.8 416 24 416h400c9.2 0 17.6-5.3 21.6-13.6s2.9-18.2-2.9-25.4l-14.9-18.6c-28.3-35.5-43.8-79.6-43.8-125V208c0-77.4-55-142-128-156.8V32c0-17.7-14.3-32-32-32m0 96c61.9 0 112 50.1 112 112v25.4c0 47.9 13.9 94.6 39.7 134.6H72.3c25.8-40 39.7-86.7 39.7-134.6V208c0-61.9 50.1-112 112-112m64 352H160c0 17 6.7 33.3 18.7 45.3S207 512 224 512s33.3-6.7 45.3-18.7S288 465 288 448"/>',
|
||||
width: 448,
|
||||
},
|
||||
},
|
||||
width: 512,
|
||||
height: 512,
|
||||
};
|
||||
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/logos@1/icons.json').then((res) => res.json()),
|
||||
},
|
||||
{
|
||||
name: 'fa',
|
||||
loader: () => staticBellIconPack,
|
||||
},
|
||||
]);
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
window.callback = function () {
|
||||
alert('A callback was triggered');
|
||||
};
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
await mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: 'redux',
|
||||
// theme: 'default',
|
||||
// theme: 'forest',
|
||||
// handDrawnSeed: 12,
|
||||
look: 'neo',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
// layout: 'dagre',
|
||||
// layout: 'elk',
|
||||
// layout: 'fixed',
|
||||
// htmlLabels: false,
|
||||
flowchart: { titleTopMargin: 10 },
|
||||
|
||||
// fontFamily: 'Caveat',
|
||||
// fontFamily: 'Kalam',
|
||||
// fontFamily: 'courier',
|
||||
fontFamily: 'Recursive',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
kanban: {
|
||||
htmlLabels: false,
|
||||
},
|
||||
fontSize: 16,
|
||||
logLevel: 0,
|
||||
securityLevel: 'loose',
|
||||
callback,
|
||||
});
|
||||
// setTimeout(() => {
|
||||
mermaid.init(undefined, document.querySelectorAll('.mermaid'));
|
||||
// }, 1000);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
306
cypress/platform/knsv-reset.html
Normal file
306
cypress/platform/knsv-reset.html
Normal file
@@ -0,0 +1,306 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background: #333; */
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
|
||||
/* background-color: #efefef;
|
||||
background-image: radial-gradient(#fff 51%, transparent 91%),
|
||||
radial-gradient(#fff 51%, transparent 91%);
|
||||
background-size: 20px 20px;
|
||||
background-position:
|
||||
0 0,
|
||||
10px 10px;
|
||||
background-repeat: repeat; */
|
||||
}
|
||||
|
||||
.malware {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 150px;
|
||||
background: red;
|
||||
color: black;
|
||||
display: flex;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
|
||||
/* tspan {
|
||||
font-size: 6px !important;
|
||||
} */
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<pre id="diagram" class="mermaid"></pre>
|
||||
<pre id="diagram2" class="mermaid"></pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
let code = `
|
||||
stateDiagram
|
||||
S:S
|
||||
T:T
|
||||
U:U
|
||||
state Z {
|
||||
state X {
|
||||
Y:Ypsilon
|
||||
}
|
||||
}
|
||||
A
|
||||
|
||||
S --> T: angrepp
|
||||
S --> T: angrepp
|
||||
T --> U
|
||||
Y --> V
|
||||
C
|
||||
D
|
||||
E
|
||||
|
||||
`;
|
||||
code = `
|
||||
flowchart TB
|
||||
c1-->a2
|
||||
subgraph one
|
||||
a1-->a2
|
||||
end
|
||||
subgraph two
|
||||
b1-->b2
|
||||
end
|
||||
subgraph three
|
||||
c1-->c2
|
||||
end
|
||||
|
||||
`;
|
||||
// code = `
|
||||
// flowchart BT
|
||||
// A
|
||||
// subgraph one
|
||||
// a1 --> a2
|
||||
// end
|
||||
// subgraph two
|
||||
// a3
|
||||
// end
|
||||
|
||||
// `;
|
||||
// code = `
|
||||
// flowchart TB
|
||||
// subgraph one
|
||||
// a1-->a2
|
||||
// end`;
|
||||
// let positions = JSON.parse(
|
||||
// '{"nodes":{"S":{"x":30.78125,"y":43.5},"Y":{"x":127.94140625,"y":50}},"edges":{}}'
|
||||
// );
|
||||
|
||||
function exctractPositions(svg) {
|
||||
const positions = { nodes: {}, edges: {} };
|
||||
|
||||
// Extract the viewbox paddings - TOSDO: update in collab
|
||||
const viewBox = svg.getAttribute('viewBox').split(' ');
|
||||
const viewBoxX = parseFloat(viewBox[0]);
|
||||
const viewBoxY = parseFloat(viewBox[1]);
|
||||
// console.log('viewBox:', viewBoxX, viewBoxY);
|
||||
svg.querySelectorAll('[data-et="node"]').forEach((node) => {
|
||||
if (node.tagName === 'g') {
|
||||
// console.log('node:', node);
|
||||
const id = node.dataset.id;
|
||||
const bbox = node.getBBox();
|
||||
const transform = node.getAttribute('transform');
|
||||
const x = parseFloat(transform.split(',')[0].split('(')[1]);
|
||||
const y = parseFloat(transform.split(',')[1].split(')')[0]);
|
||||
|
||||
// Get the bounding rectangle of the element
|
||||
const rect = node.getBoundingClientRect();
|
||||
|
||||
// Get the absolute position relative to the document
|
||||
const absoluteX = rect.left + window.pageXOffset + viewBoxX;
|
||||
const absoluteY = rect.top + window.pageYOffset + viewBoxY;
|
||||
|
||||
positions.nodes[id] = {
|
||||
x: absoluteX + rect.width / 2,
|
||||
y: absoluteY + rect.height / 2,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
};
|
||||
}
|
||||
});
|
||||
svg.querySelectorAll('[data-et="cluster"]').forEach((node) => {
|
||||
// console.log('cluster:', node);
|
||||
if (node.tagName === 'g') {
|
||||
const id = node.dataset.id;
|
||||
// console.log('cluster:', node);
|
||||
|
||||
const transform = node.getAttribute('transform');
|
||||
const rect = node.getBoundingClientRect();
|
||||
|
||||
// Get the absolute position relative to the document
|
||||
const absoluteX = rect.left + window.pageXOffset + viewBoxX;
|
||||
const absoluteY = rect.top + window.pageYOffset + viewBoxY;
|
||||
|
||||
positions.nodes[id] = {
|
||||
x: absoluteX + rect.width / 2,
|
||||
y: absoluteY + rect.height / 2,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
};
|
||||
}
|
||||
});
|
||||
svg.querySelectorAll('[data-et="edge"]').forEach((edge) => {
|
||||
// if (node.tagName === 'g') {
|
||||
const path = edge.getBoundingClientRect();
|
||||
|
||||
// Get the absolute position relative to the document
|
||||
const absoluteX = path.left + window.pageXOffset + viewBoxX;
|
||||
const absoluteY = path.top + window.pageYOffset + viewBoxY;
|
||||
console.log(
|
||||
'absoluteX:',
|
||||
absoluteX,
|
||||
'absoluteY:',
|
||||
absoluteY,
|
||||
'offset',
|
||||
window.pageXOffset
|
||||
);
|
||||
const id = edge.dataset.id;
|
||||
const points = JSON.parse(atob(edge.dataset.points));
|
||||
console.log('edge:', points, absoluteX, absoluteY);
|
||||
let minX = 10000;
|
||||
let minY = 10000;
|
||||
points.forEach((point) => {
|
||||
if (point.x < minX) {
|
||||
minX = point.x;
|
||||
}
|
||||
if (point.y < minY) {
|
||||
minY = point.y;
|
||||
}
|
||||
});
|
||||
let dx = absoluteX - minX;
|
||||
let dy = absoluteY - minY;
|
||||
if (dx < 1) {
|
||||
dx = 0;
|
||||
}
|
||||
if (dy < 1) {
|
||||
dy = 0;
|
||||
}
|
||||
positions.edges[id] = {
|
||||
points: points.map((point) => {
|
||||
console.log('point:', point.y, absoluteY);
|
||||
return {
|
||||
x: point.x + dx,
|
||||
y: point.y + dy,
|
||||
};
|
||||
}),
|
||||
};
|
||||
// }
|
||||
});
|
||||
return positions;
|
||||
}
|
||||
|
||||
const mode = 'reset';
|
||||
if (mode === 'reset') {
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
layout: 'elk',
|
||||
fontFamily: 'Kalam',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
logLevel: 5,
|
||||
});
|
||||
const { svg } = await mermaid.render('the-id-of-the-svg', code);
|
||||
const elem = document.querySelector('#diagram');
|
||||
elem.innerHTML = svg;
|
||||
elem.classList.remove('mermaid');
|
||||
const positions = exctractPositions(elem.firstChild);
|
||||
// console.log('Positions:', JSON.stringify(positions));
|
||||
const { svg: svg2 } = await mermaid.render(
|
||||
'the-id-of-the-svg2',
|
||||
'---\n config:\n layout: fixed\n---' + code,
|
||||
undefined,
|
||||
positions
|
||||
);
|
||||
// console.log('svg2', svg2);
|
||||
const elem2 = document.querySelector('#diagram2');
|
||||
elem2.innerHTML = svg2;
|
||||
} else {
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
// look: 'handdrawn',
|
||||
layout: 'fixed',
|
||||
fontFamily: 'Kalam',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
logLevel: 0,
|
||||
});
|
||||
const { svg } = await mermaid.render('the-id-of-the-svg', code, undefined, positions);
|
||||
|
||||
// console.log(JSON.stringify(positions));
|
||||
const elem = document.querySelector('#diagram');
|
||||
elem.innerHTML = svg;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -78,77 +78,86 @@
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
|
||||
pre {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* tspan {
|
||||
font-size: 6px !important;
|
||||
} */
|
||||
/* .flowchart-link {
|
||||
stroke-dasharray: 4, 4 !important;
|
||||
animation: flow 1s linear infinite;
|
||||
animation: dashdraw 4.93282s linear infinite;
|
||||
stroke-width: 2px !important;
|
||||
} */
|
||||
|
||||
@keyframes dashdraw {
|
||||
from {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*stroke-width:2;stroke-dasharray:10.000000,9.865639;stroke-dashoffset:-198.656393;animation: 4.932820s linear infinite;*/
|
||||
/* stroke-width:2;stroke-dasharray:10.000000,9.865639;stroke-dashoffset:-198.656393;animation: dashdraw 4.932820s linear infinite;*/
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
flowchart LR
|
||||
AB["apa@apa@"] --> B(("`apa@apa`"))
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
flowchart
|
||||
D(("for D"))
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
flowchart LR
|
||||
A e1@==> B
|
||||
e1@{ animate: true}
|
||||
---
|
||||
config:
|
||||
look: classic
|
||||
theme: forest
|
||||
layout: dagre
|
||||
---
|
||||
flowchart LR
|
||||
A["A"] --> C
|
||||
B("B B B B B") --> C[/"C C C C C"/]
|
||||
C@{ shape: circle }
|
||||
%%C@{ shape: question }
|
||||
C@{ shape: stadium }
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
look: classic
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
A e1@--> B
|
||||
classDef animate stroke-width:2,stroke-dasharray:10\,8,stroke-dashoffset:-180,animation: edge-animation-frame 6s linear infinite, stroke-linecap: round
|
||||
class e1 animate
|
||||
n1["n1"] --- C
|
||||
B("Continue") --> C[/"Evaluate"/]
|
||||
C -- One --> D["Option 1"]
|
||||
C -- Two --> E["Option 2"]
|
||||
C -- Three --> F["fa:fa-car Option 3"]
|
||||
C@{ shape: db }
|
||||
</pre>
|
||||
<h2>infinite</h2>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
A e1@--> B
|
||||
classDef animate stroke-dasharray: 9\,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
|
||||
class e1 animate
|
||||
</pre>
|
||||
<h2>Mermaid - edge-animation-slow</h2>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
A e1@--> B
|
||||
e1@{ animation: fast}
|
||||
</pre>
|
||||
<h2>Mermaid - edge-animation-fast</h2>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
A e1@--> B
|
||||
classDef animate stroke-dasharray: 1000,stroke-dashoffset: 1000,animation: dash 10s linear;
|
||||
class e1 edge-animation-fast
|
||||
</pre>
|
||||
%% subgraph s1["Untitled subgraph"]
|
||||
C{"Evaluate"}
|
||||
%% end
|
||||
|
||||
B --> C
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
---
|
||||
config:
|
||||
look: neo
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
%% A ==> B
|
||||
%% A2 --> B2
|
||||
D --> I((I the Circle))
|
||||
D --> I
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
subgraph S2
|
||||
subgraph s1["APA"]
|
||||
D{"Use the editor"}
|
||||
end
|
||||
|
||||
info </pre
|
||||
>
|
||||
|
||||
D -- Mermaid js --> I(("fa:fa-code Text"))
|
||||
D --> I
|
||||
D --> E --> I
|
||||
|
||||
end
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
---
|
||||
config:
|
||||
@@ -434,13 +443,10 @@ kanban
|
||||
window.callback = function () {
|
||||
alert('A callback was triggered');
|
||||
};
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
await mermaid.initialize({
|
||||
mermaid.initialize({
|
||||
// theme: 'base',
|
||||
// theme: 'default',
|
||||
// theme: 'forest',
|
||||
theme: 'forest',
|
||||
// handDrawnSeed: 12,
|
||||
// look: 'handDrawn',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
@@ -448,12 +454,10 @@ kanban
|
||||
// layout: 'elk',
|
||||
// layout: 'fixed',
|
||||
// htmlLabels: false,
|
||||
flowchart: { titleTopMargin: 10 },
|
||||
|
||||
flowchart: { titleTopMargin: 10, useMaxWidth: false },
|
||||
// fontFamily: 'Caveat',
|
||||
// fontFamily: 'Kalam',
|
||||
// fontFamily: 'courier',
|
||||
fontFamily: 'arial',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
@@ -465,9 +469,10 @@ kanban
|
||||
fontSize: 12,
|
||||
logLevel: 0,
|
||||
securityLevel: 'loose',
|
||||
callback,
|
||||
});
|
||||
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
|
||||
@@ -1,103 +1,173 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Mindmap Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
div.mermaid {
|
||||
/* font-family: 'trebuchet ms', verdana, arial; */
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background: #333; */
|
||||
font-family: 'Arial';
|
||||
/* color: white; */
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
|
||||
/* background-color: #efefef;
|
||||
background-image: radial-gradient(#fff 51%, transparent 91%),
|
||||
radial-gradient(#fff 51%, transparent 91%);
|
||||
background-size: 20px 20px;
|
||||
background-position:
|
||||
0 0,
|
||||
10px 10px;
|
||||
background-repeat: repeat; */
|
||||
}
|
||||
|
||||
.malware {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 150px;
|
||||
background: red;
|
||||
color: black;
|
||||
display: flex;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
pre {
|
||||
width: 100%;
|
||||
}
|
||||
/* tspan {
|
||||
font-size: 6px !important;
|
||||
} */
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Mindmap diagram demo</h1>
|
||||
<pre class="mermaid">
|
||||
mindmap
|
||||
root
|
||||
child1((Circle))
|
||||
grandchild 1
|
||||
grandchild 2
|
||||
child2(Round rectangle)
|
||||
grandchild 3
|
||||
grandchild 4
|
||||
child3[Square]
|
||||
grandchild 5
|
||||
::icon(mdi mdi-fire)
|
||||
gc6((grand<br/>child 6))
|
||||
::icon(mdi mdi-fire)
|
||||
gc7((grand<br/>grand<br/>child 8))
|
||||
</pre>
|
||||
|
||||
<h2>Mindmap with root wrapping text and a shape</h2>
|
||||
<pre class="mermaid">
|
||||
mindmap
|
||||
root[A root with a long text that wraps to keep the node size in check]
|
||||
</pre>
|
||||
|
||||
<div class="flex gap-4">
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
look: classic
|
||||
theme: forest
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
n1["n1"] --> C
|
||||
n2("n2") --> C
|
||||
C@{ shape: circle }
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
look: neo
|
||||
theme: redux
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
n1["n1"] --> C
|
||||
n2("n2") --> C
|
||||
C@{ shape: circle }
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
look: handDrawn
|
||||
theme: forest
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
n1["n1"] --> C
|
||||
n2("n2") --> C
|
||||
C@{ shape: circle }
|
||||
</pre
|
||||
>
|
||||
</div>
|
||||
<script type="module">
|
||||
// import mermaid from './mermaid.esm.mjs';
|
||||
import mermaid from '../../packages/mermaid/dist/mermaid.esm.mjs';
|
||||
// import mermaidMindmap from './mermaid-mindmap.esm.mjs';
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
|
||||
// import mermaidMindmap from 'https://cdn.jsdelivr.net/npm/@mermaid-js/mermaid-mindmap@9.3.0/+esm';
|
||||
// await mermaid.registerExternalDiagrams([mermaidMindmap]);
|
||||
const staticBellIconPack = {
|
||||
prefix: 'fa6-regular',
|
||||
icons: {
|
||||
bell: {
|
||||
body: '<path fill="currentColor" d="M224 0c-17.7 0-32 14.3-32 32v19.2C119 66 64 130.6 64 208v25.4c0 45.4-15.5 89.5-43.8 124.9L5.3 377c-5.8 7.2-6.9 17.1-2.9 25.4S14.8 416 24 416h400c9.2 0 17.6-5.3 21.6-13.6s2.9-18.2-2.9-25.4l-14.9-18.6c-28.3-35.5-43.8-79.6-43.8-125V208c0-77.4-55-142-128-156.8V32c0-17.7-14.3-32-32-32m0 96c61.9 0 112 50.1 112 112v25.4c0 47.9 13.9 94.6 39.7 134.6H72.3c25.8-40 39.7-86.7 39.7-134.6V208c0-61.9 50.1-112 112-112m64 352H160c0 17 6.7 33.3 18.7 45.3S207 512 224 512s33.3-6.7 45.3-18.7S288 465 288 448"/>',
|
||||
width: 448,
|
||||
},
|
||||
},
|
||||
width: 512,
|
||||
height: 512,
|
||||
};
|
||||
|
||||
const ALLOWED_TAGS = [
|
||||
'a',
|
||||
'b',
|
||||
'blockquote',
|
||||
'br',
|
||||
'dd',
|
||||
'div',
|
||||
'dl',
|
||||
'dt',
|
||||
'em',
|
||||
'foreignObject',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'h7',
|
||||
'h8',
|
||||
'hr',
|
||||
'i',
|
||||
'li',
|
||||
'ul',
|
||||
'ol',
|
||||
'p',
|
||||
'pre',
|
||||
'span',
|
||||
'strike',
|
||||
'strong',
|
||||
'table',
|
||||
'tbody',
|
||||
'td',
|
||||
'tfoot',
|
||||
'th',
|
||||
'thead',
|
||||
'tr',
|
||||
];
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/logos@1/icons.json').then((res) => res.json()),
|
||||
},
|
||||
{
|
||||
name: 'fa',
|
||||
loader: () => staticBellIconPack,
|
||||
},
|
||||
]);
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
window.callback = function () {
|
||||
alert('A callback was triggered');
|
||||
};
|
||||
mermaid.initialize({
|
||||
theme: 'base',
|
||||
startOnLoad: true,
|
||||
flowchart: { titleTopMargin: 10, useMaxWidth: false },
|
||||
fontSize: 12,
|
||||
logLevel: 0,
|
||||
flowchart: {
|
||||
useMaxWidth: false,
|
||||
htmlLabels: true,
|
||||
},
|
||||
gantt: {
|
||||
useMaxWidth: false,
|
||||
},
|
||||
useMaxWidth: false,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
|
||||
171
cypress/platform/min-size-tester.html
Normal file
171
cypress/platform/min-size-tester.html
Normal file
@@ -0,0 +1,171 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial';
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="flex w-full">
|
||||
<div id="diagram-fixed"></div>
|
||||
<div id="diagram-normal"></div>
|
||||
</div>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
//look: 'handdrawn',
|
||||
// layout: 'fixed',
|
||||
theme: 'neo-dark',
|
||||
//layout: 'elk',
|
||||
fontFamily: 'Kalam',
|
||||
logLevel: 1,
|
||||
});
|
||||
|
||||
// let shape = 'rect'; // Done
|
||||
//let shape = 'rounded'; // Done
|
||||
//let shape = 'stadium'; // Done
|
||||
// let shape = 'fr-rect'; // Done
|
||||
// let shape = 'cyl'; // Done
|
||||
//let shape = 'circle'; // Done
|
||||
// let shape = 'odd'; // Done
|
||||
// let shape = 'diam'; //Done
|
||||
// let shape = 'hex'; // Done
|
||||
// let shape = 'lean-r'; // Done
|
||||
// let shape = 'lean-l'; // Done
|
||||
// let shape = 'trap-b'; // Done
|
||||
// let shape = 'trap-t'; // Done
|
||||
// let shape = 'dbl-circ'; // Done
|
||||
// let shape = 'text'; // Done
|
||||
// let shape = 'notch-rect'; // Done
|
||||
// let shape = 'lin-rect'; // Done
|
||||
//let shape = 'sm-circ'; // Done
|
||||
// let shape = 'fr-circ'; //Done
|
||||
//let shape = 'fork'; // Done
|
||||
//let shape = 'hourglass'; //Done
|
||||
// let shape = 'bolt'; //Done
|
||||
// let shape = 'doc'; // Done
|
||||
// let shape = 'delay'; // Done
|
||||
// let shape = 'h-cyl'; // Done
|
||||
// let shape = 'lin-cyl'; // Done
|
||||
// let shape = 'curv-trap'; // Done
|
||||
// let shape = 'div-rect'; // Done
|
||||
//let shape = 'tri'; // Done
|
||||
// let shape = 'win-pane'; //Done
|
||||
// let shape = 'f-circ'; // Done
|
||||
// let shape = 'lin-doc'; // Done
|
||||
// let shape = 'notch-pent'; // Done
|
||||
// let shape = 'flip-tri'; // Done
|
||||
// let shape = 'sl-rect'; // Done
|
||||
// let shape = 'cross-circ'; // Done
|
||||
// let shape = 'bow-rect'; // Done
|
||||
// let shape = 'st-rect'; // Done
|
||||
|
||||
// let shape = 'flag';
|
||||
|
||||
// let shape = 'docs';
|
||||
// let shape = 'brace';
|
||||
// let shape = 'brace-r';
|
||||
// let shape = 'braces';
|
||||
// let shape = 'tag-doc';
|
||||
|
||||
let configFixed = `---
|
||||
config:
|
||||
layout: fixed
|
||||
---
|
||||
`;
|
||||
let code = `flowchart TB
|
||||
%% n80["APA ksldj hfaskljdh aklsjdhf klasjdhf klasjhf klsajdh klasjdhf klasjdhf klasjdh klasjhf klasjdh klajsdhfklasjdhf kljadh fklasjdhf klajsdhf lkasdhf klajsdhf klasjdhfklasjdh klasjhf klasdfh klasdfh aklsjfh akjshkasldfh klasdfh klasjh fklsjhf klasdhf kljasdhf klasdhf klj"]
|
||||
%% n80@{ shape: '${shape}'}
|
||||
n81@{ label: "Ashish", shape: '${shape}'}
|
||||
%%n82@{ label: "n82", shape: '${shape}'}
|
||||
%%n83@{ label: "n83", shape: '${shape}'}
|
||||
`;
|
||||
|
||||
let positions = {
|
||||
edges: {},
|
||||
nodes: {
|
||||
n81: {
|
||||
x: 0,
|
||||
y: 10,
|
||||
width: 107.7,
|
||||
height: 65,
|
||||
},
|
||||
n80: {
|
||||
x: -400,
|
||||
y: 10,
|
||||
width: 1,
|
||||
height: 1,
|
||||
},
|
||||
n82: {
|
||||
x: 0,
|
||||
y: 110,
|
||||
},
|
||||
n83: {
|
||||
x: 80,
|
||||
y: 10,
|
||||
},
|
||||
n84: {
|
||||
x: 1200,
|
||||
y: 10,
|
||||
width: 300,
|
||||
height: 200,
|
||||
},
|
||||
},
|
||||
};
|
||||
console.log(configFixed + code);
|
||||
const { svg } = await mermaid.render(
|
||||
'the-id-of-the-svg-1',
|
||||
configFixed + code,
|
||||
undefined,
|
||||
positions
|
||||
);
|
||||
const elem = document.querySelector('#diagram-fixed');
|
||||
elem.innerHTML = svg;
|
||||
const { svg: svg2 } = await mermaid.render('the-id-of-the-svg-2', code, undefined, positions);
|
||||
const elem2 = document.querySelector('#diagram-normal');
|
||||
elem2.innerHTML = svg2;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
2537
cypress/platform/neo-test.html
Normal file
2537
cypress/platform/neo-test.html
Normal file
File diff suppressed because it is too large
Load Diff
248
cypress/platform/omkarht-new-padding.html
Normal file
248
cypress/platform/omkarht-new-padding.html
Normal file
@@ -0,0 +1,248 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Recursive:wght@300..1000&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
.recursive-500 {
|
||||
font-family: 'Recursive', serif;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-variation-settings:
|
||||
'slnt' 0,
|
||||
'CASL' 0,
|
||||
'CRSV' 0.5,
|
||||
'MONO' 0;
|
||||
}
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background: #333; */
|
||||
/* font-family: 'Arial'; */
|
||||
font-family: 'Recursive', serif;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-variation-settings:
|
||||
'slnt' 0,
|
||||
'CASL' 0,
|
||||
'CRSV' 0.5,
|
||||
'MONO' 0;
|
||||
/* color: white; */
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
.gridify.tiny {
|
||||
background-image: linear-gradient(
|
||||
transparent 11px,
|
||||
rgba(220, 220, 200, 0.8) 12px,
|
||||
transparent 12px
|
||||
),
|
||||
linear-gradient(90deg, transparent 11px, rgba(220, 220, 200, 0.8) 12px, transparent 12px);
|
||||
background-size:
|
||||
100% 12px,
|
||||
12px 100%;
|
||||
}
|
||||
|
||||
.gridify.dots {
|
||||
background-image: radial-gradient(
|
||||
circle at center,
|
||||
rgba(220, 220, 200, 0.8) 1px,
|
||||
transparent 1px
|
||||
);
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mermaid svg {
|
||||
font-size: 16px !important;
|
||||
font-family: 'Recursive', serif;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-variation-settings:
|
||||
'slnt' 0,
|
||||
'CASL' 0,
|
||||
'CRSV' 0.5,
|
||||
'MONO' 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
width: 100%;
|
||||
/*box-shadow: 4px 4px 0px 0px #0000000F;*/
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="gridify dots">
|
||||
<p class="mb-20">Test Diagram</p>
|
||||
<div class="w-full h-64">
|
||||
<pre style="display: none">
|
||||
---
|
||||
config:
|
||||
theme: neo
|
||||
layout: dagre
|
||||
---
|
||||
flowchart TD
|
||||
A{"Cylinder"} --- n1["Rectangle"] & n2["Rounded"] & n3(["Stadium"])
|
||||
n1 --x n4["Rounded"]
|
||||
n2 --o n5["Hexagon"]
|
||||
n3 --> n6["Parallelogram"]
|
||||
n5 o--o n7["Trapezoid"]
|
||||
n4 x--x n8["Lean Right"]
|
||||
n6 <--> n9(("Circle"))
|
||||
n8 --> n10["Rose"]
|
||||
n7 --> n11["Pine"]
|
||||
n9 --> n12["Peach"]
|
||||
n2@{ shape: rounded}
|
||||
n4@{ shape: rounded}
|
||||
n5@{ shape: hex}
|
||||
n6@{ shape: lean-l}
|
||||
n7@{ shape: trap-b}
|
||||
n8@{ shape: lean-r}
|
||||
|
||||
n10:::Rose
|
||||
n11:::Pine
|
||||
n12:::Peach
|
||||
classDef Rose stroke-width:1px, stroke-dasharray:none, stroke:#FF5978, fill:#FFDFE5, color:#8E2236
|
||||
classDef Pine stroke-width:1px, stroke-dasharray:none, stroke:#254336, fill:#27654A, color:#FFFFFF
|
||||
classDef Peach stroke-width:1px, stroke-dasharray:none, stroke:#FBB35A, fill:#FFEFDB, color:#8F632D
|
||||
n10 --x End
|
||||
n11 --x End
|
||||
n12 --x End
|
||||
|
||||
</pre
|
||||
>
|
||||
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: neo
|
||||
layout: dagre
|
||||
---
|
||||
flowchart TD
|
||||
n1["Cylinder"]
|
||||
n1@{ shape: database}
|
||||
|
||||
</pre
|
||||
>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
|
||||
const staticBellIconPack = {
|
||||
prefix: 'fa6-regular',
|
||||
icons: {
|
||||
bell: {
|
||||
body: '<path fill="currentColor" d="M224 0c-17.7 0-32 14.3-32 32v19.2C119 66 64 130.6 64 208v25.4c0 45.4-15.5 89.5-43.8 124.9L5.3 377c-5.8 7.2-6.9 17.1-2.9 25.4S14.8 416 24 416h400c9.2 0 17.6-5.3 21.6-13.6s2.9-18.2-2.9-25.4l-14.9-18.6c-28.3-35.5-43.8-79.6-43.8-125V208c0-77.4-55-142-128-156.8V32c0-17.7-14.3-32-32-32m0 96c61.9 0 112 50.1 112 112v25.4c0 47.9 13.9 94.6 39.7 134.6H72.3c25.8-40 39.7-86.7 39.7-134.6V208c0-61.9 50.1-112 112-112m64 352H160c0 17 6.7 33.3 18.7 45.3S207 512 224 512s33.3-6.7 45.3-18.7S288 465 288 448"/>',
|
||||
width: 448,
|
||||
},
|
||||
},
|
||||
width: 512,
|
||||
height: 512,
|
||||
};
|
||||
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/logos@1/icons.json').then((res) => res.json()),
|
||||
},
|
||||
{
|
||||
name: 'fa',
|
||||
loader: () => staticBellIconPack,
|
||||
},
|
||||
]);
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
window.callback = function () {
|
||||
alert('A callback was triggered');
|
||||
};
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
await mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: 'redux',
|
||||
// theme: 'default',
|
||||
// theme: 'forest',
|
||||
// handDrawnSeed: 12,
|
||||
look: 'neo',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
// layout: 'dagre',
|
||||
// layout: 'elk',
|
||||
// layout: 'fixed',
|
||||
// htmlLabels: false,
|
||||
flowchart: { titleTopMargin: 10 },
|
||||
|
||||
// fontFamily: 'Caveat',
|
||||
// fontFamily: 'Kalam',
|
||||
// fontFamily: 'courier',
|
||||
fontFamily: 'Recursive',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
kanban: {
|
||||
htmlLabels: false,
|
||||
},
|
||||
fontSize: 16,
|
||||
logLevel: 0,
|
||||
securityLevel: 'loose',
|
||||
callback,
|
||||
});
|
||||
// setTimeout(() => {
|
||||
mermaid.init(undefined, document.querySelectorAll('.mermaid'));
|
||||
// }, 1000);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -4,28 +4,60 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background:#333; */
|
||||
/* background: #333; */
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
|
||||
/* background-color: #efefef;
|
||||
background-image: radial-gradient(#fff 51%, transparent 91%),
|
||||
radial-gradient(#fff 51%, transparent 91%);
|
||||
background-size: 20px 20px;
|
||||
background-position:
|
||||
0 0,
|
||||
10px 10px;
|
||||
background-repeat: repeat; */
|
||||
}
|
||||
|
||||
.malware {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
@@ -41,34 +73,75 @@
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
|
||||
/* tspan {
|
||||
font-size: 6px !important;
|
||||
} */
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>Security check</div>
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart LR
|
||||
A-->B
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
mindmap
|
||||
root
|
||||
ch1
|
||||
ch2
|
||||
</pre
|
||||
stateDiagram-v2
|
||||
direction LR
|
||||
[*] --> Active
|
||||
|
||||
state Active {
|
||||
direction BT
|
||||
[*] --> Inner
|
||||
Inner --> NumLockOn : EvNumLockPressed
|
||||
}
|
||||
%% Outer --> Inner
|
||||
</pre
|
||||
>
|
||||
<script src="./packages/mermaid-mindmap/dist/mermaid-mindmap-detector.js"></script>
|
||||
<script src="./packages/mermaid-mindmap/dist/mermaid-example-diagram-detector.js"></script>
|
||||
<script src="./packages/mermaid/dist/mermaid.esm.mjs"></script>
|
||||
<script>
|
||||
|
||||
<pre id="diagram" class="mermaid">
|
||||
stateDiagram-v2
|
||||
[*] --> First
|
||||
state First {
|
||||
[*] --> second
|
||||
second --> [*]
|
||||
}
|
||||
|
||||
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart LR
|
||||
A[Start] --Some text--> B(Continue)
|
||||
B --> C{Evaluate}
|
||||
C -- One --> D[Option 1]
|
||||
C -- Two --> E[Option 2]
|
||||
C -- Three --> F[fa:fa-car Option 3]
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: 'neo',
|
||||
handdrawnSeed: 12,
|
||||
look: 'neo',
|
||||
//layout: 'elk',
|
||||
'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
// layout: 'dagre',
|
||||
// layout: 'elk',
|
||||
flowchart: { titleTopMargin: 10 },
|
||||
// fontFamily: 'Caveat',
|
||||
//fontFamily: 'Kalam',
|
||||
fontFamily: 'Arial',
|
||||
sequence: {
|
||||
actorFontFamily: 'arial',
|
||||
noteFontFamily: 'arial',
|
||||
messageFontFamily: 'arial',
|
||||
},
|
||||
fontSize: 10,
|
||||
logLevel: 0,
|
||||
basePath: './packages/',
|
||||
// themeVariables: {relationLabelColor: 'red'}
|
||||
htmlLabels: true,
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
@@ -77,6 +150,10 @@ A-->B
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
// mermaid.test1('first_slow', 1200).then((r) => console.info(r));
|
||||
// mermaid.test1('second_fast', 200).then((r) => console.info(r));
|
||||
// mermaid.test1('third_fast', 200).then((r) => console.info(r));
|
||||
// mermaid.test1('forth_slow', 1200).then((r) => console.info(r));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
307
cypress/platform/refactor.html
Normal file
307
cypress/platform/refactor.html
Normal file
@@ -0,0 +1,307 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="//unpkg.com/alpinejs" defer></script>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial';
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border: 1px solid black;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.separator {
|
||||
height: 20px;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.vertical-header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.collapsible {
|
||||
background-color: #f9f9f9;
|
||||
color: #444;
|
||||
cursor: pointer;
|
||||
padding: 18px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
text-align: left;
|
||||
outline: none;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.active,
|
||||
.collapsible:hover {
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
.collapsible:after {
|
||||
content: '\002B';
|
||||
color: #777;
|
||||
font-weight: bold;
|
||||
float: right;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.active:after {
|
||||
content: '\2212';
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0 5px;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.2s ease-out;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.content .pre-scrollable {
|
||||
max-height: 200px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
const data = {
|
||||
shapes: [
|
||||
{
|
||||
descr: 'Stadium shape',
|
||||
code: `
|
||||
flowchart LR
|
||||
id1([This is the text in the box])
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Sub-Routine shape',
|
||||
code: `
|
||||
flowchart LR
|
||||
id1[[This is the text in the box]]
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Cylindrical shape',
|
||||
code: `
|
||||
flowchart LR
|
||||
id1[(Database)]
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Circle shape',
|
||||
code: `
|
||||
flowchart LR
|
||||
id1((Circle))
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Double Circle shape',
|
||||
code: `
|
||||
flowchart LR
|
||||
id1(((Circle)))
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Asymmetric shape',
|
||||
code: `
|
||||
flowchart LR
|
||||
id1>This is the text in the box]
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Rhombus/Diamond/Question shape',
|
||||
code: `
|
||||
flowchart LR
|
||||
id1{This is the text in the box}
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Hexagon shape',
|
||||
code: `
|
||||
flowchart LR
|
||||
id1{{This is the text in the box}}
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Parallelogram shape',
|
||||
code: `
|
||||
flowchart TD
|
||||
id1[/This is the text in the box/]
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Parallelogram Alt shape',
|
||||
code: `
|
||||
flowchart TD
|
||||
id1[\This is the text in the box\]
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Trapezoid shape',
|
||||
code: `
|
||||
flowchart TD
|
||||
A[/Christmas\\]
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Trapezoid Alt shape',
|
||||
code: `
|
||||
flowchart TD
|
||||
id1[\\This is the text in the box\\]
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Rect with rounded corner',
|
||||
code: `
|
||||
flowchart LR
|
||||
id1(This is the text in the box)
|
||||
`,
|
||||
},
|
||||
{
|
||||
descr: 'Rect with sharp corner',
|
||||
code: `
|
||||
flowchart LR
|
||||
id1[This is the text in the box]
|
||||
`,
|
||||
},
|
||||
],
|
||||
looks: ['classic', 'handdrawn', 'neo'],
|
||||
// looks: ['classic'],
|
||||
layouts: ['elk', 'dagre'],
|
||||
// layouts: ['elk'],
|
||||
themes: ['default', 'neo'],
|
||||
// themes: ['default'],
|
||||
};
|
||||
function generateMermaidCode(layout, look, theme, shape) {
|
||||
return `---
|
||||
config:
|
||||
layout: ${layout}
|
||||
look: ${look}
|
||||
theme: ${theme}
|
||||
---
|
||||
${shape.code}
|
||||
`;
|
||||
}
|
||||
</script>
|
||||
<table x-data="data">
|
||||
<tr>
|
||||
<th></th>
|
||||
<template x-for="layout in layouts">
|
||||
<template x-for="look in looks">
|
||||
<template x-for="theme in themes">
|
||||
<th x-text="layout + '-' + look + '-' + theme "></th>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
<template x-for="shape in shapes">
|
||||
<tr>
|
||||
<th class="vertical-header">
|
||||
<button class="collapsible" x-text="shape.descr">Sub-Routine shape</button>
|
||||
<div class="content">
|
||||
<div class="pre-scrollable">
|
||||
<pre x-text="shape.code"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
<template x-for="layout in layouts">
|
||||
<template x-for="look in looks">
|
||||
<template x-for="theme in themes">
|
||||
<td>
|
||||
<pre
|
||||
id="diagram6"
|
||||
class="mermaid"
|
||||
x-text="generateMermaidCode(layout, look, theme, shape)"
|
||||
></pre>
|
||||
</td>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</tr>
|
||||
</template>
|
||||
</table>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {};
|
||||
|
||||
mermaid.initialize({
|
||||
handdrawn: false,
|
||||
mergeEdges: true,
|
||||
layout: 'dagre',
|
||||
flowchart: { titleTopMargin: 10 },
|
||||
// fontFamily: 'Caveat',
|
||||
fontFamily: 'Kalam',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
fontSize: 16,
|
||||
logLevel: 0,
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
|
||||
let coll = document.getElementsByClassName('collapsible');
|
||||
for (const element of coll) {
|
||||
element.addEventListener('click', function () {
|
||||
this.classList.toggle('active');
|
||||
let content = this.nextElementSibling;
|
||||
if (content.style.maxHeight) {
|
||||
content.style.maxHeight = null;
|
||||
} else {
|
||||
content.style.maxHeight = content.scrollHeight + 'px';
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
102
cypress/platform/shape-tester.html
Normal file
102
cypress/platform/shape-tester.html
Normal file
@@ -0,0 +1,102 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial';
|
||||
background-color: #333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="diagram"></div>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
//look: 'handdrawn',
|
||||
// layout: 'fixed',
|
||||
theme: 'dark',
|
||||
//layout: 'elk',
|
||||
fontFamily: 'Kalam',
|
||||
logLevel: 1,
|
||||
});
|
||||
|
||||
let shape = 'circle';
|
||||
let simplified = true;
|
||||
// let simplified = false;
|
||||
let algorithm = 'elk';
|
||||
// let algorithm = 'dagre';
|
||||
let code = `---
|
||||
config:
|
||||
layout: ${algorithm}
|
||||
---
|
||||
flowchart TD
|
||||
A["Abrakadabra"] --> C["C"] & D["I am a circle"] & n4["Untitled Node"]
|
||||
D@{ shape: diamond}
|
||||
B["Bombrakadombra"] --> D & C & D
|
||||
C --> E["E"] & B
|
||||
D --> E & A
|
||||
n4 --> C
|
||||
A@{ shape: ${shape}}
|
||||
B@{ shape: ${shape}}
|
||||
C@{ shape: ${shape}}
|
||||
D@{ shape: ${shape}}
|
||||
E@{ shape: ${shape}}
|
||||
n4@{ shape: ${shape}}
|
||||
|
||||
`;
|
||||
if (simplified) {
|
||||
code = `---
|
||||
config:
|
||||
layout: ${algorithm}
|
||||
---
|
||||
flowchart LR
|
||||
A["Abrakadabra"] --> C["I am the circle"] & C & C & C & C
|
||||
%% A["Abrakadabra"] --> C
|
||||
A@{ shape: ${shape}}
|
||||
C@{ shape: ${shape}}
|
||||
|
||||
`;
|
||||
}
|
||||
console.log(code);
|
||||
const { svg } = await mermaid.render('the-id-of-the-svg', code, undefined, undefined);
|
||||
const elem = document.querySelector('#diagram');
|
||||
elem.innerHTML = svg;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
180
cypress/platform/size-tester.html
Normal file
180
cypress/platform/size-tester.html
Normal file
@@ -0,0 +1,180 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial';
|
||||
background-color: #333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="diagram"></div>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
//look: 'handdrawn',
|
||||
layout: 'fixed',
|
||||
theme: 'neo-dark',
|
||||
//layout: 'elk',
|
||||
fontFamily: 'Kalam',
|
||||
logLevel: 1,
|
||||
class: {
|
||||
hideEmptyMembersBox: true,
|
||||
},
|
||||
});
|
||||
|
||||
let shape = 'circle';
|
||||
|
||||
let code = `
|
||||
flowchart TB
|
||||
n80["APA ksldj hfaskljdh aklsjdhf klasjdhf klasjhf klsajdh klasjdhf klasjdhf klasjdh klasjhf klasjdh klajsdhfklasjdhf kljadh fklasjdhf klajsdhf lkasdhf klajsdhf klasjdhfklasjdh klasjhf klasdfh klasdfh aklsjfh akjshkasldfh klasdfh klasjh fklsjhf klasdhf kljasdhf klasdhf klj"]
|
||||
n80@{ shape: '${shape}'}
|
||||
n81["APA ksldj hfaskljdh aklsjdhf klasjdhf klasjhf klsajdh klasjdhf klasjdhf klasjdh klasjhf klasjdh klajsdhfklasjdhf kljadh fklasjdhf klajsdhf lkasdhf klajsdhf klasjdhfklasjdh klasjhf klasdfh klasdfh aklsjfh akjshkasldfh klasdfh klasjh fklsjhf klasdhf kljasdhf klasdhf klj"]
|
||||
n82["A single line of text"]
|
||||
n81@{ shape: '${shape}'}
|
||||
n82@{ shape: '${shape}'}
|
||||
n83@{ label: "A single line of text", shape: '${shape}'}
|
||||
n84@{ shape: '${shape}'}
|
||||
`;
|
||||
|
||||
let code2 = `
|
||||
classDiagram
|
||||
class class1 {
|
||||
int num
|
||||
string test
|
||||
string test
|
||||
string test
|
||||
string test
|
||||
string test
|
||||
method()
|
||||
}
|
||||
class class2 {
|
||||
int num
|
||||
string test
|
||||
string test
|
||||
string test
|
||||
string test
|
||||
string test
|
||||
method()
|
||||
method()
|
||||
}
|
||||
class class3 {
|
||||
int test
|
||||
}
|
||||
<<interface>> class3
|
||||
class class4 {
|
||||
int[] id
|
||||
method()
|
||||
method()
|
||||
method()
|
||||
method()
|
||||
}
|
||||
<<interface>> class4
|
||||
`;
|
||||
|
||||
let positions = {
|
||||
edges: {},
|
||||
nodes: {
|
||||
n81: {
|
||||
x: 0,
|
||||
y: 10,
|
||||
width: 300,
|
||||
height: 200,
|
||||
},
|
||||
n80: {
|
||||
x: -400,
|
||||
y: 10,
|
||||
width: 100,
|
||||
height: 50,
|
||||
},
|
||||
n82: {
|
||||
x: 400,
|
||||
y: 10,
|
||||
width: 300,
|
||||
height: 200,
|
||||
},
|
||||
n83: {
|
||||
x: 800,
|
||||
y: 10,
|
||||
},
|
||||
n84: {
|
||||
x: 1200,
|
||||
y: 10,
|
||||
width: 300,
|
||||
height: 200,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
let positions2 = {
|
||||
edges: {},
|
||||
nodes: {
|
||||
class1: {
|
||||
x: 0,
|
||||
y: 10,
|
||||
width: 100,
|
||||
height: 400,
|
||||
},
|
||||
class2: {
|
||||
x: -300,
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 0,
|
||||
},
|
||||
class3: {
|
||||
x: 400,
|
||||
y: 10,
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
class4: {
|
||||
x: 800,
|
||||
y: 10,
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { svg } = await mermaid.render('the-id-of-the-svg', code2, undefined, positions2);
|
||||
const elem = document.querySelector('#diagram');
|
||||
elem.innerHTML = svg;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1576
cypress/platform/state-refactor-looks.html
Normal file
1576
cypress/platform/state-refactor-looks.html
Normal file
File diff suppressed because it is too large
Load Diff
1540
cypress/platform/state-refactor-neo-themes.html
Normal file
1540
cypress/platform/state-refactor-neo-themes.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -93,6 +93,7 @@
|
||||
<th></th> <!-- Placeholder for the top left corner -->
|
||||
<th>Dagre</th>
|
||||
<th>Dagre with rough</th>
|
||||
<th>Dagre with neo</th>
|
||||
<th>ELK</th>
|
||||
<th>ELK with rough</th>
|
||||
</tr>
|
||||
@@ -116,6 +117,14 @@ stateDiagram-v2
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "handDrawn"} }%%
|
||||
stateDiagram-v2
|
||||
stateId
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
stateDiagram-v2
|
||||
stateId
|
||||
|
||||
@@ -163,6 +172,13 @@ stateDiagram-v2
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "handDrawn"} }%%
|
||||
stateDiagram-v2
|
||||
state "This is a state description" as s3
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
stateDiagram-v2
|
||||
state "This is a state description" as s3
|
||||
</pre>
|
||||
@@ -207,6 +223,14 @@ stateDiagram-v2
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "handDrawn"} }%%
|
||||
stateDiagram-v2
|
||||
s22 : This is a state description
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
stateDiagram-v2
|
||||
s22 : This is a state description
|
||||
|
||||
@@ -267,10 +291,20 @@ stateDiagram-v2
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
|
||||
stateDiagram-v2
|
||||
s51 --> s52
|
||||
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram3" class="mermaid">
|
||||
%%{init: {"handDrawn": false, "layout": "elk"} }%%
|
||||
stateDiagram-v2
|
||||
s51 --> s52
|
||||
s61 --> s62
|
||||
|
||||
|
||||
</pre>
|
||||
@@ -279,7 +313,7 @@ stateDiagram-v2
|
||||
<pre id="diagram4" class="mermaid">
|
||||
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
|
||||
stateDiagram-v2
|
||||
s61 --> s62
|
||||
s71 --> s72
|
||||
|
||||
|
||||
</pre>
|
||||
@@ -322,13 +356,23 @@ stateDiagram-v2
|
||||
a3 --> a4: A transition
|
||||
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
|
||||
stateDiagram-v2
|
||||
a5 --> a6: A transition
|
||||
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram3" class="mermaid">
|
||||
%%{init: {"handDrawn": false, "layout": "elk"} }%%
|
||||
stateDiagram-v2
|
||||
a5 --> a6: A transition
|
||||
a7 --> a8: A transition
|
||||
|
||||
|
||||
</pre>
|
||||
@@ -337,7 +381,7 @@ stateDiagram-v2
|
||||
<pre id="diagram4" class="mermaid">
|
||||
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
|
||||
stateDiagram-v2
|
||||
a7 --> a8: A transition
|
||||
a9 --> a10: A transition
|
||||
|
||||
|
||||
</pre>
|
||||
@@ -383,6 +427,17 @@ stateDiagram-v2
|
||||
test --> [*]
|
||||
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
|
||||
stateDiagram-v2
|
||||
[*] --> test
|
||||
test --> [*]
|
||||
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
@@ -455,6 +510,20 @@ stateDiagram-v2
|
||||
}
|
||||
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
|
||||
stateDiagram-v2
|
||||
[*] --> First
|
||||
state First {
|
||||
[*] --> second
|
||||
second --> [*]
|
||||
}
|
||||
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
@@ -568,6 +637,31 @@ stateDiagram-v2
|
||||
|
||||
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
|
||||
stateDiagram-v2
|
||||
[*] --> Level1
|
||||
|
||||
state Level1 {
|
||||
[*] --> Level2
|
||||
|
||||
state Level2 {
|
||||
[*] --> level2
|
||||
level2 --> Level3
|
||||
|
||||
state Level3 {
|
||||
[*] --> level3
|
||||
level3 --> [*]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
@@ -698,6 +792,30 @@ stateDiagram-v2
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
|
||||
stateDiagram-v2
|
||||
[*] --> B1
|
||||
B1 --> B2
|
||||
B1 --> B3
|
||||
|
||||
state B1 {
|
||||
[*] --> B11
|
||||
B11 --> [*]
|
||||
}
|
||||
state B2 {
|
||||
[*] --> B22
|
||||
B22 --> [*]
|
||||
}
|
||||
state B3 {
|
||||
[*] --> B33
|
||||
B33 --> [*]
|
||||
}
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<pre id="diagram3" class="mermaid">
|
||||
%%{init: {"handDrawn": false, "layout": "elk"} }%%
|
||||
stateDiagram-v2
|
||||
@@ -794,7 +912,19 @@ stateDiagram-v2
|
||||
if_state --> True : if n >= 0
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
|
||||
stateDiagram-v2
|
||||
state if_state <<choice>>
|
||||
[*] --> IsPositive
|
||||
IsPositive --> if_state
|
||||
if_state --> False: if n < 0
|
||||
if_state --> True : if n >= 0
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram3" class="mermaid">
|
||||
%%{init: {"handDrawn": false, "layout": "elk"} }%%
|
||||
stateDiagram-v2
|
||||
@@ -866,6 +996,23 @@ stateDiagram-v2
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "handDrawn"} }%%
|
||||
stateDiagram-v2
|
||||
state fork_state <<fork>>
|
||||
[*] --> fork_state
|
||||
fork_state --> State2
|
||||
fork_state --> State3
|
||||
|
||||
state join_state <<join>>
|
||||
State2 --> join_state
|
||||
State3 --> join_state
|
||||
join_state --> State4
|
||||
State4 --> [*]
|
||||
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
stateDiagram-v2
|
||||
state fork_state <<fork>>
|
||||
[*] --> fork_state
|
||||
@@ -956,6 +1103,19 @@ stateDiagram-v2
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "handDrawn"} }%%
|
||||
stateDiagram-v2
|
||||
TN3: The state with a note
|
||||
note right of TN3
|
||||
Important information! You can write
|
||||
notes.
|
||||
end note
|
||||
TN3 --> TN4
|
||||
note left of TN4 : This is the note to the left.
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
stateDiagram-v2
|
||||
TN3: The state with a note
|
||||
note right of TN3
|
||||
@@ -1056,6 +1216,27 @@ state Active {
|
||||
stateDiagram-v2
|
||||
[*] --> Active
|
||||
|
||||
state Active {
|
||||
[*] --> NumLockOff
|
||||
NumLockOff --> NumLockOn : EvNumLockPressed
|
||||
NumLockOn --> NumLockOff : EvNumLockPressed
|
||||
--
|
||||
[*] --> CapsLockOff
|
||||
CapsLockOff --> CapsLockOn : EvCapsLockPressed
|
||||
CapsLockOn --> CapsLockOff : EvCapsLockPressed
|
||||
--
|
||||
[*] --> ScrollLockOff
|
||||
ScrollLockOff --> ScrollLockOn : EvScrollLockPressed
|
||||
ScrollLockOn --> ScrollLockOff : EvScrollLockPressed
|
||||
}
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
stateDiagram-v2
|
||||
[*] --> Active
|
||||
|
||||
state Active {
|
||||
[*] --> NumLockOff
|
||||
NumLockOff --> NumLockOn : EvNumLockPressed
|
||||
@@ -1161,6 +1342,21 @@ direction LR
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "handDrawn"} }%%
|
||||
stateDiagram-v2
|
||||
direction LR
|
||||
[*] --> D1
|
||||
D1 --> D2
|
||||
D2 --> D3
|
||||
state D3 {
|
||||
direction TB
|
||||
D11 --> D22
|
||||
}
|
||||
D2 --> D4
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre id="diagram2" class="mermaid">
|
||||
%%{init: {"look": "neo"} }%%
|
||||
stateDiagram-v2
|
||||
direction LR
|
||||
[*] --> D1
|
||||
D1 --> D2
|
||||
|
||||
172
cypress/platform/steph.html
Normal file
172
cypress/platform/steph.html
Normal file
@@ -0,0 +1,172 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background: #333; */
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
|
||||
/* background-color: #efefef;
|
||||
background-image: radial-gradient(#fff 51%, transparent 91%),
|
||||
radial-gradient(#fff 51%, transparent 91%);
|
||||
background-size: 20px 20px;
|
||||
background-position:
|
||||
0 0,
|
||||
10px 10px;
|
||||
background-repeat: repeat; */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
%%{init: {"look": "neo", "theme": "neo","fontFamily": "Arial"} }%%
|
||||
flowchart
|
||||
A[A really really really super long node] --> B & C
|
||||
subgraph apa
|
||||
D --> E
|
||||
end
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
%%{init: {"look": "neo", "theme": "forest","fontFamily": "Arial", "themeVariables": {
|
||||
"useGradient": true,
|
||||
"gradientStart": '#fff',
|
||||
"gradientStop": '#ccc'
|
||||
}} }%%
|
||||
stateDiagram-v2
|
||||
stateId
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram2" class="mermaid2">
|
||||
flowchart LR
|
||||
id1(Start)-->id2(Stop)
|
||||
style id1 fill:#f9f,stroke:#333,stroke-width:4px
|
||||
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
|
||||
|
||||
|
||||
</pre>
|
||||
|
||||
<pre id="diagram3" class="mermaid2">
|
||||
flowchart LR
|
||||
A:::foo & B:::bar --> C:::foobar
|
||||
classDef foo stroke:#f00
|
||||
classDef bar stroke:#0f0
|
||||
classDef ash color:red
|
||||
class C ash
|
||||
style C stroke:#00f, fill:black
|
||||
|
||||
</pre>
|
||||
<!-- Flowchart with subgraph-->
|
||||
<pre id="diagram3" class="mermaid">
|
||||
flowchart TB
|
||||
c1-->a2
|
||||
subgraph one
|
||||
a1-->a2
|
||||
end
|
||||
subgraph two
|
||||
b1-->b2
|
||||
end
|
||||
subgraph three
|
||||
c1-->c2
|
||||
end
|
||||
</pre>
|
||||
|
||||
<pre id="diagram4" class="mermaid">
|
||||
stateDiagram-v2
|
||||
[*] --> First
|
||||
state First {
|
||||
[*] --> second
|
||||
second --> [*]
|
||||
}
|
||||
|
||||
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
window.callback = function () {
|
||||
alert('A callback was triggered');
|
||||
};
|
||||
mermaid.initialize({
|
||||
theme: 'neo',
|
||||
|
||||
// handdrawnSeed: 12,
|
||||
look: 'neo',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
// layout: 'dagre',
|
||||
// layout: 'elk',
|
||||
// layout: 'fixed',
|
||||
// htmlLabels: false,
|
||||
flowchart: { titleTopMargin: 10 },
|
||||
|
||||
// fontFamily: 'Caveat',
|
||||
// fontFamily: 'Kalam',
|
||||
// fontFamily: 'courier',
|
||||
fontFamily: 'arial',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
fontSize: 12,
|
||||
logLevel: 0,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
285
demos/architecture-dark.html
Normal file
285
demos/architecture-dark.html
Normal file
@@ -0,0 +1,285 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Architecture Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
/* font-family: 'trebuchet ms', verdana, arial; */
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
background-color: #333;
|
||||
}
|
||||
body {
|
||||
color: white;
|
||||
background-color: #333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Architecture diagram demo</h1>
|
||||
<h2>Simple diagram with groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
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
|
||||
service gateway(internet)[Gateway]
|
||||
|
||||
db:L -- R:server
|
||||
disk1:T -- B:server
|
||||
disk2:T -- B:db
|
||||
server:T -- B:gateway
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Groups within groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group api[API]
|
||||
group public[Public API] in api
|
||||
group private[Private API] in api
|
||||
|
||||
|
||||
service serv1(server)[Server] in public
|
||||
|
||||
|
||||
service serv2(server)[Server] in private
|
||||
service db(database)[Database] in private
|
||||
|
||||
service gateway(internet)[Gateway] in api
|
||||
|
||||
serv1:B -- T:serv2
|
||||
|
||||
serv2:L -- R:db
|
||||
|
||||
serv1:L -- R:gateway
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Default icon (?) from unknown icon name</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service unknown(iconnamedoesntexist)[Unknown Icon]
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Split Direction</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service db(database)[Database]
|
||||
service s3(disk)[Storage]
|
||||
service serv1(server)[Server 1]
|
||||
service serv2(server)[Server 2]
|
||||
service disk(disk)[Disk]
|
||||
|
||||
db:L -- R:s3
|
||||
serv1:L -- T:s3
|
||||
serv2:L -- B:s3
|
||||
serv1:T -- B:disk
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Arrow Tests</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L <--> R:servL
|
||||
servC:R <--> L:servR
|
||||
servC:T <--> B:servT
|
||||
servC:B <--> T:servB
|
||||
|
||||
servL:T <--> L:servT
|
||||
servL:B <--> L:servB
|
||||
servR:T <--> R:servT
|
||||
servR:B <--> R:servB
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L <--> R:servL
|
||||
servC:R <--> L:servR
|
||||
servC:T <--> B:servT
|
||||
servC:B <--> T:servB
|
||||
|
||||
servT:L <--> T:servL
|
||||
servB:L <--> B:servL
|
||||
servT:R <--> T:servR
|
||||
servB:R <--> B:servR
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Group Edges</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group left_group(cloud)[Left]
|
||||
group right_group(cloud)[Right]
|
||||
group top_group(cloud)[Top]
|
||||
group bottom_group(cloud)[Bottom]
|
||||
group center_group(cloud)[Center]
|
||||
|
||||
service left_disk(disk)[Disk] in left_group
|
||||
service right_disk(disk)[Disk] in right_group
|
||||
service top_disk(disk)[Disk] in top_group
|
||||
service bottom_disk(disk)[Disk] in bottom_group
|
||||
service center_disk(disk)[Disk] in center_group
|
||||
|
||||
left_disk{group}:R <--> L:center_disk{group}
|
||||
right_disk{group}:L <--> R:center_disk{group}
|
||||
top_disk{group}:B <--> T:center_disk{group}
|
||||
bottom_disk{group}:T <--> B:center_disk{group}
|
||||
</pre
|
||||
>
|
||||
<hr />
|
||||
|
||||
<h2>Edge Label Test</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L -[Label]- R:servL
|
||||
servC:R -[Label]- L:servR
|
||||
servC:T -[Label]- B:servT
|
||||
servC:B -[Label]- T:servB
|
||||
|
||||
servL:T -[Label]- L:servT
|
||||
servL:B -[Label]- L:servB
|
||||
servR:T -[Label]- R:servT
|
||||
servR:B -[Label]- R:servB
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L -[Label that is Long]- R:servL
|
||||
servC:R -[Label that is Long]- L:servR
|
||||
servC:T -[Label that is Long]- B:servT
|
||||
servC:B -[Label that is Long]- T:servB
|
||||
|
||||
servL:T -[Label that is Long]- L:servT
|
||||
servL:B -[Label that is Long]- L:servB
|
||||
servR:T -[Label that is Long]- R:servT
|
||||
servR:B -[Label that is Long]- R:servB
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
<h2>Junction Demo</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service left_disk(disk)[Disk]
|
||||
service top_disk(disk)[Disk]
|
||||
service bottom_disk(disk)[Disk]
|
||||
service top_gateway(internet)[Gateway]
|
||||
service bottom_gateway(internet)[Gateway]
|
||||
junction juncC
|
||||
junction juncR
|
||||
|
||||
left_disk:R -- L:juncC
|
||||
top_disk:B -- T:juncC
|
||||
bottom_disk:T -- B:juncC
|
||||
juncC:R -- L:juncR
|
||||
top_gateway:B -- T:juncR
|
||||
bottom_gateway:T -- B:juncR
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Junction Demo Groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group left
|
||||
group right
|
||||
service left_disk(disk)[Disk] in left
|
||||
service top_disk(disk)[Disk] in left
|
||||
service bottom_disk(disk)[Disk] in left
|
||||
service top_gateway(internet)[Gateway] in right
|
||||
service bottom_gateway(internet)[Gateway] in right
|
||||
junction juncC in left
|
||||
junction juncR in right
|
||||
|
||||
left_disk:R -- L:juncC
|
||||
top_disk:B -- T:juncC
|
||||
bottom_disk:T -- B:juncC
|
||||
|
||||
|
||||
top_gateway:B <-- T:juncR
|
||||
bottom_gateway:T <-- B:juncR
|
||||
|
||||
juncC{group}:R --> L:juncR{group}
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>External Icons Demo</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service s3(logos:aws-s3)[Cloud Store]
|
||||
service ec2(logos:aws-ec2)[Server]
|
||||
service api(logos:aws-api-gateway)[Api Gateway]
|
||||
service fa(fa:image)[Font Awesome Icon]
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'dark',
|
||||
// handDrawnSeed: 12,
|
||||
// look: 'handDrawn',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
// layout: 'dagre',
|
||||
// layout: 'elk',
|
||||
// layout: 'fixed',
|
||||
// htmlLabels: false,
|
||||
//flowchart: { titleTopMargin: 10 },
|
||||
|
||||
// fontFamily: 'Caveat',
|
||||
// fontFamily: 'Kalam',
|
||||
// fontFamily: 'courier',
|
||||
// fontFamily: 'arial',
|
||||
// sequence: {
|
||||
// actorFontFamily: 'courier',
|
||||
// noteFontFamily: 'courier',
|
||||
// messageFontFamily: 'courier',
|
||||
// },
|
||||
// fontSize: 12,
|
||||
// logLevel: 3,
|
||||
// securityLevel: 'loose',
|
||||
});
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
|
||||
},
|
||||
{
|
||||
name: 'fa',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/fa6-regular/icons.json').then((res) =>
|
||||
res.json()
|
||||
),
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
280
demos/architecture-mermaid-chart.html
Normal file
280
demos/architecture-mermaid-chart.html
Normal file
@@ -0,0 +1,280 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Architecture Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
/* font-family: 'trebuchet ms', verdana, arial; */
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Architecture diagram demo</h1>
|
||||
<h2>Simple diagram with groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
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
|
||||
service gateway(internet)[Gateway]
|
||||
|
||||
db:L -- R:server
|
||||
disk1:T -- B:server
|
||||
disk2:T -- B:db
|
||||
server:T -- B:gateway
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Groups within groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group api[API]
|
||||
group public[Public API] in api
|
||||
group private[Private API] in api
|
||||
|
||||
|
||||
service serv1(server)[Server] in public
|
||||
|
||||
|
||||
service serv2(server)[Server] in private
|
||||
service db(database)[Database] in private
|
||||
|
||||
service gateway(internet)[Gateway] in api
|
||||
|
||||
serv1:B -- T:serv2
|
||||
|
||||
serv2:L -- R:db
|
||||
|
||||
serv1:L -- R:gateway
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Default icon (?) from unknown icon name</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service unknown(iconnamedoesntexist)[Unknown Icon]
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Split Direction</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service db(database)[Database]
|
||||
service s3(disk)[Storage]
|
||||
service serv1(server)[Server 1]
|
||||
service serv2(server)[Server 2]
|
||||
service disk(disk)[Disk]
|
||||
|
||||
db:L -- R:s3
|
||||
serv1:L -- T:s3
|
||||
serv2:L -- B:s3
|
||||
serv1:T -- B:disk
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Arrow Tests</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L <--> R:servL
|
||||
servC:R <--> L:servR
|
||||
servC:T <--> B:servT
|
||||
servC:B <--> T:servB
|
||||
|
||||
servL:T <--> L:servT
|
||||
servL:B <--> L:servB
|
||||
servR:T <--> R:servT
|
||||
servR:B <--> R:servB
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L <--> R:servL
|
||||
servC:R <--> L:servR
|
||||
servC:T <--> B:servT
|
||||
servC:B <--> T:servB
|
||||
|
||||
servT:L <--> T:servL
|
||||
servB:L <--> B:servL
|
||||
servT:R <--> T:servR
|
||||
servB:R <--> B:servR
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Group Edges</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group left_group(cloud)[Left]
|
||||
group right_group(cloud)[Right]
|
||||
group top_group(cloud)[Top]
|
||||
group bottom_group(cloud)[Bottom]
|
||||
group center_group(cloud)[Center]
|
||||
|
||||
service left_disk(disk)[Disk] in left_group
|
||||
service right_disk(disk)[Disk] in right_group
|
||||
service top_disk(disk)[Disk] in top_group
|
||||
service bottom_disk(disk)[Disk] in bottom_group
|
||||
service center_disk(disk)[Disk] in center_group
|
||||
|
||||
left_disk{group}:R <--> L:center_disk{group}
|
||||
right_disk{group}:L <--> R:center_disk{group}
|
||||
top_disk{group}:B <--> T:center_disk{group}
|
||||
bottom_disk{group}:T <--> B:center_disk{group}
|
||||
</pre
|
||||
>
|
||||
<hr />
|
||||
|
||||
<h2>Edge Label Test</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L -[Label]- R:servL
|
||||
servC:R -[Label]- L:servR
|
||||
servC:T -[Label]- B:servT
|
||||
servC:B -[Label]- T:servB
|
||||
|
||||
servL:T -[Label]- L:servT
|
||||
servL:B -[Label]- L:servB
|
||||
servR:T -[Label]- R:servT
|
||||
servR:B -[Label]- R:servB
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L -[Label that is Long]- R:servL
|
||||
servC:R -[Label that is Long]- L:servR
|
||||
servC:T -[Label that is Long]- B:servT
|
||||
servC:B -[Label that is Long]- T:servB
|
||||
|
||||
servL:T -[Label that is Long]- L:servT
|
||||
servL:B -[Label that is Long]- L:servB
|
||||
servR:T -[Label that is Long]- R:servT
|
||||
servR:B -[Label that is Long]- R:servB
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
<h2>Junction Demo</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service left_disk(disk)[Disk]
|
||||
service top_disk(disk)[Disk]
|
||||
service bottom_disk(disk)[Disk]
|
||||
service top_gateway(internet)[Gateway]
|
||||
service bottom_gateway(internet)[Gateway]
|
||||
junction juncC
|
||||
junction juncR
|
||||
|
||||
left_disk:R -- L:juncC
|
||||
top_disk:B -- T:juncC
|
||||
bottom_disk:T -- B:juncC
|
||||
juncC:R -- L:juncR
|
||||
top_gateway:B -- T:juncR
|
||||
bottom_gateway:T -- B:juncR
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Junction Demo Groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group left
|
||||
group right
|
||||
service left_disk(disk)[Disk] in left
|
||||
service top_disk(disk)[Disk] in left
|
||||
service bottom_disk(disk)[Disk] in left
|
||||
service top_gateway(internet)[Gateway] in right
|
||||
service bottom_gateway(internet)[Gateway] in right
|
||||
junction juncC in left
|
||||
junction juncR in right
|
||||
|
||||
left_disk:R -- L:juncC
|
||||
top_disk:B -- T:juncC
|
||||
bottom_disk:T -- B:juncC
|
||||
|
||||
|
||||
top_gateway:B <-- T:juncR
|
||||
bottom_gateway:T <-- B:juncR
|
||||
|
||||
juncC{group}:R --> L:juncR{group}
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>External Icons Demo</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service s3(logos:aws-s3)[Cloud Store]
|
||||
service ec2(logos:aws-ec2)[Server]
|
||||
service api(logos:aws-api-gateway)[Api Gateway]
|
||||
service fa(fa:image)[Font Awesome Icon]
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'mc',
|
||||
// handDrawnSeed: 12,
|
||||
// look: 'handDrawn',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
// layout: 'dagre',
|
||||
// layout: 'elk',
|
||||
// layout: 'fixed',
|
||||
// htmlLabels: false,
|
||||
//flowchart: { titleTopMargin: 10 },
|
||||
|
||||
// fontFamily: 'Caveat',
|
||||
// fontFamily: 'Kalam',
|
||||
// fontFamily: 'courier',
|
||||
// fontFamily: 'arial',
|
||||
// sequence: {
|
||||
// actorFontFamily: 'courier',
|
||||
// noteFontFamily: 'courier',
|
||||
// messageFontFamily: 'courier',
|
||||
// },
|
||||
// fontSize: 12,
|
||||
// logLevel: 3,
|
||||
// securityLevel: 'loose',
|
||||
});
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
|
||||
},
|
||||
{
|
||||
name: 'fa',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/fa6-regular/icons.json').then((res) =>
|
||||
res.json()
|
||||
),
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
284
demos/architecture-neo-dark.html
Normal file
284
demos/architecture-neo-dark.html
Normal file
@@ -0,0 +1,284 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Architecture Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
/* font-family: 'trebuchet ms', verdana, arial; */
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
body {
|
||||
color: white;
|
||||
background-color: #333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Architecture diagram demo</h1>
|
||||
<h2>Simple diagram with groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
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
|
||||
service gateway(internet)[Gateway]
|
||||
|
||||
db:L -- R:server
|
||||
disk1:T -- B:server
|
||||
disk2:T -- B:db
|
||||
server:T -- B:gateway
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Groups within groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group api[API]
|
||||
group public[Public API] in api
|
||||
group private[Private API] in api
|
||||
|
||||
|
||||
service serv1(server)[Server] in public
|
||||
|
||||
|
||||
service serv2(server)[Server] in private
|
||||
service db(database)[Database] in private
|
||||
|
||||
service gateway(internet)[Gateway] in api
|
||||
|
||||
serv1:B -- T:serv2
|
||||
|
||||
serv2:L -- R:db
|
||||
|
||||
serv1:L -- R:gateway
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Default icon (?) from unknown icon name</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service unknown(iconnamedoesntexist)[Unknown Icon]
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Split Direction</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service db(database)[Database]
|
||||
service s3(disk)[Storage]
|
||||
service serv1(server)[Server 1]
|
||||
service serv2(server)[Server 2]
|
||||
service disk(disk)[Disk]
|
||||
|
||||
db:L -- R:s3
|
||||
serv1:L -- T:s3
|
||||
serv2:L -- B:s3
|
||||
serv1:T -- B:disk
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Arrow Tests</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L <--> R:servL
|
||||
servC:R <--> L:servR
|
||||
servC:T <--> B:servT
|
||||
servC:B <--> T:servB
|
||||
|
||||
servL:T <--> L:servT
|
||||
servL:B <--> L:servB
|
||||
servR:T <--> R:servT
|
||||
servR:B <--> R:servB
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L <--> R:servL
|
||||
servC:R <--> L:servR
|
||||
servC:T <--> B:servT
|
||||
servC:B <--> T:servB
|
||||
|
||||
servT:L <--> T:servL
|
||||
servB:L <--> B:servL
|
||||
servT:R <--> T:servR
|
||||
servB:R <--> B:servR
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Group Edges</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group left_group(cloud)[Left]
|
||||
group right_group(cloud)[Right]
|
||||
group top_group(cloud)[Top]
|
||||
group bottom_group(cloud)[Bottom]
|
||||
group center_group(cloud)[Center]
|
||||
|
||||
service left_disk(disk)[Disk] in left_group
|
||||
service right_disk(disk)[Disk] in right_group
|
||||
service top_disk(disk)[Disk] in top_group
|
||||
service bottom_disk(disk)[Disk] in bottom_group
|
||||
service center_disk(disk)[Disk] in center_group
|
||||
|
||||
left_disk{group}:R <--> L:center_disk{group}
|
||||
right_disk{group}:L <--> R:center_disk{group}
|
||||
top_disk{group}:B <--> T:center_disk{group}
|
||||
bottom_disk{group}:T <--> B:center_disk{group}
|
||||
</pre
|
||||
>
|
||||
<hr />
|
||||
|
||||
<h2>Edge Label Test</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L -[Label]- R:servL
|
||||
servC:R -[Label]- L:servR
|
||||
servC:T -[Label]- B:servT
|
||||
servC:B -[Label]- T:servB
|
||||
|
||||
servL:T -[Label]- L:servT
|
||||
servL:B -[Label]- L:servB
|
||||
servR:T -[Label]- R:servT
|
||||
servR:B -[Label]- R:servB
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L -[Label that is Long]- R:servL
|
||||
servC:R -[Label that is Long]- L:servR
|
||||
servC:T -[Label that is Long]- B:servT
|
||||
servC:B -[Label that is Long]- T:servB
|
||||
|
||||
servL:T -[Label that is Long]- L:servT
|
||||
servL:B -[Label that is Long]- L:servB
|
||||
servR:T -[Label that is Long]- R:servT
|
||||
servR:B -[Label that is Long]- R:servB
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
<h2>Junction Demo</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service left_disk(disk)[Disk]
|
||||
service top_disk(disk)[Disk]
|
||||
service bottom_disk(disk)[Disk]
|
||||
service top_gateway(internet)[Gateway]
|
||||
service bottom_gateway(internet)[Gateway]
|
||||
junction juncC
|
||||
junction juncR
|
||||
|
||||
left_disk:R -- L:juncC
|
||||
top_disk:B -- T:juncC
|
||||
bottom_disk:T -- B:juncC
|
||||
juncC:R -- L:juncR
|
||||
top_gateway:B -- T:juncR
|
||||
bottom_gateway:T -- B:juncR
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Junction Demo Groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group left
|
||||
group right
|
||||
service left_disk(disk)[Disk] in left
|
||||
service top_disk(disk)[Disk] in left
|
||||
service bottom_disk(disk)[Disk] in left
|
||||
service top_gateway(internet)[Gateway] in right
|
||||
service bottom_gateway(internet)[Gateway] in right
|
||||
junction juncC in left
|
||||
junction juncR in right
|
||||
|
||||
left_disk:R -- L:juncC
|
||||
top_disk:B -- T:juncC
|
||||
bottom_disk:T -- B:juncC
|
||||
|
||||
|
||||
top_gateway:B <-- T:juncR
|
||||
bottom_gateway:T <-- B:juncR
|
||||
|
||||
juncC{group}:R --> L:juncR{group}
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>External Icons Demo</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service s3(logos:aws-s3)[Cloud Store]
|
||||
service ec2(logos:aws-ec2)[Server]
|
||||
service api(logos:aws-api-gateway)[Api Gateway]
|
||||
service fa(fa:image)[Font Awesome Icon]
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'neo-dark',
|
||||
// handDrawnSeed: 12,
|
||||
// look: 'handDrawn',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
// layout: 'dagre',
|
||||
// layout: 'elk',
|
||||
// layout: 'fixed',
|
||||
// htmlLabels: false,
|
||||
//flowchart: { titleTopMargin: 10 },
|
||||
|
||||
// fontFamily: 'Caveat',
|
||||
// fontFamily: 'Kalam',
|
||||
// fontFamily: 'courier',
|
||||
// fontFamily: 'arial',
|
||||
// sequence: {
|
||||
// actorFontFamily: 'courier',
|
||||
// noteFontFamily: 'courier',
|
||||
// messageFontFamily: 'courier',
|
||||
// },
|
||||
// fontSize: 12,
|
||||
// logLevel: 3,
|
||||
// securityLevel: 'loose',
|
||||
});
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
|
||||
},
|
||||
{
|
||||
name: 'fa',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/fa6-regular/icons.json').then((res) =>
|
||||
res.json()
|
||||
),
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
280
demos/architecture-neo.html
Normal file
280
demos/architecture-neo.html
Normal file
@@ -0,0 +1,280 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Architecture Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
/* font-family: 'trebuchet ms', verdana, arial; */
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Architecture diagram demo</h1>
|
||||
<h2>Simple diagram with groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
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
|
||||
service gateway(internet)[Gateway]
|
||||
|
||||
db:L -- R:server
|
||||
disk1:T -- B:server
|
||||
disk2:T -- B:db
|
||||
server:T -- B:gateway
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Groups within groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group api[API]
|
||||
group public[Public API] in api
|
||||
group private[Private API] in api
|
||||
|
||||
|
||||
service serv1(server)[Server] in public
|
||||
|
||||
|
||||
service serv2(server)[Server] in private
|
||||
service db(database)[Database] in private
|
||||
|
||||
service gateway(internet)[Gateway] in api
|
||||
|
||||
serv1:B -- T:serv2
|
||||
|
||||
serv2:L -- R:db
|
||||
|
||||
serv1:L -- R:gateway
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Default icon (?) from unknown icon name</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service unknown(iconnamedoesntexist)[Unknown Icon]
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Split Direction</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service db(database)[Database]
|
||||
service s3(disk)[Storage]
|
||||
service serv1(server)[Server 1]
|
||||
service serv2(server)[Server 2]
|
||||
service disk(disk)[Disk]
|
||||
|
||||
db:L -- R:s3
|
||||
serv1:L -- T:s3
|
||||
serv2:L -- B:s3
|
||||
serv1:T -- B:disk
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Arrow Tests</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L <--> R:servL
|
||||
servC:R <--> L:servR
|
||||
servC:T <--> B:servT
|
||||
servC:B <--> T:servB
|
||||
|
||||
servL:T <--> L:servT
|
||||
servL:B <--> L:servB
|
||||
servR:T <--> R:servT
|
||||
servR:B <--> R:servB
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L <--> R:servL
|
||||
servC:R <--> L:servR
|
||||
servC:T <--> B:servT
|
||||
servC:B <--> T:servB
|
||||
|
||||
servT:L <--> T:servL
|
||||
servB:L <--> B:servL
|
||||
servT:R <--> T:servR
|
||||
servB:R <--> B:servR
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Group Edges</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group left_group(cloud)[Left]
|
||||
group right_group(cloud)[Right]
|
||||
group top_group(cloud)[Top]
|
||||
group bottom_group(cloud)[Bottom]
|
||||
group center_group(cloud)[Center]
|
||||
|
||||
service left_disk(disk)[Disk] in left_group
|
||||
service right_disk(disk)[Disk] in right_group
|
||||
service top_disk(disk)[Disk] in top_group
|
||||
service bottom_disk(disk)[Disk] in bottom_group
|
||||
service center_disk(disk)[Disk] in center_group
|
||||
|
||||
left_disk{group}:R <--> L:center_disk{group}
|
||||
right_disk{group}:L <--> R:center_disk{group}
|
||||
top_disk{group}:B <--> T:center_disk{group}
|
||||
bottom_disk{group}:T <--> B:center_disk{group}
|
||||
</pre
|
||||
>
|
||||
<hr />
|
||||
|
||||
<h2>Edge Label Test</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L -[Label]- R:servL
|
||||
servC:R -[Label]- L:servR
|
||||
servC:T -[Label]- B:servT
|
||||
servC:B -[Label]- T:servB
|
||||
|
||||
servL:T -[Label]- L:servT
|
||||
servL:B -[Label]- L:servB
|
||||
servR:T -[Label]- R:servT
|
||||
servR:B -[Label]- R:servB
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service servC(server)[Server 1]
|
||||
service servL(server)[Server 2]
|
||||
service servR(server)[Server 3]
|
||||
service servT(server)[Server 4]
|
||||
service servB(server)[Server 5]
|
||||
|
||||
servC:L -[Label that is Long]- R:servL
|
||||
servC:R -[Label that is Long]- L:servR
|
||||
servC:T -[Label that is Long]- B:servT
|
||||
servC:B -[Label that is Long]- T:servB
|
||||
|
||||
servL:T -[Label that is Long]- L:servT
|
||||
servL:B -[Label that is Long]- L:servB
|
||||
servR:T -[Label that is Long]- R:servT
|
||||
servR:B -[Label that is Long]- R:servB
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
<h2>Junction Demo</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service left_disk(disk)[Disk]
|
||||
service top_disk(disk)[Disk]
|
||||
service bottom_disk(disk)[Disk]
|
||||
service top_gateway(internet)[Gateway]
|
||||
service bottom_gateway(internet)[Gateway]
|
||||
junction juncC
|
||||
junction juncR
|
||||
|
||||
left_disk:R -- L:juncC
|
||||
top_disk:B -- T:juncC
|
||||
bottom_disk:T -- B:juncC
|
||||
juncC:R -- L:juncR
|
||||
top_gateway:B -- T:juncR
|
||||
bottom_gateway:T -- B:juncR
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Junction Demo Groups</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
group left
|
||||
group right
|
||||
service left_disk(disk)[Disk] in left
|
||||
service top_disk(disk)[Disk] in left
|
||||
service bottom_disk(disk)[Disk] in left
|
||||
service top_gateway(internet)[Gateway] in right
|
||||
service bottom_gateway(internet)[Gateway] in right
|
||||
junction juncC in left
|
||||
junction juncR in right
|
||||
|
||||
left_disk:R -- L:juncC
|
||||
top_disk:B -- T:juncC
|
||||
bottom_disk:T -- B:juncC
|
||||
|
||||
|
||||
top_gateway:B <-- T:juncR
|
||||
bottom_gateway:T <-- B:juncR
|
||||
|
||||
juncC{group}:R --> L:juncR{group}
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>External Icons Demo</h2>
|
||||
<pre class="mermaid">
|
||||
architecture-beta
|
||||
service s3(logos:aws-s3)[Cloud Store]
|
||||
service ec2(logos:aws-ec2)[Server]
|
||||
service api(logos:aws-api-gateway)[Api Gateway]
|
||||
service fa(fa:image)[Font Awesome Icon]
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'neo',
|
||||
// handDrawnSeed: 12,
|
||||
// look: 'handDrawn',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
// layout: 'dagre',
|
||||
// layout: 'elk',
|
||||
// layout: 'fixed',
|
||||
// htmlLabels: false,
|
||||
//flowchart: { titleTopMargin: 10 },
|
||||
|
||||
// fontFamily: 'Caveat',
|
||||
// fontFamily: 'Kalam',
|
||||
// fontFamily: 'courier',
|
||||
// fontFamily: 'arial',
|
||||
// sequence: {
|
||||
// actorFontFamily: 'courier',
|
||||
// noteFontFamily: 'courier',
|
||||
// messageFontFamily: 'courier',
|
||||
// },
|
||||
// fontSize: 12,
|
||||
// logLevel: 3,
|
||||
// securityLevel: 'loose',
|
||||
});
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
|
||||
},
|
||||
{
|
||||
name: 'fa',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/fa6-regular/icons.json').then((res) =>
|
||||
res.json()
|
||||
),
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -91,6 +91,18 @@
|
||||
<li>
|
||||
<h2><a href="./architecture.html">Architecture</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./architecture-neo.html">Architecture-neo</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./architecture-neo-dark.html">Architecture-neo-dark</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./architecture-mermaid-chart.html">Architecture-mermaid-chart</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./architecture-dark.html">Architecture-dark</a></h2>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/setup/README.md](../../../packages/mermaid/src/docs/config/setup/README.md).
|
||||
|
||||
# mermaid
|
||||
# @mermaid-chart/mermaid
|
||||
|
||||
## Modules
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ Error.prepareStackTrace
|
||||
|
||||
#### Defined in
|
||||
|
||||
node_modules/.pnpm/@types+node\@20.16.11/node_modules/@types/node/globals.d.ts:98
|
||||
node_modules/.pnpm/@types+node\@20.16.5/node_modules/@types/node/globals.d.ts:98
|
||||
|
||||
---
|
||||
|
||||
@@ -141,7 +141,7 @@ Error.stackTraceLimit
|
||||
|
||||
#### Defined in
|
||||
|
||||
node_modules/.pnpm/@types+node\@20.16.11/node_modules/@types/node/globals.d.ts:100
|
||||
node_modules/.pnpm/@types+node\@20.16.5/node_modules/@types/node/globals.d.ts:100
|
||||
|
||||
## Methods
|
||||
|
||||
@@ -168,4 +168,4 @@ Error.captureStackTrace
|
||||
|
||||
#### Defined in
|
||||
|
||||
node_modules/.pnpm/@types+node\@20.16.11/node_modules/@types/node/globals.d.ts:91
|
||||
node_modules/.pnpm/@types+node\@20.16.5/node_modules/@types/node/globals.d.ts:91
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/types.ts:148](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L148)
|
||||
[packages/mermaid/src/rendering-util/types.ts:149](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L149)
|
||||
|
||||
---
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/types.ts:147](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L147)
|
||||
[packages/mermaid/src/rendering-util/types.ts:148](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L148)
|
||||
|
||||
---
|
||||
|
||||
@@ -40,4 +40,4 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/types.ts:146](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L146)
|
||||
[packages/mermaid/src/rendering-util/types.ts:147](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L147)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/render.ts:24](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L24)
|
||||
[packages/mermaid/src/rendering-util/render.ts:25](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L25)
|
||||
|
||||
---
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/render.ts:23](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L23)
|
||||
[packages/mermaid/src/rendering-util/render.ts:24](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L24)
|
||||
|
||||
---
|
||||
|
||||
@@ -36,4 +36,4 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/render.ts:22](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L22)
|
||||
[packages/mermaid/src/rendering-util/render.ts:23](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L23)
|
||||
|
||||
@@ -122,7 +122,7 @@ This function should be called before the run function.
|
||||
|
||||
### mermaidAPI
|
||||
|
||||
• **mermaidAPI**: `Readonly`<{ `defaultConfig`: [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.defaultConfig; `getConfig`: () => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.getConfig; `getDiagramFromText`: (`text`: `string`, `metadata`: `Pick`<`DiagramMetadata`, `"title"`>) => `Promise`<`Diagram`> ; `getSiteConfig`: () => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`userOptions`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => `void` ; `parse`: (`text`: `string`, `parseOptions`: [`ParseOptions`](mermaid.ParseOptions.md) & { `suppressErrors`: `true` }) => `Promise`<[`ParseResult`](mermaid.ParseResult.md) | `false`>(`text`: `string`, `parseOptions?`: [`ParseOptions`](mermaid.ParseOptions.md)) => `Promise`<[`ParseResult`](mermaid.ParseResult.md)> ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](mermaid.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.setConfig; `updateSiteConfig`: (`conf`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.updateSiteConfig }>
|
||||
• **mermaidAPI**: `Readonly`<{ `defaultConfig`: [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.defaultConfig; `getConfig`: () => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.getConfig; `getDiagramFromText`: (`text`: `string`, `metadata`: `Pick`<`DiagramMetadata`, `"title"`>) => `Promise`<`Diagram`> ; `getSiteConfig`: () => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`userOptions`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => `void` ; `parse`: (`text`: `string`, `parseOptions`: [`ParseOptions`](mermaid.ParseOptions.md) & { `suppressErrors`: `true` }) => `Promise`<[`ParseResult`](mermaid.ParseResult.md) & { `error?`: `unknown` }>(`text`: `string`, `parseOptions?`: [`ParseOptions`](mermaid.ParseOptions.md)) => `Promise`<[`ParseResult`](mermaid.ParseResult.md)> ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`, `positions?`: `Positions`) => `Promise`<[`RenderResult`](mermaid.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.setConfig; `updateSiteConfig`: (`conf`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.updateSiteConfig }>
|
||||
|
||||
**`Deprecated`**
|
||||
|
||||
@@ -136,11 +136,11 @@ Use [parse](mermaid.Mermaid.md#parse) and [render](mermaid.Mermaid.md#render) in
|
||||
|
||||
### parse
|
||||
|
||||
• **parse**: (`text`: `string`, `parseOptions`: [`ParseOptions`](mermaid.ParseOptions.md) & { `suppressErrors`: `true` }) => `Promise`<[`ParseResult`](mermaid.ParseResult.md) | `false`>(`text`: `string`, `parseOptions?`: [`ParseOptions`](mermaid.ParseOptions.md)) => `Promise`<[`ParseResult`](mermaid.ParseResult.md)>
|
||||
• **parse**: (`text`: `string`, `parseOptions`: [`ParseOptions`](mermaid.ParseOptions.md) & { `suppressErrors`: `true` }) => `Promise`<[`ParseResult`](mermaid.ParseResult.md) & { `error?`: `unknown` }>(`text`: `string`, `parseOptions?`: [`ParseOptions`](mermaid.ParseOptions.md)) => `Promise`<[`ParseResult`](mermaid.ParseResult.md)>
|
||||
|
||||
#### Type declaration
|
||||
|
||||
▸ (`text`, `parseOptions`): `Promise`<[`ParseResult`](mermaid.ParseResult.md) | `false`>
|
||||
▸ (`text`, `parseOptions`): `Promise`<[`ParseResult`](mermaid.ParseResult.md) & { `error?`: `unknown` }>
|
||||
|
||||
Parse the text and validate the syntax.
|
||||
|
||||
@@ -153,7 +153,7 @@ Parse the text and validate the syntax.
|
||||
|
||||
##### Returns
|
||||
|
||||
`Promise`<[`ParseResult`](mermaid.ParseResult.md) | `false`>
|
||||
`Promise`<[`ParseResult`](mermaid.ParseResult.md) & { `error?`: `unknown` }>
|
||||
|
||||
An object with the `diagramType` set to type of the diagram if valid. Otherwise `false` if parseOptions.suppressErrors is `true`.
|
||||
|
||||
@@ -272,19 +272,20 @@ Used to register external diagram types.
|
||||
|
||||
### render
|
||||
|
||||
• **render**: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](mermaid.RenderResult.md)>
|
||||
• **render**: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`, `positions?`: `Positions`) => `Promise`<[`RenderResult`](mermaid.RenderResult.md)>
|
||||
|
||||
#### Type declaration
|
||||
|
||||
▸ (`id`, `text`, `svgContainingElement?`): `Promise`<[`RenderResult`](mermaid.RenderResult.md)>
|
||||
▸ (`id`, `text`, `svgContainingElement?`, `positions?`): `Promise`<[`RenderResult`](mermaid.RenderResult.md)>
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :---------------------- | :-------- |
|
||||
| `id` | `string` |
|
||||
| `text` | `string` |
|
||||
| `svgContainingElement?` | `Element` |
|
||||
| Name | Type |
|
||||
| :---------------------- | :---------- |
|
||||
| `id` | `string` |
|
||||
| `text` | `string` |
|
||||
| `svgContainingElement?` | `Element` |
|
||||
| `positions?` | `Positions` |
|
||||
|
||||
##### Returns
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:122](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L122)
|
||||
[packages/mermaid/src/config.type.ts:133](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L133)
|
||||
|
||||
---
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:194](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L194)
|
||||
[packages/mermaid/src/config.type.ts:205](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L205)
|
||||
|
||||
---
|
||||
|
||||
@@ -39,7 +39,7 @@ This matters if you are using base tag settings.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:141](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L141)
|
||||
[packages/mermaid/src/config.type.ts:152](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L152)
|
||||
|
||||
---
|
||||
|
||||
@@ -49,7 +49,7 @@ This matters if you are using base tag settings.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:201](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L201)
|
||||
[packages/mermaid/src/config.type.ts:212](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L212)
|
||||
|
||||
---
|
||||
|
||||
@@ -59,7 +59,7 @@ This matters if you are using base tag settings.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:198](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L198)
|
||||
[packages/mermaid/src/config.type.ts:209](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L209)
|
||||
|
||||
---
|
||||
|
||||
@@ -69,7 +69,7 @@ This matters if you are using base tag settings.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:187](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L187)
|
||||
[packages/mermaid/src/config.type.ts:198](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L198)
|
||||
|
||||
---
|
||||
|
||||
@@ -79,7 +79,7 @@ This matters if you are using base tag settings.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:113](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L113)
|
||||
[packages/mermaid/src/config.type.ts:124](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L124)
|
||||
|
||||
---
|
||||
|
||||
@@ -93,7 +93,7 @@ You can set this attribute to base the seed on a static string.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:181](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L181)
|
||||
[packages/mermaid/src/config.type.ts:192](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L192)
|
||||
|
||||
---
|
||||
|
||||
@@ -111,7 +111,7 @@ should not change unless content is changed.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:174](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L174)
|
||||
[packages/mermaid/src/config.type.ts:185](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L185)
|
||||
|
||||
---
|
||||
|
||||
@@ -121,7 +121,7 @@ should not change unless content is changed.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:202](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L202)
|
||||
[packages/mermaid/src/config.type.ts:213](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L213)
|
||||
|
||||
---
|
||||
|
||||
@@ -139,7 +139,7 @@ should not change unless content is changed.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:91](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L91)
|
||||
[packages/mermaid/src/config.type.ts:102](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L102)
|
||||
|
||||
---
|
||||
|
||||
@@ -149,7 +149,7 @@ should not change unless content is changed.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:189](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L189)
|
||||
[packages/mermaid/src/config.type.ts:200](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L200)
|
||||
|
||||
---
|
||||
|
||||
@@ -159,7 +159,7 @@ should not change unless content is changed.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:182](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L182)
|
||||
[packages/mermaid/src/config.type.ts:193](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L193)
|
||||
|
||||
---
|
||||
|
||||
@@ -173,7 +173,7 @@ See <https://developer.mozilla.org/en-US/docs/Web/CSS/font-family>
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:121](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L121)
|
||||
[packages/mermaid/src/config.type.ts:132](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L132)
|
||||
|
||||
---
|
||||
|
||||
@@ -183,7 +183,7 @@ See <https://developer.mozilla.org/en-US/docs/Web/CSS/font-family>
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:204](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L204)
|
||||
[packages/mermaid/src/config.type.ts:215](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L215)
|
||||
|
||||
---
|
||||
|
||||
@@ -197,7 +197,7 @@ If set to true, ignores legacyMathML.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:163](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L163)
|
||||
[packages/mermaid/src/config.type.ts:174](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L174)
|
||||
|
||||
---
|
||||
|
||||
@@ -207,7 +207,7 @@ If set to true, ignores legacyMathML.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:184](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L184)
|
||||
[packages/mermaid/src/config.type.ts:195](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L195)
|
||||
|
||||
---
|
||||
|
||||
@@ -217,7 +217,7 @@ If set to true, ignores legacyMathML.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:197](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L197)
|
||||
[packages/mermaid/src/config.type.ts:208](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L208)
|
||||
|
||||
---
|
||||
|
||||
@@ -229,7 +229,7 @@ Defines the seed to be used when using handDrawn look. This is important for the
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:76](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L76)
|
||||
[packages/mermaid/src/config.type.ts:87](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L87)
|
||||
|
||||
---
|
||||
|
||||
@@ -239,7 +239,7 @@ Defines the seed to be used when using handDrawn look. This is important for the
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:114](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L114)
|
||||
[packages/mermaid/src/config.type.ts:125](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L125)
|
||||
|
||||
---
|
||||
|
||||
@@ -249,7 +249,7 @@ Defines the seed to be used when using handDrawn look. This is important for the
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:185](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L185)
|
||||
[packages/mermaid/src/config.type.ts:196](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L196)
|
||||
|
||||
---
|
||||
|
||||
@@ -259,7 +259,7 @@ Defines the seed to be used when using handDrawn look. This is important for the
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:196](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L196)
|
||||
[packages/mermaid/src/config.type.ts:207](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L207)
|
||||
|
||||
---
|
||||
|
||||
@@ -271,7 +271,7 @@ Defines which layout algorithm to use for rendering the diagram.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:81](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L81)
|
||||
[packages/mermaid/src/config.type.ts:92](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L92)
|
||||
|
||||
---
|
||||
|
||||
@@ -286,7 +286,7 @@ fall back to legacy rendering for KaTeX.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:156](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L156)
|
||||
[packages/mermaid/src/config.type.ts:167](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L167)
|
||||
|
||||
---
|
||||
|
||||
@@ -298,19 +298,19 @@ This option decides the amount of logging to be used by mermaid.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:127](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L127)
|
||||
[packages/mermaid/src/config.type.ts:138](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L138)
|
||||
|
||||
---
|
||||
|
||||
### look
|
||||
|
||||
• `Optional` **look**: `"classic"` | `"handDrawn"`
|
||||
• `Optional` **look**: `"neo"` | `"classic"` | `"handDrawn"`
|
||||
|
||||
Defines which main look to use for the diagram.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:71](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L71)
|
||||
[packages/mermaid/src/config.type.ts:82](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L82)
|
||||
|
||||
---
|
||||
|
||||
@@ -320,7 +320,7 @@ Defines which main look to use for the diagram.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:205](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L205)
|
||||
[packages/mermaid/src/config.type.ts:216](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L216)
|
||||
|
||||
---
|
||||
|
||||
@@ -332,7 +332,7 @@ Defines the maximum number of edges that can be drawn in a graph.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:90](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L90)
|
||||
[packages/mermaid/src/config.type.ts:101](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L101)
|
||||
|
||||
---
|
||||
|
||||
@@ -344,7 +344,7 @@ The maximum allowed size of the users text diagram
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:85](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L85)
|
||||
[packages/mermaid/src/config.type.ts:96](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L96)
|
||||
|
||||
---
|
||||
|
||||
@@ -354,7 +354,7 @@ The maximum allowed size of the users text diagram
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:195](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L195)
|
||||
[packages/mermaid/src/config.type.ts:206](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L206)
|
||||
|
||||
---
|
||||
|
||||
@@ -364,7 +364,7 @@ The maximum allowed size of the users text diagram
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:200](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L200)
|
||||
[packages/mermaid/src/config.type.ts:211](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L211)
|
||||
|
||||
---
|
||||
|
||||
@@ -374,7 +374,7 @@ The maximum allowed size of the users text diagram
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:190](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L190)
|
||||
[packages/mermaid/src/config.type.ts:201](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L201)
|
||||
|
||||
---
|
||||
|
||||
@@ -384,7 +384,7 @@ The maximum allowed size of the users text diagram
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:191](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L191)
|
||||
[packages/mermaid/src/config.type.ts:202](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L202)
|
||||
|
||||
---
|
||||
|
||||
@@ -394,7 +394,7 @@ The maximum allowed size of the users text diagram
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:193](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L193)
|
||||
[packages/mermaid/src/config.type.ts:204](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L204)
|
||||
|
||||
---
|
||||
|
||||
@@ -404,7 +404,7 @@ The maximum allowed size of the users text diagram
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:199](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L199)
|
||||
[packages/mermaid/src/config.type.ts:210](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L210)
|
||||
|
||||
---
|
||||
|
||||
@@ -418,7 +418,7 @@ This prevents malicious graph directives from overriding a site's default securi
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:148](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L148)
|
||||
[packages/mermaid/src/config.type.ts:159](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L159)
|
||||
|
||||
---
|
||||
|
||||
@@ -430,7 +430,7 @@ Level of trust for parsed diagram
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:131](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L131)
|
||||
[packages/mermaid/src/config.type.ts:142](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L142)
|
||||
|
||||
---
|
||||
|
||||
@@ -440,7 +440,7 @@ Level of trust for parsed diagram
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:183](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L183)
|
||||
[packages/mermaid/src/config.type.ts:194](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L194)
|
||||
|
||||
---
|
||||
|
||||
@@ -452,7 +452,7 @@ Dictates whether mermaid starts on Page load
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:135](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L135)
|
||||
[packages/mermaid/src/config.type.ts:146](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L146)
|
||||
|
||||
---
|
||||
|
||||
@@ -462,7 +462,7 @@ Dictates whether mermaid starts on Page load
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:188](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L188)
|
||||
[packages/mermaid/src/config.type.ts:199](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L199)
|
||||
|
||||
---
|
||||
|
||||
@@ -475,13 +475,13 @@ This is useful when you want to control how to handle syntax errors in your appl
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:211](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L211)
|
||||
[packages/mermaid/src/config.type.ts:222](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L222)
|
||||
|
||||
---
|
||||
|
||||
### theme
|
||||
|
||||
• `Optional` **theme**: `"default"` | `"base"` | `"dark"` | `"forest"` | `"neutral"` | `"null"`
|
||||
• `Optional` **theme**: `"default"` | `"base"` | `"dark"` | `"forest"` | `"neutral"` | `"neo"` | `"neo-dark"` | `"redux"` | `"redux-dark"` | `"mc"` | `"null"`
|
||||
|
||||
Theme, the CSS style sheet.
|
||||
You may also use `themeCSS` to override this value.
|
||||
@@ -498,7 +498,7 @@ You may also use `themeCSS` to override this value.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:66](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L66)
|
||||
[packages/mermaid/src/config.type.ts:77](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L77)
|
||||
|
||||
---
|
||||
|
||||
@@ -508,7 +508,7 @@ You may also use `themeCSS` to override this value.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:65](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L65)
|
||||
[packages/mermaid/src/config.type.ts:76](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L76)
|
||||
|
||||
---
|
||||
|
||||
@@ -518,7 +518,7 @@ You may also use `themeCSS` to override this value.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:186](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L186)
|
||||
[packages/mermaid/src/config.type.ts:197](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L197)
|
||||
|
||||
---
|
||||
|
||||
@@ -528,7 +528,7 @@ You may also use `themeCSS` to override this value.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:203](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L203)
|
||||
[packages/mermaid/src/config.type.ts:214](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L214)
|
||||
|
||||
---
|
||||
|
||||
@@ -538,4 +538,4 @@ You may also use `themeCSS` to override this value.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:192](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L192)
|
||||
[packages/mermaid/src/config.type.ts:203](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L203)
|
||||
|
||||
@@ -19,4 +19,4 @@ The `parseError` function will not be called.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:64](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L64)
|
||||
[packages/mermaid/src/types.ts:66](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L66)
|
||||
|
||||
@@ -10,6 +10,18 @@
|
||||
|
||||
## Properties
|
||||
|
||||
### code
|
||||
|
||||
• **code**: `string`
|
||||
|
||||
The mermaid code after extracting the config.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:74](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L74)
|
||||
|
||||
---
|
||||
|
||||
### config
|
||||
|
||||
• **config**: [`MermaidConfig`](mermaid.MermaidConfig.md)
|
||||
@@ -18,16 +30,46 @@ The config passed as YAML frontmatter or directives
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:75](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L75)
|
||||
[packages/mermaid/src/types.ts:78](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L78)
|
||||
|
||||
---
|
||||
|
||||
### diagramType
|
||||
### diagram
|
||||
|
||||
• **diagramType**: `string`
|
||||
|
||||
The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
• `Optional` **diagram**: `Diagram`
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:71](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L71)
|
||||
[packages/mermaid/src/types.ts:80](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L80)
|
||||
|
||||
---
|
||||
|
||||
### error
|
||||
|
||||
• `Optional` **error**: `unknown`
|
||||
|
||||
The error that occurred during parsing, if any.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:84](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L84)
|
||||
|
||||
---
|
||||
|
||||
### success
|
||||
|
||||
• **success**: `boolean`
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:70](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L70)
|
||||
|
||||
---
|
||||
|
||||
### title
|
||||
|
||||
• `Optional` **title**: `string`
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:79](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L79)
|
||||
|
||||
@@ -39,7 +39,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:103](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L103)
|
||||
[packages/mermaid/src/types.ts:113](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L113)
|
||||
|
||||
---
|
||||
|
||||
@@ -51,7 +51,7 @@ The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:93](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L93)
|
||||
[packages/mermaid/src/types.ts:103](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L103)
|
||||
|
||||
---
|
||||
|
||||
@@ -63,4 +63,4 @@ The svg code for the rendered graph.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:89](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L89)
|
||||
[packages/mermaid/src/types.ts:99](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L99)
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/diagram-api/types.ts:130](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L130)
|
||||
[packages/mermaid/src/diagram-api/types.ts:157](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L157)
|
||||
|
||||
---
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/diagram-api/types.ts:132](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L132)
|
||||
[packages/mermaid/src/diagram-api/types.ts:159](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L159)
|
||||
|
||||
## Variables
|
||||
|
||||
@@ -88,3 +88,77 @@
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/mermaid.ts:442](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L442)
|
||||
|
||||
## Functions
|
||||
|
||||
### calcIntersect
|
||||
|
||||
▸ **calcIntersect**(`nodeId`, `point`): `Point` | `Promise`<`Point`>
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------- | :------- |
|
||||
| `nodeId` | `string` |
|
||||
| `point` | `Point` |
|
||||
|
||||
#### Returns
|
||||
|
||||
`Point` | `Promise`<`Point`>
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/layout-algorithms/fixed/index.js:172](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/layout-algorithms/fixed/index.js#L172)
|
||||
|
||||
---
|
||||
|
||||
### calcIntersections
|
||||
|
||||
▸ **calcIntersections**(`startNodeId`, `endNodeId`, `startNodeSize`, `endNodeSize`): `IntersectionPoint`\[]
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :-------------------- | :---------------------- |
|
||||
| `startNodeId` | `string` |
|
||||
| `endNodeId` | `undefined` \| `string` |
|
||||
| `startNodeSize` | `NodePosition` |
|
||||
| `endNodeSize` | `Object` |
|
||||
| `endNodeSize.height?` | `number` |
|
||||
| `endNodeSize.width?` | `number` |
|
||||
| `endNodeSize.x` | `number` |
|
||||
| `endNodeSize.y` | `number` |
|
||||
|
||||
#### Returns
|
||||
|
||||
`IntersectionPoint`\[]
|
||||
|
||||
**`Throws`**
|
||||
|
||||
If the start node doesn't exist in the nodeDB (e.g. `render` hasn't been called yet)
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/layout-algorithms/fixed/index.js:115](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/layout-algorithms/fixed/index.js#L115)
|
||||
|
||||
---
|
||||
|
||||
### calcNodeIntersections
|
||||
|
||||
▸ **calcNodeIntersections**(`targetNodeId`, `_node1`, `_node2`): `IntersectionPoint`\[] | `Promise`<`IntersectionPoint`\[]>
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------------- | :------------------------------------------------------------------------------------------------ |
|
||||
| `targetNodeId` | `any` |
|
||||
| `_node1` | `Pick`<`Node`, `"width"` \| `"height"` \| `"x"` \| `"y"` \| `"id"` \| `"shape"` \| `"intersect"`> |
|
||||
| `_node2` | `Pick`<`Node`, `"width"` \| `"height"` \| `"x"` \| `"y"` \| `"id"` \| `"shape"` \| `"intersect"`> |
|
||||
|
||||
#### Returns
|
||||
|
||||
`IntersectionPoint`\[] | `Promise`<`IntersectionPoint`\[]>
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/layout-algorithms/fixed/index.js:78](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/layout-algorithms/fixed/index.js#L78)
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^8.2.2",
|
||||
"mermaid": "workspace:*",
|
||||
"@mermaid-chart/mermaid": "workspace:*",
|
||||
"rimraf": "^5.0.5"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ExternalDiagramDefinition } from 'mermaid';
|
||||
import type { ExternalDiagramDefinition } from '@mermaid-chart/mermaid';
|
||||
|
||||
const id = 'example-diagram';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mermaid-js/layout-elk",
|
||||
"version": "0.1.7",
|
||||
"name": "@mermaid-chart/layout-elk",
|
||||
"version": "0.1.7-b.1",
|
||||
"description": "ELK layout engine for mermaid",
|
||||
"module": "dist/mermaid-layout-elk.core.mjs",
|
||||
"types": "dist/layouts.d.ts",
|
||||
@@ -34,10 +34,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/d3": "^7.4.3",
|
||||
"mermaid": "workspace:^"
|
||||
"@mermaid-chart/mermaid": "workspace:^"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"mermaid": "^11.0.0"
|
||||
"@mermaid-chart/mermaid": "^11.0.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { LayoutLoaderDefinition } from 'mermaid';
|
||||
import type { LayoutLoaderDefinition } from '@mermaid-chart/mermaid';
|
||||
|
||||
const loader = async () => await import(`./render.js`);
|
||||
const algos = ['elk.stress', 'elk.force', 'elk.mrtree', 'elk.sporeOverlap'];
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
import type {
|
||||
InternalHelpers,
|
||||
LayoutData,
|
||||
RenderOptions,
|
||||
SVG,
|
||||
SVGGroup,
|
||||
} from '@mermaid-chart/mermaid';
|
||||
// @ts-ignore TODO: Investigate D3 issue
|
||||
import { curveLinear } from 'd3';
|
||||
import ELK from 'elkjs/lib/elk.bundled.js';
|
||||
import type { InternalHelpers, LayoutData, RenderOptions, SVG, SVGGroup } from 'mermaid';
|
||||
import { type TreeData, findCommonAncestor } from './find-common-ancestor.js';
|
||||
|
||||
type Node = LayoutData['nodes'][number];
|
||||
|
||||
// Used to calculate distances in order to avoid floating number rounding issues when comparing floating numbers
|
||||
const epsilon = 0.0001;
|
||||
interface LabelData {
|
||||
width: number;
|
||||
height: number;
|
||||
@@ -17,7 +25,16 @@ interface NodeWithVertex extends Omit<Node, 'domId'> {
|
||||
labelData?: LabelData;
|
||||
domId?: Node['domId'] | SVGGroup | d3.Selection<SVGAElement, unknown, Element | null, unknown>;
|
||||
}
|
||||
|
||||
interface Point {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
function distance(p1?: Point, p2?: Point): number {
|
||||
if (!p1 || !p2) {
|
||||
return 0;
|
||||
}
|
||||
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
|
||||
}
|
||||
export const render = async (
|
||||
data4Layout: LayoutData,
|
||||
svg: SVG,
|
||||
@@ -51,17 +68,17 @@ export const render = async (
|
||||
|
||||
// Add the element to the DOM
|
||||
if (!node.isGroup) {
|
||||
const child: NodeWithVertex = {
|
||||
...node,
|
||||
};
|
||||
graph.children.push(child);
|
||||
nodeDb[node.id] = child;
|
||||
// const child: NodeWithVertex = {
|
||||
// ...node,
|
||||
// };
|
||||
graph.children.push(node);
|
||||
nodeDb[node.id] = node;
|
||||
|
||||
const childNodeEl = await insertNode(nodeEl, node, { config, dir: node.dir });
|
||||
const boundingBox = childNodeEl.node()!.getBBox();
|
||||
child.domId = childNodeEl;
|
||||
child.width = boundingBox.width;
|
||||
child.height = boundingBox.height;
|
||||
node.domId = childNodeEl;
|
||||
node.width = boundingBox.width;
|
||||
node.height = boundingBox.height;
|
||||
} else {
|
||||
// A subgraph
|
||||
const child: NodeWithVertex & { children: NodeWithVertex[] } = {
|
||||
@@ -289,7 +306,7 @@ export const render = async (
|
||||
linkIdCnt[linkIdBase]++;
|
||||
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
|
||||
}
|
||||
const linkId = linkIdBase + '_' + linkIdCnt[linkIdBase];
|
||||
const linkId = linkIdBase; // + '_' + linkIdCnt[linkIdBase];
|
||||
edge.id = linkId;
|
||||
log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);
|
||||
const linkNameStart = 'LS_' + edge.start;
|
||||
@@ -459,302 +476,6 @@ export const render = async (
|
||||
}
|
||||
}
|
||||
|
||||
function intersectLine(
|
||||
p1: { y: number; x: number },
|
||||
p2: { y: number; x: number },
|
||||
q1: { x: any; y: any },
|
||||
q2: { x: any; y: any }
|
||||
) {
|
||||
log.debug('UIO intersectLine', p1, p2, q1, q2);
|
||||
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
|
||||
// p7 and p473.
|
||||
|
||||
// let a1, a2, b1, b2, c1, c2;
|
||||
// let r1, r2, r3, r4;
|
||||
// let denom, offset, num;
|
||||
// let x, y;
|
||||
|
||||
// Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
|
||||
// b1 y + c1 = 0.
|
||||
const a1 = p2.y - p1.y;
|
||||
const b1 = p1.x - p2.x;
|
||||
const c1 = p2.x * p1.y - p1.x * p2.y;
|
||||
|
||||
// Compute r3 and r4.
|
||||
const r3 = a1 * q1.x + b1 * q1.y + c1;
|
||||
const r4 = a1 * q2.x + b1 * q2.y + c1;
|
||||
|
||||
const epsilon = 1e-6;
|
||||
|
||||
// Check signs of r3 and r4. If both point 3 and point 4 lie on
|
||||
// same side of line 1, the line segments do not intersect.
|
||||
if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {
|
||||
return /*DON'T_INTERSECT*/;
|
||||
}
|
||||
|
||||
// Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
|
||||
const a2 = q2.y - q1.y;
|
||||
const b2 = q1.x - q2.x;
|
||||
const c2 = q2.x * q1.y - q1.x * q2.y;
|
||||
|
||||
// Compute r1 and r2
|
||||
const r1 = a2 * p1.x + b2 * p1.y + c2;
|
||||
const r2 = a2 * p2.x + b2 * p2.y + c2;
|
||||
|
||||
// Check signs of r1 and r2. If both point 1 and point 2 lie
|
||||
// on same side of second line segment, the line segments do
|
||||
// not intersect.
|
||||
if (Math.abs(r1) < epsilon && Math.abs(r2) < epsilon && sameSign(r1, r2)) {
|
||||
return /*DON'T_INTERSECT*/;
|
||||
}
|
||||
|
||||
// Line segments intersect: compute intersection point.
|
||||
const denom = a1 * b2 - a2 * b1;
|
||||
if (denom === 0) {
|
||||
return /*COLLINEAR*/;
|
||||
}
|
||||
|
||||
const offset = Math.abs(denom / 2);
|
||||
|
||||
// The denom/2 is to get rounding instead of truncating. It
|
||||
// is added or subtracted to the numerator, depending upon the
|
||||
// sign of the numerator.
|
||||
let num = b1 * c2 - b2 * c1;
|
||||
const x = num < 0 ? (num - offset) / denom : (num + offset) / denom;
|
||||
|
||||
num = a2 * c1 - a1 * c2;
|
||||
const y = num < 0 ? (num - offset) / denom : (num + offset) / denom;
|
||||
|
||||
return { x: x, y: y };
|
||||
}
|
||||
|
||||
function sameSign(r1: number, r2: number) {
|
||||
return r1 * r2 > 0;
|
||||
}
|
||||
const diamondIntersection = (
|
||||
bounds: { x: any; y: any; width: any; height: any },
|
||||
outsidePoint: { x: number; y: number },
|
||||
insidePoint: any
|
||||
) => {
|
||||
const x1 = bounds.x;
|
||||
const y1 = bounds.y;
|
||||
|
||||
const w = bounds.width; //+ bounds.padding;
|
||||
const h = bounds.height; // + bounds.padding;
|
||||
|
||||
const polyPoints = [
|
||||
{ x: x1, y: y1 - h / 2 },
|
||||
{ x: x1 + w / 2, y: y1 },
|
||||
{ x: x1, y: y1 + h / 2 },
|
||||
{ x: x1 - w / 2, y: y1 },
|
||||
];
|
||||
log.debug(
|
||||
`APA16 diamondIntersection calc abc89:
|
||||
outsidePoint: ${JSON.stringify(outsidePoint)}
|
||||
insidePoint : ${JSON.stringify(insidePoint)}
|
||||
node-bounds : x:${bounds.x} y:${bounds.y} w:${bounds.width} h:${bounds.height}`,
|
||||
JSON.stringify(polyPoints)
|
||||
);
|
||||
|
||||
const intersections = [];
|
||||
|
||||
let minX = Number.POSITIVE_INFINITY;
|
||||
let minY = Number.POSITIVE_INFINITY;
|
||||
|
||||
polyPoints.forEach(function (entry) {
|
||||
minX = Math.min(minX, entry.x);
|
||||
minY = Math.min(minY, entry.y);
|
||||
});
|
||||
|
||||
const left = x1 - w / 2 - minX;
|
||||
const top = y1 - h / 2 - minY;
|
||||
|
||||
for (let i = 0; i < polyPoints.length; i++) {
|
||||
const p1 = polyPoints[i];
|
||||
const p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
|
||||
const intersect = intersectLine(
|
||||
bounds,
|
||||
outsidePoint,
|
||||
{ x: left + p1.x, y: top + p1.y },
|
||||
{ x: left + p2.x, y: top + p2.y }
|
||||
);
|
||||
|
||||
if (intersect) {
|
||||
intersections.push(intersect);
|
||||
}
|
||||
}
|
||||
|
||||
if (!intersections.length) {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
log.debug('UIO intersections', intersections);
|
||||
|
||||
if (intersections.length > 1) {
|
||||
// More intersections, find the one nearest to edge end point
|
||||
intersections.sort(function (p, q) {
|
||||
const pdx = p.x - outsidePoint.x;
|
||||
const pdy = p.y - outsidePoint.y;
|
||||
const distp = Math.sqrt(pdx * pdx + pdy * pdy);
|
||||
|
||||
const qdx = q.x - outsidePoint.x;
|
||||
const qdy = q.y - outsidePoint.y;
|
||||
const distq = Math.sqrt(qdx * qdx + qdy * qdy);
|
||||
|
||||
return distp < distq ? -1 : distp === distq ? 0 : 1;
|
||||
});
|
||||
}
|
||||
|
||||
return intersections[0];
|
||||
};
|
||||
|
||||
const intersection = (
|
||||
node: { x: any; y: any; width: number; height: number },
|
||||
outsidePoint: { x: number; y: number },
|
||||
insidePoint: { x: number; y: number }
|
||||
) => {
|
||||
log.debug(`intersection calc abc89:
|
||||
outsidePoint: ${JSON.stringify(outsidePoint)}
|
||||
insidePoint : ${JSON.stringify(insidePoint)}
|
||||
node : x:${node.x} y:${node.y} w:${node.width} h:${node.height}`);
|
||||
const x = node.x;
|
||||
const y = node.y;
|
||||
|
||||
const dx = Math.abs(x - insidePoint.x);
|
||||
// const dy = Math.abs(y - insidePoint.y);
|
||||
const w = node.width / 2;
|
||||
let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;
|
||||
const h = node.height / 2;
|
||||
|
||||
const Q = Math.abs(outsidePoint.y - insidePoint.y);
|
||||
const R = Math.abs(outsidePoint.x - insidePoint.x);
|
||||
|
||||
if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h) {
|
||||
// Intersection is top or bottom of rect.
|
||||
const q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
|
||||
r = (R * q) / Q;
|
||||
const res = {
|
||||
x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - R + r,
|
||||
y: insidePoint.y < outsidePoint.y ? insidePoint.y + Q - q : insidePoint.y - Q + q,
|
||||
};
|
||||
|
||||
if (r === 0) {
|
||||
res.x = outsidePoint.x;
|
||||
res.y = outsidePoint.y;
|
||||
}
|
||||
if (R === 0) {
|
||||
res.x = outsidePoint.x;
|
||||
}
|
||||
if (Q === 0) {
|
||||
res.y = outsidePoint.y;
|
||||
}
|
||||
|
||||
log.debug(`abc89 topp/bott calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, res); // cspell: disable-line
|
||||
|
||||
return res;
|
||||
} else {
|
||||
// Intersection onn sides of rect
|
||||
if (insidePoint.x < outsidePoint.x) {
|
||||
r = outsidePoint.x - w - x;
|
||||
} else {
|
||||
// r = outsidePoint.x - w - x;
|
||||
r = x - w - outsidePoint.x;
|
||||
}
|
||||
const q = (Q * r) / R;
|
||||
// OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x + dx - w;
|
||||
// OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;
|
||||
let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - R + r;
|
||||
// let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;
|
||||
let _y = insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q;
|
||||
log.debug(`sides calc abc89, Q ${Q}, q ${q}, R ${R}, r ${r}`, { _x, _y });
|
||||
if (r === 0) {
|
||||
_x = outsidePoint.x;
|
||||
_y = outsidePoint.y;
|
||||
}
|
||||
if (R === 0) {
|
||||
_x = outsidePoint.x;
|
||||
}
|
||||
if (Q === 0) {
|
||||
_y = outsidePoint.y;
|
||||
}
|
||||
|
||||
return { x: _x, y: _y };
|
||||
}
|
||||
};
|
||||
const outsideNode = (
|
||||
node: { x: any; y: any; width: number; height: number },
|
||||
point: { x: number; y: number }
|
||||
) => {
|
||||
const x = node.x;
|
||||
const y = node.y;
|
||||
const dx = Math.abs(point.x - x);
|
||||
const dy = Math.abs(point.y - y);
|
||||
const w = node.width / 2;
|
||||
const h = node.height / 2;
|
||||
if (dx >= w || dy >= h) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/**
|
||||
* This function will page a path and node where the last point(s) in the path is inside the node
|
||||
* and return an update path ending by the border of the node.
|
||||
*/
|
||||
const cutPathAtIntersect = (
|
||||
_points: any[],
|
||||
bounds: { x: any; y: any; width: any; height: any; padding: any },
|
||||
isDiamond: boolean
|
||||
) => {
|
||||
log.debug('APA18 cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
|
||||
const points: any[] = [];
|
||||
let lastPointOutside = _points[0];
|
||||
let isInside = false;
|
||||
_points.forEach((point: any) => {
|
||||
// check if point is inside the boundary rect
|
||||
if (!outsideNode(bounds, point) && !isInside) {
|
||||
// First point inside the rect found
|
||||
// Calc the intersection coord between the point anf the last point outside the rect
|
||||
let inter;
|
||||
|
||||
if (isDiamond) {
|
||||
const inter2 = diamondIntersection(bounds, lastPointOutside, point);
|
||||
const distance = Math.sqrt(
|
||||
(lastPointOutside.x - inter2.x) ** 2 + (lastPointOutside.y - inter2.y) ** 2
|
||||
);
|
||||
if (distance > 1) {
|
||||
inter = inter2;
|
||||
}
|
||||
}
|
||||
if (!inter) {
|
||||
inter = intersection(bounds, lastPointOutside, point);
|
||||
}
|
||||
|
||||
// Check case where the intersection is the same as the last point
|
||||
let pointPresent = false;
|
||||
points.forEach((p) => {
|
||||
pointPresent = pointPresent || (p.x === inter.x && p.y === inter.y);
|
||||
});
|
||||
// if (!pointPresent) {
|
||||
if (!points.some((e) => e.x === inter.x && e.y === inter.y)) {
|
||||
points.push(inter);
|
||||
} else {
|
||||
log.debug('abc88 no intersect', inter, points);
|
||||
}
|
||||
// points.push(inter);
|
||||
isInside = true;
|
||||
} else {
|
||||
// Outside
|
||||
log.debug('abc88 outside', point, lastPointOutside, points);
|
||||
lastPointOutside = point;
|
||||
// points.push(point);
|
||||
if (!isInside) {
|
||||
points.push(point);
|
||||
}
|
||||
}
|
||||
});
|
||||
return points;
|
||||
};
|
||||
|
||||
// @ts-ignore - ELK is not typed
|
||||
const elk = new ELK();
|
||||
const element = svg.select('g');
|
||||
@@ -766,20 +487,30 @@ export const render = async (
|
||||
id: 'root',
|
||||
layoutOptions: {
|
||||
'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
|
||||
'elk.algorithm': algorithm,
|
||||
'nodePlacement.strategy': data4Layout.config.elk?.nodePlacementStrategy,
|
||||
'elk.layered.priority.direction': 10,
|
||||
'elk.algorithm': 'elk.layered',
|
||||
// 'elk.algorithm': 'elk.stress',
|
||||
// 'partitioning.activate': true,
|
||||
// 'nodePlacement.strategy': data4Layout.config.elk?.nodePlacementStrategy,
|
||||
'elk.layered.nodePlacement.strategy': 'INTERACTIVE',
|
||||
// 'nodePlacement.strategy': 'LINEAR_SEGMENTS',
|
||||
'elk.layered.mergeEdges': data4Layout.config.elk?.mergeEdges,
|
||||
'elk.direction': 'DOWN',
|
||||
'spacing.baseValue': 35,
|
||||
'elk.layered.unnecessaryBendpoints': true,
|
||||
'elk.layered.cycleBreaking.strategy': data4Layout.config.elk?.cycleBreakingStrategy,
|
||||
// 'spacing.nodeNode': 20,
|
||||
// 'spacing.nodeNodeBetweenLayers': 25,
|
||||
// 'spacing.edgeNode': 20,
|
||||
// 'spacing.edgeNodeBetweenLayers': 10,
|
||||
// 'spacing.edgeEdge': 10,
|
||||
// 'spacing.edgeEdgeBetweenLayers': 20,
|
||||
// 'spacing.nodeSelfLoop': 20,
|
||||
// 'elk.layered.unnecessaryBendpoints': true,
|
||||
// 'elk.layered.cycleBreaking.strategy': data4Layout.config.elk?.cycleBreakingStrategy,
|
||||
// 'elk.layered.cycleBreaking.strategy': 'INTERACTIVE',
|
||||
// 'elk.layered.layering.strategy': 'MIN_WIDTH',
|
||||
// 'layering.strategy': 'SIMPLE',
|
||||
// 'layering.nodePromotion.strategy': 'NODECOUNT_PERCENTAGE',
|
||||
// 'elk.topdown.nodeType': 'PARALLEL_NODE',
|
||||
'spacing.nodeNode': 20,
|
||||
'spacing.nodeNodeBetweenLayers': 25,
|
||||
'spacing.edgeNode': 20,
|
||||
'spacing.edgeNodeBetweenLayers': 20,
|
||||
'spacing.edgeEdge': 10,
|
||||
'spacing.edgeEdgeBetweenLayers': 20,
|
||||
'spacing.nodeSelfLoop': 20,
|
||||
|
||||
// Tweaking options
|
||||
// 'elk.layered.nodePlacement.favorStraightEdges': true,
|
||||
@@ -790,14 +521,21 @@ export const render = async (
|
||||
// 'elk.layered.edgeRouting.selfLoopDistribution': 'EQUALLY',
|
||||
// 'elk.layered.mergeHierarchyEdges': true,
|
||||
// 'elk.layered.feedbackEdges': true,
|
||||
// 'elk.layered.crossingMinimization.semiInteractive': true,
|
||||
// 'elk.layered.crossingMinimization.semiInteractive': false,
|
||||
// 'crossingMinimization.semiInteractive': false,
|
||||
// 'elk.layered.edgeRouting.splines.sloppy.layerSpacingFactor': 1,
|
||||
// 'elk.layered.edgeRouting.polyline.slopedEdgeZoneWidth': 4.0,
|
||||
// 'elk.layered.wrapping.validify.strategy': 'LOOK_BACK',
|
||||
// 'elk.insideSelfLoops.activate': true,
|
||||
// 'elk.alg.layered.options.EdgeStraighteningStrategy': 'NONE',
|
||||
// 'elk.layered.considerModelOrder.strategy': 'NODES_AND_EDGES', // NODES_AND_EDGES
|
||||
// 'elk.layered.considerModelOrder.strategy': 'PREFER_NODES',
|
||||
// 'elk.layered.wrapping.cutting.strategy': 'ARD', // NODES_AND_EDGES
|
||||
// 'elk.layered.wrapping.cutting.strategy': 'NODES_AND_EDGES',
|
||||
// 'elk.alignment': 'BOTTOM',
|
||||
// 'elk.layered.nodePlacement.bk.fixedAlignment': 'RIGHTDOWN',
|
||||
// 'elk.edgeRouting': 'UNDEFINED',
|
||||
'elk.layered.crossingMinimization.forceNodeModelOrder': false,
|
||||
},
|
||||
children: [],
|
||||
edges: [],
|
||||
@@ -832,6 +570,7 @@ export const render = async (
|
||||
|
||||
// Iterate through all nodes and add the top level nodes to the graph
|
||||
const nodes = data4Layout.nodes;
|
||||
|
||||
nodes.forEach((n: { id: string | number }) => {
|
||||
const node = nodeDb[n.id];
|
||||
|
||||
@@ -850,6 +589,7 @@ export const render = async (
|
||||
'spacing.baseValue': 30,
|
||||
'nodeLabels.placement': '[H_CENTER V_TOP, INSIDE]',
|
||||
};
|
||||
|
||||
if (node.dir) {
|
||||
node.layoutOptions = {
|
||||
...node.layoutOptions,
|
||||
@@ -860,6 +600,7 @@ export const render = async (
|
||||
'elk.hierarchyHandling': 'SEPARATE_CHILDREN',
|
||||
};
|
||||
}
|
||||
|
||||
delete node.x;
|
||||
delete node.y;
|
||||
delete node.width;
|
||||
@@ -877,9 +618,7 @@ export const render = async (
|
||||
setIncludeChildrenPolicy(target, ancestorId);
|
||||
}
|
||||
});
|
||||
|
||||
const g = await elk.layout(elkGraph);
|
||||
|
||||
// debugger;
|
||||
await drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
|
||||
g.edges?.map(
|
||||
@@ -966,42 +705,44 @@ export const render = async (
|
||||
startNode.innerHTML
|
||||
);
|
||||
}
|
||||
if (startNode.shape === 'diamond' || startNode.shape === 'diam') {
|
||||
edge.points.unshift({
|
||||
x: startNode.offset.posX + startNode.width / 2,
|
||||
y: startNode.offset.posY + startNode.height / 2,
|
||||
});
|
||||
}
|
||||
if (endNode.shape === 'diamond' || endNode.shape === 'diam') {
|
||||
edge.points.push({
|
||||
x: endNode.offset.posX + endNode.width / 2,
|
||||
y: endNode.offset.posY + endNode.height / 2,
|
||||
});
|
||||
}
|
||||
if (startNode.intersect) {
|
||||
// Remove the first point of the edge points
|
||||
// edge.points.shift();
|
||||
const firstPoint = edge.points[0];
|
||||
// Transpose points to adjust for elk standard
|
||||
const adjustedFirstPoint = {
|
||||
x: firstPoint.x - startNode.width / 2,
|
||||
y: firstPoint.y - startNode.height / 2,
|
||||
};
|
||||
const intersectionRaw = startNode.intersect(adjustedFirstPoint);
|
||||
const intersection = {
|
||||
x: intersectionRaw.x + startNode.width / 2,
|
||||
y: intersectionRaw.y + startNode.height / 2,
|
||||
};
|
||||
|
||||
edge.points = cutPathAtIntersect(
|
||||
edge.points.reverse(),
|
||||
{
|
||||
x: startNode.offset.posX + startNode.width / 2,
|
||||
y: startNode.offset.posY + startNode.height / 2,
|
||||
width: sw,
|
||||
height: startNode.height,
|
||||
padding: startNode.padding,
|
||||
},
|
||||
startNode.shape === 'diamond' || startNode.shape === 'diam'
|
||||
).reverse();
|
||||
if (distance(intersection, firstPoint) > epsilon) {
|
||||
edge.points.unshift(intersection);
|
||||
}
|
||||
}
|
||||
if (endNode.intersect) {
|
||||
// Remove the last point of the edge points
|
||||
// edge.points.pop();
|
||||
|
||||
edge.points = cutPathAtIntersect(
|
||||
edge.points,
|
||||
{
|
||||
x: endNode.offset.posX + endNode.width / 2,
|
||||
y: endNode.offset.posY + endNode.height / 2,
|
||||
width: ew,
|
||||
height: endNode.height,
|
||||
padding: endNode.padding,
|
||||
},
|
||||
endNode.shape === 'diamond' || endNode.shape === 'diam'
|
||||
);
|
||||
const lastPoint = edge.points[edge.points.length - 1];
|
||||
// Transpose points to adjust for elk standard
|
||||
const adjustedLastPoint = {
|
||||
x: lastPoint.x - endNode.width / 2,
|
||||
y: lastPoint.y - endNode.height / 2,
|
||||
};
|
||||
const intersectionRaw = endNode.intersect(adjustedLastPoint);
|
||||
const intersection = {
|
||||
x: intersectionRaw.x + endNode.width / 2,
|
||||
y: intersectionRaw.y + endNode.height / 2,
|
||||
};
|
||||
if (distance(intersection, lastPoint) > epsilon) {
|
||||
edge.points.push(intersection);
|
||||
}
|
||||
}
|
||||
|
||||
const paths = insertEdge(
|
||||
edgesEl,
|
||||
@@ -1012,7 +753,6 @@ export const render = async (
|
||||
endNode,
|
||||
data4Layout.diagramId
|
||||
);
|
||||
log.info('APA12 edge points after insert', JSON.stringify(edge.points));
|
||||
|
||||
edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
|
||||
edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"@zenuml/core": "^3.23.27"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mermaid": "workspace:^"
|
||||
"@mermaid-chart/mermaid": "workspace:^"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"mermaid": "^10 || ^11"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "11.4.1",
|
||||
"name": "@mermaid-chart/mermaid",
|
||||
"version": "11.4.1-b.12",
|
||||
"description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
|
||||
"type": "module",
|
||||
"module": "./dist/mermaid.core.mjs",
|
||||
@@ -52,7 +52,7 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mermaid-js/mermaid"
|
||||
"url": "https://github.com/Mermaid-Chart/mermaid"
|
||||
},
|
||||
"author": "Knut Sveidqvist",
|
||||
"license": "MIT",
|
||||
@@ -69,7 +69,7 @@
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^7.0.1",
|
||||
"@iconify/utils": "^2.1.32",
|
||||
"@mermaid-js/parser": "workspace:^",
|
||||
"@mermaid-js/parser": "^0.3.1-rc.1",
|
||||
"@types/d3": "^7.4.3",
|
||||
"cytoscape": "^3.29.2",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
@@ -105,6 +105,8 @@
|
||||
"@types/prettier": "^3.0.0",
|
||||
"@types/stylis": "^4.2.5",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
||||
"@typescript-eslint/parser": "^7.3.1",
|
||||
"ajv": "^8.12.0",
|
||||
"chokidar": "^3.6.0",
|
||||
"concurrently": "^8.2.2",
|
||||
@@ -134,8 +136,5 @@
|
||||
"files": [
|
||||
"dist/",
|
||||
"README.md"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -53,12 +53,13 @@ import mm from 'micromatch';
|
||||
// @ts-ignore No typescript declaration file
|
||||
import flatmap from 'unist-util-flatmap';
|
||||
import { visit } from 'unist-util-visit';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// short-circuit `.schema.yaml` imports, so that we can safely import `shapes.js`
|
||||
register('./loadHook.mjs', import.meta.url);
|
||||
const { shapesDefs } = await import('../src/rendering-util/rendering-elements/shapes.js');
|
||||
|
||||
export const MERMAID_RELEASE_VERSION = JSON.parse(readFileSync('../mermaid/package.json', 'utf8'))
|
||||
const packageJsonPath = join(fileURLToPath(import.meta.url), '../../package.json');
|
||||
export const MERMAID_RELEASE_VERSION = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
|
||||
.version as string;
|
||||
const MERMAID_MAJOR_VERSION = MERMAID_RELEASE_VERSION.split('.')[0];
|
||||
const CDN_URL = 'https://cdn.jsdelivr.net/npm'; // 'https://unpkg.com';
|
||||
|
||||
@@ -53,8 +53,8 @@ export class Diagram {
|
||||
public renderer: DiagramDefinition['renderer']
|
||||
) {}
|
||||
|
||||
async render(id: string, version: string) {
|
||||
await this.renderer.draw(this.text, id, version, this);
|
||||
async render(id: string, version: string, positions?: any) {
|
||||
await this.renderer.draw(this.text, id, version, this, positions);
|
||||
}
|
||||
|
||||
getParser() {
|
||||
|
||||
@@ -61,14 +61,25 @@ export interface MermaidConfig {
|
||||
* You may also use `themeCSS` to override this value.
|
||||
*
|
||||
*/
|
||||
theme?: 'default' | 'base' | 'dark' | 'forest' | 'neutral' | 'null';
|
||||
theme?:
|
||||
| 'default'
|
||||
| 'base'
|
||||
| 'dark'
|
||||
| 'forest'
|
||||
| 'neutral'
|
||||
| 'neo'
|
||||
| 'neo-dark'
|
||||
| 'redux'
|
||||
| 'redux-dark'
|
||||
| 'mc'
|
||||
| 'null';
|
||||
themeVariables?: any;
|
||||
themeCSS?: string;
|
||||
/**
|
||||
* Defines which main look to use for the diagram.
|
||||
*
|
||||
*/
|
||||
look?: 'classic' | 'handDrawn';
|
||||
look?: 'classic' | 'handDrawn' | 'neo';
|
||||
/**
|
||||
* Defines the seed to be used when using handDrawn look. This is important for the automated tests as they will always find differences without the seed. The default value is 0 which gives a random seed.
|
||||
*
|
||||
@@ -261,7 +272,12 @@ export interface FlowchartDiagramConfig extends BaseDiagramConfig {
|
||||
* Defines how mermaid renders curves for flowcharts.
|
||||
*
|
||||
*/
|
||||
curve?: 'basis' | 'linear' | 'cardinal';
|
||||
curve?: 'basis' | 'linear' | 'cardinal' | 'rounded';
|
||||
/**
|
||||
* Highlights the points in an edge for debugging.
|
||||
*
|
||||
*/
|
||||
edgeDebug?: boolean;
|
||||
/**
|
||||
* Represents the padding between the labels and the shape
|
||||
*
|
||||
@@ -754,6 +770,11 @@ export interface StateDiagramConfig extends BaseDiagramConfig {
|
||||
edgeLengthFactor?: string;
|
||||
compositTitleSize?: number;
|
||||
radius?: number;
|
||||
/**
|
||||
* Defines how mermaid renders curves for flowcharts.
|
||||
*
|
||||
*/
|
||||
curve?: 'basis' | 'linear' | 'cardinal' | 'rounded';
|
||||
/**
|
||||
* Decides which rendering engine that is to be used for the rendering.
|
||||
*
|
||||
|
||||
@@ -15,6 +15,8 @@ const rect = (parent, node) => {
|
||||
const shapeSvg = parent
|
||||
.insert('g')
|
||||
.attr('class', 'cluster' + (node.class ? ' ' + node.class : ''))
|
||||
.attr('data-et', 'cluster')
|
||||
.attr('data-id', node.id)
|
||||
.attr('id', node.id);
|
||||
|
||||
// add the rect
|
||||
|
||||
@@ -29,6 +29,7 @@ const arrowTypesMap = {
|
||||
arrow_cross: 'cross',
|
||||
arrow_point: 'point',
|
||||
arrow_barb: 'barb',
|
||||
arrow_neo: 'barbNeo',
|
||||
arrow_circle: 'circle',
|
||||
aggregation: 'aggregation',
|
||||
extension: 'extension',
|
||||
|
||||
@@ -39,7 +39,7 @@ export const insertEdgeLabel = (elem, edge) => {
|
||||
const edgeLabel = elem.insert('g').attr('class', 'edgeLabel');
|
||||
|
||||
// Create inner g, label, this will be positioned now for centering the text
|
||||
const label = edgeLabel.insert('g').attr('class', 'label');
|
||||
const label = edgeLabel.insert('g').attr('class', 'label').attr('data-id', edge.id);
|
||||
label.node().appendChild(labelElement);
|
||||
|
||||
// Center the label
|
||||
@@ -423,6 +423,8 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
|
||||
.append('path')
|
||||
.attr('d', lineFunction(lineData))
|
||||
.attr('id', edge.id)
|
||||
// MC
|
||||
.attr('data-edge', 'true')
|
||||
.attr('class', ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : ''))
|
||||
.attr('style', edge.style);
|
||||
|
||||
|
||||
@@ -1156,6 +1156,10 @@ export const insertNode = async (elem, node, renderOptions) => {
|
||||
el.attr('class', 'node default ' + node.class);
|
||||
}
|
||||
|
||||
// MC Special
|
||||
newEl.attr('data-node', 'true');
|
||||
newEl.attr('data-id', node.id);
|
||||
|
||||
nodeElems[node.id] = newEl;
|
||||
|
||||
if (node.haveCallback) {
|
||||
|
||||
@@ -39,6 +39,7 @@ export const detectType = function (text: string, config?: MermaidConfig): strin
|
||||
.replace(directiveRegex, '')
|
||||
.replace(anyCommentRegex, '\n');
|
||||
for (const [key, { detector }] of Object.entries(detectors)) {
|
||||
console.log('APA20', key);
|
||||
const diagram = detector(text, config);
|
||||
if (diagram) {
|
||||
return key;
|
||||
|
||||
@@ -18,6 +18,7 @@ import journey from '../diagrams/user-journey/journeyDetector.js';
|
||||
import errorDiagram from '../diagrams/error/errorDiagram.js';
|
||||
import flowchartElk from '../diagrams/flowchart/elk/detector.js';
|
||||
import timeline from '../diagrams/timeline/detector.js';
|
||||
import swimlane from '../diagrams/swimlane/detector.js';
|
||||
import mindmap from '../diagrams/mindmap/detector.js';
|
||||
import kanban from '../diagrams/kanban/detector.js';
|
||||
import sankey from '../diagrams/sankey/sankeyDetector.js';
|
||||
@@ -94,6 +95,7 @@ export const addDiagrams = () => {
|
||||
packet,
|
||||
xychart,
|
||||
block,
|
||||
architecture
|
||||
architecture,
|
||||
swimlane
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { addDetector } from './detectType.js';
|
||||
import { log as _log, setLogLevel as _setLogLevel } from '../logger.js';
|
||||
import {
|
||||
defaultConfig as _defaultConfig,
|
||||
getConfig as _getConfig,
|
||||
setConfig as _setConfig,
|
||||
defaultConfig as _defaultConfig,
|
||||
setSiteConfig as _setSiteConfig,
|
||||
} from '../config.js';
|
||||
import { sanitizeText as _sanitizeText } from '../diagrams/common/common.js';
|
||||
import * as _commonDb from '../diagrams/common/commonDb.js';
|
||||
import { log as _log, setLogLevel as _setLogLevel } from '../logger.js';
|
||||
import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox.js';
|
||||
import { addStylesForDiagram } from '../styles.js';
|
||||
import { addDetector } from './detectType.js';
|
||||
import type { DiagramDefinition, DiagramDetector } from './types.js';
|
||||
import * as _commonDb from '../diagrams/common/commonDb.js';
|
||||
|
||||
/*
|
||||
Packaging and exposing resources for external diagrams so that they can import
|
||||
|
||||
@@ -105,6 +105,30 @@ export interface ExternalDiagramDefinition {
|
||||
export type DiagramDetector = (text: string, config?: MermaidConfig) => boolean;
|
||||
export type DiagramLoader = () => Promise<{ id: string; diagram: DiagramDefinition }>;
|
||||
|
||||
/* Types for the positions used in the free layout engine */
|
||||
interface Point {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface IntersectionPoint extends Point {
|
||||
pos: 't' | 'b' | 'l' | 'r';
|
||||
}
|
||||
|
||||
export interface NodePosition extends Point {
|
||||
width?: number;
|
||||
height?: number;
|
||||
}
|
||||
|
||||
export interface EdgePoints {
|
||||
points: Point[];
|
||||
}
|
||||
|
||||
export interface Positions {
|
||||
nodes: Record<string, NodePosition>;
|
||||
edges: Record<string, EdgePoints>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type for function draws diagram in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
@@ -117,7 +141,10 @@ export type DrawDefinition = (
|
||||
text: string,
|
||||
id: string,
|
||||
version: string,
|
||||
diagramObject: Diagram
|
||||
diagramObject: Diagram,
|
||||
// Todo: types from positions when logic is done
|
||||
// MC Special
|
||||
positions?: any
|
||||
) => void | Promise<void>;
|
||||
|
||||
export interface ParserDefinition {
|
||||
|
||||
@@ -20,10 +20,10 @@ const getStyles: DiagramStylesProvider = (options: ArchitectureStyleOptions) =>
|
||||
stroke-dasharray: 8;
|
||||
}
|
||||
.node-icon-text {
|
||||
display: flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
.node-icon-text > div {
|
||||
color: #fff;
|
||||
margin: 1px;
|
||||
@@ -33,6 +33,9 @@ const getStyles: DiagramStylesProvider = (options: ArchitectureStyleOptions) =>
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
.architecture-services, .architecture-edges, .architecture-groups {
|
||||
font-size: 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
||||
|
||||
@@ -105,7 +105,6 @@ const getStyles = (options: BlockChartStyleOptions) =>
|
||||
}
|
||||
|
||||
.node .cluster {
|
||||
// fill: ${fade(options.mainBkg, 0.5)};
|
||||
fill: ${fade(options.clusterBkg, 0.5)};
|
||||
stroke: ${fade(options.clusterBorder, 0.2)};
|
||||
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
|
||||
|
||||
@@ -38,7 +38,13 @@ export const getClasses = function (
|
||||
return diagramObj.db.getClasses();
|
||||
};
|
||||
|
||||
export const draw = async function (text: string, id: string, _version: string, diag: any) {
|
||||
export const draw = async function (
|
||||
text: string,
|
||||
id: string,
|
||||
_version: string,
|
||||
diag: any,
|
||||
positions: any
|
||||
) {
|
||||
log.info('REF0:');
|
||||
log.info('Drawing class diagram (v3)', id);
|
||||
const { securityLevel, state: conf, layout } = getConfig();
|
||||
@@ -60,7 +66,7 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
data4Layout.rankSpacing = conf?.rankSpacing || 50;
|
||||
data4Layout.markers = ['aggregation', 'extension', 'composition', 'dependency', 'lollipop'];
|
||||
data4Layout.diagramId = id;
|
||||
await render(data4Layout, svg);
|
||||
await render(data4Layout, svg, positions);
|
||||
const padding = 8;
|
||||
utils.insertTitle(
|
||||
svg,
|
||||
|
||||
@@ -960,6 +960,7 @@ You have to call mermaid.initialize.`
|
||||
let arrowTypeStart = 'none';
|
||||
let arrowTypeEnd = 'arrow_point';
|
||||
switch (type) {
|
||||
case 'arrow_open':
|
||||
case 'arrow_point':
|
||||
case 'arrow_circle':
|
||||
case 'arrow_cross':
|
||||
@@ -1096,6 +1097,7 @@ You have to call mermaid.initialize.`
|
||||
if (rawEdge.style) {
|
||||
styles.push(...rawEdge.style);
|
||||
}
|
||||
|
||||
const edge: Edge = {
|
||||
id: getEdgeId(rawEdge.start, rawEdge.end, { counter: index, prefix: 'L' }, rawEdge.id),
|
||||
isUserDefinedId: rawEdge.isUserDefinedId,
|
||||
@@ -1122,6 +1124,8 @@ You have to call mermaid.initialize.`
|
||||
style: styles,
|
||||
pattern: rawEdge.stroke,
|
||||
look: config.look,
|
||||
curve: config.flowchart?.curve,
|
||||
showPoints: config.flowchart?.edgeDebug,
|
||||
animate: rawEdge.animate,
|
||||
animation: rawEdge.animation,
|
||||
};
|
||||
|
||||
@@ -15,7 +15,13 @@ export const getClasses = function (
|
||||
return diagramObj.db.getClasses();
|
||||
};
|
||||
|
||||
export const draw = async function (text: string, id: string, _version: string, diag: any) {
|
||||
export const draw = async function (
|
||||
text: string,
|
||||
id: string,
|
||||
_version: string,
|
||||
diag: any,
|
||||
positions: any
|
||||
) {
|
||||
log.info('REF0:');
|
||||
log.info('Drawing state diagram (v2)', id);
|
||||
const { securityLevel, flowchart: conf, layout } = getConfig();
|
||||
@@ -40,6 +46,7 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
|
||||
data4Layout.type = diag.type;
|
||||
data4Layout.layoutAlgorithm = getRegisteredLayoutAlgorithm(layout);
|
||||
|
||||
if (data4Layout.layoutAlgorithm === 'dagre' && layout === 'elk') {
|
||||
log.warn(
|
||||
'flowchart-elk was moved to an external package in Mermaid v11. Please refer [release notes](https://github.com/mermaid-js/mermaid/releases/tag/v11.0.0) for more details. This diagram will be rendered using `dagre` layout as a fallback.'
|
||||
@@ -52,7 +59,7 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
|
||||
data4Layout.diagramId = id;
|
||||
log.debug('REF1:', data4Layout);
|
||||
await render(data4Layout, svg);
|
||||
await render(data4Layout, svg, positions);
|
||||
const padding = data4Layout.config.flowchart?.diagramPadding ?? 8;
|
||||
utils.insertTitle(
|
||||
svg,
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface FlowChartStyleOptions {
|
||||
tertiaryColor: string;
|
||||
textColor: string;
|
||||
titleColor: string;
|
||||
strokeWidth: string;
|
||||
}
|
||||
|
||||
const fade = (color: string, opacity: number) => {
|
||||
@@ -57,17 +58,11 @@ const getStyles = (options: FlowChartStyleOptions) =>
|
||||
.node path {
|
||||
fill: ${options.mainBkg};
|
||||
stroke: ${options.nodeBorder};
|
||||
stroke-width: 1px;
|
||||
stroke-width: ${options.strokeWidth}px;
|
||||
}
|
||||
.rough-node .label text , .node .label text, .image-shape .label, .icon-shape .label {
|
||||
text-anchor: middle;
|
||||
}
|
||||
// .flowchart-label .text-outer-tspan {
|
||||
// text-anchor: middle;
|
||||
// }
|
||||
// .flowchart-label .text-inner-tspan {
|
||||
// text-anchor: start;
|
||||
// }
|
||||
|
||||
.node .katex path {
|
||||
fill: #000;
|
||||
@@ -95,7 +90,7 @@ const getStyles = (options: FlowChartStyleOptions) =>
|
||||
|
||||
.edgePath .path {
|
||||
stroke: ${options.lineColor};
|
||||
stroke-width: 2.0px;
|
||||
stroke-width: ${options.strokeWidth}px;
|
||||
}
|
||||
|
||||
.flowchart-link {
|
||||
@@ -125,7 +120,7 @@ const getStyles = (options: FlowChartStyleOptions) =>
|
||||
.cluster rect {
|
||||
fill: ${options.clusterBkg};
|
||||
stroke: ${options.clusterBorder};
|
||||
stroke-width: 1px;
|
||||
stroke-width: ${options.strokeWidth}px;
|
||||
}
|
||||
|
||||
.cluster text {
|
||||
|
||||
@@ -237,7 +237,7 @@ interface NoteModel {
|
||||
* @param elem - The diagram to draw to.
|
||||
* @param noteModel - Note model options.
|
||||
*/
|
||||
const drawNote = async function (elem: any, noteModel: NoteModel) {
|
||||
const drawNote = async function (elem: any, noteModel: NoteModel, id: string) {
|
||||
bounds.bumpVerticalPos(conf.boxMargin);
|
||||
noteModel.height = conf.boxMargin;
|
||||
noteModel.starty = bounds.getVerticalPos();
|
||||
@@ -248,6 +248,8 @@ const drawNote = async function (elem: any, noteModel: NoteModel) {
|
||||
rect.class = 'note';
|
||||
|
||||
const g = elem.append('g');
|
||||
g.attr('data-et', 'note');
|
||||
g.attr('data-id', 'i' + id);
|
||||
const rectElem = svgDraw.drawRect(g, rect);
|
||||
const textObj = svgDrawCommon.getTextObj();
|
||||
textObj.x = noteModel.startx;
|
||||
@@ -447,6 +449,11 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
line.attr('class', 'messageLine0');
|
||||
}
|
||||
|
||||
line.attr('data-et', 'message');
|
||||
line.attr('data-id', 'i' + msgModel.id);
|
||||
line.attr('data-from', msgModel.from);
|
||||
line.attr('data-to', msgModel.to);
|
||||
|
||||
let url = '';
|
||||
if (conf.arrowMarkerAbsolute) {
|
||||
url =
|
||||
@@ -865,7 +872,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
case diagObj.db.LINETYPE.NOTE:
|
||||
bounds.resetVerticalPos();
|
||||
noteModel = msg.noteModel;
|
||||
await drawNote(diagram, noteModel);
|
||||
await drawNote(diagram, noteModel, msg.id);
|
||||
break;
|
||||
case diagObj.db.LINETYPE.ACTIVE_START:
|
||||
bounds.newActivation(msg, diagram, actors);
|
||||
@@ -884,7 +891,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
break;
|
||||
case diagObj.db.LINETYPE.LOOP_END:
|
||||
loopModel = bounds.endLoop();
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'loop', conf);
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'loop', conf, msg);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
bounds.models.addLoop(loopModel);
|
||||
break;
|
||||
@@ -910,7 +917,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
break;
|
||||
case diagObj.db.LINETYPE.OPT_END:
|
||||
loopModel = bounds.endLoop();
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'opt', conf);
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'opt', conf, msg);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
bounds.models.addLoop(loopModel);
|
||||
break;
|
||||
@@ -934,7 +941,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
break;
|
||||
case diagObj.db.LINETYPE.ALT_END:
|
||||
loopModel = bounds.endLoop();
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'alt', conf);
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'alt', conf, msg);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
bounds.models.addLoop(loopModel);
|
||||
break;
|
||||
@@ -960,7 +967,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
break;
|
||||
case diagObj.db.LINETYPE.PAR_END:
|
||||
loopModel = bounds.endLoop();
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'par', conf);
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'par', conf, msg);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
bounds.models.addLoop(loopModel);
|
||||
break;
|
||||
@@ -993,7 +1000,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
break;
|
||||
case diagObj.db.LINETYPE.CRITICAL_END:
|
||||
loopModel = bounds.endLoop();
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'critical', conf);
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'critical', conf, msg);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
bounds.models.addLoop(loopModel);
|
||||
break;
|
||||
@@ -1008,7 +1015,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
break;
|
||||
case diagObj.db.LINETYPE.BREAK_END:
|
||||
loopModel = bounds.endLoop();
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'break', conf);
|
||||
await svgDraw.drawLoop(diagram, loopModel, 'break', conf, msg);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
bounds.models.addLoop(loopModel);
|
||||
break;
|
||||
@@ -1018,6 +1025,9 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
msgModel.starty = bounds.getVerticalPos();
|
||||
msgModel.sequenceIndex = sequenceIndex;
|
||||
msgModel.sequenceVisible = diagObj.db.showSequenceNumbers();
|
||||
msgModel.id = msg.id;
|
||||
msgModel.from = msg.from;
|
||||
msgModel.to = msg.to;
|
||||
const lineStartY = await boundMessage(diagram, msgModel);
|
||||
adjustCreatedDestroyedData(
|
||||
msg,
|
||||
@@ -1087,6 +1097,18 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
const requiredBoxSize = drawActorsPopup(diagram, actors, actorKeys, doc);
|
||||
|
||||
const { bounds: box } = bounds.getBounds();
|
||||
if (box.startx === undefined) {
|
||||
box.startx = 0;
|
||||
}
|
||||
if (box.starty === undefined) {
|
||||
box.starty = 0;
|
||||
}
|
||||
if (box.stopx === undefined) {
|
||||
box.stopx = 0;
|
||||
}
|
||||
if (box.stopy === undefined) {
|
||||
box.stopy = 0;
|
||||
}
|
||||
|
||||
if (box.startx === undefined) {
|
||||
box.startx = 0;
|
||||
|
||||
@@ -348,7 +348,9 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
|
||||
.attr('class', 'actor-line 200')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999')
|
||||
.attr('name', actor.name);
|
||||
.attr('name', actor.name)
|
||||
.attr('data-et', 'life-line')
|
||||
.attr('data-id', actor.name);
|
||||
|
||||
g = boxplusLineGroup.append('g');
|
||||
actor.actorCnt = actorCnt;
|
||||
@@ -390,6 +392,11 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFooter) {
|
||||
g.attr('data-et', 'participant');
|
||||
g.attr('data-id', actor.name);
|
||||
}
|
||||
|
||||
_drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
actor.description,
|
||||
g,
|
||||
@@ -430,7 +437,9 @@ const drawActorTypeActor = function (elem, actor, conf, isFooter) {
|
||||
.attr('class', 'actor-line 200')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999')
|
||||
.attr('name', actor.name);
|
||||
.attr('name', actor.name)
|
||||
.attr('data-et', 'life-line')
|
||||
.attr('data-id', actor.name);
|
||||
|
||||
actor.actorCnt = actorCnt;
|
||||
}
|
||||
@@ -444,6 +453,10 @@ const drawActorTypeActor = function (elem, actor, conf, isFooter) {
|
||||
actElem.attr('class', cssClass);
|
||||
actElem.attr('name', actor.name);
|
||||
|
||||
if (!isFooter) {
|
||||
actElem.attr('data-et', 'participant').attr('data-id', actor.name);
|
||||
}
|
||||
|
||||
const rect = svgDrawCommon.getNoteRect();
|
||||
rect.x = actor.x;
|
||||
rect.y = actorY;
|
||||
@@ -567,7 +580,7 @@ export const drawActivation = function (elem, bounds, verticalPos, conf, actorAc
|
||||
* @param {any} conf - Diagram configuration
|
||||
* @returns {any}
|
||||
*/
|
||||
export const drawLoop = async function (elem, loopModel, labelText, conf) {
|
||||
export const drawLoop = async function (elem, loopModel, labelText, conf, msg) {
|
||||
const {
|
||||
boxMargin,
|
||||
boxTextMargin,
|
||||
@@ -577,7 +590,10 @@ export const drawLoop = async function (elem, loopModel, labelText, conf) {
|
||||
messageFontSize: fontSize,
|
||||
messageFontWeight: fontWeight,
|
||||
} = conf;
|
||||
const g = elem.append('g');
|
||||
const g = elem
|
||||
.append('g')
|
||||
.attr('data-et', 'control-structure')
|
||||
.attr('data-id', 'i' + msg.id);
|
||||
const drawLoopLine = function (startx, starty, stopx, stopy) {
|
||||
return g
|
||||
.append('line')
|
||||
|
||||
@@ -54,16 +54,46 @@ export function stateDomId(itemId = '', counter = 0, type = '', typeSpacer = DOM
|
||||
return `${DOMID_STATE}-${itemId}${typeStr}-${counter}`;
|
||||
}
|
||||
|
||||
const setupDoc = (parentParsedItem, doc, diagramStates, nodes, edges, altFlag, look, classes) => {
|
||||
const setupDoc = (
|
||||
parentParsedItem,
|
||||
doc,
|
||||
diagramStates,
|
||||
nodes,
|
||||
edges,
|
||||
altFlag,
|
||||
look,
|
||||
classes,
|
||||
config
|
||||
) => {
|
||||
// graphItemCount = 0;
|
||||
log.trace('items', doc);
|
||||
doc.forEach((item) => {
|
||||
switch (item.stmt) {
|
||||
case STMT_STATE:
|
||||
dataFetcher(parentParsedItem, item, diagramStates, nodes, edges, altFlag, look, classes);
|
||||
dataFetcher(
|
||||
parentParsedItem,
|
||||
item,
|
||||
diagramStates,
|
||||
nodes,
|
||||
edges,
|
||||
altFlag,
|
||||
look,
|
||||
classes,
|
||||
config
|
||||
);
|
||||
break;
|
||||
case DEFAULT_STATE_TYPE:
|
||||
dataFetcher(parentParsedItem, item, diagramStates, nodes, edges, altFlag, look, classes);
|
||||
dataFetcher(
|
||||
parentParsedItem,
|
||||
item,
|
||||
diagramStates,
|
||||
nodes,
|
||||
edges,
|
||||
altFlag,
|
||||
look,
|
||||
classes,
|
||||
config
|
||||
);
|
||||
break;
|
||||
case STMT_RELATION:
|
||||
{
|
||||
@@ -75,7 +105,8 @@ const setupDoc = (parentParsedItem, doc, diagramStates, nodes, edges, altFlag, l
|
||||
edges,
|
||||
altFlag,
|
||||
look,
|
||||
classes
|
||||
classes,
|
||||
config
|
||||
);
|
||||
dataFetcher(
|
||||
parentParsedItem,
|
||||
@@ -85,7 +116,8 @@ const setupDoc = (parentParsedItem, doc, diagramStates, nodes, edges, altFlag, l
|
||||
edges,
|
||||
altFlag,
|
||||
look,
|
||||
classes
|
||||
classes,
|
||||
config
|
||||
);
|
||||
const edgeData = {
|
||||
id: 'edge' + graphItemCount,
|
||||
@@ -102,6 +134,7 @@ const setupDoc = (parentParsedItem, doc, diagramStates, nodes, edges, altFlag, l
|
||||
thickness: G_EDGE_THICKNESS,
|
||||
classes: CSS_EDGE,
|
||||
look,
|
||||
curve: config.state?.curve,
|
||||
};
|
||||
edges.push(edgeData);
|
||||
graphItemCount++;
|
||||
@@ -181,7 +214,8 @@ export const dataFetcher = (
|
||||
edges,
|
||||
altFlag,
|
||||
look,
|
||||
classes
|
||||
classes,
|
||||
config
|
||||
) => {
|
||||
const itemId = parsedItem.id;
|
||||
const dbState = diagramStates.get(itemId);
|
||||
@@ -362,6 +396,7 @@ export const dataFetcher = (
|
||||
labelType: G_EDGE_LABELTYPE,
|
||||
thickness: G_EDGE_THICKNESS,
|
||||
look,
|
||||
curve: config.state?.curve,
|
||||
});
|
||||
} else {
|
||||
insertOrUpdateNode(nodes, nodeData, classes);
|
||||
@@ -369,7 +404,17 @@ export const dataFetcher = (
|
||||
}
|
||||
if (parsedItem.doc) {
|
||||
log.trace('Adding nodes children ');
|
||||
setupDoc(parsedItem, parsedItem.doc, diagramStates, nodes, edges, !altFlag, look, classes);
|
||||
setupDoc(
|
||||
parsedItem,
|
||||
parsedItem.doc,
|
||||
diagramStates,
|
||||
nodes,
|
||||
edges,
|
||||
!altFlag,
|
||||
look,
|
||||
classes,
|
||||
config
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ const extract = (_doc) => {
|
||||
const config = getConfig();
|
||||
const look = config.look;
|
||||
resetDataFetching();
|
||||
dataFetcher(undefined, getRootDocV2(), diagramStates, nodes, edges, true, look, classes);
|
||||
dataFetcher(undefined, getRootDocV2(), diagramStates, nodes, edges, true, look, classes, config);
|
||||
nodes.forEach((node) => {
|
||||
if (Array.isArray(node.label)) {
|
||||
// add the rest as description
|
||||
|
||||
@@ -40,9 +40,16 @@ export const getClasses = function (
|
||||
return diagramObj.db.getClasses();
|
||||
};
|
||||
|
||||
export const draw = async function (text: string, id: string, _version: string, diag: any) {
|
||||
log.info('REF0:');
|
||||
export const draw = async function (
|
||||
text: string,
|
||||
id: string,
|
||||
_version: string,
|
||||
diag: any,
|
||||
positions: any
|
||||
) {
|
||||
log.info('REF0:', positions);
|
||||
log.info('Drawing state diagram (v2)', id);
|
||||
log.info('Diagram Configuration:', getConfig());
|
||||
const { securityLevel, state: conf, layout } = getConfig();
|
||||
// Extracting the data from the parsed structure into a more usable form
|
||||
// Not related to the refactoring, but this is the first step in the rendering process
|
||||
@@ -64,10 +71,14 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
|
||||
data4Layout.nodeSpacing = conf?.nodeSpacing || 50;
|
||||
data4Layout.rankSpacing = conf?.rankSpacing || 50;
|
||||
data4Layout.markers = ['barb'];
|
||||
const config = getConfig();
|
||||
if (config.look === 'neo') {
|
||||
data4Layout.markers = ['barbNeo'];
|
||||
} else {
|
||||
data4Layout.markers = ['barb'];
|
||||
}
|
||||
data4Layout.diagramId = id;
|
||||
// console.log('REF1:', data4Layout);
|
||||
await render(data4Layout, svg);
|
||||
await render(data4Layout, svg, positions);
|
||||
const padding = 8;
|
||||
utils.insertTitle(
|
||||
svg,
|
||||
|
||||
@@ -104,14 +104,21 @@ g.stateGroup line {
|
||||
}
|
||||
|
||||
.node circle.state-end {
|
||||
fill: ${options.innerEndBackground};
|
||||
fill: ${options.stateBkg || options.mainBkg};
|
||||
stroke: ${options.background};
|
||||
stroke-width: 1.5
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
|
||||
[data-look="neo"].node circle.state-end {
|
||||
filter: none;
|
||||
stroke:${options.background};
|
||||
fill: ${options.lineColor};
|
||||
}
|
||||
|
||||
.end-state-inner {
|
||||
fill: ${options.compositeBackground || options.background};
|
||||
// stroke: ${options.background};
|
||||
stroke-width: 1.5
|
||||
stroke: ${options.background};
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
|
||||
.node rect {
|
||||
@@ -119,6 +126,13 @@ g.stateGroup line {
|
||||
stroke: ${options.stateBorder || options.nodeBorder};
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.node-rect-neo {
|
||||
fill: ${options.stateBkg || options.mainBkg};
|
||||
stroke: none;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.node polygon {
|
||||
fill: ${options.mainBkg};
|
||||
stroke: ${options.stateBorder || options.nodeBorder};;
|
||||
@@ -136,26 +150,26 @@ g.stateGroup line {
|
||||
|
||||
.cluster-label, .nodeLabel {
|
||||
color: ${options.stateLabelColor};
|
||||
// line-height: 1;
|
||||
line-height: 1.0;
|
||||
}
|
||||
|
||||
.statediagram-cluster rect.outer {
|
||||
rx: 5px;
|
||||
ry: 5px;
|
||||
rx: ${options.radius}px;
|
||||
ry: ${options.radius}px;
|
||||
}
|
||||
.statediagram-state .divider {
|
||||
stroke: ${options.stateBorder || options.nodeBorder};
|
||||
}
|
||||
|
||||
.statediagram-state .title-state {
|
||||
rx: 5px;
|
||||
ry: 5px;
|
||||
rx: ${options.radius}px;
|
||||
ry: ${options.radius}px;
|
||||
}
|
||||
.statediagram-cluster.statediagram-cluster .inner {
|
||||
fill: ${options.compositeBackground || options.background};
|
||||
}
|
||||
.statediagram-cluster.statediagram-cluster-alt .inner {
|
||||
fill: ${options.altBackground ? options.altBackground : '#efefef'};
|
||||
fill: ${options.altBackground ? options.altBackground : '#f0f0f0'};
|
||||
}
|
||||
|
||||
.statediagram-cluster .inner {
|
||||
@@ -164,9 +178,16 @@ g.stateGroup line {
|
||||
}
|
||||
|
||||
.statediagram-state rect.basic {
|
||||
rx: 5px;
|
||||
ry: 5px;
|
||||
rx: ${options.radius}px;
|
||||
ry: ${options.radius}px;
|
||||
}
|
||||
|
||||
|
||||
.state-shadow-neo {
|
||||
filter: ${options.dropShadow};
|
||||
}
|
||||
|
||||
|
||||
.statediagram-state rect.divider {
|
||||
stroke-dasharray: 10,10;
|
||||
fill: ${options.altBackground ? options.altBackground : '#efefef'};
|
||||
@@ -198,6 +219,11 @@ g.stateGroup line {
|
||||
.statediagram-note .nodeLabel {
|
||||
color: ${options.noteTextColor};
|
||||
}
|
||||
|
||||
.node.statediagram-note rect {
|
||||
stroke: ${options.noteBorderColor} !important;
|
||||
}
|
||||
|
||||
.statediagram .edgeLabel {
|
||||
color: red; // ${options.noteTextColor};
|
||||
}
|
||||
|
||||
24
packages/mermaid/src/diagrams/swimlane/detector.ts
Normal file
24
packages/mermaid/src/diagrams/swimlane/detector.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'swimlane';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return /^\s*swimlane/.test(txt);
|
||||
};
|
||||
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./swimlaneDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
const plugin: ExternalDiagramDefinition = {
|
||||
id,
|
||||
detector,
|
||||
loader,
|
||||
};
|
||||
|
||||
export default plugin;
|
||||
67
packages/mermaid/src/diagrams/swimlane/flowDb.spec.ts
Normal file
67
packages/mermaid/src/diagrams/swimlane/flowDb.spec.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import flowDb from './flowDb.js';
|
||||
import type { FlowSubGraph } from './types.js';
|
||||
|
||||
describe('flow db subgraphs', () => {
|
||||
let subgraphs: FlowSubGraph[];
|
||||
beforeEach(() => {
|
||||
subgraphs = [
|
||||
{ nodes: ['a', 'b', 'c', 'e'] },
|
||||
{ nodes: ['f', 'g', 'h'] },
|
||||
{ nodes: ['i', 'j'] },
|
||||
{ nodes: ['k'] },
|
||||
] as FlowSubGraph[];
|
||||
});
|
||||
describe('exist', () => {
|
||||
it('should return true when the is exists in a subgraph', () => {
|
||||
expect(flowDb.exists(subgraphs, 'a')).toBe(true);
|
||||
expect(flowDb.exists(subgraphs, 'h')).toBe(true);
|
||||
expect(flowDb.exists(subgraphs, 'j')).toBe(true);
|
||||
expect(flowDb.exists(subgraphs, 'k')).toBe(true);
|
||||
});
|
||||
it('should return false when the is exists in a subgraph', () => {
|
||||
expect(flowDb.exists(subgraphs, 'a2')).toBe(false);
|
||||
expect(flowDb.exists(subgraphs, 'l')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('makeUniq', () => {
|
||||
it('should remove ids from sungraph that already exists in another subgraph even if it gets empty', () => {
|
||||
const subgraph = flowDb.makeUniq({ nodes: ['i', 'j'] } as FlowSubGraph, subgraphs);
|
||||
|
||||
expect(subgraph.nodes).toEqual([]);
|
||||
});
|
||||
it('should remove ids from sungraph that already exists in another subgraph', () => {
|
||||
const subgraph = flowDb.makeUniq({ nodes: ['i', 'j', 'o'] } as FlowSubGraph, subgraphs);
|
||||
|
||||
expect(subgraph.nodes).toEqual(['o']);
|
||||
});
|
||||
it('should not remove ids from subgraph if they are unique', () => {
|
||||
const subgraph = flowDb.makeUniq({ nodes: ['q', 'r', 's'] } as FlowSubGraph, subgraphs);
|
||||
|
||||
expect(subgraph.nodes).toEqual(['q', 'r', 's']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('flow db addClass', () => {
|
||||
beforeEach(() => {
|
||||
flowDb.clear();
|
||||
});
|
||||
it('should detect many classes', () => {
|
||||
flowDb.addClass('a,b', ['stroke-width: 8px']);
|
||||
const classes = flowDb.getClasses();
|
||||
|
||||
expect(classes.has('a')).toBe(true);
|
||||
expect(classes.has('b')).toBe(true);
|
||||
expect(classes.get('a')?.styles).toEqual(['stroke-width: 8px']);
|
||||
expect(classes.get('b')?.styles).toEqual(['stroke-width: 8px']);
|
||||
});
|
||||
|
||||
it('should detect single class', () => {
|
||||
flowDb.addClass('a', ['stroke-width: 8px']);
|
||||
const classes = flowDb.getClasses();
|
||||
|
||||
expect(classes.has('a')).toBe(true);
|
||||
expect(classes.get('a')?.styles).toEqual(['stroke-width: 8px']);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import plugin from './detector.js';
|
||||
import { describe, it } from 'vitest';
|
||||
|
||||
const { detector } = plugin;
|
||||
|
||||
describe('swimlane detector', () => {
|
||||
it('should fail for dagre-d3', () => {
|
||||
expect(
|
||||
detector('swimlane', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'dagre-d3',
|
||||
},
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
it('should fail for dagre-wrapper', () => {
|
||||
expect(
|
||||
detector('flowchart', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'dagre-wrapper',
|
||||
},
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
it('should succeed for elk', () => {
|
||||
expect(
|
||||
detector('flowchart', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'elk',
|
||||
},
|
||||
})
|
||||
).toBe(true);
|
||||
expect(
|
||||
detector('graph', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'elk',
|
||||
},
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should detect swimlane', () => {
|
||||
expect(detector('swimlane')).toBe(true);
|
||||
});
|
||||
|
||||
it('should not detect class with defaultRenderer set to elk', () => {
|
||||
expect(
|
||||
detector('class', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'elk',
|
||||
},
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
import type {
|
||||
ExternalDiagramDefinition,
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
} from '../../../diagram-api/types.js';
|
||||
const id = 'swimlane';
|
||||
|
||||
|
||||
const detector: DiagramDetector = (txt, config): boolean => {
|
||||
if (txt.match(/^\s*swimlane/)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./swimlane-definition.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
const plugin: ExternalDiagramDefinition = {
|
||||
id,
|
||||
detector,
|
||||
loader,
|
||||
};
|
||||
|
||||
export default plugin;
|
||||
@@ -0,0 +1,40 @@
|
||||
import { findCommonAncestor, TreeData } from './render-utils.js';
|
||||
describe('when rendering a flowchart using elk ', () => {
|
||||
let lookupDb: TreeData;
|
||||
beforeEach(() => {
|
||||
lookupDb = {
|
||||
parentById: {
|
||||
B4: 'inner',
|
||||
B5: 'inner',
|
||||
C4: 'inner2',
|
||||
C5: 'inner2',
|
||||
B2: 'Ugge',
|
||||
B3: 'Ugge',
|
||||
inner: 'Ugge',
|
||||
inner2: 'Ugge',
|
||||
B6: 'outer',
|
||||
},
|
||||
childrenById: {
|
||||
inner: ['B4', 'B5'],
|
||||
inner2: ['C4', 'C5'],
|
||||
Ugge: ['B2', 'B3', 'inner', 'inner2'],
|
||||
outer: ['B6'],
|
||||
},
|
||||
};
|
||||
});
|
||||
it('to find parent of siblings in a subgraph', () => {
|
||||
expect(findCommonAncestor('B4', 'B5', lookupDb)).toBe('inner');
|
||||
});
|
||||
it('to find an uncle', () => {
|
||||
expect(findCommonAncestor('B4', 'B2', lookupDb)).toBe('Ugge');
|
||||
});
|
||||
it('to find a cousin', () => {
|
||||
expect(findCommonAncestor('B4', 'C4', lookupDb)).toBe('Ugge');
|
||||
});
|
||||
it('to find a grandparent', () => {
|
||||
expect(findCommonAncestor('B4', 'B6', lookupDb)).toBe('root');
|
||||
});
|
||||
it('to find ancestor of siblings in the root', () => {
|
||||
expect(findCommonAncestor('B1', 'outer', lookupDb)).toBe('root');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
export interface TreeData {
|
||||
parentById: Record<string, string>;
|
||||
childrenById: Record<string, string[]>;
|
||||
}
|
||||
|
||||
export const findCommonAncestor = (id1: string, id2: string, treeData: TreeData) => {
|
||||
const { parentById } = treeData;
|
||||
const visited = new Set();
|
||||
let currentId = id1;
|
||||
while (currentId) {
|
||||
visited.add(currentId);
|
||||
if (currentId === id2) {
|
||||
return currentId;
|
||||
}
|
||||
currentId = parentById[currentId];
|
||||
}
|
||||
currentId = id2;
|
||||
while (currentId) {
|
||||
if (visited.has(currentId)) {
|
||||
return currentId;
|
||||
}
|
||||
currentId = parentById[currentId];
|
||||
}
|
||||
return 'root';
|
||||
};
|
||||
@@ -0,0 +1,395 @@
|
||||
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
||||
import { select, curveLinear, selectAll } from 'd3';
|
||||
import { getConfig } from '../../../config.js';
|
||||
import utils from '../../../utils.js';
|
||||
|
||||
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
|
||||
import { log } from '../../../logger.js';
|
||||
import common, { evaluate } from '../../common/common.js';
|
||||
import { interpolateToCurve, getStylesFromArray } from '../../../utils.js';
|
||||
|
||||
const conf = {};
|
||||
export const setConf = function (cnf) {
|
||||
const keys = Object.keys(cnf);
|
||||
for (const key of keys) {
|
||||
conf[key] = cnf[key];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add edges to graph based on parsed graph definition
|
||||
*
|
||||
* @param {object} edges The edges to add to the graph
|
||||
* @param {object} g The graph object
|
||||
* @param diagObj
|
||||
*/
|
||||
export const addEdges = function (edges, g, diagObj,svg) {
|
||||
log.info('abc78 edges = ', edges);
|
||||
let cnt = 0;
|
||||
let linkIdCnt = {};
|
||||
|
||||
let defaultStyle;
|
||||
let defaultLabelStyle;
|
||||
|
||||
if (edges.defaultStyle !== undefined) {
|
||||
const defaultStyles = getStylesFromArray(edges.defaultStyle);
|
||||
defaultStyle = defaultStyles.style;
|
||||
defaultLabelStyle = defaultStyles.labelStyle;
|
||||
}
|
||||
|
||||
edges.forEach(function (edge) {
|
||||
cnt++;
|
||||
|
||||
// Identify Link
|
||||
var linkIdBase = 'L-' + edge.start + '-' + edge.end;
|
||||
// count the links from+to the same node to give unique id
|
||||
if (linkIdCnt[linkIdBase] === undefined) {
|
||||
linkIdCnt[linkIdBase] = 0;
|
||||
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
|
||||
} else {
|
||||
linkIdCnt[linkIdBase]++;
|
||||
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
|
||||
}
|
||||
let linkId = linkIdBase + '-' + linkIdCnt[linkIdBase];
|
||||
log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);
|
||||
var linkNameStart = 'LS-' + edge.start;
|
||||
var linkNameEnd = 'LE-' + edge.end;
|
||||
|
||||
const edgeData = { style: '', labelStyle: '' };
|
||||
edgeData.minlen = edge.length || 1;
|
||||
//edgeData.id = 'id' + cnt;
|
||||
|
||||
// Set link type for rendering
|
||||
if (edge.type === 'arrow_open') {
|
||||
edgeData.arrowhead = 'none';
|
||||
} else {
|
||||
edgeData.arrowhead = 'normal';
|
||||
}
|
||||
|
||||
// Check of arrow types, placed here in order not to break old rendering
|
||||
edgeData.arrowTypeStart = 'arrow_open';
|
||||
edgeData.arrowTypeEnd = 'arrow_open';
|
||||
|
||||
/* eslint-disable no-fallthrough */
|
||||
switch (edge.type) {
|
||||
case 'double_arrow_cross':
|
||||
edgeData.arrowTypeStart = 'arrow_cross';
|
||||
case 'arrow_cross':
|
||||
edgeData.arrowTypeEnd = 'arrow_cross';
|
||||
break;
|
||||
case 'double_arrow_point':
|
||||
edgeData.arrowTypeStart = 'arrow_point';
|
||||
case 'arrow_point':
|
||||
edgeData.arrowTypeEnd = 'arrow_point';
|
||||
break;
|
||||
case 'double_arrow_circle':
|
||||
edgeData.arrowTypeStart = 'arrow_circle';
|
||||
case 'arrow_circle':
|
||||
edgeData.arrowTypeEnd = 'arrow_circle';
|
||||
break;
|
||||
}
|
||||
|
||||
let style = '';
|
||||
let labelStyle = '';
|
||||
|
||||
switch (edge.stroke) {
|
||||
case 'normal':
|
||||
style = 'fill:none;';
|
||||
if (defaultStyle !== undefined) {
|
||||
style = defaultStyle;
|
||||
}
|
||||
if (defaultLabelStyle !== undefined) {
|
||||
labelStyle = defaultLabelStyle;
|
||||
}
|
||||
edgeData.thickness = 'normal';
|
||||
edgeData.pattern = 'solid';
|
||||
break;
|
||||
case 'dotted':
|
||||
edgeData.thickness = 'normal';
|
||||
edgeData.pattern = 'dotted';
|
||||
edgeData.style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
|
||||
break;
|
||||
case 'thick':
|
||||
edgeData.thickness = 'thick';
|
||||
edgeData.pattern = 'solid';
|
||||
edgeData.style = 'stroke-width: 3.5px;fill:none;';
|
||||
break;
|
||||
case 'invisible':
|
||||
edgeData.thickness = 'invisible';
|
||||
edgeData.pattern = 'solid';
|
||||
edgeData.style = 'stroke-width: 0;fill:none;';
|
||||
break;
|
||||
}
|
||||
if (edge.style !== undefined) {
|
||||
const styles = getStylesFromArray(edge.style);
|
||||
style = styles.style;
|
||||
labelStyle = styles.labelStyle;
|
||||
}
|
||||
|
||||
edgeData.style = edgeData.style += style;
|
||||
edgeData.labelStyle = edgeData.labelStyle += labelStyle;
|
||||
|
||||
if (edge.interpolate !== undefined) {
|
||||
edgeData.curve = interpolateToCurve(edge.interpolate, curveLinear);
|
||||
} else if (edges.defaultInterpolate !== undefined) {
|
||||
edgeData.curve = interpolateToCurve(edges.defaultInterpolate, curveLinear);
|
||||
} else {
|
||||
edgeData.curve = interpolateToCurve(conf.curve, curveLinear);
|
||||
}
|
||||
|
||||
if (edge.text === undefined) {
|
||||
if (edge.style !== undefined) {
|
||||
edgeData.arrowheadStyle = 'fill: #333';
|
||||
}
|
||||
} else {
|
||||
edgeData.arrowheadStyle = 'fill: #333';
|
||||
edgeData.labelpos = 'c';
|
||||
}
|
||||
|
||||
edgeData.labelType = edge.labelType;
|
||||
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
|
||||
|
||||
if (edge.style === undefined) {
|
||||
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;';
|
||||
}
|
||||
|
||||
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
|
||||
|
||||
edgeData.id = linkId;
|
||||
edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd;
|
||||
|
||||
// Add the edge to the graph
|
||||
g.setEdge(edge.start, edge.end, edgeData, cnt);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Function that adds the vertices found during parsing to the graph to be rendered.
|
||||
*
|
||||
* @param vert Object containing the vertices.
|
||||
* @param g The graph that is to be drawn.
|
||||
* @param svgId
|
||||
* @param root
|
||||
* @param doc
|
||||
* @param diagObj
|
||||
*/
|
||||
export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
|
||||
const svg = root.select(`[id="${svgId}"]`);
|
||||
const keys = Object.keys(vert);
|
||||
|
||||
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
|
||||
keys.forEach(function (id) {
|
||||
const vertex = vert[id];
|
||||
|
||||
/**
|
||||
* Variable for storing the classes for the vertex
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
let classStr = 'default';
|
||||
if (vertex.classes.length > 0) {
|
||||
classStr = vertex.classes.join(' ');
|
||||
}
|
||||
classStr = classStr + ' flowchart-label';
|
||||
const styles = getStylesFromArray(vertex.styles);
|
||||
|
||||
// Use vertex id as text in the box if no text is provided by the graph definition
|
||||
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id;
|
||||
|
||||
// We create a SVG label, either by delegating to addHtmlLabel or manually
|
||||
let vertexNode;
|
||||
log.info('vertex', vertex, vertex.labelType);
|
||||
if (vertex.labelType === 'markdown') {
|
||||
log.info('vertex', vertex, vertex.labelType);
|
||||
} else {
|
||||
if (evaluate(getConfig().flowchart.htmlLabels) && svg.html) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
const node = {
|
||||
label: vertexText.replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g,
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
};
|
||||
vertexNode = addHtmlLabel(svg, node).node();
|
||||
vertexNode.parentNode.removeChild(vertexNode);
|
||||
} else {
|
||||
const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
|
||||
|
||||
const rows = vertexText.split(common.lineBreakRegex);
|
||||
|
||||
for (const row of rows) {
|
||||
const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
|
||||
tspan.setAttribute('dy', '1em');
|
||||
tspan.setAttribute('x', '1');
|
||||
tspan.textContent = row;
|
||||
svgLabel.appendChild(tspan);
|
||||
}
|
||||
vertexNode = svgLabel;
|
||||
}
|
||||
}
|
||||
|
||||
let radious = 0;
|
||||
let _shape = '';
|
||||
// Set the shape based parameters
|
||||
switch (vertex.type) {
|
||||
case 'round':
|
||||
radious = 5;
|
||||
_shape = 'rect';
|
||||
break;
|
||||
case 'square':
|
||||
_shape = 'rect';
|
||||
break;
|
||||
case 'diamond':
|
||||
_shape = 'question';
|
||||
break;
|
||||
case 'hexagon':
|
||||
_shape = 'hexagon';
|
||||
break;
|
||||
case 'odd':
|
||||
_shape = 'rect_left_inv_arrow';
|
||||
break;
|
||||
case 'lean_right':
|
||||
_shape = 'lean_right';
|
||||
break;
|
||||
case 'lean_left':
|
||||
_shape = 'lean_left';
|
||||
break;
|
||||
case 'trapezoid':
|
||||
_shape = 'trapezoid';
|
||||
break;
|
||||
case 'inv_trapezoid':
|
||||
_shape = 'inv_trapezoid';
|
||||
break;
|
||||
case 'odd_right':
|
||||
_shape = 'rect_left_inv_arrow';
|
||||
break;
|
||||
case 'circle':
|
||||
_shape = 'circle';
|
||||
break;
|
||||
case 'ellipse':
|
||||
_shape = 'ellipse';
|
||||
break;
|
||||
case 'stadium':
|
||||
_shape = 'stadium';
|
||||
break;
|
||||
case 'subroutine':
|
||||
_shape = 'subroutine';
|
||||
break;
|
||||
case 'cylinder':
|
||||
_shape = 'cylinder';
|
||||
break;
|
||||
case 'group':
|
||||
_shape = 'rect';
|
||||
break;
|
||||
case 'doublecircle':
|
||||
_shape = 'doublecircle';
|
||||
break;
|
||||
default:
|
||||
_shape = 'rect';
|
||||
}
|
||||
// Add the node
|
||||
g.setNode(vertex.id, {
|
||||
labelStyle: styles.labelStyle,
|
||||
shape: _shape,
|
||||
labelText: vertexText,
|
||||
labelType: vertex.labelType,
|
||||
rx: radious,
|
||||
ry: radious,
|
||||
class: classStr,
|
||||
style: styles.style,
|
||||
id: vertex.id,
|
||||
link: vertex.link,
|
||||
linkTarget: vertex.linkTarget,
|
||||
tooltip: diagObj.db.getTooltip(vertex.id) || '',
|
||||
domId: diagObj.db.lookUpDomId(vertex.id),
|
||||
haveCallback: vertex.haveCallback,
|
||||
width: vertex.type === 'group' ? 500 : undefined,
|
||||
dir: vertex.dir,
|
||||
type: vertex.type,
|
||||
props: vertex.props,
|
||||
padding: getConfig().flowchart.padding,
|
||||
});
|
||||
|
||||
log.info('setNode', {
|
||||
labelStyle: styles.labelStyle,
|
||||
labelType: vertex.labelType,
|
||||
shape: _shape,
|
||||
labelText: vertexText,
|
||||
rx: radious,
|
||||
ry: radious,
|
||||
class: classStr,
|
||||
style: styles.style,
|
||||
id: vertex.id,
|
||||
domId: diagObj.db.lookUpDomId(vertex.id),
|
||||
width: vertex.type === 'group' ? 500 : undefined,
|
||||
type: vertex.type,
|
||||
dir: vertex.dir,
|
||||
props: vertex.props,
|
||||
padding: getConfig().flowchart.padding,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param diagObj
|
||||
* @param id
|
||||
* @param root
|
||||
* @param doc
|
||||
*/
|
||||
function setupGraph(diagObj, id, root, doc) {
|
||||
const { securityLevel, flowchart: conf } = getConfig();
|
||||
const nodeSpacing = conf.nodeSpacing || 50;
|
||||
const rankSpacing = conf.rankSpacing || 50;
|
||||
|
||||
// Fetch the default direction, use TD if none was found
|
||||
let dir = diagObj.db.getDirection();
|
||||
if (dir === undefined) {
|
||||
dir = 'TD';
|
||||
}
|
||||
|
||||
// Create the input mermaid.graph
|
||||
const g = new graphlib.Graph({
|
||||
multigraph: true,
|
||||
compound: true,
|
||||
})
|
||||
.setGraph({
|
||||
rankdir: dir,
|
||||
nodesep: nodeSpacing,
|
||||
ranksep: rankSpacing,
|
||||
marginx: 0,
|
||||
marginy: 0,
|
||||
})
|
||||
.setDefaultEdgeLabel(function () {
|
||||
return {};
|
||||
});
|
||||
|
||||
let subG;
|
||||
const subGraphs = diagObj.db.getSubGraphs();
|
||||
|
||||
// Fetch the vertices/nodes and edges/links from the parsed graph definition
|
||||
const vert = diagObj.db.getVertices();
|
||||
|
||||
const edges = diagObj.db.getEdges();
|
||||
|
||||
log.info('Edges', edges);
|
||||
let i = 0;
|
||||
// for (i = subGraphs.length - 1; i >= 0; i--) {
|
||||
// // for (let i = 0; i < subGraphs.length; i++) {
|
||||
// subG = subGraphs[i];
|
||||
|
||||
// selectAll('cluster').append('text');
|
||||
|
||||
// for (let j = 0; j < subG.nodes.length; j++) {
|
||||
// log.info('Setting up subgraphs', subG.nodes[j], subG.id);
|
||||
// g.setParent(subG.nodes[j], subG.id);
|
||||
// }
|
||||
// }
|
||||
addVertices(vert, g, id, root, doc, diagObj);
|
||||
addEdges(edges, g, diagObj);
|
||||
return g;
|
||||
}
|
||||
|
||||
export default setupGraph;
|
||||
143
packages/mermaid/src/diagrams/swimlane/lost-and-found/styles.ts
Normal file
143
packages/mermaid/src/diagrams/swimlane/lost-and-found/styles.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
/** Returns the styles given options */
|
||||
export interface FlowChartStyleOptions {
|
||||
arrowheadColor: string;
|
||||
border2: string;
|
||||
clusterBkg: string;
|
||||
clusterBorder: string;
|
||||
edgeLabelBackground: string;
|
||||
fontFamily: string;
|
||||
lineColor: string;
|
||||
mainBkg: string;
|
||||
nodeBorder: string;
|
||||
nodeTextColor: string;
|
||||
tertiaryColor: string;
|
||||
textColor: string;
|
||||
titleColor: string;
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
const genSections = (options: FlowChartStyleOptions) => {
|
||||
let sections = '';
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
sections += `
|
||||
.subgraph-lvl-${i} {
|
||||
fill: ${options[`surface${i}`]};
|
||||
stroke: ${options[`surfacePeer${i}`]};
|
||||
}
|
||||
`;
|
||||
}
|
||||
return sections;
|
||||
};
|
||||
|
||||
const getStyles = (options: FlowChartStyleOptions) =>
|
||||
`.label {
|
||||
font-family: ${options.fontFamily};
|
||||
color: ${options.nodeTextColor || options.textColor};
|
||||
}
|
||||
.cluster-label text {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
.cluster-label span {
|
||||
color: ${options.titleColor};
|
||||
}
|
||||
|
||||
.label text,span {
|
||||
fill: ${options.nodeTextColor || options.textColor};
|
||||
color: ${options.nodeTextColor || options.textColor};
|
||||
}
|
||||
|
||||
.node rect,
|
||||
.node circle,
|
||||
.node ellipse,
|
||||
.node polygon,
|
||||
.node path {
|
||||
fill: ${options.mainBkg};
|
||||
stroke: ${options.nodeBorder};
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.node .label {
|
||||
text-align: center;
|
||||
}
|
||||
.node.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.arrowheadPath {
|
||||
fill: ${options.arrowheadColor};
|
||||
}
|
||||
|
||||
.edgePath .path {
|
||||
stroke: ${options.lineColor};
|
||||
stroke-width: 2.0px;
|
||||
}
|
||||
|
||||
.flowchart-link {
|
||||
stroke: ${options.lineColor};
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.edgeLabel {
|
||||
background-color: ${options.edgeLabelBackground};
|
||||
rect {
|
||||
opacity: 0.85;
|
||||
background-color: ${options.edgeLabelBackground};
|
||||
fill: ${options.edgeLabelBackground};
|
||||
}
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cluster rect {
|
||||
fill: ${options.clusterBkg};
|
||||
stroke: ${options.clusterBorder};
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.cluster text {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
|
||||
.cluster span {
|
||||
color: ${options.titleColor};
|
||||
}
|
||||
/* .cluster div {
|
||||
color: ${options.titleColor};
|
||||
} */
|
||||
|
||||
div.mermaidTooltip {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
max-width: 200px;
|
||||
padding: 2px;
|
||||
font-family: ${options.fontFamily};
|
||||
font-size: 12px;
|
||||
background: ${options.tertiaryColor};
|
||||
border: 1px solid ${options.border2};
|
||||
border-radius: 2px;
|
||||
pointer-events: none;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.flowchartTitleText {
|
||||
text-anchor: middle;
|
||||
font-size: 18px;
|
||||
fill: ${options.textColor};
|
||||
}
|
||||
.subgraph {
|
||||
stroke-width:2;
|
||||
rx:3;
|
||||
}
|
||||
// .subgraph-lvl-1 {
|
||||
// fill:#ccc;
|
||||
// // stroke:black;
|
||||
// }
|
||||
|
||||
.flowchart-label text {
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
${genSections(options)}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
||||
@@ -0,0 +1,13 @@
|
||||
// @ts-ignore: JISON typing missing
|
||||
import parser from '../parser/flow.jison';
|
||||
|
||||
import * as db from '../flowDb.js';
|
||||
import renderer from './swimlaneRenderer.js';
|
||||
import styles from './styles.js';
|
||||
|
||||
export const diagram = {
|
||||
db,
|
||||
renderer,
|
||||
parser,
|
||||
styles,
|
||||
};
|
||||
@@ -0,0 +1,220 @@
|
||||
import { log } from '../../../logger.js';
|
||||
import flowDb from '../flowDb.js';
|
||||
|
||||
export const getSubgraphLookupTable = function (diagObj) {
|
||||
const subGraphs = diagObj.db.getSubGraphs();
|
||||
const subgraphDb = {};
|
||||
log.info('Subgraphs - ', subGraphs);
|
||||
for (let i = subGraphs.length - 1; i >= 0; i--) {
|
||||
const subG = subGraphs[i];
|
||||
log.info('Subgraph - ', subG);
|
||||
for (let j = 0; j < subG.nodes.length; j++) {
|
||||
log.info('Setting up subgraphs', subG.nodes[j], subG.id);
|
||||
subgraphDb[flowDb.lookUpId(subG.nodes[j])] = subG.id;
|
||||
}
|
||||
}
|
||||
return subgraphDb;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param graph
|
||||
* @param subgraphLookupTable
|
||||
*/
|
||||
export function assignRanks(graph, subgraphLookupTable) {
|
||||
let visited = new Set();
|
||||
const lock = new Map();
|
||||
const ranks = new Map();
|
||||
let cnt = 0;
|
||||
let changesDetected = true;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nodeId
|
||||
* @param currentRank
|
||||
*/
|
||||
function dfs(nodeId, currentRank) {
|
||||
if (visited.has(nodeId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visited.add(nodeId);
|
||||
const existingRank = ranks.get(nodeId) || 0;
|
||||
|
||||
// console.log('APA444 DFS Base case for', nodeId, 'to', Math.max(existingRank, currentRank));
|
||||
if (lock.get(nodeId) !== 1) {
|
||||
ranks.set(nodeId, Math.max(existingRank, currentRank));
|
||||
} else {
|
||||
console.log(
|
||||
'APA444 ',
|
||||
nodeId,
|
||||
'was locked to ',
|
||||
existingRank,
|
||||
'so not changing it',
|
||||
ranks.get(nodeId)
|
||||
);
|
||||
}
|
||||
|
||||
const currentRankAdjusted = ranks.get(nodeId) || currentRank;
|
||||
graph.successors(nodeId).forEach((targetId) => {
|
||||
if (subgraphLookupTable[targetId] !== subgraphLookupTable[nodeId]) {
|
||||
dfs(targetId, currentRankAdjusted);
|
||||
} else {
|
||||
// In same line, easy increase
|
||||
dfs(targetId, currentRankAdjusted + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function adjustSuccessors() {
|
||||
console.log('APA444 Adjusting successors');
|
||||
graph.nodes().forEach((nodeId) => {
|
||||
console.log('APA444 Going through nodes', nodeId);
|
||||
// if (graph.predecessors(nodeId).length === 0) {
|
||||
console.log('APA444 has no predecessors', nodeId);
|
||||
graph.successors(nodeId).forEach((successorNodeId) => {
|
||||
console.log('APA444 has checking successor', successorNodeId);
|
||||
if (subgraphLookupTable[successorNodeId] !== subgraphLookupTable[nodeId]) {
|
||||
const newRank = ranks.get(successorNodeId);
|
||||
ranks.set(nodeId, newRank);
|
||||
console.log('APA444 POST-process case for', nodeId, 'to', newRank);
|
||||
lock.set(nodeId, 1);
|
||||
changesDetected = true;
|
||||
// setRankFromTopNodes();
|
||||
|
||||
// Adjust ranks of successors in the same subgraph
|
||||
graph.successors(nodeId).forEach((sameSubGraphSuccessorNodeId) => {
|
||||
if (subgraphLookupTable[sameSubGraphSuccessorNodeId] === subgraphLookupTable[nodeId]) {
|
||||
console.log(
|
||||
'APA444 Adjusting rank of',
|
||||
sameSubGraphSuccessorNodeId,
|
||||
'to',
|
||||
newRank + 1
|
||||
);
|
||||
ranks.set(sameSubGraphSuccessorNodeId, newRank + 1);
|
||||
lock.set(sameSubGraphSuccessorNodeId, 1);
|
||||
changesDetected = true;
|
||||
// dfs(sameSubGraphSuccessorNodeId, newRank + 1);
|
||||
// setRankFromTopNodes();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('APA444 Node', nodeId, ' and ', successorNodeId, ' is in the same lane');
|
||||
}
|
||||
});
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function setRankFromTopNodes() {
|
||||
visited = new Set();
|
||||
graph.nodes().forEach((nodeId) => {
|
||||
if (graph.predecessors(nodeId).length === 0) {
|
||||
dfs(nodeId, 0);
|
||||
}
|
||||
});
|
||||
adjustSuccessors();
|
||||
}
|
||||
|
||||
while (changesDetected && cnt < 10) {
|
||||
setRankFromTopNodes();
|
||||
cnt++;
|
||||
}
|
||||
// Post-process the ranks
|
||||
|
||||
return ranks;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param graph
|
||||
* @param subgraphLÖookupTable
|
||||
* @param ranks
|
||||
* @param subgraphLookupTable
|
||||
*/
|
||||
export function assignAffinities(graph, ranks, subgraphLookupTable) {
|
||||
const affinities = new Map();
|
||||
const swimlaneRankAffinities = new Map();
|
||||
const swimlaneMaxAffinity = new Map();
|
||||
|
||||
graph.nodes().forEach((nodeId) => {
|
||||
const swimlane = subgraphLookupTable[nodeId];
|
||||
const rank = ranks.get(nodeId);
|
||||
const key = swimlane + ':' + rank;
|
||||
let currentAffinity = swimlaneRankAffinities.get(key);
|
||||
if (currentAffinity === undefined) {
|
||||
currentAffinity = -1;
|
||||
}
|
||||
const newAffinity = currentAffinity + 1;
|
||||
swimlaneRankAffinities.set(key, newAffinity);
|
||||
affinities.set(nodeId, newAffinity);
|
||||
let currentMaxAffinity = swimlaneMaxAffinity.get(swimlane);
|
||||
if (currentMaxAffinity === undefined) {
|
||||
swimlaneMaxAffinity.set(swimlane, 0);
|
||||
currentMaxAffinity = 0;
|
||||
}
|
||||
if (newAffinity > currentMaxAffinity) {
|
||||
swimlaneMaxAffinity.set(swimlane, newAffinity);
|
||||
}
|
||||
});
|
||||
|
||||
// console.log('APA444 affinities', swimlaneRankAffinities);
|
||||
|
||||
return { affinities, swimlaneMaxAffinity };
|
||||
//return affinities;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param graph
|
||||
* @param diagObj
|
||||
*/
|
||||
export function swimlaneLayout(graph, diagObj) {
|
||||
const subgraphLookupTable = getSubgraphLookupTable(diagObj);
|
||||
const ranks = assignRanks(graph, subgraphLookupTable);
|
||||
|
||||
const { affinities, swimlaneMaxAffinity } = assignAffinities(graph, ranks, subgraphLookupTable);
|
||||
// const affinities = assignAffinities(graph, ranks, subgraphLookupTable);
|
||||
|
||||
const subGraphs = diagObj.db.getSubGraphs();
|
||||
const lanes = [];
|
||||
const laneDb = {};
|
||||
let xPos = 0;
|
||||
for (const subG of subGraphs) {
|
||||
const maxAffinity = swimlaneMaxAffinity.get(subG.id);
|
||||
const lane = {
|
||||
title: subG.title,
|
||||
x: xPos,
|
||||
width: 200 + maxAffinity * 150,
|
||||
};
|
||||
xPos += lane.width;
|
||||
lanes.push(lane);
|
||||
laneDb[subG.id] = lane;
|
||||
}
|
||||
|
||||
const rankWidth = [];
|
||||
// Basic layout, calculate the node positions based on rank
|
||||
graph.nodes().forEach((nodeId) => {
|
||||
const rank = ranks.get(nodeId);
|
||||
|
||||
if (!rankWidth[rank]) {
|
||||
const laneId = subgraphLookupTable[nodeId];
|
||||
const lane = laneDb[laneId];
|
||||
const n = graph.node(nodeId);
|
||||
console.log('Node', nodeId, n);
|
||||
const affinity = affinities.get(nodeId);
|
||||
|
||||
console.log('APA444', nodeId, 'rank', rank, 'affinity', affinity);
|
||||
graph.setNode(nodeId, { y: rank * 200 + 50, x: lane.x + 150 * affinity + 100 });
|
||||
// lane.width = Math.max(lane.width, lane.x + 150*affinity + lane.width / 4);
|
||||
}
|
||||
});
|
||||
|
||||
return { graph, lanes };
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import { cleanupComments } from '../../../diagram-api/comments.js';
|
||||
import setupGraph from './setup-graph.js';
|
||||
import { swimlaneLayout, assignRanks, getSubgraphLookupTable } from './swimlane-layout.js';
|
||||
import { getDiagramFromText } from '../../../Diagram.js';
|
||||
import { addDiagrams } from '../../../diagram-api/diagram-orchestration.ts';
|
||||
import jsdom from 'jsdom';
|
||||
|
||||
const { JSDOM } = jsdom;
|
||||
|
||||
addDiagrams();
|
||||
describe('When doing a assigning ranks specific for swim lanes ', () => {
|
||||
let root;
|
||||
let doc;
|
||||
beforeEach(function () {
|
||||
const dom = new JSDOM(`<!DOCTYPE html><body><pre id="swimmer">My First JSDOM!</pre></body>`);
|
||||
root = select(dom.window.document.getElementById('swimmer'));
|
||||
root.html = () => {
|
||||
' return <div>hello</div>';
|
||||
};
|
||||
|
||||
doc = dom.window.document;
|
||||
});
|
||||
describe('Layout: ', () => {
|
||||
// it('should rank the nodes:', async () => {
|
||||
// const diagram = await getDiagramFromText(`swimlane LR
|
||||
// subgraph "\`one\`"
|
||||
// start --> cat --> rat
|
||||
// end`);
|
||||
// const g = setupGraph(diagram, 'swimmer', root, doc);
|
||||
// const subgraphLookupTable = getSubgraphLookupTable(diagram);
|
||||
// const ranks = assignRanks(g, subgraphLookupTable);
|
||||
// expect(ranks.get('start')).toEqual(0);
|
||||
// expect(ranks.get('cat')).toEqual(1);
|
||||
// expect(ranks.get('rat')).toEqual(2);
|
||||
// });
|
||||
|
||||
it('should rank the nodes:', async () => {
|
||||
const diagram = await getDiagramFromText(`swimlane LR
|
||||
subgraph "\`one\`"
|
||||
start --> cat --> rat
|
||||
end
|
||||
subgraph "\`two\`"
|
||||
monkey --> dog --> done
|
||||
end
|
||||
cat --> monkey`);
|
||||
const g = setupGraph(diagram, 'swimmer', root, doc);
|
||||
const subgraphLookupTable = getSubgraphLookupTable(diagram);
|
||||
const ranks = assignRanks(g, subgraphLookupTable);
|
||||
expect(ranks.get('start')).toEqual(0);
|
||||
expect(ranks.get('cat')).toEqual(1);
|
||||
expect(ranks.get('rat')).toEqual(2);
|
||||
expect(ranks.get('monkey')).toEqual(1);
|
||||
expect(ranks.get('dog')).toEqual(2);
|
||||
expect(ranks.get('done')).toEqual(3);
|
||||
});
|
||||
});
|
||||
describe('Layout: ', () => {
|
||||
it('should rank the nodes:', async () => {
|
||||
const diagram = await getDiagramFromText(`swimlane LR
|
||||
subgraph "\`one\`"
|
||||
start --> cat --> rat
|
||||
end`);
|
||||
const g = setupGraph(diagram, 'swimmer', root, doc);
|
||||
const subgraphLookupTable = getSubgraphLookupTable(diagram);
|
||||
const { graph, lanes } = swimlaneLayout(g, diagram);
|
||||
expect(lanes.length).toBe(1);
|
||||
const start = graph.node('start');
|
||||
const cat = graph.node('cat');
|
||||
const rat = graph.node('rat');
|
||||
expect(start.y).toBe(50);
|
||||
expect(cat.y).toBe(250);
|
||||
expect(rat.y).toBe(450);
|
||||
expect(rat.x).toBe(100);
|
||||
});
|
||||
|
||||
it('should rank the nodes:', async () => {
|
||||
const diagram = await getDiagramFromText(`swimlane LR
|
||||
subgraph "\`one\`"
|
||||
start --> cat --> rat
|
||||
end
|
||||
subgraph "\`two\`"
|
||||
monkey --> dog --> done
|
||||
end
|
||||
cat --> monkey`);
|
||||
const g = setupGraph(diagram, 'swimmer', root, doc);
|
||||
const subgraphLookupTable = getSubgraphLookupTable(diagram);
|
||||
const { graph, lanes } = swimlaneLayout(g, diagram);
|
||||
expect(lanes.length).toBe(2);
|
||||
const start = graph.node('start');
|
||||
const cat = graph.node('cat');
|
||||
const rat = graph.node('rat');
|
||||
const monkey = graph.node('monkey');
|
||||
const dog = graph.node('dog');
|
||||
const done = graph.node('done');
|
||||
|
||||
expect(start.y).toBe(50);
|
||||
expect(cat.y).toBe(250);
|
||||
expect(rat.y).toBe(450);
|
||||
expect(rat.x).toBe(100);
|
||||
expect(monkey.y).toBe(250);
|
||||
expect(dog.y).toBe(450);
|
||||
expect(done.y).toBe(650);
|
||||
expect(monkey.x).toBe(300);
|
||||
});
|
||||
it.only('should rank the nodes:', async () => {
|
||||
const diagram = await getDiagramFromText(`swimlane LR
|
||||
subgraph "\`one\`"
|
||||
start --> cat --> rat & hat
|
||||
end
|
||||
`);
|
||||
const g = setupGraph(diagram, 'swimmer', root, doc);
|
||||
const subgraphLookupTable = getSubgraphLookupTable(diagram);
|
||||
const { graph, lanes } = swimlaneLayout(g, diagram);
|
||||
expect(lanes.length).toBe(1);
|
||||
const start = graph.node('start');
|
||||
const cat = graph.node('cat');
|
||||
const rat = graph.node('rat');
|
||||
const hat = graph.node('rat');
|
||||
|
||||
expect(start.y).toBe(50);
|
||||
expect(cat.y).toBe(250);
|
||||
expect(rat.y).toBe(450);
|
||||
expect(rat.x).toBe(300);
|
||||
expect(hat.y).toBe(450);
|
||||
expect(hat.x).toBe(100);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,596 @@
|
||||
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
||||
import { select, curveLinear, selectAll } from 'd3';
|
||||
import { swimlaneLayout } from './swimlane-layout.js';
|
||||
import insertMarkers from '../../../dagre-wrapper/markers.js';
|
||||
import { insertNode } from '../../../dagre-wrapper/nodes.js';
|
||||
import flowDb from '../flowDb.js';
|
||||
import { getConfig } from '../../../config.js';
|
||||
import {getStylesFromArray} from '../../../utils.js';
|
||||
import setupGraph, { addEdges, addVertices } from './setup-graph.js';
|
||||
import { render } from '../../../dagre-wrapper/index.js';
|
||||
import { log } from '../../../logger.js';
|
||||
import { setupGraphViewbox } from '../../../setupGraphViewbox.js';
|
||||
import common, { evaluate } from '../../common/common.js';
|
||||
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
|
||||
import { insertEdge,positionEdgeLabel } from '../../../dagre-wrapper/edges.js';
|
||||
import {
|
||||
clear as clearGraphlib,
|
||||
clusterDb,
|
||||
adjustClustersAndEdges,
|
||||
findNonClusterChild,
|
||||
sortNodesByHierarchy,
|
||||
} from '../../../dagre-wrapper/mermaid-graphlib.js';
|
||||
|
||||
|
||||
const conf = {};
|
||||
export const setConf = function (cnf) {
|
||||
const keys = Object.keys(cnf);
|
||||
for (const key of keys) {
|
||||
conf[key] = cnf[key];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param element
|
||||
* @param graph
|
||||
* @param layout
|
||||
* @param vert
|
||||
* @param elem
|
||||
* @param g
|
||||
* @param id
|
||||
* @param conf
|
||||
*/
|
||||
async function swimlaneRender(layout,vert, elem,g, id, conf) {
|
||||
|
||||
let renderedNodes = [];
|
||||
// draw nodes from layout.graph to element
|
||||
const nodes = layout.graph.nodes();
|
||||
|
||||
// lanes are the swimlanes
|
||||
const lanes = layout.lanes;
|
||||
|
||||
|
||||
|
||||
const nodesElements = elem.insert('g').attr('class', 'nodes');
|
||||
// for each node, draw a rect, with a child text inside as label
|
||||
for (const node of nodes) {
|
||||
const nodeFromLayout = layout.graph.node(node);
|
||||
const vertex = vert[node];
|
||||
//Initialise the node
|
||||
/**
|
||||
* Variable for storing the classes for the vertex
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
let classStr = 'default';
|
||||
if (vertex.classes.length > 0) {
|
||||
classStr = vertex.classes.join(' ');
|
||||
}
|
||||
classStr = classStr + ' swimlane-label';
|
||||
const styles = getStylesFromArray(vertex.styles);
|
||||
|
||||
// Use vertex id as text in the box if no text is provided by the graph definition
|
||||
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id;
|
||||
|
||||
// We create a SVG label, either by delegating to addHtmlLabel or manually
|
||||
let vertexNode;
|
||||
log.info('vertex', vertex, vertex.labelType);
|
||||
if (vertex.labelType === 'markdown') {
|
||||
log.info('vertex', vertex, vertex.labelType);
|
||||
} else {
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
const node = {
|
||||
label: vertexText.replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g,
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
};
|
||||
vertexNode = addHtmlLabel(elem, node).node();
|
||||
vertexNode.parentNode.removeChild(vertexNode);
|
||||
} else {
|
||||
const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
|
||||
|
||||
const rows = vertexText.split(common.lineBreakRegex);
|
||||
|
||||
for (const row of rows) {
|
||||
const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
|
||||
tspan.setAttribute('dy', '1em');
|
||||
tspan.setAttribute('x', '1');
|
||||
tspan.textContent = row;
|
||||
svgLabel.appendChild(tspan);
|
||||
}
|
||||
vertexNode = svgLabel;
|
||||
}
|
||||
}
|
||||
|
||||
let radious = 0;
|
||||
let _shape = '';
|
||||
// Set the shape based parameters
|
||||
switch (vertex.type) {
|
||||
case 'round':
|
||||
radious = 5;
|
||||
_shape = 'rect';
|
||||
break;
|
||||
case 'square':
|
||||
_shape = 'rect';
|
||||
break;
|
||||
case 'diamond':
|
||||
_shape = 'question';
|
||||
break;
|
||||
case 'hexagon':
|
||||
_shape = 'hexagon';
|
||||
break;
|
||||
case 'odd':
|
||||
_shape = 'rect_left_inv_arrow';
|
||||
break;
|
||||
case 'lean_right':
|
||||
_shape = 'lean_right';
|
||||
break;
|
||||
case 'lean_left':
|
||||
_shape = 'lean_left';
|
||||
break;
|
||||
case 'trapezoid':
|
||||
_shape = 'trapezoid';
|
||||
break;
|
||||
case 'inv_trapezoid':
|
||||
_shape = 'inv_trapezoid';
|
||||
break;
|
||||
case 'odd_right':
|
||||
_shape = 'rect_left_inv_arrow';
|
||||
break;
|
||||
case 'circle':
|
||||
_shape = 'circle';
|
||||
break;
|
||||
case 'ellipse':
|
||||
_shape = 'ellipse';
|
||||
break;
|
||||
case 'stadium':
|
||||
_shape = 'stadium';
|
||||
break;
|
||||
case 'subroutine':
|
||||
_shape = 'subroutine';
|
||||
break;
|
||||
case 'cylinder':
|
||||
_shape = 'cylinder';
|
||||
break;
|
||||
case 'group':
|
||||
_shape = 'rect';
|
||||
break;
|
||||
case 'doublecircle':
|
||||
_shape = 'doublecircle';
|
||||
break;
|
||||
default:
|
||||
_shape = 'rect';
|
||||
}
|
||||
// Add the node
|
||||
let nodeObj ={
|
||||
labelStyle: styles.labelStyle,
|
||||
shape: _shape,
|
||||
labelText: vertexText,
|
||||
labelType: vertex.labelType,
|
||||
rx: radious,
|
||||
ry: radious,
|
||||
class: classStr,
|
||||
style: styles.style,
|
||||
id: vertex.id,
|
||||
link: vertex.link,
|
||||
linkTarget: vertex.linkTarget,
|
||||
// tooltip: diagObj.db.getTooltip(vertex.id) || '',
|
||||
// domId: diagObj.db.lookUpDomId(vertex.id),
|
||||
haveCallback: vertex.haveCallback,
|
||||
width: vertex.type === 'group' ? 500 : undefined,
|
||||
dir: vertex.dir,
|
||||
type: vertex.type,
|
||||
props: vertex.props,
|
||||
padding: getConfig().flowchart.padding,
|
||||
x: nodeFromLayout.x,
|
||||
y: nodeFromLayout.y,
|
||||
};
|
||||
|
||||
let boundingBox;
|
||||
let nodeEl;
|
||||
|
||||
// Add the element to the DOM
|
||||
|
||||
nodeEl = await insertNode(nodesElements, nodeObj, vertex.dir);
|
||||
boundingBox = nodeEl.node().getBBox();
|
||||
nodeEl.attr('transform', `translate(${nodeObj.x}, ${nodeObj.y / 2})`);
|
||||
|
||||
// add to rendered nodes
|
||||
renderedNodes.push({id: vertex.id, nodeObj: nodeObj, boundingBox: boundingBox});
|
||||
|
||||
}
|
||||
|
||||
|
||||
return renderedNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the all the styles from classDef statements in the graph definition.
|
||||
*
|
||||
* @param text
|
||||
* @param diagObj
|
||||
* @returns {object} ClassDef styles
|
||||
*/
|
||||
// export const getClasses = function (text, diagObj) {
|
||||
// log.info('Extracting classes');
|
||||
// diagObj.db.clear();
|
||||
// try {
|
||||
// // Parse the graph definition
|
||||
// diagObj.parse(text);
|
||||
// return diagObj.db.getClasses();
|
||||
// } catch (e) {
|
||||
// return;
|
||||
// }
|
||||
// };
|
||||
|
||||
/**
|
||||
* Returns the all the styles from classDef statements in the graph definition.
|
||||
*
|
||||
* @param text
|
||||
* @param diagObj
|
||||
* @returns {Record<string, import('../../../diagram-api/types.js').DiagramStyleClassDef>} ClassDef styles
|
||||
*/
|
||||
export const getClasses = function (text, diagObj) {
|
||||
log.info('Extracting classes');
|
||||
return diagObj.db.getClasses();
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws a flowchart in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
* @param text
|
||||
* @param id
|
||||
*/
|
||||
|
||||
export const draw = async function (text, id, _version, diagObj) {
|
||||
log.info('Drawing flowchart');
|
||||
diagObj.db.clear();
|
||||
flowDb.setGen('gen-2');
|
||||
// Parse the graph definition
|
||||
diagObj.parser.parse(text);
|
||||
|
||||
const { securityLevel, flowchart: conf } = getConfig();
|
||||
|
||||
// Handle root and document for when rendering in sandbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// create g as a graphlib graph using setupGraph from setup-graph.js
|
||||
const g = setupGraph(diagObj, id, root, doc);
|
||||
|
||||
|
||||
|
||||
let subG;
|
||||
const subGraphs = diagObj.db.getSubGraphs();
|
||||
log.info('Subgraphs - ', subGraphs);
|
||||
for (let i = subGraphs.length - 1; i >= 0; i--) {
|
||||
subG = subGraphs[i];
|
||||
log.info('Subgraph - ', subG);
|
||||
diagObj.db.addVertex(
|
||||
subG.id,
|
||||
{ text: subG.title, type: subG.labelType },
|
||||
'group',
|
||||
undefined,
|
||||
subG.classes,
|
||||
subG.dir
|
||||
);
|
||||
}
|
||||
|
||||
// Fetch the vertices/nodes and edges/links from the parsed graph definition
|
||||
const vert = diagObj.db.getVertices();
|
||||
|
||||
const edges = diagObj.db.getEdges();
|
||||
|
||||
log.info('Edges', edges);
|
||||
|
||||
const svg = root.select('#' + id);
|
||||
|
||||
svg.append('g');
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
// const element = root.select('#' + id + ' g');
|
||||
console.log('diagObj',diagObj);
|
||||
console.log('subGraphs', diagObj.db.getSubGraphs());
|
||||
const layout = swimlaneLayout(g, diagObj);
|
||||
console.log('custom layout',layout);
|
||||
|
||||
|
||||
// insert markers
|
||||
// Define the supported markers for the diagram
|
||||
const markers = ['point', 'circle', 'cross'];
|
||||
insertMarkers(svg, markers, 'flowchart', id);
|
||||
// draw lanes as vertical lines
|
||||
const lanesElements = svg.insert('g').attr('class', 'lanes');
|
||||
|
||||
|
||||
let laneCount = 0;
|
||||
|
||||
for (const lane of layout.lanes) {
|
||||
|
||||
laneCount++;
|
||||
|
||||
//draw lane header as rectangle with lane title centered in it
|
||||
const laneHeader = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
||||
|
||||
// Set attributes for the rectangle
|
||||
laneHeader.setAttribute("x",lane.x); // x-coordinate of the top-left corner
|
||||
laneHeader.setAttribute("y", -50); // y-coordinate of the top-left corner
|
||||
laneHeader.setAttribute("width", lane.width); // width of the rectangle
|
||||
laneHeader.setAttribute("height", "50"); // height of the rectangle
|
||||
if(laneCount % 2 == 0){
|
||||
//set light blue color for even lanes
|
||||
laneHeader.setAttribute("fill", "blue"); // fill color of the rectangle
|
||||
}else{
|
||||
//set white color odd lanes
|
||||
laneHeader.setAttribute("fill", "grey"); // fill color of the rectangle
|
||||
}
|
||||
|
||||
laneHeader.setAttribute("stroke", "black"); // color of the stroke/border
|
||||
laneHeader.setAttribute("stroke-width", "2"); // width of the stroke/border
|
||||
|
||||
// Append the rectangle to the SVG element
|
||||
lanesElements.node().appendChild(laneHeader);
|
||||
|
||||
//draw lane title
|
||||
const laneTitle = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
||||
|
||||
// Set attributes for the rectangle
|
||||
laneTitle.setAttribute("x",lane.x + lane.width/2); // x-coordinate of the top-left corner
|
||||
laneTitle.setAttribute("y", -50 + 50/2); // y-coordinate of the top-left corner
|
||||
laneTitle.setAttribute("width", lane.width); // width of the rectangle
|
||||
laneTitle.setAttribute("height", "50"); // height of the rectangle
|
||||
laneTitle.setAttribute("fill", "white"); // fill color of the rectangle
|
||||
laneTitle.setAttribute("stroke-width", "1"); // width of the stroke/border
|
||||
laneTitle.setAttribute("text-anchor", "middle"); // width of the stroke/border
|
||||
laneTitle.setAttribute("alignment-baseline", "middle"); // width of the stroke/border
|
||||
laneTitle.setAttribute("font-size", "20"); // width of the stroke/border
|
||||
laneTitle.textContent = lane.title;
|
||||
|
||||
// Append the rectangle to the SVG element
|
||||
lanesElements.node().appendChild(laneTitle);
|
||||
|
||||
//draw lane
|
||||
|
||||
// Create a <rect> element
|
||||
const rectangle = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
||||
|
||||
// Set attributes for the rectangle
|
||||
rectangle.setAttribute("x",lane.x); // x-coordinate of the top-left corner
|
||||
rectangle.setAttribute("y", 0); // y-coordinate of the top-left corner
|
||||
rectangle.setAttribute("width", lane.width); // width of the rectangle
|
||||
rectangle.setAttribute("height", "500"); // height of the rectangle
|
||||
|
||||
if(laneCount % 2 == 0){
|
||||
//set light blue color for even lanes
|
||||
rectangle.setAttribute("fill", "lightblue"); // fill color of the rectangle
|
||||
}else{
|
||||
//set white color odd lanes
|
||||
rectangle.setAttribute("fill", "#ffffff"); // fill color of the rectangle
|
||||
}
|
||||
|
||||
rectangle.setAttribute("stroke", "black"); // color of the stroke/border
|
||||
rectangle.setAttribute("stroke-width", "2"); // width of the stroke/border
|
||||
|
||||
// Append the rectangle to the SVG element
|
||||
lanesElements.node().appendChild(rectangle);
|
||||
}
|
||||
|
||||
// append lanesElements to elem
|
||||
svg.node().appendChild(lanesElements.node());
|
||||
|
||||
// add lane headers
|
||||
const laneHeaders = svg.insert('g').attr('class', 'laneHeaders');
|
||||
|
||||
let drawnEdges =[];
|
||||
|
||||
//get edge markers
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let renderedNodes = await swimlaneRender(layout,vert, svg,g,id, conf);
|
||||
let renderedEdgePaths= [];
|
||||
addEdges(edges, g, diagObj,svg);
|
||||
|
||||
g.edges().forEach(function (e) {
|
||||
const edge = g.edge(e);
|
||||
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);
|
||||
const edgePaths = svg.insert('g').attr('class', 'edgePaths');
|
||||
|
||||
|
||||
|
||||
//get start node x, y coordinates
|
||||
|
||||
let sourceNode = {x:layout.graph.node(e.v).x, y:layout.graph.node(e.v).y/2, id: e.v};
|
||||
//get end node x, y coordinates=
|
||||
const targetNode = {x:layout.graph.node(e.w).x, y:layout.graph.node(e.w).y/2, id: e.w};
|
||||
|
||||
|
||||
//create edge points based on start and end node
|
||||
edge.points = getEdgePoints(sourceNode, targetNode, drawnEdges, renderedNodes,renderedEdgePaths);
|
||||
|
||||
|
||||
// add to drawn edges
|
||||
drawnEdges.push(edge);
|
||||
|
||||
const paths = insertEdge(edgePaths, e, edge, clusterDb, 'flowchart', g);
|
||||
//positionEdgeLabel(edge, paths);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// utils.insertTitle(svg, 'flowchartTitleText', conf.titleTopMargin, diagObj.db.getDiagramTitle());
|
||||
|
||||
setupGraphViewbox(g, svg, conf.diagramPadding, conf.useMaxWidth);
|
||||
};
|
||||
|
||||
// function to find edge path points based on start and end node
|
||||
/**
|
||||
*
|
||||
* @param startNode
|
||||
* @param endNode
|
||||
* @param drawnEdges
|
||||
* @param renderedNodes
|
||||
*/
|
||||
function getEdgePoints(startNode, endNode, drawnEdges, renderedNodes) {
|
||||
|
||||
let potentialEdgePaths = [];
|
||||
|
||||
for(let i=1;i<=3;i++){
|
||||
const points = [];
|
||||
|
||||
// add start point
|
||||
points.push({ x: startNode.x, y: startNode.y })
|
||||
|
||||
// Point in the middle, if both nodes do not have same x or y
|
||||
if (startNode.x !== endNode.x && startNode.y !== endNode.y && i!=1) {
|
||||
|
||||
if(i==2){
|
||||
points.push({ x: startNode.x, y: endNode.y });
|
||||
}else{
|
||||
points.push({ x: endNode.x, y: startNode.y });
|
||||
}
|
||||
}
|
||||
// add end point
|
||||
points.push({ x: endNode.x, y: endNode.y });
|
||||
|
||||
|
||||
//print points
|
||||
console.log('points before intersection', points);
|
||||
|
||||
// get start and end node objects from array of rendered nodes
|
||||
const startNodeObj = renderedNodes.find(node => node.id === startNode.id);
|
||||
const endNodeObj = renderedNodes.find(node => node.id === endNode.id);
|
||||
|
||||
console.log(" intersection startNodeObj", startNodeObj);
|
||||
console.log(" intersection endNodeObj", endNodeObj);
|
||||
startNodeObj.nodeObj.x = startNode.x;
|
||||
startNodeObj.nodeObj.y = startNode.y;
|
||||
// the first point should be the intersection of the start node and the edge
|
||||
let startInsection = startNodeObj.nodeObj.intersect(points[1]);
|
||||
points[0] = startInsection;
|
||||
|
||||
//log intersection
|
||||
console.log('start intersection', startInsection);
|
||||
|
||||
endNodeObj.nodeObj.x = endNode.x;
|
||||
endNodeObj.nodeObj.y = endNode.y;
|
||||
// the last point should be the intersection of the end node and the edge
|
||||
let endInsection = endNodeObj.nodeObj.intersect(points[points.length - 2]);
|
||||
points[points.length - 1] = endInsection;
|
||||
|
||||
//log intersection
|
||||
console.log('end intersection', endInsection);
|
||||
|
||||
//push points to potential edge paths
|
||||
potentialEdgePaths.push({points: points});
|
||||
}
|
||||
|
||||
// Create a new list of renderedNodes without the start and end node
|
||||
const filteredRenderedNodes = renderedNodes.filter(node => node.id !== startNode.id && node.id !== endNode.id);
|
||||
|
||||
//Rank the potential edge path
|
||||
const rankedEdgePaths = rankEdgePaths(potentialEdgePaths, filteredRenderedNodes);
|
||||
if(startNode.id==='sheep' && endNode.id === 'dog'){
|
||||
console.log('sheep--> dog rankedEdgePaths', rankedEdgePaths);
|
||||
}
|
||||
|
||||
return rankedEdgePaths[0].edgePath.points;
|
||||
|
||||
}
|
||||
|
||||
// Function to check if a point is inside a nodes bounding box
|
||||
/**
|
||||
*
|
||||
* @param point
|
||||
* @param nodes
|
||||
*/
|
||||
function isPointInsideNode(point, nodes) {
|
||||
let isInside = false;
|
||||
for (const node of nodes) {
|
||||
if (
|
||||
point.x >= node.nodeObj.x &&
|
||||
point.x <= node.nodeObj.x + node.boundingBox.width &&
|
||||
point.y >= node.nodeObj.y &&
|
||||
point.y <= node.nodeObj.y + node.boundingBox.height
|
||||
) {
|
||||
isInside = true;
|
||||
}
|
||||
}
|
||||
return isInside;
|
||||
}
|
||||
|
||||
// Ranks edgePaths (points) based on the number of intersections with nodes
|
||||
/**
|
||||
*
|
||||
* @param edgePaths
|
||||
* @param nodes
|
||||
*/
|
||||
function rankEdgePaths(edgePaths, nodes) {
|
||||
let rankedEdgePaths = [];
|
||||
for (const edgePath of edgePaths) {
|
||||
let rank = 10 + edgePath.points.length;
|
||||
for (const point of edgePath.points) {
|
||||
if (isPointInsideNode(point, nodes)) {
|
||||
// remove edge path
|
||||
|
||||
}
|
||||
}
|
||||
rankedEdgePaths.push({ rank: rank, edgePath: edgePath });
|
||||
}
|
||||
|
||||
//sort on the basis of rank, highest rank first
|
||||
rankedEdgePaths.sort((a, b) => (a.rank < b.rank ? 1 : -1));
|
||||
return rankedEdgePaths;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to find if edge path is intersecting with any other edge path
|
||||
* @param edgePath
|
||||
* @param renderedEdgePaths
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isEdgePathIntersecting(edgePath, renderedEdgePaths) {
|
||||
let isIntersecting = false;
|
||||
for (const renderedEdgePath of renderedEdgePaths) {
|
||||
// check if line drawn from start point of edge path to start point of rendered edge path is intersecting with any other edge path
|
||||
|
||||
if (
|
||||
common.isLineIntersecting(
|
||||
edgePath.points[0],
|
||||
renderedEdgePath.points[0],
|
||||
edgePath.points[1],
|
||||
renderedEdgePath.points[1]
|
||||
)
|
||||
) {
|
||||
isIntersecting = true;
|
||||
}
|
||||
}
|
||||
return isIntersecting;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default {
|
||||
setConf,
|
||||
addVertices,
|
||||
addEdges,
|
||||
getClasses,
|
||||
draw,
|
||||
};
|
||||
@@ -0,0 +1,269 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('[Arrows] when parsing', () => {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('should handle a nodes and edges', function () {
|
||||
const res = flow.parser.parse('graph TD;\nA-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it("should handle angle bracket ' > ' as direction LR", function () {
|
||||
const res = flow.parser.parse('graph >;A-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
const direction = flow.parser.yy.getDirection();
|
||||
|
||||
expect(direction).toBe('LR');
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it("should handle angle bracket ' < ' as direction RL", function () {
|
||||
const res = flow.parser.parse('graph <;A-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
const direction = flow.parser.yy.getDirection();
|
||||
|
||||
expect(direction).toBe('RL');
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it("should handle caret ' ^ ' as direction BT", function () {
|
||||
const res = flow.parser.parse('graph ^;A-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
const direction = flow.parser.yy.getDirection();
|
||||
|
||||
expect(direction).toBe('BT');
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].length).toBe(1);
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it("should handle lower-case 'v' as direction TB", function () {
|
||||
const res = flow.parser.parse('graph v;A-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
const direction = flow.parser.yy.getDirection();
|
||||
|
||||
expect(direction).toBe('TB');
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle a nodes and edges and a space between link and node', function () {
|
||||
const res = flow.parser.parse('graph TD;A --> B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle a nodes and edges, a space between link and node and each line ending without semicolon', function () {
|
||||
const res = flow.parser.parse('graph TD\nA --> B\n style e red');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle statements ending without semicolon', function () {
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nB-->C');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(2);
|
||||
expect(edges[1].start).toBe('B');
|
||||
expect(edges[1].end).toBe('C');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
describe('it should handle multi directional arrows', function () {
|
||||
describe('point', function () {
|
||||
it('should handle double edged nodes and edges', function () {
|
||||
const res = flow.parser.parse('graph TD;\nA<-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle double edged nodes with text', function () {
|
||||
const res = flow.parser.parse('graph TD;\nA<-- text -->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('text');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle double edged nodes and edges on thick arrows', function () {
|
||||
const res = flow.parser.parse('graph TD;\nA<==>B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('thick');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle double edged nodes with text on thick arrows', function () {
|
||||
const res = flow.parser.parse('graph TD;\nA<== text ==>B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('text');
|
||||
expect(edges[0].stroke).toBe('thick');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle double edged nodes and edges on dotted arrows', function () {
|
||||
const res = flow.parser.parse('graph TD;\nA<-.->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('dotted');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle double edged nodes with text on dotted arrows', function () {
|
||||
const res = flow.parser.parse('graph TD;\nA<-. text .->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('text');
|
||||
expect(edges[0].stroke).toBe('dotted');
|
||||
expect(edges[0].length).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,154 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
import { cleanupComments } from '../../../diagram-api/comments.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('[Comments] when parsing', () => {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('should handle comments', function () {
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n%% Comment\n A-->B;'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle comments at the start', function () {
|
||||
const res = flow.parser.parse(cleanupComments('%% Comment\ngraph TD;\n A-->B;'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle comments at the end', function () {
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n A-->B\n %% Comment at the end\n'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle comments at the end no trailing newline', function () {
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n A-->B\n%% Comment'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle comments at the end many trailing newlines', function () {
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n A-->B\n%% Comment\n\n\n'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle no trailing newlines', function () {
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n A-->B'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle many trailing newlines', function () {
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n A-->B\n\n'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle a comment with blank rows in-between', function () {
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n\n\n %% Comment\n A-->B;'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle a comment with mermaid flowchart code in them', function () {
|
||||
const res = flow.parser.parse(
|
||||
cleanupComments(
|
||||
'graph TD;\n\n\n %% Test od>Odd shape]-->|Two line<br>edge comment|ro;\n A-->B;'
|
||||
)
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('when parsing directions', function () {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
flow.parser.yy.setGen('gen-2');
|
||||
});
|
||||
|
||||
it('should use default direction from top level', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
subgraph A
|
||||
a --> b
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(2);
|
||||
expect(subgraph.nodes[0]).toBe('b');
|
||||
expect(subgraph.nodes[1]).toBe('a');
|
||||
expect(subgraph.id).toBe('A');
|
||||
expect(subgraph.dir).toBe(undefined);
|
||||
});
|
||||
it('should handle a subgraph with a direction', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
subgraph A
|
||||
direction BT
|
||||
a --> b
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(2);
|
||||
expect(subgraph.nodes[0]).toBe('b');
|
||||
expect(subgraph.nodes[1]).toBe('a');
|
||||
expect(subgraph.id).toBe('A');
|
||||
expect(subgraph.dir).toBe('BT');
|
||||
});
|
||||
it('should use the last defined direction', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
subgraph A
|
||||
direction BT
|
||||
a --> b
|
||||
direction RL
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(2);
|
||||
expect(subgraph.nodes[0]).toBe('b');
|
||||
expect(subgraph.nodes[1]).toBe('a');
|
||||
expect(subgraph.id).toBe('A');
|
||||
expect(subgraph.dir).toBe('RL');
|
||||
});
|
||||
|
||||
it('should handle nested subgraphs 1', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
subgraph A
|
||||
direction RL
|
||||
b-->B
|
||||
a
|
||||
end
|
||||
a-->c
|
||||
subgraph B
|
||||
direction LR
|
||||
c
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(2);
|
||||
|
||||
const subgraphA = subgraphs.find((o) => o.id === 'A');
|
||||
const subgraphB = subgraphs.find((o) => o.id === 'B');
|
||||
|
||||
expect(subgraphB.nodes[0]).toBe('c');
|
||||
expect(subgraphB.dir).toBe('LR');
|
||||
expect(subgraphA.nodes).toContain('B');
|
||||
expect(subgraphA.nodes).toContain('b');
|
||||
expect(subgraphA.nodes).toContain('a');
|
||||
expect(subgraphA.nodes).not.toContain('c');
|
||||
expect(subgraphA.dir).toBe('RL');
|
||||
});
|
||||
});
|
||||
496
packages/mermaid/src/diagrams/swimlane/parser/flow-edges.spec.js
Normal file
496
packages/mermaid/src/diagrams/swimlane/parser/flow-edges.spec.js
Normal file
@@ -0,0 +1,496 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
const keywords = [
|
||||
'graph',
|
||||
'flowchart',
|
||||
'flowchart-elk',
|
||||
'style',
|
||||
'default',
|
||||
'linkStyle',
|
||||
'interpolate',
|
||||
'classDef',
|
||||
'class',
|
||||
'href',
|
||||
'call',
|
||||
'click',
|
||||
'_self',
|
||||
'_blank',
|
||||
'_parent',
|
||||
'_top',
|
||||
'end',
|
||||
'subgraph',
|
||||
'kitty',
|
||||
];
|
||||
|
||||
const doubleEndedEdges = [
|
||||
{ edgeStart: 'x--', edgeEnd: '--x', stroke: 'normal', type: 'double_arrow_cross' },
|
||||
{ edgeStart: 'x==', edgeEnd: '==x', stroke: 'thick', type: 'double_arrow_cross' },
|
||||
{ edgeStart: 'x-.', edgeEnd: '.-x', stroke: 'dotted', type: 'double_arrow_cross' },
|
||||
{ edgeStart: 'o--', edgeEnd: '--o', stroke: 'normal', type: 'double_arrow_circle' },
|
||||
{ edgeStart: 'o==', edgeEnd: '==o', stroke: 'thick', type: 'double_arrow_circle' },
|
||||
{ edgeStart: 'o-.', edgeEnd: '.-o', stroke: 'dotted', type: 'double_arrow_circle' },
|
||||
{ edgeStart: '<--', edgeEnd: '-->', stroke: 'normal', type: 'double_arrow_point' },
|
||||
{ edgeStart: '<==', edgeEnd: '==>', stroke: 'thick', type: 'double_arrow_point' },
|
||||
{ edgeStart: '<-.', edgeEnd: '.->', stroke: 'dotted', type: 'double_arrow_point' },
|
||||
];
|
||||
|
||||
describe('[Edges] when parsing', () => {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('should handle open ended edges', function () {
|
||||
const res = flow.parser.parse('graph TD;A---B;');
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_open');
|
||||
});
|
||||
|
||||
it('should handle cross ended edges', function () {
|
||||
const res = flow.parser.parse('graph TD;A--xB;');
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
});
|
||||
|
||||
it('should handle open ended edges', function () {
|
||||
const res = flow.parser.parse('graph TD;A--oB;');
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_circle');
|
||||
});
|
||||
|
||||
describe('edges', function () {
|
||||
doubleEndedEdges.forEach((edgeType) => {
|
||||
it(`should handle ${edgeType.stroke} ${edgeType.type} with no text`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA ${edgeType.edgeStart}${edgeType.edgeEnd} B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe(`${edgeType.type}`);
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
|
||||
});
|
||||
|
||||
it(`should handle ${edgeType.stroke} ${edgeType.type} with text`, function () {
|
||||
const res = flow.parser.parse(
|
||||
`graph TD;\nA ${edgeType.edgeStart} text ${edgeType.edgeEnd} B;`
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe(`${edgeType.type}`);
|
||||
expect(edges[0].text).toBe('text');
|
||||
expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
|
||||
});
|
||||
|
||||
it.each(keywords)(
|
||||
`should handle ${edgeType.stroke} ${edgeType.type} with %s text`,
|
||||
function (keyword) {
|
||||
const res = flow.parser.parse(
|
||||
`graph TD;\nA ${edgeType.edgeStart} ${keyword} ${edgeType.edgeEnd} B;`
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe(`${edgeType.type}`);
|
||||
expect(edges[0].text).toBe(`${keyword}`);
|
||||
expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple edges', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;A---|This is the 123 s text|B;\nA---|This is the second edge|B;'
|
||||
);
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(2);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_open');
|
||||
expect(edges[0].text).toBe('This is the 123 s text');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(1);
|
||||
expect(edges[1].start).toBe('A');
|
||||
expect(edges[1].end).toBe('B');
|
||||
expect(edges[1].type).toBe('arrow_open');
|
||||
expect(edges[1].text).toBe('This is the second edge');
|
||||
expect(edges[1].stroke).toBe('normal');
|
||||
expect(edges[1].length).toBe(1);
|
||||
});
|
||||
|
||||
describe('edge length', function () {
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle normal edges with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA -${'-'.repeat(length)}- B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_open');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle normal labelled edges with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA -- Label -${'-'.repeat(length)}- B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_open');
|
||||
expect(edges[0].text).toBe('Label');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle normal edges with arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA -${'-'.repeat(length)}> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle normal labelled edges with arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA -- Label -${'-'.repeat(length)}> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('Label');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle normal edges with double arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA <-${'-'.repeat(length)}> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle normal labelled edges with double arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA <-- Label -${'-'.repeat(length)}> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('Label');
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle thick edges with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA =${'='.repeat(length)}= B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_open');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('thick');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle thick labelled edges with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA == Label =${'='.repeat(length)}= B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_open');
|
||||
expect(edges[0].text).toBe('Label');
|
||||
expect(edges[0].stroke).toBe('thick');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle thick edges with arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA =${'='.repeat(length)}> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('thick');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle thick labelled edges with arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA == Label =${'='.repeat(length)}> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('Label');
|
||||
expect(edges[0].stroke).toBe('thick');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle thick edges with double arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA <=${'='.repeat(length)}> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('thick');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle thick labelled edges with double arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA <== Label =${'='.repeat(length)}> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('Label');
|
||||
expect(edges[0].stroke).toBe('thick');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle dotted edges with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA -${'.'.repeat(length)}- B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_open');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('dotted');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle dotted labelled edges with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA -. Label ${'.'.repeat(length)}- B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_open');
|
||||
expect(edges[0].text).toBe('Label');
|
||||
expect(edges[0].stroke).toBe('dotted');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle dotted edges with arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA -${'.'.repeat(length)}-> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('dotted');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle dotted labelled edges with arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA -. Label ${'.'.repeat(length)}-> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('Label');
|
||||
expect(edges[0].stroke).toBe('dotted');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle dotted edges with double arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA <-${'.'.repeat(length)}-> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[0].stroke).toBe('dotted');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
|
||||
for (let length = 1; length <= 3; ++length) {
|
||||
it(`should handle dotted edges with double arrows with length ${length}`, function () {
|
||||
const res = flow.parser.parse(`graph TD;\nA <-. Label ${'.'.repeat(length)}-> B;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('double_arrow_point');
|
||||
expect(edges[0].text).toBe('Label');
|
||||
expect(edges[0].stroke).toBe('dotted');
|
||||
expect(edges[0].length).toBe(length);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('[Text] when parsing', () => {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
describe('it should handle huge files', function () {
|
||||
// skipped because this test takes like 2 minutes or more!
|
||||
it.skip('it should handlehuge diagrams', function () {
|
||||
const nodes = ('A-->B;B-->A;'.repeat(415) + 'A-->B;').repeat(57) + 'A-->B;B-->A;'.repeat(275);
|
||||
flow.parser.parse(`graph LR;${nodes}`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges.length).toBe(47917);
|
||||
expect(vert.size).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,158 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
import { vi } from 'vitest';
|
||||
const spyOn = vi.spyOn;
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('[Interactions] when parsing', () => {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('should be possible to use click to a callback', function () {
|
||||
spyOn(flowDb, 'setClickEvent');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A callback');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setClickEvent).toHaveBeenCalledWith('A', 'callback');
|
||||
});
|
||||
|
||||
it('should be possible to use click to a click and call callback', function () {
|
||||
spyOn(flowDb, 'setClickEvent');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A call callback()');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setClickEvent).toHaveBeenCalledWith('A', 'callback');
|
||||
});
|
||||
|
||||
it('should be possible to use click to a callback with toolip', function () {
|
||||
spyOn(flowDb, 'setClickEvent');
|
||||
spyOn(flowDb, 'setTooltip');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A callback "tooltip"');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setClickEvent).toHaveBeenCalledWith('A', 'callback');
|
||||
expect(flowDb.setTooltip).toHaveBeenCalledWith('A', 'tooltip');
|
||||
});
|
||||
|
||||
it('should be possible to use click to a click and call callback with toolip', function () {
|
||||
spyOn(flowDb, 'setClickEvent');
|
||||
spyOn(flowDb, 'setTooltip');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A call callback() "tooltip"');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setClickEvent).toHaveBeenCalledWith('A', 'callback');
|
||||
expect(flowDb.setTooltip).toHaveBeenCalledWith('A', 'tooltip');
|
||||
});
|
||||
|
||||
it('should be possible to use click to a callback with an arbitrary number of args', function () {
|
||||
spyOn(flowDb, 'setClickEvent');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A call callback("test0", test1, test2)');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setClickEvent).toHaveBeenCalledWith('A', 'callback', '"test0", test1, test2');
|
||||
});
|
||||
|
||||
it('should handle interaction - click to a link', function () {
|
||||
spyOn(flowDb, 'setLink');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A "click.html"');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html');
|
||||
});
|
||||
|
||||
it('should handle interaction - click to a click and href link', function () {
|
||||
spyOn(flowDb, 'setLink');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A href "click.html"');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html');
|
||||
});
|
||||
|
||||
it('should handle interaction - click to a link with tooltip', function () {
|
||||
spyOn(flowDb, 'setLink');
|
||||
spyOn(flowDb, 'setTooltip');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A "click.html" "tooltip"');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html');
|
||||
expect(flowDb.setTooltip).toHaveBeenCalledWith('A', 'tooltip');
|
||||
});
|
||||
|
||||
it('should handle interaction - click to a click and href link with tooltip', function () {
|
||||
spyOn(flowDb, 'setLink');
|
||||
spyOn(flowDb, 'setTooltip');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A href "click.html" "tooltip"');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html');
|
||||
expect(flowDb.setTooltip).toHaveBeenCalledWith('A', 'tooltip');
|
||||
});
|
||||
|
||||
it('should handle interaction - click to a link with target', function () {
|
||||
spyOn(flowDb, 'setLink');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A "click.html" _blank');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', '_blank');
|
||||
});
|
||||
|
||||
it('should handle interaction - click to a click and href link with target', function () {
|
||||
spyOn(flowDb, 'setLink');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A href "click.html" _blank');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', '_blank');
|
||||
});
|
||||
|
||||
it('should handle interaction - click to a link with tooltip and target', function () {
|
||||
spyOn(flowDb, 'setLink');
|
||||
spyOn(flowDb, 'setTooltip');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A "click.html" "tooltip" _blank');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', '_blank');
|
||||
expect(flowDb.setTooltip).toHaveBeenCalledWith('A', 'tooltip');
|
||||
});
|
||||
|
||||
it('should handle interaction - click to a click and href link with tooltip and target', function () {
|
||||
spyOn(flowDb, 'setLink');
|
||||
spyOn(flowDb, 'setTooltip');
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclick A href "click.html" "tooltip" _blank');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', '_blank');
|
||||
expect(flowDb.setTooltip).toHaveBeenCalledWith('A', 'tooltip');
|
||||
});
|
||||
});
|
||||
119
packages/mermaid/src/diagrams/swimlane/parser/flow-lines.spec.js
Normal file
119
packages/mermaid/src/diagrams/swimlane/parser/flow-lines.spec.js
Normal file
@@ -0,0 +1,119 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('[Lines] when parsing', () => {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('should handle line interpolation default definitions', function () {
|
||||
const res = flow.parser.parse('graph TD\n' + 'A-->B\n' + 'linkStyle default interpolate basis');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.defaultInterpolate).toBe('basis');
|
||||
});
|
||||
|
||||
it('should handle line interpolation numbered definitions', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD\n' +
|
||||
'A-->B\n' +
|
||||
'A-->C\n' +
|
||||
'linkStyle 0 interpolate basis\n' +
|
||||
'linkStyle 1 interpolate cardinal'
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].interpolate).toBe('basis');
|
||||
expect(edges[1].interpolate).toBe('cardinal');
|
||||
});
|
||||
|
||||
it('should handle line interpolation multi-numbered definitions', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD\n' + 'A-->B\n' + 'A-->C\n' + 'linkStyle 0,1 interpolate basis'
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].interpolate).toBe('basis');
|
||||
expect(edges[1].interpolate).toBe('basis');
|
||||
});
|
||||
|
||||
it('should handle line interpolation default with style', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD\n' + 'A-->B\n' + 'linkStyle default interpolate basis stroke-width:1px;'
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.defaultInterpolate).toBe('basis');
|
||||
});
|
||||
|
||||
it('should handle line interpolation numbered with style', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD\n' +
|
||||
'A-->B\n' +
|
||||
'A-->C\n' +
|
||||
'linkStyle 0 interpolate basis stroke-width:1px;\n' +
|
||||
'linkStyle 1 interpolate cardinal stroke-width:1px;'
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].interpolate).toBe('basis');
|
||||
expect(edges[1].interpolate).toBe('cardinal');
|
||||
});
|
||||
|
||||
it('should handle line interpolation multi-numbered with style', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD\n' + 'A-->B\n' + 'A-->C\n' + 'linkStyle 0,1 interpolate basis stroke-width:1px;'
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].interpolate).toBe('basis');
|
||||
expect(edges[1].interpolate).toBe('basis');
|
||||
});
|
||||
|
||||
describe('it should handle new line type notation', function () {
|
||||
it('should handle regular lines', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
});
|
||||
|
||||
it('should handle dotted lines', function () {
|
||||
const res = flow.parser.parse('graph TD;A-.->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].stroke).toBe('dotted');
|
||||
});
|
||||
|
||||
it('should handle dotted lines', function () {
|
||||
const res = flow.parser.parse('graph TD;A==>B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].stroke).toBe('thick');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('parsing a flow chart with markdown strings', function () {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('mardown formatting in nodes and labels', function () {
|
||||
const res = flow.parser.parse(`flowchart
|
||||
A["\`The cat in **the** hat\`"]-- "\`The *bat* in the chat\`" -->B["The dog in the hog"] -- "The rat in the mat" -->C;`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('A').text).toBe('The cat in **the** hat');
|
||||
expect(vert.get('A').labelType).toBe('markdown');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(vert.get('B').text).toBe('The dog in the hog');
|
||||
expect(vert.get('B').labelType).toBe('string');
|
||||
expect(edges.length).toBe(2);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('The *bat* in the chat');
|
||||
expect(edges[0].labelType).toBe('markdown');
|
||||
expect(edges[1].start).toBe('B');
|
||||
expect(edges[1].end).toBe('C');
|
||||
expect(edges[1].type).toBe('arrow_point');
|
||||
expect(edges[1].text).toBe('The rat in the mat');
|
||||
expect(edges[1].labelType).toBe('string');
|
||||
});
|
||||
it('mardown formatting in subgraphs', function () {
|
||||
const res = flow.parser.parse(`flowchart LR
|
||||
subgraph "One"
|
||||
a("\`The **cat**
|
||||
in the hat\`") -- "1o" --> b{{"\`The **dog** in the hog\`"}}
|
||||
end
|
||||
subgraph "\`**Two**\`"
|
||||
c("\`The **cat**
|
||||
in the hat\`") -- "\`1o **ipa**\`" --> d("The dog in the hog")
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(2);
|
||||
const subgraph = subgraphs[0];
|
||||
|
||||
expect(subgraph.nodes.length).toBe(2);
|
||||
expect(subgraph.title).toBe('One');
|
||||
expect(subgraph.labelType).toBe('text');
|
||||
|
||||
const subgraph2 = subgraphs[1];
|
||||
expect(subgraph2.nodes.length).toBe(2);
|
||||
expect(subgraph2.title).toBe('**Two**');
|
||||
expect(subgraph2.labelType).toBe('markdown');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,293 @@
|
||||
import flowDb from '../swimlaneDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('when parsing directions', function () {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
flow.parser.yy.setGen('gen-2');
|
||||
});
|
||||
|
||||
it('should handle basic shape data statements', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded}`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
});
|
||||
it('should handle basic shape data statements', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded }`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
});
|
||||
|
||||
it('should handle basic shape data statements with &', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded } & E`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(2);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
expect(data4Layout.nodes[1].label).toEqual('E');
|
||||
});
|
||||
it('should handle shape data statements with edges', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded } --> E`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(2);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
expect(data4Layout.nodes[1].label).toEqual('E');
|
||||
});
|
||||
it('should handle basic shape data statements with amp and edges 1', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded } & E --> F`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(3);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
expect(data4Layout.nodes[1].label).toEqual('E');
|
||||
});
|
||||
it('should handle basic shape data statements with amp and edges 2', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded } & E@{ shape: rounded } --> F`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(3);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
expect(data4Layout.nodes[1].label).toEqual('E');
|
||||
});
|
||||
it('should handle basic shape data statements with amp and edges 3', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded } & E@{ shape: rounded } --> F & G@{ shape: rounded }`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(4);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
expect(data4Layout.nodes[1].label).toEqual('E');
|
||||
});
|
||||
it('should handle basic shape data statements with amp and edges 4', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded } & E@{ shape: rounded } --> F@{ shape: rounded } & G@{ shape: rounded }`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(4);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
expect(data4Layout.nodes[1].label).toEqual('E');
|
||||
});
|
||||
it('should handle basic shape data statements with amp and edges 5, trailing space', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded } & E@{ shape: rounded } --> F{ shape: rounded } & G{ shape: rounded } `);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(4);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
expect(data4Layout.nodes[1].label).toEqual('E');
|
||||
});
|
||||
it('should no matter of there are no leading spaces', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{shape: rounded}`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
});
|
||||
|
||||
it('should no matter of there are many leading spaces', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded}`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
});
|
||||
|
||||
it('should be forgiving with many spaces before teh end', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded }`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('D');
|
||||
});
|
||||
it('should be possible to add multiple properties on the same line', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
D@{ shape: rounded , label: "DD"}`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('rounded');
|
||||
expect(data4Layout.nodes[0].label).toEqual('DD');
|
||||
});
|
||||
it('should be possible to link to a node with more data', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
A --> D@{
|
||||
shape: circle
|
||||
other: "clock"
|
||||
}
|
||||
|
||||
`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(2);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
|
||||
expect(data4Layout.nodes[0].label).toEqual('A');
|
||||
expect(data4Layout.nodes[1].label).toEqual('D');
|
||||
expect(data4Layout.nodes[1].shape).toEqual('circle');
|
||||
|
||||
expect(data4Layout.edges.length).toBe(1);
|
||||
});
|
||||
it('should not disturb adding multiple nodes after each other', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
A[hello]
|
||||
B@{
|
||||
shape: circle
|
||||
other: "clock"
|
||||
}
|
||||
C[Hello]@{
|
||||
shape: circle
|
||||
other: "clock"
|
||||
}
|
||||
`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(3);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
|
||||
expect(data4Layout.nodes[0].label).toEqual('hello');
|
||||
expect(data4Layout.nodes[1].shape).toEqual('circle');
|
||||
expect(data4Layout.nodes[1].label).toEqual('B');
|
||||
expect(data4Layout.nodes[2].shape).toEqual('circle');
|
||||
expect(data4Layout.nodes[2].label).toEqual('Hello');
|
||||
});
|
||||
it('should use handle bracket end (}) character inside the shape data', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
A@{
|
||||
label: "This is }"
|
||||
other: "clock"
|
||||
}
|
||||
`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
|
||||
expect(data4Layout.nodes[0].label).toEqual('This is }');
|
||||
});
|
||||
it('should error on non-existent shape', function () {
|
||||
expect(() => {
|
||||
flow.parser.parse(`flowchart TB
|
||||
A@{ shape: this-shape-does-not-exist }
|
||||
`);
|
||||
}).toThrow('No such shape: this-shape-does-not-exist.');
|
||||
});
|
||||
it('should error on internal-only shape', function () {
|
||||
expect(() => {
|
||||
// this shape does exist, but it's only supposed to be for internal/backwards compatibility use
|
||||
flow.parser.parse(`flowchart TB
|
||||
A@{ shape: rect_left_inv_arrow }
|
||||
`);
|
||||
}).toThrow('No such shape: rect_left_inv_arrow. Shape names should be lowercase.');
|
||||
});
|
||||
it('Diamond shapes should work as usual', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
A{This is a label}
|
||||
`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('diamond');
|
||||
expect(data4Layout.nodes[0].label).toEqual('This is a label');
|
||||
});
|
||||
it('Multi line strings should be supported', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
A@{
|
||||
label: |
|
||||
This is a
|
||||
multiline string
|
||||
other: "clock"
|
||||
}
|
||||
`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
|
||||
expect(data4Layout.nodes[0].label).toEqual('This is a\nmultiline string\n');
|
||||
});
|
||||
it('Multi line strings should be supported', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
A@{
|
||||
label: "This is a
|
||||
multiline string"
|
||||
other: "clock"
|
||||
}
|
||||
`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
|
||||
expect(data4Layout.nodes[0].label).toEqual('This is a<br/>multiline string');
|
||||
});
|
||||
it(' should be possible to use } in strings', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
A@{
|
||||
label: "This is a string with }"
|
||||
other: "clock"
|
||||
}
|
||||
`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
|
||||
expect(data4Layout.nodes[0].label).toEqual('This is a string with }');
|
||||
});
|
||||
it(' should be possible to use @ in strings', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
A@{
|
||||
label: "This is a string with @"
|
||||
other: "clock"
|
||||
}
|
||||
`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
|
||||
expect(data4Layout.nodes[0].label).toEqual('This is a string with @');
|
||||
});
|
||||
it(' should be possible to use @ in strings', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
A@{
|
||||
label: "This is a string with}"
|
||||
other: "clock"
|
||||
}
|
||||
`);
|
||||
|
||||
const data4Layout = flow.parser.yy.getData();
|
||||
expect(data4Layout.nodes.length).toBe(1);
|
||||
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
|
||||
expect(data4Layout.nodes[0].label).toEqual('This is a string with}');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,371 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
const keywords = [
|
||||
'graph',
|
||||
'flowchart',
|
||||
'flowchart-elk',
|
||||
'style',
|
||||
'default',
|
||||
'linkStyle',
|
||||
'interpolate',
|
||||
'classDef',
|
||||
'class',
|
||||
'href',
|
||||
'call',
|
||||
'click',
|
||||
'_self',
|
||||
'_blank',
|
||||
'_parent',
|
||||
'_top',
|
||||
'end',
|
||||
'subgraph',
|
||||
];
|
||||
|
||||
const specialChars = ['#', ':', '0', '&', ',', '*', '.', '\\', 'v', '-', '/', '_'];
|
||||
|
||||
describe('[Singlenodes] when parsing', () => {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('should handle a single node', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;A;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('A').styles.length).toBe(0);
|
||||
});
|
||||
it('should handle a single node with white space after it (SN1)', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;A ;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('A').styles.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle a single square node', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a[A];');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').styles.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('square');
|
||||
});
|
||||
|
||||
it('should handle a single round square node', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a[A];');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').styles.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('square');
|
||||
});
|
||||
|
||||
it('should handle a single circle node', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a((A));');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('circle');
|
||||
});
|
||||
|
||||
it('should handle a single round node', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a(A);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('round');
|
||||
});
|
||||
|
||||
it('should handle a single odd node', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a>A];');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('odd');
|
||||
});
|
||||
|
||||
it('should handle a single diamond node', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a{A};');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('diamond');
|
||||
});
|
||||
|
||||
it('should handle a single diamond node with whitespace after it', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a{A} ;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('diamond');
|
||||
});
|
||||
|
||||
it('should handle a single diamond node with html in it (SN3)', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a{A <br> end};');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('diamond');
|
||||
expect(vert.get('a').text).toBe('A <br> end');
|
||||
});
|
||||
|
||||
it('should handle a single hexagon node', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a{{A}};');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('hexagon');
|
||||
});
|
||||
|
||||
it('should handle a single hexagon node with html in it', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a{{A <br> end}};');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('hexagon');
|
||||
expect(vert.get('a').text).toBe('A <br> end');
|
||||
});
|
||||
|
||||
it('should handle a single round node with html in it', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a(A <br> end);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('round');
|
||||
expect(vert.get('a').text).toBe('A <br> end');
|
||||
});
|
||||
|
||||
it('should handle a single double circle node', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a(((A)));');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('doublecircle');
|
||||
});
|
||||
|
||||
it('should handle a single double circle node with whitespace after it', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a(((A))) ;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('doublecircle');
|
||||
});
|
||||
|
||||
it('should handle a single double circle node with html in it (SN3)', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;a(((A <br> end)));');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('a').type).toBe('doublecircle');
|
||||
expect(vert.get('a').text).toBe('A <br> end');
|
||||
});
|
||||
|
||||
it('should handle a single node with alphanumerics starting on a char', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;id1;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('id1').styles.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle a single node with a single digit', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;1;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('1').text).toBe('1');
|
||||
});
|
||||
|
||||
it('should handle a single node with a single digit in a subgraph', function () {
|
||||
// Silly but syntactically correct
|
||||
|
||||
const res = flow.parser.parse('graph TD;subgraph "hello";1;end;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('1').text).toBe('1');
|
||||
});
|
||||
|
||||
it('should handle a single node with alphanumerics starting on a num', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;1id;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('1id').styles.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle a single node with alphanumerics containing a minus sign', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;i-d;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('i-d').styles.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle a single node with alphanumerics containing a underscore sign', function () {
|
||||
// Silly but syntactically correct
|
||||
const res = flow.parser.parse('graph TD;i_d;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert.get('i_d').styles.length).toBe(0);
|
||||
});
|
||||
|
||||
it.each(keywords)('should handle keywords between dashes "-"', function (keyword) {
|
||||
const res = flow.parser.parse(`graph TD;a-${keyword}-node;`);
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
expect(vert.get(`a-${keyword}-node`).text).toBe(`a-${keyword}-node`);
|
||||
});
|
||||
|
||||
it.each(keywords)('should handle keywords between periods "."', function (keyword) {
|
||||
const res = flow.parser.parse(`graph TD;a.${keyword}.node;`);
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
expect(vert.get(`a.${keyword}.node`).text).toBe(`a.${keyword}.node`);
|
||||
});
|
||||
|
||||
it.each(keywords)('should handle keywords between underscores "_"', function (keyword) {
|
||||
const res = flow.parser.parse(`graph TD;a_${keyword}_node;`);
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
expect(vert.get(`a_${keyword}_node`).text).toBe(`a_${keyword}_node`);
|
||||
});
|
||||
|
||||
it.each(keywords)('should handle nodes ending in %s', function (keyword) {
|
||||
const res = flow.parser.parse(`graph TD;node_${keyword};node.${keyword};node-${keyword};`);
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
expect(vert.get(`node_${keyword}`).text).toBe(`node_${keyword}`);
|
||||
expect(vert.get(`node.${keyword}`).text).toBe(`node.${keyword}`);
|
||||
expect(vert.get(`node-${keyword}`).text).toBe(`node-${keyword}`);
|
||||
});
|
||||
|
||||
const errorKeywords = [
|
||||
'graph',
|
||||
'flowchart',
|
||||
'flowchart-elk',
|
||||
'style',
|
||||
'linkStyle',
|
||||
'interpolate',
|
||||
'classDef',
|
||||
'class',
|
||||
'_self',
|
||||
'_blank',
|
||||
'_parent',
|
||||
'_top',
|
||||
'end',
|
||||
'subgraph',
|
||||
];
|
||||
it.each(errorKeywords)('should throw error at nodes beginning with %s', function (keyword) {
|
||||
const str = `graph TD;${keyword}.node;${keyword}-node;${keyword}/node`;
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
|
||||
expect(() => flow.parser.parse(str)).toThrowError();
|
||||
});
|
||||
|
||||
const workingKeywords = ['default', 'href', 'click', 'call'];
|
||||
|
||||
it.each(workingKeywords)('should parse node beginning with %s', function (keyword) {
|
||||
flow.parser.parse(`graph TD; ${keyword}.node;${keyword}-node;${keyword}/node;`);
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
expect(vert.get(`${keyword}.node`).text).toBe(`${keyword}.node`);
|
||||
expect(vert.get(`${keyword}-node`).text).toBe(`${keyword}-node`);
|
||||
expect(vert.get(`${keyword}/node`).text).toBe(`${keyword}/node`);
|
||||
});
|
||||
|
||||
it.each(specialChars)(
|
||||
'should allow node ids of single special characters',
|
||||
function (specialChar) {
|
||||
flow.parser.parse(`graph TD; ${specialChar} --> A`);
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
expect(vert.get(`${specialChar}`).text).toBe(`${specialChar}`);
|
||||
}
|
||||
);
|
||||
|
||||
it.each(specialChars)(
|
||||
'should allow node ids with special characters at start of id',
|
||||
function (specialChar) {
|
||||
flow.parser.parse(`graph TD; ${specialChar}node --> A`);
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
expect(vert.get(`${specialChar}node`).text).toBe(`${specialChar}node`);
|
||||
}
|
||||
);
|
||||
|
||||
it.each(specialChars)(
|
||||
'should allow node ids with special characters at end of id',
|
||||
function (specialChar) {
|
||||
flow.parser.parse(`graph TD; node${specialChar} --> A`);
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
expect(vert.get(`node${specialChar}`).text).toBe(`node${specialChar}`);
|
||||
}
|
||||
);
|
||||
});
|
||||
370
packages/mermaid/src/diagrams/swimlane/parser/flow-style.spec.js
Normal file
370
packages/mermaid/src/diagrams/swimlane/parser/flow-style.spec.js
Normal file
@@ -0,0 +1,370 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('[Style] when parsing', () => {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
flow.parser.yy.setGen('gen-2');
|
||||
});
|
||||
|
||||
// log.debug(flow.parser.parse('graph TD;style Q background:#fff;'));
|
||||
it('should handle styles for vertices', function () {
|
||||
const res = flow.parser.parse('graph TD;style Q background:#fff;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('Q').styles.length).toBe(1);
|
||||
expect(vert.get('Q').styles[0]).toBe('background:#fff');
|
||||
});
|
||||
|
||||
it('should handle multiple styles for a vortex', function () {
|
||||
const res = flow.parser.parse('graph TD;style R background:#fff,border:1px solid red;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('R').styles.length).toBe(2);
|
||||
expect(vert.get('R').styles[0]).toBe('background:#fff');
|
||||
expect(vert.get('R').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
|
||||
it('should handle multiple styles in a graph', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;style S background:#aaa;\nstyle T background:#bbb,border:1px solid red;'
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('S').styles.length).toBe(1);
|
||||
expect(vert.get('T').styles.length).toBe(2);
|
||||
expect(vert.get('S').styles[0]).toBe('background:#aaa');
|
||||
expect(vert.get('T').styles[0]).toBe('background:#bbb');
|
||||
expect(vert.get('T').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
|
||||
it('should handle styles and graph definitions in a graph', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;S-->T;\nstyle S background:#aaa;\nstyle T background:#bbb,border:1px solid red;'
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('S').styles.length).toBe(1);
|
||||
expect(vert.get('T').styles.length).toBe(2);
|
||||
expect(vert.get('S').styles[0]).toBe('background:#aaa');
|
||||
expect(vert.get('T').styles[0]).toBe('background:#bbb');
|
||||
expect(vert.get('T').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
|
||||
it('should handle styles and graph definitions in a graph', function () {
|
||||
const res = flow.parser.parse('graph TD;style T background:#bbb,border:1px solid red;');
|
||||
// const res = flow.parser.parse('graph TD;style T background: #bbb;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
|
||||
expect(vert.get('T').styles.length).toBe(2);
|
||||
expect(vert.get('T').styles[0]).toBe('background:#bbb');
|
||||
expect(vert.get('T').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
|
||||
it('should keep node label text (if already defined) when a style is applied', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;A(( ));B((Test));C;style A background:#fff;style D border:1px solid red;'
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
|
||||
expect(vert.get('A').text).toBe('');
|
||||
expect(vert.get('B').text).toBe('Test');
|
||||
expect(vert.get('C').text).toBe('C');
|
||||
expect(vert.get('D').text).toBe('D');
|
||||
});
|
||||
|
||||
it('should be possible to declare a class', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;classDef exClass background:#bbb,border:1px solid red;'
|
||||
);
|
||||
// const res = flow.parser.parse('graph TD;style T background: #bbb;');
|
||||
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes.get('exClass').styles.length).toBe(2);
|
||||
expect(classes.get('exClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('exClass').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
|
||||
it('should be possible to declare multiple classes', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;classDef firstClass,secondClass background:#bbb,border:1px solid red;'
|
||||
);
|
||||
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes.get('firstClass').styles.length).toBe(2);
|
||||
expect(classes.get('firstClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('firstClass').styles[1]).toBe('border:1px solid red');
|
||||
|
||||
expect(classes.get('secondClass').styles.length).toBe(2);
|
||||
expect(classes.get('secondClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('secondClass').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
|
||||
it('should be possible to declare a class with a dot in the style', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;classDef exClass background:#bbb,border:1.5px solid red;'
|
||||
);
|
||||
// const res = flow.parser.parse('graph TD;style T background: #bbb;');
|
||||
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes.get('exClass').styles.length).toBe(2);
|
||||
expect(classes.get('exClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('exClass').styles[1]).toBe('border:1.5px solid red');
|
||||
});
|
||||
it('should be possible to declare a class with a space in the style', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;classDef exClass background: #bbb,border:1.5px solid red;'
|
||||
);
|
||||
// const res = flow.parser.parse('graph TD;style T background : #bbb;');
|
||||
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes.get('exClass').styles.length).toBe(2);
|
||||
expect(classes.get('exClass').styles[0]).toBe('background: #bbb');
|
||||
expect(classes.get('exClass').styles[1]).toBe('border:1.5px solid red');
|
||||
});
|
||||
it('should be possible to apply a class to a vertex', function () {
|
||||
let statement = '';
|
||||
|
||||
statement = statement + 'graph TD;' + '\n';
|
||||
statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n';
|
||||
statement = statement + 'a-->b;' + '\n';
|
||||
statement = statement + 'class a exClass;';
|
||||
|
||||
const res = flow.parser.parse(statement);
|
||||
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes.get('exClass').styles.length).toBe(2);
|
||||
expect(classes.get('exClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('exClass').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
it('should be possible to apply a class to a vertex with an id containing _', function () {
|
||||
let statement = '';
|
||||
|
||||
statement = statement + 'graph TD;' + '\n';
|
||||
statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n';
|
||||
statement = statement + 'a_a-->b_b;' + '\n';
|
||||
statement = statement + 'class a_a exClass;';
|
||||
|
||||
const res = flow.parser.parse(statement);
|
||||
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes.get('exClass').styles.length).toBe(2);
|
||||
expect(classes.get('exClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('exClass').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
it('should be possible to apply a class to a vertex directly', function () {
|
||||
let statement = '';
|
||||
|
||||
statement = statement + 'graph TD;' + '\n';
|
||||
statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n';
|
||||
statement = statement + 'a-->b[test]:::exClass;' + '\n';
|
||||
|
||||
const res = flow.parser.parse(statement);
|
||||
const vertices = flow.parser.yy.getVertices();
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes.get('exClass').styles.length).toBe(2);
|
||||
expect(vertices.get('b').classes[0]).toBe('exClass');
|
||||
expect(classes.get('exClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('exClass').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
|
||||
it('should be possible to apply a class to a vertex directly : usecase A[text].class ', function () {
|
||||
let statement = '';
|
||||
|
||||
statement = statement + 'graph TD;' + '\n';
|
||||
statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n';
|
||||
statement = statement + 'b[test]:::exClass;' + '\n';
|
||||
|
||||
const res = flow.parser.parse(statement);
|
||||
const vertices = flow.parser.yy.getVertices();
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes.get('exClass').styles.length).toBe(2);
|
||||
expect(vertices.get('b').classes[0]).toBe('exClass');
|
||||
expect(classes.get('exClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('exClass').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
|
||||
it('should be possible to apply a class to a vertex directly : usecase A[text].class-->B[test2] ', function () {
|
||||
let statement = '';
|
||||
|
||||
statement = statement + 'graph TD;' + '\n';
|
||||
statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n';
|
||||
statement = statement + 'A[test]:::exClass-->B[test2];' + '\n';
|
||||
|
||||
const res = flow.parser.parse(statement);
|
||||
const vertices = flow.parser.yy.getVertices();
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes.get('exClass').styles.length).toBe(2);
|
||||
expect(vertices.get('A').classes[0]).toBe('exClass');
|
||||
expect(classes.get('exClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('exClass').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
|
||||
it('should be possible to apply a class to a vertex directly 2', function () {
|
||||
let statement = '';
|
||||
|
||||
statement = statement + 'graph TD;' + '\n';
|
||||
statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n';
|
||||
statement = statement + 'a-->b[1 a a text!.]:::exClass;' + '\n';
|
||||
|
||||
const res = flow.parser.parse(statement);
|
||||
const vertices = flow.parser.yy.getVertices();
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes.get('exClass').styles.length).toBe(2);
|
||||
expect(vertices.get('b').classes[0]).toBe('exClass');
|
||||
expect(classes.get('exClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('exClass').styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
it('should be possible to apply a class to a comma separated list of vertices', function () {
|
||||
let statement = '';
|
||||
|
||||
statement = statement + 'graph TD;' + '\n';
|
||||
statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n';
|
||||
statement = statement + 'a-->b;' + '\n';
|
||||
statement = statement + 'class a,b exClass;';
|
||||
|
||||
const res = flow.parser.parse(statement);
|
||||
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
const vertices = flow.parser.yy.getVertices();
|
||||
|
||||
expect(classes.get('exClass').styles.length).toBe(2);
|
||||
expect(classes.get('exClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('exClass').styles[1]).toBe('border:1px solid red');
|
||||
expect(vertices.get('a').classes[0]).toBe('exClass');
|
||||
expect(vertices.get('b').classes[0]).toBe('exClass');
|
||||
});
|
||||
|
||||
it('should handle style definitions with more then 1 digit in a row', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD\n' +
|
||||
'A-->B1\n' +
|
||||
'A-->B2\n' +
|
||||
'A-->B3\n' +
|
||||
'A-->B4\n' +
|
||||
'A-->B5\n' +
|
||||
'A-->B6\n' +
|
||||
'A-->B7\n' +
|
||||
'A-->B8\n' +
|
||||
'A-->B9\n' +
|
||||
'A-->B10\n' +
|
||||
'A-->B11\n' +
|
||||
'linkStyle 10 stroke-width:1px;'
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
|
||||
it('should handle style definitions within number of edges', function () {
|
||||
expect(() =>
|
||||
flow.parser
|
||||
.parse(
|
||||
`graph TD
|
||||
A-->B
|
||||
linkStyle 1 stroke-width:1px;`
|
||||
)
|
||||
.toThrow(
|
||||
'The index 1 for linkStyle is out of bounds. Valid indices for linkStyle are between 0 and 0. (Help: Ensure that the index is within the range of existing edges.)'
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle style definitions within number of edges', function () {
|
||||
const res = flow.parser.parse(`graph TD
|
||||
A-->B
|
||||
linkStyle 0 stroke-width:1px;`);
|
||||
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].style[0]).toBe('stroke-width:1px');
|
||||
});
|
||||
|
||||
it('should handle multi-numbered style definitions with more then 1 digit in a row', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD\n' +
|
||||
'A-->B1\n' +
|
||||
'A-->B2\n' +
|
||||
'A-->B3\n' +
|
||||
'A-->B4\n' +
|
||||
'A-->B5\n' +
|
||||
'A-->B6\n' +
|
||||
'A-->B7\n' +
|
||||
'A-->B8\n' +
|
||||
'A-->B9\n' +
|
||||
'A-->B10\n' +
|
||||
'A-->B11\n' +
|
||||
'A-->B12\n' +
|
||||
'linkStyle 10,11 stroke-width:1px;'
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
|
||||
it('should handle classDefs with style in classes', function () {
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nclassDef exClass font-style:bold;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
|
||||
it('should handle classDefs with % in classes', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD\nA-->B\nclassDef exClass fill:#f96,stroke:#333,stroke-width:4px,font-size:50%,font-style:bold;'
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
|
||||
it('should handle multiple vertices with style', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph TD
|
||||
classDef C1 stroke-dasharray:4
|
||||
classDef C2 stroke-dasharray:6
|
||||
A & B:::C1 & D:::C1 --> E:::C2
|
||||
`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
|
||||
expect(vert.get('A').classes.length).toBe(0);
|
||||
expect(vert.get('B').classes[0]).toBe('C1');
|
||||
expect(vert.get('D').classes[0]).toBe('C1');
|
||||
expect(vert.get('E').classes[0]).toBe('C2');
|
||||
});
|
||||
});
|
||||
609
packages/mermaid/src/diagrams/swimlane/parser/flow-text.spec.js
Normal file
609
packages/mermaid/src/diagrams/swimlane/parser/flow-text.spec.js
Normal file
@@ -0,0 +1,609 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('[Text] when parsing', () => {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
describe('it should handle text on edges', function () {
|
||||
it('should handle text without space', function () {
|
||||
const res = flow.parser.parse('graph TD;A--x|textNoSpace|B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
});
|
||||
|
||||
it('should handle with space', function () {
|
||||
const res = flow.parser.parse('graph TD;A--x|text including space|B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
});
|
||||
|
||||
it('should handle text with /', function () {
|
||||
const res = flow.parser.parse('graph TD;A--x|text with / should work|B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].text).toBe('text with / should work');
|
||||
});
|
||||
|
||||
it('should handle space and space between vertices and link', function () {
|
||||
const res = flow.parser.parse('graph TD;A --x|textNoSpace| B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
});
|
||||
|
||||
it('should handle space and CAPS', function () {
|
||||
const res = flow.parser.parse('graph TD;A--x|text including CAPS space|B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
});
|
||||
|
||||
it('should handle space and dir', function () {
|
||||
const res = flow.parser.parse('graph TD;A--x|text including URL space|B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
expect(edges[0].text).toBe('text including URL space');
|
||||
});
|
||||
|
||||
it('should handle space and send', function () {
|
||||
const res = flow.parser.parse('graph TD;A--text including URL space and send-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('text including URL space and send');
|
||||
});
|
||||
it('should handle space and send', function () {
|
||||
const res = flow.parser.parse('graph TD;A-- text including URL space and send -->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('text including URL space and send');
|
||||
});
|
||||
|
||||
it('should handle space and dir (TD)', function () {
|
||||
const res = flow.parser.parse('graph TD;A--x|text including R TD space|B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
expect(edges[0].text).toBe('text including R TD space');
|
||||
});
|
||||
it('should handle `', function () {
|
||||
const res = flow.parser.parse('graph TD;A--x|text including `|B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
expect(edges[0].text).toBe('text including `');
|
||||
});
|
||||
it('should handle v in node ids only v', function () {
|
||||
// only v
|
||||
const res = flow.parser.parse('graph TD;A--xv(my text);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
expect(vert.get('v').text).toBe('my text');
|
||||
});
|
||||
it('should handle v in node ids v at end', function () {
|
||||
// v at end
|
||||
const res = flow.parser.parse('graph TD;A--xcsv(my text);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
expect(vert.get('csv').text).toBe('my text');
|
||||
});
|
||||
it('should handle v in node ids v in middle', function () {
|
||||
// v in middle
|
||||
const res = flow.parser.parse('graph TD;A--xava(my text);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
expect(vert.get('ava').text).toBe('my text');
|
||||
});
|
||||
it('should handle v in node ids, v at start', function () {
|
||||
// v at start
|
||||
const res = flow.parser.parse('graph TD;A--xva(my text);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
expect(vert.get('va').text).toBe('my text');
|
||||
});
|
||||
it('should handle keywords', function () {
|
||||
const res = flow.parser.parse('graph TD;A--x|text including graph space|B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].text).toBe('text including graph space');
|
||||
});
|
||||
it('should handle keywords', function () {
|
||||
const res = flow.parser.parse('graph TD;V-->a[v]');
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
expect(vert.get('a').text).toBe('v');
|
||||
});
|
||||
it('should handle quoted text', function () {
|
||||
const res = flow.parser.parse('graph TD;V-- "test string()" -->a[v]');
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
expect(edges[0].text).toBe('test string()');
|
||||
});
|
||||
});
|
||||
|
||||
describe('it should handle text on lines', () => {
|
||||
it('should handle normal text on lines', function () {
|
||||
const res = flow.parser.parse('graph TD;A-- test text with == -->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].stroke).toBe('normal');
|
||||
});
|
||||
it('should handle dotted text on lines (TD3)', function () {
|
||||
const res = flow.parser.parse('graph TD;A-. test text with == .->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].stroke).toBe('dotted');
|
||||
});
|
||||
it('should handle thick text on lines', function () {
|
||||
const res = flow.parser.parse('graph TD;A== test text with - ==>B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].stroke).toBe('thick');
|
||||
});
|
||||
});
|
||||
|
||||
describe('it should handle text on edges using the new notation', function () {
|
||||
it('should handle text without space', function () {
|
||||
const res = flow.parser.parse('graph TD;A-- textNoSpace --xB;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
});
|
||||
|
||||
it('should handle text with multiple leading space', function () {
|
||||
const res = flow.parser.parse('graph TD;A-- textNoSpace --xB;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
});
|
||||
|
||||
it('should handle with space', function () {
|
||||
const res = flow.parser.parse('graph TD;A-- text including space --xB;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
});
|
||||
|
||||
it('should handle text with /', function () {
|
||||
const res = flow.parser.parse('graph TD;A -- text with / should work --x B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].text).toBe('text with / should work');
|
||||
});
|
||||
|
||||
it('should handle space and space between vertices and link', function () {
|
||||
const res = flow.parser.parse('graph TD;A -- textNoSpace --x B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
});
|
||||
|
||||
it('should handle space and CAPS', function () {
|
||||
const res = flow.parser.parse('graph TD;A-- text including CAPS space --xB;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
});
|
||||
|
||||
it('should handle space and dir', function () {
|
||||
const res = flow.parser.parse('graph TD;A-- text including URL space --xB;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
expect(edges[0].text).toBe('text including URL space');
|
||||
});
|
||||
|
||||
it('should handle space and dir (TD2)', function () {
|
||||
const res = flow.parser.parse('graph TD;A-- text including R TD space --xB;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_cross');
|
||||
expect(edges[0].text).toBe('text including R TD space');
|
||||
});
|
||||
it('should handle keywords', function () {
|
||||
const res = flow.parser.parse('graph TD;A-- text including graph space and v --xB;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].text).toBe('text including graph space and v');
|
||||
});
|
||||
it('should handle keywords', function () {
|
||||
const res = flow.parser.parse('graph TD;A-- text including graph space and v --xB[blav]');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].text).toBe('text including graph space and v');
|
||||
});
|
||||
// it.skip('should handle text on open links',function(){
|
||||
// const res = flow.parser.parse('graph TD;A-- text including graph space --B');
|
||||
//
|
||||
// const vert = flow.parser.yy.getVertices();
|
||||
// const edges = flow.parser.yy.getEdges();
|
||||
//
|
||||
// expect(edges[0].text).toBe('text including graph space');
|
||||
//
|
||||
// });
|
||||
});
|
||||
|
||||
describe('it should handle text in vertices, ', function () {
|
||||
it('should handle space', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->C(Chimpansen hoppar);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('C').type).toBe('round');
|
||||
expect(vert.get('C').text).toBe('Chimpansen hoppar');
|
||||
});
|
||||
|
||||
const keywords = [
|
||||
'graph',
|
||||
'flowchart',
|
||||
'flowchart-elk',
|
||||
'style',
|
||||
'default',
|
||||
'linkStyle',
|
||||
'interpolate',
|
||||
'classDef',
|
||||
'class',
|
||||
'href',
|
||||
'call',
|
||||
'click',
|
||||
'_self',
|
||||
'_blank',
|
||||
'_parent',
|
||||
'_top',
|
||||
'end',
|
||||
'subgraph',
|
||||
'kitty',
|
||||
];
|
||||
|
||||
const shapes = [
|
||||
{ start: '[', end: ']', name: 'square' },
|
||||
{ start: '(', end: ')', name: 'round' },
|
||||
{ start: '{', end: '}', name: 'diamond' },
|
||||
{ start: '(-', end: '-)', name: 'ellipse' },
|
||||
{ start: '([', end: '])', name: 'stadium' },
|
||||
{ start: '>', end: ']', name: 'odd' },
|
||||
{ start: '[(', end: ')]', name: 'cylinder' },
|
||||
{ start: '(((', end: ')))', name: 'doublecircle' },
|
||||
{ start: '[/', end: '\\]', name: 'trapezoid' },
|
||||
{ start: '[\\', end: '/]', name: 'inv_trapezoid' },
|
||||
{ start: '[/', end: '/]', name: 'lean_right' },
|
||||
{ start: '[\\', end: '\\]', name: 'lean_left' },
|
||||
{ start: '[[', end: ']]', name: 'subroutine' },
|
||||
{ start: '{{', end: '}}', name: 'hexagon' },
|
||||
];
|
||||
|
||||
shapes.forEach((shape) => {
|
||||
it.each(keywords)(`should handle %s keyword in ${shape.name} vertex`, function (keyword) {
|
||||
const rest = flow.parser.parse(
|
||||
`graph TD;A_${keyword}_node-->B${shape.start}This node has a ${keyword} as text${shape.end};`
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
expect(vert.get('B').type).toBe(`${shape.name}`);
|
||||
expect(vert.get('B').text).toBe(`This node has a ${keyword} as text`);
|
||||
});
|
||||
});
|
||||
|
||||
it.each(keywords)('should handle %s keyword in rect vertex', function (keyword) {
|
||||
const rest = flow.parser.parse(
|
||||
`graph TD;A_${keyword}_node-->B[|borders:lt|This node has a ${keyword} as text];`
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
expect(vert.get('B').type).toBe('rect');
|
||||
expect(vert.get('B').text).toBe(`This node has a ${keyword} as text`);
|
||||
});
|
||||
|
||||
it('should handle edge case for odd vertex with node id ending with minus', function () {
|
||||
const res = flow.parser.parse('graph TD;A_node-->odd->Vertex Text];');
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
|
||||
expect(vert.get('odd-').type).toBe('odd');
|
||||
expect(vert.get('odd-').text).toBe('Vertex Text');
|
||||
});
|
||||
it('should allow forward slashes in lean_right vertices', function () {
|
||||
const rest = flow.parser.parse(`graph TD;A_node-->B[/This node has a / as text/];`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
expect(vert.get('B').type).toBe('lean_right');
|
||||
expect(vert.get('B').text).toBe(`This node has a / as text`);
|
||||
});
|
||||
|
||||
it('should allow back slashes in lean_left vertices', function () {
|
||||
const rest = flow.parser.parse(`graph TD;A_node-->B[\\This node has a \\ as text\\];`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
expect(vert.get('B').type).toBe('lean_left');
|
||||
expect(vert.get('B').text).toBe(`This node has a \\ as text`);
|
||||
});
|
||||
|
||||
it('should handle åäö and minus', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->C{Chimpansen hoppar åäö-ÅÄÖ};');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('C').type).toBe('diamond');
|
||||
expect(vert.get('C').text).toBe('Chimpansen hoppar åäö-ÅÄÖ');
|
||||
});
|
||||
|
||||
it('should handle with åäö, minus and space and br', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->C(Chimpansen hoppar åäö <br> - ÅÄÖ);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('C').type).toBe('round');
|
||||
expect(vert.get('C').text).toBe('Chimpansen hoppar åäö <br> - ÅÄÖ');
|
||||
});
|
||||
// it.skip('should handle åäö, minus and space and br',function(){
|
||||
// const res = flow.parser.parse('graph TD; A[Object(foo,bar)]-->B(Thing);');
|
||||
//
|
||||
// const vert = flow.parser.yy.getVertices();
|
||||
// const edges = flow.parser.yy.getEdges();
|
||||
//
|
||||
// expect(vert.get('C').type).toBe('round');
|
||||
// expect(vert.get('C').text).toBe(' A[Object(foo,bar)]-->B(Thing);');
|
||||
// });
|
||||
it('should handle unicode chars', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->C(Начало);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
|
||||
expect(vert.get('C').text).toBe('Начало');
|
||||
});
|
||||
it('should handle backslask', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->C(c:\\windows);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
|
||||
expect(vert.get('C').text).toBe('c:\\windows');
|
||||
});
|
||||
it('should handle CAPS', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->C(some CAPS);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('C').type).toBe('round');
|
||||
expect(vert.get('C').text).toBe('some CAPS');
|
||||
});
|
||||
it('should handle directions', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->C(some URL);');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('C').type).toBe('round');
|
||||
expect(vert.get('C').text).toBe('some URL');
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multi-line text', function () {
|
||||
const res = flow.parser.parse('graph TD;A--o|text space|B;\n B-->|more text with space|C;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_circle');
|
||||
expect(edges[1].type).toBe('arrow_point');
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(vert.get('C').id).toBe('C');
|
||||
expect(edges.length).toBe(2);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
// expect(edges[0].text).toBe('text space');
|
||||
expect(edges[1].start).toBe('B');
|
||||
expect(edges[1].end).toBe('C');
|
||||
expect(edges[1].text).toBe('more text with space');
|
||||
});
|
||||
|
||||
it('should handle text in vertices with space', function () {
|
||||
const res = flow.parser.parse('graph TD;A[chimpansen hoppar]-->C;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').type).toBe('square');
|
||||
expect(vert.get('A').text).toBe('chimpansen hoppar');
|
||||
});
|
||||
|
||||
it('should handle text in vertices with space with spaces between vertices and link', function () {
|
||||
const res = flow.parser.parse('graph TD;A[chimpansen hoppar] --> C;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').type).toBe('square');
|
||||
expect(vert.get('A').text).toBe('chimpansen hoppar');
|
||||
});
|
||||
it('should handle text including _ in vertices', function () {
|
||||
const res = flow.parser.parse('graph TD;A[chimpansen_hoppar] --> C;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').type).toBe('square');
|
||||
expect(vert.get('A').text).toBe('chimpansen_hoppar');
|
||||
});
|
||||
|
||||
it('should handle quoted text in vertices ', function () {
|
||||
const res = flow.parser.parse('graph TD;A["chimpansen hoppar ()[]"] --> C;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').type).toBe('square');
|
||||
expect(vert.get('A').text).toBe('chimpansen hoppar ()[]');
|
||||
});
|
||||
|
||||
it('should handle text in circle vertices with space', function () {
|
||||
const res = flow.parser.parse('graph TD;A((chimpansen hoppar))-->C;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').type).toBe('circle');
|
||||
expect(vert.get('A').text).toBe('chimpansen hoppar');
|
||||
});
|
||||
|
||||
it('should handle text in ellipse vertices', function () {
|
||||
const res = flow.parser.parse('graph TD\nA(-this is an ellipse-)-->B');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').type).toBe('ellipse');
|
||||
expect(vert.get('A').text).toBe('this is an ellipse');
|
||||
});
|
||||
|
||||
it('should not freeze when ellipse text has a `(`', function () {
|
||||
expect(() => flow.parser.parse('graph\nX(- My Text (')).toThrowError();
|
||||
});
|
||||
|
||||
it('should handle text in diamond vertices with space', function () {
|
||||
const res = flow.parser.parse('graph TD;A(chimpansen hoppar)-->C;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').type).toBe('round');
|
||||
expect(vert.get('A').text).toBe('chimpansen hoppar');
|
||||
});
|
||||
|
||||
it('should handle text in with ?', function () {
|
||||
const res = flow.parser.parse('graph TD;A(?)-->|?|C;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').text).toBe('?');
|
||||
expect(edges[0].text).toBe('?');
|
||||
});
|
||||
it('should handle text in with éèêàçô', function () {
|
||||
const res = flow.parser.parse('graph TD;A(éèêàçô)-->|éèêàçô|C;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').text).toBe('éèêàçô');
|
||||
expect(edges[0].text).toBe('éèêàçô');
|
||||
});
|
||||
|
||||
it('should handle text in with ,.?!+-*', function () {
|
||||
const res = flow.parser.parse('graph TD;A(,.?!+-*)-->|,.?!+-*|C;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').text).toBe(',.?!+-*');
|
||||
expect(edges[0].text).toBe(',.?!+-*');
|
||||
});
|
||||
|
||||
it('should throw error at nested set of brackets', function () {
|
||||
const str = 'graph TD; A[This is a () in text];';
|
||||
expect(() => flow.parser.parse(str)).toThrowError("got 'PS'");
|
||||
});
|
||||
|
||||
it('should throw error for strings and text at the same time', function () {
|
||||
const str = 'graph TD;A(this node has "string" and text)-->|this link has "string" and text|C;';
|
||||
|
||||
expect(() => flow.parser.parse(str)).toThrowError("got 'STR'");
|
||||
});
|
||||
|
||||
it('should throw error for escaping quotes in text state', function () {
|
||||
//prettier-ignore
|
||||
const str = 'graph TD; A[This is a \"()\" in text];'; //eslint-disable-line no-useless-escape
|
||||
|
||||
expect(() => flow.parser.parse(str)).toThrowError("got 'STR'");
|
||||
});
|
||||
|
||||
it('should throw error for nested quoatation marks', function () {
|
||||
const str = 'graph TD; A["This is a "()" in text"];';
|
||||
|
||||
expect(() => flow.parser.parse(str)).toThrowError("Expecting 'SQE'");
|
||||
});
|
||||
|
||||
it('should throw error', function () {
|
||||
const str = `graph TD; node[hello ) world] --> works`;
|
||||
expect(() => flow.parser.parse(str)).toThrowError("got 'PE'");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,222 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('when parsing flowcharts', function () {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
flow.parser.yy.setGen('gen-2');
|
||||
});
|
||||
|
||||
it('should handle chaining of vertices', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph TD
|
||||
A-->B-->C;
|
||||
`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(vert.get('C').id).toBe('C');
|
||||
expect(edges.length).toBe(2);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[1].start).toBe('B');
|
||||
expect(edges[1].end).toBe('C');
|
||||
expect(edges[1].type).toBe('arrow_point');
|
||||
expect(edges[1].text).toBe('');
|
||||
});
|
||||
it('should handle chaining of vertices', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph TD
|
||||
A & B --> C;
|
||||
`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(vert.get('C').id).toBe('C');
|
||||
expect(edges.length).toBe(2);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('C');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[1].start).toBe('B');
|
||||
expect(edges[1].end).toBe('C');
|
||||
expect(edges[1].type).toBe('arrow_point');
|
||||
expect(edges[1].text).toBe('');
|
||||
});
|
||||
it('should multiple vertices in link statement in the begining', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph TD
|
||||
A-->B & C;
|
||||
`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(vert.get('C').id).toBe('C');
|
||||
expect(edges.length).toBe(2);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[1].start).toBe('A');
|
||||
expect(edges[1].end).toBe('C');
|
||||
expect(edges[1].type).toBe('arrow_point');
|
||||
expect(edges[1].text).toBe('');
|
||||
});
|
||||
it('should multiple vertices in link statement at the end', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph TD
|
||||
A & B--> C & D;
|
||||
`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(vert.get('C').id).toBe('C');
|
||||
expect(vert.get('D').id).toBe('D');
|
||||
expect(edges.length).toBe(4);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('C');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[1].start).toBe('A');
|
||||
expect(edges[1].end).toBe('D');
|
||||
expect(edges[1].type).toBe('arrow_point');
|
||||
expect(edges[1].text).toBe('');
|
||||
expect(edges[2].start).toBe('B');
|
||||
expect(edges[2].end).toBe('C');
|
||||
expect(edges[2].type).toBe('arrow_point');
|
||||
expect(edges[2].text).toBe('');
|
||||
expect(edges[3].start).toBe('B');
|
||||
expect(edges[3].end).toBe('D');
|
||||
expect(edges[3].type).toBe('arrow_point');
|
||||
expect(edges[3].text).toBe('');
|
||||
});
|
||||
it('should handle chaining of vertices at both ends at once', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph TD
|
||||
A & B--> C & D;
|
||||
`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(vert.get('C').id).toBe('C');
|
||||
expect(vert.get('D').id).toBe('D');
|
||||
expect(edges.length).toBe(4);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('C');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[1].start).toBe('A');
|
||||
expect(edges[1].end).toBe('D');
|
||||
expect(edges[1].type).toBe('arrow_point');
|
||||
expect(edges[1].text).toBe('');
|
||||
expect(edges[2].start).toBe('B');
|
||||
expect(edges[2].end).toBe('C');
|
||||
expect(edges[2].type).toBe('arrow_point');
|
||||
expect(edges[2].text).toBe('');
|
||||
expect(edges[3].start).toBe('B');
|
||||
expect(edges[3].end).toBe('D');
|
||||
expect(edges[3].type).toBe('arrow_point');
|
||||
expect(edges[3].text).toBe('');
|
||||
});
|
||||
it('should handle chaining and multiple nodes in link statement FVC ', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph TD
|
||||
A --> B & B2 & C --> D2;
|
||||
`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(vert.get('B2').id).toBe('B2');
|
||||
expect(vert.get('C').id).toBe('C');
|
||||
expect(vert.get('D2').id).toBe('D2');
|
||||
expect(edges.length).toBe(6);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
expect(edges[1].start).toBe('A');
|
||||
expect(edges[1].end).toBe('B2');
|
||||
expect(edges[1].type).toBe('arrow_point');
|
||||
expect(edges[1].text).toBe('');
|
||||
expect(edges[2].start).toBe('A');
|
||||
expect(edges[2].end).toBe('C');
|
||||
expect(edges[2].type).toBe('arrow_point');
|
||||
expect(edges[2].text).toBe('');
|
||||
expect(edges[3].start).toBe('B');
|
||||
expect(edges[3].end).toBe('D2');
|
||||
expect(edges[3].type).toBe('arrow_point');
|
||||
expect(edges[3].text).toBe('');
|
||||
expect(edges[4].start).toBe('B2');
|
||||
expect(edges[4].end).toBe('D2');
|
||||
expect(edges[4].type).toBe('arrow_point');
|
||||
expect(edges[4].text).toBe('');
|
||||
expect(edges[5].start).toBe('C');
|
||||
expect(edges[5].end).toBe('D2');
|
||||
expect(edges[5].type).toBe('arrow_point');
|
||||
expect(edges[5].text).toBe('');
|
||||
});
|
||||
it('should handle chaining and multiple nodes in link statement with extra info in statements', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph TD
|
||||
A[ h ] -- hello --> B[" test "]:::exClass & C --> D;
|
||||
classDef exClass background:#bbb,border:1px solid red;
|
||||
`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes.get('exClass').styles.length).toBe(2);
|
||||
expect(classes.get('exClass').styles[0]).toBe('background:#bbb');
|
||||
expect(classes.get('exClass').styles[1]).toBe('border:1px solid red');
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(vert.get('B').classes[0]).toBe('exClass');
|
||||
expect(vert.get('C').id).toBe('C');
|
||||
expect(vert.get('D').id).toBe('D');
|
||||
expect(edges.length).toBe(4);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('hello');
|
||||
expect(edges[1].start).toBe('A');
|
||||
expect(edges[1].end).toBe('C');
|
||||
expect(edges[1].type).toBe('arrow_point');
|
||||
expect(edges[1].text).toBe('hello');
|
||||
expect(edges[2].start).toBe('B');
|
||||
expect(edges[2].end).toBe('D');
|
||||
expect(edges[2].type).toBe('arrow_point');
|
||||
expect(edges[2].text).toBe('');
|
||||
expect(edges[3].start).toBe('C');
|
||||
expect(edges[3].end).toBe('D');
|
||||
expect(edges[3].type).toBe('arrow_point');
|
||||
expect(edges[3].text).toBe('');
|
||||
});
|
||||
});
|
||||
240
packages/mermaid/src/diagrams/swimlane/parser/flow.spec.js
Normal file
240
packages/mermaid/src/diagrams/swimlane/parser/flow.spec.js
Normal file
@@ -0,0 +1,240 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { cleanupComments } from '../../../diagram-api/comments.js';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('parsing a flow chart', function () {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('should handle a trailing whitespaces after statements', function () {
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n\n\n %% Comment\n A-->B; \n B-->C;'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
expect(edges.length).toBe(2);
|
||||
expect(edges[0].start).toBe('A');
|
||||
expect(edges[0].end).toBe('B');
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle node names with "end" substring', function () {
|
||||
const res = flow.parser.parse('graph TD\nendpoint --> sender');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('endpoint').id).toBe('endpoint');
|
||||
expect(vert.get('sender').id).toBe('sender');
|
||||
expect(edges[0].start).toBe('endpoint');
|
||||
expect(edges[0].end).toBe('sender');
|
||||
});
|
||||
|
||||
it('should handle node names ending with keywords', function () {
|
||||
const res = flow.parser.parse('graph TD\nblend --> monograph');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('blend').id).toBe('blend');
|
||||
expect(vert.get('monograph').id).toBe('monograph');
|
||||
expect(edges[0].start).toBe('blend');
|
||||
expect(edges[0].end).toBe('monograph');
|
||||
});
|
||||
|
||||
it('should allow default in the node name/id', function () {
|
||||
const res = flow.parser.parse('graph TD\ndefault --> monograph');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('default').id).toBe('default');
|
||||
expect(vert.get('monograph').id).toBe('monograph');
|
||||
expect(edges[0].start).toBe('default');
|
||||
expect(edges[0].end).toBe('monograph');
|
||||
});
|
||||
|
||||
describe('special characters should be handled.', function () {
|
||||
const charTest = function (char, result) {
|
||||
const res = flow.parser.parse('graph TD;A(' + char + ')-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(vert.get('A').id).toBe('A');
|
||||
expect(vert.get('B').id).toBe('B');
|
||||
if (result) {
|
||||
expect(vert.get('A').text).toBe(result);
|
||||
} else {
|
||||
expect(vert.get('A').text).toBe(char);
|
||||
}
|
||||
flow.parser.yy.clear();
|
||||
};
|
||||
|
||||
it("should be able to parse a '.'", function () {
|
||||
charTest('.');
|
||||
charTest('Start 103a.a1');
|
||||
});
|
||||
|
||||
// it('should be able to parse text containing \'_\'', function () {
|
||||
// charTest('_')
|
||||
// })
|
||||
|
||||
it("should be able to parse a ':'", function () {
|
||||
charTest(':');
|
||||
});
|
||||
|
||||
it("should be able to parse a ','", function () {
|
||||
charTest(',');
|
||||
});
|
||||
|
||||
it("should be able to parse text containing '-'", function () {
|
||||
charTest('a-b');
|
||||
});
|
||||
|
||||
it("should be able to parse a '+'", function () {
|
||||
charTest('+');
|
||||
});
|
||||
|
||||
it("should be able to parse a '*'", function () {
|
||||
charTest('*');
|
||||
});
|
||||
|
||||
it("should be able to parse a '<'", function () {
|
||||
charTest('<', '<');
|
||||
});
|
||||
|
||||
// it("should be able to parse a '>'", function() {
|
||||
// charTest('>', '>');
|
||||
// });
|
||||
|
||||
// it("should be able to parse a '='", function() {
|
||||
// charTest('=', '=');
|
||||
// });
|
||||
it("should be able to parse a '&'", function () {
|
||||
charTest('&');
|
||||
});
|
||||
});
|
||||
|
||||
it('should be possible to use direction in node ids', function () {
|
||||
let statement = '';
|
||||
|
||||
statement = statement + 'graph TD;' + '\n';
|
||||
statement = statement + ' node1TB\n';
|
||||
|
||||
const res = flow.parser.parse(statement);
|
||||
const vertices = flow.parser.yy.getVertices();
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
expect(vertices.get('node1TB').id).toBe('node1TB');
|
||||
});
|
||||
|
||||
it('should be possible to use direction in node ids', function () {
|
||||
let statement = '';
|
||||
|
||||
statement = statement + 'graph TD;A--x|text including URL space|B;';
|
||||
const res = flow.parser.parse(statement);
|
||||
const vertices = flow.parser.yy.getVertices();
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
expect(vertices.get('A').id).toBe('A');
|
||||
});
|
||||
|
||||
it('should be possible to use numbers as labels', function () {
|
||||
let statement = '';
|
||||
|
||||
statement = statement + 'graph TB;subgraph "number as labels";1;end;';
|
||||
const res = flow.parser.parse(statement);
|
||||
const vertices = flow.parser.yy.getVertices();
|
||||
|
||||
expect(vertices.get('1').id).toBe('1');
|
||||
});
|
||||
|
||||
it('should add accTitle and accDescr to flow chart', function () {
|
||||
const flowChart = `graph LR
|
||||
accTitle: Big decisions
|
||||
accDescr: Flow chart of the decision making process
|
||||
A[Hard] -->|Text| B(Round)
|
||||
B --> C{Decision}
|
||||
C -->|One| D[Result 1]
|
||||
C -->|Two| E[Result 2]
|
||||
`;
|
||||
|
||||
flow.parser.parse(flowChart);
|
||||
expect(flow.parser.yy.getAccTitle()).toBe('Big decisions');
|
||||
expect(flow.parser.yy.getAccDescription()).toBe('Flow chart of the decision making process');
|
||||
});
|
||||
it('should add accTitle and a multi line accDescr to flow chart', function () {
|
||||
const flowChart = `graph LR
|
||||
accTitle: Big decisions
|
||||
|
||||
accDescr {
|
||||
Flow chart of the decision making process
|
||||
with a second line
|
||||
}
|
||||
|
||||
A[Hard] -->|Text| B(Round)
|
||||
B --> C{Decision}
|
||||
C -->|One| D[Result 1]
|
||||
C -->|Two| E[Result 2]
|
||||
`;
|
||||
|
||||
flow.parser.parse(flowChart);
|
||||
expect(flow.parser.yy.getAccTitle()).toBe('Big decisions');
|
||||
expect(flow.parser.yy.getAccDescription()).toBe(
|
||||
`Flow chart of the decision making process
|
||||
with a second line`
|
||||
);
|
||||
});
|
||||
|
||||
for (const unsafeProp of ['__proto__', 'constructor']) {
|
||||
it(`should work with node id ${unsafeProp}`, function () {
|
||||
const flowChart = `graph LR
|
||||
${unsafeProp} --> A;`;
|
||||
|
||||
expect(() => {
|
||||
flow.parser.parse(flowChart);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it(`should work with tooltip id ${unsafeProp}`, function () {
|
||||
const flowChart = `graph LR
|
||||
click ${unsafeProp} callback "${unsafeProp}";`;
|
||||
|
||||
expect(() => {
|
||||
flow.parser.parse(flowChart);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it(`should work with class id ${unsafeProp}`, function () {
|
||||
const flowChart = `graph LR
|
||||
${unsafeProp} --> A;
|
||||
classDef ${unsafeProp} color:#ffffff,fill:#000000;
|
||||
class ${unsafeProp} ${unsafeProp};`;
|
||||
|
||||
expect(() => {
|
||||
flow.parser.parse(flowChart);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it(`should work with subgraph id ${unsafeProp}`, function () {
|
||||
const flowChart = `graph LR
|
||||
${unsafeProp} --> A;
|
||||
subgraph ${unsafeProp}
|
||||
C --> D;
|
||||
end;`;
|
||||
|
||||
expect(() => {
|
||||
flow.parser.parse(flowChart);
|
||||
}).not.toThrow();
|
||||
});
|
||||
}
|
||||
});
|
||||
312
packages/mermaid/src/diagrams/swimlane/parser/subgraph.spec.js
Normal file
312
packages/mermaid/src/diagrams/swimlane/parser/subgraph.spec.js
Normal file
@@ -0,0 +1,312 @@
|
||||
import flowDb from '../flowDb.js';
|
||||
import flow from './flow.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('when parsing subgraphs', function () {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
flow.parser.yy.setGen('gen-2');
|
||||
});
|
||||
it('should handle subgraph with tab indentation', function () {
|
||||
const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2\nend');
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
|
||||
expect(subgraph.nodes.length).toBe(2);
|
||||
expect(subgraph.nodes[0]).toBe('a2');
|
||||
expect(subgraph.nodes[1]).toBe('a1');
|
||||
expect(subgraph.title).toBe('One');
|
||||
expect(subgraph.id).toBe('One');
|
||||
});
|
||||
it('should handle subgraph with chaining nodes indentation', function () {
|
||||
const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2-->a3\nend');
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(3);
|
||||
expect(subgraph.nodes[0]).toBe('a3');
|
||||
expect(subgraph.nodes[1]).toBe('a2');
|
||||
expect(subgraph.nodes[2]).toBe('a1');
|
||||
expect(subgraph.title).toBe('One');
|
||||
expect(subgraph.id).toBe('One');
|
||||
});
|
||||
|
||||
it('should handle subgraph with multiple words in title', function () {
|
||||
const res = flow.parser.parse('graph TB\nsubgraph "Some Title"\n\ta1-->a2\nend');
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(2);
|
||||
expect(subgraph.nodes[0]).toBe('a2');
|
||||
expect(subgraph.nodes[1]).toBe('a1');
|
||||
expect(subgraph.title).toBe('Some Title');
|
||||
expect(subgraph.id).toBe('subGraph0');
|
||||
});
|
||||
|
||||
it('should handle subgraph with id and title notation', function () {
|
||||
const res = flow.parser.parse('graph TB\nsubgraph some-id[Some Title]\n\ta1-->a2\nend');
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(2);
|
||||
expect(subgraph.nodes[0]).toBe('a2');
|
||||
expect(subgraph.nodes[1]).toBe('a1');
|
||||
expect(subgraph.title).toBe('Some Title');
|
||||
expect(subgraph.id).toBe('some-id');
|
||||
});
|
||||
|
||||
it.skip('should handle subgraph without id and space in title', function () {
|
||||
const res = flow.parser.parse('graph TB\nsubgraph Some Title\n\ta1-->a2\nend');
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(2);
|
||||
expect(subgraph.nodes[0]).toBe('a1');
|
||||
expect(subgraph.nodes[1]).toBe('a2');
|
||||
expect(subgraph.title).toBe('Some Title');
|
||||
expect(subgraph.id).toBe('some-id');
|
||||
});
|
||||
|
||||
it('should handle subgraph id starting with a number', function () {
|
||||
const res = flow.parser.parse(`graph TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
subgraph 1test
|
||||
A
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(1);
|
||||
expect(subgraph.nodes[0]).toBe('A');
|
||||
expect(subgraph.id).toBe('1test');
|
||||
});
|
||||
|
||||
it('should handle subgraphs1', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->B;subgraph myTitle;c-->d;end;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
it('should handle subgraphs with title in quotes', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->B;subgraph "title in quotes";c-->d;end;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
|
||||
expect(subgraph.title).toBe('title in quotes');
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
it('should handle subgraphs in old style that was broken', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->B;subgraph old style that is broken;c-->d;end;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
|
||||
expect(subgraph.title).toBe('old style that is broken');
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
it('should handle subgraphs with dashes in the title', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->B;subgraph a-b-c;c-->d;end;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
|
||||
expect(subgraph.title).toBe('a-b-c');
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
it('should handle subgraphs with id and title in brackets', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->B;subgraph uid1[text of doom];c-->d;end;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
|
||||
expect(subgraph.title).toBe('text of doom');
|
||||
expect(subgraph.id).toBe('uid1');
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
it('should handle subgraphs with id and title in brackets and quotes', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->B;subgraph uid2["text of doom"];c-->d;end;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
|
||||
expect(subgraph.title).toBe('text of doom');
|
||||
expect(subgraph.id).toBe('uid2');
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
it('should handle subgraphs with id and title in brackets without spaces', function () {
|
||||
const res = flow.parser.parse('graph TD;A-->B;subgraph uid2[textofdoom];c-->d;end;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
|
||||
expect(subgraph.title).toBe('textofdoom');
|
||||
expect(subgraph.id).toBe('uid2');
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
|
||||
it('should handle subgraphs2', function () {
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\n\n c-->d \nend\n');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
|
||||
it('should handle subgraphs3', function () {
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle \n\n c-->d \nend\n');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
|
||||
it('should handle nested subgraphs', function () {
|
||||
const str =
|
||||
'graph TD\n' +
|
||||
'A-->B\n' +
|
||||
'subgraph myTitle\n\n' +
|
||||
' c-->d \n\n' +
|
||||
' subgraph inner\n\n e-->f \n end \n\n' +
|
||||
' subgraph inner\n\n h-->i \n end \n\n' +
|
||||
'end\n';
|
||||
const res = flow.parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle subgraphs4', function () {
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-->d\nend;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
|
||||
it('should handle subgraphs5', function () {
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-- text -->d\nd-->e\n end;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
it('should handle subgraphs with multi node statements in it', function () {
|
||||
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\na & b --> c & e\n end;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
it('should handle nested subgraphs 1', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
subgraph A
|
||||
b-->B
|
||||
a
|
||||
end
|
||||
a-->c
|
||||
subgraph B
|
||||
c
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(2);
|
||||
|
||||
const subgraphA = subgraphs.find((o) => o.id === 'A');
|
||||
const subgraphB = subgraphs.find((o) => o.id === 'B');
|
||||
|
||||
expect(subgraphB.nodes[0]).toBe('c');
|
||||
expect(subgraphA.nodes).toContain('B');
|
||||
expect(subgraphA.nodes).toContain('b');
|
||||
expect(subgraphA.nodes).toContain('a');
|
||||
expect(subgraphA.nodes).not.toContain('c');
|
||||
});
|
||||
it('should handle nested subgraphs 2', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
b-->B
|
||||
a-->c
|
||||
subgraph B
|
||||
c
|
||||
end
|
||||
subgraph A
|
||||
a
|
||||
b
|
||||
B
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(2);
|
||||
|
||||
const subgraphA = subgraphs.find((o) => o.id === 'A');
|
||||
const subgraphB = subgraphs.find((o) => o.id === 'B');
|
||||
|
||||
expect(subgraphB.nodes[0]).toBe('c');
|
||||
expect(subgraphA.nodes).toContain('B');
|
||||
expect(subgraphA.nodes).toContain('b');
|
||||
expect(subgraphA.nodes).toContain('a');
|
||||
expect(subgraphA.nodes).not.toContain('c');
|
||||
});
|
||||
it('should handle nested subgraphs 3', function () {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
subgraph B
|
||||
c
|
||||
end
|
||||
a-->c
|
||||
subgraph A
|
||||
b-->B
|
||||
a
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(2);
|
||||
|
||||
const subgraphA = subgraphs.find((o) => o.id === 'A');
|
||||
const subgraphB = subgraphs.find((o) => o.id === 'B');
|
||||
expect(subgraphB.nodes[0]).toBe('c');
|
||||
expect(subgraphA.nodes).toContain('B');
|
||||
expect(subgraphA.nodes).toContain('b');
|
||||
expect(subgraphA.nodes).toContain('a');
|
||||
expect(subgraphA.nodes).not.toContain('c');
|
||||
});
|
||||
});
|
||||
628
packages/mermaid/src/diagrams/swimlane/parser/swimlane.jison
Normal file
628
packages/mermaid/src/diagrams/swimlane/parser/swimlane.jison
Normal file
@@ -0,0 +1,628 @@
|
||||
/** mermaid
|
||||
* https://mermaidjs.github.io/
|
||||
* (c) 2015 Knut Sveidqvist
|
||||
* MIT license.
|
||||
*/
|
||||
|
||||
/* lexical grammar */
|
||||
%lex
|
||||
%x string
|
||||
%x md_string
|
||||
%x acc_title
|
||||
%x acc_descr
|
||||
%x acc_descr_multiline
|
||||
%x dir
|
||||
%x vertex
|
||||
%x text
|
||||
%x ellipseText
|
||||
%x trapText
|
||||
%x edgeText
|
||||
%x thickEdgeText
|
||||
%x dottedEdgeText
|
||||
%x click
|
||||
%x href
|
||||
%x callbackname
|
||||
%x callbackargs
|
||||
%x shapeData
|
||||
%x shapeDataStr
|
||||
%x shapeDataEndBracket
|
||||
|
||||
%%
|
||||
accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; }
|
||||
<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; }
|
||||
accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; }
|
||||
<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; }
|
||||
accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
|
||||
<acc_descr_multiline>[\}] { this.popState(); }
|
||||
<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value";
|
||||
// <acc_descr_multiline>.*[^\n]* { return "acc_descr_line"}
|
||||
|
||||
|
||||
\@\{ {
|
||||
// console.log('=> shapeData', yytext);
|
||||
this.pushState("shapeData"); yytext=""; return 'SHAPE_DATA' }
|
||||
<shapeData>["] {
|
||||
// console.log('=> shapeDataStr', yytext);
|
||||
this.pushState("shapeDataStr");
|
||||
return 'SHAPE_DATA';
|
||||
}
|
||||
<shapeDataStr>["] {
|
||||
// console.log('shapeData <==', yytext);
|
||||
this.popState(); return 'SHAPE_DATA'}
|
||||
<shapeDataStr>[^\"]+ {
|
||||
// console.log('shapeData', yytext);
|
||||
const re = /\n\s*/g;
|
||||
yytext = yytext.replace(re,"<br/>");
|
||||
return 'SHAPE_DATA'}
|
||||
<shapeData>[^}^"]+ {
|
||||
// console.log('shapeData', yytext);
|
||||
return 'SHAPE_DATA';
|
||||
}
|
||||
<shapeData>"}" {
|
||||
// console.log('<== root', yytext)
|
||||
this.popState();
|
||||
}
|
||||
|
||||
/*
|
||||
---interactivity command---
|
||||
'call' adds a callback to the specified node. 'call' can only be specified when
|
||||
the line was introduced with 'click'.
|
||||
'call <callbackname>(<args>)' attaches the function 'callbackname' with the specified
|
||||
arguments to the node that was specified by 'click'.
|
||||
Function arguments are optional: 'call <callbackname>()' simply executes 'callbackname' without any arguments.
|
||||
*/
|
||||
"call"[\s]+ this.begin("callbackname");
|
||||
<callbackname>\([\s]*\) this.popState();
|
||||
<callbackname>\( this.popState(); this.begin("callbackargs");
|
||||
<callbackname>[^(]* return 'CALLBACKNAME';
|
||||
<callbackargs>\) this.popState();
|
||||
<callbackargs>[^)]* return 'CALLBACKARGS';
|
||||
|
||||
|
||||
<md_string>[^`"]+ { return "MD_STR";}
|
||||
<md_string>[`]["] { this.popState();}
|
||||
<*>["][`] { this.begin("md_string");}
|
||||
<string>[^"]+ { return "STR"; }
|
||||
<string>["] this.popState();
|
||||
<*>["] this.pushState("string");
|
||||
"style" return 'STYLE';
|
||||
"default" return 'DEFAULT';
|
||||
"linkStyle" return 'LINKSTYLE';
|
||||
"interpolate" return 'INTERPOLATE';
|
||||
"classDef" return 'CLASSDEF';
|
||||
"class" return 'CLASS';
|
||||
|
||||
|
||||
|
||||
/*
|
||||
---interactivity command---
|
||||
'href' adds a link to the specified node. 'href' can only be specified when the
|
||||
line was introduced with 'click'.
|
||||
'href "<link>"' attaches the specified link to the node that was specified by 'click'.
|
||||
*/
|
||||
"href"[\s] return 'HREF';
|
||||
|
||||
|
||||
/*
|
||||
'click' is the keyword to introduce a line that contains interactivity commands.
|
||||
'click' must be followed by an existing node-id. All commands are attached to
|
||||
that id.
|
||||
'click <id>' can be followed by href or call commands in any desired order
|
||||
*/
|
||||
"click"[\s]+ this.begin("click");
|
||||
<click>[\s\n] this.popState();
|
||||
<click>[^\s\n]* return 'CLICK';
|
||||
|
||||
"swimlane" {if(yy.lex.firstGraph()){this.begin("dir");} return 'GRAPH';}
|
||||
"lane" return 'subgraph';
|
||||
"end"\b\s* return 'end';
|
||||
|
||||
"_self" return 'LINK_TARGET';
|
||||
"_blank" return 'LINK_TARGET';
|
||||
"_parent" return 'LINK_TARGET';
|
||||
"_top" return 'LINK_TARGET';
|
||||
|
||||
<dir>(\r?\n)*\s*\n { this.popState(); return 'NODIR'; }
|
||||
<dir>\s*"LR" { this.popState(); return 'DIR'; }
|
||||
<dir>\s*"RL" { this.popState(); return 'DIR'; }
|
||||
<dir>\s*"TB" { this.popState(); return 'DIR'; }
|
||||
<dir>\s*"BT" { this.popState(); return 'DIR'; }
|
||||
<dir>\s*"TD" { this.popState(); return 'DIR'; }
|
||||
<dir>\s*"BR" { this.popState(); return 'DIR'; }
|
||||
<dir>\s*"<" { this.popState(); return 'DIR'; }
|
||||
<dir>\s*">" { this.popState(); return 'DIR'; }
|
||||
<dir>\s*"^" { this.popState(); return 'DIR'; }
|
||||
<dir>\s*"v" { this.popState(); return 'DIR'; }
|
||||
|
||||
.*direction\s+TB[^\n]* return 'direction_tb';
|
||||
.*direction\s+BT[^\n]* return 'direction_bt';
|
||||
.*direction\s+RL[^\n]* return 'direction_rl';
|
||||
.*direction\s+LR[^\n]* return 'direction_lr';
|
||||
|
||||
[0-9]+ return 'NUM';
|
||||
\# return 'BRKT';
|
||||
":::" return 'STYLE_SEPARATOR';
|
||||
":" return 'COLON';
|
||||
"&" return 'AMP';
|
||||
";" return 'SEMI';
|
||||
"," return 'COMMA';
|
||||
"*" return 'MULT';
|
||||
|
||||
<INITIAL,edgeText>\s*[xo<]?\-\-+[-xo>]\s* { this.popState(); return 'LINK'; }
|
||||
<INITIAL>\s*[xo<]?\-\-\s* { this.pushState("edgeText"); return 'START_LINK'; }
|
||||
<edgeText>[^-]|\-(?!\-)+ return 'EDGE_TEXT';
|
||||
|
||||
<INITIAL,thickEdgeText>\s*[xo<]?\=\=+[=xo>]\s* { this.popState(); return 'LINK'; }
|
||||
<INITIAL>\s*[xo<]?\=\=\s* { this.pushState("thickEdgeText"); return 'START_LINK'; }
|
||||
<thickEdgeText>[^=]|\=(?!=) return 'EDGE_TEXT';
|
||||
|
||||
<INITIAL,dottedEdgeText>\s*[xo<]?\-?\.+\-[xo>]?\s* { this.popState(); return 'LINK'; }
|
||||
<INITIAL>\s*[xo<]?\-\.\s* { this.pushState("dottedEdgeText"); return 'START_LINK'; }
|
||||
<dottedEdgeText>[^\.]|\.(?!-) return 'EDGE_TEXT';
|
||||
|
||||
|
||||
<*>\s*\~\~[\~]+\s* return 'LINK';
|
||||
|
||||
<ellipseText>[-/\)][\)] { this.popState(); return '-)'; }
|
||||
<ellipseText>[^\(\)\[\]\{\}]|-\!\)+ return "TEXT"
|
||||
<*>"(-" { this.pushState("ellipseText"); return '(-'; }
|
||||
|
||||
<text>"])" { this.popState(); return 'STADIUMEND'; }
|
||||
<*>"([" { this.pushState("text"); return 'STADIUMSTART'; }
|
||||
|
||||
<text>"]]" { this.popState(); return 'SUBROUTINEEND'; }
|
||||
<*>"[[" { this.pushState("text"); return 'SUBROUTINESTART'; }
|
||||
|
||||
"[|" { return 'VERTEX_WITH_PROPS_START'; }
|
||||
|
||||
\> { this.pushState("text"); return 'TAGEND'; }
|
||||
|
||||
<text>")]" { this.popState(); return 'CYLINDEREND'; }
|
||||
<*>"[(" { this.pushState("text") ;return 'CYLINDERSTART'; }
|
||||
|
||||
<text>")))" { this.popState(); return 'DOUBLECIRCLEEND'; }
|
||||
<*>"(((" { this.pushState("text"); return 'DOUBLECIRCLESTART'; }
|
||||
|
||||
<trapText>[\\(?=\])][\]] { this.popState(); return 'TRAPEND'; }
|
||||
<trapText>\/(?=\])\] { this.popState(); return 'INVTRAPEND'; }
|
||||
<trapText>\/(?!\])|\\(?!\])|[^\\\[\]\(\)\{\}\/]+ return 'TEXT';
|
||||
<*>"[/" { this.pushState("trapText"); return 'TRAPSTART'; }
|
||||
|
||||
<*>"[\\" { this.pushState("trapText"); return 'INVTRAPSTART'; }
|
||||
|
||||
|
||||
"<" return 'TAGSTART';
|
||||
">" return 'TAGEND';
|
||||
"^" return 'UP';
|
||||
"\|" return 'SEP';
|
||||
"v" return 'DOWN';
|
||||
"*" return 'MULT';
|
||||
"#" return 'BRKT';
|
||||
"&" return 'AMP';
|
||||
([A-Za-z0-9!"\#$%&'*+\.`?\\_\/]|\-(?=[^\>\-\.])|=(?!=))+ return 'NODE_STRING';
|
||||
"-" return 'MINUS'
|
||||
[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|
|
||||
[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|
|
||||
[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|
|
||||
[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|
|
||||
[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|
|
||||
[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|
|
||||
[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|
|
||||
[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|
|
||||
[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|
|
||||
[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|
|
||||
[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|
|
||||
[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|
|
||||
[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|
|
||||
[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|
|
||||
[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|
|
||||
[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|
|
||||
[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|
|
||||
[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|
|
||||
[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|
|
||||
[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|
|
||||
[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|
|
||||
[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|
|
||||
[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|
|
||||
[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|
|
||||
[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|
|
||||
[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|
|
||||
[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|
|
||||
[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|
|
||||
[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|
|
||||
[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|
|
||||
[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|
|
||||
[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|
|
||||
[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|
|
||||
[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|
|
||||
[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|
|
||||
[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|
|
||||
[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|
|
||||
[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|
|
||||
[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|
|
||||
[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|
|
||||
[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|
|
||||
[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|
|
||||
[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|
|
||||
[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|
|
||||
[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|
|
||||
[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|
|
||||
[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|
|
||||
[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|
|
||||
[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|
|
||||
[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|
|
||||
[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|
|
||||
[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|
|
||||
[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|
|
||||
[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|
|
||||
[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|
|
||||
[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|
|
||||
[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|
|
||||
[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|
|
||||
[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|
|
||||
[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|
|
||||
[\uFFD2-\uFFD7\uFFDA-\uFFDC]
|
||||
return 'UNICODE_TEXT';
|
||||
|
||||
<text>"|" { this.popState(); return 'PIPE'; }
|
||||
<*>"|" { this.pushState("text"); return 'PIPE'; }
|
||||
|
||||
<text>")" { this.popState(); return 'PE'; }
|
||||
<*>"(" { this.pushState("text"); return 'PS'; }
|
||||
|
||||
<text>"]" { this.popState(); return 'SQE'; }
|
||||
<*>"[" { this.pushState("text"); return 'SQS'; }
|
||||
|
||||
<text>(\}) { this.popState(); return 'DIAMOND_STOP' }
|
||||
<*>"{" { this.pushState("text"); return 'DIAMOND_START' }
|
||||
<text>[^\[\]\(\)\{\}\|\"]+ return "TEXT";
|
||||
|
||||
"\"" return 'QUOTE';
|
||||
(\r?\n)+ return 'NEWLINE';
|
||||
\s return 'SPACE';
|
||||
<<EOF>> return 'EOF';
|
||||
|
||||
/lex
|
||||
|
||||
/* operator associations and precedence */
|
||||
|
||||
%left '^'
|
||||
|
||||
%start start
|
||||
|
||||
%% /* language grammar */
|
||||
|
||||
start
|
||||
: graphConfig document
|
||||
;
|
||||
|
||||
|
||||
document
|
||||
: /* empty */
|
||||
{ $$ = [];}
|
||||
| document line
|
||||
{
|
||||
if(!Array.isArray($line) || $line.length > 0){
|
||||
$document.push($line);
|
||||
}
|
||||
$$=$document;}
|
||||
;
|
||||
|
||||
line
|
||||
: statement
|
||||
{$$=$statement;}
|
||||
| SEMI
|
||||
| NEWLINE
|
||||
| SPACE
|
||||
| EOF
|
||||
;
|
||||
|
||||
graphConfig
|
||||
: SPACE graphConfig
|
||||
| NEWLINE graphConfig
|
||||
| GRAPH NODIR
|
||||
{ yy.setDirection('TB');$$ = 'TB';}
|
||||
| GRAPH DIR FirstStmtSeparator
|
||||
{ yy.setDirection($DIR);$$ = $DIR;}
|
||||
// | GRAPH SPACE TAGEND FirstStmtSeparator
|
||||
// { yy.setDirection("LR");$$ = $TAGEND;}
|
||||
// | GRAPH SPACE TAGSTART FirstStmtSeparator
|
||||
// { yy.setDirection("RL");$$ = $TAGSTART;}
|
||||
// | GRAPH SPACE UP FirstStmtSeparator
|
||||
// { yy.setDirection("BT");$$ = $UP;}
|
||||
// | GRAPH SPACE DOWN FirstStmtSeparator
|
||||
// { yy.setDirection("TB");$$ = $DOWN;}
|
||||
;
|
||||
|
||||
ending: endToken ending
|
||||
| endToken
|
||||
;
|
||||
|
||||
endToken: NEWLINE | SPACE | EOF;
|
||||
|
||||
FirstStmtSeparator
|
||||
: SEMI | NEWLINE | spaceList NEWLINE ;
|
||||
|
||||
|
||||
spaceListNewline
|
||||
: SPACE spaceListNewline
|
||||
| NEWLINE spaceListNewline
|
||||
| NEWLINE
|
||||
| SPACE
|
||||
;
|
||||
|
||||
|
||||
spaceList
|
||||
: SPACE spaceList
|
||||
| SPACE
|
||||
;
|
||||
|
||||
statement
|
||||
: vertexStatement separator
|
||||
{ /* console.warn('finat vs', $vertexStatement.nodes); */ $$=$vertexStatement.nodes}
|
||||
| styleStatement separator
|
||||
{$$=[];}
|
||||
| linkStyleStatement separator
|
||||
{$$=[];}
|
||||
| classDefStatement separator
|
||||
{$$=[];}
|
||||
| classStatement separator
|
||||
{$$=[];}
|
||||
| clickStatement separator
|
||||
{$$=[];}
|
||||
| subgraph SPACE textNoTags SQS text SQE separator document end
|
||||
{$$=yy.addSubGraph($textNoTags,$document,$text);}
|
||||
| subgraph SPACE textNoTags separator document end
|
||||
{$$=yy.addSubGraph($textNoTags,$document,$textNoTags);}
|
||||
| subgraph separator document end
|
||||
{$$=yy.addSubGraph(undefined,$document,undefined);}
|
||||
|
||||
| lane SPACE textNoTags SQS text SQE separator document end
|
||||
{$$=yy.addSubGraph($textNoTags,$document,$text, 'lane');}
|
||||
| lane SPACE textNoTags separator document end
|
||||
{$$=yy.addSubGraph($textNoTags,$document,$textNoTags, 'lane');}
|
||||
| lane separator document end
|
||||
{$$=yy.addSubGraph(undefined,$document,undefined, 'lane');}
|
||||
|
||||
| direction
|
||||
| acc_title acc_title_value { $$=$acc_title_value.trim();yy.setAccTitle($$); }
|
||||
| acc_descr acc_descr_value { $$=$acc_descr_value.trim();yy.setAccDescription($$); }
|
||||
| acc_descr_multiline_value { $$=$acc_descr_multiline_value.trim();yy.setAccDescription($$); }
|
||||
;
|
||||
|
||||
separator: NEWLINE | SEMI | EOF ;
|
||||
|
||||
shapeData:
|
||||
shapeData SHAPE_DATA
|
||||
{ $$ = $1 + $2; }
|
||||
| SHAPE_DATA
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
vertexStatement: vertexStatement link node shapeData
|
||||
{ /* console.warn('vs shapeData',$vertexStatement.stmt,$node, $shapeData);*/ yy.addVertex($node[0],undefined,undefined,undefined, undefined,undefined, undefined,$shapeData); yy.addLink($vertexStatement.stmt,$node,$link); $$ = { stmt: $node, nodes: $node.concat($vertexStatement.nodes) } }
|
||||
| vertexStatement link node
|
||||
{ /*console.warn('vs',$vertexStatement.stmt,$node);*/ yy.addLink($vertexStatement.stmt,$node,$link); $$ = { stmt: $node, nodes: $node.concat($vertexStatement.nodes) } }
|
||||
| vertexStatement link node spaceList
|
||||
{ /* console.warn('vs',$vertexStatement.stmt,$node); */ yy.addLink($vertexStatement.stmt,$node,$link); $$ = { stmt: $node, nodes: $node.concat($vertexStatement.nodes) } }
|
||||
|node spaceList { /*console.warn('vertexStatement: node spaceList', $node);*/ $$ = {stmt: $node, nodes:$node }}
|
||||
|node shapeData {
|
||||
/*console.warn('vertexStatement: node shapeData', $node[0], $shapeData);*/
|
||||
yy.addVertex($node[0],undefined,undefined,undefined, undefined,undefined, undefined,$shapeData);
|
||||
$$ = {stmt: $node, nodes:$node, shapeData: $shapeData}
|
||||
}
|
||||
|node { /* console.warn('vertexStatement: single node', $node); */ $$ = {stmt: $node, nodes:$node }}
|
||||
;
|
||||
|
||||
node: styledVertex
|
||||
{ /*console.warn('nod', $styledVertex);*/ $$ = [$styledVertex];}
|
||||
| node shapeData spaceList AMP spaceList styledVertex
|
||||
{ yy.addVertex($node[0],undefined,undefined,undefined, undefined,undefined, undefined,$shapeData); $$ = $node.concat($styledVertex); /*console.warn('pip2', $node[0], $styledVertex, $$);*/ }
|
||||
| node spaceList AMP spaceList styledVertex
|
||||
{ $$ = $node.concat($styledVertex); /*console.warn('pip', $node[0], $styledVertex, $$);*/ }
|
||||
;
|
||||
|
||||
styledVertex: vertex
|
||||
{ /* console.warn('nodc', $vertex);*/ $$ = $vertex;}
|
||||
| vertex STYLE_SEPARATOR idString
|
||||
{$$ = $vertex;yy.setClass($vertex,$idString)}
|
||||
;
|
||||
|
||||
vertex: idString SQS text SQE
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'square');}
|
||||
| idString DOUBLECIRCLESTART text DOUBLECIRCLEEND
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'doublecircle');}
|
||||
| idString PS PS text PE PE
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'circle');}
|
||||
| idString '(-' text '-)'
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'ellipse');}
|
||||
| idString STADIUMSTART text STADIUMEND
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'stadium');}
|
||||
| idString SUBROUTINESTART text SUBROUTINEEND
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'subroutine');}
|
||||
| idString VERTEX_WITH_PROPS_START NODE_STRING\[field] COLON NODE_STRING\[value] PIPE text SQE
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'rect',undefined,undefined,undefined, Object.fromEntries([[$field, $value]]));}
|
||||
| idString CYLINDERSTART text CYLINDEREND
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'cylinder');}
|
||||
| idString PS text PE
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'round');}
|
||||
| idString DIAMOND_START text DIAMOND_STOP
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'diamond');}
|
||||
| idString DIAMOND_START DIAMOND_START text DIAMOND_STOP DIAMOND_STOP
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'hexagon');}
|
||||
| idString TAGEND text SQE
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'odd');}
|
||||
| idString TRAPSTART text TRAPEND
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'trapezoid');}
|
||||
| idString INVTRAPSTART text INVTRAPEND
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'inv_trapezoid');}
|
||||
| idString TRAPSTART text INVTRAPEND
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'lean_right');}
|
||||
| idString INVTRAPSTART text TRAPEND
|
||||
{$$ = $idString;yy.addVertex($idString,$text,'lean_left');}
|
||||
| idString
|
||||
{ /*console.warn('h: ', $idString);*/$$ = $idString;yy.addVertex($idString);}
|
||||
;
|
||||
|
||||
|
||||
|
||||
link: linkStatement arrowText
|
||||
{$linkStatement.text = $arrowText;$$ = $linkStatement;}
|
||||
| linkStatement TESTSTR SPACE
|
||||
{$linkStatement.text = $TESTSTR;$$ = $linkStatement;}
|
||||
| linkStatement arrowText SPACE
|
||||
{$linkStatement.text = $arrowText;$$ = $linkStatement;}
|
||||
| linkStatement
|
||||
{$$ = $linkStatement;}
|
||||
| START_LINK edgeText LINK
|
||||
{var inf = yy.destructLink($LINK, $START_LINK); $$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length,"text":$edgeText};}
|
||||
;
|
||||
|
||||
edgeText: edgeTextToken
|
||||
{$$={text:$edgeTextToken, type:'text'};}
|
||||
| edgeText edgeTextToken
|
||||
{$$={text:$edgeText.text+''+$edgeTextToken, type:$edgeText.type};}
|
||||
|STR
|
||||
{$$={text: $STR, type: 'string'};}
|
||||
| MD_STR
|
||||
{$$={text:$MD_STR, type:'markdown'};}
|
||||
;
|
||||
|
||||
|
||||
linkStatement: LINK
|
||||
{var inf = yy.destructLink($LINK);$$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length};}
|
||||
;
|
||||
|
||||
arrowText:
|
||||
PIPE text PIPE
|
||||
{$$ = $text;}
|
||||
;
|
||||
|
||||
text: textToken
|
||||
{ $$={text:$textToken, type: 'text'};}
|
||||
| text textToken
|
||||
{ $$={text:$text.text+''+$textToken, type: $text.type};}
|
||||
| STR
|
||||
{ $$ = {text: $STR, type: 'string'};}
|
||||
| MD_STR
|
||||
{ $$={text: $MD_STR, type: 'markdown'};}
|
||||
;
|
||||
|
||||
|
||||
|
||||
keywords
|
||||
: STYLE | LINKSTYLE | CLASSDEF | CLASS | CLICK | GRAPH | DIR | subgraph | end | DOWN | UP;
|
||||
|
||||
|
||||
textNoTags: textNoTagsToken
|
||||
{$$={text:$textNoTagsToken, type: 'text'};}
|
||||
| textNoTags textNoTagsToken
|
||||
{$$={text:$textNoTags.text+''+$textNoTagsToken, type: $textNoTags.type};}
|
||||
| STR
|
||||
{ $$={text: $STR, type: 'text'};}
|
||||
| MD_STR
|
||||
{ $$={text: $MD_STR, type: 'markdown'};}
|
||||
;
|
||||
|
||||
|
||||
classDefStatement:CLASSDEF SPACE idString SPACE stylesOpt
|
||||
{$$ = $CLASSDEF;yy.addClass($idString,$stylesOpt);}
|
||||
;
|
||||
|
||||
classStatement:CLASS SPACE idString\[vertex] SPACE idString\[class]
|
||||
{$$ = $CLASS;yy.setClass($vertex, $class);}
|
||||
;
|
||||
|
||||
clickStatement
|
||||
: CLICK CALLBACKNAME {$$ = $CLICK;yy.setClickEvent($CLICK, $CALLBACKNAME);}
|
||||
| CLICK CALLBACKNAME SPACE STR {$$ = $CLICK;yy.setClickEvent($CLICK, $CALLBACKNAME);yy.setTooltip($CLICK, $STR);}
|
||||
| CLICK CALLBACKNAME CALLBACKARGS {$$ = $CLICK;yy.setClickEvent($CLICK, $CALLBACKNAME, $CALLBACKARGS);}
|
||||
| CLICK CALLBACKNAME CALLBACKARGS SPACE STR {$$ = $CLICK;yy.setClickEvent($CLICK, $CALLBACKNAME, $CALLBACKARGS);yy.setTooltip($CLICK, $STR);}
|
||||
| CLICK HREF STR {$$ = $CLICK;yy.setLink($CLICK, $STR);}
|
||||
| CLICK HREF STR SPACE STR {$$ = $CLICK;yy.setLink($CLICK, $STR1);yy.setTooltip($CLICK, $STR2);}
|
||||
| CLICK HREF STR SPACE LINK_TARGET {$$ = $CLICK;yy.setLink($CLICK, $STR, $LINK_TARGET);}
|
||||
| CLICK HREF STR\[link] SPACE STR\[tooltip] SPACE LINK_TARGET {$$ = $CLICK;yy.setLink($CLICK, $link, $LINK_TARGET);yy.setTooltip($CLICK, $tooltip);}
|
||||
| CLICK alphaNum {$$ = $CLICK;yy.setClickEvent($CLICK, $alphaNum);}
|
||||
| CLICK alphaNum SPACE STR {$$ = $CLICK;yy.setClickEvent($CLICK, $alphaNum);yy.setTooltip($CLICK, $STR);}
|
||||
| CLICK STR {$$ = $CLICK;yy.setLink($CLICK, $STR);}
|
||||
| CLICK STR\[link] SPACE STR\[tooltip] {$$ = $CLICK;yy.setLink($CLICK, $link);yy.setTooltip($CLICK, $tooltip);}
|
||||
| CLICK STR SPACE LINK_TARGET {$$ = $CLICK;yy.setLink($CLICK, $STR, $LINK_TARGET);}
|
||||
| CLICK STR\[link] SPACE STR\[tooltip] SPACE LINK_TARGET {$$ = $CLICK;yy.setLink($CLICK, $link, $LINK_TARGET);yy.setTooltip($CLICK, $tooltip);}
|
||||
;
|
||||
|
||||
styleStatement:STYLE SPACE idString SPACE stylesOpt
|
||||
{$$ = $STYLE;yy.addVertex($idString,undefined,undefined,$stylesOpt);}
|
||||
;
|
||||
|
||||
linkStyleStatement
|
||||
: LINKSTYLE SPACE DEFAULT SPACE stylesOpt
|
||||
{$$ = $LINKSTYLE;yy.updateLink([$DEFAULT],$stylesOpt);}
|
||||
| LINKSTYLE SPACE numList SPACE stylesOpt
|
||||
{$$ = $LINKSTYLE;yy.updateLink($numList,$stylesOpt);}
|
||||
| LINKSTYLE SPACE DEFAULT SPACE INTERPOLATE SPACE alphaNum SPACE stylesOpt
|
||||
{$$ = $LINKSTYLE;yy.updateLinkInterpolate([$DEFAULT],$alphaNum);yy.updateLink([$DEFAULT],$stylesOpt);}
|
||||
| LINKSTYLE SPACE numList SPACE INTERPOLATE SPACE alphaNum SPACE stylesOpt
|
||||
{$$ = $LINKSTYLE;yy.updateLinkInterpolate($numList,$alphaNum);yy.updateLink($numList,$stylesOpt);}
|
||||
| LINKSTYLE SPACE DEFAULT SPACE INTERPOLATE SPACE alphaNum
|
||||
{$$ = $LINKSTYLE;yy.updateLinkInterpolate([$DEFAULT],$alphaNum);}
|
||||
| LINKSTYLE SPACE numList SPACE INTERPOLATE SPACE alphaNum
|
||||
{$$ = $LINKSTYLE;yy.updateLinkInterpolate($numList,$alphaNum);}
|
||||
;
|
||||
|
||||
numList: NUM
|
||||
{$$ = [$NUM]}
|
||||
| numList COMMA NUM
|
||||
{$numList.push($NUM);$$ = $numList;}
|
||||
;
|
||||
|
||||
stylesOpt: style
|
||||
{$$ = [$style]}
|
||||
| stylesOpt COMMA style
|
||||
{$stylesOpt.push($style);$$ = $stylesOpt;}
|
||||
;
|
||||
|
||||
style: styleComponent
|
||||
|style styleComponent
|
||||
{$$ = $style + $styleComponent;}
|
||||
;
|
||||
|
||||
styleComponent: NUM | NODE_STRING| COLON | UNIT | SPACE | BRKT | STYLE | PCT ;
|
||||
|
||||
/* Token lists */
|
||||
idStringToken : NUM | NODE_STRING | DOWN | MINUS | DEFAULT | COMMA | COLON | AMP | BRKT | MULT | UNICODE_TEXT;
|
||||
|
||||
textToken : TEXT | TAGSTART | TAGEND | UNICODE_TEXT;
|
||||
|
||||
textNoTagsToken: NUM | NODE_STRING | SPACE | MINUS | AMP | UNICODE_TEXT | COLON | MULT | BRKT | keywords | START_LINK ;
|
||||
|
||||
edgeTextToken : EDGE_TEXT | UNICODE_TEXT ;
|
||||
|
||||
alphaNumToken : NUM | UNICODE_TEXT | NODE_STRING | DIR | DOWN | MINUS | COMMA | COLON | AMP | BRKT | MULT;
|
||||
|
||||
idString
|
||||
:idStringToken
|
||||
{$$=$idStringToken}
|
||||
| idString idStringToken
|
||||
{$$=$idString+''+$idStringToken}
|
||||
;
|
||||
|
||||
alphaNum
|
||||
: alphaNumToken
|
||||
{$$=$alphaNumToken;}
|
||||
| alphaNum alphaNumToken
|
||||
{$$=$alphaNum+''+$alphaNumToken;}
|
||||
;
|
||||
|
||||
|
||||
direction
|
||||
: direction_tb
|
||||
{ $$={stmt:'dir', value:'TB'};}
|
||||
| direction_bt
|
||||
{ $$={stmt:'dir', value:'BT'};}
|
||||
| direction_rl
|
||||
{ $$={stmt:'dir', value:'RL'};}
|
||||
| direction_lr
|
||||
{ $$={stmt:'dir', value:'LR'};}
|
||||
;
|
||||
|
||||
%%
|
||||
38
packages/mermaid/src/diagrams/swimlane/styles.ts
Normal file
38
packages/mermaid/src/diagrams/swimlane/styles.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
// import khroma from 'khroma';
|
||||
import * as khroma from 'khroma';
|
||||
import getStyleFlowchart from '../flowchart/styles.ts';
|
||||
|
||||
/** Returns the styles given options */
|
||||
export interface FlowChartStyleOptions {
|
||||
arrowheadColor: string;
|
||||
border2: string;
|
||||
clusterBkg: string;
|
||||
clusterBorder: string;
|
||||
edgeLabelBackground: string;
|
||||
fontFamily: string;
|
||||
lineColor: string;
|
||||
mainBkg: string;
|
||||
nodeBorder: string;
|
||||
nodeTextColor: string;
|
||||
tertiaryColor: string;
|
||||
textColor: string;
|
||||
titleColor: string;
|
||||
}
|
||||
|
||||
const fade = (color: string, opacity: number) => {
|
||||
// @ts-ignore TODO: incorrect types from khroma
|
||||
const channel = khroma.channel;
|
||||
|
||||
const r = channel(color, 'r');
|
||||
const g = channel(color, 'g');
|
||||
const b = channel(color, 'b');
|
||||
|
||||
// @ts-ignore incorrect types from khroma
|
||||
return khroma.rgba(r, g, b, opacity);
|
||||
};
|
||||
|
||||
const getStyles = (options: FlowChartStyleOptions) =>
|
||||
`${getStyleFlowchart(options)}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user