Compare commits

..

328 Commits

Author SHA1 Message Date
Sidharth Vinod
0b4f129220 Merge branch 'master' into add-flowchart-blog-post
* master:
  Changes to intro.md 1. Removed the Slack link 2. Updated the Discord invite link
  Changes to intro.md 1. Removed the Slack invite and left only the Discord invite
  Changes to intro.md 1. Added a link to the Discord server
2024-02-09 13:45:14 +05:30
Sidharth Vinod
1406de5a6c Merge pull request #5268 from FutzMonitor/updateContribute
Update contribute
2024-02-09 13:44:26 +05:30
futzmonitor
ec7591bfa8 Changes to intro.md
1. Removed the Slack link
2. Updated the Discord invite link
2024-02-09 13:41:55 +05:30
futzmonitor
c45f39e819 Changes to intro.md
1. Removed the Slack invite and left only the Discord invite
2024-02-09 13:41:55 +05:30
futzmonitor
6682988403 Changes to intro.md
1. Added a link to the Discord server
2024-02-09 13:41:54 +05:30
steph
5f8749418e add latest blog post 2024-02-04 23:08:43 -08:00
Knut Sveidqvist
1c61ccabad Merge branch 'release/10.8.0' 2024-02-02 11:33:33 +01:00
Knut Sveidqvist
3fe7e2dfe8 Updated contributions file 2024-02-02 11:30:29 +01:00
Knut Sveidqvist
51e7444b94 #3358 Layoutfix for growing parent when children spans new rows due to updated columns widths 2024-02-02 11:10:42 +01:00
knsv
2fa9219353 Update docs 2024-02-02 07:56:48 +00:00
Knut Sveidqvist
f5555245f9 Mermaid version 10.8.0 2024-02-02 08:53:29 +01:00
Knut Sveidqvist
5c9857c4eb Merge pull request #5247 from mermaid-js/sidv/mindmapToTs
Convert Mindmap to TS
2024-02-01 13:23:13 +00:00
Christian
494ba45c5e Fixed Typo in ErrorRenderer.ts (#5256)
* Changes to flow.jison
1. Added support for the plus symbol.

* Changes to errorRenderer.ts
1. Fixed a typo where 'renering' instead 'rendering'

* Revert "Changes to flow.jison"

This reverts commit 28b9dc897f.
2024-02-01 17:32:52 +05:30
Ashish Jain
b38def6866 Merge pull request #5221 from mermaid-js/3358-blocks-diagram
Adding new diagram type - Block Diagram
2024-02-01 11:22:18 +00:00
Knut Sveidqvist
a7afc11079 #3358 Removing redundant file 2024-02-01 10:49:59 +01:00
Knut Sveidqvist
d3c5b02008 Merge branch '3358-blocks-diagram' of github.com:mermaid-js/mermaid into 3358-blocks-diagram 2024-02-01 10:41:11 +01:00
Knut Sveidqvist
16149abcc0 #3358 Fix after review 2024-02-01 10:40:39 +01:00
Ashish Jain
13d0b61757 Merge branch 'develop' into 3358-blocks-diagram 2024-01-31 15:08:09 +01:00
Sidharth Vinod
45f4d3d443 Merge branch 'develop' into sidv/mindmapToTs 2024-01-31 15:20:16 +05:30
Sidharth Vinod
33d45f639c Merge pull request #5254 from mermaid-js/chore/InterfaceNaming
chore: Add interface naming Convention
2024-01-31 09:49:59 +00:00
Sidharth Vinod
7503694453 Merge pull request #5241 from Ronid1/feature/4653-add_actor-top_class_to_sequence_diagram
Feature/4653 add actor-top class to sequence diagram
2024-01-31 09:15:18 +00:00
Sidharth Vinod
e9680e086e Fix selector 2024-01-31 14:27:46 +05:30
Knut Sveidqvist
cd7003e9c1 Merge branch '3358-blocks-diagram' of github.com:mermaid-js/mermaid into 3358-blocks-diagram 2024-01-31 09:55:13 +01:00
Sidharth Vinod
941d9d13d5 Merge branch 'develop' into feature/4653-add_actor-top_class_to_sequence_diagram 2024-01-31 14:22:26 +05:30
Knut Sveidqvist
4786cfb6aa #3358 Renaming of IOperation to ActionFun 2024-01-31 09:50:11 +01:00
Sidharth Vinod
7aa4466b69 chore: Add interface naming 2024-01-31 14:19:01 +05:30
Sidharth Vinod
2bfd5a9e2a Merge branch 'develop' into 3358-blocks-diagram
* develop:
  Update container
  Update container
  Remove pnpm cache
  Use `.node-version` file in workflows
  Remove node version from matrix
  Update to Node v20
  Update to Node v20
2024-01-31 14:11:53 +05:30
Sidharth Vinod
56da881ed4 Merge branch 'develop' into sidv/mindmapToTs
* develop:
  Update container
  Update container
  Remove pnpm cache
  Use `.node-version` file in workflows
  fix: Redirect of old URLs
  Remove node version from matrix
  Update to Node v20
  Update to Node v20
  fix lint
  add latest blog post
  update discord invite link
  remove holiday promo text
2024-01-31 14:10:51 +05:30
Sidharth Vinod
aa50db8bf5 Merge pull request #5248 from mermaid-js/sidv/node20
Use node v20
2024-01-31 08:10:41 +00:00
Sidharth Vinod
e8db7a71e2 Update container 2024-01-31 11:35:07 +05:30
Sidharth Vinod
f00e7676b9 Update container 2024-01-31 11:32:55 +05:30
Sidharth Vinod
63ef228ed0 Remove pnpm cache 2024-01-31 09:42:33 +05:30
Knut Sveidqvist
6fce617284 3358 Adding types for blockArrowHelper 2024-01-30 17:48:46 +01:00
Sidharth Vinod
2a64834ecc Merge branch 'develop' into sidv/node20
* develop:
  fix: Redirect of old URLs
  fix lint
  add latest blog post
  update discord invite link
  remove holiday promo text
2024-01-30 22:10:23 +05:30
Knut Sveidqvist
7bcdea9bd1 #3358n Updated lockfile 2024-01-30 16:55:01 +01:00
Knut Sveidqvist
8fdf512b4c Merge branch 'develop' into 3358-blocks-diagram 2024-01-30 16:53:46 +01:00
knsv
dbcb80087c Update docs 2024-01-30 15:29:43 +00:00
Knut Sveidqvist
b99b1bfd0c #3358 Another set of review changes 2024-01-30 16:26:10 +01:00
Sidharth Vinod
fcffa6ca4e Merge branch 'develop' into feature/4653-add_actor-top_class_to_sequence_diagram 2024-01-30 20:51:52 +05:30
Sidharth Vinod
6fd69090ed Merge branch 'master' into develop
* master:
  fix: Redirect of old URLs
  fix lint
  add latest blog post
  update discord invite link
  remove holiday promo text
2024-01-30 20:50:30 +05:30
Sidharth Vinod
051ef598f6 Use .node-version file in workflows
Co-authored-by: Alois Klink <alois@aloisklink.com>
2024-01-30 20:44:39 +05:30
Knut Sveidqvist
907006ff3d #3358 Some fixes 2024-01-30 16:07:19 +01:00
Knut Sveidqvist
df9b801b0e #3358 Some fixes 2024-01-30 16:05:16 +01:00
Sidharth Vinod
726d633dd3 Use config from defaultConfig
Co-authored-by: Reda Al Sulais <u.yokozuna@gmail.com>
2024-01-30 20:00:54 +05:30
Knut Sveidqvist
4a04ce6bf8 Update cypress/integration/rendering/block.spec.ts
Co-authored-by: Sidharth Vinod <sidharthv96@gmail.com>
2024-01-30 14:49:14 +01:00
Knut Sveidqvist
010fc703eb Update packages/mermaid/src/diagrams/block/blockTypes.ts
Co-authored-by: Alois Klink <alois@aloisklink.com>
2024-01-30 14:46:14 +01:00
Knut Sveidqvist
8f8ce2f142 Merge branch '3358-blocks-diagram' of github.com:mermaid-js/mermaid into 3358-blocks-diagram 2024-01-30 14:37:53 +01:00
Knut Sveidqvist
452cb83ad7 #3358 Review changes 2024-01-30 14:37:35 +01:00
Knut Sveidqvist
2f8f9dd341 Update packages/mermaid/src/diagrams/block/blockDB.ts
Co-authored-by: Alois Klink <alois@aloisklink.com>
2024-01-30 14:36:38 +01:00
Knut Sveidqvist
4a14d997d1 Update packages/mermaid/src/diagrams/block/blockRenderer.ts
Co-authored-by: Alois Klink <alois@aloisklink.com>
2024-01-30 14:18:58 +01:00
Knut Sveidqvist
10237976f3 Merge branch 'develop' into 3358-blocks-diagram 2024-01-30 13:21:47 +01:00
Sidharth Vinod
92e7c7b894 Merge pull request #5250 from mermaid-js/fix/DocsRedirect
fix: Redirect of old URLs
2024-01-30 14:59:48 +05:30
Sidharth Vinod
80c20a72b2 Remove MermaidConfigWithDefaults 2024-01-30 14:25:44 +05:30
Sidharth Vinod
2d92ffb085 fix: Redirect of old URLs 2024-01-30 13:41:47 +05:30
Knut Sveidqvist
4823cf5df4 Update packages/mermaid/src/diagrams/block/blockDB.ts
Co-authored-by: Alois Klink <alois@aloisklink.com>
2024-01-30 08:52:59 +01:00
Knut Sveidqvist
dae8a13e8a Update packages/mermaid/src/defaultConfig.ts
Co-authored-by: Alois Klink <alois@aloisklink.com>
2024-01-30 08:51:47 +01:00
Sidharth Vinod
78f1631c8f Organize imports 2024-01-30 10:04:42 +05:30
Sidharth Vinod
ff6988e875 chore: Address review comments
Co-authored-by: Reda Al Sulais <u.yokozuna@gmail.com>
2024-01-30 09:51:40 +05:30
Ronid1
cddca04885 add actor-bottom to docs 2024-01-29 12:39:39 -08:00
Ronid1
f737c9f6f9 add actor-bottom class 2024-01-29 11:42:23 -08:00
Ronid1
7e86d03dc9 Merge branch 'develop' of https://github.com/mermaid-js/mermaid into feature/4653-add_actor-top_class_to_sequence_diagram 2024-01-29 11:28:01 -08:00
Knut Sveidqvist
bfa8111e14 #3358 Third set of changes after review 2024-01-29 17:32:27 +01:00
Knut Sveidqvist
5aab2ba1dd Merge branch '3358-blocks-diagram' of github.com:mermaid-js/mermaid into 3358-blocks-diagram 2024-01-29 16:25:02 +01:00
Knut Sveidqvist
37d7c7e2dd #3358 Second set of changes after review 2024-01-29 16:22:48 +01:00
Knut Sveidqvist
1965f69a10 Update packages/mermaid/src/schemas/config.schema.yaml
Co-authored-by: Alois Klink <alois@aloisklink.com>
2024-01-29 15:29:26 +01:00
Sidharth Vinod
95dcd30324 Merge branch 'develop' into sidv/mindmapToTs 2024-01-29 16:53:21 +05:30
Sidharth Vinod
65bb82962f Merge branch 'develop' into sidv/node20
* develop:
  Remove node version from matrix
2024-01-29 16:47:45 +05:30
Sidharth Vinod
c84c7f52f9 Remove node version from matrix 2024-01-29 16:46:48 +05:30
Sidharth Vinod
cd04c430af Merge branch 'sidv/node20' of github.com:mermaid-js/mermaid into sidv/node20
* 'sidv/node20' of github.com:mermaid-js/mermaid:
  chore: Update docs
  Update demos/pie.html
  Update pie.html demo
  Fix typos in timeline syntax samples
2024-01-29 16:44:52 +05:30
Sidharth Vinod
dd553cb28f Remove node version from matrix 2024-01-29 16:44:44 +05:30
Sidharth Vinod
25d0de13a5 Merge branch 'develop' into sidv/node20 2024-01-29 16:38:27 +05:30
Sidharth Vinod
52bb31b98a Update to Node v20 2024-01-29 13:56:03 +05:30
Sidharth Vinod
a4a94fd6e2 Update to Node v20 2024-01-29 13:55:51 +05:30
Sidharth Vinod
cd8e354234 Merge pull request #5139 from sblom/patch-2
Fix typos in timeline syntax samples
2024-01-29 08:20:53 +00:00
Sidharth Vinod
d797365802 Merge pull request #5141 from JenningsWilliam/feature_update_pie_labeling
Accurate pie chart labeling for text alignment
2024-01-29 08:19:21 +00:00
Sidharth Vinod
73293efcf3 Merge branch 'develop' into patch-2 2024-01-29 13:29:04 +05:30
Sidharth Vinod
91ae282808 Merge branch 'develop' into feature_update_pie_labeling 2024-01-29 13:28:18 +05:30
Sidharth Vinod
4c551b2aca Lint 2024-01-29 12:35:39 +05:30
Sidharth Vinod
d21461fba0 Lint 2024-01-29 12:27:17 +05:30
Sidharth Vinod
b51d8ff7ba Convert svgDraw.ts 2024-01-29 12:16:21 +05:30
Sidharth Vinod
75ec719257 Rename svgDraw.js 2024-01-29 11:31:22 +05:30
Sidharth Vinod
13e052ff81 Fix styles.ts 2024-01-29 11:26:10 +05:30
Sidharth Vinod
bde6a9ff4f Rename styles.js 2024-01-29 11:21:42 +05:30
Sidharth Vinod
23d843b6d3 refactor: Remove db import from svgDraw 2024-01-29 11:21:12 +05:30
Sidharth Vinod
cffac848ea chore: Fix mindmapDb exports 2024-01-29 10:52:58 +05:30
Sidharth Vinod
9651d0c2da refactor: Fix types and imports 2024-01-29 10:45:47 +05:30
Sidharth Vinod
e1a23f10df chore: Fix config type 2024-01-28 21:43:03 +05:30
Sidharth Vinod
d346a77e3c Convert MindmapRenderer.ts 2024-01-28 16:04:42 +05:30
Sidharth Vinod
f069de5487 Convert MindmapDB.ts 2024-01-28 16:04:42 +05:30
Sidharth Vinod
ba0bddf417 Add MermaidConfigWithDefaults 2024-01-28 16:04:42 +05:30
Sidharth Vinod
f30c26485e Cleanup svgDraw.js 2024-01-28 16:04:41 +05:30
Sidharth Vinod
b71f4c7e54 Add MindmapDB type 2024-01-28 16:04:41 +05:30
Sidharth Vinod
e046da10c2 Convert mindmap.spec.js 2024-01-28 16:04:40 +05:30
Sidharth Vinod
12dc3d8373 Rename files to TS 2024-01-28 16:04:40 +05:30
Sidharth Vinod
c5272d5279 Merge pull request #5236 from mermaid-js/fix/DompurifyHooks
fix: Dompurify Hooks
2024-01-27 15:11:54 +00:00
Ronid1
9ee5667580 Merge branch 'develop' of https://github.com/mermaid-js/mermaid into feature/4653-add_actor-top_class_to_sequence_diagram 2024-01-26 14:08:13 -08:00
Ronid1
36c196e80b add test 2024-01-26 14:07:12 -08:00
Sidharth Vinod
7ca990d762 Merge branch 'develop' into fix/DompurifyHooks 2024-01-27 00:25:15 +05:30
Sidharth Vinod
91907fe0eb Merge pull request #5095 from FutzMonitor/issue1981
Changes to Gantt Parsers to allow hashes and semicolons to titles, sections, and task data.
2024-01-26 17:21:58 +00:00
Sidharth Vinod
6bf5571f96 chore: Update docs 2024-01-26 22:50:17 +05:30
Sidharth Vinod
8619a53a9c Update demos/pie.html 2024-01-26 22:48:12 +05:30
Sidharth Vinod
9bedfa2033 Merge pull request #5160 from vitorsss/fix/4212_actor_menus_sequence_diagram_popup
[Fix] Sequence diagram actor menu popup
2024-01-26 17:16:27 +00:00
FutzMonitor
59264a33d7 Changes to gantt.html
1. Added a Gantt diagram that demonstrates to users that hashtages and semicolons can be added to titles, sections, and task data.
Changes to gantt.spec.js
1. Added unit tests to ensure that semicolons and hashtags didn't break the functionality of the gantt diagram when used in titles, sections or task data.
Changes to /parser/gantt.spec.js
1. Added rendering tests to ensure that semicolons and hashtags in titles, sections, and task data didn't break the rendering of Gantt diagrams.
2024-01-26 11:48:48 -05:00
Ronid1
70d9f50fc9 add const for class name 2024-01-25 17:59:46 -08:00
Ronid1
b253cd65d4 update docs 2024-01-25 17:19:00 -08:00
Ronid1
f2f8d89a28 add actor-top class to rectangle actor and man actor 2024-01-25 17:16:09 -08:00
FutzMonitor
0b0f988180 Merge branch 'develop' into issue1981 2024-01-25 17:03:16 -05:00
Sidharth Vinod
1c200ee5bc perf: prevent adding multiple DOMPurify hooks
Currently, everytime `removeScript()` is called, the same DOMPurify
hooks are getting added again and again.

Co-authored-by: Alois Klink <alois@aloisklink.com>
2024-01-25 23:28:42 +05:30
Sidharth Vinod
98c578da02 Merge pull request #5232 from mermaid-js/mermaid-chart-updates
Docs: Mermaid chart updates
2024-01-24 12:43:54 +05:30
steph
cbf7e6a880 fix lint 2024-01-23 22:17:55 -08:00
steph
8982e2f78c add latest blog post 2024-01-23 22:02:24 -08:00
steph
62ae072918 update discord invite link 2024-01-23 21:59:54 -08:00
steph
04f92e5b1c remove holiday promo text 2024-01-23 21:58:37 -08:00
Sidharth Vinod
6939cf52e6 Merge pull request #5228 from mermaid-js/updateCypress
UpdateCypress
2024-01-24 00:31:20 +05:30
Sidharth Vinod
ec79ac200c Lint 2024-01-23 23:53:48 +05:30
Sidharth Vinod
de03a017db Remove echo 2024-01-23 23:51:48 +05:30
Sidharth Vinod
42ad1f4fe4 RefTest 2024-01-23 23:49:52 +05:30
Sidharth Vinod
a01be16d27 Echo event 2024-01-23 23:38:21 +05:30
Sidharth Vinod
5c6c8d1135 Update cypress 2024-01-23 20:36:29 +05:30
Sidharth Vinod
493f238319 Fix applitools 2024-01-23 20:32:58 +05:30
Sidharth Vinod
17066aab97 Merge branch 'master' of github.com:mermaid-js/mermaid into develop
* 'master' of github.com:mermaid-js/mermaid:
  docs: fix lint
  docs: move community to Discord
  Delete docs/syntax/gantt.html
  Add more detailed docs for Gantt tasks
  Update docs
  Update packages/mermaid/src/docs/syntax/flowchart.md
  Update flowchart.md #5195
2024-01-23 19:55:53 +05:30
Sidharth Vinod
21c9397ec1 Merge pull request #5225 from Olegt0rr/discord
Update Slack community links to Discord
2024-01-23 19:54:53 +05:30
Oleg A
427bcaa3f6 docs: fix lint 2024-01-23 19:53:42 +05:30
Oleg A
8fad1f55e2 docs: move community to Discord 2024-01-23 19:53:41 +05:30
Sidharth Vinod
05e17c0bf0 Merge pull request #5161 from mathbraga/feature/5114_add_parallel_commit_config
Feature/5114 add parallel commit config
2024-01-23 04:40:24 +00:00
Sidharth Vinod
1612d3fabd Merge pull request #5127 from mathbraga/bug/5059_fix_external_connection_after_updating_edges
Bug/5059 fix external connection after updating edges
2024-01-23 02:35:01 +00:00
Matheus Braga
679f77dea5 Merge branch 'develop' into bug/5059_fix_external_connection_after_updating_edges 2024-01-22 20:22:50 -03:00
Matheus Braga
1bad612c51 Merge branch 'develop' into feature/5114_add_parallel_commit_config 2024-01-22 20:19:52 -03:00
Matheus B
81825f22f5 Swap condition blocks to avoid using negation 2024-01-22 20:09:20 -03:00
Matheus B
e668698b5c Reposition const declaration to ideal place 2024-01-22 19:56:25 -03:00
Knut Sveidqvist
1629a91a25 Updated lockfile 2024-01-22 14:52:02 +01:00
Knut Sveidqvist
c85b24862d Merge branch 'develop' into 3358-blocks-diagram 2024-01-22 14:19:30 +01:00
Knut Sveidqvist
fe89b9510d #3358 Adjusting docs and a bug fix for nested blocks 2024-01-22 14:14:54 +01:00
Sidharth Vinod
7b624667fa Merge pull request #5219 from Yokozuna59/yokozuna/fix-broken-link
docs: fix swimm link
2024-01-22 08:03:56 +00:00
Matheus Braga
e7c52bbf59 Merge branch 'develop' into bug/5059_fix_external_connection_after_updating_edges 2024-01-21 13:20:24 -03:00
Matheus B
3e87412e97 Merge branch 'feature/5114_add_parallel_commit_config' of https://github.com/mathbraga/mermaid into feature/5114_add_parallel_commit_config 2024-01-20 21:13:44 -03:00
Matheus B
2401f334ec Merge branch 'develop' of https://github.com/mathbraga/mermaid into feature/5114_add_parallel_commit_config 2024-01-20 21:07:53 -03:00
Matheus B
4f60a27472 Change repetitive values into consts 2024-01-20 20:57:58 -03:00
Reda Al Sulais
2bbdd15031 docs: fix swimm link 2024-01-20 13:30:49 +03:00
Vitor Soares Silva
c226358f65 Merge branch 'develop' into fix/4212_actor_menus_sequence_diagram_popup 2024-01-19 16:24:54 -03:00
Vitor Soares Silva
8fd268d59b add sequenceDiagram link e2e test 2024-01-19 16:10:23 -03:00
Sidharth Vinod
b91624cb63 Merge pull request #5066 from Ronid1/docs/4974_reorder_integration_links
Docs/4974 reorder integration links
2024-01-19 18:10:58 +00:00
Sidharth Vinod
54f2452406 Merge branch 'develop' of github.com:mermaid-js/mermaid into develop
* 'develop' of github.com:mermaid-js/mermaid:
  Use pnpm/action-setup@v2
  Fix pnpm-lock by resetting it, sorry!
  chore: update browsers list
  Update update-browserlist.yml
  Update update-browserlist.yml to install pnpm
  Update update-browserlist.yml to fix deprecation and action fails
2024-01-19 23:47:14 +05:30
Sidharth Vinod
84a18a1858 Fix Update Browserslist 2024-01-19 23:47:07 +05:30
Sidharth Vinod
5b2a10e592 Merge pull request #5151 from Abrifq/patch-4
Update update-browserlist.yml to fix deprecation and action fails
2024-01-19 23:42:20 +05:30
Sidharth Vinod
8820c7baf1 Merge branch 'develop' into patch-4 2024-01-19 23:39:27 +05:30
Sidharth Vinod
1e70b3817e Use pnpm/action-setup@v2 2024-01-19 23:38:27 +05:30
Sidharth Vinod
1f37b6c91b Fix lint 2024-01-19 23:28:43 +05:30
Sidharth Vinod
c080522102 Merge branch 'develop' into issue1981 2024-01-19 23:18:53 +05:30
Sidharth Vinod
d95fdfee94 Merge branch 'develop' into pr/Ronid1/5066
* develop: (122 commits)
  Cleanup e2e.yml
  Ignore push events on merge queue
  Remove ::
  Remove ::
  Remove ::
  Debug
  Debug
  Remove spec selector
  Handle edge cases in E2E
  Always run combineArtifacts
  Fix error message
  Fix cache save
  Update cache key
  Notify users
  Flatten uploaded images
  Flatten uploaded images
  Use pixelmatch for image comparison
  Run all tests
  Fix lint
  Update lockfile
  ...
2024-01-19 23:15:52 +05:30
Vitor Soares Silva
d74025bd80 Merge branch 'develop' into fix/4212_actor_menus_sequence_diagram_popup 2024-01-19 13:40:30 -03:00
Sidharth Vinod
d0224b23b0 Cleanup e2e.yml 2024-01-19 19:47:42 +05:30
Sidharth Vinod
6334516639 Merge branch 'combineImages' into develop
* combineImages:
  Ignore push events on merge queue
2024-01-19 19:47:12 +05:30
Sidharth Vinod
aadf32ab3e Ignore push events on merge queue 2024-01-19 19:45:55 +05:30
Sidharth Vinod
6424f823b2 Merge pull request #5213 from mermaid-js/combineImages
Optimise caching of test results
2024-01-19 14:09:03 +00:00
Sidharth Vinod
8bfb269b37 Remove :: 2024-01-19 19:33:59 +05:30
Sidharth Vinod
3935f6b389 Remove :: 2024-01-19 19:31:25 +05:30
Sidharth Vinod
f5dd24bce4 Remove :: 2024-01-19 19:29:45 +05:30
Knut Sveidqvist
d96425d19e #3358 Reviving arrow heads after merging develop 2024-01-19 14:57:45 +01:00
Sidharth Vinod
279e31bc55 Debug 2024-01-19 19:23:13 +05:30
Sidharth Vinod
f1fc874da8 Debug 2024-01-19 19:20:39 +05:30
Sidharth Vinod
a871a68f3c Remove spec selector 2024-01-19 19:05:06 +05:30
Sidharth Vinod
a964af67ec Handle edge cases in E2E 2024-01-19 19:04:25 +05:30
Sidharth Vinod
6f205f89b2 Always run combineArtifacts 2024-01-19 16:58:19 +05:30
Sidharth Vinod
35b3192c2b Fix error message 2024-01-19 16:58:19 +05:30
Sidharth Vinod
be4721b24d Fix cache save 2024-01-19 16:58:19 +05:30
Sidharth Vinod
a9a8a208a6 Update cache key 2024-01-19 16:58:19 +05:30
Sidharth Vinod
f58a86d747 Notify users 2024-01-19 16:58:19 +05:30
Sidharth Vinod
4ce5d07125 Flatten uploaded images 2024-01-19 16:58:18 +05:30
Sidharth Vinod
658af081ee Flatten uploaded images 2024-01-19 14:42:51 +05:30
Sidharth Vinod
fdfa917cdb Merge branch 'develop' into feature/5114_add_parallel_commit_config 2024-01-19 14:12:08 +05:30
Sidharth Vinod
46552faa2e Merge branch 'develop' into fix/4212_actor_menus_sequence_diagram_popup 2024-01-19 14:10:30 +05:30
Sidharth Vinod
1285e59080 Merge branch 'develop' into bug/5059_fix_external_connection_after_updating_edges 2024-01-19 13:18:45 +05:30
Sidharth Vinod
cb0ee5aa41 Use pixelmatch for image comparison 2024-01-19 13:17:14 +05:30
Sidharth Vinod
95ebb4aaec Merge branch 'develop' into bug/5059_fix_external_connection_after_updating_edges 2024-01-19 12:46:17 +05:30
Sidharth Vinod
97f9919250 Merge pull request #5210 from sidharthv96/sidv/e2e
E2E test
2024-01-19 12:24:41 +05:30
Sidharth Vinod
d6e738ac4c Run all tests 2024-01-19 12:21:51 +05:30
Sidharth Vinod
91a63933ec Merge branch 'develop' into sidv/e2e
* develop:
  Fix lint
2024-01-19 12:17:45 +05:30
Sidharth Vinod
448756ab54 Fix lint 2024-01-19 12:17:20 +05:30
Sidharth Vinod
7805e05495 Update lockfile 2024-01-19 12:15:01 +05:30
Sidharth Vinod
98782d3a1f Merge branch 'develop' into sidv/e2e 2024-01-19 12:11:45 +05:30
Sidharth Vinod
76dacf8e90 E2E test 2024-01-19 12:10:39 +05:30
Sidharth Vinod
681d3c3ed8 Merge pull request #5208 from sidharthv96/sidv/e2e
E2E Image comparison
2024-01-19 12:10:14 +05:30
Sidharth Vinod
d2c82c1802 Use cache to store snapshots 2024-01-19 12:06:53 +05:30
Sidharth Vinod
3852117581 Merge pull request #5194 from sorenisanerd/gantt-docs
Add more detailed docs for Gantt tasks
2024-01-19 09:35:33 +05:30
Sidharth Vinod
bf55d940b6 Delete docs/syntax/gantt.html 2024-01-19 09:34:21 +05:30
Soren L. Hansen
e0ee9b1bc0 Add more detailed docs for Gantt tasks 2024-01-19 09:34:20 +05:30
Sidharth Vinod
51aea90e9a Merge pull request #5196 from arukiidou/patch-1
Update flowchart.md - how to use font-awesome #5195
2024-01-19 09:24:32 +05:30
Sidharth Vinod
7918f96f94 Update docs 2024-01-19 09:22:38 +05:30
arukiidou
be8faae68c Update packages/mermaid/src/docs/syntax/flowchart.md
Co-authored-by: Sidharth Vinod <sidharthv96@gmail.com>
2024-01-19 09:22:38 +05:30
arukiidou
04ebf0ddc9 Update flowchart.md #5195 2024-01-19 09:22:38 +05:30
Matheus Braga
223c8c92cb Merge branch 'develop' into bug/5059_fix_external_connection_after_updating_edges 2024-01-18 20:59:24 -03:00
Knut Sveidqvist
b4dece88e9 Merge branch '3358-blocks-diagram' of github.com:mermaid-js/mermaid into 3358-blocks-diagram 2024-01-18 18:03:58 +01:00
Knut Sveidqvist
d075766760 #3358 Doc updates after viewing the page 2024-01-18 18:03:37 +01:00
Sidharth Vinod
8754b9dd5d Merge pull request #5150 from mermaid-js/renovate/patch-all-patch
chore(deps): update all patch dependencies (patch)
2024-01-18 17:03:11 +00:00
renovate[bot]
fb7cd9ca40 chore(deps): update all patch dependencies 2024-01-18 16:17:34 +00:00
knsv
5553cbbb22 Update docs 2024-01-18 16:10:57 +00:00
Sidharth Vinod
858d512766 Merge pull request #5200 from mermaid-js/dependabot/npm_and_yarn/follow-redirects-1.15.5
build(deps-dev): bump follow-redirects from 1.15.2 to 1.15.5
2024-01-18 16:10:27 +00:00
Sidharth Vinod
781065dee4 Merge pull request #5205 from mathbraga/revert-5197-revert-5041-feature/4935_subgraph-title-margin-config-option
Revert "Revert 5041 feature/4935 subgraph title margin config option"
2024-01-18 16:10:05 +00:00
Knut Sveidqvist
bf64509216 Merge branch 'develop' into 3358-blocks-diagram 2024-01-18 17:07:34 +01:00
Sidharth Vinod
2525966853 Merge pull request #5132 from nirname/docs/2910_update-contributing-guidelines
Contribution documentation improvements
2024-01-18 15:59:47 +00:00
Knut Sveidqvist
173ba2ecf5 Final console.log removed 2024-01-18 15:48:40 +01:00
Knut Sveidqvist
8e147206d8 #3358 Removed logging som type fixes 2024-01-18 15:44:16 +01:00
Knut Sveidqvist
1230da7fc7 #3358 Some cleanup 2024-01-18 15:31:14 +01:00
Knut Sveidqvist
a0d328d734 #3358 Removed logging, fixed som tests 2024-01-18 14:28:14 +01:00
Knut Sveidqvist
bbc7fe6163 #3358 Fix for width of composite blocks 2024-01-18 10:22:09 +01:00
Alois Klink
8788b49351 Merge pull request #5192 from murdoa/bug/5191_fix_gantt_chart_padding_docs
Updated gantt chart docs to show all config options
2024-01-17 18:55:03 +00:00
Matheus Braga
7a8a1315c0 Merge branch 'develop' into feature/5114_add_parallel_commit_config 2024-01-16 21:14:17 -03:00
Matheus B
9213afbacd Add tests for gitgraphs with unconnected branches 2024-01-16 20:55:42 -03:00
Matheus B
c77a6e156c Include logic for gitgraph with unconnected branches 2024-01-16 20:54:26 -03:00
Matheus B
02246f64d2 Include undefined on findClosestParent return types and update the function 2024-01-16 20:01:03 -03:00
Matheus B
bf1edd99f9 Remove unnecessary argument on findClosestParent call 2024-01-16 19:37:52 -03:00
Matheus B
6f09bc7dc7 Use already defined const instead of method call 2024-01-16 19:34:16 -03:00
Matheus B
96ac2369b6 Change string concatenation to template literal 2024-01-16 15:36:31 -03:00
Matheus Braga
8c7edebe93 Revert "Revert 5041 feature/4935 subgraph title margin config option" 2024-01-16 13:21:31 -03:00
Nikolay Rozhkov
36fdff8378 Merge branch 'develop' into docs/2910_update-contributing-guidelines 2024-01-15 13:17:47 +03:00
dependabot[bot]
0e7e597384 build(deps-dev): bump follow-redirects from 1.15.2 to 1.15.5
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.5.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.5)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-15 09:18:38 +00:00
Nikolay Rozhkov
bafb991a35 Run dev docs without npx 2024-01-14 01:07:37 +03:00
Nikolay Rozhkov
385bf328c2 Remove npx completely from run script 2024-01-14 01:05:47 +03:00
nirname
3290c38260 Update docs 2024-01-13 20:41:27 +00:00
Nikolay Rozhkov
621d6cbda1 Fix linters 2024-01-13 23:38:11 +03:00
Nikolay Rozhkov
f6b321d769 Removed volta requirement, leave pnpm only 2024-01-13 15:19:36 +03:00
Abrifq
3fb6acbf8f Fix pnpm-lock by resetting it, sorry! 2024-01-12 23:50:35 +03:00
Abrifq
cbeee51108 Merge branch 'develop' into patch-4 2024-01-12 23:42:18 +03:00
Nikolay Rozhkov
a3092fc174 Fixed dead link 2024-01-12 02:00:30 +03:00
Nikolay Rozhkov
26f6aec442 build 2024-01-12 01:57:13 +03:00
Nikolay Rozhkov
21ecc28b40 Merge branch 'develop' into docs/2910_update-contributing-guidelines 2024-01-12 01:41:00 +03:00
nirname
374e788e81 Update docs 2024-01-11 22:35:39 +00:00
Nikolay Rozhkov
7219d604a9 Updated contributing docs after review, minor fixes 2024-01-12 01:32:07 +03:00
murdoa
e52fcd0bdd Updated gantt chart docs to show all config options 2024-01-11 22:24:50 +00:00
Knut Sveidqvist
1d1875718d #3358 Sieblinmg height alignment 2024-01-08 15:48:59 +01:00
Knut Sveidqvist
7043892e87 #3358 Fix for layout where a siebling has wider siize 2024-01-08 14:03:42 +01:00
Knut Sveidqvist
809c450164 #3358 Support for adding tests and fixed issues for some shapes 2024-01-08 11:49:34 +01:00
Knut Sveidqvist
818cb2fd76 #3358 Adding support for style statements 2024-01-05 20:56:57 +01:00
Nikolay Rozhkov
e628f64a93 Empty 2024-01-05 21:22:56 +03:00
nirname
be7c6377ca Update docs 2024-01-05 18:08:31 +00:00
Nikolay Rozhkov
5f9b965be3 Linters 2024-01-05 21:05:10 +03:00
Nikolay Rozhkov
6d5f33856c Fixed redirects 2024-01-05 19:33:15 +03:00
Nikolay Rozhkov
e0bd684248 Removed duplicated docs, keep community folder name 2024-01-05 18:02:13 +03:00
Nikolay Rozhkov
17312a0232 Cleanup 2024-01-05 17:37:34 +03:00
nirname
a05aba4cc9 Update docs 2024-01-05 14:19:54 +00:00
Nikolay Rozhkov
3c27f46c57 Fixed dead links 2024-01-05 17:16:07 +03:00
Knut Sveidqvist
275e01acba #3358 Adding support for classDef and class statements 2024-01-05 15:13:15 +01:00
nirname
9ccb340d63 Update docs 2024-01-05 13:56:36 +00:00
Nikolay Rozhkov
9aaf63139a Removed unused files 2024-01-05 16:53:31 +03:00
Nikolay Rozhkov
67dde70bec Fixes 2024-01-05 16:36:12 +03:00
Knut Sveidqvist
72135c294e #3358 Edge labels 2024-01-04 16:28:13 +01:00
Knut Sveidqvist
d0eca268ad #3358 Multiple arrows 2024-01-04 16:05:19 +01:00
Knut Sveidqvist
2ed4469029 #3358 Adding arrows to rendering 2024-01-04 14:15:30 +01:00
Nikolay Rozhkov
98cf63ebb2 Merge branch 'develop' into docs/2910_update-contributing-guidelines 2024-01-04 04:14:18 +03:00
nirname
a32e72b660 Update docs 2024-01-04 01:12:59 +00:00
Nikolay Rozhkov
e7824f05cb Fixes for tutorials link 2024-01-04 04:07:56 +03:00
nirname
e2fd5ecd02 Update docs 2024-01-04 01:00:15 +00:00
Nikolay Rozhkov
a7d0d414b2 Small reorganizing 2024-01-04 03:56:45 +03:00
nirname
8edf96fe1c Update docs 2024-01-04 00:41:07 +00:00
Nikolay Rozhkov
807a5bfab4 Batch of small improvements for the documentation 2024-01-04 03:37:47 +03:00
Matheus B
c50a82a60e Build config types 2023-12-22 21:52:19 -03:00
Matheus Braga
f5ef0b600e Merge branch 'develop' into bug/5059_fix_external_connection_after_updating_edges 2023-12-22 21:49:21 -03:00
Matheus B
41f3f9fb32 Fix linter issues 2023-12-22 21:48:19 -03:00
Matheus B
46583cf4eb Merge branch 'develop' into feature/5114_add_parallel_commit_config 2023-12-22 21:32:20 -03:00
Matheus B
eb3e924c44 Add tests for gitGraph with parallel commits 2023-12-22 21:11:50 -03:00
Matheus B
222c46e7f0 Implement support for parallel commits config 2023-12-22 21:08:15 -03:00
Matheus B
00ac6ccb37 Add parallelCommits config option for gitGraphs 2023-12-22 20:42:24 -03:00
Vitor Soares Silva
e6bd1ae9dc fix sequence diagram popup 2023-12-22 11:30:24 -03:00
nirname
d54d13ef28 Update docs 2023-12-21 00:44:22 +00:00
Nikolay Rozhkov
dfa0ad5b7a Refined contribution guide again 2023-12-21 03:41:21 +03:00
Ronid1
8e6f5bbdb1 Merge branch 'docs/4974_reorder_integration_links' of https://github.com/Ronid1/mermaid into docs/4974_reorder_integration_links 2023-12-19 18:30:20 -08:00
Ronid1
8002d9e2eb Merge branch 'develop' of https://github.com/mermaid-js/mermaid into docs/4974_reorder_integration_links 2023-12-19 18:17:58 -08:00
nirname
97ee5a8488 Update docs 2023-12-19 01:36:43 +00:00
Nikolay Rozhkov
d2b9240a22 Simplify things 2023-12-19 04:33:38 +03:00
nirname
37829696d8 Update docs 2023-12-19 00:59:26 +00:00
Nikolay Rozhkov
2705c0de03 Different fixes 2023-12-19 03:56:16 +03:00
nirname
5b58883db8 Update docs 2023-12-18 23:58:33 +00:00
Nikolay Rozhkov
3bc39409e5 Formatting 2023-12-19 02:55:20 +03:00
Nikolay Rozhkov
2f3f76fa24 Contribution guidelines rework 2023-12-19 02:48:22 +03:00
Nikolay Rozhkov
7b6764da20 Merge branch 'develop' into docs/2910_update-contributing-guidelines 2023-12-19 00:55:46 +03:00
Nikolay Rozhkov
f66f4f438f Use deep outline for the whole documentation website 2023-12-19 00:54:33 +03:00
Matheus Braga
ddd6e9ac73 Merge branch 'develop' into bug/5059_fix_external_connection_after_updating_edges 2023-12-18 17:12:44 -03:00
Abrifq
31578ae72d chore: update browsers list 2023-12-18 18:28:37 +00:00
Arda Aydın
5d70b8922d Update update-browserlist.yml 2023-12-18 21:27:19 +03:00
Arda Aydın
26956bf128 Update update-browserlist.yml to install pnpm
this feels like a disgusting fix, not gonna lie
2023-12-18 21:22:52 +03:00
Arda Aydın
11aa7a7052 Update update-browserlist.yml to fix deprecation and action fails 2023-12-18 20:59:02 +03:00
Nikolay Rozhkov
0506ba872a Fixed linters 2023-12-17 13:35:49 +03:00
William Jennings
7e6fd1ebe2 Update pie.html demo 2023-12-12 13:53:25 -08:00
Scott Blomquist
5e1f0c620a Fix typos in timeline syntax samples 2023-12-12 12:48:07 -08:00
Nikolay Rozhkov
01908b1278 Development Into planning 2023-12-11 05:22:58 +03:00
Nikolay Rozhkov
57f0a3aa8e Contribution documentation improvements 2023-12-11 05:08:42 +03:00
Matheus B
c8f0b39075 Add e2e test for edge case 2023-12-08 13:39:53 -03:00
Matheus Braga
7e1cc27c76 Merge branch 'mermaid-js:develop' into bug/5059_fix_external_connection_after_updating_edges 2023-12-08 13:15:09 -03:00
Matheus B
8bff32adab Modify algorithm to re-check for external connections after defining anchor nodes 2023-12-08 13:08:13 -03:00
futzmonitor
03b5c00f03 Merge branch 'develop' into issue1981 2023-12-05 21:56:08 -05:00
futzmonitor
aa3a19b63c Merge branch 'develop' into issue1981 2023-12-04 15:25:09 -05:00
futzmonitor
8e95cdb883 Changes to gantt.jison
1. Consistent spacing on line 30
2023-12-02 12:56:58 -05:00
futzmonitor
68ff352f2d Changes to gantt.jison
1. Removed typo
2023-12-02 10:26:46 -05:00
futzmonitor
f02dfe60af Changes to gnatt.jison
1. Removed the hash and semicolon symbols from the title regex to allow for their use.
2. Removed the hash and semicolon symbols from the section regex to allow for their use.
3. Removed the hash and semicolon symbols for the taskTxt regex to allow for their use. I did not remove the colon because the parser fails to recognize when the actual taskData begins if that distinctions isn't kept.
4. Removed the regex \#[^\n]* which skipped comments to fix some bugs with hash symbols in the taskTxt. I tested this changed by putting it back and using the comment  to see if it was recognized as a comment, but I would receive a syntax error and the diagram would not be rendered. So, I think we can safely remove that line, BUT it would be best practice if someone else tested this change to ensure that this will not break anyone's Gantt diagrams.
2023-12-02 10:23:44 -05:00
Sidharth Vinod
53b4f584db Merge branch 'develop' into docs/4974_reorder_integration_links 2023-11-24 11:33:41 +05:30
Ronid1
201016ccc5 update build docs 2023-11-23 20:57:43 -08:00
Ronid1
aaf9fd5f03 update and verify links 2023-11-23 20:44:35 -08:00
Ronid1
783becebf6 alphabetically order sub categories 2023-11-23 20:38:44 -08:00
Ronid1
3e098ab73b sort links alphabetically 2023-11-23 20:38:44 -08:00
Knut Sveidqvist
df858dc7b6 #3358 Adding arrows to syntax 2023-11-20 14:00:25 +01:00
Knut Sveidqvist
03c59adaed Parsing of block arrows with directions, creating a dedicated new node for this. 2023-10-26 22:02:16 +02:00
Knut Sveidqvist
7198fe55a9 Parsing of block arrows with directions, creating a dedicated new node for this. 2023-10-26 22:01:44 +02:00
Knut Sveidqvist
f3f25c7874 #3358 Adding support for space blocks and different shapes 2023-10-20 12:30:25 +02:00
Knut Sveidqvist
5619f8771b #3358 Adding support for space blocks and different shapes 2023-10-20 12:13:49 +02:00
Knut Sveidqvist
74a9e86e74 #3358 Putting the elements back in 2023-10-15 22:55:29 +02:00
Knut Sveidqvist
a641fd51e8 #3358 Adding support for column statements 2023-10-15 22:21:25 +02:00
Knut Sveidqvist
da79b371fe #3358 Recursive positioning paddings 2023-10-04 10:44:29 +02:00
Knut Sveidqvist
c8d155c455 #3358 Recursive positioning 2023-10-03 20:12:33 +02:00
Knut Sveidqvist
f00871a6b4 #3358 Recursive positioning 2023-10-03 14:19:08 +02:00
Knut Sveidqvist
b4e32542e8 #3358 Recursive positioning 2023-10-03 12:56:47 +02:00
Knut Sveidqvist
836d3a87be WIP 2023-09-14 10:11:43 +02:00
Knut Sveidqvist
ccdb803501 Rendering, interim 2023-09-05 15:15:08 +02:00
Knut Sveidqvist
1e864a508d Rendering, tmp commit before refactoring 2023-09-05 11:13:27 +02:00
Knut Sveidqvist
5f1cfc7519 Support for compound blocks with id, title and type 2023-09-01 16:22:23 +02:00
Knut Sveidqvist
e52de6c279 Some cleanup 2023-09-01 15:40:49 +02:00
Knut Sveidqvist
8a55b212a2 Saving data from compound blocks 2023-09-01 15:33:38 +02:00
Knut Sveidqvist
aa7f5a8387 before refactoring 2023-09-01 14:06:13 +02:00
Knut Sveidqvist
5fc99f1982 #3358 Adding db calls from node statements 2023-08-28 12:51:49 +02:00
Knut Sveidqvist
b9531d56c4 Adding support for compound blocks 2023-08-08 15:56:02 +02:00
Knut Sveidqvist
13114ebaa1 Merge branch 'develop' into 3358-blocks-diagram 2023-07-25 11:47:22 +02:00
Nikolay Rozhkov
e251baa61c Started layout and rendering 2023-07-11 02:51:10 +03:00
Nikolay Rozhkov
d165e8a642 Started block diag db development 2023-07-10 23:33:11 +03:00
Knut Sveidqvist
c10f76580f Adding some more tests 2023-07-09 12:28:14 +02:00
Nikolay Rozhkov
975f36c7db Fixed block diagram parser import 2023-07-07 14:14:30 +03:00
Nikolay Rozhkov
fee2b244a1 Small cleanup 2023-07-07 14:12:18 +03:00
Nikolay Rozhkov
791e67641e Rename BlockDiagram to Block 2023-07-07 13:58:30 +03:00
Knut Sveidqvist
86e1bb38ee #3358 First commit with basic grammar and 1st test 2023-07-05 12:01:37 +02:00
151 changed files with 7879 additions and 3321 deletions

View File

@@ -63,6 +63,17 @@ module.exports = {
minimumDescriptionLength: 10, minimumDescriptionLength: 10,
}, },
], ],
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'typeLike',
format: ['PascalCase'],
custom: {
regex: '^I[A-Z]',
match: false,
},
},
],
'json/*': ['error', 'allowComments'], 'json/*': ['error', 'allowComments'],
'@cspell/spellchecker': [ '@cspell/spellchecker': [
'error', 'error',

View File

@@ -3,9 +3,9 @@ contact_links:
- name: GitHub Discussions - name: GitHub Discussions
url: https://github.com/mermaid-js/mermaid/discussions url: https://github.com/mermaid-js/mermaid/discussions
about: Ask the Community questions or share your own graphs in our discussions. about: Ask the Community questions or share your own graphs in our discussions.
- name: Slack - name: Discord
url: https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE url: https://discord.gg/AgrbSrBer3
about: Join our Community on Slack for Help and a casual chat. about: Join our Community on Discord for Help and a casual chat.
- name: Documentation - name: Documentation
url: https://mermaid.js.org url: https://mermaid.js.org
about: Read our documentation for all that Mermaid.js can offer. about: Read our documentation for all that Mermaid.js can offer.

4
.github/lychee.toml vendored
View File

@@ -34,8 +34,8 @@ exclude = [
# Don't check files that are generated during the build via `pnpm docs:code` # Don't check files that are generated during the build via `pnpm docs:code`
'packages/mermaid/src/docs/config/setup/*', 'packages/mermaid/src/docs/config/setup/*',
# Ignore slack invite # Ignore Discord invite
"https://join.slack.com/" "https://discord.gg"
] ]
# Exclude all private IPs from checking. # Exclude all private IPs from checking.

View File

@@ -14,5 +14,5 @@ Make sure you
- [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md) - [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md)
- [ ] :computer: have added necessary unit/e2e tests. - [ ] :computer: have added necessary unit/e2e tests.
- [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/docs/community/development.md#3-update-documentation) is used for all new features. - [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/docs/community/contributing.md#update-documentation) is used for all new features.
- [ ] :bookmark: targeted `develop` branch - [ ] :bookmark: targeted `develop` branch

View File

@@ -24,7 +24,7 @@ jobs:
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18 node-version-file: '.node-version'
- name: Install Packages - name: Install Packages
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile

View File

@@ -15,20 +15,17 @@ permissions:
jobs: jobs:
build-mermaid: build-mermaid:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: ${{ matrix.node-version }} node-version-file: '.node-version'
- name: Install Packages - name: Install Packages
run: | run: |

View File

@@ -21,9 +21,9 @@ env:
jobs: jobs:
e2e-applitools: e2e-applitools:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: container:
matrix: image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
node-version: [18.x] options: --user 1001
steps: steps:
- if: ${{ ! env.USE_APPLI }} - if: ${{ ! env.USE_APPLI }}
name: Warn if not using Applitools name: Warn if not using Applitools
@@ -35,10 +35,10 @@ jobs:
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version-file: '.node-version'
- if: ${{ env.USE_APPLI }} - if: ${{ env.USE_APPLI }}
name: Notify applitools of new batch name: Notify applitools of new batch

View File

@@ -1,20 +1,71 @@
# We use github cache to save snapshots between runs.
# For PRs and MergeQueues, the target commit is used, and for push events, github.event.previous is used.
# If a snapshot for a given Hash is not found, we checkout that commit, run the tests and cache the snapshots.
# These are then downloaded before running the E2E, providing the reference snapshots.
# If there are any errors, the diff image is uploaded to artifacts, and the user is notified.
name: E2E name: E2E
on: on:
push: push:
branches-ignore:
- 'gh-readonly-queue/**'
pull_request: pull_request:
merge_group: merge_group:
permissions: permissions:
contents: read contents: read
env:
# For PRs and MergeQueues, the target commit is used, and for push events, github.event.previous is used.
targetHash: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || (github.event.before == '0000000000000000000000000000000000000000' && 'develop' || github.event.before) }}
jobs: jobs:
cache:
runs-on: ubuntu-latest
container:
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
options: --user 1001
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: '.node-version'
- name: Cache snapshots
id: cache-snapshot
uses: actions/cache@v4
with:
save-always: true
path: ./cypress/snapshots
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
# If a snapshot for a given Hash is not found, we checkout that commit, run the tests and cache the snapshots.
- name: Switch to base branch
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
uses: actions/checkout@v4
with:
ref: ${{ env.targetHash }}
- name: Cypress run
uses: cypress-io/github-action@v4
id: cypress-snapshot-gen
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
with:
start: pnpm run dev
wait-on: 'http://localhost:9000'
browser: chrome
e2e: e2e:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container:
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
options: --user 1001
needs: cache
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
node-version: [18.x]
containers: [1, 2, 3, 4] containers: [1, 2, 3, 4]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -22,10 +73,18 @@ jobs:
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version-file: '.node-version'
# These cached snapshots are downloaded, providing the reference snapshots.
- name: Cache snapshots
id: cache-snapshot
uses: actions/cache/restore@v3
with:
path: ./cypress/snapshots
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
# Install NPM dependencies, cache them correctly # Install NPM dependencies, cache them correctly
# and run all Cypress tests # and run all Cypress tests
@@ -38,6 +97,7 @@ jobs:
with: with:
start: pnpm run dev:coverage start: pnpm run dev:coverage
wait-on: 'http://localhost:9000' wait-on: 'http://localhost:9000'
browser: chrome
# Disable recording if we don't have an API key # Disable recording if we don't have an API key
# e.g. if this action was run from a fork # e.g. if this action was run from a fork
record: ${{ secrets.CYPRESS_RECORD_KEY != '' }} record: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
@@ -46,6 +106,7 @@ jobs:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
VITEST_COVERAGE: true VITEST_COVERAGE: true
CYPRESS_COMMIT: ${{ github.sha }} CYPRESS_COMMIT: ${{ github.sha }}
- name: Upload Coverage to Codecov - name: Upload Coverage to Codecov
uses: codecov/codecov-action@v3 uses: codecov/codecov-action@v3
# Run step only pushes to develop and pull_requests # Run step only pushes to develop and pull_requests
@@ -57,9 +118,55 @@ jobs:
fail_ci_if_error: false fail_ci_if_error: false
verbose: true verbose: true
token: 6845cc80-77ee-4e17-85a1-026cd95e0766 token: 6845cc80-77ee-4e17-85a1-026cd95e0766
# We upload the artifacts into numbered archives to prevent overwriting
- name: Upload Artifacts - name: Upload Artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: ${{ failure() && steps.cypress.conclusion == 'failure' }} if: ${{ always() }}
with:
name: snapshots-${{ matrix.containers }}
retention-days: 1
path: ./cypress/snapshots
combineArtifacts:
needs: e2e
runs-on: ubuntu-latest
if: ${{ always() }}
steps:
# Download all snapshot artifacts and merge them into a single folder
- name: Download All Artifacts
uses: actions/download-artifact@v4
with:
path: snapshots
pattern: snapshots-*
merge-multiple: true
# For successful push events, we save the snapshots cache
- name: Save snapshots cache
id: cache-upload
if: ${{ github.event_name == 'push' && needs.e2e.result != 'failure' }}
uses: actions/cache/save@v3
with:
path: ./snapshots
key: ${{ runner.os }}-snapshots-${{ github.event.after }}
- name: Flatten images to a folder
if: ${{ needs.e2e.result == 'failure' }}
run: |
mkdir errors
cd snapshots
find . -mindepth 2 -type d -name "*__diff_output__*" -exec sh -c 'mv "$0"/*.png ../errors/' {} \;
- name: Upload Error snapshots
if: ${{ needs.e2e.result == 'failure' }}
uses: actions/upload-artifact@v4
id: upload-artifacts
with: with:
name: error-snapshots name: error-snapshots
path: cypress/snapshots/**/__diff_output__/* retention-days: 10
path: errors/
- name: Notify Users
if: ${{ needs.e2e.result == 'failure' }}
run: |
echo "::error title=Visual tests failed::You can view images that failed by downloading the error-snapshots artifact: ${{ steps.upload-artifacts.outputs.artifact-url }}"

View File

@@ -16,20 +16,17 @@ permissions:
jobs: jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: ${{ matrix.node-version }} node-version-file: '.node-version'
- name: Install Packages - name: Install Packages
run: | run: |

View File

@@ -31,7 +31,7 @@ jobs:
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18 node-version-file: '.node-version'
- name: Install Packages - name: Install Packages
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile

View File

@@ -19,7 +19,7 @@ jobs:
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18.x node-version-file: '.node-version'
- name: Install Packages - name: Install Packages
run: | run: |

View File

@@ -14,11 +14,11 @@ jobs:
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js v18 - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18.x node-version-file: '.node-version'
- name: Install Packages - name: Install Packages
run: | run: |

View File

@@ -8,20 +8,17 @@ permissions:
jobs: jobs:
unit-test: unit-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: ${{ matrix.node-version }} node-version-file: '.node-version'
- name: Install Packages - name: Install Packages
run: | run: |

View File

@@ -9,10 +9,17 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: npx browserslist@latest --update-db - uses: pnpm/action-setup@v2
- run: npx update-browserslist-db@latest
- name: Commit changes - name: Commit changes
uses: EndBug/add-and-commit@v9 uses: EndBug/add-and-commit@v9
with: with:
author_name: ${{ github.actor }} author_name: ${{ github.actor }}
author_email: ${{ github.actor }}@users.noreply.github.com author_email: ${{ github.actor }}@users.noreply.github.com
message: 'chore: update browsers list' message: 'chore: update browsers list'
push: false
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:
branch: update-browserslist
title: Update Browserslist

1
.gitignore vendored
View File

@@ -46,3 +46,4 @@ stats/
demos/dev/** demos/dev/**
!/demos/dev/example.html !/demos/dev/example.html
tsx-0/**

1
.node-version Normal file
View File

@@ -0,0 +1 @@
v20.11.0

View File

@@ -25,6 +25,7 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
'gitGraph', 'gitGraph',
'c4', 'c4',
'sankey', 'sankey',
'block',
] as const; ] as const;
/** /**

View File

@@ -1,78 +0,0 @@
# Contributing
Please read in detail about how to contribute documentation and code on the [Mermaid documentation site.](https://mermaid-js.github.io/mermaid/#/development)
---
# Mermaid contribution cheat-sheet
## Requirements
- [volta](https://volta.sh/) to manage node versions.
- [Node.js](https://nodejs.org/en/). `volta install node`
- [pnpm](https://pnpm.io/) package manager. `volta install pnpm`
## Development Installation
If you don't have direct access to push to mermaid repositories, make a fork first. Then clone. Or clone directly from mermaid-js:
```bash
git clone git@github.com:mermaid-js/mermaid.git
cd mermaid
```
Install required packages:
```bash
# npx is required for first install as volta support for pnpm is not added yet.
npx pnpm install
pnpm test # run unit tests
pnpm dev # starts a dev server
```
Open <http://localhost:9000> in your browser after starting the dev server.
You can also duplicate the `example.html` file in `demos/dev`, rename it and add your own mermaid code to it.
That will be served at <http://localhost:9000/dev/your-file-name.html>.
### Docker
If you are using docker and docker-compose, you have self-documented `run` bash script, which is a convenient alias for docker-compose commands:
```bash
./run install # npx pnpm install
./run test # pnpm test
```
## Testing
```bash
# Run unit test
pnpm test
# Run unit test in watch mode
pnpm test:watch
# Run E2E test
pnpm e2e
# Debug E2E tests
pnpm dev
pnpm cypress:open # in another terminal
```
## Branch name format:
```text
[feature | bug | chore | docs]/[issue number]_[short description using dashes ('-') or underscores ('_') instead of spaces]
```
eg: `feature/2945_state-diagram-new-arrow-florbs`, `bug/1123_fix_random_ugly_red_text`
## Documentation
Documentation is necessary for all non bugfix/refactoring changes.
Only make changes to files that are in [`/packages/mermaid/src/docs`](packages/mermaid/src/docs)
**_DO NOT CHANGE FILES IN `/docs` MANUALLY_**
The `/docs` folder will be rebuilt and committed as part of a pre-commit hook.
[Join our slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)

1
CONTRIBUTING.md Symbolic link
View File

@@ -0,0 +1 @@
./packages/mermaid/src/docs/community/contributing.md

2
Dockerfile Normal file
View File

@@ -0,0 +1,2 @@
FROM node:20.11.0-alpine3.19 AS base
RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -

View File

@@ -15,7 +15,7 @@ Generate diagrams from markdown-like text.
<a href="https://mermaid.live/"><b>Live Editor!</b></a> <a href="https://mermaid.live/"><b>Live Editor!</b></a>
</p> </p>
<p align="center"> <p align="center">
<a href="https://mermaid.js.org">📖 Documentation</a> | <a href="https://mermaid.js.org/intro/">🚀 Getting Started</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE" title="Slack invite">🙌 Join Us</a> <a href="https://mermaid.js.org">📖 Documentation</a> | <a href="https://mermaid.js.org/intro/">🚀 Getting Started</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/AgrbSrBer3" title="Discord invite">🙌 Join Us</a>
</p> </p>
<p align="center"> <p align="center">
<a href="./README.zh-CN.md">简体中文</a> <a href="./README.zh-CN.md">简体中文</a>
@@ -33,7 +33,7 @@ Try Live Editor previews of future releases: <a href="https://develop.git.mermai
[![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop) [![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
[![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid)
[![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![Join our Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/AgrbSrBer3)
[![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_) [![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_)
<img src="./img/header.png" alt="" /> <img src="./img/header.png" alt="" />
@@ -74,12 +74,12 @@ Mermaid addresses this problem by enabling users to create easily modifiable dia
<br/> <br/>
Mermaid allows even non-programmers to easily create detailed diagrams through the [Mermaid Live Editor](https://mermaid.live/).<br/> Mermaid allows even non-programmers to easily create detailed diagrams through the [Mermaid Live Editor](https://mermaid.live/).<br/>
For video tutorials, visit our [Tutorials](./docs/config/Tutorials.md) page. For video tutorials, visit our [Tutorials](./docs/ecosystem/tutorials.md) page.
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations-community.md). Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations-community.md).
You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) as well many of your other favorite applications—check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations-community.md). You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) as well many of your other favorite applications—check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations-community.md).
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/intro/getting-started.md), [Usage](./docs/config/usage.md) and [Tutorials](./docs/config/Tutorials.md). For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/intro/getting-started.md), [Usage](./docs/config/usage.md) and [Tutorials](./docs/ecosystem/tutorials.md).
In our release process we rely heavily on visual regression tests using [applitools](https://applitools.com/). Applitools is a great service which has been easy to use and integrate with our tests. In our release process we rely heavily on visual regression tests using [applitools](https://applitools.com/). Applitools is a great service which has been easy to use and integrate with our tests.

View File

@@ -15,7 +15,7 @@ Mermaid
<a href="https://mermaid.live/"><b>实时编辑器!</b></a> <a href="https://mermaid.live/"><b>实时编辑器!</b></a>
</p> </p>
<p align="center"> <p align="center">
<a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE" title="Slack invite">🙌 加入我们</a> <a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/AgrbSrBer3" title="Discord invite">🙌 加入我们</a>
</p> </p>
<p align="center"> <p align="center">
<a href="./README.md">English</a> <a href="./README.md">English</a>
@@ -34,7 +34,7 @@ Mermaid
[![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop) [![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
[![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid)
[![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![Join our Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/AgrbSrBer3)
[![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_) [![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_)
<img src="./img/header.png" alt="" /> <img src="./img/header.png" alt="" />
@@ -57,9 +57,9 @@ Mermaid 是一个基于 Javascript 的图表绘制工具,通过解析类 Markd
Mermaid 通过允许用户创建便于修改的图表来解决这一难题,它也可以作为生产脚本(或其他代码)的一部分。<br/> Mermaid 通过允许用户创建便于修改的图表来解决这一难题,它也可以作为生产脚本(或其他代码)的一部分。<br/>
<br/> <br/>
Mermaid 甚至能让非程序员也能通过 [Mermaid Live Editor](https://mermaid.live/) 轻松创建详细的图表。<br/> Mermaid 甚至能让非程序员也能通过 [Mermaid Live Editor](https://mermaid.live/) 轻松创建详细的图表。<br/>
你可以访问 [教程](./docs/config/Tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/ecosystem/integrations-community.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。 你可以访问 [教程](./docs/ecosystem/tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/ecosystem/integrations-community.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/intro/getting-started.md), [用法](./docs/config/usage.md) 和 [教程](./docs/config/Tutorials.md). 如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/intro/getting-started.md), [用法](./docs/config/usage.md) 和 [教程](./docs/ecosystem/tutorials.md).
<!-- </Main description> --> <!-- </Main description> -->

View File

@@ -1,19 +0,0 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { defineConfig } = require('cypress');
module.exports = defineConfig({
testConcurrency: 1,
browser: [
// Add browsers with different viewports
// { width: 800, height: 600, name: 'chrome' },
// { width: 700, height: 500, name: 'firefox' },
// { width: 1600, height: 1200, name: 'ie11' },
// { width: 1024, height: 768, name: 'edgechromium' },
// { width: 800, height: 600, name: 'safari' },
// // Add mobile emulation devices in Portrait mode
// { deviceName: 'iPhone X', screenOrientation: 'portrait' },
// { deviceName: 'Pixel 2', screenOrientation: 'portrait' },
],
// set batch name to the configuration
// batchName: `Mermaid ${process.env.APPLI_BRANCH ?? "'no APPLI_BRANCH set'"}`,
});

View File

@@ -28,6 +28,7 @@
"codedoc", "codedoc",
"codemia", "codemia",
"colour", "colour",
"colours",
"commitlint", "commitlint",
"cpettitt", "cpettitt",
"customizability", "customizability",
@@ -102,6 +103,7 @@
"pathe", "pathe",
"pbrolin", "pbrolin",
"phpbb", "phpbb",
"pixelmatch",
"plantuml", "plantuml",
"playfair", "playfair",
"pnpm", "pnpm",
@@ -124,6 +126,7 @@
"sidharth", "sidharth",
"sidharthv", "sidharthv",
"sphinxcontrib", "sphinxcontrib",
"ssim",
"startx", "startx",
"starty", "starty",
"statediagram", "statediagram",

View File

@@ -1,24 +0,0 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const { defineConfig } = require('cypress');
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
const coverage = require('@cypress/code-coverage/task');
module.exports = defineConfig({
projectId: 'n2sma2',
e2e: {
specPattern: 'cypress/integration/**/*.{js,jsx,ts,tsx}',
setupNodeEvents(on, config) {
coverage(on, config);
addMatchImageSnapshotPlugin(on, config);
// copy any needed variables from process.env to config.env
config.env.useAppli = process.env.USE_APPLI ? true : false;
// do not forget to return the changed config object!
return config;
},
},
video: false,
});
require('@applitools/eyes-cypress')(module);

30
cypress.config.ts Normal file
View File

@@ -0,0 +1,30 @@
import { defineConfig } from 'cypress';
import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';
import coverage from '@cypress/code-coverage/task';
import eyesPlugin from '@applitools/eyes-cypress';
export default eyesPlugin(
defineConfig({
projectId: 'n2sma2',
viewportWidth: 1440,
viewportHeight: 1024,
e2e: {
specPattern: 'cypress/integration/**/*.{js,ts}',
setupNodeEvents(on, config) {
coverage(on, config);
on('before:browser:launch', (browser, launchOptions) => {
if (browser.name === 'chrome' && browser.isHeadless) {
launchOptions.args.push('--window-size=1440,1024', '--force-device-scale-factor=1');
}
return launchOptions;
});
addMatchImageSnapshotPlugin(on, config);
// copy any needed variables from process.env to config.env
config.env.useAppli = process.env.USE_APPLI ? true : false;
// do not forget to return the changed config object!
return config;
},
},
video: false,
})
);

View File

@@ -117,7 +117,6 @@ describe('Configuration', () => {
}); });
it('should not taint the initial configuration when using multiple directives', () => { it('should not taint the initial configuration when using multiple directives', () => {
const url = 'http://localhost:9000/regression/issue-1874.html'; const url = 'http://localhost:9000/regression/issue-1874.html';
cy.viewport(1440, 1024);
cy.visit(url); cy.visit(url);
cy.get('svg'); cy.get('svg');

View File

@@ -1,14 +1,12 @@
describe('Rerendering', () => { describe('Rerendering', () => {
it('should be able to render after an error has occurred', () => { it('should be able to render after an error has occurred', () => {
const url = 'http://localhost:9000/render-after-error.html'; const url = 'http://localhost:9000/render-after-error.html';
cy.viewport(1440, 1024);
cy.visit(url); cy.visit(url);
cy.get('#graphDiv').should('exist'); cy.get('#graphDiv').should('exist');
}); });
it('should be able to render and rerender a graph via API', () => { it('should be able to render and rerender a graph via API', () => {
const url = 'http://localhost:9000/rerender.html'; const url = 'http://localhost:9000/rerender.html';
cy.viewport(1440, 1024);
cy.visit(url); cy.visit(url);
cy.get('#graph [id^=flowchart-A]').should('have.text', 'XMas'); cy.get('#graph [id^=flowchart-A]').should('have.text', 'XMas');

View File

@@ -0,0 +1,386 @@
import { imgSnapshotTest } from '../../helpers/util';
/* eslint-disable no-useless-escape */
describe('Block diagram', () => {
it('BL1: should calculate the block widths', () => {
imgSnapshotTest(
`block-beta
columns 2
block
id2["I am a wide one"]
id1
end
id["Next row"]
`
);
});
it('BL2: should handle colums statement in sub-blocks', () => {
imgSnapshotTest(
`block-beta
id1["Hello"]
block
columns 3
id2["to"]
id3["the"]
id4["World"]
id5["World"]
end
`,
{}
);
});
it('BL3: should align block widths and handle colums statement in sub-blocks', () => {
imgSnapshotTest(
`block-beta
block
columns 1
id1
id2
id2.1
end
id3
id4
`,
{}
);
});
it('BL4: should align block widths and handle colums statements in deeper sub-blocks then 1 level', () => {
imgSnapshotTest(
`block-beta
columns 1
block
columns 1
block
columns 3
id1
id2
id2.1(("XYZ"))
end
id48
end
id3
`,
{}
);
});
it('BL5: should align block widths and handle colums statements in deeper sub-blocks then 1 level (alt)', () => {
imgSnapshotTest(
`block-beta
columns 1
block
id1
id2
block
columns 1
id3("Wider then")
id5(("id5"))
end
end
id4
`,
{}
);
});
it('BL6: should handle block arrows and spece statements', () => {
imgSnapshotTest(
`block-beta
columns 3
space:3
ida idb idc
id1 id2
blockArrowId<["Label"]>(right)
blockArrowId2<["Label"]>(left)
blockArrowId3<["Label"]>(up)
blockArrowId4<["Label"]>(down)
blockArrowId5<["Label"]>(x)
blockArrowId6<["Label"]>(y)
blockArrowId6<["Label"]>(x, down)
`,
{}
);
});
it('BL7: should handle different types of edges', () => {
imgSnapshotTest(
`block-beta
columns 3
A space:5
A --o B
A --> C
A --x D
`,
{}
);
});
it('BL8: should handle sub-blocks without columns statements', () => {
imgSnapshotTest(
`block-beta
columns 2
C A B
block
D
E
end
`,
{}
);
});
it('BL9: should handle edges from blocks in sub blocks to other blocks', () => {
imgSnapshotTest(
`block-beta
columns 3
B space
block
D
end
D --> B
`,
{}
);
});
it('BL10: should handle edges from composite blocks', () => {
imgSnapshotTest(
`block-beta
columns 3
B space
block BL
D
end
BL --> B
`,
{}
);
});
it('BL11: should handle edges to composite blocks', () => {
imgSnapshotTest(
`block-beta
columns 3
B space
block BL
D
end
B --> BL
`,
{}
);
});
it('BL12: edges should handle labels', () => {
imgSnapshotTest(
`block-beta
A
space
A -- "apa" --> E
`,
{}
);
});
it('BL13: should handle block arrows in different directions', () => {
imgSnapshotTest(
`block-beta
columns 3
space blockArrowId1<["down"]>(down) space
blockArrowId2<["right"]>(right) blockArrowId3<["Sync"]>(x, y) blockArrowId4<["left"]>(left)
space blockArrowId5<["up"]>(up) space
blockArrowId6<["x"]>(x) space blockArrowId7<["y"]>(y)
`,
{}
);
});
it('BL14: should style statements and class statements', () => {
imgSnapshotTest(
`block-beta
A
B
classDef blue fill:#66f,stroke:#333,stroke-width:2px;
class A blue
style B fill:#f9F,stroke:#333,stroke-width:4px
`,
{}
);
});
it('BL15: width alignment - D and E should share available space', () => {
imgSnapshotTest(
`block-beta
block
D
E
end
db("This is the text in the box")
`,
{}
);
});
it('BL16: width alignment - C should be as wide as the composite block', () => {
imgSnapshotTest(
`block-beta
block
A("This is the text")
B
end
C
`,
{}
);
});
it('BL16: width alignment - blocks shold be equal in width', () => {
imgSnapshotTest(
`block-beta
A("This is the text")
B
C
`,
{}
);
});
it('BL17: block types 1 - square, rounded and circle', () => {
imgSnapshotTest(
`block-beta
A["square"]
B("rounded")
C(("circle"))
`,
{}
);
});
it('BL18: block types 2 - odd, diamond and hexagon', () => {
imgSnapshotTest(
`block-beta
A>"rect_left_inv_arrow"]
B{"diamond"}
C{{"hexagon"}}
`,
{}
);
});
it('BL19: block types 3 - stadium', () => {
imgSnapshotTest(
`block-beta
A(["stadium"])
`,
{}
);
});
it('BL20: block types 4 - lean right, lean left, trapezoid and inv trapezoid', () => {
imgSnapshotTest(
`block-beta
A[/"lean right"/]
B[\"lean left"\]
C[/"trapezoid"\]
D[\"trapezoid alt"/]
`,
{}
);
});
it('BL21: block types 1 - square, rounded and circle', () => {
imgSnapshotTest(
`block-beta
A["square"]
B("rounded")
C(("circle"))
`,
{}
);
});
it('BL22: sizing - it should be possible to make a block wider', () => {
imgSnapshotTest(
`block-beta
A("rounded"):2
B:2
C
`,
{}
);
});
it('BL23: sizing - it should be possible to make a composite block wider', () => {
imgSnapshotTest(
`block-beta
block:2
A
end
B
`,
{}
);
});
it('BL24: block in the middle with space on each side', () => {
imgSnapshotTest(
`block-beta
columns 3
space
middle["In the middle"]
space
`,
{}
);
});
it('BL25: space and an edge', () => {
imgSnapshotTest(
`block-beta
columns 5
A space B
A --x B
`,
{}
);
});
it('BL26: block sizes for regular blocks', () => {
imgSnapshotTest(
`block-beta
columns 3
a["A wide one"] b:2 c:2 d
`,
{}
);
});
it('BL27: composite block with a set width - f should use the available space', () => {
imgSnapshotTest(
`block-beta
columns 3
a:3
block:e:3
f
end
g
`,
{}
);
});
it('BL23: composite block with a set width - f and g should split the available space', () => {
imgSnapshotTest(
`block-beta
columns 3
a:3
block:e:3
f
g
end
h
i
j
`,
{}
);
});
});

View File

@@ -1,12 +0,0 @@
import { imgSnapshotTest } from '../../helpers/util.ts';
describe('Flowchart', () => {
it('34: testing the label width in percy', () => {
imgSnapshotTest(
`graph TD
A[Christmas]
`,
{ theme: 'forest', fontFamily: '"Noto Sans SC", sans-serif' }
);
});
});

View File

@@ -741,6 +741,25 @@ A ~~~ B
); );
}); });
it('5059: Should render when subgraph contains only subgraphs, has link to outside and itself is part of a link', () => {
imgSnapshotTest(
`flowchart
subgraph Main
subgraph Child1
Node1
Node2
end
subgraph Child2
Node3
Node4
end
end
Main --> Out1
Child2 --> Out2`
);
});
describe('Markdown strings flowchart (#4220)', () => { describe('Markdown strings flowchart (#4220)', () => {
describe('html labels', () => { describe('html labels', () => {
it('With styling and classes', () => { it('With styling and classes', () => {
@@ -886,4 +905,93 @@ end
}); });
}); });
}); });
describe('Subgraph title margins', () => {
it('Should render subgraphs with title margins set (LR)', () => {
imgSnapshotTest(
`flowchart LR
subgraph TOP
direction TB
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
`,
{ flowchart: { subGraphTitleMargin: { top: 10, bottom: 5 } } }
);
});
it('Should render subgraphs with title margins set (TD)', () => {
imgSnapshotTest(
`flowchart TD
subgraph TOP
direction LR
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
`,
{ flowchart: { subGraphTitleMargin: { top: 8, bottom: 16 } } }
);
});
it('Should render subgraphs with title margins set (LR) and htmlLabels set to false', () => {
imgSnapshotTest(
`flowchart LR
subgraph TOP
direction TB
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
`,
{
htmlLabels: false,
flowchart: { htmlLabels: false, subGraphTitleMargin: { top: 10, bottom: 5 } },
}
);
});
it('Should render subgraphs with title margins and edge labels', () => {
imgSnapshotTest(
`flowchart LR
subgraph TOP
direction TB
subgraph B1
direction RL
i1 --lb1-->f1
end
subgraph B2
direction BT
i2 --lb2-->f2
end
end
A --lb3--> TOP --lb4--> B
B1 --lb5--> B2
`,
{ flowchart: { subGraphTitleMargin: { top: 10, bottom: 5 } } }
);
});
});
}); });

View File

@@ -245,7 +245,10 @@ describe('Gantt diagram', () => {
const style = svg.attr('style'); const style = svg.attr('style');
expect(style).to.match(/^max-width: [\d.]+px;$/); expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
expect(maxWidthValue).to.be.within(984 * 0.95, 984 * 1.05); expect(maxWidthValue).to.be.within(
Cypress.config().viewportWidth * 0.95,
Cypress.config().viewportWidth * 1.05
);
}); });
}); });
@@ -285,11 +288,11 @@ describe('Gantt diagram', () => {
{ gantt: { useMaxWidth: false } } { gantt: { useMaxWidth: false } }
); );
cy.get('svg').should((svg) => { cy.get('svg').should((svg) => {
// const height = parseFloat(svg.attr('height'));
const width = parseFloat(svg.attr('width')); const width = parseFloat(svg.attr('width'));
// use within because the absolute value can be slightly different depending on the environment ±5% expect(width).to.be.within(
// expect(height).to.be.within(484 * 0.95, 484 * 1.05); Cypress.config().viewportWidth * 0.95,
expect(width).to.be.within(984 * 0.95, 984 * 1.05); Cypress.config().viewportWidth * 1.05
);
expect(svg).to.not.have.attr('style'); expect(svg).to.not.have.attr('style');
}); });
}); });
@@ -580,4 +583,106 @@ describe('Gantt diagram', () => {
{} {}
); );
}); });
it("should render when there's a semicolon in the title", () => {
imgSnapshotTest(
`
gantt
title ;Gantt With a Semicolon in the Title
dateFormat YYYY-MM-DD
section Section
A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2014-01-12 , 12d
another task : 24d
`,
{}
);
});
it("should render when there's a semicolon in a section is true", () => {
imgSnapshotTest(
`
gantt
title Gantt Digram
dateFormat YYYY-MM-DD
section ;Section With a Semicolon
A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2014-01-12 , 12d
another task : 24d
`,
{}
);
});
it("should render when there's a semicolon in the task data", () => {
imgSnapshotTest(
`
gantt
title Gantt Digram
dateFormat YYYY-MM-DD
section Section
;A task with a semiclon :a1, 2014-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2014-01-12 , 12d
another task : 24d
`,
{}
);
});
it("should render when there's a hashtag in the title", () => {
imgSnapshotTest(
`
gantt
title #Gantt With a Hashtag in the Title
dateFormat YYYY-MM-DD
section Section
A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2014-01-12 , 12d
another task : 24d
`,
{}
);
});
it("should render when there's a hashtag in a section is true", () => {
imgSnapshotTest(
`
gantt
title Gantt Digram
dateFormat YYYY-MM-DD
section #Section With a Hashtag
A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2014-01-12 , 12d
another task : 24d
`,
{}
);
});
it("should render when there's a hashtag in the task data", () => {
imgSnapshotTest(
`
gantt
title Gantt Digram
dateFormat YYYY-MM-DD
section Section
#A task with a hashtag :a1, 2014-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2014-01-12 , 12d
another task : 24d
`,
{}
);
});
}); });

View File

@@ -826,4 +826,121 @@ gitGraph TB:
cherry-pick id: "M" parent:"B"` cherry-pick id: "M" parent:"B"`
); );
}); });
it('41: should render default GitGraph with parallelCommits set to false', () => {
imgSnapshotTest(
`gitGraph
commit id:"1-abcdefg"
commit id:"2-abcdefg"
branch develop
commit id:"3-abcdefg"
commit id:"4-abcdefg"
checkout main
branch feature
commit id:"5-abcdefg"
commit id:"6-abcdefg"
checkout main
commit id:"7-abcdefg"
commit id:"8-abcdefg"
`,
{ gitGraph: { parallelCommits: false } }
);
});
it('42: should render GitGraph with parallel commits', () => {
imgSnapshotTest(
`gitGraph
commit id:"1-abcdefg"
commit id:"2-abcdefg"
branch develop
commit id:"3-abcdefg"
commit id:"4-abcdefg"
checkout main
branch feature
commit id:"5-abcdefg"
commit id:"6-abcdefg"
checkout main
commit id:"7-abcdefg"
commit id:"8-abcdefg"
`,
{ gitGraph: { parallelCommits: true } }
);
});
it('43: should render GitGraph with parallel commits | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id:"1-abcdefg"
commit id:"2-abcdefg"
branch develop
commit id:"3-abcdefg"
commit id:"4-abcdefg"
checkout main
branch feature
commit id:"5-abcdefg"
commit id:"6-abcdefg"
checkout main
commit id:"7-abcdefg"
commit id:"8-abcdefg"
`,
{ gitGraph: { parallelCommits: true } }
);
});
it('44: should render GitGraph with unconnected branches and no parallel commits', () => {
imgSnapshotTest(
`gitGraph
branch dev
branch v2
branch feat
commit id:"1-abcdefg"
commit id:"2-abcdefg"
checkout main
commit id:"3-abcdefg"
checkout dev
commit id:"4-abcdefg"
checkout v2
commit id:"5-abcdefg"
checkout main
commit id:"6-abcdefg"
`,
{ gitGraph: { parallelCommits: false } }
);
});
it('45: should render GitGraph with unconnected branches and parallel commits', () => {
imgSnapshotTest(
`gitGraph
branch dev
branch v2
branch feat
commit id:"1-abcdefg"
commit id:"2-abcdefg"
checkout main
commit id:"3-abcdefg"
checkout dev
commit id:"4-abcdefg"
checkout v2
commit id:"5-abcdefg"
checkout main
commit id:"6-abcdefg"
`,
{ gitGraph: { parallelCommits: true } }
);
});
it('46: should render GitGraph with unconnected branches and parallel commits | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
branch dev
branch v2
branch feat
commit id:"1-abcdefg"
commit id:"2-abcdefg"
checkout main
commit id:"3-abcdefg"
checkout dev
commit id:"4-abcdefg"
checkout v2
commit id:"5-abcdefg"
checkout main
commit id:"6-abcdefg"
`,
{ gitGraph: { parallelCommits: true } }
);
});
}); });

View File

@@ -375,6 +375,26 @@ context('Sequence diagram', () => {
{} {}
); );
}); });
it('should have actor-top and actor-bottom classes on top and bottom actor box and symbol', () => {
imgSnapshotTest(
`
sequenceDiagram
actor Bob
Alice->>Bob: Hi Bob
Bob->>Alice: Hi Alice
`,
{}
);
cy.get('.actor').should('have.class', 'actor-top');
cy.get('.actor-man').should('have.class', 'actor-top');
cy.get('.actor.actor-top').should('not.have.class', 'actor-bottom');
cy.get('.actor-man.actor-top').should('not.have.class', 'actor-bottom');
cy.get('.actor').should('have.class', 'actor-bottom');
cy.get('.actor-man').should('have.class', 'actor-bottom');
cy.get('.actor.actor-bottom').should('not.have.class', 'actor-top');
cy.get('.actor-man.actor-bottom').should('not.have.class', 'actor-top');
});
it('should render long notes left of actor', () => { it('should render long notes left of actor', () => {
imgSnapshotTest( imgSnapshotTest(
` `
@@ -792,6 +812,34 @@ context('Sequence diagram', () => {
}); });
}); });
context('links', () => { context('links', () => {
it('should support actor links', () => {
renderGraph(
`
sequenceDiagram
link Alice: Dashboard @ https://dashboard.contoso.com/alice
link Alice: Wiki @ https://wiki.contoso.com/alice
link John: Dashboard @ https://dashboard.contoso.com/john
link John: Wiki @ https://wiki.contoso.com/john
Alice->>John: Hello John<br/>
John-->>Alice: Great<br/><br/>day!
`,
{ securityLevel: 'loose' }
);
cy.get('#actor0_popup').should((popupMenu) => {
const style = popupMenu.attr('style');
expect(style).to.undefined;
});
cy.get('#root-0').click();
cy.get('#actor0_popup').should((popupMenu) => {
const style = popupMenu.attr('style');
expect(style).to.match(/^display: block;$/);
});
cy.get('#root-0').click();
cy.get('#actor0_popup').should((popupMenu) => {
const style = popupMenu.attr('style');
expect(style).to.match(/^display: none;$/);
});
});
it('should support actor links and properties EXPERIMENTAL: USE WITH CAUTION', () => { it('should support actor links and properties EXPERIMENTAL: USE WITH CAUTION', () => {
//Be aware that the syntax for "properties" is likely to be changed. //Be aware that the syntax for "properties" is likely to be changed.
imgSnapshotTest( imgSnapshotTest(

View File

@@ -17,24 +17,30 @@
<style> <style>
body { body {
/* background: rgb(221, 208, 208); */ /* background: rgb(221, 208, 208); */
/* background:#333; */ background: #333;
font-family: 'Arial'; font-family: 'Arial';
/* font-size: 18px !important; */ /* font-size: 18px !important; */
} }
h1 { h1 {
color: grey; color: grey;
} }
.mermaid {
border: 1px solid #ddd;
margin: 10px;
}
.mermaid2 { .mermaid2 {
display: none; display: none;
} }
.mermaid svg { .mermaid svg {
/* font-size: 18px !important; */ /* font-size: 18px !important; */
background-color: #efefef; /* background-color: #efefef; */
background-image: radial-gradient(#fff 51%, transparent 91%), background-color: #333;
radial-gradient(#fff 51%, transparent 91%); background-image: radial-gradient(#333 51%, transparent 91%),
radial-gradient(#333 51%, transparent 91%);
background-size: 20px 20px; background-size: 20px 20px;
background-position: 0 0, 10px 10px; background-position: 0 0, 10px 10px;
background-repeat: repeat; background-repeat: repeat;
border: 2px solid rgb(131, 142, 205);
} }
.malware { .malware {
position: fixed; position: fixed;
@@ -58,46 +64,192 @@
</head> </head>
<body> <body>
<pre id="diagram" class="mermaid"> <pre id="diagram" class="mermaid">
flowchart TB block-beta
C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z & A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8 blockArrowId<["Label"]>(right)
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------> blockArrowId2<["Label"]>(left)
C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z & A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8 blockArrowId3<["Label"]>(up)
blockArrowId4<["Label"]>(down)
blockArrowId5<["Label"]>(x)
blockArrowId6<["Label"]>(y)
blockArrowId6<["Label"]>(x, down)
</pre>
<pre id="diagram" class="mermaid">
block-beta
block:e:4
columns 2
f
g
end
</pre>
<pre id="diagram" class="mermaid">
block-beta
block:e:4
columns 2
f
g
h
end
</pre>
<pre id="diagram" class="mermaid">
block-beta
columns 4
a b c d
block:e:4
columns 2
f
g
h
end
i:4
</pre> </pre>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
flowchart TB flowchart LR
A & A & A & A & A & A & A & A ---> C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z X-- "y" -->z
</pre> </pre>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
flowchart TB block-beta
A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8 --> C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z columns 5
A space B
A --x B
</pre> </pre>
<pre id="diagram" class="mermaid2">
block-beta
columns 3
a["A wide one"] b:2 c:2 d
</pre>
<pre id="diagram" class="mermaid2">
block-beta
block:e
f
end
</pre>
<pre id="diagram" class="mermaid2">
block-beta
columns 3
a:3
block:e:3
f
end
g
</pre>
<pre id="diagram" class="mermaid2">
block-beta
columns 3
a:3
block:e:3
f
g
end
h
i
j
</pre>
<pre id="diagram" class="mermaid2">
block-beta
columns 3
a b:2
block:e:3
f
end
g h i
</pre>
<pre id="diagram" class="mermaid">
block-beta
columns 3
a b c
e:3
f g h
</pre>
<pre id="diagram" class="mermaid">
block-beta
columns 1
db(("DB"))
blockArrowId6<["&nbsp;&nbsp;&nbsp;"]>(down)
block:ID
A
B["A wide one in the middle"]
C
end
space
D
ID --> D
C --> D
style B fill:#f9F,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram" class="mermaid">
block-beta
columns 5
A1:3
A2:1
A3
B1 B2 B3:3
</pre>
<pre id="diagram" class="mermaid2">
block-beta
block
D
E
end
db("This is the text in the box")
</pre>
<pre id="diagram" class="mermaid2">
block-beta
block
D
end
A["A: I am a wide one"]
</pre>
<pre id="diagram" class="mermaid2">
block-beta
A["square"]
B("rounded")
C(("circle"))
</pre>
<pre id="diagram" class="mermaid2">
block-beta
A>"rect_left_inv_arrow"]
B{"diamond"}
C{{"hexagon"}}
</pre>
<pre id="diagram" class="mermaid2">
block-beta
A(["stadium"])
</pre>
<pre id="diagram" class="mermaid2">
block-beta
%% A[["subroutine"]]
%% B[("cylinder")]
C>"surprise"]
</pre>
<pre id="diagram" class="mermaid2">
block-beta
A[/"lean right"/]
B[\"lean left"\]
C[/"trapezoid"\]
D[\"trapezoid"/]
</pre>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
flowchart flowchart
Node1:::class1 --> Node2:::class2 B
Node1:::class1 --> Node3:::class2 style B fill:#f9F,stroke:#333,stroke-width:4px
Node3 --> Node4((I am a circle)):::larger </pre>
classDef class1 fill:lightblue
classDef class2 fill:pink
classDef larger font-size:30px,fill:yellow
</pre
>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
stateDiagram-v2 flowchart LR
[*] --> Still a1 -- apa --> b1
Still --> [*] </pre>
Still --> Moving
Moving --> Still
Moving --> Crash
Crash --> [*] </pre
>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
flowchart RL flowchart RL
subgraph "`one`" subgraph "`one`"
a1 -- l1 --> a2 id
a1 -- l2 --> a2 end
end
</pre> </pre>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
flowchart RL flowchart RL
@@ -442,14 +594,8 @@ mindmap
// useMaxWidth: false, // useMaxWidth: false,
// }); // });
mermaid.initialize({ mermaid.initialize({
flowchart: { titleTopMargin: 10 }, theme: 'dark',
fontFamily: 'courier', startOnLoad: true,
sequence: {
actorFontFamily: 'courier',
noteFontFamily: 'courier',
messageFontFamily: 'courier',
},
fontSize: 16,
logLevel: 0, logLevel: 0,
}); });
function callback() { function callback() {

View File

@@ -24,8 +24,18 @@
// -- This is will overwrite an existing command -- // -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
// import '@percy/cypress';
import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command'; import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command';
// The SSIM comparison method can be used if the pixelmatch is throwing lots of false positives.
// SSIM actually does not catch minute changes in the image, so it is not as accurate as pixelmatch.
// addMatchImageSnapshotCommand({
// comparisonMethod: 'ssim',
// failureThreshold: 0.01,
// failureThresholdType: 'percent',
// customDiffConfig: {
// ssim: 'fast',
// },
// blur: 1,
// });
addMatchImageSnapshotCommand(); addMatchImageSnapshotCommand();

139
demos/block.html Normal file
View File

@@ -0,0 +1,139 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Mermaid Block diagram demo page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
</head>
<body>
<h1>Block diagram demos</h1>
<pre id="diagram" class="mermaid">
block-beta
columns 1
db(("DB"))
blockArrowId6<["&nbsp;&nbsp;&nbsp;"]>(down)
block:ID
A
B["A wide one in the middle"]
C
end
space
D
ID --> D
C --> D
style B fill:#f9F,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram" class="mermaid">
block-beta
A1["square"]
B1("rounded")
C1(("circle"))
A2>"rect_left_inv_arrow"]
B2{"diamond"}
C2{{"hexagon"}}
</pre>
<pre id="diagram" class="mermaid">
block-beta
A1(["stadium"])
A2[["subroutine"]]
B1[("cylinder")]
C1>"surprise"]
A3[/"lean right"/]
B2[\"lean left"\]
C2[/"trapezoid"\]
D2[\"trapezoid"/]
</pre>
<pre id="diagram" class="mermaid">
block-beta
block:e:4
columns 2
f
g
end
</pre>
<pre id="diagram" class="mermaid">
block-beta
block:e:4
columns 2
f
g
h
end
</pre>
<pre id="diagram" class="mermaid">
block-beta
columns 3
a:3
block:e:3
f
g
end
h
i
j
</pre>
<pre id="diagram" class="mermaid">
block-beta
columns 4
a b c d
block:e:4
columns 2
f
g
h
end
i:4
</pre>
<pre id="diagram" class="mermaid">
flowchart LR
X-- "a label" -->z
</pre>
<pre id="diagram" class="mermaid">
block-beta
columns 5
A space B
A --x B
</pre>
<pre id="diagram" class="mermaid">
block-beta
columns 3
a["A wide one"] b:2 c:2 d
</pre>
<pre id="diagram" class="mermaid">
block-beta
columns 3
a b c
e:3
f g h
</pre>
<pre id="diagram" class="mermaid">
block-beta
A1:3
A2:1
A3
</pre>
<script type="module">
import mermaid from './mermaid.esm.mjs';
mermaid.initialize({
theme: 'default',
logLevel: 3,
securityLevel: 'loose',
block: {
padding: 10,
},
});
</script>
</body>
</html>

View File

@@ -30,6 +30,21 @@
</pre> </pre>
<hr /> <hr />
<pre class="mermaid">
gantt
title #; Gantt Diagrams Allow Semicolons and Hashtags #;!
accTitle: A simple sample gantt diagram
accDescr: 2 sections with 2 tasks each, from 2014
dateFormat YYYY-MM-DD
section #;Section
#;A task :a1, 2014-01-01, 30d
#;Another task :after a1 , 20d
section #;Another
Task in sec :2014-01-12 , 12d
another task : 24d
</pre>
<hr />
<pre class="mermaid"> <pre class="mermaid">
gantt gantt
title Airworks roadmap title Airworks roadmap

View File

@@ -81,6 +81,9 @@
<li> <li>
<h2><a href="./sankey.html">Sankey</a></h2> <h2><a href="./sankey.html">Sankey</a></h2>
</li> </li>
<li>
<h2><a href="./block.html">Layered Blocks</a></h2>
</li>
</ul> </ul>
</body> </body>
</html> </html>

View File

@@ -15,7 +15,7 @@
<body> <body>
<h1>Pie chart demos</h1> <h1>Pie chart demos</h1>
<pre class="mermaid"> <pre class="mermaid">
pie title Pets adopted by volunteers pie title Default text position: Animal adoption
accTitle: simple pie char demo accTitle: simple pie char demo
accDescr: pie chart with 3 sections: dogs, cats, rats. Most are dogs. accDescr: pie chart with 3 sections: dogs, cats, rats. Most are dogs.
"Dogs": 386 "Dogs": 386
@@ -27,7 +27,7 @@
<pre class="mermaid"> <pre class="mermaid">
%%{init: {"pie": {"textPosition": 0.9}, "themeVariables": {"pieOuterStrokeWidth": "5px"}}}%% %%{init: {"pie": {"textPosition": 0.9}, "themeVariables": {"pieOuterStrokeWidth": "5px"}}}%%
pie pie
title Key elements in Product X title Offset labels close to border: Product X
accTitle: Key elements in Product X accTitle: Key elements in Product X
accDescr: This is a pie chart showing the key elements in Product X. accDescr: This is a pie chart showing the key elements in Product X.
"Calcium": 42.96 "Calcium": 42.96
@@ -36,6 +36,19 @@
"Iron": 5 "Iron": 5
</pre> </pre>
<pre class="mermaid">
%%{init: {"pie": {"textPosition": 0.45}, "themeVariables": {"pieOuterStrokeWidth": "5px"}}}%%
pie
title Centralized labels: Languages
accTitle: Key elements in Product X
accDescr: This is a pie chart showing the key elements in Product X.
"JavaScript": 30
"Python": 25
"Java": 20
"C#": 15
"Others": 10
</pre>
<script type="module"> <script type="module">
import mermaid from './mermaid.esm.mjs'; import mermaid from './mermaid.esm.mjs';
mermaid.initialize({ mermaid.initialize({

View File

@@ -23,6 +23,10 @@
participant Alice participant Alice
participant Bob participant Bob
participant John as John<br />Second Line participant John as John<br />Second Line
link Alice: Dashboard @ https://dashboard.contoso.com/alice
link Alice: Wiki @ https://wiki.contoso.com/alice
link John: Dashboard @ https://dashboard.contoso.com/john
link John: Wiki @ https://wiki.contoso.com/john
autonumber 10 10 autonumber 10 10
rect rgb(200, 220, 100) rect rgb(200, 220, 100)
rect rgb(200, 255, 200) rect rgb(200, 255, 200)
@@ -62,6 +66,26 @@
</pre> </pre>
<hr /> <hr />
<pre class="mermaid"> <pre class="mermaid">
---
title: With forced menus
config:
sequence:
forceMenus: true
---
sequenceDiagram
participant Alice
participant John
link Alice: Dashboard @ https://dashboard.contoso.com/alice
link Alice: Wiki @ https://wiki.contoso.com/alice
link John: Dashboard @ https://dashboard.contoso.com/john
link John: Wiki @ https://wiki.contoso.com/john
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
</pre
>
<hr />
<pre class="mermaid">
sequenceDiagram sequenceDiagram
accTitle: Sequence diagram title is here accTitle: Sequence diagram title is here
accDescr: Hello friends accDescr: Hello friends

View File

@@ -1,13 +1,16 @@
version: '3.9' version: '3.9'
services: services:
mermaid: mermaid:
image: node:18.19.0-alpine3.18 build:
context: .
dockerfile: Dockerfile
stdin_open: true stdin_open: true
tty: true tty: true
working_dir: /mermaid working_dir: /mermaid
mem_limit: '4G' mem_limit: '8G'
entrypoint: '/mermaid/docker-entrypoint.sh'
environment: environment:
- NODE_OPTIONS=--max_old_space_size=4096 - NODE_OPTIONS=--max_old_space_size=8192
volumes: volumes:
- ./:/mermaid - ./:/mermaid
- root_cache:/root/.cache - root_cache:/root/.cache

3
docker-entrypoint.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
source /root/.shrc
exec "$@"

View File

@@ -1,176 +0,0 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/community/code.md](../../packages/mermaid/src/docs/community/code.md).
# Contributing Code
The basic steps for contributing code are:
```mermaid-example
graph LR
git[1. Checkout a git branch] --> codeTest[2. Write tests and code] --> doc[3. Update documentation] --> submit[4. Submit a PR] --> review[5. Review and merge]
```
```mermaid
graph LR
git[1. Checkout a git branch] --> codeTest[2. Write tests and code] --> doc[3. Update documentation] --> submit[4. Submit a PR] --> review[5. Review and merge]
```
1. **Create** and checkout a git branch and work on your code in the branch
2. Write and update **tests** (unit and perhaps even integration (e2e) tests) (If you do TDD/BDD, the order might be different.)
3. **Let users know** that things have changed or been added in the documents! This is often overlooked, but _critical_
4. **Submit** your code as a _pull request_.
5. Maintainers will **review** your code. If there are no changes necessary, the PR will be merged. Otherwise, make the requested changes and repeat.
## 1. Checkout a git branch
Mermaid uses a [Git Flow](https://guides.github.com/introduction/flow/)inspired approach to branching.
Development is done in the `develop` branch.
Once development is done we create a `release/vX.X.X` branch from `develop` for testing.
Once the release happens we add a tag to the `release` branch and merge it with `master`. The live product and on-line documentation are what is in the `master` branch.
**All new work should be based on the `develop` branch.**
**When you are ready to do work, always, ALWAYS:**
1. Make sure you have the most up-to-date version of the `develop` branch. (fetch or pull to update it)
2. Check out the `develop` branch
3. Create a new branch for your work. Please name the branch following our naming convention below.
We use the following naming convention for branches:
```txt
[feature | bug | chore | docs]/[issue number]_[short description using dashes ('-') or underscores ('_') instead of spaces]
```
You can always check current [configuration of labelling and branch prefixes](https://github.com/mermaid-js/mermaid/blob/develop/.github/pr-labeler.yml)
- The first part is the **type** of change: a feature, bug, chore, or documentation change ('docs')
- followed by a _slash_ (which helps to group like types together in many git tools)
- followed by the **issue number**
- followed by an _underscore_ ('\_')
- followed by a short text description (but use dashes ('-') or underscores ('\_') instead of spaces)
If your work is specific to a single diagram type, it is a good idea to put the diagram type at the start of the description. This will help us keep release notes organized: it will help us keep changes for a diagram type together.
**Ex: A new feature described in issue 2945 that adds a new arrow type called 'florbs' to state diagrams**
`feature/2945_state-diagram-new-arrow-florbs`
**Ex: A bug described in issue 1123 that causes random ugly red text in multiple diagram types**
`bug/1123_fix_random_ugly_red_text`
## 2. Write Tests
Tests ensure that each function, module, or part of code does what it says it will do. This is critically
important when other changes are made to ensure that existing code is not broken (no regression).
Just as important, the tests act as _specifications:_ they specify what the code does (or should do).
Whenever someone is new to a section of code, they should be able to read the tests to get a thorough understanding of what it does and why.
If you are fixing a bug, you should add tests to ensure that your code has actually fixed the bug, to specify/describe what the code is doing, and to ensure the bug doesn't happen again.
(If there had been a test for the situation, the bug never would have happened in the first place.)
You may need to change existing tests if they were inaccurate.
If you are adding a feature, you will definitely need to add tests. Depending on the size of your feature, you may need to add integration tests.
### Unit Tests
Unit tests are tests that test a single function or module. They are the easiest to write and the fastest to run.
Unit tests are mandatory all code except the renderers. (The renderers are tested with integration tests.)
We use [Vitest](https://vitest.dev) to run unit tests.
You can use the following command to run the unit tests:
```sh
pnpm test
```
When writing new tests, it's easier to have the tests automatically run as you make changes. You can do this by running the following command:
```sh
pnpm test:watch
```
### Integration/End-to-End (e2e) tests
These test the rendering and visual appearance of the diagrams.
This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks!
To start working with the e2e tests:
1. Run `pnpm dev` to start the dev server
2. Start **Cypress** by running `pnpm cypress:open`.
The rendering tests are very straightforward to create. There is a function `imgSnapshotTest`, which takes a diagram in text form and the mermaid options, and it renders that diagram in Cypress.
When running in CI it will take a snapshot of the rendered diagram and compare it with the snapshot from last build and flag it for review if it differs.
This is what a rendering test looks like:
```js
it('should render forks and joins', () => {
imgSnapshotTest(
`
stateDiagram
state fork_state &lt;&lt;fork&gt;&gt;
[*] --> fork_state
fork_state --> State2
fork_state --> State3
state join_state &lt;&lt;join&gt;&gt;
State2 --> join_state
State3 --> join_state
join_state --> State4
State4 --> [*]
`,
{ logLevel: 0 }
);
cy.get('svg');
});
```
**_\[TODO - running the tests against what is expected in development. ]_**
**_\[TODO - how to generate new screenshots]_**
....
## 3. Update Documentation
If the users have no way to know that things have changed, then you haven't really _fixed_ anything for the users; you've just added to making Mermaid feel broken.
Likewise, if users don't know that there is a new feature that you've implemented, it will forever remain unknown and unused.
The documentation has to be updated to users know that things have changed and added!
If you are adding a new feature, add `(v<MERMAID_RELEASE_VERSION>+)` in the title or description. It will be replaced automatically with the current version number when the release happens.
eg: `# Feature Name (v<MERMAID_RELEASE_VERSION>+)`
We know it can sometimes be hard to code _and_ write user documentation.
Our documentation is managed in `packages/mermaid/src/docs`. Details on how to edit is in the [Contributing Documentation](#contributing-documentation) section.
Create another issue specifically for the documentation.\
You will need to help with the PR, but definitely ask for help if you feel stuck.
When it feels hard to write stuff out, explaining it to someone and having that person ask you clarifying questions can often be 80% of the work!
When in doubt, write up and submit what you can. It can be clarified and refined later. (With documentation, something is better than nothing!)
## 4. Submit your pull request
**\[TODO - PR titles should start with (fix | feat | ....)]**
We make all changes via Pull Requests (PRs). As we have many Pull Requests from developers new to Mermaid, we have put in place a process wherein _knsv, Knut Sveidqvist_ is in charge of the final release process and the active maintainers are in charge of reviewing and merging most PRs.
- PRs will be reviewed by active maintainers, who will provide feedback and request changes as needed.
- The maintainers will request a review from knsv, if necessary.
- Once the PR is approved, the maintainers will merge the PR into the `develop` branch.
- When a release is ready, the `release/x.x.x` branch will be created, extensively tested and knsv will be in charge of the release process.
**Reminder: Pull Requests should be submitted to the develop branch.**

View File

@@ -0,0 +1,521 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/community/contributing.md](../../packages/mermaid/src/docs/community/contributing.md).
# Mermaid Contributing Guide
You decided to take part in the development? Welcome!
We are trying to make our guidelines for you as explicit and detailed as possible.
## Initial Setup
Initial setup consists of 3 main steps:
```mermaid
flowchart LR
source --> requirements --> setup
source[Get the Source Code]
requirements[Install the Requirements]
setup[Install Packages]
```
### Get the Source Code
In GitHub, you first [**fork a mermaid repository**](https://github.com/mermaid-js/mermaid/fork) when you are going to make changes and submit pull requests.
Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with.
> **💡 Tip** > [Here is a GitHub document that gives an overview of the process](https://docs.github.com/en/get-started/quickstart/fork-a-repo).
```bash
git clone git@github.com/your-fork/mermaid
```
Once you have cloned the repository onto your development machine, change into the `mermaid` project folder (the top level directory of the mermaid project repository)
```bash
cd mermaid
```
### Install Requirements
We support **development within Docker** environment along with **host setup**. You may choose it up to your preferences.
**Host**
These are the tools we use for working with the code and documentation:
- [Node.js](https://nodejs.org/en/).
- [pnpm](https://pnpm.io/) package manager.
The following commands must be sufficient enough to start with:
```bash
curl -fsSL https://get.pnpm.io/install.sh | sh -
pnpm env use --global 18
```
You may also need to reload `.shrc` or `.bashrc` afterwards.
**Docker**
[Install Docker](https://docs.docker.com/engine/install/). And that is pretty much all you need.
Optionally, to run GUI (Cypress) within Docker you will also need an X11 server installed.
You might already have it installed, so check this by running:
```bash
echo $DISPLAY
```
If the `$DISPLAY` variable is not empty, then an X11 server is running. Otherwise you may need to install one.
### Install Packages
**Host**
Install packages:
```bash
pnpm install
```
**Docker**
For development using Docker there is a self-documented `run` bash script, which provides convenient aliases for `docker compose` commands.
Make sure that `./run` script is executable:
```bash
chmod +x run
```
> **💡 Tip**
> To get detailed help simply type `./run` or `./run help`.
>
> It also has short _Development quick start guide_ embedded.
Then install packages:
```bash
./run pnpm install
```
### Verify Everything Works
This step is optional, but it helps to make sure that everything in development branch was OK before you started making any changes.
You can run the `test` script to verify that pnpm is working _and_ that the repository has been cloned correctly:
**Host**
```bash
pnpm test
```
**Docker**
```bash
./run pnpm test
```
The `test` script and others are in the top-level `package.json` file.
All tests should run successfully without any errors or failures.
> **Note**
> You might see _lint_ or _formatting_ warnings. Those are ok during this step.
## Workflow
Contributing process is very simple and strightforward:
```mermaid
flowchart LR
branch --> changes --> submit
branch[Checkout a New Branch]
changes[Make Changes]
submit[Submit a PR]
```
Mermaid uses a [Git Flow](https://guides.github.com/introduction/flow/)inspired approach to branching.
Development is done in the `develop` branch.
```mermaid
---
config:
gitGraph:
mainBranchName: develop
---
gitGraph LR:
commit
commit
branch "docs/2910_update-guidelines" order: 1
commit
commit
commit
checkout develop
merge "docs/2910_update-guidelines"
commit
```
To prepare a new version for release the maintainers create a `release/vX.X.X` branch from `develop` for testing. Once the release happens we add a tag to the `release` branch and merge it with `master`. The live product and on-line documentation are what is in the `master` branch.
## Checkout a New Branch
> **💡 Tip**
> All new work should be based on the `develop` branch.
Make sure you have the most up-to-date version of the `develop` branch.
Check out the `develop` branch, then `fetch` or `pull` to update it:
```bash
git checkout develop
git fetch # or `git pull`
```
Create a new branch for your work:
```bash
git checkout -b docs/2910_update-contributing-guidelines
```
We use the following naming convention for branches:
```txt
[feature | bug | chore | docs]/[issue number]_[short-description]
```
You can always check current [configuration of labelling and branch prefixes](https://github.com/mermaid-js/mermaid/blob/develop/.github/pr-labeler.yml)
- The first part is the **type** of change: a `feature`, `bug`, `chore`, `docs`
- followed by a **slash** (`/`),which helps to group like types together in many git tools
- followed by the **issue number**, e.g. `2910`
- followed by an **underscore** (`_`)
- followed by a **short description** with dashes (`-`) or underscores (`_`) instead of spaces
```mermaid
flowchart LR
feature --> slash
bug --> slash
chore --> slash
docs --> slash
slash --> 2945 --> underscore
slash --> 1123 --> underscore
underscore --> short_description_1
underscore --> short_description_2
underscore["_"]
slash["/"]
short_description_1["state-diagram-new-arrow-florbs"]
short_description_2["fix_random_ugly_red_text"]
```
If your work is specific to a single diagram type, it is a good idea to put the diagram type at the start of the description. This will help us keep release notes organized by a diagram type.
> **Note**
> A new feature described in issue 2945 that adds a new arrow type called 'florbs' to state diagrams
>
> `feature/2945_state-diagram-new-arrow-florbs`
> **💡 Tip**
> A bug described in issue 1123 that causes random ugly red text in multiple diagram types
>
> `bug/1123_fix_random_ugly_red_text`
## Contributing Code
Code is the heart of every software project. We strive to make it better. Who if not us?
### Where is the Code Located?
The core of Mermaid is located under `packages/mermaid/src`.
### Running Mermaid Locally
**Host**
```bash
pnpm run dev
```
**Docker**
```bash
./run dev
```
After starting the dev server open <http://localhost:9000> in your browser.
Now you are ready to make your changes!
### Make Changes
Have a look at <http://localhost:9000>. There is a list of demos that can be used to see and test your changes.
If you need a specific diagram, you can duplicate the `example.html` file in `/demos/dev` and add your own mermaid code to your copy.
That will be served at <http://localhost:9000/dev/your-file-name.html>.
After making code changes, the dev server will rebuild the mermaid library and automatically reload the page.
Edit files in `packages/mermaid/src` as required.
### Write Tests
Tests ensure that each function, module, or part of code does what it says it will do. This is critically important when other changes are made to ensure that existing code is not broken (no regression).
Just as important, the tests act as _specifications:_ they specify what the code does (or should do).
Whenever someone is new to a section of code, they should be able to read the tests to get a thorough understanding of what it does and why.
If you are fixing a bug, you should add tests to ensure that your code has actually fixed the bug, to specify/describe what the code is doing, and to ensure the bug doesn't happen again.
(If there had been a test for the situation, the bug never would have happened in the first place.)
You may need to change existing tests if they were inaccurate.
If you are adding a feature, you will definitely need to add tests. Depending on the size of your feature, you may need to add integration tests.
#### Unit Tests
Unit tests are tests that test a single function or module. They are the easiest to write and the fastest to run.
Unit tests are mandatory for all code except the renderers. (The renderers are tested with integration tests.)
We use [Vitest](https://vitest.dev) to run unit tests.
**Host**
You can use the following command to run the unit tests:
```sh
pnpm test
```
When writing new tests, it's easier to have the tests automatically run as you make changes. You can do this by running the following command:
```sh
pnpm test:watch
```
**Docker**
When using Docker prepend your command with `./run`:
```sh
./run pnpm test
```
#### Integration / End-to-End (E2E) Tests
These test the rendering and visual appearance of the diagrams.
This ensures that the rendering of that feature in the E2E will be reviewed in the release process going forward. Less chance that it breaks!
To start working with the E2E tests:
**Host**
- Run `pnpm dev` to start the dev server
- Start **Cypress** by running `pnpm cypress:open`
**Docker**
- Enable local connections for x11 server `xhost +local:`
- Run `./run pnpm dev` to start the dev server
- Start **Cypress** by running `./run pnpm cypress:open --project .`
The rendering tests are very straightforward to create. There is a function `imgSnapshotTest`, which takes a diagram in text form and the mermaid options, and it renders that diagram in Cypress.
When running in CI it will take a snapshot of the rendered diagram and compare it with the snapshot from last build and flag it for review if it differs.
This is what a rendering test looks like:
```js
it('should render forks and joins', () => {
imgSnapshotTest(
`
stateDiagram
state fork_state &lt;&lt;fork&gt;&gt;
[*] --> fork_state
fork_state --> State2
fork_state --> State3
state join_state &lt;&lt;join&gt;&gt;
State2 --> join_state
State3 --> join_state
join_state --> State4
State4 --> [*]
`,
{ logLevel: 0 }
);
});
```
<!-- **_[TODO - running the tests against what is expected in development. ]_** -->
<!-- **_[TODO - how to generate new screenshots]_** -->
### Update Documentation
> **💡 Tip**
> Our documentation is managed in `packages/mermaid/src/docs`. Details on how to edit is in the [documentation section](#contributing-documentation)
If the users have no way to know that things have changed, then you haven't really _fixed_ anything for the users; you've just added to making Mermaid feel broken.
Likewise, if users don't know that there is a new feature that you've implemented, it will forever remain unknown and unused.
The documentation has to be updated for users to know that things have been changed and added!
If you are adding a new feature, add `(v10.8.0+)` in the title or description. It will be replaced automatically with the current version number when the release happens.
eg: `# Feature Name (v10.8.0+)`
We know it can sometimes be hard to code _and_ write user documentation.
Create another issue specifically for the documentation.\
You will need to help with the PR, but definitely ask for help if you feel stuck.
When it feels hard to write stuff out, explaining it to someone and having that person ask you clarifying questions can often be 80% of the work!
When in doubt, write up and submit what you can. It can be clarified and refined later. (With documentation, something is better than nothing!)
## Contributing Documentation
If it is not in the documentation, it's like it never happened. Wouldn't that be sad? With all the effort that was put into the feature?
### Where is the Documentation Located?
> **Warning**
> DO NOT CHANGE FILES IN `/docs`
>
> The `docs` folder will be automatically generated when committing to `packages/mermaid/src/docs` and **should not** be edited manually.
Documentation is located in the [`packages/mermaid/src/docs`](https://github.com/mermaid-js/mermaid/tree/develop/packages/mermaid/src/docs) folder. Just pick the right section and start typing.
The contents of [mermaid.js.org](https://mermaid.js.org/) are based on the docs from the `master` branch. Updates committed to the `master` branch are reflected in the [Mermaid Docs](https://mermaid.js.org/) once published.
```mermaid-example
flowchart LR
classDef default fill:#fff,color:black,stroke:black
source["Edit /packages/mermaid/src/docs"] -- automatic processing--> published["View /docs which will be publised on Official Website"]
```
```mermaid
flowchart LR
classDef default fill:#fff,color:black,stroke:black
source["Edit /packages/mermaid/src/docs"] -- automatic processing--> published["View /docs which will be publised on Official Website"]
```
### Running the Documentation Website Locally
**[The mermaid documentation site](https://mermaid.js.org/) is powered by [Vitepress](https://vitepress.vuejs.org/).**
Start development server for the documentation site
**Host**
```bash
pnpm --filter mermaid run docs:dev
```
or
```bash
cd packages/mermaid
pnpm docs:dev
```
**Docker**
```bash
./run docs:dev
```
Open <http://localhost:3333/> in your browser.
### Formatting
The documentation is written in Markdown. To get acquainted with its syntax [see the GitHub Markdown help page](https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax).
You can use `note`, `tip`, `warning` and `danger` in triple backticks to add a note, tip, warning or danger box.
> **‼️ Danger**
> Do not use vitepress specific markdown syntax `::: warning` as it will not be processed correctly.
Here are a few examples:
````markdown
```note
This is a note
```
```tip
This is a tip
```
```warning
This is a warning
```
```danger
This is a danger alert
```
````
> **Note**
> This is a note
> **💡 Tip**
> This is a tip
> **Warning**
> This is a warning
> **‼️ Danger**
> This is a danger alert
### Navigation
If you want to propose changes to how the documentation is _organized_, such as adding a new section or re-arranging or renaming a section, you must update the **sidebar navigation**, which is defined in [the vitepress config](../.vitepress/config.ts). The same goes to **topbar**.
### Build Docs
The content of `/docs` folder is built with Github Actions.
> **Warning**
> So as to allow automatic compilation of documentation pages you have to enable Github Actions on your fork first
## Submit your pull request
> **Note**
> Do not forget to push your changes
>
> ```bash
> git push -u origin docs/2910_update-guidelines
> ```
We make all changes via Pull Requests (PRs). Open a new one.
Right now we are not following any strict rules about naming PRs. Give it a representative title and short description. There is also a [pull request template](https://github.com/mermaid-js/mermaid/blob/develop/.github/pull_request_template.md) which will help you with it.
In case in its description contains a [magic comment](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) your PR will be automatically attached to the issue:
```markdown
Resolves #<your issue ID here>
```
## Congratulations
You have successfully submitted your improvements! What is next?
- PRs will be reviewed by active maintainers, who will provide feedback and request changes as needed.
- The maintainers will request a review from _knsv_, if necessary.
- Once the PR is approved, the maintainers will merge the PR into the `develop` branch.
- When a release is ready, the `release/x.x.x` branch will be created, extensively tested and knsv will be in charge of the release process.
Thanks for you help!

View File

@@ -1,96 +0,0 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/community/development.md](../../packages/mermaid/src/docs/community/development.md).
# Contributing to Mermaid
> The following documentation describes how to work with Mermaid in your host environment.
> There's also a [Docker installation guide](../community/docker-development.md)
> if you prefer to work in a Docker environment.
So you want to help? That's great!
![Image of happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif)
Here are a few things to get you started on the right path.
## Get the Source Code
In GitHub, you first **fork** a repository when you are going to make changes and submit pull requests.
Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with.
[Fork mermaid](https://github.com/mermaid-js/mermaid/fork) to start contributing to the main project and its documentation, or [search for other repositories](https://github.com/orgs/mermaid-js/repositories).
[Here is a GitHub document that gives an overview of the process.](https://docs.github.com/en/get-started/quickstart/fork-a-repo)
## Technical Requirements
> The following documentation describes how to work with Mermaid in your host environment.
> There's also a [Docker installation guide](../community/docker-development.md)
> if you prefer to work in a Docker environment.
These are the tools we use for working with the code and documentation:
- [volta](https://volta.sh/) to manage node versions.
- [Node.js](https://nodejs.org/en/). `volta install node`
- [pnpm](https://pnpm.io/) package manager. `volta install pnpm`
- [npx](https://docs.npmjs.com/cli/v8/commands/npx) the packaged executor in npm. This is needed [to install pnpm.](#install-packages)
Follow the setup steps below to install them and start the development.
## Setup and Launch
### Switch to project
Once you have cloned the repository onto your development machine, change into the `mermaid` project folder (the top level directory of the mermaid project repository)
```bash
cd mermaid
```
### Install packages
Run `npx pnpm install`. You will need `npx` for this because volta doesn't support it yet.
```bash
npx pnpm install # npx is required for first install
```
### Launch
```bash
npx pnpm run dev
```
Now you are ready to make your changes! Edit whichever files in `src` as required.
Open <http://localhost:9000> in your browser, after starting the dev server.
There is a list of demos that can be used to see and test your changes.
If you need a specific diagram, you can duplicate the `example.html` file in `/demos/dev` and add your own mermaid code to your copy.
That will be served at <http://localhost:9000/dev/your-file-name.html>.
After making code changes, the dev server will rebuild the mermaid library. You will need to reload the browser page yourself to see the changes. (PRs for auto reload are welcome!)
## Verify Everything is Working
You can run the `test` script to verify that pnpm is working _and_ that the repository has been cloned correctly:
```bash
pnpm test
```
The `test` script and others are in the top-level `package.json` file.
All tests should run successfully without any errors or failures. (You might see _lint_ or _formatting_ warnings; those are ok during this step.)
## Last Words
Don't get daunted if it is hard in the beginning. We have a great community with only encouraging words. So, if you get stuck, ask for help and hints in the Slack forum. If you want to show off something good, show it off there.
[Join our Slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
![Image of superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)

View File

@@ -1,109 +0,0 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/community/docker-development.md](../../packages/mermaid/src/docs/community/docker-development.md).
# Contributing to Mermaid via Docker
> The following documentation describes how to work with Mermaid in a Docker environment.
> There's also a [host installation guide](../community/development.md)
> if you prefer to work without a Docker environment.
So you want to help? That's great!
![Image of happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif)
Here are a few things to get you started on the right path.
## Get the Source Code
In GitHub, you first **fork** a repository when you are going to make changes and submit pull requests.
Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with.
[Fork mermaid](https://github.com/mermaid-js/mermaid/fork) to start contributing to the main project and its documentation, or [search for other repositories](https://github.com/orgs/mermaid-js/repositories).
[Here is a GitHub document that gives an overview of the process.](https://docs.github.com/en/get-started/quickstart/fork-a-repo)
## Technical Requirements
> The following documentation describes how to work with Mermaid in a Docker environment.
> There's also a [host installation guide](../community/development.md)
> if you prefer to work without a Docker environment.
[Install Docker](https://docs.docker.com/engine/install/). And that is pretty much all you need.
Optionally, to run GUI (Cypress) within Docker you will also need an X11 server installed.
You might already have it installed, so check this by running:
```bash
echo $DISPLAY
```
If the `$DISPLAY` variable is not empty, then an X11 server is running. Otherwise you may need to install one.
## Setup and Launch
### Switch to project
Once you have cloned the repository onto your development machine, change into the `mermaid` project folder (the top level directory of the mermaid project repository)
```bash
cd mermaid
```
### Make `./run` executable
For development using Docker there is a self-documented `run` bash script, which provides convenient aliases for `docker compose` commands.
Ensure `./run` script is executable:
```bash
chmod +x run
```
> **💡 Tip**
> To get detailed help simply type `./run` or `./run help`.
>
> It also has short _Development quick start guide_ embedded.
### Install packages
```bash
./run pnpm install # Install packages
```
### Launch
```bash
./run dev
```
Now you are ready to make your changes! Edit whichever files in `src` as required.
Open <http://localhost:9000> in your browser, after starting the dev server.
There is a list of demos that can be used to see and test your changes.
If you need a specific diagram, you can duplicate the `example.html` file in `/demos/dev` and add your own mermaid code to your copy.
That will be served at <http://localhost:9000/dev/your-file-name.html>.
After making code changes, the dev server will rebuild the mermaid library. You will need to reload the browser page yourself to see the changes. (PRs for auto reload are welcome!)
## Verify Everything is Working
```bash
./run pnpm test
```
The `test` script and others are in the top-level `package.json` file.
All tests should run successfully without any errors or failures. (You might see _lint_ or _formatting_ warnings; those are ok during this step.)
## Last Words
Don't get daunted if it is hard in the beginning. We have a great community with only encouraging words. So, if you get stuck, ask for help and hints in the Slack forum. If you want to show off something good, show it off there.
[Join our Slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
![Image of superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)

View File

@@ -1,105 +0,0 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/community/documentation.md](../../packages/mermaid/src/docs/community/documentation.md).
# Contributing Documentation
**_\[TODO: This section is still a WIP. It still needs MAJOR revision.]_**
If it is not in the documentation, it's like it never happened. Wouldn't that be sad? With all the effort that was put into the feature?
The docs are located in the `packages/mermaid/src/docs` folder and are written in Markdown. Just pick the right section and start typing.
The contents of [mermaid.js.org](https://mermaid.js.org/) are based on the docs from the `master` branch.
Updates committed to the `master` branch are reflected in the [Mermaid Docs](https://mermaid.js.org/) once published.
## How to Contribute to Documentation
We are a little less strict here, it is OK to commit directly in the `develop` branch if you are a collaborator.
The documentation is located in the `packages/mermaid/src/docs` directory and organized according to relevant subfolder.
The `docs` folder will be automatically generated when committing to `packages/mermaid/src/docs` and **should not** be edited manually.
```mermaid-example
flowchart LR
classDef default fill:#fff,color:black,stroke:black
source["files in /packages/mermaid/src/docs\n(changes should be done here)"] -- automatic processing\nto generate the final documentation--> published["files in /docs\ndisplayed on the official documentation site"]
```
```mermaid
flowchart LR
classDef default fill:#fff,color:black,stroke:black
source["files in /packages/mermaid/src/docs\n(changes should be done here)"] -- automatic processing\nto generate the final documentation--> published["files in /docs\ndisplayed on the official documentation site"]
```
You can use `note`, `tip`, `warning` and `danger` in triple backticks to add a note, tip, warning or danger box.
Do not use vitepress specific markdown syntax `::: warning` as it will not be processed correctly.
````markdown
```note
Note content
```
```tip
Tip content
```
```warning
Warning content
```
```danger
Danger content
```
````
> **Note**
> If the change is _only_ to the documentation, you can get your changes published to the site quicker by making a PR to the `master` branch. In that case, your branch should be based on master, not develop.
We encourage contributions to the documentation at [packages/mermaid/src/docs in the _develop_ branch](https://github.com/mermaid-js/mermaid/tree/develop/packages/mermaid/src/docs).
**_DO NOT CHANGE FILES IN `/docs`_**
## The official documentation site
**[The mermaid documentation site](https://mermaid.js.org/) is powered by [Vitepress](https://vitepress.vuejs.org/).**
To run the documentation site locally:
1. Run `pnpm --filter mermaid run docs:dev` to start the dev server. (Or `pnpm docs:dev` inside the `packages/mermaid` directory.)
2. Open <http://localhost:3333/> in your browser.
Markdown is used to format the text, for more information about Markdown [see the GitHub Markdown help page](https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax).
To edit Docs on your computer:
_\[TODO: need to keep this in sync with [check out a git branch in Contributing Code above](#1-checkout-a-git-branch) ]_
1. Create a fork of the develop branch to work on.
2. Find the Markdown file (.md) to edit in the `packages/mermaid/src/docs` directory.
3. Make changes or add new documentation.
4. Commit changes to your branch and push it to GitHub (which should create a new branch).
5. Create a Pull Request from the branch of your fork.
To edit Docs on GitHub:
1. Login to [GitHub.com](https://www.github.com).
2. Navigate to [packages/mermaid/src/docs](https://github.com/mermaid-js/mermaid/tree/develop/packages/mermaid/src/docs) in the mermaid-js repository.
3. To edit a file, click the pencil icon at the top-right of the file contents panel.
4. Describe what you changed in the **Propose file change** section, located at the bottom of the page.
5. Submit your changes by clicking the button **Propose file change** at the bottom (by automatic creation of a fork and a new branch).
6. Visit the Actions tab in Github, `https://github.com/<Your Username>/mermaid/actions` and enable the actions for your fork. This will ensure that the documentation is built and updated in your fork.
7. Create a Pull Request of your newly forked branch by clicking the green **Create Pull Request** button.
## Documentation organization: Sidebar navigation
If you want to propose changes to how the documentation is _organized_, such as adding a new section or re-arranging or renaming a section, you must update the **sidebar navigation.**
The sidebar navigation is defined in [the vitepress configuration file config.ts](../.vitepress/config.ts).

60
docs/community/intro.md Normal file
View File

@@ -0,0 +1,60 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/community/intro.md](../../packages/mermaid/src/docs/community/intro.md).
# Getting Started
So you want to help? That's great!
![Image of happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif)
Here are a few things to get you started on the right path.
## How can I help?
```mermaid
mindmap
root)Contributing(
Development
Solving issues
Adding new diagrams
Handling pull requests
Updating tooling
Testing
Verification of fixed issues
Regression testing in connection with releases
Testing pull requests
Management
Coordinating the work
Classification and monitoring of incoming issues
```
## Join the Development
> **💡 Tip** > **Check out our** [**detailed contribution guide**](./contributing.md).
Where to start:
- You could start getting some knowledge of the code base by working on [these "good first issues"](https://github.com/mermaid-js/mermaid/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%21%22+).
- You could jump right in and help us fix any of [these bugs](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Bug+%2F+Error%22++label%3A%22Contributor+needed%22+)!
- You could help write and [improve the documentation](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Area%3A+Documentation%22).
- You could work on a new feature! [These](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Area%3A+Development%22+label%3A%22Type%3A+Enhancement%22+label%3A%22Status%3A+Approved%22+) are some ideas!
- You could confirm the bugs in [these issues](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Status%3A+Triage%22++label%3A%22Type%3A+Bug+%2F+Error%22).
[You can join our Discord server if you want closer contact!](https://discord.gg/AgrbSrBer3)
## A Question Or a Suggestion?
> **💡 Tip** > **Have a look at** [**how to open an issue**](./questions-and-suggestions.md).
If you have faced a vulnerability [report it to us](./security.md).
## Last Words
Don't get daunted if it is hard in the beginning. We have a great community with only encouraging words. So, if you get stuck, ask for help and hints in the Slack forum. If you want to show off something good, show it off there.
[You can join our Discord server if you want closer contact!](https://discord.gg/AgrbSrBer3)
![Image of superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)

View File

@@ -2,7 +2,7 @@
> >
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. > ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
> >
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/community/newDiagram.md](../../packages/mermaid/src/docs/community/newDiagram.md). > ## Please edit the corresponding file in [/packages/mermaid/src/docs/community/new-diagram.md](../../packages/mermaid/src/docs/community/new-diagram.md).
# Adding a New Diagram/Chart 📊 # Adding a New Diagram/Chart 📊

View File

@@ -6,20 +6,20 @@
# Questions or Suggestions? # Questions or Suggestions?
**_\[TODO: This section is still a WIP. It still needs MAJOR revision.]_** ## Search for Existing Issue
## First search to see if someone has already asked (and hopefully been answered) or suggested the same thing. First search to see if someone has already asked (and hopefully been answered) or suggested the same thing.
- [Search in Discussions](https://github.com/orgs/mermaid-js/discussions) - [Search in Discussions](https://github.com/orgs/mermaid-js/discussions)
- [Search in Issues (Open & Closed)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue) - [Search in Issues (Open & Closed)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue)
If you find an open issue or discussion thread that is similar to your question but isn't answered, you can let us know that you are also interested in it. If you find an open issue or discussion thread that is similar to your question but isn't answered, you can let us know that you are also interested in it.
Use the GitHub reactions to add a thumbs-up to the issue or discussion thread. Use the GitHub reactions to add a thumbs-up to the issue or discussion thread, or append to the issue if needed.
This helps the team know the relative interest in something and helps them set priorities and assignments. This helps the team know the relative interest in something and helps them set priorities and assignments.
Feel free to add to the discussion on the issue or topic. ## Add a new Issue
If you can't find anything that already addresses your question or suggestion, _open a new issue:_ You have not found anything that already addresses your request, or maybe you have come up with the new idea? Feel free to open a new issue or discussion.
Log in to [GitHub.com](https://www.github.com), open or append to an issue [using the GitHub issue tracker of the mermaid-js repository](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Area%3A+Documentation%22). Log in to [GitHub.com](https://www.github.com), and use [GitHub issue tracker of the mermaid-js repository](https://github.com/mermaid-js/mermaid/issues). Press \[<https://github.com/mermaid-js/mermaid/issues/new/choose>] issue, select the appropriate template and describe your problem.

View File

@@ -16,7 +16,7 @@ We aim to reply within three working days, probably much sooner.
You should expect a close collaboration as we work to resolve the issue you have reported. Please reach out to <security@mermaid.live> again if you do not receive prompt attention and regular updates. You should expect a close collaboration as we work to resolve the issue you have reported. Please reach out to <security@mermaid.live> again if you do not receive prompt attention and regular updates.
You may also reach out to the team via our public Slack chat channels; however, please make sure to e-mail <security@mermaid.live> when reporting an issue, and avoid revealing information about vulnerabilities in public as that could that could put users at risk. You may also reach out to the team via our public Discord chat channels; however, please make sure to e-mail <security@mermaid.live> when reporting an issue, and avoid revealing information about vulnerabilities in public as that could that could put users at risk.
## Best practices ## Best practices

View File

@@ -1,30 +0,0 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/advanced.md](../../packages/mermaid/src/docs/config/advanced.md).
# Advanced mermaid (Coming soon..)
## splitting mermaid code from html
A more condensed html code can be achieved by embedding the mermaid code in its own .js file, which is referenced like so:
```html
...
</div>
</body>
</html>
```
The actual mermaid file could for example look like this:
```javascript
mermaid content ...
```
## mermaid configuration options
```markdown
(coming soon)
```

View File

@@ -96,7 +96,7 @@ mermaid.initialize(config);
#### Defined in #### Defined in
[mermaidAPI.ts:608](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L608) [mermaidAPI.ts:607](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L607)
## Functions ## Functions

View File

@@ -20,7 +20,7 @@ Please note that you can switch versions through the dropdown box at the top rig
For the majority of users, Using the [Live Editor](https://mermaid.live/) would be sufficient, however you may also opt to deploy mermaid as a dependency or using the [Mermaid API](./setup/README.md). For the majority of users, Using the [Live Editor](https://mermaid.live/) would be sufficient, however you may also opt to deploy mermaid as a dependency or using the [Mermaid API](./setup/README.md).
We have compiled some Video [Tutorials](./Tutorials.md) on how to use the Mermaid Live Editor. We have compiled some Video [Tutorials](../ecosystem/tutorials.md) on how to use the Mermaid Live Editor.
### Installing and Hosting Mermaid on a Webpage ### Installing and Hosting Mermaid on a Webpage

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -27,50 +27,49 @@ To add an integration to this list, see the [Integrations - create page](./integ
### Productivity tools ### Productivity tools
- [GitHub](https://github.com) ✅
- [Using code blocks](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) ✅
- [GitHub action: Compile mermaid to image](https://github.com/neenjaw/compile-mermaid-markdown-action)
- [svg-generator](https://github.com/SimonKenyonShepard/mermaidjs-github-svg-generator)
- [GitHub Writer](https://github.com/ckeditor/github-writer)
- [GitLab](https://docs.gitlab.com/ee/user/markdown.html#diagrams-and-flowcharts) ✅
- [Gitea](https://gitea.io) ✅
- [Azure Devops](https://docs.microsoft.com/en-us/azure/devops/project/wiki/wiki-markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) ✅
- [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) ✅
- [Mermaid Flow Visual Editor](https://www.mermaidflow.app) ✅
- [Deepdwn](https://billiam.itch.io/deepdwn) ✅
- [Joplin](https://joplinapp.org) ✅
- [Slab](https://slab.com) ✅
- [Swimm](https://swimm.io) ✅
- [Notion](https://notion.so) ✅
- [Observable](https://observablehq.com/@observablehq/mermaid) ✅
- [Obsidian](https://help.obsidian.md/Editing+and+formatting/Advanced+formatting+syntax#Diagram) ✅
- [NotesHub](https://noteshub.app) ✅
- [GitBook](https://gitbook.com)
- [Mermaid Plugin](https://github.com/JozoVilcek/gitbook-plugin-mermaid)
- [Markdown with Mermaid CLI](https://github.com/miao1007/gitbook-plugin-mermaid-cli)
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
- [LiveBook](https://livebook.dev) ✅
- [Atlassian Products](https://www.atlassian.com) - [Atlassian Products](https://www.atlassian.com)
- [Mermaid for Confluence](https://marketplace.atlassian.com/apps/1224722/mermaid-for-confluence?hosting=cloud&tab=overview) - [Mermaid for Confluence](https://marketplace.atlassian.com/apps/1224722/mermaid-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Integration for Confluence](https://marketplace.atlassian.com/apps/1222792/mermaid-integration-for-confluence?hosting=cloud&tab=overview) - [Mermaid Integration for Confluence](https://marketplace.atlassian.com/apps/1222792/mermaid-integration-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Diagrams for Confluence](https://marketplace.atlassian.com/apps/1226945/mermaid-diagrams-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Macro for Confluence](https://marketplace.atlassian.com/apps/1231150/mermaid-macro-for-confluence?hosting=cloud&tab=overview)
- [EliteSoft Mermaid Charts and Diagrams](https://marketplace.atlassian.com/apps/1227286/elitesoft-mermaid-charts-and-diagrams?hosting=cloud&tab=overview)
- [Mermaid for Jira Cloud - Draw UML diagrams easily](https://marketplace.atlassian.com/apps/1223053/mermaid-for-jira-cloud-draw-uml-diagrams-easily?hosting=cloud&tab=overview)
- [Mermaid Charts & Diagrams for Confluence](https://marketplace.atlassian.com/apps/1222572/) - [Mermaid Charts & Diagrams for Confluence](https://marketplace.atlassian.com/apps/1222572/)
- [Mermaid Charts & Diagrams for Jira](https://marketplace.atlassian.com/apps/1224537/) - [Mermaid Diagrams for Confluence](https://marketplace.atlassian.com/apps/1226945/mermaid-diagrams-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview) - [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Macro for Confluence](https://marketplace.atlassian.com/apps/1231150/mermaid-macro-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Plugin for Confluence](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview) - [Mermaid Plugin for Confluence](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview)
- [CloudScript.io Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview) - [EliteSoft Mermaid Charts and Diagrams](https://marketplace.atlassian.com/apps/1227286/elitesoft-mermaid-charts-and-diagrams?hosting=cloud&tab=overview)
- [Auto convert diagrams in Jira](https://github.com/coddingtonbear/jirafs-mermaid) - [Auto convert diagrams in Jira](https://github.com/coddingtonbear/jirafs-mermaid)
- [Mermaid Charts & Diagrams for Jira](https://marketplace.atlassian.com/apps/1224537/)
- [Mermaid for Jira Cloud - Draw UML diagrams easily](https://marketplace.atlassian.com/apps/1223053/mermaid-for-jira-cloud-draw-uml-diagrams-easily?hosting=cloud&tab=overview)
- [CloudScript.io Mermaid Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview)
- [Azure Devops](https://learn.microsoft.com/en-us/azure/devops/project/wiki/markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) ✅
- [Deepdwn](https://billiam.itch.io/deepdwn) ✅
- [GitBook](https://gitbook.com)
- [Mermaid Plugin](https://github.com/JozoVilcek/gitbook-plugin-mermaid)
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
- [Markdown with Mermaid CLI](https://github.com/miao1007/gitbook-plugin-mermaid-cli)
- [Gitea](https://gitea.io) ✅
- [GitHub](https://github.com) ✅
- [Using code blocks](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) ✅
- [GitHub action: Compile mermaid to image](https://github.com/neenjaw/compile-mermaid-markdown-action)
- [GitHub Writer](https://github.com/ckeditor/github-writer)
- [SVG diagram generator](https://github.com/SimonKenyonShepard/mermaidjs-github-svg-generator)
- [GitLab](https://docs.gitlab.com/ee/user/markdown.html#diagrams-and-flowcharts) ✅
- [Mermaid Plugin for JetBrains IDEs](https://plugins.jetbrains.com/plugin/20146-mermaid)
- [Joplin](https://joplinapp.org) ✅
- [LiveBook](https://livebook.dev) ✅
- [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) ✅
- [Mermaid Flow Visual Editor](https://www.mermaidflow.app) ✅
- [Mermerd](https://github.com/KarnerTh/mermerd)
- [Slab](https://slab.com) ✅
- [Swimm](https://docs.swimm.io/features/diagrams-and-charts/#mermaid--swimm--up-to-date-diagrams-) ✅
- [NotesHub](https://noteshub.app) ✅
- [Notion](https://notion.so) ✅
- [Observable](https://observablehq.com/@observablehq/mermaid) ✅
- [Obsidian](https://help.obsidian.md/Editing+and+formatting/Advanced+formatting+syntax#Diagram) ✅
- [Redmine](https://redmine.org) - [Redmine](https://redmine.org)
- [Mermaid Macro](https://www.redmine.org/plugins/redmine_mermaid_macro) - [Mermaid Macro](https://www.redmine.org/plugins/redmine_mermaid_macro)
- [Markdown for mermaid plugin](https://github.com/jamieh-mongolian/markdown-for-mermaid-plugin)
- [redmine-mermaid](https://github.com/styz/redmine_mermaid) - [redmine-mermaid](https://github.com/styz/redmine_mermaid)
- [markdown-for-mermaid-plugin](https://github.com/jamieh-mongolian/markdown-for-mermaid-plugin)
- [Mermaid Plugin for JetBrains IDEs](https://plugins.jetbrains.com/plugin/20146-mermaid)
- [mermerd](https://github.com/KarnerTh/mermerd)
- Visual Studio Code [Polyglot Interactive Notebooks](https://github.com/dotnet/interactive#net-interactive) - Visual Studio Code [Polyglot Interactive Notebooks](https://github.com/dotnet/interactive#net-interactive)
- Codemia [a tool to practice system design problems](https://codemia.io)
### CRM/ERP ### CRM/ERP
@@ -82,139 +81,137 @@ Customer Relationship Management/Enterprise Resource Planning
Blogging frameworks and platforms Blogging frameworks and platforms
- [WordPress](https://wordpress.org)
- [WordPress Markdown Editor](https://wordpress.org/plugins/wp-githuber-md)
- [WP-ReliableMD](https://wordpress.org/plugins/wp-reliablemd/)
- [Hexo](https://hexo.io) - [Hexo](https://hexo.io)
- [hexo-filter-mermaid-diagrams](https://github.com/webappdevelp/hexo-filter-mermaid-diagrams) - [hexo-filter-mermaid-diagrams](https://github.com/webappdevelp/hexo-filter-mermaid-diagrams)
- [hexo-tag-mermaid](https://github.com/JameChou/hexo-tag-mermaid) - [hexo-tag-mermaid](https://github.com/JameChou/hexo-tag-mermaid)
- [hexo-mermaid-diagrams](https://github.com/mslxl/hexo-mermaid-diagrams) - [hexo-mermaid-diagrams](https://github.com/mslxl/hexo-mermaid-diagrams)
- [Nextra](https://nextra.site/) - [Nextra](https://nextra.site/)
- [Mermaid](https://nextra.site/docs/guide/mermaid) - [Mermaid](https://nextra.site/docs/guide/mermaid)
- [WordPress](https://wordpress.org)
- [WordPress Markdown Editor](https://wordpress.org/plugins/wp-githuber-md)
- [WP-ReliableMD](https://wordpress.org/plugins/wp-reliablemd/)
### CMS/ECM ### CMS/ECM
Content Management Systems/Enterprise Content Management Content Management Systems/Enterprise Content Management
- [Grav CMS](https://getgrav.org/)
- [Mermaid Diagrams Plugin](https://github.com/DanielFlaum/grav-plugin-mermaid-diagrams)
- [GitLab Markdown Adapter](https://github.com/Goutte/grav-plugin-gitlab-markdown-adapter)
- [VitePress](https://vitepress.vuejs.org/) - [VitePress](https://vitepress.vuejs.org/)
- [Plugin for Mermaid.js](https://emersonbottero.github.io/vitepress-plugin-mermaid/) - [Plugin for Mermaid.js](https://emersonbottero.github.io/vitepress-plugin-mermaid/)
- [VuePress](https://vuepress.vuejs.org/) - [VuePress](https://vuepress.vuejs.org/)
- [Plugin for Mermaid.js](https://github.com/eFrane/vuepress-plugin-mermaidjs) - [Plugin for Mermaid.js](https://github.com/eFrane/vuepress-plugin-mermaidjs)
- [Grav CMS](https://getgrav.org/)
- [Mermaid Diagrams](https://github.com/DanielFlaum/grav-plugin-mermaid-diagrams)
- [GitLab Markdown Adapter](https://github.com/Goutte/grav-plugin-gitlab-markdown-adapter)
### Communication ### Communication
Communication tools and platforms Communication tools and platforms
- [Discourse](https://discourse.org) - [Discourse](https://discourse.org)
- [Mermaid Plugin](https://github.com/pnewell/discourse-mermaid), [And](https://github.com/unfoldingWord-dev/discourse-mermaid) - [Mermaid Plugin](https://github.com/pnewell/discourse-mermaid)
- [Mattermost](https://mattermost.com/) - [Mattermost](https://mattermost.com/)
- [Mermaid Plugin](https://github.com/SpikeTings/Mermaid) - [Mermaid Plugin](https://github.com/SpikeTings/Mermaid)
- [NodeBB](https://nodebb.org)
- [Mermaid Parser Plugin](https://www.npmjs.com/package/nodebb-plugin-mermaid)
- [phpBB](https://phpbb.com) - [phpBB](https://phpbb.com)
- [phpbb-ext-mermaid](https://github.com/AlfredoRamos/phpbb-ext-mermaid) - [phpbb-ext-mermaid](https://github.com/AlfredoRamos/phpbb-ext-mermaid)
- [NodeBB](https://nodebb.org)
- [Mermaid Plugin](https://www.npmjs.com/package/nodebb-plugin-mermaid)
- [Slack](https://slack.com) - [Slack](https://slack.com)
- [Mermaid for Slack](https://github.com/JackuB/mermaid-for-slack) - [Mermaid Preview](https://github.com/JackuB/mermaid-for-slack)
### Wikis ### Wikis
- [PmWiki](https://www.pmwiki.org) - [DokuWiki](https://dokuwiki.org)
- [MermaidJs Cookbook recipe](https://www.pmwiki.org/wiki/Cookbook/MermaidJs) - [ComboStrap](https://combostrap.com/mermaid)
- [MediaWiki](https://www.mediawiki.org) - [Mermaid Plugin](https://www.dokuwiki.org/plugin:mermaid)
- [Mermaid Extension](https://www.mediawiki.org/wiki/Extension:Mermaid)
- [Flex Diagrams Extension](https://www.mediawiki.org/wiki/Extension:Flex_Diagrams)
- [Semantic Media Wiki](https://semantic-mediawiki.org)
- [Mermaid Plugin](https://github.com/SemanticMediaWiki/Mermaid)
- [Foswiki](https://foswiki.org) - [Foswiki](https://foswiki.org)
- [Mermaid Plugin](https://foswiki.org/Extensions/MermaidPlugin) - [Mermaid Plugin](https://foswiki.org/Extensions/MermaidPlugin)
- [DokuWiki](https://dokuwiki.org) - [MediaWiki](https://www.mediawiki.org)
- [Mermaid Plugin](https://www.dokuwiki.org/plugin:mermaid) - [Flex Diagrams Extension](https://www.mediawiki.org/wiki/Extension:Flex_Diagrams)
- [ComboStrap](https://combostrap.com/mermaid) - [Mermaid Extension](https://www.mediawiki.org/wiki/Extension:Mermaid)
- [PmWiki](https://www.pmwiki.org)
- [MermaidJs Cookbook recipe](https://www.pmwiki.org/wiki/Cookbook/MermaidJs)
- [Semantic Media Wiki](https://semantic-mediawiki.org)
- [Mermaid Plugin](https://github.com/SemanticMediaWiki/Mermaid)
- [TiddlyWiki](https://tiddlywiki.com/) - [TiddlyWiki](https://tiddlywiki.com/)
- [mermaid-tw5: full js library](https://github.com/efurlanm/mermaid-tw5) - [mermaid-tw5: wrapper for Mermaid Live](https://github.com/efurlanm/mermaid-tw5)
- [tw5-mermaid: wrapper for Mermaid Live](https://github.com/jasonmhoule/tw5-mermaid) - [tw5-mermaid: plugin for managing Mermaid.js tiddlers](https://github.com/jasonmhoule/tw5-mermaid)
### Editor Plugins ### Editor Plugins
- [VS Code](https://code.visualstudio.com/) - Atom _(Atom has been [archived.](https://github.blog/2022-06-08-sunsetting-atom/))_
- [Markdown Preview Mermaid Support](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-mermaid) - [Markdown Preview Enhanced](https://github.com/shd101wyy/markdown-preview-enhanced)
- [Mermaid Preview](https://marketplace.visualstudio.com/items?itemName=vstirbu.vscode-mermaid-preview) - [Atom Mermaid](https://github.com/y-takey/atom-mermaid)
- [Markdown Preview Enhanced](https://marketplace.visualstudio.com/items?itemName=shd101wyy.markdown-preview-enhanced) - [Language Mermaid Syntax Highlighter](https://github.com/ytisf/language-mermaid)
- [Mermaid Markdown Syntax Highlighting](https://marketplace.visualstudio.com/items?itemName=bpruitt-goddard.mermaid-markdown-syntax-highlighting) - [Astah](https://astah.net)
- [Mermaid Editor](https://marketplace.visualstudio.com/items?itemName=tomoyukim.vscode-mermaid-editor) - [Export to Mermaid](https://github.com/Avens666/Astah_Jude_UML_export_to_Markdown-mermaid-Plantuml-)
- [Mermaid Export](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.mermaid-export) - [Brackets](https://brackets.io/)
- [Markdown PDF](https://marketplace.visualstudio.com/items?itemName=yzane.markdown-pdf) - [Mermaid Preview](https://github.com/AlanHohn/mermaid-preview)
- [Preview](https://marketplace.visualstudio.com/items?itemName=searKing.preview-vscode) - [CKEditor](https://github.com/ckeditor/ckeditor5)
- [Preview Sequence Diagrams](https://marketplace.visualstudio.com/items?itemName=arichika.previewseqdiag-vscode) - [CKEditor 5 Mermaid plugin](https://github.com/ckeditor/ckeditor5-mermaid)
- [Draw.io](https://draw.io)
- [Mermaid Plugin](https://github.com/nopeslide/drawio_mermaid_plugin)
- [GNU Emacs](https://www.gnu.org/software/emacs/)
- [Major mode for .mmd files](https://github.com/abrochard/mermaid-mode)
- [Org-Mode integration](https://github.com/arnm/ob-mermaid)
- [GNU Nano](https://www.nano-editor.org/)
- [Nano Mermaid](https://github.com/Yash-Singh1/nano-mermaid)
- [Google docs](https://docs.google.com/)
- [Mermaid plugin for google docs](https://workspace.google.com/marketplace/app/mermaid/636321283856)
- [Inkdrop](https://www.inkdrop.app)
- [Mermaid Plugin](https://github.com/inkdropapp/inkdrop-mermaid)
- [Light Table](http://lighttable.com/)
- [Mermaid Plugin](https://github.com/cldwalker/Mermaid)
- [Markdown-It](https://github.com/markdown-it/markdown-it) - [Markdown-It](https://github.com/markdown-it/markdown-it)
- [Textual UML Parser](https://github.com/manastalukdar/markdown-it-textual-uml) - [Textual UML Parser](https://github.com/manastalukdar/markdown-it-textual-uml)
- [Mermaid Plugin](https://github.com/tylingsoft/markdown-it-mermaid) - [Mermaid Plugin](https://github.com/tylingsoft/markdown-it-mermaid)
- [md-it-mermaid](https://github.com/iamcco/md-it-mermaid) - [md-it-mermaid](https://github.com/iamcco/md-it-mermaid)
- [markdown-it-mermaid-less](https://github.com/searKing/markdown-it-mermaid-less) - [markdown-it-mermaid-less](https://github.com/searKing/markdown-it-mermaid-less)
- Atom _(Atom has been [archived.](https://github.blog/2022-06-08-sunsetting-atom/))_ - [Podlite](https://github.com/zag/podlite-desktop)
- [Markdown Preview Enhanced](https://github.com/shd101wyy/markdown-preview-enhanced) - [=Diagram block](https://github.com/zag/podlite/tree/main/packages/podlite-diagrams)
- [Atom Mermaid](https://github.com/y-takey/atom-mermaid) - [Standard Notes](https://standardnotes.com/)
- [Language Mermaid Syntax Highlighter](https://github.com/ytisf/language-mermaid) - [Mermaid Extension](https://github.com/nienow/sn-mermaid)
- [Sublime Text 3](https://sublimetext.com) - [Sublime Text 3](https://sublimetext.com)
- [Mermaid Package](https://packagecontrol.io/packages/Mermaid) - [Mermaid Package](https://packagecontrol.io/packages/Mermaid)
- [Astah](https://astah.net) - [VS Code](https://code.visualstudio.com/)
- [Export to Mermaid](https://github.com/Avens666/Astah_Jude_UML_export_to_Markdown-mermaid-Plantuml-) - [Mermaid Editor](https://marketplace.visualstudio.com/items?itemName=tomoyukim.vscode-mermaid-editor)
- [Light Table](http://lighttable.com/) - [Mermaid Export](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.mermaid-export)
- [Mermaid Plugin](https://github.com/cldwalker/Mermaid) - [Markdown PDF](https://marketplace.visualstudio.com/items?itemName=yzane.markdown-pdf)
- [Draw.io](https://draw.io) - [Plugin](https://github.com/nopeslide/drawio_mermaid_plugin) - [Markdown Preview Mermaid Support](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-mermaid)
- [Inkdrop](https://www.inkdrop.app) - [Plugin](https://github.com/inkdropapp/inkdrop-mermaid) - [Markdown Preview Enhanced](https://marketplace.visualstudio.com/items?itemName=shd101wyy.markdown-preview-enhanced)
- [Mermaid Preview](https://marketplace.visualstudio.com/items?itemName=vstirbu.vscode-mermaid-preview)
- [Preview](https://marketplace.visualstudio.com/items?itemName=searKing.preview-vscode)
- [Preview Sequence Diagrams](https://marketplace.visualstudio.com/items?itemName=arichika.previewseqdiag-vscode)
- [Mermaid Markdown Syntax Highlighting](https://marketplace.visualstudio.com/items?itemName=bpruitt-goddard.mermaid-markdown-syntax-highlighting)
- [Vim](https://www.vim.org) - [Vim](https://www.vim.org)
- [Official Vim Syntax and ftplugin](https://github.com/craigmac/vim-mermaid)
- [Vim Diagram Syntax](https://github.com/zhaozg/vim-diagram) - [Vim Diagram Syntax](https://github.com/zhaozg/vim-diagram)
- [GNU Emacs](https://www.gnu.org/software/emacs/) - [Official Vim Syntax and ft plugin](https://github.com/craigmac/vim-mermaid)
- [Major mode for .mmd files](https://github.com/abrochard/mermaid-mode)
- [Org-Mode integration](https://github.com/arnm/ob-mermaid)
- [Brackets](https://brackets.io/)
- [Mermaid Preview](https://github.com/AlanHohn/mermaid-preview)
- [Iodide](https://github.com/iodide-project/iodide)
- [iodide-mermaid-plugin](https://github.com/iodide-project/iodide-mermaid-plugin)
- [Google docs](https://docs.google.com/)
- [Mermaid plugin for google docs](https://workspace.google.com/marketplace/app/mermaid/636321283856)
- [Podlite](https://github.com/zag/podlite-desktop)
- [Named block =Diagram](https://github.com/zag/podlite/tree/main/packages/podlite-diagrams)
- [GNU Nano](https://www.nano-editor.org/)
- [Nano Mermaid](https://github.com/Yash-Singh1/nano-mermaid)
- [CKEditor](https://github.com/ckeditor/ckeditor5)
- [CKEditor 5 Mermaid plugin](https://github.com/ckeditor/ckeditor5-mermaid)
- [Standard Notes](https://standardnotes.com/)
- [sn-mermaid](https://github.com/nienow/sn-mermaid)
### Document Generation ### Document Generation
- [Codedoc](https://codedoc.cc/)
- [codedoc-mermaid-plugin](https://www.npmjs.com/package/codedoc-mermaid-plugin)
- [Docsy Hugo Theme](https://www.docsy.dev/docs/adding-content/lookandfeel/#diagrams-with-mermaid) ✅
- [Docusaurus](https://docusaurus.io/docs/markdown-features/diagrams) ✅ - [Docusaurus](https://docusaurus.io/docs/markdown-features/diagrams) ✅
- [Unison programming language](https://www.unison-lang.org/docs/usage-topics/documentation/) ✅
- [Swimm - Up-to-date diagrams with Swimm, the knowledge management tool for code](https://docs.swimm.io/features/diagrams-and-charts/#mermaid--swimm--up-to-date-diagrams-)
- [Sphinx](https://www.sphinx-doc.org/en/master/)
- [sphinxcontrib-mermaid](https://github.com/mgaitan/sphinxcontrib-mermaid)
- [remark](https://remark.js.org/)
- [remark-mermaidjs](https://github.com/remcohaszing/remark-mermaidjs)
- [rehype](https://github.com/rehypejs/rehype)
- [rehype-mermaid](https://github.com/remcohaszing/rehype-mermaid)
- [Gatsby](https://www.gatsbyjs.com/) - [Gatsby](https://www.gatsbyjs.com/)
- [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid) - [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid)
- [JSDoc](https://jsdoc.app/) - [JSDoc](https://jsdoc.app/)
- [jsdoc-mermaid](https://github.com/Jellyvision/jsdoc-mermaid) - [jsdoc-mermaid](https://github.com/Jellyvision/jsdoc-mermaid)
- [mdBook](https://rust-lang.github.io/mdBook/index.html)
- [mdbook-mermaid](https://github.com/badboy/mdbook-mermaid)
- [MkDocs](https://www.mkdocs.org) - [MkDocs](https://www.mkdocs.org)
- [mkdocs-mermaid2-plugin](https://github.com/fralau/mkdocs-mermaid2-plugin) - [mkdocs-mermaid2-plugin](https://github.com/fralau/mkdocs-mermaid2-plugin)
- [mkdocs-material](https://github.com/squidfunk/mkdocs-material), check the [docs](https://squidfunk.github.io/mkdocs-material/reference/diagrams/) - [mkdocs-material](https://github.com/squidfunk/mkdocs-material), check the [docs](https://squidfunk.github.io/mkdocs-material/reference/diagrams/)
- [Quarto](https://quarto.org/)
- [rehype](https://github.com/rehypejs/rehype)
- [rehype-mermaid](https://github.com/remcohaszing/rehype-mermaid)
- [remark](https://remark.js.org/)
- [remark-mermaidjs](https://github.com/remcohaszing/remark-mermaidjs)
- [Sphinx](https://www.sphinx-doc.org/en/master/)
- [sphinxcontrib-mermaid](https://github.com/mgaitan/sphinxcontrib-mermaid)
- [Type Doc](https://typedoc.org/) - [Type Doc](https://typedoc.org/)
- [typedoc-plugin-mermaid](https://www.npmjs.com/package/typedoc-plugin-mermaid) - [typedoc-plugin-mermaid](https://www.npmjs.com/package/typedoc-plugin-mermaid)
- [Docsy Hugo Theme](https://www.docsy.dev/docs/adding-content/lookandfeel/#diagrams-with-mermaid) ✅ - [Typora](https://support.typora.io/Draw-Diagrams-With-Markdown/#mermaid) ✅
- [Codedoc](https://codedoc.cc/) - [Unison programming language](https://www.unison-lang.org/docs/usage-topics/documentation/)
- [codedoc-mermaid-plugin](https://www.npmjs.com/package/codedoc-mermaid-plugin)
- [mdbook](https://rust-lang.github.io/mdBook/index.html)
- [mdbook-mermaid](https://github.com/badboy/mdbook-mermaid)
- [Quarto](https://quarto.org/)
- [Typora](https://typora.io/) ✅
- [See docs](https://support.typora.io/Draw-Diagrams-With-Markdown/#mermaid)
### Browser Extensions ### Browser Extensions
@@ -225,7 +222,7 @@ Communication tools and platforms
| Diagram Tab | - | - | - | - | [🐙🔗](https://github.com/khafast/diagramtab) | | Diagram Tab | - | - | - | - | [🐙🔗](https://github.com/khafast/diagramtab) |
| Markdown Diagrams | [🎡🔗](https://chrome.google.com/webstore/detail/markdown-diagrams/pmoglnmodacnbbofbgcagndelmgaclel/) | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-diagrams/) | [🔴🔗](https://addons.opera.com/en/extensions/details/markdown-diagrams/) | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/markdown-diagrams/hceenoomhhdkjjijnmlclkpenkapfihe) | [🐙🔗](https://github.com/marcozaccari/markdown-diagrams-browser-extension/tree/master/doc/examples) | | Markdown Diagrams | [🎡🔗](https://chrome.google.com/webstore/detail/markdown-diagrams/pmoglnmodacnbbofbgcagndelmgaclel/) | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-diagrams/) | [🔴🔗](https://addons.opera.com/en/extensions/details/markdown-diagrams/) | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/markdown-diagrams/hceenoomhhdkjjijnmlclkpenkapfihe) | [🐙🔗](https://github.com/marcozaccari/markdown-diagrams-browser-extension/tree/master/doc/examples) |
| Markdown Viewer | - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | - | - | [🐙🔗](https://github.com/simov/markdown-viewer) | | Markdown Viewer | - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | - | - | [🐙🔗](https://github.com/simov/markdown-viewer) |
| Extensions for Mermaid | - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | [🔴🔗](https://addons.opera.com/en/extensions/details/extensions-for-mermaid/) | - | [🐙🔗](https://github.com/Stefan-S/mermaid-extension) | | Extensions for Mermaid | - | - | [🔴🔗](https://addons.opera.com/en/extensions/details/extensions-for-mermaid/) | - | [🐙🔗](https://github.com/Stefan-S/mermaid-extension) |
| Chrome Diagrammer | [🎡🔗](https://chrome.google.com/webstore/detail/chrome-diagrammer/bkpbgjmkomfoakfklcjeoegkklgjnnpk) | - | - | - | - | | Chrome Diagrammer | [🎡🔗](https://chrome.google.com/webstore/detail/chrome-diagrammer/bkpbgjmkomfoakfklcjeoegkklgjnnpk) | - | - | - | - |
| Mermaid Diagrams | [🎡🔗](https://chrome.google.com/webstore/detail/mermaid-diagrams/phfcghedmopjadpojhmmaffjmfiakfil) | - | - | - | - | | Mermaid Diagrams | [🎡🔗](https://chrome.google.com/webstore/detail/mermaid-diagrams/phfcghedmopjadpojhmmaffjmfiakfil) | - | - | - | - |
| Monkeys | [🎡🔗](https://chrome.google.com/webstore/detail/monkeys-mermaid-for-githu/cplfdpoajbclbgphaphphcldamfkjlgi) | - | - | - | - | | Monkeys | [🎡🔗](https://chrome.google.com/webstore/detail/monkeys-mermaid-for-githu/cplfdpoajbclbgphaphphcldamfkjlgi) | - | - | - | - |
@@ -233,19 +230,23 @@ Communication tools and platforms
### Other ### Other
- [Bisheng](https://www.npmjs.com/package/bisheng)
- [bisheng-plugin-mermaid](https://github.com/yct21/bisheng-plugin-mermaid)
- [Codemia: A tool to practice system design problems](https://codemia.io) ✅
- [ExDoc](https://github.com/elixir-lang/ex_doc)
- [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs)
- [Jekyll](https://jekyllrb.com/) - [Jekyll](https://jekyllrb.com/)
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid) - [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams) - [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)
- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic)
- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)
- [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io) ✅
- [ui.mermaid(...)](https://nicegui.io/documentation/mermaid)
- [Reveal.js](https://github.com/hakimel/reveal.js) - [Reveal.js](https://github.com/hakimel/reveal.js)
- [reveal.js-mermaid-plugin](https://github.com/ludwick/reveal.js-mermaid-plugin) - [reveal.js-mermaid-plugin](https://github.com/ludwick/reveal.js-mermaid-plugin)
- [Bisheng](https://www.npmjs.com/package/bisheng)
- [bisheng-plugin-mermaid](https://github.com/yct21/bisheng-plugin-mermaid)
- [Reveal CK](https://github.com/jedcn/reveal-ck) - [Reveal CK](https://github.com/jedcn/reveal-ck)
- [reveal-ck-mermaid-plugin](https://github.com/tmtm/reveal-ck-mermaid-plugin) - [reveal-ck-mermaid-plugin](https://github.com/tmtm/reveal-ck-mermaid-plugin)
- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic) - [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic)
- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server) - [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)
- [ExDoc](https://github.com/elixir-lang/ex_doc) - [ExDoc](https://github.com/elixir-lang/ex_doc)
- [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs) - [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs)
- [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io) ✅
- [ui.mermaid(...)](https://nicegui.io/documentation/section_text_elements#markdown_element)
- [ui.markdown(..., extras=\['mermaid'\])](https://nicegui.io/documentation/section_text_elements#mermaid_diagrams)

View File

@@ -22,9 +22,9 @@ Currently pending [IANA](https://www.iana.org/) recognition.
## Showcase ## Showcase
### Mermaid Slack workspace ### Mermaid Discord workspace
We would love to see what you create with Mermaid. Please share your creations with us in our [Slack](https://join.slack.com/t/mermaid-talk/shared_invite/zt-22p2r8p9y-qiyP1H38GjFQ6S6jbBkOxQ) workspace [#community-showcase](https://mermaid-talk.slack.com/archives/C05NK37LT40) channel. We would love to see what you create with Mermaid. Please share your creations with us in our [Discord](https://discord.gg/AgrbSrBer3) server [#showcase](https://discord.com/channels/1079455296289788015/1079502635054399649) channel.
### Add to Mermaid Ecosystem ### Add to Mermaid Ecosystem

View File

@@ -2,7 +2,7 @@
> >
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. > ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
> >
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/Tutorials.md](../../packages/mermaid/src/docs/config/Tutorials.md). > ## Please edit the corresponding file in [/packages/mermaid/src/docs/ecosystem/tutorials.md](../../packages/mermaid/src/docs/ecosystem/tutorials.md).
# Tutorials # Tutorials

View File

@@ -17,7 +17,7 @@ This section talks about the different ways to **deploy** Mermaid.
If you are a beginner: If you are a beginner:
- Check out the [Diagram Syntax](syntax-reference.md) page - Check out the [Diagram Syntax](syntax-reference.md) page
- Check out the [Tutorials](../config/Tutorials.md) page - Check out the [Tutorials](../ecosystem/tutorials.md) page
## Ways to use Mermaid ## Ways to use Mermaid
@@ -71,7 +71,7 @@ graph TD
Configuration options are available in the `Configuration` panel. The options are applied to the diagram in the `Preview` panel. Configuration options are available in the `Configuration` panel. The options are applied to the diagram in the `Preview` panel.
For learn more, visit the [Configuration Reference](../config/setup/README.md) page To learn more, visit the [Configuration Reference](../config/setup/README.md) page
![Code,Config and Preview](./img/Code-Preview-Config.png) ![Code,Config and Preview](./img/Code-Preview-Config.png)

View File

@@ -22,7 +22,7 @@ It is a JavaScript based diagramming and charting tool that renders Markdown-ins
[![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master)
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
[![NPM](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![NPM](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid)
[![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![Join our Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/AgrbSrBer3)
[![Twitter Follow](https://img.shields.io/twitter/follow/mermaidjs_?style=social)](https://twitter.com/mermaidjs_) [![Twitter Follow](https://img.shields.io/twitter/follow/mermaidjs_?style=social)](https://twitter.com/mermaidjs_)
</div> </div>
@@ -41,13 +41,13 @@ Diagramming and documentation costs precious developer time and gets outdated qu
But not having diagrams or docs ruins productivity and hurts organizational learning.<br/> But not having diagrams or docs ruins productivity and hurts organizational learning.<br/>
Mermaid addresses this problem by enabling users to create easily modifiable diagrams, it can also be made part of production scripts (and other pieces of code).<br/> <br/> Mermaid addresses this problem by enabling users to create easily modifiable diagrams, it can also be made part of production scripts (and other pieces of code).<br/> <br/>
Mermaid allows even non-programmers to easily create detailed and diagrams through the [Mermaid Live Editor](https://mermaid.live/).<br/> Mermaid allows even non-programmers to easily create detailed and diagrams through the [Mermaid Live Editor](https://mermaid.live/).<br/>
[Tutorials](../config/Tutorials.md) has video tutorials. [Tutorials](../ecosystem/tutorials.md) has video tutorials.
Use Mermaid with your favorite applications, check out the list of [Community Integrations](../ecosystem/integrations-community.md). Use Mermaid with your favorite applications, check out the list of [Community Integrations](../ecosystem/integrations-community.md).
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](../intro/getting-started.md) and [Usage](../config/usage.md). For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](../intro/getting-started.md) and [Usage](../config/usage.md).
🌐 [CDN](https://www.jsdelivr.com/package/npm/mermaid) | 📖 [Documentation](https://mermaidjs.github.io) | 🙌 [Contribution](../community/development.md) | 🔌 [Plug-Ins](../ecosystem/integrations-community.md) 🌐 [CDN](https://www.jsdelivr.com/package/npm/mermaid) | 📖 [Documentation](https://mermaidjs.github.io) | 🙌 [Contribution](../community/contributing.md) | 🔌 [Plug-Ins](../ecosystem/integrations-community.md)
> 🖖 Keep a steady pulse: mermaid needs more Collaborators, [Read More](https://github.com/knsv/mermaid/issues/866). > 🖖 Keep a steady pulse: mermaid needs more Collaborators, [Read More](https://github.com/knsv/mermaid/issues/866).
@@ -378,7 +378,7 @@ Don't hesitate to contact me if you want to get involved!
Mermaid is a growing community and is always accepting new contributors. There's a lot of different ways to help out and we're always looking for extra hands! Look at [this issue](https://github.com/mermaid-js/mermaid/issues/866) if you want to know where to start helping out. Mermaid is a growing community and is always accepting new contributors. There's a lot of different ways to help out and we're always looking for extra hands! Look at [this issue](https://github.com/mermaid-js/mermaid/issues/866) if you want to know where to start helping out.
Detailed information about how to contribute can be found in the [contribution guideline](/community/development). Detailed information about how to contribute can be found in the [contribution guideline](../community/contributing.md).
### Requirements ### Requirements

View File

@@ -14,19 +14,6 @@ Create flowchart nodes, connect them with edges, update shapes, change colors, a
Read more about it in our latest [BLOG POST](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts) and watch a [DEMO VIDEO](https://www.youtube.com/watch?v=5aja0gijoO0) on our YouTube page. Read more about it in our latest [BLOG POST](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts) and watch a [DEMO VIDEO](https://www.youtube.com/watch?v=5aja0gijoO0) on our YouTube page.
## 🎉 Mermaid Chart is running a Holiday promotion
### Use <span class="text-[#FE3470]">HOLIDAYS2023</span> to get a 14-day free trial and 25% off a Pro subscription
With a Pro subscription, you get access to:
- AI functionality
- Team collaboration and multi-user editing
- Unlimited diagrams and presentations
- And more!
Redeem the promo code on the [Mermaid Chart website](https://www.mermaidchart.com/app/user/billing/checkout?coupon=HOLIDAYS2023).
## 📖 Blog posts ## 📖 Blog posts
Visit our [Blog](./blog.md) to see the latest blog posts. Visit our [Blog](./blog.md) to see the latest blog posts.

View File

@@ -6,6 +6,18 @@
# Blog # Blog
## [How to Make a Flowchart with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-flowcharts-with-mermaid-chart/)
30 January 2024 · 6 mins
Learn how to make a flowchart with Mermaid Chart, the leading text-to-diagram platform for both developers and non-developers.
## [How one data scientist uses Mermaid Chart to quickly and easily build flowcharts](https://www.mermaidchart.com/blog/posts/customer-spotlight-ari-tal/)
23 January 2024 · 4 mins
Read about how Ari Tal, a data scientist and founder of Leveling Up with XAI, utilizes Mermaid Chart for its easy-to-use flowchart creation capabilities to enhance his work in explainable AI (XAI).
## [Introducing Mermaid Charts JetBrains IDE Extension](https://www.mermaidchart.com/blog/posts/introducing-mermaid-charts-jetbrains-ide-extension/) ## [Introducing Mermaid Charts JetBrains IDE Extension](https://www.mermaidchart.com/blog/posts/introducing-mermaid-charts-jetbrains-ide-extension/)
20 December 2023 · 5 mins 20 December 2023 · 5 mins

706
docs/syntax/block.md Normal file
View File

@@ -0,0 +1,706 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/block.md](../../packages/mermaid/src/docs/syntax/block.md).
# Block Diagrams Documentation
## Introduction to Block Diagrams
```mermaid-example
block-beta
columns 1
db(("DB"))
blockArrowId6<["&nbsp;&nbsp;&nbsp;"]>(down)
block:ID
A
B["A wide one in the middle"]
C
end
space
D
ID --> D
C --> D
style B fill:#969,stroke:#333,stroke-width:4px
```
```mermaid
block-beta
columns 1
db(("DB"))
blockArrowId6<["&nbsp;&nbsp;&nbsp;"]>(down)
block:ID
A
B["A wide one in the middle"]
C
end
space
D
ID --> D
C --> D
style B fill:#969,stroke:#333,stroke-width:4px
```
### Definition and Purpose
Block diagrams are an intuitive and efficient way to represent complex systems, processes, or architectures visually. They are composed of blocks and connectors, where blocks represent the fundamental components or functions, and connectors show the relationship or flow between these components. This method of diagramming is essential in various fields such as engineering, software development, and process management.
The primary purpose of block diagrams is to provide a high-level view of a system, allowing for easy understanding and analysis without delving into the intricate details of each component. This makes them particularly useful for simplifying complex systems and for explaining the overall structure and interaction of components within a system.
Many people use mermaid flowcharts for this purpose. A side-effect of this is that the automatic layout sometimes move shapes to positions that the diagram maker does not want. Block diagrams use a different approach. In this diagram we give the author full control over where the shapes are positioned.
### General Use Cases
Block diagrams have a wide range of applications across various industries and disciplines. Some of the key use cases include:
- **Software Architecture**: In software development, block diagrams can be used to illustrate the architecture of a software application. This includes showing how different modules or services interact, data flow, and high-level component interaction.
- **Network Diagrams**: Block diagrams are ideal for representing network architectures in IT and telecommunications. They can depict how different network devices and services are interconnected, including routers, switches, firewalls, and the flow of data across the network.
- **Process Flowcharts**: In business and manufacturing, block diagrams can be employed to create process flowcharts. These flowcharts represent various stages of a business or manufacturing process, helping to visualize the sequence of steps, decision points, and the flow of control.
- **Electrical Systems**: Engineers use block diagrams to represent electrical systems and circuitry. They can illustrate the high-level structure of an electrical system, the interaction between different electrical components, and the flow of electrical currents.
- **Educational Purposes**: Block diagrams are also extensively used in educational materials to explain complex concepts and systems in a simplified manner. They help in breaking down and visualizing scientific theories, engineering principles, and technological systems.
These examples demonstrate the versatility of block diagrams in providing clear and concise representations of complex systems. Their simplicity and clarity make them a valuable tool for professionals across various fields to communicate complex ideas effectively.
In the following sections, we will delve into the specifics of creating and manipulating block diagrams using Mermaid, covering everything from basic syntax to advanced configurations and styling.
Creating block diagrams with Mermaid is straightforward and accessible. This section introduces the basic syntax and structure needed to start building simple diagrams. Understanding these foundational concepts is key to efficiently utilizing Mermaid for more complex diagramming tasks.
### Simple Block Diagrams
#### Basic Structure
At its core, a block diagram consists of blocks representing different entities or components. In Mermaid, these blocks are easily created using simple text labels. The most basic form of a block diagram can be a series of blocks without any connectors.
**Example - Simple Block Diagram**:
To create a simple block diagram with three blocks labeled 'a', 'b', and 'c', the syntax is as follows:
```mermaid-example
block-beta
a b c
```
```mermaid
block-beta
a b c
```
This example will produce a horizontal sequence of three blocks. Each block is automatically spaced and aligned for optimal readability.
### Defining the number of columns to use
#### Column Usage
While simple block diagrams are linear and straightforward, more complex systems may require a structured layout. Mermaid allows for the organization of blocks into multiple columns, facilitating the creation of more intricate and detailed diagrams.
**Example - Multi-Column Diagram:**
In scenarios where you need to distribute blocks across multiple columns, you can specify the number of columns and arrange the blocks accordingly. Here's how to create a block diagram with three columns and four blocks, where the fourth block appears in a second row:
```mermaid-example
block-beta
columns 3
a b c d
```
```mermaid
block-beta
columns 3
a b c d
```
This syntax instructs Mermaid to arrange the blocks 'a', 'b', 'c', and 'd' across three columns, wrapping to the next row as needed. This feature is particularly useful for representing layered or multi-tiered systems, such as network layers or hierarchical structures.
These basic building blocks of Mermaid's block diagrams provide a foundation for more complex diagramming. The simplicity of the syntax allows for quick creation and iteration of diagrams, making it an efficient tool for visualizing ideas and concepts. In the next section, we'll explore advanced block configuration options, including setting block widths and creating composite blocks.
## 3. Advanced Block Configuration
Building upon the basics, this section delves into more advanced features of block diagramming in Mermaid. These features allow for greater flexibility and complexity in diagram design, accommodating a wider range of use cases and scenarios.
### Setting Block Width
#### Spanning Multiple Columns
In more complex diagrams, you may need blocks that span multiple columns to emphasize certain components or to represent larger entities. Mermaid allows for the adjustment of block widths to cover multiple columns, enhancing the diagram's readability and structure.
**Example - Block Spanning Multiple Columns**:
To create a block diagram where one block spans across two columns, you can specify the desired width for each block:
```mermaid-example
block-beta
columns 3
a["A label"] b:2 c:2 d
```
```mermaid
block-beta
columns 3
a["A label"] b:2 c:2 d
```
In this example, the block labeled "A wide one" spans two columns, while blocks 'b', 'c', and 'd' are allocated their own columns. This flexibility in block sizing is crucial for accurately representing systems with components of varying significance or size.
### Creating Composite Blocks
#### Nested Blocks
Composite blocks, or blocks within blocks, are an advanced feature in Mermaid's block diagram syntax. They allow for the representation of nested or hierarchical systems, where one component encompasses several subcomponents.
**Example - Composite Blocks:**
Creating a composite block involves defining a parent block and then nesting other blocks within it. Here's how to define a composite block with nested elements:
```mermaid-example
block-beta
block
D
end
A["A: I am a wide one"]
```
```mermaid
block-beta
block
D
end
A["A: I am a wide one"]
```
In this syntax, 'D' is a nested block within a larger parent block. This feature is particularly useful for depicting complex structures, such as a server with multiple services or a department within a larger organizational framework.
### Column Width Dynamics
#### Adjusting Widths
Mermaid also allows for dynamic adjustment of column widths based on the content of the blocks. The width of the columns is determined by the widest block in the column, ensuring that the diagram remains balanced and readable.
**Example - Dynamic Column Widths:**
In diagrams with varying block sizes, Mermaid automatically adjusts the column widths to fit the largest block in each column. Here's an example:
```mermaid-example
block-beta
columns 3
a:3
block:group1:2
columns 2
h i j k
end
g
block:group2:3
%% columns auto (default)
l m n o p q r
end
```
```mermaid
block-beta
columns 3
a:3
block:group1:2
columns 2
h i j k
end
g
block:group2:3
%% columns auto (default)
l m n o p q r
end
```
This example demonstrates how Mermaid dynamically adjusts the width of the columns to accommodate the widest block, in this case, 'a' and the composite block 'e'. This dynamic adjustment is essential for creating visually balanced and easy-to-understand diagrams.
With these advanced configuration options, Mermaid's block diagrams can be tailored to represent a wide array of complex systems and structures. The flexibility offered by these features enables users to create diagrams that are both informative and visually appealing. In the following sections, we will explore further capabilities, including different block shapes and linking options.
## 4. Block Varieties and Shapes
Mermaid's block diagrams are not limited to standard rectangular shapes. A variety of block shapes are available, allowing for a more nuanced and tailored representation of different types of information or entities. This section outlines the different block shapes you can use in Mermaid and their specific applications.
### Standard and Special Block Shapes
Mermaid supports a range of block shapes to suit different diagramming needs, from basic geometric shapes to more specialized forms.
#### Example - Round Edged Block
To create a block with round edges, which can be used to represent a softer or more flexible component:
```mermaid-example
block-beta
id1("This is the text in the box")
```
```mermaid
block-beta
id1("This is the text in the box")
```
#### Example - Stadium-Shaped Block
A stadium-shaped block, resembling an elongated circle, can be used for components that are process-oriented:
```mermaid-example
block-beta
id1(["This is the text in the box"])
```
```mermaid
block-beta
id1(["This is the text in the box"])
```
#### Example - Subroutine Shape
For representing subroutines or contained processes, a block with double vertical lines is useful:
```mermaid-example
block-beta
id1[["This is the text in the box"]]
```
```mermaid
block-beta
id1[["This is the text in the box"]]
```
#### Example - Cylindrical Shape
The cylindrical shape is ideal for representing databases or storage components:
```mermaid-example
block-beta
id1[("Database")]
```
```mermaid
block-beta
id1[("Database")]
```
#### Example - Circle Shape
A circle can be used for centralized or pivotal components:
```mermaid-example
block-beta
id1(("This is the text in the circle"))
```
```mermaid
block-beta
id1(("This is the text in the circle"))
```
#### Example - Asymmetric, Rhombus, and Hexagon Shapes
For decision points, use a rhombus, and for unique or specialized processes, asymmetric and hexagon shapes can be utilized:
**Asymmetric**
```mermaid-example
block-beta
id1>"This is the text in the box"]
```
```mermaid
block-beta
id1>"This is the text in the box"]
```
**Rhombus**
```mermaid-example
block-beta
id1{"This is the text in the box"}
```
```mermaid
block-beta
id1{"This is the text in the box"}
```
**Hexagon**
```mermaid-example
block-beta
id1{{"This is the text in the box"}}
```
```mermaid
block-beta
id1{{"This is the text in the box"}}
```
#### Example - Parallelogram and Trapezoid Shapes
Parallelogram and trapezoid shapes are perfect for inputs/outputs and transitional processes:
```mermaid-example
block-beta
id1[/"This is the text in the box"/]
id2[\"This is the text in the box"\]
A[/"Christmas"\]
B[\"Go shopping"/]
```
```mermaid
block-beta
id1[/"This is the text in the box"/]
id2[\"This is the text in the box"\]
A[/"Christmas"\]
B[\"Go shopping"/]
```
#### Example - Double Circle
For highlighting critical or high-priority components, a double circle can be effective:
```mermaid-example
block-beta
id1((("This is the text in the circle")))
```
```mermaid
block-beta
id1((("This is the text in the circle")))
```
### Block Arrows and Space Blocks
Mermaid also offers unique shapes like block arrows and space blocks for directional flow and spacing.
#### Example - Block Arrows
Block arrows can visually indicate direction or flow within a process:
```mermaid-example
block-beta
blockArrowId<["Label"]>(right)
blockArrowId2<["Label"]>(left)
blockArrowId3<["Label"]>(up)
blockArrowId4<["Label"]>(down)
blockArrowId5<["Label"]>(x)
blockArrowId6<["Label"]>(y)
blockArrowId6<["Label"]>(x, down)
```
```mermaid
block-beta
blockArrowId<["Label"]>(right)
blockArrowId2<["Label"]>(left)
blockArrowId3<["Label"]>(up)
blockArrowId4<["Label"]>(down)
blockArrowId5<["Label"]>(x)
blockArrowId6<["Label"]>(y)
blockArrowId6<["Label"]>(x, down)
```
#### Example - Space Blocks
Space blocks can be used to create intentional empty spaces in the diagram, which is useful for layout and readability:
```mermaid-example
block-beta
columns 3
a space b
c d e
```
```mermaid
block-beta
columns 3
a space b
c d e
```
or
```mermaid-example
block-beta
ida space:3 idb idc
```
```mermaid
block-beta
ida space:3 idb idc
```
Note that you can set how many columns the spece block occupied using the number notaion `space:num` where num is a number indicating the num columns width. You can alsio use `space` which defaults to one column.
The variety of shapes and special blocks in Mermaid enhances the expressive power of block diagrams, allowing for more accurate and context-specific representations. These options give users the flexibility to create diagrams that are both informative and visually appealing. In the next sections, we will explore the ways to connect these blocks and customize their appearance.
### Standard and Special Block Shapes
Discuss the various shapes available for blocks, including standard shapes and special forms like block arrows and space blocks.
## 5. Connecting Blocks with Edges
One of the key features of block diagrams in Mermaid is the ability to connect blocks using various types of edges or links. This section explores the different ways blocks can be interconnected to represent relationships and flows between components.
### Basic Linking and Arrow Types
The most fundamental aspect of connecting blocks is the use of arrows or links. These connectors depict the relationships or the flow of information between the blocks. Mermaid offers a range of arrow types to suit different diagramming needs.
**Example - Basic Links**
A simple link with an arrow can be created to show direction or flow from one block to another:
```mermaid-example
block-beta
A space B
A-->B
```
```mermaid
block-beta
A space B
A-->B
```
This example illustrates a direct connection from block 'A' to block 'B', using a straightforward arrow.
This syntax creates a line connecting 'A' and 'B', implying a relationship or connection without indicating a specific direction.
### Text on Links
In addition to connecting blocks, it's often necessary to describe or label the relationship. Mermaid allows for the inclusion of text on links, providing context to the connections.
Example - Text with Links
To add text to a link, the syntax includes the text within the link definition:
```mermaid-example
block-beta
A space:2 B
A-- "X" -->B
```
```mermaid
block-beta
A space:2 B
A-- "X" -->B
```
This example show how to add descriptive text to the links, enhancing the information conveyed by the diagram.
Example - Edges and Styles:
```mermaid-example
block-beta
columns 1
db(("DB"))
blockArrowId6<["&nbsp;&nbsp;&nbsp;"]>(down)
block:ID
A
B["A wide one in the middle"]
C
end
space
D
ID --> D
C --> D
style B fill:#939,stroke:#333,stroke-width:4px
```
```mermaid
block-beta
columns 1
db(("DB"))
blockArrowId6<["&nbsp;&nbsp;&nbsp;"]>(down)
block:ID
A
B["A wide one in the middle"]
C
end
space
D
ID --> D
C --> D
style B fill:#939,stroke:#333,stroke-width:4px
```
## 6. Styling and Customization
Beyond the structure and layout of block diagrams, Mermaid offers extensive styling options. These customization features allow for the creation of more visually distinctive and informative diagrams. This section covers how to apply individual styles to blocks and how to use classes for consistent styling across multiple elements.
### Individual Block Styling
Mermaid enables detailed styling of individual blocks, allowing you to apply various CSS properties such as color, stroke, and border thickness. This feature is especially useful for highlighting specific parts of a diagram or for adhering to certain visual themes.
#### Example - Styling a Single Block
To apply custom styles to a block, you can use the `style` keyword followed by the block identifier and the desired CSS properties:
```mermaid-example
block-beta
id1 space id2
id1("Start")-->id2("Stop")
style id1 fill:#636,stroke:#333,stroke-width:4px
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
```
```mermaid
block-beta
id1 space id2
id1("Start")-->id2("Stop")
style id1 fill:#636,stroke:#333,stroke-width:4px
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
```
In this example, a class named 'blue' is defined and applied to block 'A', while block 'B' receives individual styling. This demonstrates the flexibility of Mermaid in applying both shared and unique styles within the same diagram.
The ability to style blocks individually or through classes provides a powerful tool for enhancing the visual impact and clarity of block diagrams. Whether emphasizing certain elements or maintaining a cohesive design across the diagram, these styling capabilities are central to effective diagramming. The next sections will present practical examples and use cases, followed by tips for troubleshooting common issues.
### 7. Practical Examples and Use Cases
The versatility of Mermaid's block diagrams becomes evident when applied to real-world scenarios. This section provides practical examples demonstrating the application of various features discussed in previous sections. These examples showcase how block diagrams can be used to represent complex systems and processes in an accessible and informative manner.
### Detailed Examples Illustrating Various Features
Combining the elements of structure, linking, and styling, we can create comprehensive diagrams that serve specific purposes in different contexts.
#### Example - System Architecture
Illustrating a simple software system architecture with interconnected components:
```mermaid-example
block-beta
columns 3
Frontend blockArrowId6<[" "]>(right) Backend
space:2 down<[" "]>(down)
Disk left<[" "]>(left) Database[("Database")]
classDef front fill:#696,stroke:#333;
classDef back fill:#969,stroke:#333;
class Frontend front
class Backend,Database back
```
```mermaid
block-beta
columns 3
Frontend blockArrowId6<[" "]>(right) Backend
space:2 down<[" "]>(down)
Disk left<[" "]>(left) Database[("Database")]
classDef front fill:#696,stroke:#333;
classDef back fill:#969,stroke:#333;
class Frontend front
class Backend,Database back
```
This example shows a basic architecture with a frontend, backend, and database. The blocks are styled to differentiate between types of components.
#### Example - Business Process Flow
Representing a business process flow with decision points and multiple stages:
```mermaid-example
block-beta
columns 3
Start(("Start")) space:2
down<[" "]>(down) space:2
Decision{{"Make Decision"}} right<["Yes"]>(right) Process1["Process A"]
downAgain<["No"]>(down) space r3<["Done"]>(down)
Process2["Process B"] r2<["Done"]>(right) End(("End"))
style Start fill:#969;
style End fill:#696;
```
```mermaid
block-beta
columns 3
Start(("Start")) space:2
down<[" "]>(down) space:2
Decision{{"Make Decision"}} right<["Yes"]>(right) Process1["Process A"]
downAgain<["No"]>(down) space r3<["Done"]>(down)
Process2["Process B"] r2<["Done"]>(right) End(("End"))
style Start fill:#969;
style End fill:#696;
```
These practical examples and scenarios underscore the utility of Mermaid block diagrams in simplifying and effectively communicating complex information across various domains.
The next section, 'Troubleshooting and Common Issues', will provide insights into resolving common challenges encountered when working with Mermaid block diagrams, ensuring a smooth diagramming experience.
## 8. Troubleshooting and Common Issues
Working with Mermaid block diagrams can sometimes present challenges, especially as the complexity of the diagrams increases. This section aims to provide guidance on resolving common issues and offers tips for managing more intricate diagram structures.
### Common Syntax Errors
Understanding and avoiding common syntax errors is key to a smooth experience with Mermaid diagrams.
#### Example - Incorrect Linking
A common mistake is incorrect linking syntax, which can lead to unexpected results or broken diagrams:
block-beta
A - B
**Correction**:
Ensure that links between blocks are correctly specified with arrows (--> or ---) to define the direction and type of connection. Also rememeber that one of the fundaments for block diagram is to give the author full control of where the boxes are positioned so in the example you need to add a space between the boxes:
```mermaid-example
block-beta
A space B
A --> B
```
```mermaid
block-beta
A space B
A --> B
```
#### Example - Misplaced Styling
Applying styles in the wrong context or with incorrect syntax can lead to blocks not being styled as intended:
```mermaid-example
block-beta
A
style A fill#969;
```
```mermaid
block-beta
A
style A fill#969;
```
**Correction:**
Correct the syntax by ensuring proper separation of style properties with commas and using the correct CSS property format:
```mermaid-example
block-beta
A
style A fill:#969,stroke:#333;
```
```mermaid
block-beta
A
style A fill:#969,stroke:#333;
```
### Tips for Complex Diagram Structures
Managing complexity in Mermaid diagrams involves planning and employing best practices.
#### Modular Design
Break down complex diagrams into smaller, more manageable components. This approach not only makes the diagram easier to understand but also simplifies the creation and maintenance process.
#### Consistent Styling
Use classes to maintain consistent styling across similar elements. This not only saves time but also ensures a cohesive and professional appearance.
#### Comments and Documentation
Use comments with `%%` within the Mermaid syntax to document the purpose of various parts of the diagram. This practice is invaluable for maintaining clarity, especially when working in teams or returning to a diagram after some time.
With these troubleshooting tips and best practices, you can effectively manage and resolve common issues in Mermaid block diagrams. The final section, 'Conclusion', will summarize the key points covered in this documentation and invite user feedback for continuous improvement.

View File

@@ -1134,7 +1134,19 @@ flowchart TD
B-->E(A fa:fa-camera-retro perhaps?) B-->E(A fa:fa-camera-retro perhaps?)
``` ```
Mermaid is compatible with Font Awesome up to version 5, Free icons only. Check that the icons you use are from the [supported set of icons](https://fontawesome.com/v5/search?o=r&m=free). Mermaid supports Font Awesome if the CSS is included on the website.
Mermaid does not have any restriction on the version of Font Awesome that can be used.
Please refer the [Official Font Awesome Documentation](https://fontawesome.com/start) on how to include it in your website.
Adding this snippet in the `<head>` would add support for Font Awesome v6.5.1
```html
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
rel="stylesheet"
/>
```
## Graph declarations with spaces between vertices and link and without semicolon ## Graph declarations with spaces between vertices and link and without semicolon

View File

@@ -114,7 +114,30 @@ gantt
Add another diagram to demo page :48h Add another diagram to demo page :48h
``` ```
It is possible to set multiple dependencies separated by space: Tasks are by default sequential. A task start date defaults to the end date of the preceding task.
A colon, `:`, separates the task title from its metadata.
Metadata items are separated by a comma, `,`. Valid tags are `active`, `done`, `crit`, and `milestone`. Tags are optional, but if used, they must be specified first.
After processing the tags, the remaining metadata items are interpreted as follows:
1. If a single item is specified, it determines when the task ends. It can either be a specific date/time or a duration. If a duration is specified, it is added to the start date of the task to determine the end date of the task, taking into account any exclusions.
2. If two items are specified, the last item is interpreted as in the previous case. The first item can either specify an explicit start date/time (in the format specified by `dateFormat`) or reference another task using `after <otherTaskID> [[otherTaskID2 [otherTaskID3]]...]`. In the latter case, the start date of the task will be set according to the latest end date of any referenced task.
3. If three items are specified, the last two will be interpreted as in the previous case. The first item will denote the ID of the task, which can be referenced using the `later <taskID>` syntax.
| Metadata syntax | Start date | End date | ID |
| ------------------------------------------ | --------------------------------------------------- | ------------------------------------------- | -------- |
| `<taskID>, <startDate>, <endDate>` | `startdate` as interpreted using `dateformat` | `endDate` as interpreted using `dateformat` | `taskID` |
| `<taskID>, <startDate>, <length>` | `startdate` as interpreted using `dateformat` | Start date + `length` | `taskID` |
| `<taskID>, after <otherTaskId>, <endDate>` | End date of previously specified task `otherTaskID` | `endDate` as interpreted using `dateformat` | `taskID` |
| `<taskID>, after <otherTaskId>, <length>` | End date of previously specified task `otherTaskID` | Start date + `length` | `taskID` |
| `<startDate>, <endDate>` | `startdate` as interpreted using `dateformat` | `enddate` as interpreted using `dateformat` | n/a |
| `<startDate>, <length>` | `startdate` as interpreted using `dateformat` | Start date + `length` | n/a |
| `after <otherTaskID>, <endDate>` | End date of previously specified task `otherTaskID` | `enddate` as interpreted using `dateformat` | n/a |
| `after <otherTaskID>, <length>` | End date of previously specified task `otherTaskID` | Start date + `length` | n/a |
| `<endDate>` | End date of preceding task | `enddate` as interpreted using `dateformat` | n/a |
| `<length>` | End date of preceding task | Start date + `length` | n/a |
For simplicity, the table does not show the use of multiple tasks listed with the `after` keyword. Here is an example of how to use it and how it's interpreted:
```mermaid-example ```mermaid-example
gantt gantt
@@ -420,11 +443,21 @@ mermaid.ganttConfig can be set to a JSON string with config parameters or the co
```javascript ```javascript
mermaid.ganttConfig = { mermaid.ganttConfig = {
titleTopMargin: 25, titleTopMargin: 25, // Margin top for the text over the diagram
barHeight: 20, barHeight: 20, // The height of the bars in the graph
barGap: 4, barGap: 4, // The margin between the different activities in the gantt diagram
topPadding: 75, topPadding: 75, // Margin between title and gantt diagram and between axis and gantt diagram.
sidePadding: 75, rightPadding: 75, // The space allocated for the section name to the right of the activities
leftPadding: 75, // The space allocated for the section name to the left of the activities
gridLineStartPadding: 10, // Vertical starting position of the grid lines
fontSize: 12, // Font size
sectionFontSize: 24, // Font size for sections
numberSectionStyles: 1, // The number of alternating section styles
axisFormat: '%d/%m', // Date/time format of the axis
tickInterval: '1 week', // Axis ticks
topAxis: true, // When this flag is set, date labels will be added to the top of the chart
displayMode: 'compact', // Turns compact mode on
weekday: 'sunday', // On which day a week-based interval should start
}; };
``` ```

View File

@@ -740,20 +740,22 @@ Styling of a sequence diagram is done by defining a number of css classes. Durin
### Classes used ### Classes used
| Class | Description | | Class | Description |
| ------------ | ----------------------------------------------------------- | | ------------ | -------------------------------------------------------------- |
| actor | Style for the actor box at the top of the diagram. | | actor | Styles for the actor box. |
| text.actor | Styles for text in the actor box at the top of the diagram. | | actor-top | Styles for the actor figure/ box at the top of the diagram. |
| actor-line | The vertical line for an actor. | | actor-bottom | Styles for the actor figure/ box at the bottom of the diagram. |
| messageLine0 | Styles for the solid message line. | | text.actor | Styles for text in the actor box. |
| messageLine1 | Styles for the dotted message line. | | actor-line | The vertical line for an actor. |
| messageText | Defines styles for the text on the message arrows. | | messageLine0 | Styles for the solid message line. |
| labelBox | Defines styles label to left in a loop. | | messageLine1 | Styles for the dotted message line. |
| labelText | Styles for the text in label for loops. | | messageText | Defines styles for the text on the message arrows. |
| loopText | Styles for the text in the loop box. | | labelBox | Defines styles label to left in a loop. |
| loopLine | Defines styles for the lines in the loop box. | | labelText | Styles for the text in label for loops. |
| note | Styles for the note box. | | loopText | Styles for the text in the loop box. |
| noteText | Styles for the text on in the note boxes. | | loopLine | Defines styles for the lines in the loop box. |
| note | Styles for the note box. |
| noteText | Styles for the text on in the note boxes. |
### Sample stylesheet ### Sample stylesheet

View File

@@ -163,11 +163,11 @@ timeline
timeline timeline
title MermaidChart 2023 Timeline title MermaidChart 2023 Timeline
section 2023 Q1 <br> Release Personal Tier section 2023 Q1 <br> Release Personal Tier
Buttet 1 : sub-point 1a : sub-point 1b Bullet 1 : sub-point 1a : sub-point 1b
: sub-point 1c : sub-point 1c
Bullet 2 : sub-point 2a : sub-point 2b Bullet 2 : sub-point 2a : sub-point 2b
section 2023 Q2 <br> Release XYZ Tier section 2023 Q2 <br> Release XYZ Tier
Buttet 3 : sub-point <br> 3a : sub-point 3b Bullet 3 : sub-point <br> 3a : sub-point 3b
: sub-point 3c : sub-point 3c
Bullet 4 : sub-point 4a : sub-point 4b Bullet 4 : sub-point 4a : sub-point 4b
``` ```
@@ -176,11 +176,11 @@ timeline
timeline timeline
title MermaidChart 2023 Timeline title MermaidChart 2023 Timeline
section 2023 Q1 <br> Release Personal Tier section 2023 Q1 <br> Release Personal Tier
Buttet 1 : sub-point 1a : sub-point 1b Bullet 1 : sub-point 1a : sub-point 1b
: sub-point 1c : sub-point 1c
Bullet 2 : sub-point 2a : sub-point 2b Bullet 2 : sub-point 2a : sub-point 2b
section 2023 Q2 <br> Release XYZ Tier section 2023 Q2 <br> Release XYZ Tier
Buttet 3 : sub-point <br> 3a : sub-point 3b Bullet 3 : sub-point <br> 3a : sub-point 3b
: sub-point 3c : sub-point 3c
Bullet 4 : sub-point 4a : sub-point 4b Bullet 4 : sub-point 4a : sub-point 4b
``` ```

View File

@@ -61,11 +61,11 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@applitools/eyes-cypress": "^3.33.1", "@applitools/eyes-cypress": "^3.40.6",
"@commitlint/cli": "^17.6.1", "@commitlint/cli": "^17.6.1",
"@commitlint/config-conventional": "^17.6.1", "@commitlint/config-conventional": "^17.6.1",
"@cspell/eslint-plugin": "^6.31.1", "@cspell/eslint-plugin": "^6.31.1",
"@cypress/code-coverage": "^3.10.7", "@cypress/code-coverage": "^3.12.18",
"@rollup/plugin-typescript": "^11.1.1", "@rollup/plugin-typescript": "^11.1.1",
"@types/cors": "^2.8.13", "@types/cors": "^2.8.13",
"@types/eslint": "^8.37.0", "@types/eslint": "^8.37.0",
@@ -74,7 +74,7 @@
"@types/jsdom": "^21.1.1", "@types/jsdom": "^21.1.1",
"@types/lodash": "^4.14.194", "@types/lodash": "^4.14.194",
"@types/mdast": "^3.0.11", "@types/mdast": "^3.0.11",
"@types/node": "^18.16.0", "@types/node": "^20.11.10",
"@types/prettier": "^2.7.2", "@types/prettier": "^2.7.2",
"@types/rollup-plugin-visualizer": "^4.2.1", "@types/rollup-plugin-visualizer": "^4.2.1",
"@typescript-eslint/eslint-plugin": "^6.7.2", "@typescript-eslint/eslint-plugin": "^6.7.2",
@@ -85,7 +85,7 @@
"ajv": "^8.12.0", "ajv": "^8.12.0",
"concurrently": "^8.0.1", "concurrently": "^8.0.1",
"cors": "^2.8.5", "cors": "^2.8.5",
"cypress": "^12.10.0", "cypress": "^12.17.4",
"cypress-image-snapshot": "^4.0.1", "cypress-image-snapshot": "^4.0.1",
"esbuild": "^0.19.0", "esbuild": "^0.19.0",
"eslint": "^8.47.0", "eslint": "^8.47.0",
@@ -122,10 +122,12 @@
"vite-plugin-istanbul": "^4.1.0", "vite-plugin-istanbul": "^4.1.0",
"vitest": "^0.34.0" "vitest": "^0.34.0"
}, },
"volta": {
"node": "18.19.0"
},
"nyc": { "nyc": {
"report-dir": "coverage/cypress" "report-dir": "coverage/cypress"
},
"pnpm": {
"patchedDependencies": {
"cytoscape@3.28.1": "patches/cytoscape@3.28.1.patch"
}
} }
} }

View File

@@ -39,15 +39,10 @@
}, },
"dependencies": { "dependencies": {
"@braintree/sanitize-url": "^6.0.1", "@braintree/sanitize-url": "^6.0.1",
"cytoscape": "^3.23.0",
"cytoscape-cose-bilkent": "^4.1.0",
"cytoscape-fcose": "^2.1.0",
"d3": "^7.0.0", "d3": "^7.0.0",
"khroma": "^2.0.0", "khroma": "^2.0.0"
"non-layered-tidy-tree-layout": "^2.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/cytoscape": "^3.19.9",
"concurrently": "^8.0.0", "concurrently": "^8.0.0",
"rimraf": "^5.0.0", "rimraf": "^5.0.0",
"mermaid": "workspace:*" "mermaid": "workspace:*"

View File

@@ -1,6 +1,6 @@
{ {
"name": "mermaid", "name": "mermaid",
"version": "10.7.0", "version": "10.8.0",
"description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", "description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module", "type": "module",
"module": "./dist/mermaid.core.mjs", "module": "./dist/mermaid.core.mjs",
@@ -62,9 +62,8 @@
"@braintree/sanitize-url": "^6.0.1", "@braintree/sanitize-url": "^6.0.1",
"@types/d3-scale": "^4.0.3", "@types/d3-scale": "^4.0.3",
"@types/d3-scale-chromatic": "^3.0.0", "@types/d3-scale-chromatic": "^3.0.0",
"cytoscape": "^3.23.0", "cytoscape": "^3.28.1",
"cytoscape-cose-bilkent": "^4.1.0", "cytoscape-cose-bilkent": "^4.1.0",
"cytoscape-fcose": "^2.1.0",
"d3": "^7.4.0", "d3": "^7.4.0",
"d3-sankey": "^0.12.3", "d3-sankey": "^0.12.3",
"dagre-d3-es": "7.0.10", "dagre-d3-es": "7.0.10",
@@ -122,8 +121,8 @@
"typescript": "^5.0.4", "typescript": "^5.0.4",
"unist-util-flatmap": "^1.0.0", "unist-util-flatmap": "^1.0.0",
"unist-util-visit": "^4.1.2", "unist-util-visit": "^4.1.2",
"vitepress": "^1.0.0-alpha.72", "vitepress": "^1.0.0-rc.40",
"vitepress-plugin-search": "^1.0.4-alpha.20" "vitepress-plugin-search": "^1.0.4-alpha.22"
}, },
"files": [ "files": [
"dist/", "dist/",

View File

@@ -60,13 +60,11 @@ const CDN_URL = 'https://cdn.jsdelivr.net/npm'; // 'https://unpkg.com';
const MERMAID_KEYWORD = 'mermaid'; const MERMAID_KEYWORD = 'mermaid';
const MERMAID_CODE_ONLY_KEYWORD = 'mermaid-example'; const MERMAID_CODE_ONLY_KEYWORD = 'mermaid-example';
const MERMAID_DIAGRAM_ONLY = 'mermaid-nocode';
// These keywords will produce both a mermaid diagram and a code block with the diagram source // These keywords will produce both a mermaid diagram and a code block with the diagram source
const MERMAID_EXAMPLE_KEYWORDS = [MERMAID_KEYWORD, 'mmd', MERMAID_CODE_ONLY_KEYWORD]; // 'mmd' is an old keyword that used to be used const MERMAID_EXAMPLE_KEYWORDS = [MERMAID_KEYWORD, 'mmd', MERMAID_CODE_ONLY_KEYWORD]; // 'mmd' is an old keyword that used to be used
// This keyword will only produce a mermaid diagram
const MERMAID_DIAGRAM_ONLY = 'mermaid-nocode';
// These will be transformed into block quotes // These will be transformed into block quotes
const BLOCK_QUOTE_KEYWORDS = ['note', 'tip', 'warning', 'danger']; const BLOCK_QUOTE_KEYWORDS = ['note', 'tip', 'warning', 'danger'];

View File

@@ -161,10 +161,20 @@ export interface MermaidConfig {
gitGraph?: GitGraphDiagramConfig; gitGraph?: GitGraphDiagramConfig;
c4?: C4DiagramConfig; c4?: C4DiagramConfig;
sankey?: SankeyDiagramConfig; sankey?: SankeyDiagramConfig;
block?: BlockDiagramConfig;
dompurifyConfig?: DOMPurifyConfiguration; dompurifyConfig?: DOMPurifyConfiguration;
wrap?: boolean; wrap?: boolean;
fontSize?: number; fontSize?: number;
} }
/**
* The object containing configurations specific for block diagrams.
*
* This interface was referenced by `MermaidConfig`'s JSON-Schema
* via the `definition` "BlockDiagramConfig".
*/
export interface BlockDiagramConfig extends BaseDiagramConfig {
padding?: number;
}
/** /**
* This interface was referenced by `MermaidConfig`'s JSON-Schema * This interface was referenced by `MermaidConfig`'s JSON-Schema
* via the `definition` "BaseDiagramConfig". * via the `definition` "BaseDiagramConfig".
@@ -576,6 +586,7 @@ export interface GitGraphDiagramConfig extends BaseDiagramConfig {
showCommitLabel?: boolean; showCommitLabel?: boolean;
showBranches?: boolean; showBranches?: boolean;
rotateCommitLabel?: boolean; rotateCommitLabel?: boolean;
parallelCommits?: boolean;
/** /**
* Controls whether or arrow markers in html code are absolute paths or anchors. * Controls whether or arrow markers in html code are absolute paths or anchors.
* This matters if you are using base tag settings. * This matters if you are using base tag settings.
@@ -1416,6 +1427,14 @@ export interface FlowchartDiagramConfig extends BaseDiagramConfig {
* Margin top for the text over the diagram * Margin top for the text over the diagram
*/ */
titleTopMargin?: number; titleTopMargin?: number;
/**
* Defines a top/bottom margin for subgraph titles
*
*/
subGraphTitleMargin?: {
top?: number;
bottom?: number;
};
arrowMarkerAbsolute?: boolean; arrowMarkerAbsolute?: boolean;
/** /**
* The amount of padding around the diagram as a whole so that embedded * The amount of padding around the diagram as a whole so that embedded

View File

@@ -0,0 +1,248 @@
import type { Direction } from '../../src/diagrams/block/blockTypes.js';
const expandAndDeduplicateDirections = (directions: Direction[]) => {
const uniqueDirections = new Set();
for (const direction of directions) {
switch (direction) {
case 'x':
uniqueDirections.add('right');
uniqueDirections.add('left');
break;
case 'y':
uniqueDirections.add('up');
uniqueDirections.add('down');
break;
default:
uniqueDirections.add(direction);
break;
}
}
return uniqueDirections;
};
export const getArrowPoints = (
duplicatedDirections: Direction[],
bbox: { width: number; height: number },
node: any
) => {
// Expand and deduplicate the provided directions.
// for instance: x, right => right, left
const directions = expandAndDeduplicateDirections(duplicatedDirections);
// Factor to divide height for some calculations.
const f = 2;
// Calculated height of the bounding box, accounting for node padding.
const height = bbox.height + 2 * node.padding;
// Midpoint calculation based on height.
const midpoint = height / f;
// Calculated width of the bounding box, accounting for additional width and node padding.
const width = bbox.width + 2 * midpoint + node.padding;
// Padding to use, half of the node padding.
const padding = node.padding / 2;
// Initialize an empty array to store points for the arrow.
const points = [];
if (
directions.has('right') &&
directions.has('left') &&
directions.has('up') &&
directions.has('down')
) {
// SQUARE
return [
// Bottom
{ x: 0, y: 0 },
{ x: midpoint, y: 0 },
{ x: width / 2, y: 2 * padding },
{ x: width - midpoint, y: 0 },
{ x: width, y: 0 },
// Right
{ x: width, y: -height / 3 },
{ x: width + 2 * padding, y: -height / 2 },
{ x: width, y: (-2 * height) / 3 },
{ x: width, y: -height },
// Top
{ x: width - midpoint, y: -height },
{ x: width / 2, y: -height - 2 * padding },
{ x: midpoint, y: -height },
// Left
{ x: 0, y: -height },
{ x: 0, y: (-2 * height) / 3 },
{ x: -2 * padding, y: -height / 2 },
{ x: 0, y: -height / 3 },
];
}
if (directions.has('right') && directions.has('left') && directions.has('up')) {
// RECTANGLE_VERTICAL (Top Open)
return [
{ x: midpoint, y: 0 },
{ x: width - midpoint, y: 0 },
{ x: width, y: -height / 2 },
{ x: width - midpoint, y: -height },
{ x: midpoint, y: -height },
{ x: 0, y: -height / 2 },
];
}
if (directions.has('right') && directions.has('left') && directions.has('down')) {
// RECTANGLE_VERTICAL (Bottom Open)
return [
{ x: 0, y: 0 },
{ x: midpoint, y: -height },
{ x: width - midpoint, y: -height },
{ x: width, y: 0 },
];
}
if (directions.has('right') && directions.has('up') && directions.has('down')) {
// RECTANGLE_HORIZONTAL (Right Open)
return [
{ x: 0, y: 0 },
{ x: width, y: -midpoint },
{ x: width, y: -height + midpoint },
{ x: 0, y: -height },
];
}
if (directions.has('left') && directions.has('up') && directions.has('down')) {
// RECTANGLE_HORIZONTAL (Left Open)
return [
{ x: width, y: 0 },
{ x: 0, y: -midpoint },
{ x: 0, y: -height + midpoint },
{ x: width, y: -height },
];
}
if (directions.has('right') && directions.has('left')) {
// HORIZONTAL_LINE
return [
{ x: midpoint, y: 0 },
{ x: midpoint, y: -padding },
{ x: width - midpoint, y: -padding },
{ x: width - midpoint, y: 0 },
{ x: width, y: -height / 2 },
{ x: width - midpoint, y: -height },
{ x: width - midpoint, y: -height + padding },
{ x: midpoint, y: -height + padding },
{ x: midpoint, y: -height },
{ x: 0, y: -height / 2 },
];
}
if (directions.has('up') && directions.has('down')) {
// VERTICAL_LINE
return [
// Bottom center
{ x: width / 2, y: 0 },
// Left pont of bottom arrow
{ x: 0, y: -padding },
{ x: midpoint, y: -padding },
// Left top over vertical section
{ x: midpoint, y: -height + padding },
{ x: 0, y: -height + padding },
// Top of arrow
{ x: width / 2, y: -height },
{ x: width, y: -height + padding },
// Top of right vertical bar
{ x: width - midpoint, y: -height + padding },
{ x: width - midpoint, y: -padding },
{ x: width, y: -padding },
];
}
if (directions.has('right') && directions.has('up')) {
// ANGLE_RT
return [
{ x: 0, y: 0 },
{ x: width, y: -midpoint },
{ x: 0, y: -height },
];
}
if (directions.has('right') && directions.has('down')) {
// ANGLE_RB
return [
{ x: 0, y: 0 },
{ x: width, y: 0 },
{ x: 0, y: -height },
];
}
if (directions.has('left') && directions.has('up')) {
// ANGLE_LT
return [
{ x: width, y: 0 },
{ x: 0, y: -midpoint },
{ x: width, y: -height },
];
}
if (directions.has('left') && directions.has('down')) {
// ANGLE_LB
return [
{ x: width, y: 0 },
{ x: 0, y: 0 },
{ x: width, y: -height },
];
}
if (directions.has('right')) {
// ARROW_RIGHT
return [
{ x: midpoint, y: -padding },
{ x: midpoint, y: -padding },
{ x: width - midpoint, y: -padding },
{ x: width - midpoint, y: 0 },
{ x: width, y: -height / 2 },
{ x: width - midpoint, y: -height },
{ x: width - midpoint, y: -height + padding },
// top left corner of arrow
{ x: midpoint, y: -height + padding },
{ x: midpoint, y: -height + padding },
];
}
if (directions.has('left')) {
// ARROW_LEFT
return [
{ x: midpoint, y: 0 },
{ x: midpoint, y: -padding },
// Two points, the right corners
{ x: width - midpoint, y: -padding },
{ x: width - midpoint, y: -height + padding },
{ x: midpoint, y: -height + padding },
{ x: midpoint, y: -height },
{ x: 0, y: -height / 2 },
];
}
if (directions.has('up')) {
// ARROW_TOP
return [
// Bottom center
{ x: midpoint, y: -padding },
// Left top over vertical section
{ x: midpoint, y: -height + padding },
{ x: 0, y: -height + padding },
// Top of arrow
{ x: width / 2, y: -height },
{ x: width, y: -height + padding },
// Top of right vertical bar
{ x: width - midpoint, y: -height + padding },
{ x: width - midpoint, y: -padding },
];
}
if (directions.has('down')) {
// ARROW_BOTTOM
return [
// Bottom center
{ x: width / 2, y: 0 },
// Left pont of bottom arrow
{ x: 0, y: -padding },
{ x: midpoint, y: -padding },
// Left top over vertical section
{ x: midpoint, y: -height + padding },
{ x: width - midpoint, y: -height + padding },
{ x: width - midpoint, y: -padding },
{ x: width, y: -padding },
];
}
// POINT
return [{ x: 0, y: 0 }];
};

View File

@@ -5,9 +5,11 @@ import { createText } from '../rendering-util/createText.js';
import { select } from 'd3'; import { select } from 'd3';
import { getConfig } from '../diagram-api/diagramAPI.js'; import { getConfig } from '../diagram-api/diagramAPI.js';
import { evaluate } from '../diagrams/common/common.js'; import { evaluate } from '../diagrams/common/common.js';
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';
const rect = (parent, node) => { const rect = (parent, node) => {
log.info('Creating subgraph rect for ', node.id, node); log.info('Creating subgraph rect for ', node.id, node);
const siteConfig = getConfig();
// Add outer g element // Add outer g element
const shapeSvg = parent const shapeSvg = parent
@@ -18,7 +20,7 @@ const rect = (parent, node) => {
// add the rect // add the rect
const rect = shapeSvg.insert('rect', ':first-child'); const rect = shapeSvg.insert('rect', ':first-child');
const useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels); const useHtmlLabels = evaluate(siteConfig.flowchart.htmlLabels);
// Create the label and insert it after the rect // Create the label and insert it after the rect
const label = shapeSvg.insert('g').attr('class', 'cluster-label'); const label = shapeSvg.insert('g').attr('class', 'cluster-label');
@@ -34,7 +36,7 @@ const rect = (parent, node) => {
// Get the size of the label // Get the size of the label
let bbox = text.getBBox(); let bbox = text.getBBox();
if (evaluate(getConfig().flowchart.htmlLabels)) { if (evaluate(siteConfig.flowchart.htmlLabels)) {
const div = text.children[0]; const div = text.children[0];
const dv = select(text); const dv = select(text);
bbox = div.getBoundingClientRect(); bbox = div.getBoundingClientRect();
@@ -63,17 +65,18 @@ const rect = (parent, node) => {
.attr('width', width) .attr('width', width)
.attr('height', node.height + padding); .attr('height', node.height + padding);
const { subGraphTitleTopMargin } = getSubGraphTitleMargins(siteConfig);
if (useHtmlLabels) { if (useHtmlLabels) {
label.attr( label.attr(
'transform', 'transform',
// This puts the labal on top of the box instead of inside it // This puts the labal on top of the box instead of inside it
'translate(' + (node.x - bbox.width / 2) + ', ' + (node.y - node.height / 2) + ')' `translate(${node.x - bbox.width / 2}, ${node.y - node.height / 2 + subGraphTitleTopMargin})`
); );
} else { } else {
label.attr( label.attr(
'transform', 'transform',
// This puts the labal on top of the box instead of inside it // This puts the labal on top of the box instead of inside it
'translate(' + node.x + ', ' + (node.y - node.height / 2) + ')' `translate(${node.x}, ${node.y - node.height / 2 + subGraphTitleTopMargin})`
); );
} }
// Center the label // Center the label
@@ -127,6 +130,8 @@ const noteGroup = (parent, node) => {
return shapeSvg; return shapeSvg;
}; };
const roundedWithTitle = (parent, node) => { const roundedWithTitle = (parent, node) => {
const siteConfig = getConfig();
// Add outer g element // Add outer g element
const shapeSvg = parent.insert('g').attr('class', node.classes).attr('id', node.id); const shapeSvg = parent.insert('g').attr('class', node.classes).attr('id', node.id);
@@ -143,7 +148,7 @@ const roundedWithTitle = (parent, node) => {
// Get the size of the label // Get the size of the label
let bbox = text.getBBox(); let bbox = text.getBBox();
if (evaluate(getConfig().flowchart.htmlLabels)) { if (evaluate(siteConfig.flowchart.htmlLabels)) {
const div = text.children[0]; const div = text.children[0];
const dv = select(text); const dv = select(text);
bbox = div.getBoundingClientRect(); bbox = div.getBoundingClientRect();
@@ -175,17 +180,17 @@ const roundedWithTitle = (parent, node) => {
.attr('width', width + padding) .attr('width', width + padding)
.attr('height', node.height + padding - bbox.height - 3); .attr('height', node.height + padding - bbox.height - 3);
const { subGraphTitleTopMargin } = getSubGraphTitleMargins(siteConfig);
// Center the label // Center the label
label.attr( label.attr(
'transform', 'transform',
'translate(' + `translate(${node.x - bbox.width / 2}, ${
(node.x - bbox.width / 2) + node.y -
', ' + node.height / 2 -
(node.y - node.padding / 3 +
node.height / 2 - (evaluate(siteConfig.flowchart.htmlLabels) ? 5 : 3) +
node.padding / 3 + subGraphTitleTopMargin
(evaluate(getConfig().flowchart.htmlLabels) ? 5 : 3)) + })`
')'
); );
const rectBox = rect.node().getBBox(); const rectBox = rect.node().getBBox();

View File

@@ -56,7 +56,7 @@ const createLabel = (_vertexText, style, isTitle, isNode) => {
if (evaluate(getConfig().flowchart.htmlLabels)) { if (evaluate(getConfig().flowchart.htmlLabels)) {
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that? // TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
vertexText = vertexText.replace(/\\n|\n/g, '<br />'); vertexText = vertexText.replace(/\\n|\n/g, '<br />');
log.info('vertexText' + vertexText); log.debug('vertexText' + vertexText);
const node = { const node = {
isNode, isNode,
label: decodeEntities(vertexText).replace( label: decodeEntities(vertexText).replace(

View File

@@ -6,6 +6,7 @@ import { getConfig } from '../diagram-api/diagramAPI.js';
import utils from '../utils.js'; import utils from '../utils.js';
import { evaluate } from '../diagrams/common/common.js'; import { evaluate } from '../diagrams/common/common.js';
import { getLineFunctionsWithOffset } from '../utils/lineWithOffset.js'; import { getLineFunctionsWithOffset } from '../utils/lineWithOffset.js';
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';
import { addEdgeMarkers } from './edgeMarker.js'; import { addEdgeMarkers } from './edgeMarker.js';
let edgeLabels = {}; let edgeLabels = {};
@@ -27,7 +28,6 @@ export const insertEdgeLabel = (elem, edge) => {
addSvgBackground: true, addSvgBackground: true,
}) })
: createLabel(edge.label, edge.labelStyle); : createLabel(edge.label, edge.labelStyle);
log.info('abc82', edge, edge.labelType);
// Create outer g, edgeLabel, this will be positioned after graph layout // Create outer g, edgeLabel, this will be positioned after graph layout
const edgeLabel = elem.insert('g').attr('class', 'edgeLabel'); const edgeLabel = elem.insert('g').attr('class', 'edgeLabel');
@@ -134,8 +134,10 @@ function setTerminalWidth(fo, value) {
} }
export const positionEdgeLabel = (edge, paths) => { export const positionEdgeLabel = (edge, paths) => {
log.info('Moving label abc78 ', edge.id, edge.label, edgeLabels[edge.id]); log.debug('Moving label abc88 ', edge.id, edge.label, edgeLabels[edge.id], paths);
let path = paths.updatedPath ? paths.updatedPath : paths.originalPath; let path = paths.updatedPath ? paths.updatedPath : paths.originalPath;
const siteConfig = getConfig();
const { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
if (edge.label) { if (edge.label) {
const el = edgeLabels[edge.id]; const el = edgeLabels[edge.id];
let x = edge.x; let x = edge.x;
@@ -143,7 +145,7 @@ export const positionEdgeLabel = (edge, paths) => {
if (path) { if (path) {
// // debugger; // // debugger;
const pos = utils.calcLabelPosition(path); const pos = utils.calcLabelPosition(path);
log.info( log.debug(
'Moving label ' + edge.label + ' from (', 'Moving label ' + edge.label + ' from (',
x, x,
',', ',',
@@ -152,14 +154,14 @@ export const positionEdgeLabel = (edge, paths) => {
pos.x, pos.x,
',', ',',
pos.y, pos.y,
') abc78' ') abc88'
); );
if (paths.updatedPath) { if (paths.updatedPath) {
x = pos.x; x = pos.x;
y = pos.y; y = pos.y;
} }
} }
el.attr('transform', 'translate(' + x + ', ' + y + ')'); el.attr('transform', `translate(${x}, ${y + subGraphTitleTotalMargin / 2})`);
} }
//let path = paths.updatedPath ? paths.updatedPath : paths.originalPath; //let path = paths.updatedPath ? paths.updatedPath : paths.originalPath;
@@ -173,7 +175,7 @@ export const positionEdgeLabel = (edge, paths) => {
x = pos.x; x = pos.x;
y = pos.y; y = pos.y;
} }
el.attr('transform', 'translate(' + x + ', ' + y + ')'); el.attr('transform', `translate(${x}, ${y})`);
} }
if (edge.startLabelRight) { if (edge.startLabelRight) {
const el = terminalLabels[edge.id].startRight; const el = terminalLabels[edge.id].startRight;
@@ -189,7 +191,7 @@ export const positionEdgeLabel = (edge, paths) => {
x = pos.x; x = pos.x;
y = pos.y; y = pos.y;
} }
el.attr('transform', 'translate(' + x + ', ' + y + ')'); el.attr('transform', `translate(${x}, ${y})`);
} }
if (edge.endLabelLeft) { if (edge.endLabelLeft) {
const el = terminalLabels[edge.id].endLeft; const el = terminalLabels[edge.id].endLeft;
@@ -201,7 +203,7 @@ export const positionEdgeLabel = (edge, paths) => {
x = pos.x; x = pos.x;
y = pos.y; y = pos.y;
} }
el.attr('transform', 'translate(' + x + ', ' + y + ')'); el.attr('transform', `translate(${x}, ${y})`);
} }
if (edge.endLabelRight) { if (edge.endLabelRight) {
const el = terminalLabels[edge.id].endRight; const el = terminalLabels[edge.id].endRight;
@@ -213,12 +215,11 @@ export const positionEdgeLabel = (edge, paths) => {
x = pos.x; x = pos.x;
y = pos.y; y = pos.y;
} }
el.attr('transform', 'translate(' + x + ', ' + y + ')'); el.attr('transform', `translate(${x}, ${y})`);
} }
}; };
const outsideNode = (node, point) => { const outsideNode = (node, point) => {
// log.warn('Checking bounds ', node, point);
const x = node.x; const x = node.x;
const y = node.y; const y = node.y;
const dx = Math.abs(point.x - x); const dx = Math.abs(point.x - x);
@@ -232,7 +233,7 @@ const outsideNode = (node, point) => {
}; };
export const intersection = (node, outsidePoint, insidePoint) => { export const intersection = (node, outsidePoint, insidePoint) => {
log.warn(`intersection calc abc89: log.debug(`intersection calc abc89:
outsidePoint: ${JSON.stringify(outsidePoint)} outsidePoint: ${JSON.stringify(outsidePoint)}
insidePoint : ${JSON.stringify(insidePoint)} insidePoint : ${JSON.stringify(insidePoint)}
node : x:${node.x} y:${node.y} w:${node.width} h:${node.height}`); node : x:${node.x} y:${node.y} w:${node.width} h:${node.height}`);
@@ -245,29 +246,11 @@ export const intersection = (node, outsidePoint, insidePoint) => {
let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx; let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;
const h = node.height / 2; const h = node.height / 2;
// const edges = {
// x1: x - w,
// x2: x + w,
// y1: y - h,
// y2: y + h
// };
// if (
// outsidePoint.x === edges.x1 ||
// outsidePoint.x === edges.x2 ||
// outsidePoint.y === edges.y1 ||
// outsidePoint.y === edges.y2
// ) {
// log.warn('abc89 calc equals on edge', outsidePoint, edges);
// return outsidePoint;
// }
const Q = Math.abs(outsidePoint.y - insidePoint.y); const Q = Math.abs(outsidePoint.y - insidePoint.y);
const R = Math.abs(outsidePoint.x - insidePoint.x); const R = Math.abs(outsidePoint.x - insidePoint.x);
// log.warn();
if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h) { if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h) {
// Intersection is top or bottom of rect. // Intersection is top or bottom of rect.
// let q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
let q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y; let q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
r = (R * q) / Q; r = (R * q) / Q;
const res = { const res = {
@@ -286,7 +269,7 @@ export const intersection = (node, outsidePoint, insidePoint) => {
res.y = outsidePoint.y; res.y = outsidePoint.y;
} }
log.warn(`abc89 topp/bott calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, res); log.debug(`abc89 topp/bott calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, res);
return res; return res;
} else { } else {
@@ -303,7 +286,7 @@ export const intersection = (node, outsidePoint, insidePoint) => {
let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - R + 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 _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;
let _y = insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q; let _y = insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q;
log.warn(`sides calc abc89, Q ${Q}, q ${q}, R ${R}, r ${r}`, { _x, _y }); log.debug(`sides calc abc89, Q ${Q}, q ${q}, R ${R}, r ${r}`, { _x, _y });
if (r === 0) { if (r === 0) {
_x = outsidePoint.x; _x = outsidePoint.x;
_y = outsidePoint.y; _y = outsidePoint.y;
@@ -327,21 +310,16 @@ export const intersection = (node, outsidePoint, insidePoint) => {
* @returns {Array} Points * @returns {Array} Points
*/ */
const cutPathAtIntersect = (_points, boundryNode) => { const cutPathAtIntersect = (_points, boundryNode) => {
log.warn('abc88 cutPathAtIntersect', _points, boundryNode); log.debug('abc88 cutPathAtIntersect', _points, boundryNode);
let points = []; let points = [];
let lastPointOutside = _points[0]; let lastPointOutside = _points[0];
let isInside = false; let isInside = false;
_points.forEach((point) => { _points.forEach((point) => {
// const node = clusterDb[edge.toCluster].node;
log.info('abc88 checking point', point, boundryNode);
// check if point is inside the boundary rect // check if point is inside the boundary rect
if (!outsideNode(boundryNode, point) && !isInside) { if (!outsideNode(boundryNode, point) && !isInside) {
// First point inside the rect found // First point inside the rect found
// Calc the intersection coord between the point anf the last point outside the rect // Calc the intersection coord between the point anf the last point outside the rect
const inter = intersection(boundryNode, lastPointOutside, point); const inter = intersection(boundryNode, lastPointOutside, point);
log.warn('abc88 inside', point, lastPointOutside, inter);
log.warn('abc88 intersection', inter);
// // Check case where the intersection is the same as the last point // // Check case where the intersection is the same as the last point
let pointPresent = false; let pointPresent = false;
@@ -351,14 +329,11 @@ const cutPathAtIntersect = (_points, boundryNode) => {
// // if (!pointPresent) { // // if (!pointPresent) {
if (!points.some((e) => e.x === inter.x && e.y === inter.y)) { if (!points.some((e) => e.x === inter.x && e.y === inter.y)) {
points.push(inter); points.push(inter);
} else {
log.warn('abc88 no intersect', inter, points);
} }
// points.push(inter);
isInside = true; isInside = true;
} else { } else {
// Outside // Outside
log.warn('abc88 outside', point, lastPointOutside);
lastPointOutside = point; lastPointOutside = point;
// points.push(point); // points.push(point);
if (!isInside) { if (!isInside) {
@@ -366,67 +341,31 @@ const cutPathAtIntersect = (_points, boundryNode) => {
} }
} }
}); });
log.warn('abc88 returning points', points);
return points; return points;
}; };
export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph, id) { export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph, id) {
let points = edge.points; let points = edge.points;
log.debug('abc88 InsertEdge: edge=', edge, 'e=', e);
let pointsHasChanged = false; let pointsHasChanged = false;
const tail = graph.node(e.v); const tail = graph.node(e.v);
var head = graph.node(e.w); var head = graph.node(e.w);
log.info('abc88 InsertEdge: ', edge); if (head?.intersect && tail?.intersect) {
if (head.intersect && tail.intersect) {
points = points.slice(1, edge.points.length - 1); points = points.slice(1, edge.points.length - 1);
points.unshift(tail.intersect(points[0])); points.unshift(tail.intersect(points[0]));
log.info(
'Last point',
points[points.length - 1],
head,
head.intersect(points[points.length - 1])
);
points.push(head.intersect(points[points.length - 1])); points.push(head.intersect(points[points.length - 1]));
} }
if (edge.toCluster) { if (edge.toCluster) {
log.info('to cluster abc88', clusterDb[edge.toCluster]); log.debug('to cluster abc88', clusterDb[edge.toCluster]);
points = cutPathAtIntersect(edge.points, clusterDb[edge.toCluster].node); points = cutPathAtIntersect(edge.points, clusterDb[edge.toCluster].node);
// log.trace('edge', edge);
// points = [];
// let lastPointOutside; // = edge.points[0];
// let isInside = false;
// edge.points.forEach(point => {
// const node = clusterDb[edge.toCluster].node;
// log.warn('checking from', edge.fromCluster, point, node);
// if (!outsideNode(node, point) && !isInside) {
// log.trace('inside', edge.toCluster, point, lastPointOutside);
// // First point inside the rect
// const inter = intersection(node, lastPointOutside, point);
// let pointPresent = false;
// points.forEach(p => {
// pointPresent = pointPresent || (p.x === inter.x && p.y === inter.y);
// });
// // if (!pointPresent) {
// if (!points.find(e => e.x === inter.x && e.y === inter.y)) {
// points.push(inter);
// } else {
// log.warn('no intersect', inter, points);
// }
// isInside = true;
// } else {
// // outside
// lastPointOutside = point;
// if (!isInside) points.push(point);
// }
// });
pointsHasChanged = true; pointsHasChanged = true;
} }
if (edge.fromCluster) { if (edge.fromCluster) {
log.info('from cluster abc88', clusterDb[edge.fromCluster]); log.debug('from cluster abc88', clusterDb[edge.fromCluster]);
points = cutPathAtIntersect(points.reverse(), clusterDb[edge.fromCluster].node).reverse(); points = cutPathAtIntersect(points.reverse(), clusterDb[edge.fromCluster].node).reverse();
pointsHasChanged = true; pointsHasChanged = true;
@@ -504,8 +443,6 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
url = url.replace(/\(/g, '\\('); url = url.replace(/\(/g, '\\(');
url = url.replace(/\)/g, '\\)'); url = url.replace(/\)/g, '\\)');
} }
log.info('arrowTypeStart', edge.arrowTypeStart);
log.info('arrowTypeEnd', edge.arrowTypeEnd);
addEdgeMarkers(svgPath, edge, url, id, diagramType); addEdgeMarkers(svgPath, edge, url, id, diagramType);

View File

@@ -13,8 +13,10 @@ import { insertNode, positionNode, clear as clearNodes, setNodeElem } from './no
import { insertCluster, clear as clearClusters } from './clusters.js'; import { insertCluster, clear as clearClusters } from './clusters.js';
import { insertEdgeLabel, positionEdgeLabel, insertEdge, clear as clearEdges } from './edges.js'; import { insertEdgeLabel, positionEdgeLabel, insertEdge, clear as clearEdges } from './edges.js';
import { log } from '../logger.js'; import { log } from '../logger.js';
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';
import { getConfig } from '../diagram-api/diagramAPI.js';
const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster) => { const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster, siteConfig) => {
log.info('Graph in recursive render: XXX', graphlibJson.write(graph), parentCluster); log.info('Graph in recursive render: XXX', graphlibJson.write(graph), parentCluster);
const dir = graph.graph().rankdir; const dir = graph.graph().rankdir;
log.trace('Dir in recursive render - dir:', dir); log.trace('Dir in recursive render - dir:', dir);
@@ -52,7 +54,14 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster) =>
if (node && node.clusterNode) { if (node && node.clusterNode) {
// const children = graph.children(v); // const children = graph.children(v);
log.info('Cluster identified', v, node.width, graph.node(v)); log.info('Cluster identified', v, node.width, graph.node(v));
const o = await recursiveRender(nodes, node.graph, diagramtype, id, graph.node(v)); const o = await recursiveRender(
nodes,
node.graph,
diagramtype,
id,
graph.node(v),
siteConfig
);
const newEl = o.elem; const newEl = o.elem;
updateNodeBounds(node, newEl); updateNodeBounds(node, newEl);
node.diff = o.diff || 0; node.diff = o.diff || 0;
@@ -101,6 +110,7 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster) =>
log.info('Graph after layout:', graphlibJson.write(graph)); log.info('Graph after layout:', graphlibJson.write(graph));
// Move the nodes to the correct place // Move the nodes to the correct place
let diff = 0; let diff = 0;
const { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
sortNodesByHierarchy(graph).forEach(function (v) { sortNodesByHierarchy(graph).forEach(function (v) {
const node = graph.node(v); const node = graph.node(v);
log.info('Position ' + v + ': ' + JSON.stringify(graph.node(v))); log.info('Position ' + v + ': ' + JSON.stringify(graph.node(v)));
@@ -114,16 +124,18 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster) =>
); );
if (node && node.clusterNode) { if (node && node.clusterNode) {
// clusterDb[node.id].node = node; // clusterDb[node.id].node = node;
node.y += subGraphTitleTotalMargin;
positionNode(node); positionNode(node);
} else { } else {
// Non cluster node // Non cluster node
if (graph.children(v).length > 0) { if (graph.children(v).length > 0) {
// A cluster in the non-recursive way // A cluster in the non-recursive way
// positionCluster(node); // positionCluster(node);
node.height += subGraphTitleTotalMargin;
insertCluster(clusters, node); insertCluster(clusters, node);
clusterDb[node.id].node = node; clusterDb[node.id].node = node;
} else { } else {
node.y += subGraphTitleTotalMargin / 2;
positionNode(node); positionNode(node);
} }
} }
@@ -134,6 +146,7 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster) =>
const edge = graph.edge(e); const edge = graph.edge(e);
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge); log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);
edge.points.forEach((point) => (point.y += subGraphTitleTotalMargin / 2));
const paths = insertEdge(edgePaths, e, edge, clusterDb, diagramtype, graph, id); const paths = insertEdge(edgePaths, e, edge, clusterDb, diagramtype, graph, id);
positionEdgeLabel(edge, paths); positionEdgeLabel(edge, paths);
}); });
@@ -159,7 +172,8 @@ export const render = async (elem, graph, markers, diagramtype, id) => {
adjustClustersAndEdges(graph); adjustClustersAndEdges(graph);
log.warn('Graph after:', JSON.stringify(graphlibJson.write(graph))); log.warn('Graph after:', JSON.stringify(graphlibJson.write(graph)));
// log.warn('Graph ever after:', graphlibJson.write(graph.node('A').graph)); // log.warn('Graph ever after:', graphlibJson.write(graph.node('A').graph));
await recursiveRender(elem, graph, diagramtype, id); const siteConfig = getConfig();
await recursiveRender(elem, graph, diagramtype, id, undefined, siteConfig);
}; };
// const shapeDefinitions = {}; // const shapeDefinitions = {};

View File

@@ -254,6 +254,16 @@ export const adjustClustersAndEdges = (graph, depth) => {
} }
}); });
for (let id of Object.keys(clusterDb)) {
const nonClusterChild = clusterDb[id].id;
const parent = graph.parent(nonClusterChild);
// Change replacement node of id to parent of current replacement node if valid
if (parent !== id && clusterDb[parent] && !clusterDb[parent].externalConnections) {
clusterDb[id].id = parent;
}
}
// For clusters with incoming and/or outgoing edges translate those edges to a real node // For clusters with incoming and/or outgoing edges translate those edges to a real node
// in the cluster in order to fake the edge // in the cluster in order to fake the edge
graph.edges().forEach(function (e) { graph.edges().forEach(function (e) {
@@ -307,9 +317,13 @@ export const adjustClustersAndEdges = (graph, depth) => {
w = getAnchorId(e.w); w = getAnchorId(e.w);
graph.removeEdge(e.v, e.w, e.name); graph.removeEdge(e.v, e.w, e.name);
if (v !== e.v) { if (v !== e.v) {
const parent = graph.parent(v);
clusterDb[parent].externalConnections = true;
edge.fromCluster = e.v; edge.fromCluster = e.v;
} }
if (w !== e.w) { if (w !== e.w) {
const parent = graph.parent(w);
clusterDb[parent].externalConnections = true;
edge.toCluster = e.w; edge.toCluster = e.w;
} }
log.warn('Fix Replacing with XXX', v, w, e.name); log.warn('Fix Replacing with XXX', v, w, e.name);

View File

@@ -6,6 +6,7 @@ import intersect from './intersect/index.js';
import createLabel from './createLabel.js'; import createLabel from './createLabel.js';
import note from './shapes/note.js'; import note from './shapes/note.js';
import { evaluate } from '../diagrams/common/common.js'; import { evaluate } from '../diagrams/common/common.js';
import { getArrowPoints } from './blockArrowHelper.js';
const formatClass = (str) => { const formatClass = (str) => {
if (str) { if (str) {
@@ -30,6 +31,7 @@ const question = async (parent, node) => {
const w = bbox.width + node.padding; const w = bbox.width + node.padding;
const h = bbox.height + node.padding; const h = bbox.height + node.padding;
const s = w + h; const s = w + h;
const points = [ const points = [
{ x: s / 2, y: 0 }, { x: s / 2, y: 0 },
{ x: s, y: -s / 2 }, { x: s, y: -s / 2 },
@@ -117,6 +119,27 @@ const hexagon = async (parent, node) => {
return shapeSvg; return shapeSvg;
}; };
const block_arrow = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const f = 2;
const h = bbox.height + 2 * node.padding;
const m = h / f;
const w = bbox.width + 2 * m + node.padding;
const points = getArrowPoints(node.directions, bbox, node);
const blockArrow = insertPolygonShape(shapeSvg, w, h, points);
blockArrow.attr('style', node.style);
updateNodeBounds(node, blockArrow);
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};
return shapeSvg;
};
const rect_left_inv_arrow = async (parent, node) => { const rect_left_inv_arrow = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper( const { shapeSvg, bbox } = await labelHelper(
parent, parent,
@@ -374,17 +397,64 @@ const rect = async (parent, node) => {
// const totalWidth = bbox.width + node.padding * 2; // const totalWidth = bbox.width + node.padding * 2;
// const totalHeight = bbox.height + node.padding * 2; // const totalHeight = bbox.height + node.padding * 2;
const totalWidth = bbox.width + node.padding; const totalWidth = node.positioned ? node.width : bbox.width + node.padding;
const totalHeight = bbox.height + node.padding; const totalHeight = node.positioned ? node.height : bbox.height + node.padding;
const x = node.positioned ? -totalWidth / 2 : -bbox.width / 2 - halfPadding;
const y = node.positioned ? -totalHeight / 2 : -bbox.height / 2 - halfPadding;
rect rect
.attr('class', 'basic label-container') .attr('class', 'basic label-container')
.attr('style', node.style) .attr('style', node.style)
.attr('rx', node.rx) .attr('rx', node.rx)
.attr('ry', node.ry) .attr('ry', node.ry)
// .attr('x', -bbox.width / 2 - node.padding) .attr('x', x)
// .attr('y', -bbox.height / 2 - node.padding) .attr('y', y)
.attr('x', -bbox.width / 2 - halfPadding) .attr('width', totalWidth)
.attr('y', -bbox.height / 2 - halfPadding) .attr('height', totalHeight);
if (node.props) {
const propKeys = new Set(Object.keys(node.props));
if (node.props.borders) {
applyNodePropertyBorders(rect, node.props.borders, totalWidth, totalHeight);
propKeys.delete('borders');
}
propKeys.forEach((propKey) => {
log.warn(`Unknown node property ${propKey}`);
});
}
updateNodeBounds(node, rect);
node.intersect = function (point) {
return intersect.rect(node, point);
};
return shapeSvg;
};
const composite = async (parent, node) => {
const { shapeSvg, bbox, halfPadding } = await labelHelper(
parent,
node,
'node ' + node.classes,
true
);
// add the rect
const rect = shapeSvg.insert('rect', ':first-child');
// const totalWidth = bbox.width + node.padding * 2;
// const totalHeight = bbox.height + node.padding * 2;
const totalWidth = node.positioned ? node.width : bbox.width + node.padding;
const totalHeight = node.positioned ? node.height : bbox.height + node.padding;
const x = node.positioned ? -totalWidth / 2 : -bbox.width / 2 - halfPadding;
const y = node.positioned ? -totalHeight / 2 : -bbox.height / 2 - halfPadding;
rect
.attr('class', 'basic cluster composite label-container')
.attr('style', node.style)
.attr('rx', node.rx)
.attr('ry', node.ry)
.attr('x', x)
.attr('y', y)
.attr('width', totalWidth) .attr('width', totalWidth)
.attr('height', totalHeight); .attr('height', totalHeight);
@@ -1031,6 +1101,7 @@ const class_box = (parent, node) => {
const shapes = { const shapes = {
rhombus: question, rhombus: question,
composite,
question, question,
rect, rect,
labelRect, labelRect,
@@ -1040,6 +1111,7 @@ const shapes = {
doublecircle, doublecircle,
stadium, stadium,
hexagon, hexagon,
block_arrow,
rect_left_inv_arrow, rect_left_inv_arrow,
lean_right, lean_right,
lean_left, lean_left,
@@ -1082,6 +1154,9 @@ export const insertNode = async (elem, node, dir) => {
if (node.class) { if (node.class) {
el.attr('class', 'node default ' + node.class); el.attr('class', 'node default ' + node.class);
} }
// MC Special
newEl.attr('data-node', 'true');
newEl.attr('data-id', node.id);
nodeElems[node.id] = newEl; nodeElems[node.id] = newEl;
@@ -1099,7 +1174,6 @@ export const clear = () => {
export const positionNode = (node) => { export const positionNode = (node) => {
const el = nodeElems[node.id]; const el = nodeElems[node.id];
log.trace( log.trace(
'Transforming node', 'Transforming node',
node.diff, node.diff,

View File

@@ -115,6 +115,7 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')'); label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');
} }
label.insert('rect', ':first-child'); label.insert('rect', ':first-child');
return { shapeSvg, bbox, halfPadding, label }; return { shapeSvg, bbox, halfPadding, label };
}; };

View File

@@ -20,6 +20,7 @@ import flowchartElk from '../diagrams/flowchart/elk/detector.js';
import timeline from '../diagrams/timeline/detector.js'; import timeline from '../diagrams/timeline/detector.js';
import mindmap from '../diagrams/mindmap/detector.js'; import mindmap from '../diagrams/mindmap/detector.js';
import sankey from '../diagrams/sankey/sankeyDetector.js'; import sankey from '../diagrams/sankey/sankeyDetector.js';
import block from '../diagrams/block/blockDetector.js';
import { registerLazyLoadedDiagrams } from './detectType.js'; import { registerLazyLoadedDiagrams } from './detectType.js';
import { registerDiagram } from './diagramAPI.js'; import { registerDiagram } from './diagramAPI.js';
@@ -87,6 +88,7 @@ export const addDiagrams = () => {
journey, journey,
quadrantChart, quadrantChart,
sankey, sankey,
xychart xychart,
block
); );
}; };

View File

@@ -0,0 +1,311 @@
import type { DiagramDB } from '../../diagram-api/types.js';
import type { BlockConfig, BlockType, Block, ClassDef } from './blockTypes.js';
import * as configApi from '../../config.js';
import { clear as commonClear } from '../common/commonDb.js';
import { log } from '../../logger.js';
import clone from 'lodash-es/clone.js';
// Initialize the node database for simple lookups
let blockDatabase: Record<string, Block> = {};
let edgeList: Block[] = [];
let edgeCount: Record<string, number> = {};
const COLOR_KEYWORD = 'color';
const FILL_KEYWORD = 'fill';
const BG_FILL = 'bgFill';
const STYLECLASS_SEP = ',';
let classes = {} as Record<string, ClassDef>;
/**
* Called when the parser comes across a (style) class definition
* @example classDef my-style fill:#f96;
*
* @param id - the id of this (style) class
* @param styleAttributes - the string with 1 or more style attributes (each separated by a comma)
*/
export const addStyleClass = function (id: string, styleAttributes = '') {
// create a new style class object with this id
if (classes[id] === undefined) {
classes[id] = { id: id, styles: [], textStyles: [] }; // This is a classDef
}
const foundClass = classes[id];
if (styleAttributes !== undefined && styleAttributes !== null) {
styleAttributes.split(STYLECLASS_SEP).forEach((attrib) => {
// remove any trailing ;
const fixedAttrib = attrib.replace(/([^;]*);/, '$1').trim();
// replace some style keywords
if (attrib.match(COLOR_KEYWORD)) {
const newStyle1 = fixedAttrib.replace(FILL_KEYWORD, BG_FILL);
const newStyle2 = newStyle1.replace(COLOR_KEYWORD, FILL_KEYWORD);
foundClass.textStyles.push(newStyle2);
}
foundClass.styles.push(fixedAttrib);
});
}
};
/**
* Called when the parser comes across a style definition
* @example style my-block-id fill:#f96;
*
* @param id - the id of the block to style
* @param styles - the string with 1 or more style attributes (each separated by a comma)
*/
export const addStyle2Node = function (id: string, styles = '') {
const foundBlock = blockDatabase[id];
if (styles !== undefined && styles !== null) {
foundBlock.styles = styles.split(STYLECLASS_SEP);
}
};
/**
* Add a CSS/style class to the block with the given id.
* If the block isn't already in the list of known blocks, add it.
* Might be called by parser when a CSS/style class should be applied to a block
*
* @param itemIds - The id or a list of ids of the item(s) to apply the css class to
* @param cssClassName - CSS class name
*/
export const setCssClass = function (itemIds: string, cssClassName: string) {
itemIds.split(',').forEach(function (id: string) {
let foundBlock = blockDatabase[id];
if (foundBlock === undefined) {
const trimmedId = id.trim();
blockDatabase[trimmedId] = { id: trimmedId, type: 'na', children: [] } as Block;
foundBlock = blockDatabase[trimmedId];
}
if (!foundBlock.classes) {
foundBlock.classes = [];
}
foundBlock.classes.push(cssClassName);
});
};
const populateBlockDatabase = (_blockList: Block[] | Block[][], parent: Block): void => {
const blockList = _blockList.flat();
const children = [];
for (const block of blockList) {
if (block.type === 'classDef') {
addStyleClass(block.id, block.css);
continue;
}
if (block.type === 'applyClass') {
setCssClass(block.id, block?.styleClass || '');
continue;
}
if (block.type === 'applyStyles') {
if (block?.stylesStr) {
addStyle2Node(block.id, block?.stylesStr);
}
continue;
}
if (block.type === 'column-setting') {
parent.columns = block.columns || -1;
} else if (block.type === 'edge') {
if (edgeCount[block.id]) {
edgeCount[block.id]++;
} else {
edgeCount[block.id] = 1;
}
block.id = edgeCount[block.id] + '-' + block.id;
edgeList.push(block);
} else {
if (!block.label) {
if (block.type === 'composite') {
block.label = '';
// log.debug('abc89 composite', block);
} else {
block.label = block.id;
}
}
const newBlock = !blockDatabase[block.id];
if (newBlock) {
blockDatabase[block.id] = block;
} else {
// Add newer relevant data to aggregated node
if (block.type !== 'na') {
blockDatabase[block.id].type = block.type;
}
if (block.label !== block.id) {
blockDatabase[block.id].label = block.label;
}
}
if (block.children) {
populateBlockDatabase(block.children, block);
}
if (block.type === 'space') {
// log.debug('abc95 space', block);
const w = block.width || 1;
for (let j = 0; j < w; j++) {
const newBlock = clone(block);
newBlock.id = newBlock.id + '-' + j;
blockDatabase[newBlock.id] = newBlock;
children.push(newBlock);
}
} else if (newBlock) {
children.push(block);
}
}
}
parent.children = children;
};
let blocks: Block[] = [];
let rootBlock = { id: 'root', type: 'composite', children: [], columns: -1 } as Block;
const clear = (): void => {
log.debug('Clear called');
commonClear();
rootBlock = { id: 'root', type: 'composite', children: [], columns: -1 } as Block;
blockDatabase = { root: rootBlock };
blocks = [] as Block[];
classes = {} as Record<string, ClassDef>;
edgeList = [];
edgeCount = {};
};
export function typeStr2Type(typeStr: string) {
log.debug('typeStr2Type', typeStr);
switch (typeStr) {
case '[]':
return 'square';
case '()':
log.debug('we have a round');
return 'round';
case '(())':
return 'circle';
case '>]':
return 'rect_left_inv_arrow';
case '{}':
return 'diamond';
case '{{}}':
return 'hexagon';
case '([])':
return 'stadium';
case '[[]]':
return 'subroutine';
case '[()]':
return 'cylinder';
case '((()))':
return 'doublecircle';
case '[//]':
return 'lean_right';
case '[\\\\]':
return 'lean_left';
case '[/\\]':
return 'trapezoid';
case '[\\/]':
return 'inv_trapezoid';
case '<[]>':
return 'block_arrow';
default:
return 'na';
}
}
export function edgeTypeStr2Type(typeStr: string): string {
log.debug('typeStr2Type', typeStr);
switch (typeStr) {
case '==':
return 'thick';
default:
return 'normal';
}
}
export function edgeStrToEdgeData(typeStr: string): string {
switch (typeStr.trim()) {
case '--x':
return 'arrow_cross';
case '--o':
return 'arrow_circle';
default:
return 'arrow_point';
}
}
let cnt = 0;
export const generateId = () => {
cnt++;
return 'id-' + Math.random().toString(36).substr(2, 12) + '-' + cnt;
};
const setHierarchy = (block: Block[]): void => {
rootBlock.children = block;
populateBlockDatabase(block, rootBlock);
blocks = rootBlock.children;
};
const getColumns = (blockid: string): number => {
const block = blockDatabase[blockid];
if (!block) {
return -1;
}
if (block.columns) {
return block.columns;
}
if (!block.children) {
return -1;
}
return block.children.length;
};
/**
* Returns all the blocks as a flat array
* @returns
*/
const getBlocksFlat = () => {
return [...Object.values(blockDatabase)];
};
/**
* Returns the the hierarchy of blocks
* @returns
*/
const getBlocks = () => {
return blocks || [];
};
const getEdges = () => {
return edgeList;
};
const getBlock = (id: string) => {
return blockDatabase[id];
};
const setBlock = (block: Block) => {
blockDatabase[block.id] = block;
};
const getLogger = () => console;
/**
* Return all of the style classes
*/
export const getClasses = function () {
return classes;
};
const db = {
getConfig: () => configApi.getConfig().block,
typeStr2Type: typeStr2Type,
edgeTypeStr2Type: edgeTypeStr2Type,
edgeStrToEdgeData,
getLogger,
getBlocksFlat,
getBlocks,
getEdges,
setHierarchy,
getBlock,
setBlock,
getColumns,
getClasses,
clear,
generateId,
} as const;
export type BlockDB = typeof db & DiagramDB;
export default db;

View File

@@ -0,0 +1,20 @@
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
const id = 'block';
const detector: DiagramDetector = (txt) => {
return /^\s*block-beta/.test(txt);
};
const loader = async () => {
const { diagram } = await import('./blockDiagram.js');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,13 @@
import type { DiagramDefinition } from '../../diagram-api/types.js';
// @ts-ignore: jison doesn't export types
import parser from './parser/block.jison';
import db from './blockDB.js';
import flowStyles from './styles.js';
import renderer from './blockRenderer.js';
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
styles: flowStyles,
};

View File

@@ -0,0 +1,96 @@
import type { Diagram } from '../../Diagram.js';
import * as configApi from '../../config.js';
import { calculateBlockSizes, insertBlocks, insertEdges } from './renderHelpers.js';
import { layout } from './layout.js';
import type { MermaidConfig, BaseDiagramConfig } from '../../config.type.js';
import insertMarkers from '../../dagre-wrapper/markers.js';
import {
select as d3select,
scaleOrdinal as d3scaleOrdinal,
schemeTableau10 as d3schemeTableau10,
} from 'd3';
import type { ContainerElement } from 'd3';
import { log } from '../../logger.js';
import type { BlockDB } from './blockDB.js';
import type { Block } from './blockTypes.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
/**
* Returns the all the styles from classDef statements in the graph definition.
*
* @param text - The text with the classes
* @param diagObj - The diagram object
* @returns ClassDef - The styles
*/
export const getClasses = function (text: any, diagObj: any) {
return diagObj.db.getClasses();
};
export const draw = async function (
text: string,
id: string,
_version: string,
diagObj: Diagram
): Promise<void> {
const { securityLevel, block: conf } = configApi.getConfig();
const db = diagObj.db as BlockDB;
let sandboxElement: any;
if (securityLevel === 'sandbox') {
sandboxElement = d3select('#i' + id);
}
const root =
securityLevel === 'sandbox'
? d3select<HTMLBodyElement, unknown>(sandboxElement.nodes()[0].contentDocument.body)
: d3select<HTMLBodyElement, unknown>('body');
const svg =
securityLevel === 'sandbox'
? root.select<SVGSVGElement>(`[id="${id}"]`)
: d3select<SVGSVGElement, unknown>(`[id="${id}"]`);
// Define the supported markers for the diagram
const markers = ['point', 'circle', 'cross'];
// Add the marker definitions to the svg as marker tags
// insertMarkers(svg, markers, diagObj.type, diagObj.arrowMarkerAbsolute);
// insertMarkers(svg, markers, diagObj.type, true);
insertMarkers(svg, markers, diagObj.type, id);
const bl = db.getBlocks();
const blArr = db.getBlocksFlat();
const edges = db.getEdges();
const nodes = svg.insert('g').attr('class', 'block');
await calculateBlockSizes(nodes, bl, db);
const bounds = layout(db);
await insertBlocks(nodes, bl, db);
await insertEdges(nodes, edges, blArr, db, id);
// log.debug('Here', bl);
// Establish svg dimensions and get width and height
//
// const bounds2 = nodes.node().getBoundingClientRect();
// Why, oh why ????
if (bounds) {
const bounds2 = bounds;
const magicFactor = Math.max(1, Math.round(0.125 * (bounds2.width / bounds2.height)));
const height = bounds2.height + magicFactor + 10;
const width = bounds2.width + 10;
const { useMaxWidth } = conf as Exclude<MermaidConfig['block'], undefined>;
configureSvgSize(svg, height, width, !!useMaxWidth);
log.debug('Here Bounds', bounds, bounds2);
svg.attr(
'viewBox',
`${bounds2.x - 5} ${bounds2.y - 5} ${bounds2.width + 10} ${bounds2.height + 10}`
);
}
// Get color scheme for the graph
const colorScheme = d3scaleOrdinal(d3schemeTableau10);
};
export default {
draw,
getClasses,
};

View File

@@ -0,0 +1,68 @@
export type { BlockDiagramConfig as BlockConfig } from '../../config.type.js';
export type BlockType =
| 'na'
| 'column-setting'
| 'edge'
| 'round'
| 'block_arrow'
| 'space'
| 'square'
| 'diamond'
| 'hexagon'
| 'odd'
| 'lean_right'
| 'lean_left'
| 'trapezoid'
| 'inv_trapezoid'
| 'rect_left_inv_arrow'
| 'odd_right'
| 'circle'
| 'ellipse'
| 'stadium'
| 'subroutine'
| 'cylinder'
| 'group'
| 'doublecircle'
| 'classDef'
| 'applyClass'
| 'applyStyles'
| 'composite';
export interface Block {
// When the block have the type edge, the start and end are the id of the source and target blocks
start?: string;
end?: string;
arrowTypeEnd?: string;
arrowTypeStart?: string;
width?: number;
id: string;
label?: string;
intersect?: any;
parent?: Block;
type?: BlockType;
children: Block[];
size?: {
width: number;
height: number;
x: number;
y: number;
};
node?: any;
columns?: number; // | TBlockColumnsDefaultValue;
classes?: string[];
directions?: string[];
css?: string;
styleClass?: string;
styles?: string[];
stylesStr?: string;
widthInColumns?: number;
}
export interface ClassDef {
id: string;
textStyles: string[];
styles: string[];
}
export type Direction = 'up' | 'down' | 'left' | 'right' | 'x' | 'y';

View File

@@ -0,0 +1,8 @@
export const prepareTextForParsing = (text: string): string => {
const textToParse = text
.replaceAll(/^[^\S\n\r]+|[^\S\n\r]+$/g, '') // remove all trailing spaces for each row
.replaceAll(/([\n\r])+/g, '\n') // remove empty lines duplicated
.trim();
return textToParse;
};

View File

@@ -0,0 +1,12 @@
import { calculateBlockPosition } from './layout.js';
describe('Layout', function () {
it('should calculate position correctly', () => {
expect(calculateBlockPosition(2, 0)).toEqual({ px: 0, py: 0 });
expect(calculateBlockPosition(2, 1)).toEqual({ px: 1, py: 0 });
expect(calculateBlockPosition(2, 2)).toEqual({ px: 0, py: 1 });
expect(calculateBlockPosition(2, 3)).toEqual({ px: 1, py: 1 });
expect(calculateBlockPosition(2, 4)).toEqual({ px: 0, py: 2 });
expect(calculateBlockPosition(1, 3)).toEqual({ px: 0, py: 3 });
});
});

View File

@@ -0,0 +1,327 @@
import type { BlockDB } from './blockDB.js';
import type { Block } from './blockTypes.js';
import { log } from '../../logger.js';
import { getConfig } from '../../diagram-api/diagramAPI.js';
const padding = getConfig()?.block?.padding || 8;
interface BlockPosition {
px: number;
py: number;
}
export function calculateBlockPosition(columns: number, position: number): BlockPosition {
// log.debug('calculateBlockPosition abc89', columns, position);
// Ensure that columns is a positive integer
if (columns === 0 || !Number.isInteger(columns)) {
throw new Error('Columns must be an integer !== 0.');
}
// Ensure that position is a non-negative integer
if (position < 0 || !Number.isInteger(position)) {
throw new Error('Position must be a non-negative integer.' + position);
}
if (columns < 0) {
// Auto coulumns is set
return { px: position, py: 0 };
}
if (columns === 1) {
// Auto coulumns is set
return { px: 0, py: position };
}
// Calculate posX and posY
const px = position % columns;
const py = Math.floor(position / columns);
// log.debug('calculateBlockPosition abc89', columns, position, '=> (', px, py, ')');
return { px, py };
}
const getMaxChildSize = (block: Block) => {
let maxWidth = 0;
let maxHeight = 0;
// find max width of children
// log.debug('getMaxChildSize abc95 (start) parent:', block.id);
for (const child of block.children) {
const { width, height, x, y } = child.size || { width: 0, height: 0, x: 0, y: 0 };
log.debug(
'getMaxChildSize abc95 child:',
child.id,
'width:',
width,
'height:',
height,
'x:',
x,
'y:',
y,
child.type
);
if (child.type === 'space') {
continue;
}
if (width > maxWidth) {
maxWidth = width / (block.widthInColumns || 1);
}
if (height > maxHeight) {
maxHeight = height;
}
}
return { width: maxWidth, height: maxHeight };
};
function setBlockSizes(block: Block, db: BlockDB, siblingWidth = 0, siblingHeight = 0) {
log.debug(
'setBlockSizes abc95 (start)',
block.id,
block?.size?.x,
'block width =',
block?.size,
'sieblingWidth',
siblingWidth
);
if (!block?.size?.width) {
block.size = {
width: siblingWidth,
height: siblingHeight,
x: 0,
y: 0,
};
}
let maxWidth = 0;
let maxHeight = 0;
if (block.children?.length > 0) {
for (const child of block.children) {
setBlockSizes(child, db);
}
// find max width of children
const childSize = getMaxChildSize(block);
maxWidth = childSize.width;
maxHeight = childSize.height;
log.debug('setBlockSizes abc95 maxWidth of', block.id, ':s children is ', maxWidth, maxHeight);
// set width of block to max width of children
for (const child of block.children) {
if (child.size) {
log.debug(
`abc95 Setting size of children of ${block.id} id=${child.id} ${maxWidth} ${maxHeight} ${child.size}`
);
child.size.width =
maxWidth * (child.widthInColumns || 1) + padding * ((child.widthInColumns || 1) - 1);
child.size.height = maxHeight;
child.size.x = 0;
child.size.y = 0;
log.debug(
`abc95 updating size of ${block.id} children child:${child.id} maxWidth:${maxWidth} maxHeight:${maxHeight}`
);
}
}
for (const child of block.children) {
setBlockSizes(child, db, maxWidth, maxHeight);
}
const columns = block.columns || -1;
let numItems = 0;
for (const child of block.children) {
numItems += child.widthInColumns || 1;
}
// The width and height in number blocks
let xSize = block.children.length;
if (columns > 0 && columns < numItems) {
xSize = columns;
}
const w = block.widthInColumns || 1;
const ySize = Math.ceil(numItems / xSize);
let width = xSize * (maxWidth + padding) + padding;
let height = ySize * (maxHeight + padding) + padding;
// If maxWidth
if (width < siblingWidth) {
log.debug(
`Detected to small siebling: abc95 ${block.id} sieblingWidth ${siblingWidth} sieblingHeight ${siblingHeight} width ${width}`
);
width = siblingWidth;
height = siblingHeight;
const childWidth = (siblingWidth - xSize * padding - padding) / xSize;
const childHeight = (siblingHeight - ySize * padding - padding) / ySize;
log.debug('Size indata abc88', block.id, 'childWidth', childWidth, 'maxWidth', maxWidth);
log.debug('Size indata abc88', block.id, 'childHeight', childHeight, 'maxHeight', maxHeight);
log.debug('Size indata abc88 xSize', xSize, 'paddiong', padding);
// set width of block to max width of children
for (const child of block.children) {
if (child.size) {
child.size.width = childWidth;
child.size.height = childHeight;
child.size.x = 0;
child.size.y = 0;
}
}
}
log.debug(
`abc95 (finale calc) ${block.id} xSize ${xSize} ySize ${ySize} columns ${columns}${
block.children.length
} width=${Math.max(width, block.size?.width || 0)}`
);
if (width < (block?.size?.width || 0)) {
width = block?.size?.width || 0;
// Grow children to fit
const num = columns > 0 ? Math.min(block.children.length, columns) : block.children.length;
if (num > 0) {
const childWidth = (width - num * padding - padding) / num;
log.debug('abc95 (growing to fit) width', block.id, width, block.size?.width, childWidth);
for (const child of block.children) {
if (child.size) {
child.size.width = childWidth;
}
}
}
}
block.size = {
width,
height,
x: 0,
y: 0,
};
}
log.debug(
'setBlockSizes abc94 (done)',
block.id,
block?.size?.x,
block?.size?.width,
block?.size?.y,
block?.size?.height
);
}
function layoutBlocks(block: Block, db: BlockDB) {
log.debug(
`abc85 layout blocks (=>layoutBlocks) ${block.id} x: ${block?.size?.x} y: ${block?.size?.y} width: ${block?.size?.width}`
);
const columns = block.columns || -1;
log.debug('layoutBlocks columns abc95', block.id, '=>', columns, block);
if (
block.children && // find max width of children
block.children.length > 0
) {
const width = block?.children[0]?.size?.width || 0;
const widthOfChildren = block.children.length * width + (block.children.length - 1) * padding;
log.debug('widthOfChildren 88', widthOfChildren, 'posX');
// let first = true;
let columnPos = 0;
log.debug('abc91 block?.size?.x', block.id, block?.size?.x);
let startingPosX = block?.size?.x ? block?.size?.x + (-block?.size?.width / 2 || 0) : -padding;
let rowPos = 0;
for (const child of block.children) {
const parent = block;
if (!child.size) {
continue;
}
const { width, height } = child.size;
const { px, py } = calculateBlockPosition(columns, columnPos);
if (py != rowPos) {
rowPos = py;
startingPosX = block?.size?.x ? block?.size?.x + (-block?.size?.width / 2 || 0) : -padding;
log.debug('New row in layout for block', block.id, ' and child ', child.id, rowPos);
}
log.debug(
`abc89 layout blocks (child) id: ${child.id} Pos: ${columnPos} (px, py) ${px},${py} (${parent?.size?.x},${parent?.size?.y}) parent: ${parent.id} width: ${width}${padding}`
);
if (parent.size) {
const halfWidth = width / 2;
child.size.x = startingPosX + padding + halfWidth;
log.debug(
`abc91 layout blocks (calc) px, pyid:${
child.id
} startingPos=X${startingPosX} new startingPosX${
child.size.x
} ${halfWidth} padding=${padding} width=${width} halfWidth=${halfWidth} => x:${
child.size.x
} y:${child.size.y} ${child.widthInColumns} (width * (child?.w || 1)) / 2 ${
(width * (child?.widthInColumns || 1)) / 2
}`
);
startingPosX = child.size.x + halfWidth;
child.size.y =
parent.size.y - parent.size.height / 2 + py * (height + padding) + height / 2 + padding;
log.debug(
`abc88 layout blocks (calc) px, pyid:${
child.id
}startingPosX${startingPosX}${padding}${halfWidth}=>x:${child.size.x}y:${child.size.y}${
child.widthInColumns
}(width * (child?.w || 1)) / 2${(width * (child?.widthInColumns || 1)) / 2}`
);
}
// posY += height + padding;
if (child.children) {
layoutBlocks(child, db);
}
columnPos += child?.widthInColumns || 1;
log.debug('abc88 columnsPos', child, columnPos);
}
}
log.debug(
`layout blocks (<==layoutBlocks) ${block.id} x: ${block?.size?.x} y: ${block?.size?.y} width: ${block?.size?.width}`
);
}
function findBounds(
block: Block,
{ minX, minY, maxX, maxY } = { minX: 0, minY: 0, maxX: 0, maxY: 0 }
) {
if (block.size && block.id !== 'root') {
const { x, y, width, height } = block.size;
if (x - width / 2 < minX) {
minX = x - width / 2;
}
if (y - height / 2 < minY) {
minY = y - height / 2;
}
if (x + width / 2 > maxX) {
maxX = x + width / 2;
}
if (y + height / 2 > maxY) {
maxY = y + height / 2;
}
}
if (block.children) {
for (const child of block.children) {
({ minX, minY, maxX, maxY } = findBounds(child, { minX, minY, maxX, maxY }));
}
}
return { minX, minY, maxX, maxY };
}
export function layout(db: BlockDB) {
const root = db.getBlock('root');
if (!root) {
return;
}
setBlockSizes(root, db, 0, 0);
layoutBlocks(root, db);
// Position blocks relative to parents
// positionBlock(root, root, db);
log.debug('getBlocks', JSON.stringify(root, null, 2));
const { minX, minY, maxX, maxY } = findBounds(root);
const height = maxY - minY;
const width = maxX - minX;
return { x: minX, y: minY, width, height };
}

View File

@@ -0,0 +1,290 @@
/** mermaid */
//---------------------------------------------------------
// We support csv format as defined here:
// https://www.ietf.org/rfc/rfc4180.txt
// There are some minor changes for compliance with jison
// We also parse only 3 columns: source,target,value
// And allow blank lines for visual purposes
//---------------------------------------------------------
%lex
%x acc_title
%x acc_descr
%x acc_descr_multiline
%x string
%x space
%x md_string
%x NODE
%x BLOCK_ARROW
%x ARROW_DIR
%x LLABEL
%x CLASS
%x CLASS_STYLE
%x CLASSDEF
%x CLASSDEFID
%x STYLE_STMNT
%x STYLE_DEFINITION
// as per section 6.1 of RFC 2234 [2]
COMMA \u002C
CR \u000D
LF \u000A
CRLF \u000D\u000A
%%
"block-beta" { return 'BLOCK_DIAGRAM_KEY'; }
"block"\s+ { yy.getLogger().debug('Found space-block'); return 'block';}
"block"\n+ { yy.getLogger().debug('Found nl-block'); return 'block';}
"block:" { yy.getLogger().debug('Found space-block'); return 'id-block';}
// \s*\%\%.* { yy.getLogger().debug('Found comment',yytext); }
[\s]+ { yy.getLogger().debug('.', yytext); /* skip all whitespace */ }
[\n]+ {yy.getLogger().debug('_', yytext); /* skip all whitespace */ }
// [\n] return 'NL';
<INITIAL>({CRLF}|{LF}) { return 'NL' }
"columns"\s+"auto" { yytext=-1; return 'COLUMNS'; }
"columns"\s+[\d]+ { yytext = yytext.replace(/columns\s+/,''); yy.getLogger().debug('COLUMNS (LEX)', yytext); return 'COLUMNS'; }
["][`] { this.pushState("md_string");}
<md_string>[^`"]+ { return "MD_STR";}
<md_string>[`]["] { this.popState();}
["] this.pushState("string");
<string>["] { yy.getLogger().debug('LEX: POPPING STR:', yytext);this.popState();}
<string>[^"]* { yy.getLogger().debug('LEX: STR end:', yytext); return "STR";}
space[:]\d+ { yytext = yytext.replace(/space\:/,'');yy.getLogger().debug('SPACE NUM (LEX)', yytext); return 'SPACE_BLOCK'; }
space { yytext = '1'; yy.getLogger().debug('COLUMNS (LEX)', yytext); return 'SPACE_BLOCK'; }
"default" return 'DEFAULT';
"linkStyle" return 'LINKSTYLE';
"interpolate" return 'INTERPOLATE';
"classDef"\s+ { this.pushState('CLASSDEF'); return 'classDef'; }
<CLASSDEF>DEFAULT\s+ { this.popState(); this.pushState('CLASSDEFID'); return 'DEFAULT_CLASSDEF_ID' }
<CLASSDEF>\w+\s+ { this.popState(); this.pushState('CLASSDEFID'); return 'CLASSDEF_ID' }
<CLASSDEFID>[^\n]* { this.popState(); return 'CLASSDEF_STYLEOPTS' }
"class"\s+ { this.pushState('CLASS'); return 'class'; }
<CLASS>(\w+)+((","\s*\w+)*) { this.popState(); this.pushState('CLASS_STYLE'); return 'CLASSENTITY_IDS' }
<CLASS_STYLE>[^\n]* { this.popState(); return 'STYLECLASS' }
"style"\s+ { this.pushState('STYLE_STMNT'); return 'style'; }
<STYLE_STMNT>(\w+)+((","\s*\w+)*) { this.popState(); this.pushState('STYLE_DEFINITION'); return 'STYLE_ENTITY_IDS' }
<STYLE_DEFINITION>[^\n]* { this.popState(); return 'STYLE_DEFINITION_DATA' }
accTitle\s*":"\s* { this.pushState("acc_title");return 'acc_title'; }
<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; }
accDescr\s*":"\s* { this.pushState("acc_descr");return 'acc_descr'; }
<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; }
accDescr\s*"{"\s* { this.pushState("acc_descr_multiline");}
<acc_descr_multiline>[\}] { this.popState(); }
<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value";
"end"\b\s* return 'end';
// Node end of shape
<NODE>"(((" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; }
<NODE>")))" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; }
<NODE>[\)]\) { this.popState();yy.getLogger().debug('Lex: ))'); return "NODE_DEND"; }
<NODE>"}}" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; }
<NODE>"}" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; }
<NODE>"(-" { this.popState();yy.getLogger().debug('Lex: (-'); return "NODE_DEND"; }
<NODE>"-)" { this.popState();yy.getLogger().debug('Lex: -)'); return "NODE_DEND"; }
<NODE>"((" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; }
<NODE>"]]" { this.popState();yy.getLogger().debug('Lex: ]]'); return "NODE_DEND"; }
<NODE>"(" { this.popState();yy.getLogger().debug('Lex: ('); return "NODE_DEND"; }
<NODE>"])" { this.popState();yy.getLogger().debug('Lex: ])'); return "NODE_DEND"; }
<NODE>"\\]" { this.popState();yy.getLogger().debug('Lex: /]'); return "NODE_DEND"; }
<NODE>"/]" { this.popState();yy.getLogger().debug('Lex: /]'); return "NODE_DEND"; }
<NODE>")]" { this.popState();yy.getLogger().debug('Lex: )]'); return "NODE_DEND"; }
<NODE>[\)] { this.popState();yy.getLogger().debug('Lex: )'); return "NODE_DEND"; }
<NODE>\]\> { this.popState();yy.getLogger().debug('Lex: ]>'); return "NODE_DEND"; }
<NODE>[\]] { this.popState();yy.getLogger().debug('Lex: ]'); return "NODE_DEND"; }
// Start of nodes with shapes and description
"-)" { yy.getLogger().debug('Lexa: -)'); this.pushState('NODE');return 'NODE_DSTART'; }
"(-" { yy.getLogger().debug('Lexa: (-'); this.pushState('NODE');return 'NODE_DSTART'; }
"))" { yy.getLogger().debug('Lexa: ))'); this.pushState('NODE');return 'NODE_DSTART'; }
")" { yy.getLogger().debug('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
"(((" { yy.getLogger().debug('Lex: ((('); this.pushState('NODE');return 'NODE_DSTART'; }
"((" { yy.getLogger().debug('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
"{{" { yy.getLogger().debug('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
"{" { yy.getLogger().debug('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
">" { yy.getLogger().debug('Lexc: >'); this.pushState('NODE');return 'NODE_DSTART'; }
"([" { yy.getLogger().debug('Lexa: (['); this.pushState('NODE');return 'NODE_DSTART'; }
"(" { yy.getLogger().debug('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
"[[" { this.pushState('NODE');return 'NODE_DSTART'; }
"[|" { this.pushState('NODE');return 'NODE_DSTART'; }
"[(" { this.pushState('NODE');return 'NODE_DSTART'; }
")))" { this.pushState('NODE');return 'NODE_DSTART'; }
"[\\" { this.pushState('NODE');return 'NODE_DSTART'; }
"[/" { this.pushState('NODE');return 'NODE_DSTART'; }
"[\\" { this.pushState('NODE');return 'NODE_DSTART'; }
"[" { yy.getLogger().debug('Lexa: ['); this.pushState('NODE');return 'NODE_DSTART'; }
"<[" { this.pushState('BLOCK_ARROW');yy.getLogger().debug('LEX ARR START');return 'BLOCK_ARROW_START'; }
[^\(\[\n\-\)\{\}\s\<\>:]+ { yy.getLogger().debug('Lex: NODE_ID', yytext);return 'NODE_ID'; }
<<EOF>> { yy.getLogger().debug('Lex: EOF', yytext);return 'EOF'; }
// Handling of strings in node
<BLOCK_ARROW>["][`] { this.pushState("md_string");}
<NODE>["][`] { this.pushState("md_string");}
<md_string>[^`"]+ { return "NODE_DESCR";}
<md_string>[`]["] { this.popState();}
<NODE>["] { yy.getLogger().debug('Lex: Starting string');this.pushState("string");}
<BLOCK_ARROW>["] { yy.getLogger().debug('LEX ARR: Starting string');this.pushState("string");}
<string>[^"]+ { yy.getLogger().debug('LEX: NODE_DESCR:', yytext); return "NODE_DESCR";}
<string>["] {yy.getLogger().debug('LEX POPPING');this.popState();}
<BLOCK_ARROW>"]>"\s*"(" { yy.getLogger().debug('Lex: =>BAE'); this.pushState('ARROW_DIR'); }
<ARROW_DIR>","?\s*right\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (right): dir:',yytext);return "DIR"; }
<ARROW_DIR>","?\s*left\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (left):',yytext);return "DIR"; }
<ARROW_DIR>","?\s*x\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (x):',yytext); return "DIR"; }
<ARROW_DIR>","?\s*y\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (y):',yytext); return "DIR"; }
<ARROW_DIR>","?\s*up\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (up):',yytext); return "DIR"; }
<ARROW_DIR>","?\s*down\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (down):',yytext); return "DIR"; }
<ARROW_DIR>")"\s* { yytext=']>';yy.getLogger().debug('Lex (ARROW_DIR end):',yytext);this.popState();this.popState();return "BLOCK_ARROW_END"; }
// Edges
\s*[xo<]?\-\-+[-xo>]\s* { yy.getLogger().debug('Lex: LINK', '#'+yytext+'#'); return 'LINK'; }
\s*[xo<]?\=\=+[=xo>]\s* { yy.getLogger().debug('Lex: LINK', yytext); return 'LINK'; }
\s*[xo<]?\-?\.+\-[xo>]?\s* { yy.getLogger().debug('Lex: LINK', yytext); return 'LINK'; }
\s*\~\~[\~]+\s* { yy.getLogger().debug('Lex: LINK', yytext); return 'LINK'; }
\s*[xo<]?\-\-\s* { yy.getLogger().debug('Lex: START_LINK', yytext);this.pushState("LLABEL");return 'START_LINK'; }
\s*[xo<]?\=\=\s* { yy.getLogger().debug('Lex: START_LINK', yytext);this.pushState("LLABEL");return 'START_LINK'; }
\s*[xo<]?\-\.\s* { yy.getLogger().debug('Lex: START_LINK', yytext);this.pushState("LLABEL");return 'START_LINK'; }
<LLABEL>["][`] { this.pushState("md_string");}
<LLABEL>["] { yy.getLogger().debug('Lex: Starting string');this.pushState("string"); return "LINK_LABEL";}
<LLABEL>\s*[xo<]?\-\-+[-xo>]\s* { this.popState(); yy.getLogger().debug('Lex: LINK', '#'+yytext+'#'); return 'LINK'; }
<LLABEL>\s*[xo<]?\=\=+[=xo>]\s* { this.popState(); yy.getLogger().debug('Lex: LINK', yytext); return 'LINK'; }
<LLABEL>\s*[xo<]?\-?\.+\-[xo>]?\s* { this.popState(); yy.getLogger().debug('Lex: LINK', yytext); return 'LINK'; }
':'\d+ { yy.getLogger().debug('Lex: COLON', yytext); yytext=yytext.slice(1);return 'SIZE'; }
/lex
%left '^'
%start start
%% // language grammar
spaceLines
: SPACELINE
| spaceLines SPACELINE
| spaceLines NL
;
seperator
: NL
{yy.getLogger().debug('Rule: seperator (NL) ');}
| SPACE
{yy.getLogger().debug('Rule: seperator (Space) ');}
| EOF
{yy.getLogger().debug('Rule: seperator (EOF) ');}
;
start: BLOCK_DIAGRAM_KEY document EOF
{ yy.getLogger().debug("Rule: hierarchy: ", $2); yy.setHierarchy($2); }
;
stop
: NL {yy.getLogger().debug('Stop NL ');}
| EOF {yy.getLogger().debug('Stop EOF ');}
// | SPACELINE
| stop NL {yy.getLogger().debug('Stop NL2 ');}
| stop EOF {yy.getLogger().debug('Stop EOF2 ');}
;
//array of statements
document
: statement { yy.getLogger().debug("Rule: statement: ", $1); typeof $1.length === 'number'?$$ = $1:$$ = [$1]; }
| statement document { yy.getLogger().debug("Rule: statement #2: ", $1); $$ = [$1].concat($2); }
;
link
: LINK
{ yy.getLogger().debug("Rule: link: ", $1, yytext); $$={edgeTypeStr: $1, label:''}; }
| START_LINK LINK_LABEL STR LINK
{ yy.getLogger().debug("Rule: LABEL link: ", $1, $3, $4); $$={edgeTypeStr: $4, label:$3}; }
;
statement
: nodeStatement
| columnsStatement
| SPACE_BLOCK
{ const num=parseInt($1); const spaceId = yy.generateId(); $$ = { id: spaceId, type:'space', label:'', width: num, children: [] }}
| blockStatement
| classDefStatement
| cssClassStatement
| styleStatement
;
nodeStatement
: nodeStatement link node {
yy.getLogger().debug('Rule: (nodeStatement link node) ', $1, $2, $3, ' typestr: ',$2.edgeTypeStr);
const edgeData = yy.edgeStrToEdgeData($2.edgeTypeStr)
$$ = [
{id: $1.id, label: $1.label, type:$1.type, directions: $1.directions},
{id: $1.id + '-' + $3.id, start: $1.id, end: $3.id, label: $2.label, type: 'edge', directions: $3.directions, arrowTypeEnd: edgeData, arrowTypeStart: 'arrow_open' },
{id: $3.id, label: $3.label, type: yy.typeStr2Type($3.typeStr), directions: $3.directions}
];
}
| node SIZE { yy.getLogger().debug('Rule: nodeStatement (abc88 node size) ', $1, $2); $$ = {id: $1.id, label: $1.label, type: yy.typeStr2Type($1.typeStr), directions: $1.directions, widthInColumns: parseInt($2,10)}; }
| node { yy.getLogger().debug('Rule: nodeStatement (node) ', $1); $$ = {id: $1.id, label: $1.label, type: yy.typeStr2Type($1.typeStr), directions: $1.directions, widthInColumns:1}; }
;
columnsStatement
: COLUMNS { yy.getLogger().debug('APA123', this? this:'na'); yy.getLogger().debug("COLUMNS: ", $1); $$ = {type: 'column-setting', columns: $1 === 'auto'?-1:parseInt($1) } }
;
blockStatement
: id-block nodeStatement document end { yy.getLogger().debug('Rule: id-block statement : ', $2, $3); const id2 = yy.generateId(); $$ = { ...$2, type:'composite', children: $3 }; }
| block document end { yy.getLogger().debug('Rule: blockStatement : ', $1, $2, $3); const id = yy.generateId(); $$ = { id, type:'composite', label:'', children: $2 }; }
;
node
: NODE_ID
{ yy.getLogger().debug("Rule: node (NODE_ID seperator): ", $1); $$ = { id: $1 }; }
| NODE_ID nodeShapeNLabel
{
yy.getLogger().debug("Rule: node (NODE_ID nodeShapeNLabel seperator): ", $1, $2);
$$ = { id: $1, label: $2.label, typeStr: $2.typeStr, directions: $2.directions };
}
;
dirList: DIR { yy.getLogger().debug("Rule: dirList: ", $1); $$ = [$1]; }
| DIR dirList { yy.getLogger().debug("Rule: dirList: ", $1, $2); $$ = [$1].concat($2); }
;
nodeShapeNLabel
: NODE_DSTART STR NODE_DEND
{ yy.getLogger().debug("Rule: nodeShapeNLabel: ", $1, $2, $3); $$ = { typeStr: $1 + $3, label: $2 }; }
| BLOCK_ARROW_START STR dirList BLOCK_ARROW_END
{ yy.getLogger().debug("Rule: BLOCK_ARROW nodeShapeNLabel: ", $1, $2, " #3:",$3, $4); $$ = { typeStr: $1 + $4, label: $2, directions: $3}; }
;
classDefStatement
: classDef CLASSDEF_ID CLASSDEF_STYLEOPTS {
$$ = { type: 'classDef', id: $2.trim(), css: $3.trim() };
}
| classDef DEFAULT CLASSDEF_STYLEOPTS {
$$ = { type: 'classDef', id: $2.trim(), css: $3.trim() };
}
;
cssClassStatement
: class CLASSENTITY_IDS STYLECLASS {
//log.debug('apply class: id(s): ',$2, ' style class: ', $3);
$$={ type: 'applyClass', id: $2.trim(), styleClass: $3.trim() };
}
;
styleStatement
: style STYLE_ENTITY_IDS STYLE_DEFINITION_DATA {
$$={ type: 'applyStyles', id: $2.trim(), stylesStr: $3.trim() };
}
;
%%

View File

@@ -0,0 +1,409 @@
// @ts-ignore: jison doesn't export types
import block from './block.jison';
import db from '../blockDB.js';
import { cleanupComments } from '../../../diagram-api/comments.js';
import { prepareTextForParsing } from '../blockUtils.js';
import { setConfig } from '../../../config.js';
describe('Block diagram', function () {
describe('when parsing an block diagram graph it should handle > ', function () {
beforeEach(function () {
block.parser.yy = db;
block.parser.yy.clear();
block.parser.yy.getLogger = () => console;
});
it('a diagram with a node', async () => {
const str = `block-beta
id
`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(1);
expect(blocks[0].id).toBe('id');
expect(blocks[0].label).toBe('id');
});
it('a node with a square shape and a label', async () => {
const str = `block-beta
id["A label"]
`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(1);
expect(blocks[0].id).toBe('id');
expect(blocks[0].label).toBe('A label');
expect(blocks[0].type).toBe('square');
});
it('a diagram with multiple nodes', async () => {
const str = `block-beta
id1
id2
`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(2);
expect(blocks[0].id).toBe('id1');
expect(blocks[0].label).toBe('id1');
expect(blocks[0].type).toBe('na');
expect(blocks[1].id).toBe('id2');
expect(blocks[1].label).toBe('id2');
expect(blocks[1].type).toBe('na');
});
it('a diagram with multiple nodes', async () => {
const str = `block-beta
id1
id2
id3
`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(3);
expect(blocks[0].id).toBe('id1');
expect(blocks[0].label).toBe('id1');
expect(blocks[0].type).toBe('na');
expect(blocks[1].id).toBe('id2');
expect(blocks[1].label).toBe('id2');
expect(blocks[1].type).toBe('na');
expect(blocks[2].id).toBe('id3');
expect(blocks[2].label).toBe('id3');
expect(blocks[2].type).toBe('na');
});
it('a node with a square shape and a label', async () => {
const str = `block-beta
id["A label"]
id2`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(2);
expect(blocks[0].id).toBe('id');
expect(blocks[0].label).toBe('A label');
expect(blocks[0].type).toBe('square');
expect(blocks[1].id).toBe('id2');
expect(blocks[1].label).toBe('id2');
expect(blocks[1].type).toBe('na');
});
it('a diagram with multiple nodes with edges abc123', async () => {
const str = `block-beta
id1["first"] --> id2["second"]
`;
block.parse(str);
const blocks = db.getBlocks();
const edges = db.getEdges();
expect(blocks.length).toBe(2);
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('id1');
expect(edges[0].end).toBe('id2');
expect(edges[0].arrowTypeEnd).toBe('arrow_point');
});
it('a diagram with multiple nodes with edges abc123', async () => {
const str = `block-beta
id1["first"] -- "a label" --> id2["second"]
`;
block.parse(str);
const blocks = db.getBlocks();
const edges = db.getEdges();
expect(blocks.length).toBe(2);
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('id1');
expect(edges[0].end).toBe('id2');
expect(edges[0].arrowTypeEnd).toBe('arrow_point');
expect(edges[0].label).toBe('a label');
});
it('a diagram with column statements', async () => {
const str = `block-beta
columns 2
block1["Block 1"]
`;
block.parse(str);
expect(db.getColumns('root')).toBe(2);
const blocks = db.getBlocks();
expect(blocks.length).toBe(1);
});
it('a diagram withput column statements', async () => {
const str = `block-beta
block1["Block 1"]
`;
block.parse(str);
expect(db.getColumns('root')).toBe(-1);
const blocks = db.getBlocks();
expect(blocks.length).toBe(1);
});
it('a diagram with auto column statements', async () => {
const str = `block-beta
columns auto
block1["Block 1"]
`;
block.parse(str);
expect(db.getColumns('root')).toBe(-1);
const blocks = db.getBlocks();
expect(blocks.length).toBe(1);
});
it('blocks next to each other', async () => {
const str = `block-beta
columns 2
block1["Block 1"]
block2["Block 2"]
`;
block.parse(str);
const blocks = db.getBlocks();
expect(db.getColumns('root')).toBe(2);
expect(blocks.length).toBe(2);
});
it('blocks on top of each other', async () => {
const str = `block-beta
columns 1
block1["Block 1"]
block2["Block 2"]
`;
block.parse(str);
const blocks = db.getBlocks();
expect(db.getColumns('root')).toBe(1);
expect(blocks.length).toBe(2);
});
it('compound blocks 2', async () => {
const str = `block-beta
block
aBlock["ABlock"]
bBlock["BBlock"]
end
`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(1);
expect(blocks[0].children.length).toBe(2);
expect(blocks[0].id).not.toBe(undefined);
expect(blocks[0].label).toBe('');
expect(blocks[0].type).toBe('composite');
const aBlock = blocks[0].children[0];
expect(aBlock.id).not.toBe(aBlock);
expect(aBlock.label).toBe('ABlock');
expect(aBlock.type).toBe('square');
const bBlock = blocks[0].children[1];
expect(bBlock.id).not.toBe(bBlock);
expect(bBlock.label).toBe('BBlock');
expect(bBlock.type).toBe('square');
});
it('compound blocks of compound blocks', async () => {
const str = `block-beta
block
aBlock["ABlock"]
block
bBlock["BBlock"]
end
end
`;
block.parse(str);
const blocks = db.getBlocks();
const aBlock = blocks[0].children[0];
const secondComposite = blocks[0].children[1];
const bBlock = blocks[0].children[1].children[0];
expect(blocks[0].children.length).toBe(2);
expect(blocks[0].id).not.toBe(undefined);
expect(blocks[0].label).toBe('');
expect(blocks[0].type).toBe('composite');
expect(secondComposite.children.length).toBe(1);
expect(secondComposite.id).not.toBe(undefined);
expect(secondComposite.label).toBe('');
expect(secondComposite.type).toBe('composite');
expect(aBlock.id).not.toBe(aBlock);
expect(aBlock.label).toBe('ABlock');
expect(aBlock.type).toBe('square');
expect(bBlock.id).not.toBe(bBlock);
expect(bBlock.label).toBe('BBlock');
expect(bBlock.type).toBe('square');
});
it('compound blocks with title', async () => {
const str = `block-beta
block:compoundBlock["Compound block"]
columns 1
block2["Block 2"]
end
`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(1);
const compoundBlock = blocks[0];
const block2 = compoundBlock.children[0];
expect(compoundBlock.children.length).toBe(1);
expect(compoundBlock.id).toBe('compoundBlock');
expect(compoundBlock.label).toBe('Compound block');
expect(compoundBlock.type).toBe('composite');
expect(block2.id).toBe('block2');
expect(block2.label).toBe('Block 2');
expect(block2.type).toBe('square');
});
it('blocks mixed with compound blocks', async () => {
const str = `block-beta
columns 1
block1["Block 1"]
block
columns 2
block2["Block 2"]
block3["Block 3"]
end
`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(2);
const compoundBlock = blocks[1];
const block2 = compoundBlock.children[0];
expect(compoundBlock.children.length).toBe(2);
expect(block2.id).toBe('block2');
expect(block2.label).toBe('Block 2');
expect(block2.type).toBe('square');
});
it('Arrow blocks', async () => {
const str = `block-beta
columns 3
block1["Block 1"]
blockArrow<["&nbsp;&nbsp;&nbsp;"]>(right)
block2["Block 2"]`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(3);
const block1 = blocks[0];
const blockArrow = blocks[1];
const block2 = blocks[2];
expect(block1.id).toBe('block1');
expect(blockArrow.id).toBe('blockArrow');
expect(block2.id).toBe('block2');
expect(block2.label).toBe('Block 2');
expect(block2.type).toBe('square');
expect(blockArrow.type).toBe('block_arrow');
expect(blockArrow.directions).toContain('right');
});
it('Arrow blocks with multiple points', async () => {
const str = `block-beta
columns 1
A
blockArrow<["&nbsp;&nbsp;&nbsp;"]>(up, down)
block
columns 3
B
C
D
end`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(3);
const blockArrow = blocks[1];
expect(blockArrow.type).toBe('block_arrow');
expect(blockArrow.directions).toContain('up');
expect(blockArrow.directions).toContain('down');
expect(blockArrow.directions).not.toContain('right');
});
it('blocks with different widths', async () => {
const str = `block-beta
columns 3
one["One Slot"]
two["Two slots"]:2
`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(2);
const one = blocks[0];
const two = blocks[1];
expect(two.widthInColumns).toBe(2);
});
it('empty blocks', async () => {
const str = `block-beta
columns 3
space
middle["In the middle"]
space
`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(3);
const sp1 = blocks[0];
const middle = blocks[1];
const sp2 = blocks[2];
expect(sp1.type).toBe('space');
expect(sp2.type).toBe('space');
expect(middle.label).toBe('In the middle');
});
it('classDef statements applied to a block', async () => {
const str = `block-beta
classDef black color:#ffffff, fill:#000000;
mc["Memcache"]
class mc black
`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(1);
const mc = blocks[0];
expect(mc.classes).toContain('black');
const classes = db.getClasses();
const black = classes.black;
expect(black.id).toBe('black');
expect(black.styles[0]).toEqual('color:#ffffff');
});
it('style statements applied to a block', async () => {
const str = `block-beta
columns 1
B["A wide one in the middle"]
style B fill:#f9F,stroke:#333,stroke-width:4px
`;
block.parse(str);
const blocks = db.getBlocks();
expect(blocks.length).toBe(1);
const B = blocks[0];
expect(B.styles).toContain('fill:#f9F');
});
});
});

View File

@@ -0,0 +1,261 @@
import { getStylesFromArray } from '../../utils.js';
import { insertNode, positionNode } from '../../dagre-wrapper/nodes.js';
import { insertEdge, insertEdgeLabel, positionEdgeLabel } from '../../dagre-wrapper/edges.js';
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { getConfig } from '../../config.js';
import type { ContainerElement } from 'd3';
import type { Block } from './blockTypes.js';
import type { BlockDB } from './blockDB.js';
interface Node {
classes: string;
}
function getNodeFromBlock(block: Block, db: BlockDB, positioned = false) {
const vertex = block;
let classStr = 'default';
if ((vertex?.classes?.length || 0) > 0) {
classStr = (vertex?.classes || []).join(' ');
}
classStr = classStr + ' flowchart-label';
// We create a SVG label, either by delegating to addHtmlLabel or manually
let radius = 0;
let shape = '';
let layoutOptions = {};
let padding;
// Set the shape based parameters
switch (vertex.type) {
case 'round':
radius = 5;
shape = 'rect';
break;
case 'composite':
radius = 0;
shape = 'composite';
padding = 0;
break;
case 'square':
shape = 'rect';
break;
case 'diamond':
shape = 'question';
layoutOptions = {
portConstraints: 'FIXED_SIDE',
};
break;
case 'hexagon':
shape = 'hexagon';
break;
case 'block_arrow':
shape = 'block_arrow';
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 'rect_left_inv_arrow':
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';
}
const styles = getStylesFromArray(vertex?.styles || []);
// Use vertex id as text in the box if no text is provided by the graph definition
const vertexText = vertex.label;
const bounds = vertex.size || { width: 0, height: 0, x: 0, y: 0 };
// Add the node
const node = {
labelStyle: styles.labelStyle,
shape: shape,
labelText: vertexText,
rx: radius,
ry: radius,
class: classStr,
style: styles.style,
id: vertex.id,
directions: vertex.directions,
width: bounds.width,
height: bounds.height,
x: bounds.x,
y: bounds.y,
positioned,
intersect: undefined,
type: vertex.type,
padding: padding ?? (getConfig()?.block?.padding || 0),
};
return node;
}
async function calculateBlockSize(
elem: d3.Selection<SVGGElement, unknown, HTMLElement, any>,
block: any,
db: any
) {
const node = getNodeFromBlock(block, db, false);
if (node.type === 'group') {
return;
}
// Add the element to the DOM to size it
const nodeEl = await insertNode(elem, node);
const boundingBox = nodeEl.node().getBBox();
const obj = db.getBlock(node.id);
obj.size = { width: boundingBox.width, height: boundingBox.height, x: 0, y: 0, node: nodeEl };
db.setBlock(obj);
nodeEl.remove();
}
type ActionFun = typeof calculateBlockSize;
export async function insertBlockPositioned(elem: any, block: Block, db: any) {
const node = getNodeFromBlock(block, db, true);
// Add the element to the DOM to size it
const obj = db.getBlock(node.id);
if (obj.type !== 'space') {
const nodeEl = await insertNode(elem, node);
block.intersect = node?.intersect;
positionNode(node);
}
}
export async function performOperations(
elem: d3.Selection<SVGGElement, unknown, HTMLElement, any>,
blocks: Block[],
db: BlockDB,
operation: ActionFun
) {
for (const block of blocks) {
await operation(elem, block, db);
if (block.children) {
await performOperations(elem, block.children, db, operation);
}
}
}
export async function calculateBlockSizes(elem: any, blocks: Block[], db: BlockDB) {
await performOperations(elem, blocks, db, calculateBlockSize);
}
export async function insertBlocks(
elem: d3.Selection<SVGGElement, unknown, HTMLElement, any>,
blocks: Block[],
db: BlockDB
) {
await performOperations(elem, blocks, db, insertBlockPositioned);
}
export async function insertEdges(
elem: any,
edges: Block[],
blocks: Block[],
db: BlockDB,
id: string
) {
const g = new graphlib.Graph({
multigraph: true,
compound: true,
});
g.setGraph({
rankdir: 'TB',
nodesep: 10,
ranksep: 10,
marginx: 8,
marginy: 8,
});
for (const block of blocks) {
if (block.size) {
g.setNode(block.id, {
width: block.size.width,
height: block.size.height,
intersect: block.intersect,
});
}
}
for (const edge of edges) {
// elem, e, edge, clusterDb, diagramType, graph;
if (edge.start && edge.end) {
const startBlock = db.getBlock(edge.start);
const endBlock = db.getBlock(edge.end);
if (startBlock?.size && endBlock?.size) {
const start = startBlock.size;
const end = endBlock.size;
const points = [
{ x: start.x, y: start.y },
{ x: start.x + (end.x - start.x) / 2, y: start.y + (end.y - start.y) / 2 },
{ x: end.x, y: end.y },
];
// edge.points = points;
await insertEdge(
elem,
{ v: edge.start, w: edge.end, name: edge.id },
{
...edge,
arrowTypeEnd: edge.arrowTypeEnd,
arrowTypeStart: edge.arrowTypeStart,
points,
classes: 'edge-thickness-normal edge-pattern-solid flowchart-link LS-a1 LE-b1',
},
undefined,
'block',
g,
id
);
if (edge.label) {
await insertEdgeLabel(elem, {
...edge,
label: edge.label,
labelStyle: 'stroke: #333; stroke-width: 1.5px;fill:none;',
arrowTypeEnd: edge.arrowTypeEnd,
arrowTypeStart: edge.arrowTypeStart,
points,
classes: 'edge-thickness-normal edge-pattern-solid flowchart-link LS-a1 LE-b1',
});
await positionEdgeLabel(
{ ...edge, x: points[1].x, y: points[1].y },
{
originalPath: points,
}
);
}
}
}
}
}

View File

@@ -0,0 +1,147 @@
import * as khroma from 'khroma';
/** Returns the styles given options */
export interface BlockChartStyleOptions {
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: BlockChartStyleOptions) =>
`.label {
font-family: ${options.fontFamily};
color: ${options.nodeTextColor || options.textColor};
}
.cluster-label text {
fill: ${options.titleColor};
}
.cluster-label span,p {
color: ${options.titleColor};
}
.label text,span,p {
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;
}
.flowchart-label text {
text-anchor: middle;
}
// .flowchart-label .text-outer-tspan {
// text-anchor: middle;
// }
// .flowchart-label .text-inner-tspan {
// text-anchor: start;
// }
.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.5;
background-color: ${options.edgeLabelBackground};
fill: ${options.edgeLabelBackground};
}
text-align: center;
}
/* For html labels only */
.labelBkg {
background-color: ${fade(options.edgeLabelBackground, 0.5)};
// background-color:
}
.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;
stroke-width: 1px;
}
.cluster text {
fill: ${options.titleColor};
}
.cluster span,p {
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};
}
`;
export default getStyles;

View File

@@ -18,13 +18,18 @@ export const getRows = (s?: string): string[] => {
return str.split('#br#'); return str.split('#br#');
}; };
/** const setupDompurifyHooksIfNotSetup = (() => {
* Removes script tags from a text let setup = false;
*
* @param txt - The text to sanitize return () => {
* @returns The safer text if (!setup) {
*/ setupDompurifyHooks();
export const removeScript = (txt: string): string => { setup = true;
}
};
})();
function setupDompurifyHooks() {
const TEMPORARY_ATTRIBUTE = 'data-temp-href-target'; const TEMPORARY_ATTRIBUTE = 'data-temp-href-target';
DOMPurify.addHook('beforeSanitizeAttributes', (node: Element) => { DOMPurify.addHook('beforeSanitizeAttributes', (node: Element) => {
@@ -33,8 +38,6 @@ export const removeScript = (txt: string): string => {
} }
}); });
const sanitizedText = DOMPurify.sanitize(txt);
DOMPurify.addHook('afterSanitizeAttributes', (node: Element) => { DOMPurify.addHook('afterSanitizeAttributes', (node: Element) => {
if (node.tagName === 'A' && node.hasAttribute(TEMPORARY_ATTRIBUTE)) { if (node.tagName === 'A' && node.hasAttribute(TEMPORARY_ATTRIBUTE)) {
node.setAttribute('target', node.getAttribute(TEMPORARY_ATTRIBUTE) || ''); node.setAttribute('target', node.getAttribute(TEMPORARY_ATTRIBUTE) || '');
@@ -44,6 +47,18 @@ export const removeScript = (txt: string): string => {
} }
} }
}); });
}
/**
* Removes script tags from a text
*
* @param txt - The text to sanitize
* @returns The safer text
*/
export const removeScript = (txt: string): string => {
setupDompurifyHooksIfNotSetup();
const sanitizedText = DOMPurify.sanitize(txt);
return sanitizedText; return sanitizedText;
}; };

View File

@@ -11,7 +11,7 @@ import { configureSvgSize } from '../../setupGraphViewbox.js';
* @param version - The version * @param version - The version
*/ */
export const draw = (_text: string, id: string, version: string) => { export const draw = (_text: string, id: string, version: string) => {
log.debug('renering svg for syntax error\n'); log.debug('rendering svg for syntax error\n');
const svg: SVG = selectSvgElement(id); const svg: SVG = selectSvgElement(id);
svg.attr('viewBox', '0 0 2412 512'); svg.attr('viewBox', '0 0 2412 512');

View File

@@ -309,13 +309,12 @@ const getNextPosition = (position, edgeDirection, graphDirection) => {
}, },
}; };
portPos.TD = portPos.TB; portPos.TD = portPos.TB;
log.info('abc88', graphDirection, edgeDirection, position);
return portPos[graphDirection][edgeDirection][position]; return portPos[graphDirection][edgeDirection][position];
// return 'south'; // return 'south';
}; };
const getNextPort = (node, edgeDirection, graphDirection) => { const getNextPort = (node, edgeDirection, graphDirection) => {
log.info('getNextPort abc88', { node, edgeDirection, graphDirection }); log.info('getNextPort', { node, edgeDirection, graphDirection });
if (!portPos[node]) { if (!portPos[node]) {
switch (graphDirection) { switch (graphDirection) {
case 'TB': case 'TB':

View File

@@ -349,6 +349,8 @@ export const getClasses = function (text, diagObj) {
* *
* @param text * @param text
* @param id * @param id
* @param _version
* @param diagObj
*/ */
export const draw = async function (text, id, _version, diagObj) { export const draw = async function (text, id, _version, diagObj) {

View File

@@ -1,7 +1,7 @@
import flowDb from '../flowDb.js'; import flowDb from '../flowDb.js';
import flow from './flow.jison'; import flow from './flow.jison';
import { setConfig } from '../../../config.js';
import { cleanupComments } from '../../../diagram-api/comments.js'; import { cleanupComments } from '../../../diagram-api/comments.js';
import { setConfig } from '../../../config.js';
setConfig({ setConfig({
securityLevel: 'strict', securityLevel: 'strict',

View File

@@ -27,11 +27,10 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
\%\%(?!\{)*[^\n]* /* skip comments */ \%\%(?!\{)*[^\n]* /* skip comments */
[^\}]\%\%*[^\n]* /* skip comments */ [^\}]\%\%*[^\n]* /* skip comments */
\%\%*[^\n]*[\n]* /* do nothing */ \%\%*[^\n]*[\n]* /* do nothing */
[\n]+ return 'NL'; [\n]+ return 'NL';
\s+ /* skip whitespace */ \s+ /* skip whitespace */
\#[^\n]* /* skip comments */
\%%[^\n]* /* skip comments */ \%%[^\n]* /* skip comments */
/* /*
@@ -86,10 +85,10 @@ weekday\s+friday return 'weekday_friday'
weekday\s+saturday return 'weekday_saturday' weekday\s+saturday return 'weekday_saturday'
weekday\s+sunday return 'weekday_sunday' weekday\s+sunday return 'weekday_sunday'
\d\d\d\d"-"\d\d"-"\d\d return 'date'; \d\d\d\d"-"\d\d"-"\d\d return 'date';
"title"\s[^#\n;]+ return 'title'; "title"\s[^\n]+ return 'title';
"accDescription"\s[^#\n;]+ return 'accDescription' "accDescription"\s[^#\n;]+ return 'accDescription'
"section"\s[^#:\n;]+ return 'section'; "section"\s[^\n]+ return 'section';
[^#:\n;]+ return 'taskTxt'; [^:\n]+ return 'taskTxt';
":"[^#\n;]+ return 'taskData'; ":"[^#\n;]+ return 'taskData';
":" return ':'; ":" return ':';
<<EOF>> return 'EOF'; <<EOF>> return 'EOF';

Some files were not shown because too many files have changed in this diff Show More