mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-13 04:19:44 +02:00
Compare commits
174 Commits
lazy-load-
...
sidv/testR
Author | SHA1 | Date | |
---|---|---|---|
![]() |
361dd6a96e | ||
![]() |
17adec38af | ||
![]() |
638b9d9aae | ||
![]() |
c8f6994895 | ||
![]() |
1117a80500 | ||
![]() |
5d83ec6fa2 | ||
![]() |
bab5937426 | ||
![]() |
099a26977a | ||
![]() |
0b834485a8 | ||
![]() |
41f21d4f72 | ||
![]() |
312e5f3d96 | ||
![]() |
6ef3e7f536 | ||
![]() |
4f5228aec4 | ||
![]() |
b9daa35558 | ||
![]() |
21304a9677 | ||
![]() |
3f6613ea9f | ||
![]() |
c8635c0b9b | ||
![]() |
e78ac9b92a | ||
![]() |
7a47fcfcbc | ||
![]() |
d4c19ffa59 | ||
![]() |
120940f9f4 | ||
![]() |
48b1f489fc | ||
![]() |
e62dd255bc | ||
![]() |
13110c4ed9 | ||
![]() |
327fcbf902 | ||
![]() |
81924f72c8 | ||
![]() |
5d048ce21e | ||
![]() |
1a0309fb87 | ||
![]() |
e793aae0ec | ||
![]() |
3a2669e634 | ||
![]() |
895a5eb78a | ||
![]() |
4601c90904 | ||
![]() |
8ad8d39fe4 | ||
![]() |
56a8068a7f | ||
![]() |
d17aa6ecdd | ||
![]() |
6f27363862 | ||
![]() |
5192608f7c | ||
![]() |
77f5e0d5f3 | ||
![]() |
4c311ea4b1 | ||
![]() |
bbb3712284 | ||
![]() |
1388e201e5 | ||
![]() |
125312c114 | ||
![]() |
ea314cd24a | ||
![]() |
8230c8f8b4 | ||
![]() |
d115fbc6da | ||
![]() |
2ae8bf2987 | ||
![]() |
e86d7894f5 | ||
![]() |
752a6b2cb0 | ||
![]() |
97a842e651 | ||
![]() |
c83e29c6e3 | ||
![]() |
a4af3704ba | ||
![]() |
775fb80c43 | ||
![]() |
aec1d80966 | ||
![]() |
58a53c0fa8 | ||
![]() |
b486177ca7 | ||
![]() |
957e64fe8a | ||
![]() |
7881d1e457 | ||
![]() |
16be835c9b | ||
![]() |
59cf085af5 | ||
![]() |
fc8db95597 | ||
![]() |
cc10e62ebd | ||
![]() |
bed95c77a9 | ||
![]() |
d348f2847c | ||
![]() |
4d46ea9801 | ||
![]() |
eec97d10af | ||
![]() |
ebef4a1416 | ||
![]() |
24605784f2 | ||
![]() |
3240f8ae56 | ||
![]() |
50f44c5cb0 | ||
![]() |
cc2f4f779a | ||
![]() |
00ce0fc034 | ||
![]() |
551b37f969 | ||
![]() |
bc5ef5fb7d | ||
![]() |
c20b8a0664 | ||
![]() |
9660b0e9fb | ||
![]() |
23e590e09b | ||
![]() |
60e4585e20 | ||
![]() |
ba436cc37a | ||
![]() |
960ea450e9 | ||
![]() |
8ffa7e6334 | ||
![]() |
2fb1876023 | ||
![]() |
f5692e742b | ||
![]() |
d7e7498fea | ||
![]() |
8ea1a1a077 | ||
![]() |
7cd281eea8 | ||
![]() |
1570eb7b73 | ||
![]() |
5060c9f390 | ||
![]() |
1fea43e125 | ||
![]() |
ef47cc5b6f | ||
![]() |
e876c35ef9 | ||
![]() |
800cb65706 | ||
![]() |
25ff005dd7 | ||
![]() |
72c266b242 | ||
![]() |
828f69f011 | ||
![]() |
ad4b079d63 | ||
![]() |
5d4d7c5fbf | ||
![]() |
238b15df9d | ||
![]() |
6e2deb1fa7 | ||
![]() |
1255c0064b | ||
![]() |
d2300d375b | ||
![]() |
235797a97c | ||
![]() |
508fbccdb4 | ||
![]() |
ad0cb7ff3c | ||
![]() |
bc258793ac | ||
![]() |
10d2e0a62f | ||
![]() |
738abc8946 | ||
![]() |
de5ad8644e | ||
![]() |
97b39bca95 | ||
![]() |
3698b30809 | ||
![]() |
069437842b | ||
![]() |
ee13c7666d | ||
![]() |
a23a7edd26 | ||
![]() |
e21da2ec7f | ||
![]() |
2b40bc0a48 | ||
![]() |
7e1006db26 | ||
![]() |
44f463c4f4 | ||
![]() |
6029bdeee9 | ||
![]() |
0261e7464a | ||
![]() |
a22158b2e2 | ||
![]() |
8a3bd5bcb8 | ||
![]() |
514d12d48c | ||
![]() |
01fac85cde | ||
![]() |
18283bc48f | ||
![]() |
f31db315b8 | ||
![]() |
8a2aea219e | ||
![]() |
034fe80411 | ||
![]() |
6d9b695ada | ||
![]() |
9c1da3bca1 | ||
![]() |
0e61395aa9 | ||
![]() |
8215c7d98e | ||
![]() |
ee45ab2e6c | ||
![]() |
b1f3e21d28 | ||
![]() |
a4b0e6b87b | ||
![]() |
9fe7152d98 | ||
![]() |
0859f28a14 | ||
![]() |
56b9aab5ce | ||
![]() |
aacc40e525 | ||
![]() |
b0ed5e9be2 | ||
![]() |
3777ccb305 | ||
![]() |
6b736f0bb0 | ||
![]() |
2e72c0bf6e | ||
![]() |
a1757ba217 | ||
![]() |
5390c409d0 | ||
![]() |
4f91c9a8de | ||
![]() |
8cf4efc190 | ||
![]() |
405df09e43 | ||
![]() |
86adf96021 | ||
![]() |
a0c3de568b | ||
![]() |
c10eb5af79 | ||
![]() |
3c4acd2184 | ||
![]() |
ab1573053e | ||
![]() |
c404f6fe34 | ||
![]() |
d24256e1c2 | ||
![]() |
e494e2dc56 | ||
![]() |
ab2e727db9 | ||
![]() |
b9fcb66d28 | ||
![]() |
12e4819c49 | ||
![]() |
0b54366705 | ||
![]() |
c99fd2baa9 | ||
![]() |
868cb529aa | ||
![]() |
2d01548d02 | ||
![]() |
6fb92f6f3c | ||
![]() |
f4a5b80eff | ||
![]() |
74c7a8585d | ||
![]() |
8c1046169f | ||
![]() |
2389f4a285 | ||
![]() |
24fb2337d7 | ||
![]() |
cc55a82b64 | ||
![]() |
1f8fb56409 | ||
![]() |
5865c890b5 | ||
![]() |
00053b8e97 | ||
![]() |
1615c6d9f9 | ||
![]() |
43f3784c83 | ||
![]() |
c5d859e52e |
@@ -52,24 +52,25 @@
|
|||||||
},
|
},
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": "./**/*.html",
|
"files": ["cypress/**", "demos/**"],
|
||||||
"rules": {
|
|
||||||
"no-undef": "off",
|
|
||||||
"jsdoc/require-jsdoc": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": ["./cypress/**", "./demos/**"],
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-console": "off"
|
"no-console": "off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": ["./**/*.spec.{ts,js}", "./cypress/**", "./demos/**", "./**/docs/**"],
|
"files": ["*.spec.{ts,js}", "cypress/**", "demos/**", "**/docs/**"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"jsdoc/require-jsdoc": "off",
|
"jsdoc/require-jsdoc": "off",
|
||||||
"@typescript-eslint/no-unused-vars": "off"
|
"@typescript-eslint/no-unused-vars": "off"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["*.html", "*.md", "**/*.md/*"],
|
||||||
|
"rules": {
|
||||||
|
"no-var": "error",
|
||||||
|
"no-undef": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": "off"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,43 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve
|
|
||||||
title: ''
|
|
||||||
labels: 'Status: Triage, Type: Bug / Error'
|
|
||||||
assignees: ''
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
Steps to reproduce the behavior:
|
|
||||||
|
|
||||||
1. Go to '...'
|
|
||||||
2. Click on '....'
|
|
||||||
3. Scroll down to '....'
|
|
||||||
4. See error
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**Code Sample**
|
|
||||||
If applicable, add the code sample or a link to the [live editor](https://mermaid.live).
|
|
||||||
|
|
||||||
**Desktop (please complete the following information):**
|
|
||||||
|
|
||||||
- OS: [e.g. iOS]
|
|
||||||
- Browser [e.g. chrome, safari]
|
|
||||||
- Version [e.g. 22]
|
|
||||||
|
|
||||||
**Smartphone (please complete the following information):**
|
|
||||||
|
|
||||||
- Device: [e.g. iPhone6]
|
|
||||||
- OS: [e.g. iOS8.1]
|
|
||||||
- Browser [e.g. stock browser, safari]
|
|
||||||
- Version [e.g. 22]
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
69
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
69
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: Create a report to help us improve
|
||||||
|
labels:
|
||||||
|
- 'Status: Triage'
|
||||||
|
- 'Type: Bug / Error'
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |-
|
||||||
|
## Security vulnerabilities
|
||||||
|
Please refer our [Security Policy](https://github.com/mermaid-js/.github/blob/main/SECURITY.md) and report to keep vulnerabilities confidential so we can release fixes first.
|
||||||
|
|
||||||
|
## Before you submit...
|
||||||
|
We like to help you, but in order to do that should you make a few things first:
|
||||||
|
|
||||||
|
- Use a clear and concise title
|
||||||
|
- Fill out the text fields with as much detail as possible.
|
||||||
|
- Never be shy to give us screenshots and/or code samples. It will help!
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: Give a clear and concise description of what the bug is.
|
||||||
|
placeholder: When I do ... does ... happen.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
description: Give a step-by-step example on how to reproduce the bug.
|
||||||
|
placeholder: |-
|
||||||
|
1. Do this
|
||||||
|
2. Do that
|
||||||
|
3. ...
|
||||||
|
4. Bug!
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Screenshots
|
||||||
|
description: If applicable, add screenshots to help explain your issue.
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Code Sample
|
||||||
|
description: |-
|
||||||
|
If applicable, add the code sample or a link to the [Live Editor](https://mermaid.live).
|
||||||
|
Any text pasted here will be rendered as a Code block.
|
||||||
|
render: text
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Setup
|
||||||
|
description: |-
|
||||||
|
Please fill out the below info.
|
||||||
|
Note that you only need to fill out one and not both sections.
|
||||||
|
value: |-
|
||||||
|
**Desktop**
|
||||||
|
|
||||||
|
- OS and Version: [Windows, Linux, Mac, ...]
|
||||||
|
- Browser and Version: [Chrome, Edge, Firefox]
|
||||||
|
|
||||||
|
**Smartphone**
|
||||||
|
|
||||||
|
- Device: [Samsung, iPhone, ...]
|
||||||
|
- OS and Version: [Android, iOS, ...]
|
||||||
|
- Browser and Version: [Chrome, Safari, ...]
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional Context
|
||||||
|
description: Anything else to add?
|
17
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
17
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: GitHub Discussions
|
||||||
|
url: https://github.com/mermaid-js/mermaid/discussions
|
||||||
|
about: Ask the Community questions or share your own graphs in our discussions.
|
||||||
|
- name: Security Vulnerability
|
||||||
|
url: https://github.com/mermaid-js/.github/blob/main/SECURITY.md
|
||||||
|
about: Report security issues
|
||||||
|
- name: Slack
|
||||||
|
url: https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE
|
||||||
|
about: Join our Community on Slack for Help and a casual chat.
|
||||||
|
- name: Documentation
|
||||||
|
url: https://mermaid-js.github.io
|
||||||
|
about: Read our documentation for all that Mermaid.js can offer.
|
||||||
|
- name: Live Editor
|
||||||
|
url: https://mermaid.live
|
||||||
|
about: Try the live editor to preview graphs in no time.
|
42
.github/ISSUE_TEMPLATE/diagram_proposal.yml
vendored
Normal file
42
.github/ISSUE_TEMPLATE/diagram_proposal.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
name: Diagram Proposal
|
||||||
|
description: Suggest a new Diagram Type to add to Mermaid.
|
||||||
|
labels:
|
||||||
|
- 'Status: Triage'
|
||||||
|
- 'Type: Enhancement'
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |-
|
||||||
|
## Before you submit...
|
||||||
|
First of all, thank you for proposing a new Diagram to us.
|
||||||
|
We are always happy about new ideas to improve Mermaid.js wherever possible.
|
||||||
|
|
||||||
|
To get the fastest and best response possible, make sure you do the following:
|
||||||
|
|
||||||
|
- Use a clear and concise title
|
||||||
|
- Fill out the text fields with as much detail as possible.
|
||||||
|
- Never be shy to give us screenshots and/or code samples. It will help!
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Proposal
|
||||||
|
description: A clear and concise description of what should be added to Mermaid.js.
|
||||||
|
placeholder: Mermaid.js should add ... because ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Use Cases
|
||||||
|
description: If applicable, give some use cases for where this diagram would be useful.
|
||||||
|
placeholder: The Diagram could be used for ...
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Screenshots
|
||||||
|
description: If applicable, add screenshots to show possible examples of how the diagram may look like.
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Code Sample
|
||||||
|
description: |-
|
||||||
|
If applicable, add a code sample for how to implement this new diagram.
|
||||||
|
The text will automatically be rendered as JavaScript code.
|
||||||
|
render: javascript
|
19
.github/ISSUE_TEMPLATE/feature_request.md
vendored
19
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,19 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for this project
|
|
||||||
title: ''
|
|
||||||
labels: 'Status: Triage, Type: Enhancement'
|
|
||||||
assignees: ''
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you want to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context or screenshots about the feature request here.
|
|
16
.github/ISSUE_TEMPLATE/question.md
vendored
16
.github/ISSUE_TEMPLATE/question.md
vendored
@@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
name: Question
|
|
||||||
about: Get some help from the community.
|
|
||||||
title: ''
|
|
||||||
labels: 'Help wanted!, Type: Other'
|
|
||||||
assignees: ''
|
|
||||||
---
|
|
||||||
|
|
||||||
## Help us help you!
|
|
||||||
|
|
||||||
You want an answer. Here are some ways to get it quicker:
|
|
||||||
|
|
||||||
- Use a clear and concise title.
|
|
||||||
- Try to pose a clear and concise question.
|
|
||||||
- Include as much, or as little, code as necessary.
|
|
||||||
- Don't be shy to give us some screenshots, if it helps!
|
|
34
.github/ISSUE_TEMPLATE/syntax_proposal.yml
vendored
Normal file
34
.github/ISSUE_TEMPLATE/syntax_proposal.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: Syntax Proposal
|
||||||
|
description: Suggest a new Syntax to add to Mermaid.js.
|
||||||
|
labels:
|
||||||
|
- 'Status: Triage'
|
||||||
|
- 'Type: Enhancement'
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |-
|
||||||
|
## Before you submit...
|
||||||
|
First of all, thank you for proposing a new Syntax to us.
|
||||||
|
We are always happy about new ideas to improve Mermaid.js wherever possible.
|
||||||
|
|
||||||
|
To get the fastest and best response possible, make sure you do the following:
|
||||||
|
|
||||||
|
- Use a clear and concise title
|
||||||
|
- Fill out the text fields with as much detail as possible. Examples are always welcome.
|
||||||
|
- Never be shy to give us screenshots and/or code samples. It will help!
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Proposal
|
||||||
|
description: A clear and concise description of what Syntax should be added to Mermaid.js.
|
||||||
|
placeholder: Mermaid.js should add ... because ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Example
|
||||||
|
description: If applicable, provide an example of the new Syntax.
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Screenshots
|
||||||
|
description: If applicable, add screenshots to show possible examples of how the theme may look like.
|
42
.github/ISSUE_TEMPLATE/theme_proposal.yml
vendored
Normal file
42
.github/ISSUE_TEMPLATE/theme_proposal.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
name: Theme Proposal
|
||||||
|
description: Suggest a new theme to add to Mermaid.js.
|
||||||
|
labels:
|
||||||
|
- 'Status: Triage'
|
||||||
|
- 'Type: Enhancement'
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |-
|
||||||
|
## Before you submit...
|
||||||
|
First of all, thank you for proposing a new Theme to us.
|
||||||
|
We are always happy about new ideas to improve Mermaid.js wherever possible.
|
||||||
|
|
||||||
|
To get the fastest and best response possible, make sure you do the following:
|
||||||
|
|
||||||
|
- Use a clear and concise title
|
||||||
|
- Fill out the text fields with as much detail as possible. Examples are always welcome!
|
||||||
|
- Never be shy to give us screenshots and/or code samples. It will help!
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Proposal
|
||||||
|
description: A clear and concise description of what theme should be added to Mermaid.js.
|
||||||
|
placeholder: Mermaid.js should add ... because ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Colors
|
||||||
|
description: |-
|
||||||
|
A detailed list of the different colour values to use.
|
||||||
|
A list of currently used variable names can be found [here](https://mermaid-js.github.io/mermaid/#/theming?id=theme-variables-reference-table)
|
||||||
|
placeholder: |-
|
||||||
|
- background: #f4f4f4
|
||||||
|
- primaryColor: #fff4dd
|
||||||
|
- ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Screenshots
|
||||||
|
description: If applicable, add screenshots to show possible examples of how the theme may look like.
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [16.x]
|
node-version: [18.x]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
28
.github/workflows/docs.yml
vendored
Normal file
28
.github/workflows/docs.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
name: Documentation Checks
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
paths:
|
||||||
|
- 'packages/mermaid/src/docs/**/*'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
paths:
|
||||||
|
- 'packages/mermaid/src/docs/**/*'
|
||||||
|
jobs:
|
||||||
|
spellcheck:
|
||||||
|
name: 'Docs: Spellcheck'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
name: Check out the code
|
||||||
|
- uses: actions/setup-node@v1
|
||||||
|
name: Setup node
|
||||||
|
with:
|
||||||
|
node-version: '16'
|
||||||
|
- run: npm install -g cspell
|
||||||
|
name: Install cSpell
|
||||||
|
- run: cspell --config ./cSpell.json "packages/mermaid/src/docs/**/*.md" --no-progress
|
||||||
|
name: Run cSpell
|
2
.github/workflows/e2e-applitools.yml
vendored
2
.github/workflows/e2e-applitools.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [16.x]
|
node-version: [18.x]
|
||||||
steps:
|
steps:
|
||||||
- if: ${{ ! env.USE_APPLI }}
|
- if: ${{ ! env.USE_APPLI }}
|
||||||
name: Warn if not using Applitools
|
name: Warn if not using Applitools
|
||||||
|
2
.github/workflows/e2e.yml
vendored
2
.github/workflows/e2e.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [16.x]
|
node-version: [18.x]
|
||||||
containers: [1, 2, 3, 4]
|
containers: [1, 2, 3, 4]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [16.x]
|
node-version: [18.x]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 18.x
|
||||||
- name: Install Yarn
|
- name: Install Yarn
|
||||||
run: npm i yarn --global
|
run: npm i yarn --global
|
||||||
|
|
||||||
|
2
.github/workflows/release-publish.yml
vendored
2
.github/workflows/release-publish.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 18.x
|
||||||
- name: Install Yarn
|
- name: Install Yarn
|
||||||
run: npm i yarn --global
|
run: npm i yarn --global
|
||||||
|
|
||||||
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [16.x]
|
node-version: [18.x]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -32,3 +32,6 @@ cypress/snapshots/
|
|||||||
.eslintcache
|
.eslintcache
|
||||||
.tsbuildinfo
|
.tsbuildinfo
|
||||||
tsconfig.tsbuildinfo
|
tsconfig.tsbuildinfo
|
||||||
|
knsv*.html
|
||||||
|
|
||||||
|
local*.html
|
||||||
|
@@ -6,6 +6,7 @@ import pkg from '../package.json' assert { type: 'json' };
|
|||||||
|
|
||||||
const { dependencies } = pkg;
|
const { dependencies } = pkg;
|
||||||
const watch = process.argv.includes('--watch');
|
const watch = process.argv.includes('--watch');
|
||||||
|
const mermaidOnly = process.argv.includes('--mermaid');
|
||||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||||
|
|
||||||
type OutputOptions = Exclude<
|
type OutputOptions = Exclude<
|
||||||
@@ -129,14 +130,19 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => {
|
|||||||
const main = async () => {
|
const main = async () => {
|
||||||
const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[];
|
const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[];
|
||||||
for (const pkg of packageNames) {
|
for (const pkg of packageNames) {
|
||||||
|
if (mermaidOnly && pkg !== 'mermaid') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
await buildPackage(pkg);
|
await buildPackage(pkg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (watch) {
|
if (watch) {
|
||||||
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid' }));
|
build(getBuildConfig({ minify: false, watch, core: true, entryName: 'mermaid' }));
|
||||||
|
if (!mermaidOnly) {
|
||||||
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-mindmap' }));
|
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-mindmap' }));
|
||||||
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
|
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
void main();
|
void main();
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,15 @@
|
|||||||
import express from 'express';
|
import express, { NextFunction, Request, Response } from 'express';
|
||||||
import { createServer as createViteServer } from 'vite';
|
import { createServer as createViteServer } from 'vite';
|
||||||
// import { getBuildConfig } from './build';
|
// import { getBuildConfig } from './build';
|
||||||
|
|
||||||
|
const cors = (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
|
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
|
||||||
|
res.header('Access-Control-Allow-Headers', 'Content-Type');
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
async function createServer() {
|
async function createServer() {
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
@@ -12,6 +20,7 @@ async function createServer() {
|
|||||||
appType: 'custom', // don't include Vite's default HTML handling middlewares
|
appType: 'custom', // don't include Vite's default HTML handling middlewares
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.use(cors);
|
||||||
app.use(express.static('./packages/mermaid/dist'));
|
app.use(express.static('./packages/mermaid/dist'));
|
||||||
app.use(express.static('./packages/mermaid-example-diagram/dist'));
|
app.use(express.static('./packages/mermaid-example-diagram/dist'));
|
||||||
app.use(express.static('./packages/mermaid-mindmap/dist'));
|
app.use(express.static('./packages/mermaid-mindmap/dist'));
|
||||||
|
@@ -6,12 +6,23 @@ So you want to help? That's great!
|
|||||||
|
|
||||||
Here are a few things to know to get you started on the right path.
|
Here are a few things to know to get you started on the right path.
|
||||||
|
|
||||||
|
Below link will help you making a copy of the repository in your local system.
|
||||||
|
|
||||||
|
https://docs.github.com/en/get-started/quickstart/fork-a-repo
|
||||||
|
|
||||||
|
## 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
|
## Development Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone git@github.com:mermaid-js/mermaid.git
|
git clone git@github.com:mermaid-js/mermaid.git
|
||||||
cd mermaid
|
cd mermaid
|
||||||
pnpm install
|
# npx is required for first install as volta support for pnpm is not added yet.
|
||||||
|
npx pnpm install
|
||||||
pnpm test
|
pnpm test
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -39,16 +50,16 @@ Less strict here, it is OK to commit directly in the `develop` branch if you are
|
|||||||
|
|
||||||
The documentation is written in **Markdown**. 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).
|
The documentation is written in **Markdown**. 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).
|
||||||
|
|
||||||
### Documentation source files are in /src/docs
|
### Documentation source files are in [`/packages/mermaid/src/docs`](packages/mermaid/src/docs)
|
||||||
|
|
||||||
The source files for the project documentation are located in the `/src/docs` directory. This is where you should make changes.
|
The source files for the project documentation are located in the [`/packages/mermaid/src/docs`](packages/mermaid/src/docs) directory. This is where you should make changes.
|
||||||
The files under `/src/docs` are processed to generate the published documentation, and the resulting files are put into the `/docs` directory.
|
The files under `/packages/mermaid/src/docs` are processed to generate the published documentation, and the resulting files are put into the `/docs` directory.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR
|
flowchart LR
|
||||||
classDef default fill:#fff,color:black,stroke:black
|
classDef default fill:#fff,color:black,stroke:black
|
||||||
|
|
||||||
source["files in /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"]
|
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"]
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -137,7 +148,7 @@ it('should render forks and joins', () => {
|
|||||||
|
|
||||||
Finally, if it is not in the documentation, no one will know about it and then **no one will use it**. Wouldn't that be sad? With all the effort that was put into the feature?
|
Finally, if it is not in the documentation, no one will know about it and then **no one will use it**. Wouldn't that be sad? With all the effort that was put into the feature?
|
||||||
|
|
||||||
The source files for documentation are in `/src/docs` and are written in markdown. Just pick the right section and start typing. See the [Committing Documentation](#committing-documentation) section for more about how the documentation is generated.
|
The source files for documentation are in `/packages/mermaid/src/docs` and are written in markdown. Just pick the right section and start typing. See the [Committing Documentation](#committing-documentation) section for more about how the documentation is generated.
|
||||||
|
|
||||||
#### Adding to or changing the documentation organization
|
#### Adding to or changing the documentation organization
|
||||||
|
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
# mermaid [](https://travis-ci.org/mermaid-js/mermaid) [](https://www.npmjs.com/package/mermaid) [](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
|
# mermaid
|
||||||
|
|
||||||
# Whoa, whats going on here?
|
[](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml) [](https://www.npmjs.com/package/mermaid) [](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [](https://www.jsdelivr.com/package/npm/mermaid) [](https://www.npmjs.com/package/mermaid) [](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [](https://twitter.com/mermaidjs_)
|
||||||
|
|
||||||
|
# Whoa, what's going on here?
|
||||||
|
|
||||||
We are transforming the Mermaid repository to a so called mono-repo. This is a part of the effort to decouple the diagrams from the core of mermaid. This will:
|
We are transforming the Mermaid repository to a so called mono-repo. This is a part of the effort to decouple the diagrams from the core of mermaid. This will:
|
||||||
|
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
# mermaid [](https://travis-ci.org/mermaid-js/mermaid) [](https://www.npmjs.com/package/mermaid) [](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
|
# mermaid
|
||||||
|
|
||||||
|
[](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml) [](https://www.npmjs.com/package/mermaid) [](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [](https://www.jsdelivr.com/package/npm/mermaid) [](https://www.npmjs.com/package/mermaid) [](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [](https://twitter.com/mermaidjs_)
|
||||||
|
|
||||||
[English](./README.md) | 简体中文
|
[English](./README.md) | 简体中文
|
||||||
|
|
||||||
|
@@ -1,3 +1 @@
|
|||||||
import { vi } from 'vitest';
|
// DO NOT delete this file. It is used by vitest to mock the dagre-d3 module.
|
||||||
|
|
||||||
// export const render = vi.fn();
|
|
||||||
|
95
cSpell.json
Normal file
95
cSpell.json
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2",
|
||||||
|
"language": "en",
|
||||||
|
"words": [
|
||||||
|
"customizability",
|
||||||
|
"Gantt",
|
||||||
|
"jison",
|
||||||
|
"knsv",
|
||||||
|
"Knut",
|
||||||
|
"mindmap",
|
||||||
|
"Mindmaps",
|
||||||
|
"mitigations",
|
||||||
|
"sandboxed",
|
||||||
|
"Sveidqvist",
|
||||||
|
"verdana",
|
||||||
|
"Visio"
|
||||||
|
],
|
||||||
|
"ignoreWords": [
|
||||||
|
"Adamiecki",
|
||||||
|
"applitools",
|
||||||
|
"Asciidoctor",
|
||||||
|
"Astah",
|
||||||
|
"Bisheng",
|
||||||
|
"codedoc",
|
||||||
|
"Docsy",
|
||||||
|
"Doku",
|
||||||
|
"Gitea",
|
||||||
|
"Gitgraph",
|
||||||
|
"Grav",
|
||||||
|
"Inkdrop",
|
||||||
|
"Jaoude",
|
||||||
|
"mdbook",
|
||||||
|
"mermerd",
|
||||||
|
"mkdocs",
|
||||||
|
"phpbb",
|
||||||
|
"Plantuml",
|
||||||
|
"Playfair's",
|
||||||
|
"Podlite",
|
||||||
|
"redmine",
|
||||||
|
"sphinxcontrib",
|
||||||
|
"Tuleap"
|
||||||
|
],
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"name": "Markdown links",
|
||||||
|
"pattern": "\\((.*)\\)",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Markdown code blocks",
|
||||||
|
"pattern": "/^(\\s*`{3,}).*[\\s\\S]*?^\\1/gmx",
|
||||||
|
"description": "Taken from the cSpell example at https://cspell.org/configuration/patterns/#verbose-regular-expressions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Inline code blocks",
|
||||||
|
"pattern": "\\`([^\\`\\r\\n]+?)\\`",
|
||||||
|
"description": "https://stackoverflow.com/questions/41274241/how-to-capture-inline-markdown-code-but-not-a-markdown-code-fence-with-regex"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Link contents",
|
||||||
|
"pattern": "\\<a(.*)\\>",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Snippet references",
|
||||||
|
"pattern": "-- snippet:(.*)",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Snippet references 2",
|
||||||
|
"pattern": "\\<\\[sample:(.*)",
|
||||||
|
"description": "another kind of snippet reference"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Multi-line code blocks",
|
||||||
|
"pattern": "/^\\s*```[\\s\\S]*?^\\s*```/gm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HTML Tags",
|
||||||
|
"pattern": "<[^>]*>",
|
||||||
|
"description": "Reference: https://stackoverflow.com/questions/11229831/regular-expression-to-remove-html-tags-from-a-string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ignoreRegExpList": [
|
||||||
|
"Markdown links",
|
||||||
|
"Markdown code blocks",
|
||||||
|
"Inline code blocks",
|
||||||
|
"Link contents",
|
||||||
|
"Snippet references",
|
||||||
|
"Snippet references 2",
|
||||||
|
"Multi-line code blocks",
|
||||||
|
"HTML Tags"
|
||||||
|
],
|
||||||
|
"ignorePaths": ["packages/mermaid/src/docs/CHANGELOG.md"]
|
||||||
|
}
|
@@ -75,16 +75,6 @@ classDiagram
|
|||||||
<pre id="diagram" class="mermaid2">
|
<pre id="diagram" class="mermaid2">
|
||||||
mindmap
|
mindmap
|
||||||
root
|
root
|
||||||
A
|
|
||||||
B
|
|
||||||
C
|
|
||||||
D
|
|
||||||
E
|
|
||||||
A2
|
|
||||||
B2
|
|
||||||
C2
|
|
||||||
D2
|
|
||||||
E2
|
|
||||||
child1((Circle))
|
child1((Circle))
|
||||||
grandchild 1
|
grandchild 1
|
||||||
grandchild 2
|
grandchild 2
|
||||||
|
@@ -14,16 +14,14 @@
|
|||||||
mermaid.init({ startOnLoad: false });
|
mermaid.init({ startOnLoad: false });
|
||||||
|
|
||||||
mermaid.mermaidAPI.initialize({ securityLevel: 'strict' });
|
mermaid.mermaidAPI.initialize({ securityLevel: 'strict' });
|
||||||
(async () => {
|
|
||||||
try {
|
try {
|
||||||
console.log('rendering');
|
console.log('rendering');
|
||||||
await mermaid.mermaidAPI.render('graphDiv', `>`);
|
mermaid.mermaidAPI.render('graphDiv', `>`);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
await mermaid.mermaidAPI.render('graphDiv', `graph LR\n a --> b`, (html) => {
|
mermaid.mermaidAPI.render('graphDiv', `graph LR\n a --> b`, (html) => {
|
||||||
document.getElementById('graph').innerHTML = html;
|
document.getElementById('graph').innerHTML = html;
|
||||||
});
|
});
|
||||||
})();
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@@ -19,10 +19,9 @@
|
|||||||
function rerender(text) {
|
function rerender(text) {
|
||||||
const graphText = `graph TD
|
const graphText = `graph TD
|
||||||
A[${text}] -->|Get money| B(Go shopping)`;
|
A[${text}] -->|Get money| B(Go shopping)`;
|
||||||
mermaid.mermaidAPI.render('id', graphText).then((svg) => {
|
const graph = mermaid.mermaidAPI.render('id', graphText);
|
||||||
console.log('\x1b[35m%s\x1b[0m', '>> graph', svg);
|
console.log('\x1b[35m%s\x1b[0m', '>> graph', graph);
|
||||||
document.getElementById('graph').innerHTML = svg;
|
document.getElementById('graph').innerHTML = graph;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<button id="rerender" onclick="rerender('Saturday')">Rerender</button>
|
<button id="rerender" onclick="rerender('Saturday')">Rerender</button>
|
||||||
|
14
cypress/platform/sidv.html
Normal file
14
cypress/platform/sidv.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<pre class="mermaid">
|
||||||
|
none
|
||||||
|
hello world
|
||||||
|
</pre>
|
||||||
|
<script src="./mermaid.js"></script>
|
||||||
|
<script>
|
||||||
|
mermaid.initialize({
|
||||||
|
logLevel: 1,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = 'classDiagram\n';
|
let diagram = 'classDiagram\n';
|
||||||
diagram += 'class Square~<img/src';
|
diagram += 'class Square~<img/src';
|
||||||
diagram += "='1'/onerror=xssAttack()>~{\n";
|
diagram += "='1'/onerror=xssAttack()>~{\n";
|
||||||
diagram += 'id A\n';
|
diagram += 'id A\n';
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = 'stateDiagram-v2\n';
|
let diagram = 'stateDiagram-v2\n';
|
||||||
diagram += 's2 : This is a state description<img/src';
|
diagram += 's2 : This is a state description<img/src';
|
||||||
diagram += "='1'/onerror=xssAttack()>";
|
diagram += "='1'/onerror=xssAttack()>";
|
||||||
|
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = 'stateDiagram-v2\n';
|
let diagram = 'stateDiagram-v2\n';
|
||||||
diagram += 's2 : A<img/src';
|
diagram += 's2 : A<img/src';
|
||||||
diagram += "='1'/onerror=xssAttack()>";
|
diagram += "='1'/onerror=xssAttack()>";
|
||||||
|
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = 'stateDiagram-v2\n';
|
let diagram = 'stateDiagram-v2\n';
|
||||||
diagram += 'if_state --> False: if n < 0<img/src';
|
diagram += 'if_state --> False: if n < 0<img/src';
|
||||||
diagram += "='1'/onerror=xssAttack()>";
|
diagram += "='1'/onerror=xssAttack()>";
|
||||||
|
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = 'classDiagram\n';
|
let diagram = 'classDiagram\n';
|
||||||
diagram += 'classA <-- classB : <ifr';
|
diagram += 'classA <-- classB : <ifr';
|
||||||
diagram += "ame/srcdoc='<scr";
|
diagram += "ame/srcdoc='<scr";
|
||||||
diagram += 'ipt>parent.xssAttack(`XSS`)</';
|
diagram += 'ipt>parent.xssAttack(`XSS`)</';
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = `sequenceDiagram
|
let diagram = `sequenceDiagram
|
||||||
participant John
|
participant John
|
||||||
links John: {"XSS": "javas`;
|
links John: {"XSS": "javas`;
|
||||||
diagram += `cript:alert('AudioParam')"}`;
|
diagram += `cript:alert('AudioParam')"}`;
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = `sequenceDiagram
|
let diagram = `sequenceDiagram
|
||||||
participant Alice
|
participant Alice
|
||||||
links Alice: { "Click me!" : "javasjavascript:cript:alert('goose')" }`;
|
links Alice: { "Click me!" : "javasjavascript:cript:alert('goose')" }`;
|
||||||
|
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = `sequenceDiagram
|
let diagram = `sequenceDiagram
|
||||||
participant Alice
|
participant Alice
|
||||||
link Alice: Click Me!@javasjavascript:cript:alert("goose")`;
|
link Alice: Click Me!@javasjavascript:cript:alert("goose")`;
|
||||||
|
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = `classDiagram
|
let diagram = `classDiagram
|
||||||
Class "<img/src='x'/onerror=xssAttack(1)>" <--> "<img/src='x'/onerror=xssAttack(2)>" C2: Cool label`;
|
Class "<img/src='x'/onerror=xssAttack(1)>" <--> "<img/src='x'/onerror=xssAttack(2)>" C2: Cool label`;
|
||||||
|
|
||||||
// // var diagram = "stateDiagram-v2\n";
|
// // var diagram = "stateDiagram-v2\n";
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = `classDiagram
|
let diagram = `classDiagram
|
||||||
class Shape{
|
class Shape{
|
||||||
<<<img/src='1'/`;
|
<<<img/src='1'/`;
|
||||||
|
|
||||||
|
@@ -54,9 +54,9 @@
|
|||||||
startOnLoad: true,
|
startOnLoad: true,
|
||||||
useMaxWidth: true,
|
useMaxWidth: true,
|
||||||
});
|
});
|
||||||
var cnt = 0;
|
let cnt = 0;
|
||||||
var a;
|
let a;
|
||||||
var handler = setInterval(() => {
|
const handler = setInterval(() => {
|
||||||
cnt++;
|
cnt++;
|
||||||
a = {};
|
a = {};
|
||||||
if (typeof a.polluted !== 'undefined') {
|
if (typeof a.polluted !== 'undefined') {
|
||||||
|
@@ -96,7 +96,7 @@
|
|||||||
// var diagram = ` graph TD
|
// var diagram = ` graph TD
|
||||||
// A --> B["<a href='javasc`;
|
// A --> B["<a href='javasc`;
|
||||||
// diagram += `ript#colon;xssAttack()'>AAA</a>"]`;
|
// diagram += `ript#colon;xssAttack()'>AAA</a>"]`;
|
||||||
var diagram = ` graph TD
|
let diagram = ` graph TD
|
||||||
A --> B["<a href='javasc`;
|
A --> B["<a href='javasc`;
|
||||||
diagram += `ript#colon;xssAttack()'>AAA</a>"]`;
|
diagram += `ript#colon;xssAttack()'>AAA</a>"]`;
|
||||||
// diagram += '//via.placeholder.com/64\' width=64 />"]';
|
// diagram += '//via.placeholder.com/64\' width=64 />"]';
|
||||||
|
@@ -96,7 +96,7 @@
|
|||||||
// var diagram = ` graph TD
|
// var diagram = ` graph TD
|
||||||
// A --> B["<a href='javasc`;
|
// A --> B["<a href='javasc`;
|
||||||
// diagram += `ript#colon;xssAttack()'>AAA</a>"]`;
|
// diagram += `ript#colon;xssAttack()'>AAA</a>"]`;
|
||||||
var diagram = ` graph TD
|
let diagram = ` graph TD
|
||||||
A --> B["<a href='javasc`;
|
A --> B["<a href='javasc`;
|
||||||
diagram += `ript#9;t#colon;xssAttack()'>AAA</a>"]`;
|
diagram += `ript#9;t#colon;xssAttack()'>AAA</a>"]`;
|
||||||
// diagram += '//via.placeholder.com/64\' width=64 />"]';
|
// diagram += '//via.placeholder.com/64\' width=64 />"]';
|
||||||
|
@@ -42,9 +42,9 @@
|
|||||||
startOnLoad: true,
|
startOnLoad: true,
|
||||||
useMaxWidth: true,
|
useMaxWidth: true,
|
||||||
});
|
});
|
||||||
var cnt = 0;
|
let cnt = 0;
|
||||||
var a;
|
let a;
|
||||||
var handler = setInterval(() => {
|
const handler = setInterval(() => {
|
||||||
cnt++;
|
cnt++;
|
||||||
a = {};
|
a = {};
|
||||||
if (typeof a.polluted !== 'undefined') {
|
if (typeof a.polluted !== 'undefined') {
|
||||||
|
@@ -85,7 +85,7 @@
|
|||||||
alert('It worked');
|
alert('It worked');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = '%%{init: {"flowchart": {"htmlLabels": "true"}} }%%\n';
|
let diagram = '%%{init: {"flowchart": {"htmlLabels": "true"}} }%%\n';
|
||||||
diagram += 'flowchart\n';
|
diagram += 'flowchart\n';
|
||||||
diagram += 'A["<ifra';
|
diagram += 'A["<ifra';
|
||||||
diagram += "me srcdoc='<scrip";
|
diagram += "me srcdoc='<scrip";
|
||||||
|
@@ -92,7 +92,7 @@
|
|||||||
document.getElementsByTagName('body')[0].appendChild(div);
|
document.getElementsByTagName('body')[0].appendChild(div);
|
||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
var diagram = 'graph LR\n';
|
let diagram = 'graph LR\n';
|
||||||
diagram += 'B-->D("<img onerror=location=`java';
|
diagram += 'B-->D("<img onerror=location=`java';
|
||||||
// diagram += "script\u003aalert\u0028document.domain\u0029\` src=x>\"\);\n";
|
// diagram += "script\u003aalert\u0028document.domain\u0029\` src=x>\"\);\n";
|
||||||
diagram += 'script\x3a;xssAttack\u0028\u0029` src=x>");\n';
|
diagram += 'script\x3a;xssAttack\u0028\u0029` src=x>");\n';
|
||||||
|
@@ -92,7 +92,7 @@
|
|||||||
document.getElementsByTagName('body')[0].appendChild(div);
|
document.getElementsByTagName('body')[0].appendChild(div);
|
||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
var diagram = 'graph LR\n';
|
let diagram = 'graph LR\n';
|
||||||
diagram += 'A(<img/src/onerror=xssAttack`1`>)';
|
diagram += 'A(<img/src/onerror=xssAttack`1`>)';
|
||||||
// diagram += "script\u003aalert\u0028document.domain\u0029\` src=x>\"\);\n";
|
// diagram += "script\u003aalert\u0028document.domain\u0029\` src=x>\"\);\n";
|
||||||
console.log(diagram);
|
console.log(diagram);
|
||||||
|
@@ -92,7 +92,7 @@
|
|||||||
document.getElementsByTagName('body')[0].appendChild(div);
|
document.getElementsByTagName('body')[0].appendChild(div);
|
||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
var diagram = 'graph LR\n';
|
let diagram = 'graph LR\n';
|
||||||
diagram += " B(<a href='<";
|
diagram += " B(<a href='<";
|
||||||
diagram += 'script></';
|
diagram += 'script></';
|
||||||
diagram += "script>Javascript:xssAttack`1`'>Click)";
|
diagram += "script>Javascript:xssAttack`1`'>Click)";
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = 'stateDiagram-v2\n';
|
let diagram = 'stateDiagram-v2\n';
|
||||||
diagram += "<img/src='1'/onerror=xssAttack()> --> B";
|
diagram += "<img/src='1'/onerror=xssAttack()> --> B";
|
||||||
// diagram += "script\u003aalert\u0028document.domain\u0029\` src=x>\"\);\n";
|
// diagram += "script\u003aalert\u0028document.domain\u0029\` src=x>\"\);\n";
|
||||||
console.log(diagram);
|
console.log(diagram);
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
throw new Error('XSS Succeeded');
|
throw new Error('XSS Succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagram = 'stateDiagram-v2\n';
|
let diagram = 'stateDiagram-v2\n';
|
||||||
diagram += "<img/src='1'/onerror=xssAttack()> --> B";
|
diagram += "<img/src='1'/onerror=xssAttack()> --> B";
|
||||||
// diagram += "script\u003aalert\u0028document.domain\u0029\` src=x>\"\);\n";
|
// diagram += "script\u003aalert\u0028document.domain\u0029\` src=x>\"\);\n";
|
||||||
console.log(diagram);
|
console.log(diagram);
|
||||||
|
@@ -277,7 +277,7 @@
|
|||||||
<script>
|
<script>
|
||||||
function testClick(nodeId) {
|
function testClick(nodeId) {
|
||||||
console.log('clicked', nodeId);
|
console.log('clicked', nodeId);
|
||||||
var originalBgColor = document.querySelector('body').style.backgroundColor;
|
let originalBgColor = document.querySelector('body').style.backgroundColor;
|
||||||
document.querySelector('body').style.backgroundColor = 'yellow';
|
document.querySelector('body').style.backgroundColor = 'yellow';
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
document.querySelector('body').style.backgroundColor = originalBgColor;
|
document.querySelector('body').style.backgroundColor = originalBgColor;
|
||||||
|
@@ -46,7 +46,7 @@
|
|||||||
<script>
|
<script>
|
||||||
function testClick(nodeId) {
|
function testClick(nodeId) {
|
||||||
console.log('clicked', nodeId);
|
console.log('clicked', nodeId);
|
||||||
var originalBgColor = document.querySelector('body').style.backgroundColor;
|
let originalBgColor = document.querySelector('body').style.backgroundColor;
|
||||||
document.querySelector('body').style.backgroundColor = 'yellow';
|
document.querySelector('body').style.backgroundColor = 'yellow';
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
document.querySelector('body').style.backgroundColor = originalBgColor;
|
document.querySelector('body').style.backgroundColor = originalBgColor;
|
||||||
|
@@ -1513,7 +1513,7 @@
|
|||||||
<script>
|
<script>
|
||||||
function testClick(nodeId) {
|
function testClick(nodeId) {
|
||||||
console.log('clicked', nodeId);
|
console.log('clicked', nodeId);
|
||||||
var originalBgColor = document.querySelector('body').style.backgroundColor;
|
let originalBgColor = document.querySelector('body').style.backgroundColor;
|
||||||
document.querySelector('body').style.backgroundColor = 'yellow';
|
document.querySelector('body').style.backgroundColor = 'yellow';
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
document.querySelector('body').style.backgroundColor = originalBgColor;
|
document.querySelector('body').style.backgroundColor = originalBgColor;
|
||||||
|
@@ -174,7 +174,7 @@
|
|||||||
}
|
}
|
||||||
function testClick(nodeId) {
|
function testClick(nodeId) {
|
||||||
console.log('clicked', nodeId);
|
console.log('clicked', nodeId);
|
||||||
var originalBgColor = document.querySelector('body').style.backgroundColor;
|
let originalBgColor = document.querySelector('body').style.backgroundColor;
|
||||||
document.querySelector('body').style.backgroundColor = 'yellow';
|
document.querySelector('body').style.backgroundColor = 'yellow';
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
document.querySelector('body').style.backgroundColor = originalBgColor;
|
document.querySelector('body').style.backgroundColor = originalBgColor;
|
||||||
|
@@ -10,7 +10,7 @@ It is a JavaScript based diagramming and charting tool that renders Markdown-ins
|
|||||||
|
|
||||||
<img src="img/header.png" alt="" />
|
<img src="img/header.png" alt="" />
|
||||||
|
|
||||||
[](https://travis-ci.org/mermaid-js/mermaid) [](https://www.npmjs.com/package/mermaid) [](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
|
[](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml) [](https://www.npmjs.com/package/mermaid) [](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [](https://www.jsdelivr.com/package/npm/mermaid) [](https://www.npmjs.com/package/mermaid) [](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [](https://twitter.com/mermaidjs_)
|
||||||
|
|
||||||
<!-- Mermaid book banner -->
|
<!-- Mermaid book banner -->
|
||||||
|
|
||||||
@@ -271,16 +271,16 @@ To Deploy Mermaid:
|
|||||||
|
|
||||||
### [Mermaid API](./Setup.md):
|
### [Mermaid API](./Setup.md):
|
||||||
|
|
||||||
**To deploy mermaid without a bundler, one can insert a `script` tag with an absolute address and a `mermaidAPI` call into the HTML like so:**
|
**To deploy mermaid without a bundler, one can insert a `script` tag with an absolute address and a `mermaid.initialize` call into the HTML like so:**
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
<script type="module">
|
||||||
<script>
|
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@9/dist/mermaid.esm.min.mjs';
|
||||||
mermaid.initialize({ startOnLoad: true });
|
mermaid.initialize({ startOnLoad: true });
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Doing so will command the mermaid parser to look for the `<div>` tags with `class="mermaid"`. From these tags mermaid will try to read the diagram/chart definitions and render them into SVG charts.**
|
**Doing so will command the mermaid parser to look for the `<div>` or `<pre>` tags with `class="mermaid"`. From these tags mermaid will try to read the diagram/chart definitions and render them into SVG charts.**
|
||||||
|
|
||||||
**Examples can be found at** [Other examples](/examples)
|
**Examples can be found at** [Other examples](/examples)
|
||||||
|
|
||||||
@@ -347,7 +347,7 @@ Update version number in `package.json`.
|
|||||||
npm publish
|
npm publish
|
||||||
```
|
```
|
||||||
|
|
||||||
The above command generates files into the `dist` folder and publishes them to npmjs.org.
|
The above command generates files into the `dist` folder and publishes them to \<npmjs.org>.
|
||||||
|
|
||||||
## Related projects
|
## Related projects
|
||||||
|
|
||||||
@@ -363,7 +363,7 @@ Detailed information about how to contribute can be found in the [contribution g
|
|||||||
|
|
||||||
## Security and safe diagrams
|
## Security and safe diagrams
|
||||||
|
|
||||||
For public sites, it can be precarious to retrieve text from users on the internet, storing that content for presentation in a browser at a later stage. The reason is that the user content can contain embedded malicious scripts that will run when the data is presented. For Mermaid this is a risk, specially as mermaid diagrams contain many characters that are used in html which makes the standard sanitation unusable as it also breaks the diagrams. We still make an effort to sanitise the incoming code and keep refining the process but it is hard to guarantee that there are no loop holes.
|
For public sites, it can be precarious to retrieve text from users on the internet, storing that content for presentation in a browser at a later stage. The reason is that the user content can contain embedded malicious scripts that will run when the data is presented. For Mermaid this is a risk, specially as mermaid diagrams contain many characters that are used in html which makes the standard sanitation unusable as it also breaks the diagrams. We still make an effort to sanitize the incoming code and keep refining the process but it is hard to guarantee that there are no loop holes.
|
||||||
|
|
||||||
As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing JavaScript in the code from being executed. This is a great step forward for better security.
|
As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing JavaScript in the code from being executed. This is a great step forward for better security.
|
||||||
|
|
||||||
|
@@ -74,15 +74,15 @@ Theme , the CSS style sheet
|
|||||||
|
|
||||||
| Parameter | Description | Type | Required | Values |
|
| Parameter | Description | Type | Required | Values |
|
||||||
| ------------- | --------------------------------- | ------ | -------- | ------------------------------------------ |
|
| ------------- | --------------------------------- | ------ | -------- | ------------------------------------------ |
|
||||||
| securityLevel | Level of trust for parsed diagram | string | Required | 'sandbox', 'strict', 'loose', 'antiscript' |
|
| securityLevel | Level of trust for parsed diagram | string | Required | `sandbox`, `strict`, `loose`, `antiscript` |
|
||||||
|
|
||||||
**Notes**:
|
**Notes**:
|
||||||
|
|
||||||
- **strict**: (**default**) tags in text are encoded, click functionality is disabled
|
- **`strict`**: (**default**) tags in text are encoded, click functionality is disabled
|
||||||
- **loose**: tags in text are allowed, click functionality is enabled
|
- **`loose`**: tags in text are allowed, click functionality is enabled
|
||||||
- **antiscript**: html tags in text are allowed, (only script element is removed), click
|
- **`antiscript`**: html tags in text are allowed, (only script element is removed), click
|
||||||
functionality is enabled
|
functionality is enabled
|
||||||
- **sandbox**: With this security level all rendering takes place in a sandboxed iframe. This
|
- **`sandbox`**: With this security level all rendering takes place in a sandboxed iframe. This
|
||||||
prevent any JavaScript from running in the context. This may hinder interactive functionality
|
prevent any JavaScript from running in the context. This may hinder interactive functionality
|
||||||
of the diagram like scripts, popups in sequence diagram or links to other tabs/targets etc.
|
of the diagram like scripts, popups in sequence diagram or links to other tabs/targets etc.
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ Default value: \['secure', 'securityLevel', 'startOnLoad', 'maxTextSize']
|
|||||||
|
|
||||||
This option controls if the generated ids of nodes in the SVG are generated randomly or based
|
This option controls if the generated ids of nodes in the SVG are generated randomly or based
|
||||||
on a seed. If set to false, the IDs are generated based on the current date and thus are not
|
on a seed. If set to false, the IDs are generated based on the current date and thus are not
|
||||||
deterministic. This is the default behaviour.
|
deterministic. This is the default behavior.
|
||||||
|
|
||||||
**Notes**:
|
**Notes**:
|
||||||
|
|
||||||
@@ -213,15 +213,15 @@ Default value: true
|
|||||||
### defaultRenderer
|
### defaultRenderer
|
||||||
|
|
||||||
| Parameter | Description | Type | Required | Values |
|
| Parameter | Description | Type | Required | Values |
|
||||||
| --------------- | ----------- | ------- | -------- | ----------------------- |
|
| --------------- | ----------- | ------- | -------- | --------------------------- |
|
||||||
| defaultRenderer | See notes | boolean | 4 | dagre-d3, dagre-wrapper |
|
| defaultRenderer | See notes | boolean | 4 | `dagre-d3`, `dagre-wrapper` |
|
||||||
|
|
||||||
**Notes:**
|
**Notes:**
|
||||||
|
|
||||||
Decides which rendering engine that is to be used for the rendering. Legal values are:
|
Decides which rendering engine that is to be used for the rendering. Legal values are:
|
||||||
dagre-d3 dagre-wrapper - wrapper for dagre implemented in mermaid
|
`dagre-d3` `dagre-wrapper` - wrapper for `dagre` implemented in mermaid
|
||||||
|
|
||||||
Default value: 'dagre-wrapper'
|
Default value: `dagre-wrapper`
|
||||||
|
|
||||||
## sequence
|
## sequence
|
||||||
|
|
||||||
@@ -738,15 +738,15 @@ Default value: true
|
|||||||
## defaultRenderer
|
## defaultRenderer
|
||||||
|
|
||||||
| Parameter | Description | Type | Required | Values |
|
| Parameter | Description | Type | Required | Values |
|
||||||
| --------------- | ----------- | ------- | -------- | ----------------------- |
|
| --------------- | ----------- | ------- | -------- | --------------------------- |
|
||||||
| defaultRenderer | See notes | boolean | 4 | dagre-d3, dagre-wrapper |
|
| defaultRenderer | See notes | boolean | 4 | `dagre-d3`, `dagre-wrapper` |
|
||||||
|
|
||||||
**Notes**:
|
**Notes**:
|
||||||
|
|
||||||
Decides which rendering engine that is to be used for the rendering. Legal values are:
|
Decides which rendering engine that is to be used for the rendering. Legal values are:
|
||||||
dagre-d3 dagre-wrapper - wrapper for dagre implemented in mermaid
|
`dagre-d3` `dagre-wrapper` - wrapper for `dagre` implemented in mermaid
|
||||||
|
|
||||||
Default value: 'dagre-d3'
|
Default value: `dagre-d3`
|
||||||
|
|
||||||
## useMaxWidth
|
## useMaxWidth
|
||||||
|
|
||||||
@@ -764,15 +764,15 @@ Default value: true
|
|||||||
## defaultRenderer
|
## defaultRenderer
|
||||||
|
|
||||||
| Parameter | Description | Type | Required | Values |
|
| Parameter | Description | Type | Required | Values |
|
||||||
| --------------- | ----------- | ------- | -------- | ----------------------- |
|
| --------------- | ----------- | ------- | -------- | --------------------------- |
|
||||||
| defaultRenderer | See notes | boolean | 4 | dagre-d3, dagre-wrapper |
|
| defaultRenderer | See notes | boolean | 4 | `dagre-d3`, `dagre-wrapper` |
|
||||||
|
|
||||||
**Notes:**
|
**Notes:**
|
||||||
|
|
||||||
Decides which rendering engine that is to be used for the rendering. Legal values are:
|
Decides which rendering engine that is to be used for the rendering. Legal values are:
|
||||||
dagre-d3 dagre-wrapper - wrapper for dagre implemented in mermaid
|
`dagre-d3` `dagre-wrapper` - wrapper for `dagre` implemented in mermaid
|
||||||
|
|
||||||
Default value: 'dagre-d3'
|
Default value: `dagre-d3`
|
||||||
|
|
||||||
## er
|
## er
|
||||||
|
|
||||||
@@ -994,7 +994,7 @@ Default value: 4
|
|||||||
| --------------- | ----------- | ------- | -------- | ------------------ |
|
| --------------- | ----------- | ------- | -------- | ------------------ |
|
||||||
| c4BoundaryInRow | See Notes | Integer | Required | Any Positive Value |
|
| c4BoundaryInRow | See Notes | Integer | Required | Any Positive Value |
|
||||||
|
|
||||||
**Notes:** How many boundarys to place in each row.
|
**Notes:** How many boundaries to place in each row.
|
||||||
|
|
||||||
Default value: 2
|
Default value: 2
|
||||||
|
|
||||||
@@ -1561,7 +1561,7 @@ Returns **void**
|
|||||||
|
|
||||||
```html
|
```html
|
||||||
<script>
|
<script>
|
||||||
var config = {
|
const config = {
|
||||||
theme: 'default',
|
theme: 'default',
|
||||||
logLevel: 'fatal',
|
logLevel: 'fatal',
|
||||||
securityLevel: 'strict',
|
securityLevel: 'strict',
|
||||||
|
@@ -19,7 +19,7 @@ The diagram authors can now add the accessibility options in the diagram definit
|
|||||||
- `accTitle: "Your Accessibility Title"` or
|
- `accTitle: "Your Accessibility Title"` or
|
||||||
- `accDescr: "Your Accessibility Description"`
|
- `accDescr: "Your Accessibility Description"`
|
||||||
|
|
||||||
**When these two options are defined, they will add a coressponding `<title>` and `<desc>` tag in the SVG.**
|
**When these two options are defined, they will add a corresponding `<title>` and `<desc>` tag in the SVG.**
|
||||||
|
|
||||||
Let us take a look at the following example with a flowchart diagram:
|
Let us take a look at the following example with a flowchart diagram:
|
||||||
|
|
||||||
|
@@ -589,7 +589,7 @@ click Shape2 call callbackFunction() "This is a tooltip for a callback"
|
|||||||
|
|
||||||
```html
|
```html
|
||||||
<script>
|
<script>
|
||||||
var callbackFunction = function () {
|
const callbackFunction = function () {
|
||||||
alert('A callback was triggered');
|
alert('A callback was triggered');
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -653,10 +653,10 @@ Beginner's tip—a full example using interactive links in an HTML page:
|
|||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var callback = function () {
|
const callback = function () {
|
||||||
alert('A callback was triggered');
|
alert('A callback was triggered');
|
||||||
};
|
};
|
||||||
var config = {
|
const config = {
|
||||||
startOnLoad: true,
|
startOnLoad: true,
|
||||||
securityLevel: 'loose',
|
securityLevel: 'loose',
|
||||||
};
|
};
|
||||||
|
@@ -649,7 +649,7 @@ A node can have click events bound that lead to either a JavaScript callback or
|
|||||||
|
|
||||||
```html
|
```html
|
||||||
<script>
|
<script>
|
||||||
var callback = function (nodeId) {
|
const callback = function (nodeId) {
|
||||||
alert('A callback was triggered on ' + nodeId);
|
alert('A callback was triggered on ' + nodeId);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -727,10 +727,10 @@ Beginner's tip—here's a full example of using interactive links in HTML:
|
|||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var callback = function () {
|
const callback = function () {
|
||||||
alert('A callback was triggered');
|
alert('A callback was triggered');
|
||||||
};
|
};
|
||||||
var config = {
|
const config = {
|
||||||
startOnLoad: true,
|
startOnLoad: true,
|
||||||
flowchart: {
|
flowchart: {
|
||||||
useMaxWidth: true,
|
useMaxWidth: true,
|
||||||
|
@@ -264,6 +264,20 @@ flowchart LR
|
|||||||
A --- B
|
A --- B
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### An invisisble link
|
||||||
|
|
||||||
|
This can be a usefull tool in some instances where you want to alter the default positining of a node.
|
||||||
|
|
||||||
|
```mermaid-example
|
||||||
|
flowchart LR
|
||||||
|
A ~~~ B
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A ~~~ B
|
||||||
|
```
|
||||||
|
|
||||||
### Text on links
|
### Text on links
|
||||||
|
|
||||||
```mermaid-example
|
```mermaid-example
|
||||||
@@ -695,7 +709,7 @@ Examples of tooltip usage below:
|
|||||||
|
|
||||||
```html
|
```html
|
||||||
<script>
|
<script>
|
||||||
var callback = function () {
|
const callback = function () {
|
||||||
alert('A callback was triggered');
|
alert('A callback was triggered');
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -771,10 +785,10 @@ Beginner's tip—a full example using interactive links in a html context:
|
|||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var callback = function () {
|
const callback = function () {
|
||||||
alert('A callback was triggered');
|
alert('A callback was triggered');
|
||||||
};
|
};
|
||||||
var config = {
|
const config = {
|
||||||
startOnLoad: true,
|
startOnLoad: true,
|
||||||
flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' },
|
flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' },
|
||||||
securityLevel: 'loose',
|
securityLevel: 'loose',
|
||||||
|
@@ -391,13 +391,13 @@ Beginner's tip—a full example using interactive links in an html context:
|
|||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var printArguments = function (arg1, arg2, arg3) {
|
const printArguments = function (arg1, arg2, arg3) {
|
||||||
alert('printArguments called with arguments: ' + arg1 + ', ' + arg2 + ', ' + arg3);
|
alert('printArguments called with arguments: ' + arg1 + ', ' + arg2 + ', ' + arg3);
|
||||||
};
|
};
|
||||||
var printTask = function (taskId) {
|
const printTask = function (taskId) {
|
||||||
alert('taskId: ' + taskId);
|
alert('taskId: ' + taskId);
|
||||||
};
|
};
|
||||||
var config = {
|
const config = {
|
||||||
startOnLoad: true,
|
startOnLoad: true,
|
||||||
securityLevel: 'loose',
|
securityLevel: 'loose',
|
||||||
};
|
};
|
||||||
|
@@ -21,15 +21,13 @@
|
|||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css"
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css"
|
||||||
/>
|
/>
|
||||||
<script src="//cdn.jsdelivr.net/npm/mermaid@9.1.7/dist/mermaid.min.js"></script>
|
|
||||||
<!-- <script src="http://localhost:9000/mermaid.js"></script> -->
|
|
||||||
<script
|
<script
|
||||||
defer=""
|
defer=""
|
||||||
data-domain="mermaid-js.github.io"
|
data-domain="mermaid-js.github.io"
|
||||||
src="https://plausible.io/js/plausible.js"
|
src="https://plausible.io/js/plausible.js"
|
||||||
></script>
|
></script>
|
||||||
<script>
|
<script>
|
||||||
var require = {
|
const require = {
|
||||||
paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs' },
|
paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs' },
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -50,17 +48,46 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
<script type="module">
|
||||||
|
// import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@9/dist/mermaid.esm.min.mjs';
|
||||||
|
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@9.2.0/dist/mermaid.esm.min.mjs';
|
||||||
|
// import mermaid from 'http://localhost:9000/mermaid.esm.mjs';
|
||||||
|
console.log(mermaid); // eslint-disable-line
|
||||||
|
window.mermaid = mermaid;
|
||||||
|
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
|
||||||
|
const conf = {
|
||||||
|
logLevel: 4,
|
||||||
|
startOnLoad: true,
|
||||||
|
themeCSS: '.label { font-family: Source Sans Pro,Helvetica Neue,Arial,sans-serif; }',
|
||||||
|
lazyLoadedDiagrams: [
|
||||||
|
'https://cdn.jsdelivr.net/npm/@mermaid-js/mermaid-mindmap@9.2.0/dist/mermaid-mindmap-detector.esm.mjs',
|
||||||
|
// 'http://localhost:9000/mermaid-mindmap-detector.esm.mjs',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
if (isDarkMode) conf.theme = 'dark';
|
||||||
|
|
||||||
|
async function loadMermaid() {
|
||||||
|
await mermaid.initialize(conf);
|
||||||
|
console.log('mermaid initialized'); // eslint-disable-line
|
||||||
|
}
|
||||||
|
mermaid.parseError = (e) => {
|
||||||
|
console.log('parse error', e); // eslint-disable-line
|
||||||
|
};
|
||||||
|
await loadMermaid();
|
||||||
|
</script>
|
||||||
<script>
|
<script>
|
||||||
var initEditor = exports.default;
|
let initEditor = exports.default;
|
||||||
var parser = new DOMParser();
|
let parser = new DOMParser();
|
||||||
var currentCodeExample = 0;
|
let currentCodeExample = 0;
|
||||||
var colorize = [];
|
let colorize = [];
|
||||||
|
let num = 0;
|
||||||
|
|
||||||
function colorizeEverything(html) {
|
function colorizeEverything(html) {
|
||||||
initEditor(monaco);
|
initEditor(monaco);
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
monaco.editor.setTheme('mermaid');
|
monaco.editor.setTheme('mermaid');
|
||||||
var parsed = parser.parseFromString(html, 'text/html').body;
|
const parsed = parser.parseFromString(html, 'text/html').body;
|
||||||
Promise.all(
|
Promise.all(
|
||||||
[...parsed.querySelectorAll('pre[id*="code"]')].map((codeBlock) =>
|
[...parsed.querySelectorAll('pre[id*="code"]')].map((codeBlock) =>
|
||||||
monaco.editor.colorize(codeBlock.innerText, 'mermaid')
|
monaco.editor.colorize(codeBlock.innerText, 'mermaid')
|
||||||
@@ -95,13 +122,12 @@
|
|||||||
renderer: {
|
renderer: {
|
||||||
code: function (code, lang) {
|
code: function (code, lang) {
|
||||||
if (lang === 'mermaid-example') {
|
if (lang === 'mermaid-example') {
|
||||||
|
console.log('An example'); // eslint-disable-line
|
||||||
currentCodeExample++;
|
currentCodeExample++;
|
||||||
colorize.push(currentCodeExample);
|
colorize.push(currentCodeExample);
|
||||||
return '<pre id="code' + currentCodeExample + '">' + escapeHTML(code) + '</pre>';
|
return '<pre id="code' + currentCodeExample + '">' + escapeHTML(code) + '</pre>';
|
||||||
} else if (lang === 'mermaid') {
|
} else if (lang === 'mermaid') {
|
||||||
return (
|
return '<pre class="mermaid">' + code + '</pre>';
|
||||||
'<pre class="mermaid">' + mermaid.render('mermaid-svg-' + num++, code) + '</pre>'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return this.origin.code.apply(this, arguments);
|
return this.origin.code.apply(this, arguments);
|
||||||
},
|
},
|
||||||
@@ -117,9 +143,13 @@
|
|||||||
function (hook, vm) {
|
function (hook, vm) {
|
||||||
hook.beforeEach(function (html) {
|
hook.beforeEach(function (html) {
|
||||||
url = 'https://github.com/mermaid-js/mermaid/blob/develop/src/docs/' + vm.route.file;
|
url = 'https://github.com/mermaid-js/mermaid/blob/develop/src/docs/' + vm.route.file;
|
||||||
var editHtml = '[:memo: Edit this Page](' + url + ')\n';
|
const editHtml = '[:memo: Edit this Page](' + url + ')\n';
|
||||||
return editHtml + html;
|
return editHtml + html;
|
||||||
});
|
});
|
||||||
|
// Invoked on each page load after new HTML has been appended to the DOM
|
||||||
|
hook.doneEach(function () {
|
||||||
|
window.mermaid.init();
|
||||||
|
});
|
||||||
|
|
||||||
hook.afterEach(function (html, next) {
|
hook.afterEach(function (html, next) {
|
||||||
next(html);
|
next(html);
|
||||||
@@ -135,29 +165,17 @@
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
var num = 0;
|
|
||||||
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
||||||
|
|
||||||
const conf = {
|
|
||||||
logLevel: 4,
|
|
||||||
startOnLoad: false,
|
|
||||||
themeCSS: '.label { font-family: Source Sans Pro,Helvetica Neue,Arial,sans-serif; }',
|
|
||||||
};
|
|
||||||
if (isDarkMode) conf.theme = 'dark';
|
|
||||||
mermaid.initialize(conf);
|
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
window.onhashchange = function (a) {
|
window.onhashchange = function (a) {
|
||||||
//code
|
// if (location && ga) {
|
||||||
if (location) {
|
// ga('send', 'pageview', location.hash);
|
||||||
ga('send', 'pageview', location.hash);
|
// }
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
||||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
|
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
|
||||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/ga.min.js"></script>
|
<!-- <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/ga.min.js"></script> -->
|
||||||
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-coffeescript.min.js"></script>
|
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-coffeescript.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@@ -33,7 +33,7 @@ They also serve as proof of concept, for the variety of things that can be built
|
|||||||
- [Mermaid Macro](https://www.redmine.org/plugins/redmine_mermaid_macro)
|
- [Mermaid Macro](https://www.redmine.org/plugins/redmine_mermaid_macro)
|
||||||
- [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)
|
- [markdown-for-mermaid-plugin](https://github.com/jamieh-mongolian/markdown-for-mermaid-plugin)
|
||||||
- [Jetsbrain IDE eg Pycharm](https://www.jetbrains.com/go/guide/tips/mermaid-js-support-in-markdown/)
|
- [JetBrains IDE eg Pycharm](https://www.jetbrains.com/go/guide/tips/mermaid-js-support-in-markdown/)
|
||||||
- [mermerd](https://github.com/KarnerTh/mermerd)
|
- [mermerd](https://github.com/KarnerTh/mermerd)
|
||||||
|
|
||||||
## CRM/ERP/Similar
|
## CRM/ERP/Similar
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Mindmap
|
# Mindmap
|
||||||
|
|
||||||
> Mindmap: This is an experimental diagram for now. The syntax and properties can change in future releases. The syntax is stabel except for the icon integration which is the experimental part.
|
> Mindmap: This is an experimental diagram for now. The syntax and properties can change in future releases. The syntax is stable except for the icon integration which is the experimental part.
|
||||||
|
|
||||||
"A mind map is a diagram used to visually organize information into a hierarchy, showing relationships among pieces of the whole. It is often created around a single concept, drawn as an image in the center of a blank page, to which associated representations of ideas such as images, words and parts of words are added. Major ideas are connected directly to the central concept, and other ideas branch out from those major ideas." Wikipedia
|
"A mind map is a diagram used to visually organize information into a hierarchy, showing relationships among pieces of the whole. It is often created around a single concept, drawn as an image in the center of a blank page, to which associated representations of ideas such as images, words and parts of words are added. Major ideas are connected directly to the central concept, and other ideas branch out from those major ideas." Wikipedia
|
||||||
|
|
||||||
@@ -26,7 +26,6 @@ mindmap
|
|||||||
Tools
|
Tools
|
||||||
Pen and paper
|
Pen and paper
|
||||||
Mermaid
|
Mermaid
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
@@ -47,14 +46,13 @@ mindmap
|
|||||||
Tools
|
Tools
|
||||||
Pen and paper
|
Pen and paper
|
||||||
Mermaid
|
Mermaid
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
The syntax for creating Mindmaps is simple and relies on indentation for setting the levels in the hierarchy.
|
The syntax for creating Mindmaps is simple and relies on indentation for setting the levels in the hierarchy.
|
||||||
|
|
||||||
In the following example you can see how there are 3 dufferent levels. One with starting at the left of the text and another level with two rows starting at the same column, defining the node A. At the end there is one more level where the text is indented further then the prevoius lines defining the nodes B and C.
|
In the following example you can see how there are 3 different levels of indentation. The leftmost indentation is the root of the mindmap. There can only be one root and if you by misstake add two of them on the same level there will be a syntax error. Rows with larger indentation will be connected as children to the previous row with lower indentation. Based on that you can see in the example how the nodes B and C both are children to node A whci in turn is a child of the node Root.
|
||||||
|
|
||||||
mindmap
|
mindmap
|
||||||
Root
|
Root
|
||||||
@@ -62,7 +60,7 @@ In the following example you can see how there are 3 dufferent levels. One with
|
|||||||
B
|
B
|
||||||
C
|
C
|
||||||
|
|
||||||
In summary is a simple text outline where there are one node at the root level called `Root` which has one child `A`. `A` in turn has two children `B`and `C`. In the diagram below we can see this rendered as a mindmap.
|
In the diagram below you can see the example rendered as a mindmap.
|
||||||
|
|
||||||
```mermaid-example
|
```mermaid-example
|
||||||
mindmap
|
mindmap
|
||||||
@@ -220,7 +218,7 @@ The actual indentation does not really matter only compared with the previous ro
|
|||||||
B
|
B
|
||||||
C
|
C
|
||||||
|
|
||||||
This outline is unclear as `B` clearly is a child of `A` but when we move on to `C` the clarity is lost. `C` is not a child of `B` with a higher indentation nor does it have the same indentation as `B`. The only thing that is clear is that the first node with smaller indentation, indicating a parent, is A. Then Mermaid relies on this known truth and compensates for the unclear indentation and selects `A` as a parent of `C` leading till the same diagram with `B` and `C` as siblings.
|
This outline is unclear as `B` clearly is a child of `A` but when we move on to `C` the clarity is lost. `C` is not a child of `B` with a higher indentation nor does it have the same indentation as `B`. The only thing that is clear is that the first node with smaller indentation, indicating a parent, is A. Mermaid will rely on this known truth and compensates for the unclear indentation and selects `A` as a parent of `C` leading till the same diagram with `B` and `C` as siblings.
|
||||||
|
|
||||||
```mermaid-example
|
```mermaid-example
|
||||||
mindmap
|
mindmap
|
||||||
|
@@ -75,23 +75,13 @@ The API works by pulling rendering instructions from the source `mermaid.js` in
|
|||||||
|
|
||||||
### Requirements for the Mermaid API.
|
### Requirements for the Mermaid API.
|
||||||
|
|
||||||
When writing the .html file, we give three instructions inside the html code to the web browser:
|
When writing the .html file, we give two instructions inside the html code to the web browser:
|
||||||
|
|
||||||
a. A reference for fetching the online mermaid renderer, through the `mermaid.js` or `mermaid.min.js`.
|
a. The mermaid code for the diagram we want to create.
|
||||||
|
|
||||||
b. The mermaid code for the diagram we want to create.
|
b. The importing of mermaid library through the `mermaid.esm.js` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process .
|
||||||
|
|
||||||
c. The `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process .
|
**a. The embedded mermaid diagram definition inside a `<pre class="mermaid">`:**
|
||||||
|
|
||||||
**a. A reference to the external CDN in a `<script src>` tag, or a reference to mermaid.js as a separate file.:**
|
|
||||||
|
|
||||||
```html
|
|
||||||
<body>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
|
||||||
</body>
|
|
||||||
```
|
|
||||||
|
|
||||||
**b. The embedded mermaid diagram definition inside a `<pre class="mermaid">`:**
|
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<body>
|
<body>
|
||||||
@@ -107,13 +97,14 @@ c. The `mermaid.initialize()` call, which dictates the appearance of diagrams an
|
|||||||
|
|
||||||
**Notes**: Every Mermaid chart/graph/diagram definition, should have separate `<pre>` tags.
|
**Notes**: Every Mermaid chart/graph/diagram definition, should have separate `<pre>` tags.
|
||||||
|
|
||||||
**c. The `mermaid.initialize()` call.**
|
**b. The import of mermaid and the `mermaid.initialize()` call.**
|
||||||
|
|
||||||
`mermaid.initialize()` call takes all the definitions contained in all the `<pre class="mermaid">` tags that it finds in the html body and renders them into diagrams. Example:
|
`mermaid.initialize()` call takes all the definitions contained in all the `<pre class="mermaid">` tags that it finds in the html body and renders them into diagrams. Example:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script type="module">
|
||||||
|
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@9/dist/mermaid.esm.min.mjs';
|
||||||
mermaid.initialize({ startOnLoad: true });
|
mermaid.initialize({ startOnLoad: true });
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
@@ -135,11 +126,6 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
|
|||||||
```html
|
```html
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
|
||||||
<script>
|
|
||||||
mermaid.initialize({ startOnLoad: true });
|
|
||||||
</script>
|
|
||||||
|
|
||||||
Here is one mermaid diagram:
|
Here is one mermaid diagram:
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
graph TD
|
graph TD
|
||||||
@@ -156,6 +142,11 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
|
|||||||
B -->|tcp_456| C[Server1]
|
B -->|tcp_456| C[Server1]
|
||||||
B -->|tcp_456| D[Server2]
|
B -->|tcp_456| D[Server2]
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@9/dist/mermaid.esm.min.mjs';
|
||||||
|
mermaid.initialize({ startOnLoad: true });
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
@@ -181,8 +172,8 @@ In this example mermaid.js is referenced in `src` as a separate JavaScript file,
|
|||||||
B --> C[Server1]
|
B --> C[Server1]
|
||||||
B --> D[Server2]
|
B --> D[Server2]
|
||||||
</pre>
|
</pre>
|
||||||
<script src="The\Path\In\Your\Package\mermaid.js"></script>
|
<script type="module">
|
||||||
<script>
|
import mermaid from 'The/Path/In/Your/Package/mermaid.esm.mjs';
|
||||||
mermaid.initialize({ startOnLoad: true });
|
mermaid.initialize({ startOnLoad: true });
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
@@ -206,4 +197,4 @@ In this example mermaid.js is referenced in `src` as a separate JavaScript file,
|
|||||||
|
|
||||||
**Comments from Knut Sveidqvist, creator of mermaid:**
|
**Comments from Knut Sveidqvist, creator of mermaid:**
|
||||||
|
|
||||||
- In early versions of mermaid, the `<script src>` tag was invoked in the `<head>` part of the web page. Nowadays we can place it in the `<body>` as seen above. Older parts of the documentation frequently reflects the previous way which still works.
|
- In early versions of mermaid, the `<script>` tag was invoked in the `<head>` part of the web page. Nowadays we can place it in the `<body>` as seen above. Older parts of the documentation frequently reflects the previous way which still works.
|
||||||
|
@@ -39,23 +39,9 @@ We have compiled some Video [Tutorials](./Tutorials.md) on how to use the mermai
|
|||||||
|
|
||||||
> Note:This topic explored in greater depth in the [User Guide for Beginners](./n00b-gettingStarted.md)
|
> Note:This topic explored in greater depth in the [User Guide for Beginners](./n00b-gettingStarted.md)
|
||||||
|
|
||||||
The easiest way to integrate mermaid on a web page requires three elements:
|
The easiest way to integrate mermaid on a web page requires two elements:
|
||||||
|
|
||||||
1. Inclusion of the mermaid address in the html page using a `script` tag, in the `src` section.Example:
|
- A graph definition, inside `<pre>` tags labeled `class=mermaid`. Example:
|
||||||
|
|
||||||
```html
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
2. The `mermaidAPI` call, in a separate `script` tag. Example:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<script>
|
|
||||||
mermaid.initialize({ startOnLoad: true });
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
3. A graph definition, inside `<div>` tags labeled `class=mermaid`. Example:
|
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
@@ -66,8 +52,18 @@ The easiest way to integrate mermaid on a web page requires three elements:
|
|||||||
</pre>
|
</pre>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Following these directions, mermaid starts at page load and (when the page has loaded) it will
|
- Inclusion of the mermaid address in the html page body using a `script` tag as an ESM import, and the `mermaidAPI` call.
|
||||||
locate the graph definitions inside the `div` tags with `class="mermaid"` and return diagrams in SVG form, following given definitions.**
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script type="module">
|
||||||
|
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@9/dist/mermaid.esm.min.mjs';
|
||||||
|
mermaid.initialize({ startOnLoad: true });
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Following these directions, mermaid starts at page load and (when the page has loaded) it will locate the graph definitions inside the `pre` tags with `class="mermaid"` and return diagrams in SVG form, following given definitions.**
|
||||||
|
|
||||||
## Simple full example:
|
## Simple full example:
|
||||||
|
|
||||||
@@ -84,8 +80,8 @@ locate the graph definitions inside the `div` tags with `class="mermaid"` and re
|
|||||||
B-->C[fa:fa-ban forbidden]
|
B-->C[fa:fa-ban forbidden]
|
||||||
B-->D(fa:fa-spinner);
|
B-->D(fa:fa-spinner);
|
||||||
</pre>
|
</pre>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
<script type="module">
|
||||||
<script>
|
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@9/dist/mermaid.esm.min.mjs';
|
||||||
mermaid.initialize({ startOnLoad: true });
|
mermaid.initialize({ startOnLoad: true });
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
@@ -204,18 +200,17 @@ fetch the graph definition from the site (perhaps from a textarea), render it an
|
|||||||
The example below show an outline of how this could be used. The example just logs the resulting SVG to the JavaScript console.
|
The example below show an outline of how this could be used. The example just logs the resulting SVG to the JavaScript console.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="mermaid.js"></script>
|
<script type="module">
|
||||||
|
import mermaid from './mermaid.mjs';
|
||||||
<script>
|
|
||||||
mermaid.mermaidAPI.initialize({ startOnLoad: false });
|
mermaid.mermaidAPI.initialize({ startOnLoad: false });
|
||||||
$(function () {
|
$(async function () {
|
||||||
// Example of using the API var
|
// Example of using the API var
|
||||||
element = document.querySelector('#graphDiv');
|
element = document.querySelector('#graphDiv');
|
||||||
var insertSvg = function (svgCode, bindFunctions) {
|
const insertSvg = function (svgCode, bindFunctions) {
|
||||||
element.innerHTML = svgCode;
|
element.innerHTML = svgCode;
|
||||||
};
|
};
|
||||||
var graphDefinition = 'graph TB\na-->b';
|
const graphDefinition = 'graph TB\na-->b';
|
||||||
var graph = mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg);
|
const graph = await mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
@@ -339,7 +334,7 @@ on what kind of integration you use.
|
|||||||
```html
|
```html
|
||||||
<script src="../dist/mermaid.js"></script>
|
<script src="../dist/mermaid.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var config = { startOnLoad: true, flowchart: { useMaxWidth: false, htmlLabels: true } };
|
let config = { startOnLoad: true, flowchart: { useMaxWidth: false, htmlLabels: true } };
|
||||||
mermaid.initialize(config);
|
mermaid.initialize(config);
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
19
package.json
19
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "mermaid-monorepo",
|
"name": "mermaid-monorepo",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "9.2.0-rc2",
|
"version": "9.2.0-rc4",
|
||||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||||
"main": "dist/mermaid.core.mjs",
|
"main": "dist/mermaid.core.mjs",
|
||||||
"module": "dist/mermaid.core.mjs",
|
"module": "dist/mermaid.core.mjs",
|
||||||
@@ -26,12 +26,12 @@
|
|||||||
"git graph"
|
"git graph"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rimraf dist",
|
"build:mermaid": "ts-node-esm --transpileOnly --project=.vite/tsconfig.json .vite/build.ts --mermaid",
|
||||||
"build:vite": "ts-node-esm --transpileOnly --project=.vite/tsconfig.json .vite/build.ts",
|
"build:vite": "ts-node-esm --transpileOnly --project=.vite/tsconfig.json .vite/build.ts",
|
||||||
"build:types": "concurrently \"tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly\" \"tsc -p ./packages/mermaid-mindmap/tsconfig.json --emitDeclarationOnly\"",
|
"build:types": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-mindmap/tsconfig.json --emitDeclarationOnly",
|
||||||
"build:watch": "pnpm build:vite --watch",
|
"build:watch": "pnpm build:vite --watch",
|
||||||
"build": "pnpm clean; concurrently \"pnpm build:vite\" \"pnpm build:types\"",
|
"build": "pnpm run -r clean && concurrently \"pnpm build:vite\" \"pnpm build:types\"",
|
||||||
"dev": "concurrently \"pnpm build:vite --watch\" \"ts-node-esm .vite/server\"",
|
"dev": "concurrently \"pnpm build:vite --watch\" \"ts-node-esm .vite/server.ts\"",
|
||||||
"docs:build": "ts-node-esm --transpileOnly packages/mermaid/src/docs.mts",
|
"docs:build": "ts-node-esm --transpileOnly packages/mermaid/src/docs.mts",
|
||||||
"docs:verify": "pnpm docs:build --verify",
|
"docs:verify": "pnpm docs:build --verify",
|
||||||
"todo-postbuild": "documentation build src/mermaidAPI.ts src/config.ts src/defaultConfig.ts --shallow -f md --markdown-toc false > src/docs/Setup.md && prettier --write src/docs/Setup.md",
|
"todo-postbuild": "documentation build src/mermaidAPI.ts src/config.ts src/defaultConfig.ts --shallow -f md --markdown-toc false > src/docs/Setup.md && prettier --write src/docs/Setup.md",
|
||||||
@@ -48,7 +48,8 @@
|
|||||||
"e2e": "start-server-and-test dev http://localhost:9000/ cypress",
|
"e2e": "start-server-and-test dev http://localhost:9000/ cypress",
|
||||||
"ci": "vitest run",
|
"ci": "vitest run",
|
||||||
"test": "pnpm lint && vitest run",
|
"test": "pnpm lint && vitest run",
|
||||||
"test:watch": "vitest --coverage --watch",
|
"test:watch": "vitest --watch",
|
||||||
|
"test:coverage": "vitest --coverage",
|
||||||
"prepublishOnly": "pnpm build && pnpm test",
|
"prepublishOnly": "pnpm build && pnpm test",
|
||||||
"prepare": "concurrently \"husky install\" \"pnpm build\"",
|
"prepare": "concurrently \"husky install\" \"pnpm build\"",
|
||||||
"pre-commit": "lint-staged"
|
"pre-commit": "lint-staged"
|
||||||
@@ -97,6 +98,7 @@
|
|||||||
"@types/express": "^4.17.14",
|
"@types/express": "^4.17.14",
|
||||||
"@types/jsdom": "^20.0.0",
|
"@types/jsdom": "^20.0.0",
|
||||||
"@types/lodash": "^4.14.186",
|
"@types/lodash": "^4.14.186",
|
||||||
|
"@types/mdast": "^3.0.10",
|
||||||
"@types/prettier": "^2.7.1",
|
"@types/prettier": "^2.7.1",
|
||||||
"@types/stylis": "^4.0.2",
|
"@types/stylis": "^4.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.39.0",
|
"@typescript-eslint/eslint-plugin": "^5.39.0",
|
||||||
@@ -151,5 +153,8 @@
|
|||||||
"sideEffects": [
|
"sideEffects": [
|
||||||
"**/*.css",
|
"**/*.css",
|
||||||
"**/*.scss"
|
"**/*.scss"
|
||||||
]
|
],
|
||||||
|
"volta": {
|
||||||
|
"node": "18.5.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mermaid-js/mermaid-mindmap",
|
"name": "@mermaid-js/mermaid-mindmap",
|
||||||
"version": "9.2.0-rc2",
|
"version": "9.2.0",
|
||||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||||
"main": "dist/mermaid-mindmap.core.mjs",
|
"main": "dist/mermaid-mindmap.core.mjs",
|
||||||
"module": "dist/mermaid-mindmap.core.mjs",
|
"module": "dist/mermaid-mindmap.core.mjs",
|
||||||
@@ -58,6 +58,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^7.4.0",
|
"concurrently": "^7.4.0",
|
||||||
|
"mermaid": "workspace:*",
|
||||||
"rimraf": "^3.0.2"
|
"rimraf": "^3.0.2"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
import type { MermaidConfig } from 'mermaid';
|
||||||
|
|
||||||
const warning = (s: string) => {
|
const warning = (s: string) => {
|
||||||
// Todo remove debug code
|
// Todo remove debug code
|
||||||
console.error('Log function was called before initialization', s); // eslint-disable-line
|
console.error('Log function was called before initialization', s); // eslint-disable-line
|
||||||
@@ -24,7 +26,7 @@ export const log: Record<keyof typeof LEVELS, typeof console.log> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export let setLogLevel: (level: keyof typeof LEVELS | number | string) => void;
|
export let setLogLevel: (level: keyof typeof LEVELS | number | string) => void;
|
||||||
export let getConfig: () => object;
|
export let getConfig: () => MermaidConfig;
|
||||||
export let sanitizeText: (str: string) => string;
|
export let sanitizeText: (str: string) => string;
|
||||||
// eslint-disable @typescript-eslint/no-explicit-any
|
// eslint-disable @typescript-eslint/no-explicit-any
|
||||||
export let setupGraphViewbox: (
|
export let setupGraphViewbox: (
|
||||||
|
@@ -1,16 +1,28 @@
|
|||||||
/** Created by knut on 15-01-14. */
|
/** Created by knut on 23-07-2022. */
|
||||||
import { sanitizeText, getConfig, log } from './mermaidUtils';
|
import { sanitizeText, getConfig, log } from './mermaidUtils';
|
||||||
|
import type { DetailedError } from 'mermaid';
|
||||||
|
|
||||||
let nodes = [];
|
interface Node {
|
||||||
|
id: number;
|
||||||
|
nodeId: string;
|
||||||
|
level: number;
|
||||||
|
descr: string;
|
||||||
|
type: number;
|
||||||
|
children: Node[];
|
||||||
|
width: number;
|
||||||
|
padding: number;
|
||||||
|
icon?: string;
|
||||||
|
class?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nodes: Node[] = [];
|
||||||
let cnt = 0;
|
let cnt = 0;
|
||||||
let elements = {};
|
|
||||||
export const clear = () => {
|
export const clear = () => {
|
||||||
nodes = [];
|
nodes = [];
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
elements = {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getParent = function (level) {
|
const getParent = function (level: number) {
|
||||||
for (let i = nodes.length - 1; i >= 0; i--) {
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
||||||
if (nodes[i].level < level) {
|
if (nodes[i].level < level) {
|
||||||
return nodes[i];
|
return nodes[i];
|
||||||
@@ -23,28 +35,21 @@ const getParent = function (level) {
|
|||||||
export const getMindmap = () => {
|
export const getMindmap = () => {
|
||||||
return nodes.length > 0 ? nodes[0] : null;
|
return nodes.length > 0 ? nodes[0] : null;
|
||||||
};
|
};
|
||||||
export const addNode = (level, id, descr, type) => {
|
|
||||||
|
export const addNode = (level: number, id: string, descr: string, type: number) => {
|
||||||
log.info('addNode', level, id, descr, type);
|
log.info('addNode', level, id, descr, type);
|
||||||
const conf = getConfig();
|
const conf = getConfig();
|
||||||
const node = {
|
const padding = conf.mindmap?.padding ?? 15;
|
||||||
|
const node: Node = {
|
||||||
id: cnt++,
|
id: cnt++,
|
||||||
nodeId: sanitizeText(id),
|
nodeId: sanitizeText(id),
|
||||||
level,
|
level,
|
||||||
descr: sanitizeText(descr),
|
descr: sanitizeText(descr),
|
||||||
type,
|
type,
|
||||||
children: [],
|
children: [],
|
||||||
width: getConfig().mindmap.maxNodeWidth,
|
width: getConfig().mindmap?.maxNodeWidth ?? 200,
|
||||||
|
padding: type === nodeType.ROUNDED_RECT || type === nodeType.RECT ? 2 * padding : padding,
|
||||||
};
|
};
|
||||||
switch (node.type) {
|
|
||||||
case nodeType.ROUNDED_RECT:
|
|
||||||
node.padding = 2 * conf.mindmap.padding;
|
|
||||||
break;
|
|
||||||
case nodeType.RECT:
|
|
||||||
node.padding = 2 * conf.mindmap.padding;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
node.padding = conf.mindmap.padding;
|
|
||||||
}
|
|
||||||
const parent = getParent(level);
|
const parent = getParent(level);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent.children.push(node);
|
parent.children.push(node);
|
||||||
@@ -56,9 +61,10 @@ export const addNode = (level, id, descr, type) => {
|
|||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
} else {
|
} else {
|
||||||
// Syntax error ... there can only bee one root
|
// Syntax error ... there can only bee one root
|
||||||
let error = new Error(
|
const error = new Error(
|
||||||
'There can be only one root. No parent could be found for ("' + node.descr + '")'
|
'There can be only one root. No parent could be found for ("' + node.descr + '")'
|
||||||
);
|
);
|
||||||
|
// @ts-ignore TODO: Add mermaid error
|
||||||
error.hash = {
|
error.hash = {
|
||||||
text: 'branch ' + name,
|
text: 'branch ' + name,
|
||||||
token: 'branch ' + name,
|
token: 'branch ' + name,
|
||||||
@@ -81,7 +87,7 @@ export const nodeType = {
|
|||||||
BANG: 5,
|
BANG: 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getType = (startStr, endStr) => {
|
export const getType = (startStr: string, endStr: string): number => {
|
||||||
log.debug('In get type', startStr, endStr);
|
log.debug('In get type', startStr, endStr);
|
||||||
switch (startStr) {
|
switch (startStr) {
|
||||||
case '[':
|
case '[':
|
||||||
@@ -99,11 +105,7 @@ export const getType = (startStr, endStr) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setElementForId = (id, element) => {
|
export const decorateNode = (decoration: { icon: string; class: string }) => {
|
||||||
elements[id] = element;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const decorateNode = (decoration) => {
|
|
||||||
const node = nodes[nodes.length - 1];
|
const node = nodes[nodes.length - 1];
|
||||||
if (decoration && decoration.icon) {
|
if (decoration && decoration.icon) {
|
||||||
node.icon = sanitizeText(decoration.icon);
|
node.icon = sanitizeText(decoration.icon);
|
||||||
@@ -113,7 +115,7 @@ export const decorateNode = (decoration) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const type2Str = (type) => {
|
export const type2Str = (type: number) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case nodeType.DEFAULT:
|
case nodeType.DEFAULT:
|
||||||
return 'no-border';
|
return 'no-border';
|
||||||
@@ -132,13 +134,13 @@ export const type2Str = (type) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export let parseError;
|
export type ParseErrorFunction = (err: string | DetailedError, hash?: any) => void;
|
||||||
export const setErrorHandler = (handler) => {
|
export let parseError: ParseErrorFunction;
|
||||||
|
export const setErrorHandler = (handler: ParseErrorFunction) => {
|
||||||
parseError = handler;
|
parseError = handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Expose logger to grammar
|
// Expose logger to grammar
|
||||||
export const getLogger = () => log;
|
export const getLogger = () => log;
|
||||||
|
|
||||||
export const getNodeById = (id) => nodes[id];
|
export const getNodeById = (id: number): Node => nodes[id];
|
||||||
export const getElementById = (id) => elements[id];
|
|
@@ -1,10 +1,9 @@
|
|||||||
/** Created by knut on 14-12-11. */
|
/** Created by knut on 23-07-2022. */
|
||||||
import { select } from 'd3';
|
import { select } from 'd3';
|
||||||
import { log, getConfig, setupGraphViewbox } from './mermaidUtils';
|
import { log, getConfig, setupGraphViewbox } from './mermaidUtils';
|
||||||
import svgDraw from './svgDraw';
|
import svgDraw, { getElementById, clearElementRefs } from './svgDraw';
|
||||||
import cytoscape from 'cytoscape';
|
import cytoscape from 'cytoscape';
|
||||||
import coseBilkent from 'cytoscape-cose-bilkent';
|
import coseBilkent from 'cytoscape-cose-bilkent';
|
||||||
import * as db from './mindmapDb';
|
|
||||||
|
|
||||||
// Inject the layout algorithm into cytoscape
|
// Inject the layout algorithm into cytoscape
|
||||||
cytoscape.use(coseBilkent);
|
cytoscape.use(coseBilkent);
|
||||||
@@ -34,7 +33,7 @@ function drawNodes(svg, mindmap, section, conf) {
|
|||||||
* @param cy
|
* @param cy
|
||||||
*/
|
*/
|
||||||
function drawEdges(edgesEl, cy) {
|
function drawEdges(edgesEl, cy) {
|
||||||
cy.edges().map((edge, id) => {
|
cy?.edges().map((edge, id) => {
|
||||||
const data = edge.data();
|
const data = edge.data();
|
||||||
if (edge[0]._private.bodyBounds) {
|
if (edge[0]._private.bodyBounds) {
|
||||||
const bounds = edge[0]._private.rscratch;
|
const bounds = edge[0]._private.rscratch;
|
||||||
@@ -100,9 +99,10 @@ function addNodes(mindmap, cy, conf, level) {
|
|||||||
*/
|
*/
|
||||||
function layoutMindmap(node, conf) {
|
function layoutMindmap(node, conf) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (node.children.length === 0) {
|
// if (node.children.length === 0) {
|
||||||
return node;
|
// resolve(node);
|
||||||
}
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
// Add temporary render element
|
// Add temporary render element
|
||||||
const renderEl = select('body').append('div').attr('id', 'cy').attr('style', 'display:none');
|
const renderEl = select('body').append('div').attr('id', 'cy').attr('style', 'display:none');
|
||||||
@@ -154,7 +154,7 @@ function positionNodes(cy) {
|
|||||||
data.x = node.position().x;
|
data.x = node.position().x;
|
||||||
data.y = node.position().y;
|
data.y = node.position().y;
|
||||||
svgDraw.positionNode(data);
|
svgDraw.positionNode(data);
|
||||||
const el = db.getElementById(data.nodeId);
|
const el = getElementById(data.nodeId);
|
||||||
log.info('Id:', id, 'Position: (', node.position().x, ', ', node.position().y, ')', data);
|
log.info('Id:', id, 'Position: (', node.position().x, ', ', node.position().y, ')', data);
|
||||||
el.attr(
|
el.attr(
|
||||||
'transform',
|
'transform',
|
||||||
@@ -178,6 +178,7 @@ export const draw = async (text, id, version, diagObj) => {
|
|||||||
|
|
||||||
// This is done only for throwing the error if the text is not valid.
|
// This is done only for throwing the error if the text is not valid.
|
||||||
diagObj.db.clear();
|
diagObj.db.clear();
|
||||||
|
clearElementRefs();
|
||||||
// Parse the graph definition
|
// Parse the graph definition
|
||||||
diagObj.parser.parse(text);
|
diagObj.parser.parse(text);
|
||||||
|
|
||||||
|
@@ -22,12 +22,10 @@ const genSections = (options) => {
|
|||||||
}
|
}
|
||||||
.section-${i - 1} text {
|
.section-${i - 1} text {
|
||||||
fill: ${options['cScaleLabel' + i]};
|
fill: ${options['cScaleLabel' + i]};
|
||||||
// fill: ${options['gitInv' + i]};
|
|
||||||
}
|
}
|
||||||
.node-icon-${i - 1} {
|
.node-icon-${i - 1} {
|
||||||
font-size: 40px;
|
font-size: 40px;
|
||||||
color: ${options['cScaleLabel' + i]};
|
color: ${options['cScaleLabel' + i]};
|
||||||
// color: ${options['gitInv' + i]};
|
|
||||||
}
|
}
|
||||||
.section-edge-${i - 1}{
|
.section-edge-${i - 1}{
|
||||||
stroke: ${options['cScale' + i]};
|
stroke: ${options['cScale' + i]};
|
||||||
@@ -36,7 +34,7 @@ const genSections = (options) => {
|
|||||||
stroke-width: ${sw};
|
stroke-width: ${sw};
|
||||||
}
|
}
|
||||||
.section-${i - 1} line {
|
.section-${i - 1} line {
|
||||||
stroke: ${options['lineColor' + i]} ;
|
stroke: ${options['cScaleInv' + i]} ;
|
||||||
stroke-width: 3;
|
stroke-width: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -259,7 +259,7 @@ export const drawNode = function (elem, node, fullSection, conf) {
|
|||||||
// if (typeof node.x !== 'undefined' && typeof node.y !== 'undefined') {
|
// if (typeof node.x !== 'undefined' && typeof node.y !== 'undefined') {
|
||||||
// nodeElem.attr('transform', 'translate(' + node.x + ',' + node.y + ')');
|
// nodeElem.attr('transform', 'translate(' + node.x + ',' + node.y + ')');
|
||||||
// }
|
// }
|
||||||
db.setElementForId(node.id, nodeElem);
|
setElementById(node.id, nodeElem);
|
||||||
return node.height;
|
return node.height;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -286,7 +286,7 @@ export const drawEdge = function drawEdge(edgesElem, mindmap, parent, depth, ful
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const positionNode = function (node) {
|
export const positionNode = function (node) {
|
||||||
const nodeElem = db.getElementById(node.id);
|
const nodeElem = getElementById(node.id);
|
||||||
|
|
||||||
const x = node.x || 0;
|
const x = node.x || 0;
|
||||||
const y = node.y || 0;
|
const y = node.y || 0;
|
||||||
@@ -294,4 +294,18 @@ export const positionNode = function (node) {
|
|||||||
nodeElem.attr('transform', 'translate(' + x + ',' + y + ')');
|
nodeElem.attr('transform', 'translate(' + x + ',' + y + ')');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let elements = {};
|
||||||
|
|
||||||
|
const setElementById = (id, element) => {
|
||||||
|
elements[id] = element;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getElementById = (id) => {
|
||||||
|
return elements[id];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const clearElementRefs = () => {
|
||||||
|
elements = {};
|
||||||
|
};
|
||||||
|
|
||||||
export default { drawNode, positionNode, drawEdge };
|
export default { drawNode, positionNode, drawEdge };
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mermaid",
|
"name": "mermaid",
|
||||||
"version": "9.2.0-rc2",
|
"version": "9.2.0",
|
||||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||||
"main": "./dist/mermaid.core.mjs",
|
"main": "./dist/mermaid.core.mjs",
|
||||||
"module": "./dist/mermaid.core.mjs",
|
"module": "./dist/mermaid.core.mjs",
|
||||||
@@ -72,7 +72,8 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment-mini": "^2.24.0",
|
"moment-mini": "^2.24.0",
|
||||||
"non-layered-tidy-tree-layout": "^2.0.2",
|
"non-layered-tidy-tree-layout": "^2.0.2",
|
||||||
"stylis": "^4.1.2"
|
"stylis": "^4.1.2",
|
||||||
|
"uuid": "^9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@applitools/eyes-cypress": "^3.25.7",
|
"@applitools/eyes-cypress": "^3.25.7",
|
||||||
@@ -86,6 +87,7 @@
|
|||||||
"@types/lodash": "^4.14.185",
|
"@types/lodash": "^4.14.185",
|
||||||
"@types/prettier": "^2.7.0",
|
"@types/prettier": "^2.7.0",
|
||||||
"@types/stylis": "^4.0.2",
|
"@types/stylis": "^4.0.2",
|
||||||
|
"@types/uuid": "^8.3.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.37.0",
|
"@typescript-eslint/eslint-plugin": "^5.37.0",
|
||||||
"@typescript-eslint/parser": "^5.37.0",
|
"@typescript-eslint/parser": "^5.37.0",
|
||||||
"concurrently": "^7.4.0",
|
"concurrently": "^7.4.0",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import * as configApi from './config';
|
import * as configApi from './config';
|
||||||
import { log } from './logger';
|
import { log } from './logger';
|
||||||
import { getDiagram, registerDiagram } from './diagram-api/diagramAPI';
|
import { DiagramNotFoundError, getDiagram, registerDiagram } from './diagram-api/diagramAPI';
|
||||||
import { detectType, getDiagramLoader } from './diagram-api/detectType';
|
import { detectType, getDiagramLoader } from './diagram-api/detectType';
|
||||||
import { isDetailedError } from './utils';
|
import { isDetailedError } from './utils';
|
||||||
export class Diagram {
|
export class Diagram {
|
||||||
@@ -8,11 +8,18 @@ export class Diagram {
|
|||||||
parser;
|
parser;
|
||||||
renderer;
|
renderer;
|
||||||
db;
|
db;
|
||||||
|
private detectTypeFailed = false;
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
constructor(public txt: string, parseError?: Function) {
|
constructor(public txt: string, parseError?: Function) {
|
||||||
const cnf = configApi.getConfig();
|
const cnf = configApi.getConfig();
|
||||||
this.txt = txt;
|
this.txt = txt;
|
||||||
|
try {
|
||||||
this.type = detectType(txt, cnf);
|
this.type = detectType(txt, cnf);
|
||||||
|
} catch (e) {
|
||||||
|
this.handleError(e, parseError);
|
||||||
|
this.type = 'error';
|
||||||
|
this.detectTypeFailed = true;
|
||||||
|
}
|
||||||
const diagram = getDiagram(this.type);
|
const diagram = getDiagram(this.type);
|
||||||
log.debug('Type ' + this.type);
|
log.debug('Type ' + this.type);
|
||||||
// Setup diagram
|
// Setup diagram
|
||||||
@@ -32,12 +39,22 @@ export class Diagram {
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
parse(text: string, parseError?: Function): boolean {
|
parse(text: string, parseError?: Function): boolean {
|
||||||
|
if (this.detectTypeFailed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
text = text + '\n';
|
text = text + '\n';
|
||||||
this.db.clear();
|
this.db.clear();
|
||||||
this.parser.parse(text);
|
this.parser.parse(text);
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
this.handleError(error, parseError);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
handleError(error: unknown, parseError?: Function) {
|
||||||
// Is this the correct way to access mermiad's parseError()
|
// Is this the correct way to access mermiad's parseError()
|
||||||
// method ? (or global.mermaid.parseError()) ?
|
// method ? (or global.mermaid.parseError()) ?
|
||||||
if (parseError) {
|
if (parseError) {
|
||||||
@@ -54,8 +71,6 @@ export class Diagram {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getParser() {
|
getParser() {
|
||||||
return this.parser;
|
return this.parser;
|
||||||
@@ -66,37 +81,36 @@ export class Diagram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Diagram;
|
export const getDiagramFromText = (
|
||||||
|
txt: string,
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
export const getDiagramFromText = async (txt: string, parseError?: Function) => {
|
parseError?: Function
|
||||||
|
): Diagram | Promise<Diagram> => {
|
||||||
const type = detectType(txt, configApi.getConfig());
|
const type = detectType(txt, configApi.getConfig());
|
||||||
try {
|
try {
|
||||||
// Trying to find the diagram
|
// Trying to find the diagram
|
||||||
getDiagram(type);
|
getDiagram(type);
|
||||||
|
return new Diagram(txt, parseError);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
if (!(error instanceof DiagramNotFoundError)) {
|
||||||
|
log.error(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
const loader = getDiagramLoader(type);
|
const loader = getDiagramLoader(type);
|
||||||
if (!loader) {
|
if (!loader) {
|
||||||
throw new Error(`Diagram ${type} not found.`);
|
throw new Error(`Loader for ${type} not found.`);
|
||||||
}
|
}
|
||||||
// Diagram not avaiable, loading it
|
// TODO: Uncomment for v10
|
||||||
// const path = getPathForDiagram(type);
|
// // Diagram not available, loading it
|
||||||
const { diagram } = await loader(); // eslint-disable-line @typescript-eslint/no-explicit-any
|
// const { diagram } = await loader();
|
||||||
registerDiagram(
|
// registerDiagram(type, diagram, undefined, diagram.injectUtils);
|
||||||
type,
|
// // new diagram will try getDiagram again and if fails then it is a valid throw
|
||||||
{
|
return loader().then(({ diagram }) => {
|
||||||
db: diagram.db,
|
registerDiagram(type, diagram, undefined, diagram.injectUtils);
|
||||||
renderer: diagram.renderer,
|
|
||||||
parser: diagram.parser,
|
|
||||||
styles: diagram.styles,
|
|
||||||
},
|
|
||||||
diagram.injectUtils
|
|
||||||
);
|
|
||||||
// await loadDiagram('./packages/mermaid-mindmap/dist/mermaid-mindmap.js');
|
|
||||||
// await loadDiagram(path + 'mermaid-' + type + '.js');
|
|
||||||
// new diagram will try getDiagram again and if fails then it is a valid throw
|
|
||||||
}
|
|
||||||
// If either of the above worked, we have the diagram
|
|
||||||
// logic and can continue
|
|
||||||
return new Diagram(txt, parseError);
|
return new Diagram(txt, parseError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// return new Diagram(txt, parseError);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default Diagram;
|
||||||
|
@@ -11,17 +11,13 @@ import Diagram from '../Diagram';
|
|||||||
// Normally, we could just do the following to get the original `parse()`
|
// Normally, we could just do the following to get the original `parse()`
|
||||||
// implementation, however, requireActual returns a promise and it's not documented how to use withing mock file.
|
// implementation, however, requireActual returns a promise and it's not documented how to use withing mock file.
|
||||||
|
|
||||||
let hasLoadedDiagrams = false;
|
|
||||||
/**
|
/**
|
||||||
* @param text
|
* @param text
|
||||||
* @param parseError
|
* @param parseError
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
function parse(text: string, parseError?: Function): boolean {
|
function parse(text: string, parseError?: Function): boolean {
|
||||||
if (!hasLoadedDiagrams) {
|
|
||||||
addDiagrams();
|
addDiagrams();
|
||||||
hasLoadedDiagrams = true;
|
|
||||||
}
|
|
||||||
const diagram = new Diagram(text, parseError);
|
const diagram = new Diagram(text, parseError);
|
||||||
return diagram.parse(text, parseError);
|
return diagram.parse(text, parseError);
|
||||||
}
|
}
|
||||||
@@ -29,6 +25,7 @@ function parse(text: string, parseError?: Function): boolean {
|
|||||||
// original version cannot be modified since it was frozen with `Object.freeze()`
|
// original version cannot be modified since it was frozen with `Object.freeze()`
|
||||||
export const mermaidAPI = {
|
export const mermaidAPI = {
|
||||||
render: vi.fn(),
|
render: vi.fn(),
|
||||||
|
renderAsync: vi.fn(),
|
||||||
parse,
|
parse,
|
||||||
parseDirective: vi.fn(),
|
parseDirective: vi.fn(),
|
||||||
initialize: vi.fn(),
|
initialize: vi.fn(),
|
||||||
|
@@ -3,7 +3,8 @@
|
|||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
|
|
||||||
export interface MermaidConfig {
|
export interface MermaidConfig {
|
||||||
lazyLoadedDiagrams?: any;
|
lazyLoadedDiagrams?: string[];
|
||||||
|
loadExternalDiagramsAtStartup?: boolean;
|
||||||
theme?: string;
|
theme?: string;
|
||||||
themeVariables?: any;
|
themeVariables?: any;
|
||||||
themeCSS?: string;
|
themeCSS?: string;
|
||||||
|
@@ -438,6 +438,9 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
|
|||||||
case 'thick':
|
case 'thick':
|
||||||
strokeClasses = 'edge-thickness-thick';
|
strokeClasses = 'edge-thickness-thick';
|
||||||
break;
|
break;
|
||||||
|
case 'invisible':
|
||||||
|
strokeClasses = 'edge-thickness-thick';
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
strokeClasses = '';
|
strokeClasses = '';
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,7 @@
|
|||||||
import { MermaidConfig } from '../config.type';
|
import { MermaidConfig } from '../config.type';
|
||||||
|
import { log } from '../logger';
|
||||||
|
import { DetectorRecord, DiagramDetector, DiagramLoader } from './types';
|
||||||
|
|
||||||
export type DiagramDetector = (text: string, config?: MermaidConfig) => boolean;
|
|
||||||
export type DiagramLoader = (() => any) | null;
|
|
||||||
export type DetectorRecord = { detector: DiagramDetector; loader: DiagramLoader };
|
|
||||||
const directive =
|
const directive =
|
||||||
/[%]{2}[{]\s*(?:(?:(\w+)\s*:|(\w+))\s*(?:(?:(\w+))|((?:(?![}][%]{2}).|\r?\n)*))?\s*)(?:[}][%]{2})?/gi;
|
/[%]{2}[{]\s*(?:(?:(\w+)\s*:|(\w+))\s*(?:(?:(\w+))|((?:(?![}][%]{2}).|\r?\n)*))?\s*)(?:[}][%]{2})?/gi;
|
||||||
const anyComment = /\s*%%.*\n/gm;
|
const anyComment = /\s*%%.*\n/gm;
|
||||||
@@ -34,26 +33,22 @@ const detectors: Record<string, DetectorRecord> = {};
|
|||||||
*/
|
*/
|
||||||
export const detectType = function (text: string, config?: MermaidConfig): string {
|
export const detectType = function (text: string, config?: MermaidConfig): string {
|
||||||
text = text.replace(directive, '').replace(anyComment, '\n');
|
text = text.replace(directive, '').replace(anyComment, '\n');
|
||||||
|
|
||||||
// console.log(detectors);
|
|
||||||
|
|
||||||
for (const [key, { detector }] of Object.entries(detectors)) {
|
for (const [key, { detector }] of Object.entries(detectors)) {
|
||||||
const diagram = detector(text, config);
|
const diagram = detector(text, config);
|
||||||
if (diagram) {
|
if (diagram) {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: #3391
|
|
||||||
// throw new Error(`No diagram type detected for text: ${text}`);
|
throw new Error(`No diagram type detected for text: ${text}`);
|
||||||
return 'flowchart';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addDetector = (
|
export const addDetector = (key: string, detector: DiagramDetector, loader?: DiagramLoader) => {
|
||||||
key: string,
|
if (detectors[key]) {
|
||||||
detector: DiagramDetector,
|
throw new Error(`Detector with key ${key} already exists`);
|
||||||
loader: DiagramLoader | null
|
}
|
||||||
) => {
|
|
||||||
detectors[key] = { detector, loader };
|
detectors[key] = { detector, loader };
|
||||||
|
log.debug(`Detector with key ${key} added${loader ? ' with loader' : ''}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDiagramLoader = (key: string) => detectors[key].loader;
|
export const getDiagramLoader = (key: string) => detectors[key].loader;
|
||||||
|
@@ -1,16 +1,4 @@
|
|||||||
import {
|
import { registerDiagram } from './diagramAPI';
|
||||||
registerDiagram,
|
|
||||||
registerDetector,
|
|
||||||
DiagramDefinition,
|
|
||||||
DiagramDetector,
|
|
||||||
} from './diagramAPI';
|
|
||||||
|
|
||||||
// // @ts-ignore: TODO Fix ts errors
|
|
||||||
// import mindmapParser from '../diagrams/mindmap/parser/mindmap';
|
|
||||||
// import * as mindmapDb from '../diagrams/mindmap/mindmapDb';
|
|
||||||
// import { mindmapDetector } from '../diagrams/mindmap/mindmapDetector';
|
|
||||||
// import mindmapRenderer from '../diagrams/mindmap/mindmapRenderer';
|
|
||||||
// import mindmapStyles from '../diagrams/mindmap/styles';
|
|
||||||
|
|
||||||
// @ts-ignore: TODO Fix ts errors
|
// @ts-ignore: TODO Fix ts errors
|
||||||
import gitGraphParser from '../diagrams/git/parser/gitGraph';
|
import gitGraphParser from '../diagrams/git/parser/gitGraph';
|
||||||
@@ -106,17 +94,15 @@ import { setConfig } from '../config';
|
|||||||
import errorRenderer from '../diagrams/error/errorRenderer';
|
import errorRenderer from '../diagrams/error/errorRenderer';
|
||||||
import errorStyles from '../diagrams/error/styles';
|
import errorStyles from '../diagrams/error/styles';
|
||||||
|
|
||||||
const registerDiagramAndDetector = (
|
let hasLoadedDiagrams = false;
|
||||||
id: string,
|
|
||||||
diagram: DiagramDefinition,
|
|
||||||
detector: DiagramDetector
|
|
||||||
) => {
|
|
||||||
registerDiagram(id, diagram);
|
|
||||||
registerDetector(id, detector);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addDiagrams = () => {
|
export const addDiagrams = () => {
|
||||||
registerDiagramAndDetector(
|
if (hasLoadedDiagrams) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// This is added here to avoid race-conditions.
|
||||||
|
// We could optimize the loading logic somehow.
|
||||||
|
hasLoadedDiagrams = true;
|
||||||
|
registerDiagram(
|
||||||
'error',
|
'error',
|
||||||
// Special diagram with error messages but setup as a regular diagram
|
// Special diagram with error messages but setup as a regular diagram
|
||||||
{
|
{
|
||||||
@@ -140,7 +126,7 @@ export const addDiagrams = () => {
|
|||||||
(text) => text.toLowerCase().trim() === 'error'
|
(text) => text.toLowerCase().trim() === 'error'
|
||||||
);
|
);
|
||||||
|
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'c4',
|
'c4',
|
||||||
{
|
{
|
||||||
parser: c4Parser,
|
parser: c4Parser,
|
||||||
@@ -153,7 +139,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
c4Detector
|
c4Detector
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'class',
|
'class',
|
||||||
{
|
{
|
||||||
parser: classParser,
|
parser: classParser,
|
||||||
@@ -170,7 +156,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
classDetector
|
classDetector
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'classDiagram',
|
'classDiagram',
|
||||||
{
|
{
|
||||||
parser: classParser,
|
parser: classParser,
|
||||||
@@ -187,7 +173,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
classDetectorV2
|
classDetectorV2
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'er',
|
'er',
|
||||||
{
|
{
|
||||||
parser: erParser,
|
parser: erParser,
|
||||||
@@ -197,7 +183,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
erDetector
|
erDetector
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'gantt',
|
'gantt',
|
||||||
{
|
{
|
||||||
parser: ganttParser,
|
parser: ganttParser,
|
||||||
@@ -207,7 +193,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
ganttDetector
|
ganttDetector
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'info',
|
'info',
|
||||||
{
|
{
|
||||||
parser: infoParser,
|
parser: infoParser,
|
||||||
@@ -217,7 +203,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
infoDetector
|
infoDetector
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'pie',
|
'pie',
|
||||||
{
|
{
|
||||||
parser: pieParser,
|
parser: pieParser,
|
||||||
@@ -227,7 +213,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
pieDetector
|
pieDetector
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'requirement',
|
'requirement',
|
||||||
{
|
{
|
||||||
parser: requirementParser,
|
parser: requirementParser,
|
||||||
@@ -237,7 +223,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
requirementDetector
|
requirementDetector
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'sequence',
|
'sequence',
|
||||||
{
|
{
|
||||||
parser: sequenceParser,
|
parser: sequenceParser,
|
||||||
@@ -260,7 +246,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
sequenceDetector
|
sequenceDetector
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'state',
|
'state',
|
||||||
{
|
{
|
||||||
parser: stateParser,
|
parser: stateParser,
|
||||||
@@ -277,7 +263,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
stateDetector
|
stateDetector
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'stateDiagram',
|
'stateDiagram',
|
||||||
{
|
{
|
||||||
parser: stateParser,
|
parser: stateParser,
|
||||||
@@ -294,7 +280,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
stateDetectorV2
|
stateDetectorV2
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'journey',
|
'journey',
|
||||||
{
|
{
|
||||||
parser: journeyParser,
|
parser: journeyParser,
|
||||||
@@ -309,7 +295,7 @@ export const addDiagrams = () => {
|
|||||||
journeyDetector
|
journeyDetector
|
||||||
);
|
);
|
||||||
|
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'flowchart',
|
'flowchart',
|
||||||
{
|
{
|
||||||
parser: flowParser,
|
parser: flowParser,
|
||||||
@@ -329,7 +315,7 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
flowDetector
|
flowDetector
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'flowchart-v2',
|
'flowchart-v2',
|
||||||
{
|
{
|
||||||
parser: flowParser,
|
parser: flowParser,
|
||||||
@@ -350,14 +336,9 @@ export const addDiagrams = () => {
|
|||||||
},
|
},
|
||||||
flowDetectorV2
|
flowDetectorV2
|
||||||
);
|
);
|
||||||
registerDiagramAndDetector(
|
registerDiagram(
|
||||||
'gitGraph',
|
'gitGraph',
|
||||||
{ parser: gitGraphParser, db: gitGraphDb, renderer: gitGraphRenderer, styles: gitGraphStyles },
|
{ parser: gitGraphParser, db: gitGraphDb, renderer: gitGraphRenderer, styles: gitGraphStyles },
|
||||||
gitGraphDetector
|
gitGraphDetector
|
||||||
);
|
);
|
||||||
// registerDiagram(
|
|
||||||
// 'mindmap',
|
|
||||||
// { parser: mindmapParser, db: mindmapDb, renderer: mindmapRenderer, styles: mindmapStyles },
|
|
||||||
// mindmapDetector
|
|
||||||
// );
|
|
||||||
};
|
};
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { detectType, DiagramDetector } from './detectType';
|
import { detectType } from './detectType';
|
||||||
import { getDiagram, registerDiagram, registerDetector } from './diagramAPI';
|
import { getDiagram, registerDiagram } from './diagramAPI';
|
||||||
import { addDiagrams } from './diagram-orchestration';
|
import { addDiagrams } from './diagram-orchestration';
|
||||||
|
import { DiagramDetector } from './types';
|
||||||
|
|
||||||
addDiagrams();
|
addDiagrams();
|
||||||
|
|
||||||
@@ -15,17 +16,22 @@ describe('DiagramAPI', () => {
|
|||||||
|
|
||||||
it('should handle diagram registrations', () => {
|
it('should handle diagram registrations', () => {
|
||||||
expect(() => getDiagram('loki')).toThrow();
|
expect(() => getDiagram('loki')).toThrow();
|
||||||
expect(() => detectType('loki diagram')).not.toThrow(); // TODO: #3391
|
expect(() => detectType('loki diagram')).toThrow(
|
||||||
|
'No diagram type detected for text: loki diagram'
|
||||||
|
);
|
||||||
const detector: DiagramDetector = (str: string) => {
|
const detector: DiagramDetector = (str: string) => {
|
||||||
return str.match('loki') !== null;
|
return str.match('loki') !== null;
|
||||||
};
|
};
|
||||||
registerDetector('loki', detector);
|
registerDiagram(
|
||||||
registerDiagram('loki', {
|
'loki',
|
||||||
|
{
|
||||||
db: {},
|
db: {},
|
||||||
parser: {},
|
parser: {},
|
||||||
renderer: {},
|
renderer: {},
|
||||||
styles: {},
|
styles: {},
|
||||||
});
|
},
|
||||||
|
detector
|
||||||
|
);
|
||||||
expect(getDiagram('loki')).not.toBeNull();
|
expect(getDiagram('loki')).not.toBeNull();
|
||||||
expect(detectType('loki diagram')).toBe('loki');
|
expect(detectType('loki diagram')).toBe('loki');
|
||||||
});
|
});
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
import { addDetector, DiagramDetector as _DiagramDetector } from './detectType';
|
import { addDetector } from './detectType';
|
||||||
import { log as _log, setLogLevel as _setLogLevel } from '../logger';
|
import { log as _log, setLogLevel as _setLogLevel } from '../logger';
|
||||||
import { getConfig as _getConfig } from '../config';
|
import { getConfig as _getConfig } from '../config';
|
||||||
import { sanitizeText as _sanitizeText } from '../diagrams/common/common';
|
import { sanitizeText as _sanitizeText } from '../diagrams/common/common';
|
||||||
import { MermaidConfig } from '../config.type';
|
|
||||||
import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox';
|
import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox';
|
||||||
import { addStylesForDiagram } from '../styles';
|
import { addStylesForDiagram } from '../styles';
|
||||||
|
import { DiagramDefinition, DiagramDetector } from './types';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Packaging and exposing resources for externa diagrams so that they can import
|
Packaging and exposing resources for externa diagrams so that they can import
|
||||||
@@ -13,41 +13,19 @@ import { addStylesForDiagram } from '../styles';
|
|||||||
*/
|
*/
|
||||||
export const log = _log;
|
export const log = _log;
|
||||||
export const setLogLevel = _setLogLevel;
|
export const setLogLevel = _setLogLevel;
|
||||||
export type DiagramDetector = _DiagramDetector;
|
|
||||||
export const getConfig = _getConfig;
|
export const getConfig = _getConfig;
|
||||||
export const sanitizeText = (text: string) => _sanitizeText(text, getConfig());
|
export const sanitizeText = (text: string) => _sanitizeText(text, getConfig());
|
||||||
export const setupGraphViewbox = _setupGraphViewbox;
|
export const setupGraphViewbox = _setupGraphViewbox;
|
||||||
|
|
||||||
export interface InjectUtils {
|
|
||||||
_log: any;
|
|
||||||
_setLogLevel: any;
|
|
||||||
_getConfig: any;
|
|
||||||
_sanitizeText: any;
|
|
||||||
_setupGraphViewbox: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DiagramDefinition {
|
|
||||||
db: any;
|
|
||||||
renderer: any;
|
|
||||||
parser: any;
|
|
||||||
styles: any;
|
|
||||||
init?: (config: MermaidConfig) => void;
|
|
||||||
injectUtils?: (utils: InjectUtils) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const diagrams: Record<string, DiagramDefinition> = {};
|
const diagrams: Record<string, DiagramDefinition> = {};
|
||||||
const connectCallbacks: Record<string, any> = {}; // TODO fix, eslint-disable-line @typescript-eslint/no-explicit-any
|
|
||||||
export interface Detectors {
|
export interface Detectors {
|
||||||
[key: string]: DiagramDetector;
|
[key: string]: DiagramDetector;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const registerDetector = (id: string, detector: DiagramDetector) => {
|
|
||||||
addDetector(id, detector, null);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const registerDiagram = (
|
export const registerDiagram = (
|
||||||
id: string,
|
id: string,
|
||||||
diagram: DiagramDefinition,
|
diagram: DiagramDefinition,
|
||||||
|
detector?: DiagramDetector,
|
||||||
callback?: (
|
callback?: (
|
||||||
_log: any,
|
_log: any,
|
||||||
_setLogLevel: any,
|
_setLogLevel: any,
|
||||||
@@ -56,35 +34,36 @@ export const registerDiagram = (
|
|||||||
_setupGraphViewbox: any
|
_setupGraphViewbox: any
|
||||||
) => void
|
) => void
|
||||||
) => {
|
) => {
|
||||||
|
log.debug(`Registering diagram ${id}`);
|
||||||
if (diagrams[id]) {
|
if (diagrams[id]) {
|
||||||
log.warn(`Diagram ${id} already registered.`);
|
log.warn(`Diagram ${id} already registered.`);
|
||||||
|
// The error throw is commented out to as it breaks pages where you have multiple diagrams,
|
||||||
|
// it can happen that rendering of the same type of diagram is initiated while the previous
|
||||||
|
// one is still being imported. import deals with this and only one diagram is imported in
|
||||||
|
// the end.
|
||||||
|
// throw new Error(`Diagram ${id} already registered.`);
|
||||||
}
|
}
|
||||||
diagrams[id] = diagram;
|
diagrams[id] = diagram;
|
||||||
|
if (detector) {
|
||||||
|
addDetector(id, detector);
|
||||||
|
}
|
||||||
addStylesForDiagram(id, diagram.styles);
|
addStylesForDiagram(id, diagram.styles);
|
||||||
if (typeof callback !== 'undefined') {
|
if (typeof callback !== 'undefined') {
|
||||||
callback(log, setLogLevel, getConfig, sanitizeText, setupGraphViewbox);
|
callback(log, setLogLevel, getConfig, sanitizeText, setupGraphViewbox);
|
||||||
}
|
}
|
||||||
|
log.debug(`Registered diagram ${id}. ${Object.keys(diagrams).join(', ')} diagrams registered.`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDiagram = (name: string): DiagramDefinition => {
|
export const getDiagram = (name: string): DiagramDefinition => {
|
||||||
|
log.debug(`Getting diagram ${name}. ${Object.keys(diagrams).join(', ')} diagrams registered.`);
|
||||||
if (name in diagrams) {
|
if (name in diagrams) {
|
||||||
return diagrams[name];
|
return diagrams[name];
|
||||||
}
|
}
|
||||||
throw new Error(`Diagram ${name} not found.`);
|
throw new DiagramNotFoundError(name);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
export class DiagramNotFoundError extends Error {
|
||||||
*
|
constructor(message: string) {
|
||||||
* @param sScriptSrc
|
super(`Diagram ${message} not found.`);
|
||||||
*/
|
}
|
||||||
export const loadDiagram = (sScriptSrc: string) =>
|
}
|
||||||
new Promise((resolve) => {
|
|
||||||
const oHead = document.getElementsByTagName('HEAD')[0];
|
|
||||||
const oScript = document.createElement('script');
|
|
||||||
oScript.type = 'text/javascript';
|
|
||||||
oScript.src = sScriptSrc;
|
|
||||||
oHead.appendChild(oScript);
|
|
||||||
oScript.onload = () => {
|
|
||||||
resolve(true);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
@@ -1,227 +0,0 @@
|
|||||||
export const lineBreakRegex = /<br\s*\/?>/gi;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Caches results of functions based on input
|
|
||||||
*
|
|
||||||
* @param {Function} fn Function to run
|
|
||||||
* @param {Function} resolver Function that resolves to an ID given arguments the `fn` takes
|
|
||||||
* @returns {Function} An optimized caching function
|
|
||||||
*/
|
|
||||||
const memoize = (fn, resolver) => {
|
|
||||||
let cache = {};
|
|
||||||
return (...args) => {
|
|
||||||
let n = resolver ? resolver.apply(this, args) : args[0];
|
|
||||||
if (n in cache) {
|
|
||||||
return cache[n];
|
|
||||||
} else {
|
|
||||||
let result = fn(...args);
|
|
||||||
cache[n] = result;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* This calculates the width of the given text, font size and family.
|
|
||||||
*
|
|
||||||
* @param {any} text - The text to calculate the width of
|
|
||||||
* @param {any} config - The config for fontSize, fontFamily, and fontWeight all impacting the resulting size
|
|
||||||
* @returns {any} - The width for the given text
|
|
||||||
*/
|
|
||||||
export const calculateTextWidth = function (text, config) {
|
|
||||||
config = Object.assign({ fontSize: 12, fontWeight: 400, fontFamily: 'Arial' }, config);
|
|
||||||
return calculateTextDimensions(text, config).width;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getTextObj = function () {
|
|
||||||
return {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
fill: undefined,
|
|
||||||
anchor: 'start',
|
|
||||||
style: '#666',
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
textMargin: 0,
|
|
||||||
rx: 0,
|
|
||||||
ry: 0,
|
|
||||||
valign: undefined,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds text to an element
|
|
||||||
*
|
|
||||||
* @param {SVGElement} elem Element to add text to
|
|
||||||
* @param {{
|
|
||||||
* text: string;
|
|
||||||
* x: number;
|
|
||||||
* y: number;
|
|
||||||
* anchor: 'start' | 'middle' | 'end';
|
|
||||||
* fontFamily: string;
|
|
||||||
* fontSize: string | number;
|
|
||||||
* fontWeight: string | number;
|
|
||||||
* fill: string;
|
|
||||||
* class: string | undefined;
|
|
||||||
* textMargin: number;
|
|
||||||
* }} textData
|
|
||||||
* @returns {SVGTextElement} Text element with given styling and content
|
|
||||||
*/
|
|
||||||
export const drawSimpleText = function (elem, textData) {
|
|
||||||
// Remove and ignore br:s
|
|
||||||
const nText = textData.text.replace(lineBreakRegex, ' ');
|
|
||||||
|
|
||||||
const textElem = elem.append('text');
|
|
||||||
textElem.attr('x', textData.x);
|
|
||||||
textElem.attr('y', textData.y);
|
|
||||||
textElem.style('text-anchor', textData.anchor);
|
|
||||||
textElem.style('font-family', textData.fontFamily);
|
|
||||||
textElem.style('font-size', textData.fontSize);
|
|
||||||
textElem.style('font-weight', textData.fontWeight);
|
|
||||||
textElem.attr('fill', textData.fill);
|
|
||||||
if (typeof textData.class !== 'undefined') {
|
|
||||||
textElem.attr('class', textData.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
const span = textElem.append('tspan');
|
|
||||||
span.attr('x', textData.x + textData.textMargin * 2);
|
|
||||||
span.attr('fill', textData.fill);
|
|
||||||
span.text(nText);
|
|
||||||
|
|
||||||
return textElem;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This calculates the dimensions of the given text, font size, font family, font weight, and margins.
|
|
||||||
*
|
|
||||||
* @param {any} text - The text to calculate the width of
|
|
||||||
* @param {any} config - The config for fontSize, fontFamily, fontWeight, and margin all impacting
|
|
||||||
* the resulting size
|
|
||||||
* @returns - The width for the given text
|
|
||||||
*/
|
|
||||||
export const calculateTextDimensions = memoize(
|
|
||||||
function (text, config) {
|
|
||||||
config = Object.assign({ fontSize: 12, fontWeight: 400, fontFamily: 'Arial' }, config);
|
|
||||||
const { fontSize, fontFamily, fontWeight } = config;
|
|
||||||
if (!text) {
|
|
||||||
return { width: 0, height: 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can't really know if the user supplied font family will render on the user agent;
|
|
||||||
// thus, we'll take the max width between the user supplied font family, and a default
|
|
||||||
// of sans-serif.
|
|
||||||
const fontFamilies = ['sans-serif', fontFamily];
|
|
||||||
const lines = text.split(common.lineBreakRegex);
|
|
||||||
let dims = [];
|
|
||||||
|
|
||||||
const body = select('body');
|
|
||||||
// We don't want to leak DOM elements - if a removal operation isn't available
|
|
||||||
// for any reason, do not continue.
|
|
||||||
if (!body.remove) {
|
|
||||||
return { width: 0, height: 0, lineHeight: 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
const g = body.append('svg');
|
|
||||||
|
|
||||||
for (let fontFamily of fontFamilies) {
|
|
||||||
let cheight = 0;
|
|
||||||
let dim = { width: 0, height: 0, lineHeight: 0 };
|
|
||||||
for (let line of lines) {
|
|
||||||
const textObj = getTextObj();
|
|
||||||
textObj.text = line;
|
|
||||||
const textElem = drawSimpleText(g, textObj)
|
|
||||||
.style('font-size', fontSize)
|
|
||||||
.style('font-weight', fontWeight)
|
|
||||||
.style('font-family', fontFamily);
|
|
||||||
|
|
||||||
let bBox = (textElem._groups || textElem)[0][0].getBBox();
|
|
||||||
dim.width = Math.round(Math.max(dim.width, bBox.width));
|
|
||||||
cheight = Math.round(bBox.height);
|
|
||||||
dim.height += cheight;
|
|
||||||
dim.lineHeight = Math.round(Math.max(dim.lineHeight, cheight));
|
|
||||||
}
|
|
||||||
dims.push(dim);
|
|
||||||
}
|
|
||||||
|
|
||||||
g.remove();
|
|
||||||
|
|
||||||
let index =
|
|
||||||
isNaN(dims[1].height) ||
|
|
||||||
isNaN(dims[1].width) ||
|
|
||||||
isNaN(dims[1].lineHeight) ||
|
|
||||||
(dims[0].height > dims[1].height &&
|
|
||||||
dims[0].width > dims[1].width &&
|
|
||||||
dims[0].lineHeight > dims[1].lineHeight)
|
|
||||||
? 0
|
|
||||||
: 1;
|
|
||||||
return dims[index];
|
|
||||||
},
|
|
||||||
(text, config) => `${text}-${config.fontSize}-${config.fontWeight}-${config.fontFamily}`
|
|
||||||
);
|
|
||||||
|
|
||||||
const breakString = memoize(
|
|
||||||
(word, maxWidth, hyphenCharacter = '-', config) => {
|
|
||||||
config = Object.assign(
|
|
||||||
{ fontSize: 12, fontWeight: 400, fontFamily: 'Arial', margin: 0 },
|
|
||||||
config
|
|
||||||
);
|
|
||||||
const characters = word.split('');
|
|
||||||
const lines = [];
|
|
||||||
let currentLine = '';
|
|
||||||
characters.forEach((character, index) => {
|
|
||||||
const nextLine = `${currentLine}${character}`;
|
|
||||||
const lineWidth = calculateTextWidth(nextLine, config);
|
|
||||||
if (lineWidth >= maxWidth) {
|
|
||||||
const currentCharacter = index + 1;
|
|
||||||
const isLastLine = characters.length === currentCharacter;
|
|
||||||
const hyphenatedNextLine = `${nextLine}${hyphenCharacter}`;
|
|
||||||
lines.push(isLastLine ? nextLine : hyphenatedNextLine);
|
|
||||||
currentLine = '';
|
|
||||||
} else {
|
|
||||||
currentLine = nextLine;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return { hyphenatedStrings: lines, remainingWord: currentLine };
|
|
||||||
},
|
|
||||||
(word, maxWidth, hyphenCharacter = '-', config) =>
|
|
||||||
`${word}-${maxWidth}-${hyphenCharacter}-${config.fontSize}-${config.fontWeight}-${config.fontFamily}`
|
|
||||||
);
|
|
||||||
|
|
||||||
export const wrapLabel = memoize(
|
|
||||||
(label, maxWidth, config) => {
|
|
||||||
if (!label) {
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
config = Object.assign(
|
|
||||||
{ fontSize: 12, fontWeight: 400, fontFamily: 'Arial', joinWith: '<br/>' },
|
|
||||||
config
|
|
||||||
);
|
|
||||||
if (lineBreakRegex.test(label)) {
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
const words = label.split(' ');
|
|
||||||
const completedLines = [];
|
|
||||||
let nextLine = '';
|
|
||||||
words.forEach((word, index) => {
|
|
||||||
const wordLength = calculateTextWidth(`${word} `, config);
|
|
||||||
const nextLineLength = calculateTextWidth(nextLine, config);
|
|
||||||
if (wordLength > maxWidth) {
|
|
||||||
const { hyphenatedStrings, remainingWord } = breakString(word, maxWidth, '-', config);
|
|
||||||
completedLines.push(nextLine, ...hyphenatedStrings);
|
|
||||||
nextLine = remainingWord;
|
|
||||||
} else if (nextLineLength + wordLength >= maxWidth) {
|
|
||||||
completedLines.push(nextLine);
|
|
||||||
nextLine = word;
|
|
||||||
} else {
|
|
||||||
nextLine = [nextLine, word].filter(Boolean).join(' ');
|
|
||||||
}
|
|
||||||
const currentWord = index + 1;
|
|
||||||
const isLastWord = currentWord === words.length;
|
|
||||||
if (isLastWord) {
|
|
||||||
completedLines.push(nextLine);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return completedLines.filter((line) => line !== '').join(config.joinWith);
|
|
||||||
},
|
|
||||||
(label, maxWidth, config) =>
|
|
||||||
`${label}-${maxWidth}-${config.fontSize}-${config.fontWeight}-${config.fontFamily}-${config.joinWith}`
|
|
||||||
);
|
|
26
packages/mermaid/src/diagram-api/types.ts
Normal file
26
packages/mermaid/src/diagram-api/types.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { MermaidConfig } from '../config.type';
|
||||||
|
|
||||||
|
export interface InjectUtils {
|
||||||
|
_log: any;
|
||||||
|
_setLogLevel: any;
|
||||||
|
_getConfig: any;
|
||||||
|
_sanitizeText: any;
|
||||||
|
_setupGraphViewbox: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiagramDefinition {
|
||||||
|
db: any;
|
||||||
|
renderer: any;
|
||||||
|
parser: any;
|
||||||
|
styles: any;
|
||||||
|
init?: (config: MermaidConfig) => void;
|
||||||
|
injectUtils?: (utils: InjectUtils) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DetectorRecord {
|
||||||
|
detector: DiagramDetector;
|
||||||
|
loader?: DiagramLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DiagramDetector = (text: string, config?: MermaidConfig) => boolean;
|
||||||
|
export type DiagramLoader = (() => Promise<{ id: string; diagram: DiagramDefinition }>) | null;
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const c4Detector: DiagramDetector = (txt) => {
|
export const c4Detector: DiagramDetector = (txt) => {
|
||||||
return txt.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/) !== null;
|
return txt.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/) !== null;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const classDetectorV2: DiagramDetector = (txt, config) => {
|
export const classDetectorV2: DiagramDetector = (txt, config) => {
|
||||||
// If we have confgured to use dagre-wrapper then we should return true in this function for classDiagram code thus making it use the new class diagram
|
// If we have confgured to use dagre-wrapper then we should return true in this function for classDiagram code thus making it use the new class diagram
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const classDetector: DiagramDetector = (txt, config) => {
|
export const classDetector: DiagramDetector = (txt, config) => {
|
||||||
// If we have confgured to use dagre-wrapper then we should never return true in this function
|
// If we have confgured to use dagre-wrapper then we should never return true in this function
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const erDetector: DiagramDetector = (txt) => {
|
export const erDetector: DiagramDetector = (txt) => {
|
||||||
return txt.match(/^\s*erDiagram/) !== null;
|
return txt.match(/^\s*erDiagram/) !== null;
|
||||||
|
@@ -429,8 +429,7 @@ export const clear = function (ver = 'gen-1') {
|
|||||||
vertices = {};
|
vertices = {};
|
||||||
classes = {};
|
classes = {};
|
||||||
edges = [];
|
edges = [];
|
||||||
funs = [];
|
funs = [setupToolTips];
|
||||||
funs.push(setupToolTips);
|
|
||||||
subGraphs = [];
|
subGraphs = [];
|
||||||
subGraphLookup = {};
|
subGraphLookup = {};
|
||||||
subCount = 0;
|
subCount = 0;
|
||||||
@@ -457,8 +456,8 @@ export const defaultStyle = function () {
|
|||||||
export const addSubGraph = function (_id, list, _title) {
|
export const addSubGraph = function (_id, list, _title) {
|
||||||
// console.log('addSubGraph', _id, list, _title);
|
// console.log('addSubGraph', _id, list, _title);
|
||||||
let id = _id.trim();
|
let id = _id.trim();
|
||||||
let title = _title;
|
let title = _title.trim();
|
||||||
if (_id === _title && _title.match(/\s/)) {
|
if (id === title && title.match(/\s/)) {
|
||||||
id = undefined;
|
id = undefined;
|
||||||
}
|
}
|
||||||
/** @param a */
|
/** @param a */
|
||||||
@@ -675,6 +674,10 @@ const destructEndLink = (_str) => {
|
|||||||
stroke = 'thick';
|
stroke = 'thick';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line[0] === '~') {
|
||||||
|
stroke = 'invisible';
|
||||||
|
}
|
||||||
|
|
||||||
let dots = countChar('.', line);
|
let dots = countChar('.', line);
|
||||||
|
|
||||||
if (dots) {
|
if (dots) {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const flowDetectorV2: DiagramDetector = (txt, config) => {
|
export const flowDetectorV2: DiagramDetector = (txt, config) => {
|
||||||
// If we have confgured to use dagre-wrapper then we should return true in this function for graph code thus making it use the new flowchart diagram
|
// If we have confgured to use dagre-wrapper then we should return true in this function for graph code thus making it use the new flowchart diagram
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const flowDetector: DiagramDetector = (txt, config) => {
|
export const flowDetector: DiagramDetector = (txt, config) => {
|
||||||
// If we have confired to only use new flow charts this function shohuld always return false
|
// If we have confired to only use new flow charts this function shohuld always return false
|
||||||
|
@@ -280,6 +280,11 @@ export const addEdges = function (edges, g, diagObj) {
|
|||||||
edgeData.pattern = 'solid';
|
edgeData.pattern = 'solid';
|
||||||
edgeData.style = 'stroke-width: 3.5px;fill:none;';
|
edgeData.style = 'stroke-width: 3.5px;fill:none;';
|
||||||
break;
|
break;
|
||||||
|
case 'invisible':
|
||||||
|
edgeData.thickness = 'invisible';
|
||||||
|
edgeData.pattern = 'solid';
|
||||||
|
edgeData.style = 'stroke-width: 0;fill:none;';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (typeof edge.style !== 'undefined') {
|
if (typeof edge.style !== 'undefined') {
|
||||||
const styles = getStylesFromArray(edge.style);
|
const styles = getStylesFromArray(edge.style);
|
||||||
|
@@ -120,6 +120,7 @@ that id.
|
|||||||
\s*[xo<]?\-\-+[-xo>]\s* return 'LINK';
|
\s*[xo<]?\-\-+[-xo>]\s* return 'LINK';
|
||||||
\s*[xo<]?\=\=+[=xo>]\s* return 'LINK';
|
\s*[xo<]?\=\=+[=xo>]\s* return 'LINK';
|
||||||
\s*[xo<]?\-?\.+\-[xo>]?\s* return 'LINK';
|
\s*[xo<]?\-?\.+\-[xo>]?\s* return 'LINK';
|
||||||
|
\s*\~\~[\~]+\s* return 'LINK';
|
||||||
\s*[xo<]?\-\-\s* return 'START_LINK';
|
\s*[xo<]?\-\-\s* return 'START_LINK';
|
||||||
\s*[xo<]?\=\=\s* return 'START_LINK';
|
\s*[xo<]?\=\=\s* return 'START_LINK';
|
||||||
\s*[xo<]?\-\.\s* return 'START_LINK';
|
\s*[xo<]?\-\.\s* return 'START_LINK';
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const ganttDetector: DiagramDetector = (txt) => {
|
export const ganttDetector: DiagramDetector = (txt) => {
|
||||||
return txt.match(/^\s*gantt/) !== null;
|
return txt.match(/^\s*gantt/) !== null;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const gitGraphDetector: DiagramDetector = (txt) => {
|
export const gitGraphDetector: DiagramDetector = (txt) => {
|
||||||
return txt.match(/^\s*gitGraph/) !== null;
|
return txt.match(/^\s*gitGraph/) !== null;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const infoDetector: DiagramDetector = (txt) => {
|
export const infoDetector: DiagramDetector = (txt) => {
|
||||||
return txt.match(/^\s*info/) !== null;
|
return txt.match(/^\s*info/) !== null;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const pieDetector: DiagramDetector = (txt) => {
|
export const pieDetector: DiagramDetector = (txt) => {
|
||||||
return txt.match(/^\s*pie/) !== null;
|
return txt.match(/^\s*pie/) !== null;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const requirementDetector: DiagramDetector = (txt) => {
|
export const requirementDetector: DiagramDetector = (txt) => {
|
||||||
return txt.match(/^\s*requirement(Diagram)?/) !== null;
|
return txt.match(/^\s*requirement(Diagram)?/) !== null;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const sequenceDetector: DiagramDetector = (txt) => {
|
export const sequenceDetector: DiagramDetector = (txt) => {
|
||||||
return txt.match(/^\s*sequenceDiagram/) !== null;
|
return txt.match(/^\s*sequenceDiagram/) !== null;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/detectType';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const stateDetectorV2: DiagramDetector = (text, config) => {
|
export const stateDetectorV2: DiagramDetector = (text, config) => {
|
||||||
if (text.match(/^\s*stateDiagram-v2/) !== null) return true;
|
if (text.match(/^\s*stateDiagram-v2/) !== null) return true;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user