Merge branch 'develop' into kh-user-journey

This commit is contained in:
Knut Sveidqvist 2022-04-12 07:36:33 +02:00 committed by GitHub
commit cda21c50ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 3726 additions and 2119 deletions

View File

@ -30,7 +30,7 @@ jobs:
run: yarn build
- name: Upload Build as Artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: dist
path: dist

View File

@ -42,7 +42,7 @@ jobs:
- name: Run E2E Tests
run: yarn e2e
env:
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
# PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
CYPRESS_CACHE_FOLDER: .cache/Cypress
#- name: Post Upload Test Results

View File

@ -2,7 +2,7 @@
So you want to help? That's great!
![Image of happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif)
![Happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif)
Here are a few things to know to get you started on the right path.
@ -76,7 +76,7 @@ This is important so that, if someone else does a change to the grammar that doe
### **Add e2e tests**
This tests the rendering and visual apearance of the diagram. This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks!
This tests the rendering and visual appearance of the diagram. This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks!
To start working with the e2e tests, run `yarn dev` to start the dev server, after that start cypress by running `cypress open` in the mermaid folder. (Make sure you have path to cypress in order, the binary is located in node_modules/.bin).
@ -123,4 +123,4 @@ Don't get daunted if it is hard in the beginning. We have a great community with
[Join our slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
![Image of superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)
![A superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)

View File

@ -2,13 +2,13 @@
English | [简体中文](./README.zh-CN.md)
![banner](./img/header.png)
<img src="./img/header.png" alt="" />
:trophy: **Mermaid was nominated and won the [JS Open Source Awards (2019)](https://osawards.com/javascript/2019) in the category "The most exciting use of technology"!!!**
**Thanks to all involved, people committing pull requests, people answering questions! 🙏**
<a href="https://mermaid-js.github.io/mermaid/landing/" alt="Link to landing page for the book The Official Guide To mermaid.js"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/img/book-banner-post-release.jpg"></a>
<a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
## About
@ -36,10 +36,12 @@ For a more detailed introduction to Mermaid and some of its more basic uses, loo
__The following are some examples of the diagrams, charts and graphs that can be made using Mermaid. Click here jump into the [text syntax](https://mermaid-js.github.io/mermaid/#/n00b-syntaxReference).__
<!-- <Flowchart> -->
## Flowchart [<a href="https://mermaid-js.github.io/mermaid/#/flowchart">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0hhcmRdIC0tPnxUZXh0fCBCKFJvdW5kKVxuICAgIEIgLS0-IEN7RGVjaXNpb259XG4gICAgQyAtLT58T25lfCBEW1Jlc3VsdCAxXVxuICAgIEMgLS0-fFR3b3wgRVtSZXN1bHQgMl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
### Flowchart [<a href="https://mermaid-js.github.io/mermaid/#/flowchart">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0hhcmRdIC0tPnxUZXh0fCBCKFJvdW5kKVxuICAgIEIgLS0-IEN7RGVjaXNpb259XG4gICAgQyAtLT58T25lfCBEW1Jlc3VsdCAxXVxuICAgIEMgLS0-fFR3b3wgRVtSZXN1bHQgMl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
```
flowchart LR
title Example flow chart
accDescripton Flow chart showing examples of node usage
A[Hard] -->|Text| B(Round)
B --> C{Decision}
C -->|One| D[Result 1]
@ -47,6 +49,8 @@ C -->|Two| E[Result 2]
```
```mermaid
flowchart LR
title Example flow chart
accDescripton Flow chart showing examples of node usage
A[Hard] -->|Text| B(Round)
B --> C{Decision}
C -->|One| D[Result 1]
@ -54,7 +58,7 @@ C -->|Two| E[Result 2]
```
## Sequence diagram [<a href="https://mermaid-js.github.io/mermaid/#/sequenceDiagram">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5BbGljZS0-PkpvaG46IEhlbGxvIEpvaG4sIGhvdyBhcmUgeW91P1xubG9vcCBIZWFsdGhjaGVja1xuICAgIEpvaG4tPj5Kb2huOiBGaWdodCBhZ2FpbnN0IGh5cG9jaG9uZHJpYVxuZW5kXG5Ob3RlIHJpZ2h0IG9mIEpvaG46IFJhdGlvbmFsIHRob3VnaHRzIVxuSm9obi0tPj5BbGljZTogR3JlYXQhXG5Kb2huLT4-Qm9iOiBIb3cgYWJvdXQgeW91P1xuQm9iLS0-PkpvaG46IEpvbGx5IGdvb2QhIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
### Sequence diagram [<a href="https://mermaid-js.github.io/mermaid/#/sequenceDiagram">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5BbGljZS0-PkpvaG46IEhlbGxvIEpvaG4sIGhvdyBhcmUgeW91P1xubG9vcCBIZWFsdGhjaGVja1xuICAgIEpvaG4tPj5Kb2huOiBGaWdodCBhZ2FpbnN0IGh5cG9jaG9uZHJpYVxuZW5kXG5Ob3RlIHJpZ2h0IG9mIEpvaG46IFJhdGlvbmFsIHRob3VnaHRzIVxuSm9obi0tPj5BbGljZTogR3JlYXQhXG5Kb2huLT4-Qm9iOiBIb3cgYWJvdXQgeW91P1xuQm9iLS0-PkpvaG46IEpvbGx5IGdvb2QhIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
```
sequenceDiagram
@ -79,7 +83,7 @@ John->>Bob: How about you?
Bob-->>John: Jolly good!
```
## Gantt chart [<a href="https://mermaid-js.github.io/mermaid/#/gantt">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2FudHRcbnNlY3Rpb24gU2VjdGlvblxuQ29tcGxldGVkIDpkb25lLCAgICBkZXMxLCAyMDE0LTAxLTA2LDIwMTQtMDEtMDhcbkFjdGl2ZSAgICAgICAgOmFjdGl2ZSwgIGRlczIsIDIwMTQtMDEtMDcsIDNkXG5QYXJhbGxlbCAxICAgOiAgICAgICAgIGRlczMsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAyICAgOiAgICAgICAgIGRlczQsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAzICAgOiAgICAgICAgIGRlczUsIGFmdGVyIGRlczMsIDFkXG5QYXJhbGxlbCA0ICAgOiAgICAgICAgIGRlczYsIGFmdGVyIGRlczQsIDFkIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
### Gantt chart [<a href="https://mermaid-js.github.io/mermaid/#/gantt">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2FudHRcbnNlY3Rpb24gU2VjdGlvblxuQ29tcGxldGVkIDpkb25lLCAgICBkZXMxLCAyMDE0LTAxLTA2LDIwMTQtMDEtMDhcbkFjdGl2ZSAgICAgICAgOmFjdGl2ZSwgIGRlczIsIDIwMTQtMDEtMDcsIDNkXG5QYXJhbGxlbCAxICAgOiAgICAgICAgIGRlczMsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAyICAgOiAgICAgICAgIGRlczQsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAzICAgOiAgICAgICAgIGRlczUsIGFmdGVyIGRlczMsIDFkXG5QYXJhbGxlbCA0ICAgOiAgICAgICAgIGRlczYsIGFmdGVyIGRlczQsIDFkIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
```
gantt
@ -102,7 +106,7 @@ gantt
Parallel 4 : des6, after des4, 1d
```
## Class diagram [<a href="https://mermaid-js.github.io/mermaid/#/classDiagram">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiY2xhc3NEaWFncmFtXG5DbGFzczAxIDx8LS0gQXZlcnlMb25nQ2xhc3MgOiBDb29sXG48PGludGVyZmFjZT4-IENsYXNzMDFcbkNsYXNzMDkgLS0-IEMyIDogV2hlcmUgYW0gaT9cbkNsYXNzMDkgLS0qIEMzXG5DbGFzczA5IC0tfD4gQ2xhc3MwN1xuQ2xhc3MwNyA6IGVxdWFscygpXG5DbGFzczA3IDogT2JqZWN0W10gZWxlbWVudERhdGFcbkNsYXNzMDEgOiBzaXplKClcbkNsYXNzMDEgOiBpbnQgY2hpbXBcbkNsYXNzMDEgOiBpbnQgZ29yaWxsYVxuY2xhc3MgQ2xhc3MxMCB7XG4gID4-c2VydmljZT4-XG4gIGludCBpZFxuICBzaXplKClcbn0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
### Class diagram [<a href="https://mermaid-js.github.io/mermaid/#/classDiagram">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiY2xhc3NEaWFncmFtXG5DbGFzczAxIDx8LS0gQXZlcnlMb25nQ2xhc3MgOiBDb29sXG48PGludGVyZmFjZT4-IENsYXNzMDFcbkNsYXNzMDkgLS0-IEMyIDogV2hlcmUgYW0gaT9cbkNsYXNzMDkgLS0qIEMzXG5DbGFzczA5IC0tfD4gQ2xhc3MwN1xuQ2xhc3MwNyA6IGVxdWFscygpXG5DbGFzczA3IDogT2JqZWN0W10gZWxlbWVudERhdGFcbkNsYXNzMDEgOiBzaXplKClcbkNsYXNzMDEgOiBpbnQgY2hpbXBcbkNsYXNzMDEgOiBpbnQgZ29yaWxsYVxuY2xhc3MgQ2xhc3MxMCB7XG4gID4-c2VydmljZT4-XG4gIGludCBpZFxuICBzaXplKClcbn0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
```
classDiagram
@ -141,7 +145,7 @@ class Class10 {
}
```
## State diagram [<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtLXYyXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQiLCJ0aGVtZVZhcmlhYmxlcyI6eyJiYWNrZ3JvdW5kIjoid2hpdGUiLCJwcmltYXJ5Q29sb3IiOiIjRUNFQ0ZGIiwic2Vjb25kYXJ5Q29sb3IiOiIjZmZmZmRlIiwidGVydGlhcnlDb2xvciI6ImhzbCg4MCwgMTAwJSwgOTYuMjc0NTA5ODAzOSUpIiwicHJpbWFyeUJvcmRlckNvbG9yIjoiaHNsKDI0MCwgNjAlLCA4Ni4yNzQ1MDk4MDM5JSkiLCJzZWNvbmRhcnlCb3JkZXJDb2xvciI6ImhzbCg2MCwgNjAlLCA4My41Mjk0MTE3NjQ3JSkiLCJ0ZXJ0aWFyeUJvcmRlckNvbG9yIjoiaHNsKDgwLCA2MCUsIDg2LjI3NDUwOTgwMzklKSIsInByaW1hcnlUZXh0Q29sb3IiOiIjMTMxMzAwIiwic2Vjb25kYXJ5VGV4dENvbG9yIjoiIzAwMDAyMSIsInRlcnRpYXJ5VGV4dENvbG9yIjoicmdiKDkuNTAwMDAwMDAwMSwgOS41MDAwMDAwMDAxLCA5LjUwMDAwMDAwMDEpIiwibGluZUNvbG9yIjoiIzMzMzMzMyIsInRleHRDb2xvciI6IiMzMzMiLCJtYWluQmtnIjoiI0VDRUNGRiIsInNlY29uZEJrZyI6IiNmZmZmZGUiLCJib3JkZXIxIjoiIzkzNzBEQiIsImJvcmRlcjIiOiIjYWFhYTMzIiwiYXJyb3doZWFkQ29sb3IiOiIjMzMzMzMzIiwiZm9udEZhbWlseSI6IlwidHJlYnVjaGV0IG1zXCIsIHZlcmRhbmEsIGFyaWFsIiwiZm9udFNpemUiOiIxNnB4IiwibGFiZWxCYWNrZ3JvdW5kIjoiI2U4ZThlOCIsIm5vZGVCa2ciOiIjRUNFQ0ZGIiwibm9kZUJvcmRlciI6IiM5MzcwREIiLCJjbHVzdGVyQmtnIjoiI2ZmZmZkZSIsImNsdXN0ZXJCb3JkZXIiOiIjYWFhYTMzIiwiZGVmYXVsdExpbmtDb2xvciI6IiMzMzMzMzMiLCJ0aXRsZUNvbG9yIjoiIzMzMyIsImVkZ2VMYWJlbEJhY2tncm91bmQiOiIjZThlOGU4IiwiYWN0b3JCb3JkZXIiOiJoc2woMjU5LjYyNjE2ODIyNDMsIDU5Ljc3NjUzNjMxMjglLCA4Ny45MDE5NjA3ODQzJSkiLCJhY3RvckJrZyI6IiNFQ0VDRkYiLCJhY3RvclRleHRDb2xvciI6ImJsYWNrIiwiYWN0b3JMaW5lQ29sb3IiOiJncmV5Iiwic2lnbmFsQ29sb3IiOiIjMzMzIiwic2lnbmFsVGV4dENvbG9yIjoiIzMzMyIsImxhYmVsQm94QmtnQ29sb3IiOiIjRUNFQ0ZGIiwibGFiZWxCb3hCb3JkZXJDb2xvciI6ImhzbCgyNTkuNjI2MTY4MjI0MywgNTkuNzc2NTM2MzEyOCUsIDg3LjkwMTk2MDc4NDMlKSIsImxhYmVsVGV4dENvbG9yIjoiYmxhY2siLCJsb29wVGV4dENvbG9yIjoiYmxhY2siLCJub3RlQm9yZGVyQ29sb3IiOiIjYWFhYTMzIiwibm90ZUJrZ0NvbG9yIjoiI2ZmZjVhZCIsIm5vdGVUZXh0Q29sb3IiOiJibGFjayIsImFjdGl2YXRpb25Cb3JkZXJDb2xvciI6IiM2NjYiLCJhY3RpdmF0aW9uQmtnQ29sb3IiOiIjZjRmNGY0Iiwic2VxdWVuY2VOdW1iZXJDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yIjoicmdiYSgxMDIsIDEwMiwgMjU1LCAwLjQ5KSIsImFsdFNlY3Rpb25Ca2dDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yMiI6IiNmZmY0MDAiLCJ0YXNrQm9yZGVyQ29sb3IiOiIjNTM0ZmJjIiwidGFza0JrZ0NvbG9yIjoiIzhhOTBkZCIsInRhc2tUZXh0TGlnaHRDb2xvciI6IndoaXRlIiwidGFza1RleHRDb2xvciI6IndoaXRlIiwidGFza1RleHREYXJrQ29sb3IiOiJibGFjayIsInRhc2tUZXh0T3V0c2lkZUNvbG9yIjoiYmxhY2siLCJ0YXNrVGV4dENsaWNrYWJsZUNvbG9yIjoiIzAwMzE2MyIsImFjdGl2ZVRhc2tCb3JkZXJDb2xvciI6IiM1MzRmYmMiLCJhY3RpdmVUYXNrQmtnQ29sb3IiOiIjYmZjN2ZmIiwiZ3JpZENvbG9yIjoibGlnaHRncmV5IiwiZG9uZVRhc2tCa2dDb2xvciI6ImxpZ2h0Z3JleSIsImRvbmVUYXNrQm9yZGVyQ29sb3IiOiJncmV5IiwiY3JpdEJvcmRlckNvbG9yIjoiI2ZmODg4OCIsImNyaXRCa2dDb2xvciI6InJlZCIsInRvZGF5TGluZUNvbG9yIjoicmVkIiwibGFiZWxDb2xvciI6ImJsYWNrIiwiZXJyb3JCa2dDb2xvciI6IiM1NTIyMjIiLCJlcnJvclRleHRDb2xvciI6IiM1NTIyMjIiLCJjbGFzc1RleHQiOiIjMTMxMzAwIiwiZmlsbFR5cGUwIjoiI0VDRUNGRiIsImZpbGxUeXBlMSI6IiNmZmZmZGUiLCJmaWxsVHlwZTIiOiJoc2woMzA0LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTMiOiJoc2woMTI0LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkiLCJmaWxsVHlwZTQiOiJoc2woMTc2LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTUiOiJoc2woLTQsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSIsImZpbGxUeXBlNiI6ImhzbCg4LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTciOiJoc2woMTg4LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkifX0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9">live editor</a>]
### State diagram [<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtLXYyXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQiLCJ0aGVtZVZhcmlhYmxlcyI6eyJiYWNrZ3JvdW5kIjoid2hpdGUiLCJwcmltYXJ5Q29sb3IiOiIjRUNFQ0ZGIiwic2Vjb25kYXJ5Q29sb3IiOiIjZmZmZmRlIiwidGVydGlhcnlDb2xvciI6ImhzbCg4MCwgMTAwJSwgOTYuMjc0NTA5ODAzOSUpIiwicHJpbWFyeUJvcmRlckNvbG9yIjoiaHNsKDI0MCwgNjAlLCA4Ni4yNzQ1MDk4MDM5JSkiLCJzZWNvbmRhcnlCb3JkZXJDb2xvciI6ImhzbCg2MCwgNjAlLCA4My41Mjk0MTE3NjQ3JSkiLCJ0ZXJ0aWFyeUJvcmRlckNvbG9yIjoiaHNsKDgwLCA2MCUsIDg2LjI3NDUwOTgwMzklKSIsInByaW1hcnlUZXh0Q29sb3IiOiIjMTMxMzAwIiwic2Vjb25kYXJ5VGV4dENvbG9yIjoiIzAwMDAyMSIsInRlcnRpYXJ5VGV4dENvbG9yIjoicmdiKDkuNTAwMDAwMDAwMSwgOS41MDAwMDAwMDAxLCA5LjUwMDAwMDAwMDEpIiwibGluZUNvbG9yIjoiIzMzMzMzMyIsInRleHRDb2xvciI6IiMzMzMiLCJtYWluQmtnIjoiI0VDRUNGRiIsInNlY29uZEJrZyI6IiNmZmZmZGUiLCJib3JkZXIxIjoiIzkzNzBEQiIsImJvcmRlcjIiOiIjYWFhYTMzIiwiYXJyb3doZWFkQ29sb3IiOiIjMzMzMzMzIiwiZm9udEZhbWlseSI6IlwidHJlYnVjaGV0IG1zXCIsIHZlcmRhbmEsIGFyaWFsIiwiZm9udFNpemUiOiIxNnB4IiwibGFiZWxCYWNrZ3JvdW5kIjoiI2U4ZThlOCIsIm5vZGVCa2ciOiIjRUNFQ0ZGIiwibm9kZUJvcmRlciI6IiM5MzcwREIiLCJjbHVzdGVyQmtnIjoiI2ZmZmZkZSIsImNsdXN0ZXJCb3JkZXIiOiIjYWFhYTMzIiwiZGVmYXVsdExpbmtDb2xvciI6IiMzMzMzMzMiLCJ0aXRsZUNvbG9yIjoiIzMzMyIsImVkZ2VMYWJlbEJhY2tncm91bmQiOiIjZThlOGU4IiwiYWN0b3JCb3JkZXIiOiJoc2woMjU5LjYyNjE2ODIyNDMsIDU5Ljc3NjUzNjMxMjglLCA4Ny45MDE5NjA3ODQzJSkiLCJhY3RvckJrZyI6IiNFQ0VDRkYiLCJhY3RvclRleHRDb2xvciI6ImJsYWNrIiwiYWN0b3JMaW5lQ29sb3IiOiJncmV5Iiwic2lnbmFsQ29sb3IiOiIjMzMzIiwic2lnbmFsVGV4dENvbG9yIjoiIzMzMyIsImxhYmVsQm94QmtnQ29sb3IiOiIjRUNFQ0ZGIiwibGFiZWxCb3hCb3JkZXJDb2xvciI6ImhzbCgyNTkuNjI2MTY4MjI0MywgNTkuNzc2NTM2MzEyOCUsIDg3LjkwMTk2MDc4NDMlKSIsImxhYmVsVGV4dENvbG9yIjoiYmxhY2siLCJsb29wVGV4dENvbG9yIjoiYmxhY2siLCJub3RlQm9yZGVyQ29sb3IiOiIjYWFhYTMzIiwibm90ZUJrZ0NvbG9yIjoiI2ZmZjVhZCIsIm5vdGVUZXh0Q29sb3IiOiJibGFjayIsImFjdGl2YXRpb25Cb3JkZXJDb2xvciI6IiM2NjYiLCJhY3RpdmF0aW9uQmtnQ29sb3IiOiIjZjRmNGY0Iiwic2VxdWVuY2VOdW1iZXJDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yIjoicmdiYSgxMDIsIDEwMiwgMjU1LCAwLjQ5KSIsImFsdFNlY3Rpb25Ca2dDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yMiI6IiNmZmY0MDAiLCJ0YXNrQm9yZGVyQ29sb3IiOiIjNTM0ZmJjIiwidGFza0JrZ0NvbG9yIjoiIzhhOTBkZCIsInRhc2tUZXh0TGlnaHRDb2xvciI6IndoaXRlIiwidGFza1RleHRDb2xvciI6IndoaXRlIiwidGFza1RleHREYXJrQ29sb3IiOiJibGFjayIsInRhc2tUZXh0T3V0c2lkZUNvbG9yIjoiYmxhY2siLCJ0YXNrVGV4dENsaWNrYWJsZUNvbG9yIjoiIzAwMzE2MyIsImFjdGl2ZVRhc2tCb3JkZXJDb2xvciI6IiM1MzRmYmMiLCJhY3RpdmVUYXNrQmtnQ29sb3IiOiIjYmZjN2ZmIiwiZ3JpZENvbG9yIjoibGlnaHRncmV5IiwiZG9uZVRhc2tCa2dDb2xvciI6ImxpZ2h0Z3JleSIsImRvbmVUYXNrQm9yZGVyQ29sb3IiOiJncmV5IiwiY3JpdEJvcmRlckNvbG9yIjoiI2ZmODg4OCIsImNyaXRCa2dDb2xvciI6InJlZCIsInRvZGF5TGluZUNvbG9yIjoicmVkIiwibGFiZWxDb2xvciI6ImJsYWNrIiwiZXJyb3JCa2dDb2xvciI6IiM1NTIyMjIiLCJlcnJvclRleHRDb2xvciI6IiM1NTIyMjIiLCJjbGFzc1RleHQiOiIjMTMxMzAwIiwiZmlsbFR5cGUwIjoiI0VDRUNGRiIsImZpbGxUeXBlMSI6IiNmZmZmZGUiLCJmaWxsVHlwZTIiOiJoc2woMzA0LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTMiOiJoc2woMTI0LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkiLCJmaWxsVHlwZTQiOiJoc2woMTc2LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTUiOiJoc2woLTQsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSIsImZpbGxUeXBlNiI6ImhzbCg4LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTciOiJoc2woMTg4LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkifX0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9">live editor</a>]
```
stateDiagram-v2
[*] --> Still
@ -176,9 +180,9 @@ pie
"Rats" : 15
```
## Git graph [experimental - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2l0R3JhcGg6XG5vcHRpb25zXG57XG4gICAgXCJub2RlU3BhY2luZ1wiOiAxNTAsXG4gICAgXCJub2RlUmFkaXVzXCI6IDEwXG59XG5lbmRcbmNvbW1pdFxuYnJhbmNoIG5ld2JyYW5jaFxuY2hlY2tvdXQgbmV3YnJhbmNoXG5jb21taXRcbmNvbW1pdFxuY2hlY2tvdXQgbWFzdGVyXG5jb21taXRcbmNvbW1pdFxubWVyZ2UgbmV3YnJhbmNoXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
### Git graph [experimental - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2l0R3JhcGg6XG5vcHRpb25zXG57XG4gICAgXCJub2RlU3BhY2luZ1wiOiAxNTAsXG4gICAgXCJub2RlUmFkaXVzXCI6IDEwXG59XG5lbmRcbmNvbW1pdFxuYnJhbmNoIG5ld2JyYW5jaFxuY2hlY2tvdXQgbmV3YnJhbmNoXG5jb21taXRcbmNvbW1pdFxuY2hlY2tvdXQgbWFzdGVyXG5jb21taXRcbmNvbW1pdFxubWVyZ2UgbmV3YnJhbmNoXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
## User Journey diagram [<a href="https://mermaid-js.github.io/mermaid/#/user-journey">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
### User Journey diagram [<a href="https://mermaid-js.github.io/mermaid/#/user-journey">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
```
journey
title My working day
@ -202,7 +206,7 @@ pie
Sit down: 3: Me
```
### Release
## Release
For those who have the permission to do so:

View File

@ -291,4 +291,36 @@ describe('Gantt diagram', () => {
{ gantt: { topAxis: true } }
);
});
it('should render accessibility tags', function () {
const expectedTitle = 'Gantt Diagram';
const expectedAccDescription = 'Tasks for Q4';
renderGraph(
`
gantt
title ${expectedTitle}
accDescription ${expectedAccDescription}
dateFormat YYYY-MM-DD
section Section
A task :a1, 2014-01-01, 30d
`,
{}
);
cy.get('svg').should((svg) => {
const el = svg.get(0);
const children = Array.from(el.children);
const titleEl = children.find(function (node) {
return node.tagName === 'title';
});
const descriptionEl = children.find(function (node) {
return node.tagName === 'desc';
});
expect(titleEl).to.exist;
expect(titleEl.textContent).to.equal(expectedTitle);
expect(descriptionEl).to.exist;
expect(descriptionEl.textContent).to.equal(expectedAccDescription);
});
});
});

View File

@ -46,4 +46,69 @@ describe('Requirement diagram', () => {
);
cy.get('svg');
});
it('should render accessibility tags', function () {
const expectedTitle = 'Gantt Diagram';
const expectedAccDescription = 'Tasks for Q4';
renderGraph(
`
requirementDiagram
title: ${expectedTitle}
accDescription: ${expectedAccDescription}
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
functionalRequirement test_req2 {
id: 1.1
text: the second test text.
risk: low
verifymethod: inspection
}
performanceRequirement test_req3 {
id: 1.2
text: the third test text.
risk: medium
verifymethod: demonstration
}
element test_entity {
type: simulation
}
element test_entity2 {
type: word doc
docRef: reqs/test_entity
}
test_entity - satisfies -> test_req2
test_req - traces -> test_req2
test_req - contains -> test_req3
test_req <- copies - test_entity2
`,
{}
);
cy.get('svg').should((svg) => {
const el = svg.get(0);
const children = Array.from(el.children);
const titleEl = children.find(function (node) {
return node.tagName === 'title';
});
const descriptionEl = children.find(function (node) {
return node.tagName === 'desc';
});
expect(titleEl).to.exist;
expect(titleEl.textContent).to.equal(expectedTitle);
expect(descriptionEl).to.exist;
expect(descriptionEl.textContent).to.equal(expectedAccDescription);
});
});
});

View File

@ -26,24 +26,28 @@
</head>
<body>
<h1>info below</h1>
<div class="mermaid2" style="width: 100%; height: 20%;">
%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%%
<div class="mermaid" style="width: 100%; height: 20%;">
%%{init: { "logLevel": "debug", "theme": "default" , "gitGraph" : {"showBranches":"false"},"themeVariables": {
"gitBranchLabel0": "#ff0000",
"gitBranchLabel1": "#00ff00",
"gitBranchLabel2": "#0000ff",
"git0": "#550055"
} } }%%
gitGraph
commit "Ashish"
branch newbranch
checkout newbranch
commit id:"1111"
commit tag:"test"
commit
branch develop
commit tag:"v1.0.0"
commit
checkout main
commit type: HIGHLIGHT
commit
merge newbranch
merge develop
commit
branch b2
branch featureA
commit
</div>
<div class="mermaid" style="width: 100%; height: 20%;">
<div class="mermaid2" style="width: 100%; height: 20%;">
gitGraph
commit type:HIGHLIGHT
branch hotfix
@ -101,18 +105,19 @@
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'dark',
// themeVariables: {
// primaryColor: '#9400D3',
// darkMode: true,
// background: '#222',
// // textColor: 'white',
// // primaryTextColor: '#f4f4f4',
//theme: 'dark',
themeVariables: {
commitLabelColor: '#9400D3',
commitLabelBackground: '#FFFFFF',
// darkMode: true,
// background: '#222',
// // textColor: 'white',
// // primaryTextColor: '#f4f4f4',
// // // nodeBkg: '#ff0000',
// // // mainBkg: '#0000ff',
// // // tertiaryColor: '#ffffcc',
// },
// // // nodeBkg: '#ff0000',
// // // mainBkg: '#0000ff',
// // // tertiaryColor: '#ffffcc',
},
// theme: 'forest',
// theme: 'neutral',
// theme: 'dark',

View File

@ -9,7 +9,7 @@
<style>
body {
/* background: rgb(221, 208, 208); */
background:#111;
/* background:#111; */
/* background:#333; */
font-family: 'Arial';
}
@ -43,6 +43,7 @@
</div>
<div class="mermaid" style="width: 100%; height: 20%;">
%%{init: { "gitGraph": { "showBranches": true, "mainBranchName": "APA" }}}%%
gitGraph
commit
branch hotfix
@ -54,14 +55,14 @@
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout APA
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
checkout APA
merge hotfix
checkout featureB
commit
@ -79,10 +80,10 @@
branch release
checkout release
commit
checkout main
checkout APA
commit
checkout release
merge main
merge APA
checkout develop
merge release
@ -101,7 +102,7 @@
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'dark',
theme: 'default',
themeVariables: {
// primaryColor: '#9400D3',
// darkMode: false,
@ -119,6 +120,7 @@
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 1,
flowchart: { curve: 'linear', htmlLabels: true },
// gitGraph: { showCommitLabel: false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated

62
demos/classchart.html Normal file
View File

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
/* font-family: 'trebuchet ms', verdana, arial; */
font-family: 'Courier New', Courier, monospace !important;
}
</style>
</head>
<body>
<div class="mermaid">
classDiagram
title Animal Diagram
accDescription The animal class diagram
Animal <|-- Duck
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
logLevel: 3,
securityLevel: 'loose',
flowchart: { curve: 'basis' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>
</body>
</html>

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<title>Mermaid Quick Flowchart Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
@ -220,6 +220,8 @@
<h3>graph</h3>
<div class="mermaid">
graph TD
title What to buy
accDescription Options of what to buy with Christmas money
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me thinksssssx<br/>sssssssssssssssssssuuu<br />tttsssssssssssssssssssssss}
C -->|One| D[Laptop]
@ -230,8 +232,8 @@
<h3>flowchart</h3>
<div class="mermaid">
flowchart TD
title Christmas
accDescription Get money
title What to buy
accDescription Options of what to buy with Christmas money
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me thinksssssx<br/>sssssssssssssssssssuuu<br />tttsssssssssssssssssssssss}
C -->|One| D[Laptop]

43
demos/gantt.html Normal file
View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
font-family: 'Courier New', Courier, monospace !important;
}
</style>
</head>
<body>
<!-- accDescription Tasks for Q4 -->
<div class="mermaid">
gantt
title A Gantt Diagram
accDescription Remaining Q4 Tasks
dateFormat YYYY-MM-DD
section Section
A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2014-01-12 , 12d
another task : 24d
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
logLevel: 3,
securityLevel: 'loose',
gantt: { axisFormat: '%m/%d/%Y' },
});
</script>
</body>
</html>

View File

@ -680,6 +680,7 @@
<div class="mermaid">
stateDiagram
accDescription This is a state diagram showing one state
State1
</div>
@ -872,4 +873,4 @@
</script>
</body>
</html>
</html>

106
demos/requirements.html Normal file
View File

@ -0,0 +1,106 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
/* font-family: 'trebuchet ms', verdana, arial; */
font-family: 'Courier New', Courier, monospace !important;
}
</style>
</head>
<body>
<div class="mermaid">
requirementDiagram
title This is a title
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
functionalRequirement test_req2 {
id: 1.1
text: the second test text.
risk: low
verifymethod: inspection
}
performanceRequirement test_req3 {
id: 1.2
text: the third test text.
risk: medium
verifymethod: demonstration
}
interfaceRequirement test_req4 {
id: 1.2.1
text: the fourth test text.
risk: medium
verifymethod: analysis
}
physicalRequirement test_req5 {
id: 1.2.2
text: the fifth test text.
risk: medium
verifymethod: analysis
}
designConstraint test_req6 {
id: 1.2.3
text: the sixth test text.
risk: medium
verifymethod: analysis
}
element test_entity {
type: simulation
}
element test_entity2 {
type: word doc
docRef: reqs/test_entity
}
element test_entity3 {
type: "test suite"
docRef: github.com/all_the_tests
}
test_entity - satisfies -> test_req2
test_req - traces -> test_req2
test_req - contains -> test_req3
test_req3 - contains -> test_req4
test_req4 - derives -> test_req5
test_req5 - refines -> test_req6
test_entity3 - verifies -> test_req5
test_req <- copies - test_entity2
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
logLevel: 3,
securityLevel: 'loose',
flowchart: { curve: 'basis' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>
</body>
</html>

View File

@ -40,7 +40,8 @@
Note over John: After a few more moments, John<br />finally snaps out of it.
end
alt either this
Alice->>John: Yes
Alice->>+John: Yes
John-->>-Alice: OK
else or this
Alice->>John: No
else or this will happen
@ -69,4 +70,4 @@
</body>
</html>
</html>

50
demos/state.html Normal file
View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
/* font-family: 'trebuchet ms', verdana, arial; */
font-family: 'Courier New', Courier, monospace !important;
}
</style>
</head>
<body>
<div class="mermaid">
stateDiagram
title This is a title
accDescription This is an accessible description
State1
</div>
<div class="mermaid">
stateDiagram-v2
title This is a title
accDescription This is an accessible description
State1
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
logLevel: 3,
securityLevel: 'loose',
flowchart: { curve: 'basis' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>
</body>
</html>

1242
dist/mermaid.core.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1242
dist/mermaid.js vendored

File diff suppressed because one or more lines are too long

2
dist/mermaid.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -7,14 +7,14 @@ It is a Javascript based diagramming and charting tool that renders Markdown-ins
>If you are familiar with Markdown you should have no problem learning [Mermaid's Syntax](./n00b-syntaxReference.md).
![banner](img/header.png)
<img src="img/header.png" alt="" />
<!-- **Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/README.md) -->
[![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
<!-- Mermaidn book banner -->
[![banner](img/book-banner-post-release.jpg)](https://mermaid-js.github.io/mermaid/landing/)
<!-- Mermaid book banner -->
[![Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!](img/book-banner-post-release.jpg)](https://mermaid-js.github.io/mermaid/landing/)
<!-- <Main description> -->
@ -41,7 +41,7 @@ For a more detailed introduction to Mermaid and some of its more basic uses, loo
**Thanks to all involved, people committing pull requests, people answering questions and special thanks to Tyler Long who is helping me maintain the project 🙏**
# Diagram Types
## Diagram Types
### [Flowchart](./flowchart.md?id=flowcharts-basic-syntax)
@ -161,7 +161,7 @@ journey
```
![Journey diagram](img/user-journey.png)
# Installation
## Installation
**In depth guides and examples can be found at [Getting Started](/n00b-gettingStarted) and [Usage](/usage).**
@ -188,7 +188,7 @@ To Deploy Mermaid:
4. You can then add mermaid as a dev dependency using this command:
`yarn add --dev 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:**
@ -201,7 +201,7 @@ To Deploy Mermaid:
**Examples can be found at** [Other examples](/examples)
# Sibling projects
## Sibling projects
- [Mermaid Live Editor](https://github.com/mermaid-js/mermaid-live-editor)
- [Mermaid CLI](https://github.com/mermaid-js/mermaid-cli)

View File

@ -756,19 +756,6 @@ available space if not the absolute space required is used.
Default value: true
## useMaxWidth
| Parameter | Description | Type | Required | Values |
| ----------- | ----------- | ------- | -------- | ----------- |
| useMaxWidth | See notes | boolean | 4 | true, false |
**Notes:**
When this flag is set the height and width is set to 100% and is then scaling with the
available space if not the absolute space required is used.
Default value: true
## defaultRenderer
| Parameter | Description | Type | Required | Values |

View File

@ -71,4 +71,4 @@ graph LR;
**Output**
![image](img/python-mermaid-integration.png)
![Example graph of the Python integration](img/python-mermaid-integration.png)

View File

@ -14,6 +14,7 @@
- [Gantt](gantt.md)
- [Pie Chart](pie.md)
- [Requirement Diagram](requirementDiagram.md)
- [Gitgraph (Git) Diagram 🔥🔥🔥](gitgraph.md)
- [Other Examples](examples.md)
- ⚙️ Deployment and Configuration

View File

@ -217,7 +217,7 @@ It is possible to add a label text to a relation:
classDiagram
classA <|-- classB : implements
classC *-- classD : composition
classE o-- classF : association
classE o-- classF : aggregation
```
### Two-way relations

View File

@ -26,5 +26,3 @@ Initialize call is called **only once**. It is called by the site integrator in
## configApi.reset
This method resets the configuration for a diagram to the site configuration, the configuration provided by the site integrator. Before each rendering of a diagram reset is called in the very beginning of render.
##

View File

@ -3,7 +3,7 @@
**Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/gitgraph.md)
> A Git Graph is a pictorial representation of git commits and git actions(commands) on various branches.
These kind of diagram are particularyly helpful to developers and devops teams to share their Git branching strategies. For example, it makes it easier to visualize how git flow works.
These kind of diagram are particularly helpful to developers and devops teams to share their Git branching strategies. For example, it makes it easier to visualize how git flow works.
Mermaid can render Git diagrams
@ -28,11 +28,11 @@ In Mermaid, we support the basic git operations like:
- *merge* : To merge an existing branch onto the current branch.
With the help of these key git commands, you will be able to draw a gitgraph in Mermaid very easily and quickly.
Entity names are often capitalised, although there is no accepted standard on this, and it is not required in Mermaid.
Entity names are often capitalized, although there is no accepted standard on this, and it is not required in Mermaid.
## Syntax
Mermaid syntax for Gitgraph is very straigth-forward and simple. It follows a declarative-approach, where each commit is drawn on the timeline in the diagram, in order of its occurance/presence in code. Basically, it follows the insertion order for each command.
Mermaid syntax for Gitgraph is very straight-forward and simple. It follows a declarative-approach, where each commit is drawn on the timeline in the diagram, in order of its occurrences/presence in code. Basically, it follows the insertion order for each command.
First thing you do is to declare your diagram type using the **gitgraph** keyword. This `gitgraph` keyword, tells Mermaid that you wish to draw a gitgraph, and parse the diagram code accordingly.
@ -84,7 +84,7 @@ Let us see how these different commit type look with the help of the following d
commit
commit id: "Reverse" type: REVERSE
commit
commit id: "Hightlight" type: HIGHLIGHT
commit id: "Highlight" type: HIGHLIGHT
commit
```
@ -104,7 +104,7 @@ Let us see how this works with the help of the following diagram:
commit
commit id: "Reverse" type: REVERSE tag: "RC_1"
commit
commit id: "Hightlight" type: HIGHLIGHT tag: "8.8.4"
commit id: "Highlight" type: HIGHLIGHT tag: "8.8.4"
commit
```
@ -182,9 +182,145 @@ After this we made use of the `checkout` keyword to set the current branch as `m
After this we merge the `develop` branch onto the current branch `main`, resulting in a merge commit.
Since the current branch at this point is still `main`, the last two commits are registered against that.
## Gitgraph specific configuration options
In Mermaid, you have the option to configure the gitgraph diagram. You can configure the following options:
- `showBranches` : Boolean, default is `true`. If set to `false`, the branches are not shown in the diagram.
- `showCommitLabel` : Boolean, default is `true`. If set to `false`, the commit labels are not shown in the diagram.
- `mainBranchName` : String, default is `main`. The name of the default/root branch.
Let's look at them one by one.
## Hiding Branch names and lines
Sometimes you may want to hide the branch names and lines from the diagram. You can do this by using the `showBranches` keyword. Bye default its value is `true`. You can set it to false using directives
Usage example:
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': false}} }%%
gitGraph
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"ash" tag:"abc"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
```
## Hiding commit labels
Sometimes you may want to hide the commit labels from the diagram. You can do this by using the `showCommitLabel` keyword. By default its value is `true`. You can set it to `false` using directives.
Usage example:
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': false,'showCommitLabel': false}} }%%
gitGraph
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"ash"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
```
## Customizing the main/default branch name
Sometimes you may want to customize the name of the main/default branch. You can do this by using the `mainBranchName` keyword. By default its value is `main`. You can set it to any string using directives.
Usage example:
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'MetroLine1'}} }%%
gitGraph
commit id:"NewYork"
commit id:"Dallas"
branch MetroLine2
commit id:"LosAngeles"
commit id:"Chicago"
commit id:"Houston"
branch MetroLine3
commit id:"Phoenix"
commit type: HIGHLIGHT id:"Denver"
commit id:"Boston"
checkout MetroLine1
commit id:"Atlanta"
merge MetroLine3
commit id:"Miami"
commit id:"Washington"
merge MetroLine2
commit id:"Boston"
commit id:"Detroit"
commit type:REVERSE id:"SanFrancisco"
```
Looks at the imaginary rail road map created using these Mermaid. Here, we have changed the default main branch name to `MetroLine1`.
## Themes
Mermaid supports a bunch of pre-defined themes which you can use to find the right one for you. PS: you can actually override an existing theme's variable to get your own custom theme going. Learn more about themeing your diagram [here](./theming.md).
Mermaid supports a bunch of pre-defined themes which you can use to find the right one for you. PS: you can actually override an existing theme's variable to get your own custom theme going. Learn more about theming your diagram [here](./theming.md).
Following are the different pre-defined theme options:
- `base`
@ -434,4 +570,172 @@ Let's put them to use, add see how our sample diagram looks like in different th
merge release
```
## Customize using Theme Variables
## Customize using Theme Variables
Mermaid allows you to customize your diagram using theme variables which govern the look and feel of various elements of the diagram.
For understanding let us take a sample diagram with theme `default`, the default values of the theme variables is picked automatically from the theme. Later on we will see how to override the default values of the theme variables.
See how the default theme is used to set the colors for the branches:
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%%
gitGraph
commit
branch develop
commit tag:"v1.0.0"
commit
checkout main
commit type: HIGHLIGHT
commit
merge develop
commit
branch featureA
commit
```
### Customizing branch colors
You can customize the branch colors using the `git0` to `git7` theme variables. Mermaid allows you to set the colors for up-to 8 branches, where `git0` variable will drive the value of the first branch, `git1` will drive the value of the second branch and so on.
NOTE: Default values for these theme variables are picked from the selected theme. If you want to override the default values, you can use the `initialize` call to add your custom theme variable values.
Example:
Now let's override the default values for the `git0` to `git3` variables:
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'git0': '#ff0000',
'git1': '#00ff00',
'git2': '#0000ff',
'git3': '#ff00ff',
'git4': '#00ffff',
'git5': '#ffff00',
'git6': '#ff00ff',
'git7': '#00ffff'
} } }%%
gitGraph
commit
branch develop
commit tag:"v1.0.0"
commit
checkout main
commit type: HIGHLIGHT
commit
merge develop
commit
branch featureA
commit
```
See how the branch colors are changed to the values specified in the theme variables.
### Customizing branch label colors
You can customize the branch label colors using the `gitBranchLabel0` to `gitBranchLabel7` theme variables. Mermaid allows you to set the colors for up-to 8 branches, where `gitBranchLabel0` variable will drive the value of the first branch label, `gitBranchLabel1` will drive the value of the second branch label and so on.
Lets see how the default theme is used to set the colors for the branch labels:
Now let's override the default values for the `gitBranchLabel0` to `gitBranchLabel2` variables:
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'gitBranchLabel0': '#ff0000',
'gitBranchLabel1': '#00ff00',
'gitBranchLabel2': '#0000ff'
} } }%%
gitGraph
commit
branch develop
commit tag:"v1.0.0"
commit
checkout main
commit type: HIGHLIGHT
commit
merge develop
commit
branch featureA
commit
```
See how the branch label colors are changed to the values specified in the theme variables.
### Customizing Commit colors
You can customize commit using the `commitLabelColor` and `commitLabelBackground` theme variables for changes in the commit label color and background color respectively.
Example:
Now let's override the default values for the `commitLabelColor` to `commitLabelBackground` variables:
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'commitLabelColor': '#ff0000',
'commitLabelBackground': '#00ff00'
} } }%%
gitGraph
commit
branch develop
commit tag:"v1.0.0"
commit
checkout main
commit type: HIGHLIGHT
commit
merge develop
commit
branch featureA
commit
```
See how the commit label color and background color are changed to the values specified in the theme variables.
### Customizing Tag colors
You can customize tag using the `tagLabelColor`,`tagLabelBackground` and `tagLabelBorder` theme variables for changes in the tag label color,tag label background color and tag label border respectively.
Example:
Now let's override the default values for the `tagLabelColor`, `tagLabelBackground` and to `tagLabelBorder` variables:
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'tagLabelColor': '#ff0000',
'tagLabelBackground': '#00ff00',
'tagLabelBorder': '#0000ff'
} } }%%
gitGraph
commit
branch develop
commit tag:"v1.0.0"
commit
checkout main
commit type: HIGHLIGHT
commit
merge develop
commit
branch featureA
commit
```
See how the tag colors are changed to the values specified in the theme variables.
### Customizing Highlight commit colors
You can customize the highlight commit colors in relation to the branch it is on using the `gitInv0` to `gitInv7` theme variables. Mermaid allows you to set the colors for up-to 8 branches specific highlight commit, where `gitInv0` variable will drive the value of the first branch's highlight commits, `gitInv1` will drive the value of the second branch's highlight commit label and so on.
Example:
Now let's override the default values for the `git0` to `git3` variables:
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'gitInv0': '#ff0000'
} } }%%
gitGraph
commit
branch develop
commit tag:"v1.0.0"
commit
checkout main
commit type: HIGHLIGHT
commit
merge develop
commit
branch featureA
commit
```
Se how the highlight commit color on the first branch is changed to the value specified in the theme variable `gitInv0`.

View File

@ -17,8 +17,8 @@
/>
<!-- <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css"> -->
<link rel="stylesheet" href="theme.css" />
<!-- <script src="//cdn.jsdelivr.net/npm/mermaid@8.14.0/dist/mermaid.min.js"></script> -->
<script src="http://localhost:9000/mermaid.js"></script>
<script src="//cdn.jsdelivr.net/npm/mermaid@9.0.0/dist/mermaid.min.js"></script>
<!-- <script src="http://localhost:9000/mermaid.js"></script> -->
<script>
// prettier-ignore
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){

View File

@ -1,6 +1,6 @@
{
"name": "mermaid",
"version": "8.14.0",
"version": "9.0.0",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"main": "dist/mermaid.core.js",
"module": "dist/mermaid.esm.min.mjs",
@ -80,14 +80,14 @@
"concurrently": "^7.0.0",
"coveralls": "^3.0.2",
"css-to-string-loader": "^0.1.3",
"cypress": "9.5.2",
"cypress": "9.5.3",
"documentation": "13.2.0",
"eslint": "^8.2.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-html": "^6.2.0",
"eslint-plugin-jest": "^26.0.0",
"eslint-plugin-jsdoc": "^38.0.3",
"eslint-plugin-jsdoc": "^39.1.0",
"eslint-plugin-markdown": "^2.2.1",
"eslint-plugin-prettier": "^4.0.0",
"husky": "^7.0.1",

View File

@ -49,7 +49,7 @@ class Diagram {
this.type = utils.detectType(txt, cnf);
log.debug('Type ' + this.type);
switch (this.type) {
case 'git':
case 'gitGraph':
this.parser = gitGraphParser;
this.parser.parser.yy = gitGraphAst;
this.db = gitGraphAst;

View File

@ -1,17 +1,20 @@
/**
* This method will add a basic title and description element to a chart. The yy parser will need to
* respond to getTitle and getAccDescription, where the title is the title element on the chart,
* which is not displayed and the accDescription is the description element on the chart, which is
* also not displayed.
* which is generally not displayed and the accDescription is the description element on the chart,
* which is never displayed.
*
* The following charts display their title as a visual and accessibility element: gantt
*
* @param yy_parser
* @param svg
* @param id
*/
export default function addSVGAccessibilityFields(yy_parser, svg, id) {
if (typeof svg.insert == 'undefined') {
if (typeof svg.insert === 'undefined') {
return;
}
let title_string = yy_parser.getTitle();
let description = yy_parser.getAccDescription();
svg.attr('role', 'img').attr('aria-labelledby', 'chart-title-' + id + ' chart-desc-' + id);

View File

@ -1,162 +0,0 @@
import { assignWithDepth } from './utils';
import { log } from './logger'; // eslint-disable-line
import theme from './themes';
import config from './defaultConfig';
const handleThemeVariables = (value) => {
return theme[value] ? theme[value].getThemeVariables() : theme.default.getThemeVariables();
};
const manipulators = {
themeVariables: handleThemeVariables,
};
// debugger;
config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
config.git.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
export const defaultConfig = Object.freeze(config);
const siteConfig = assignWithDepth({}, defaultConfig);
const currentConfig = assignWithDepth({}, defaultConfig);
/**
* ## setSiteConfig
*
* | Function | Description | Type | Values |
* | ------------- | ------------------------------------- | ----------- | --------------------------------------- |
* | setSiteConfig | Sets the siteConfig to desired values | Put Request | Any Values, except ones in secure array |
*
* **Notes:** Sets the siteConfig. The siteConfig is a protected configuration for repeat use. Calls
* to reset() will reset the currentConfig to siteConfig. Calls to reset(configApi.defaultConfig)
* will reset siteConfig and currentConfig to the defaultConfig Note: currentConfig is set in this
* function Default value: At default, will mirror Global Config
*
* @param {any} conf - The base currentConfig to use as siteConfig
* @returns {any} - The siteConfig
*/
export const setSiteConfig = (conf) => {
console.log('setSiteConfig');
Object.keys(conf).forEach((key) => {
const manipulator = manipulators[key];
conf[key] = manipulator ? manipulator(conf[key]) : conf[key];
});
assignWithDepth(currentConfig, conf, { clobber: true });
// Set theme variables if user has set the theme option
assignWithDepth(siteConfig, conf);
return getSiteConfig();
};
/**
* ## getSiteConfig
*
* | Function | Description | Type | Values |
* | ------------- | ------------------------------------------------- | ----------- | -------------------------------- |
* | setSiteConfig | Returns the current siteConfig base configuration | Get Request | Returns Any Values in siteConfig |
*
* **Notes**: Returns **any** values in siteConfig.
*
* @returns {any}
*/
export const getSiteConfig = () => {
return assignWithDepth({}, siteConfig);
};
/**
* ## setConfig
*
* | Function | Description | Type | Values |
* | ------------- | ------------------------------------- | ----------- | --------------------------------------- |
* | setSiteConfig | Sets the siteConfig to desired values | Put Request | Any Values, except ones in secure array |
*
* **Notes**: Sets the currentConfig. The parameter conf is sanitized based on the siteConfig.secure
* keys. Any values found in conf with key found in siteConfig.secure will be replaced with the
* corresponding siteConfig value.
*
* @param {any} conf - The potential currentConfig
* @returns {any} - The currentConfig merged with the sanitized conf
*/
export const setConfig = (conf) => {
console.log('setConfig');
sanitize(conf);
Object.keys(conf).forEach((key) => {
const manipulator = manipulators[key];
conf[key] = manipulator ? manipulator(conf[key]) : conf[key];
});
assignWithDepth(currentConfig, conf);
return getConfig();
};
/**
* ## getConfig
*
* | Function | Description | Type | Return Values |
* | --------- | ------------------------- | ----------- | ----------------------------- |
* | getConfig | Obtains the currentConfig | Get Request | Any Values from currentConfig |
*
* **Notes**: Returns **any** the currentConfig
*
* @returns {any} - The currentConfig
*/
export const getConfig = () => {
return assignWithDepth({}, currentConfig);
};
/**
* ## sanitize
*
* | Function | Description | Type | Values |
* | -------- | -------------------------------------- | ----------- | ------ |
* | sanitize | Sets the siteConfig to desired values. | Put Request | None |
*
* Ensures options parameter does not attempt to override siteConfig secure keys **Notes**: modifies
* options in-place
*
* @param {any} options - The potential setConfig parameter
*/
export const sanitize = (options) => {
Object.keys(siteConfig.secure).forEach((key) => {
if (typeof options[siteConfig.secure[key]] !== 'undefined') {
// DO NOT attempt to print options[siteConfig.secure[key]] within `${}` as a malicious script
// can exploit the logger's attempt to stringify the value and execute arbitrary code
log.trace(
`Denied attempt to modify a secure key ${siteConfig.secure[key]}`,
options[siteConfig.secure[key]]
);
delete options[siteConfig.secure[key]];
}
});
};
/**
* ## reset
*
* | Function | Description | Type | Required | Values |
* | -------- | ---------------------------- | ----------- | -------- | ------ |
* | reset | Resets currentConfig to conf | Put Request | Required | None |
*
* | Parameter | Description |Type | Required | Values|
*
* | --- | --- | --- | --- | --- |
* | conf| base set of values, which currentConfig coul be **reset** to.| Dictionary | Required | Any Values, with respect to the secure Array|
*
* **Notes**: (default: current siteConfig ) (optional, default `getSiteConfig()`)
*
* @param {any} conf - The base currentConfig to reset to (default: current siteConfig )
*/
export const reset = (conf = getSiteConfig()) => {
console.warn('reset');
Object.keys(siteConfig).forEach((key) => delete siteConfig[key]);
Object.keys(currentConfig).forEach((key) => delete currentConfig[key]);
assignWithDepth(siteConfig, conf, { clobber: true });
assignWithDepth(currentConfig, conf, { clobber: true });
};
const configApi = Object.freeze({
sanitize,
setSiteConfig,
getSiteConfig,
setConfig,
getConfig,
reset,
defaultConfig,
});
export default configApi;

View File

@ -844,25 +844,6 @@ const config = {
*/
defaultRenderer: 'dagre-wrapper',
},
git: {
arrowMarkerAbsolute: false,
useWidth: undefined,
/**
* | Parameter | Description | Type | Required | Values |
* | ----------- | ----------- | ------- | -------- | ----------- |
* | useMaxWidth | See notes | boolean | 4 | true, false |
*
* **Notes:**
*
* When this flag is set the height and width is set to 100% and is then scaling with the
* available space if not the absolute space required is used.
*
* Default value: true
*/
useMaxWidth: true,
},
state: {
dividerMargin: 10,
sizeUnit: 5,
@ -1066,27 +1047,20 @@ const config = {
},
gitGraph: {
diagramPadding: 8,
nodeSpacing: 150,
nodeFillColor: 'yellow',
nodeStrokeWidth: 2,
nodeStrokeColor: 'grey',
lineStrokeWidth: 4,
branchOffset: 50,
lineColor: 'grey',
leftMargin: 50,
branchColors: ['#442f74', '#983351', '#609732', '#AA9A39'],
nodeRadius: 10,
nodeLabel: {
width: 75,
height: 100,
x: -25,
y: 0,
},
mainBranchName: 'main',
showCommitLabel: true,
showBranches: true,
},
};
config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
config.git.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
config.gitGraph.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
const keyify = (obj, prefix = '') =>
Object.keys(obj).reduce((res, el) => {

View File

@ -345,8 +345,34 @@ const setDirection = (dir) => {
direction = dir;
};
let title = '';
export const setTitle = function (txt) {
let sanitizedText = sanitizeText(txt, configApi.getConfig());
title = sanitizedText;
};
export const getTitle = function () {
return title;
};
let accDescription = '';
export const setAccDescription = function (txt) {
let sanitizedText = sanitizeText(txt, configApi.getConfig());
accDescription = sanitizedText;
};
export const getAccDescription = function () {
return accDescription;
};
export default {
parseDirective,
setTitle,
getTitle,
getAccDescription,
setAccDescription,
getConfig: () => configApi.getConfig().class,
addClass,
bindFunctions,

View File

@ -543,6 +543,21 @@ foo()
expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE);
});
it('should have a title and accDescription', function () {
const str =
'classDiagram\n' +
'class Car~T~\n' +
'title My Title\n' +
'accDescription My Description\n';
'Car : -List~Wheel~ wheels\n' +
'Car : +setWheels(List~Wheel~ wheels)\n' +
'Car : +getWheels() List~Wheel~';
parser.parse(str);
expect(parser.yy.getTitle()).toBe('My Title');
expect(parser.yy.getAccDescription()).toBe('My Description');
});
it('should handle relation definitions AGGREGATION and dotted line', function () {
const str = 'classDiagram\n' + 'Class01 o.. Class02';

View File

@ -11,6 +11,7 @@ import { render } from '../../dagre-wrapper/index.js';
import { curveLinear } from 'd3';
import { interpolateToCurve, getStylesFromArray, configureSvgSize } from '../../utils';
import common from '../common/common';
import addSVGAccessibilityFields from '../../accessibility';
parser.yy = classDb;
@ -397,6 +398,7 @@ export const draw = function (text, id) {
}
}
addSVGAccessibilityFields(parser.yy, svg, id);
// If node has a link, wrap it in an anchor SVG object.
// const keys = Object.keys(classes);
// keys.forEach(function(key) {

View File

@ -7,6 +7,7 @@ import { parser } from './parser/classDiagram';
import svgDraw from './svgDraw';
import { configureSvgSize } from '../../utils';
import { getConfig } from '../../config';
import addSVGAccessibilityFields from '../../accessibility';
parser.yy = classDb;
@ -263,6 +264,7 @@ export const draw = function (text, id) {
const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
log.debug(`viewBox ${vBox}`);
diagram.attr('viewBox', vBox);
addSVGAccessibilityFields(parser.yy, diagram, id);
};
export default {

View File

@ -29,6 +29,8 @@
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
\%\%(?!\{)*[^\n]*(\r?\n?)+ /* skip comments */
\%\%[^\n]*(\r?\n)* /* skip comments */
"title"\s[^#\n;]+ return 'title';
"accDescription"\s[^#\n;]+ return 'accDescription';
\s*(\r?\n)+ return 'NEWLINE';
\s+ /* skip whitespace */
@ -185,6 +187,7 @@ Function arguments are optional: 'call <callback_name>()' simply executes 'callb
start
: mermaidDoc
| statments
| direction
| directive start
;
@ -253,6 +256,9 @@ statement
| cssClassStatement
| directive
| direction
| title {yy.setTitle($1.substring(6));$$=$1.substring(6);}
| accDescription {yy.setAccDescription($1.substring(15));$$=$1.substring(15);}
;
classStatement

View File

@ -1,6 +1,7 @@
import { log } from '../../logger';
import mermaidAPI from '../../mermaidAPI';
import * as configApi from '../../config';
import common from '../common/common';
let entities = {};
let relationships = [];
@ -69,7 +70,8 @@ const getRelationships = () => relationships;
// Keep this - TODO: revisit...allow the diagram to have a title
const setTitle = function (txt) {
title = txt;
let sanitizedText = common.sanitizeText(txt, configApi.getConfig());
title = sanitizedText;
};
const getTitle = function () {
@ -77,7 +79,8 @@ const getTitle = function () {
};
const setAccDescription = function (txt) {
description = txt;
let sanitizedText = common.sanitizeText(txt, configApi.getConfig());
description = sanitizedText;
};
const getAccDescription = function () {

View File

@ -17,16 +17,36 @@ let tooltips = {};
let subCount = 0;
let firstGraphFlag = true;
let direction;
let title = 'Flow chart';
let description = '';
let version; // As in graph
// Functions to be run after graph rendering
let funs = [];
const sanitizeText = (txt) => common.sanitizeText(txt, config);
export const parseDirective = function (statement, context, type) {
mermaidAPI.parseDirective(this, statement, context, type);
};
const setTitle = function (txt) {
title = sanitizeText(txt);
};
const getTitle = function () {
return title;
};
const setAccDescription = function (txt) {
description = sanitizeText(txt);
};
const getAccDescription = function () {
return description;
};
/**
* Function to lookup domId from id in the graph definition.
*
@ -77,7 +97,7 @@ export const addVertex = function (_id, text, type, style, classes, dir, props =
vertexCounter++;
if (typeof text !== 'undefined') {
config = configApi.getConfig();
txt = common.sanitizeText(text.trim(), config);
txt = sanitizeText(text.trim());
// strip quotes if string starts and ends with a quote
if (txt[0] === '"' && txt[txt.length - 1] === '"') {
@ -132,7 +152,7 @@ export const addSingleLink = function (_start, _end, type, linktext) {
linktext = type.text;
if (typeof linktext !== 'undefined') {
edge.text = common.sanitizeText(linktext.trim(), config);
edge.text = sanitizeText(linktext.trim());
// strip quotes if string starts and exnds with a quote
if (edge.text[0] === '"' && edge.text[edge.text.length - 1] === '"') {
@ -255,7 +275,7 @@ export const setClass = function (ids, className) {
const setTooltip = function (ids, tooltip) {
ids.split(',').forEach(function (id) {
if (typeof tooltip !== 'undefined') {
tooltips[version === 'gen-1' ? lookUpDomId(id) : id] = common.sanitizeText(tooltip, config);
tooltips[version === 'gen-1' ? lookUpDomId(id) : id] = sanitizeText(tooltip);
}
});
};
@ -488,7 +508,7 @@ export const addSubGraph = function (_id, list, _title) {
id = id || 'subGraph' + subCount;
// if (id[0].match(/\d/)) id = lookUpDomId(id);
title = title || '';
title = common.sanitizeText(title, config);
title = sanitizeText(title);
subCount = subCount + 1;
const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [], dir };
@ -736,6 +756,10 @@ const makeUniq = (sg, allSubgraphs) => {
export default {
parseDirective,
defaultConfig: () => configApi.defaultConfig.flowchart,
setTitle,
getTitle,
getAccDescription,
setAccDescription,
addVertex,
lookUpDomId,
addLink,

View File

@ -10,6 +10,7 @@ import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
import { log } from '../../logger';
import common, { evaluate } from '../common/common';
import { interpolateToCurve, getStylesFromArray, configureSvgSize } from '../../utils';
import addSVGAccessibilityFields from '../../accessibility';
const conf = {};
export const setConf = function (cnf) {
@ -181,7 +182,7 @@ export const addVertices = function (vert, g, svgId, root, doc) {
};
/**
* Add edges to graph based on parsed graph defninition
* Add edges to graph based on parsed graph definition
*
* @param {object} edges The edges to add to the graph
* @param {object} g The graph object
@ -380,7 +381,7 @@ export const draw = function (text, id) {
const rankSpacing = conf.rankSpacing || 50;
const securityLevel = getConfig().securityLevel;
// Handle root and ocument for when rendering in sanbox mode
// Handle root and document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
@ -416,7 +417,7 @@ export const draw = function (text, id) {
flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes, subG.dir);
}
// Fetch the verices/nodes and edges/links from the parsed graph definition
// Fetch the vertices/nodes and edges/links from the parsed graph definition
const vert = flowDb.getVertices();
const edges = flowDb.getEdges();
@ -444,6 +445,9 @@ export const draw = function (text, id) {
const svg = root.select(`[id="${id}"]`);
svg.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
// Adds title and description to the flow chart
addSVGAccessibilityFields(parser.yy, svg, id);
// Run the renderer. This is what draws the final graph.
const element = root.select('#' + id + ' g');
render(element, g, ['point', 'circle', 'cross'], 'flowchart', id);

View File

@ -11,6 +11,7 @@ import { log } from '../../logger';
import common, { evaluate } from '../common/common';
import { interpolateToCurve, getStylesFromArray, configureSvgSize } from '../../utils';
import flowChartShapes from './flowChartShapes';
import addSVGAccessibilityFields from '../../accessibility';
const conf = {};
export const setConf = function (cnf) {
@ -158,7 +159,7 @@ export const addVertices = function (vert, g, svgId, root, _doc) {
};
/**
* Add edges to graph based on parsed graph defninition
* Add edges to graph based on parsed graph definition
*
* @param {object} edges The edges to add to the graph
* @param {object} g The graph object
@ -350,7 +351,7 @@ export const draw = function (text, id) {
flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes);
}
// Fetch the verices/nodes and edges/links from the parsed graph definition
// Fetch the vertices/nodes and edges/links from the parsed graph definition
const vert = flowDb.getVertices();
log.warn('Get vertices', vert);
@ -426,6 +427,9 @@ export const draw = function (text, id) {
log.warn(g);
// Adds title and description to the flow chart
addSVGAccessibilityFields(parser.yy, svg, id);
// Run the renderer. This is what draws the final graph.
const element = root.select('#' + id + ' g');
render(element, g);

View File

@ -7,6 +7,8 @@
/* lexical grammar */
%lex
%x string
%x title
%x accDescription
%x dir
%x vertex
%x click
@ -26,6 +28,10 @@
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
\%\%(?!\{)[^\n]* /* skip comments */
[^\}]\%\%[^\n]* /* skip comments */
title { this.begin("title");return 'title'; }
<title>(?!\n|;|#)*[^\n]* { this.popState(); return "title_value"; }
accDescription { this.begin("accDescription");return 'accDescription'; }
<accDescription>(?!\n|;|#)*[^\n]* { this.popState(); return "description_value"; }
["] this.begin("string");
<string>["] this.popState();
<string>[^"]* return "STR";
@ -337,6 +343,8 @@ statement
| subgraph separator document end
{$$=yy.addSubGraph(undefined,$3,undefined);}
| direction
| title title_value { $$=$2.trim();yy.setTitle($$); }
| accDescription description_value { $$=$2.trim();yy.setAccDescription($$); }
;
separator: NEWLINE | SEMI | EOF ;

View File

@ -6,13 +6,13 @@ setConfig({
securityLevel: 'strict',
});
describe('when parsing ', function () {
describe('parsing a flow chart', function () {
beforeEach(function () {
flow.parser.yy = flowDb;
flow.parser.yy.clear();
});
it('it should handle a trailing whitespaces after statememnts', function () {
it('should handle a trailing whitespaces after statememnts', function () {
const res = flow.parser.parse('graph TD;\n\n\n %% Comment\n A-->B; \n B-->C;');
const vert = flow.parser.yy.getVertices();
@ -80,47 +80,47 @@ describe('when parsing ', function () {
flow.parser.yy.clear();
};
it("it should be able to parse a '.'", function () {
it("should be able to parse a '.'", function () {
charTest('.');
charTest('Start 103a.a1');
});
// it('it should be able to parse text containing \'_\'', function () {
// it('should be able to parse text containing \'_\'', function () {
// charTest('_')
// })
it("it should be able to parse a ':'", function () {
it("should be able to parse a ':'", function () {
charTest(':');
});
it("it should be able to parse a ','", function () {
it("should be able to parse a ','", function () {
charTest(',');
});
it("it should be able to parse text containing '-'", function () {
it("should be able to parse text containing '-'", function () {
charTest('a-b');
});
it("it should be able to parse a '+'", function () {
it("should be able to parse a '+'", function () {
charTest('+');
});
it("it should be able to parse a '*'", function () {
it("should be able to parse a '*'", function () {
charTest('*');
});
it("it should be able to parse a '<'", function () {
it("should be able to parse a '<'", function () {
charTest('<', '&lt;');
});
// it("it should be able to parse a '>'", function() {
// it("should be able to parse a '>'", function() {
// charTest('>', '&gt;');
// });
// it("it should be able to parse a '='", function() {
// it("should be able to parse a '='", function() {
// charTest('=', '&equals;');
// });
it("it should be able to parse a '&'", function () {
it("should be able to parse a '&'", function () {
charTest('&');
});
});
@ -146,6 +146,7 @@ describe('when parsing ', function () {
const classes = flow.parser.yy.getClasses();
expect(vertices['A'].id).toBe('A');
});
it('should be possible to use numbers as labels', function () {
let statement = '';
@ -155,4 +156,19 @@ describe('when parsing ', function () {
const classes = flow.parser.yy.getClasses();
expect(vertices['1'].id).toBe('1');
});
it('should add title and description to flow chart', function () {
const flowChart = `graph LR
title Big decisions
accDescription Flow chart of the decision making process
A[Hard] -->|Text| B(Round)
B --> C{Decision}
C -->|One| D[Result 1]
C -->|Two| E[Result 2]
`;
flow.parser.parse(flowChart);
expect(flow.parser.yy.getTitle()).toBe('Big decisions');
expect(flow.parser.yy.getAccDescription()).toBe('Flow chart of the decision making process');
});
});

View File

@ -4,6 +4,7 @@ import { log } from '../../logger';
import * as configApi from '../../config';
import utils from '../../utils';
import mermaidAPI from '../../mermaidAPI';
import common from '../common/common';
let dateFormat = '';
let axisFormat = '';
@ -12,6 +13,7 @@ let includes = [];
let excludes = [];
let links = {};
let title = '';
let accDescription = '';
let sections = [];
let tasks = [];
let currentSection = '';
@ -23,6 +25,10 @@ let topAxis = false;
// The serial order of the task in the script
let lastOrder = 0;
const sanitizeText = function (txt) {
return common.sanitizeText(txt, configApi.getConfig());
};
export const parseDirective = function (statement, context, type) {
mermaidAPI.parseDirective(this, statement, context, type);
};
@ -108,13 +114,21 @@ export const getLinks = function () {
};
export const setTitle = function (txt) {
title = txt;
title = sanitizeText(txt);
};
export const getTitle = function () {
return title;
};
export const setAccDescription = function (txt) {
accDescription = sanitizeText(txt);
};
export const getAccDescription = function () {
return accDescription;
};
export const addSection = function (txt) {
currentSection = txt;
sections.push(txt);
@ -637,6 +651,8 @@ export default {
getTodayMarker,
setTitle,
getTitle,
setAccDescription,
getAccDescription,
addSection,
getSections,
getTasks,

View File

@ -32,6 +32,7 @@ describe('when using the ganttDb', function () {
fn | expected
${'getTasks'} | ${[]}
${'getTitle'} | ${''}
${'getAccDescription'} | ${''}
${'getDateFormat'} | ${''}
${'getAxisFormat'} | ${''}
${'getTodayMarker'} | ${''}

View File

@ -15,6 +15,7 @@ import common from '../common/common';
import ganttDb from './ganttDb';
import { getConfig } from '../../config';
import { configureSvgSize } from '../../utils';
import addSVGAccessibilityFields from '../../accessibility';
parser.yy = ganttDb;
export const setConf = function () {
@ -114,6 +115,8 @@ export const draw = function (text, id) {
.attr('y', conf.titleTopMargin)
.attr('class', 'titleText');
addSVGAccessibilityFields(parser.yy, svg, id);
/**
* @param tasks
* @param pageWidth

View File

@ -65,22 +65,23 @@ that id.
<click>[\s\n] this.popState();
<click>[^\s\n]* return 'click';
"gantt" return 'gantt';
"dateFormat"\s[^#\n;]+ return 'dateFormat';
"inclusiveEndDates" return 'inclusiveEndDates';
"topAxis" return 'topAxis';
"axisFormat"\s[^#\n;]+ return 'axisFormat';
"includes"\s[^#\n;]+ return 'includes';
"excludes"\s[^#\n;]+ return 'excludes';
"todayMarker"\s[^\n;]+ return 'todayMarker';
\d\d\d\d"-"\d\d"-"\d\d return 'date';
"title"\s[^#\n;]+ return 'title';
"section"\s[^#:\n;]+ return 'section';
[^#:\n;]+ return 'taskTxt';
":"[^#\n;]+ return 'taskData';
":" return ':';
<<EOF>> return 'EOF';
. return 'INVALID';
"gantt" return 'gantt';
"dateFormat"\s[^#\n;]+ return 'dateFormat';
"inclusiveEndDates" return 'inclusiveEndDates';
"topAxis" return 'topAxis';
"axisFormat"\s[^#\n;]+ return 'axisFormat';
"includes"\s[^#\n;]+ return 'includes';
"excludes"\s[^#\n;]+ return 'excludes';
"todayMarker"\s[^\n;]+ return 'todayMarker';
\d\d\d\d"-"\d\d"-"\d\d return 'date';
"title"\s[^#\n;]+ return 'title';
"accDescription"\s[^#\n;]+ return 'accDescription'
"section"\s[^#:\n;]+ return 'section';
[^#:\n;]+ return 'taskTxt';
":"[^#\n;]+ return 'taskData';
":" return ':';
<<EOF>> return 'EOF';
. return 'INVALID';
/lex
@ -116,6 +117,7 @@ statement
| includes {yy.setIncludes($1.substr(9));$$=$1.substr(9);}
| todayMarker {yy.setTodayMarker($1.substr(12));$$=$1.substr(12);}
| title {yy.setTitle($1.substr(6));$$=$1.substr(6);}
| accDescription {yy.setAccDescription($1.substr(15));$$=$1.substr(15);}
| section {yy.addSection($1.substr(8));$$=$1.substr(8);}
| clickStatement
| taskTxt taskData {yy.addTask($1,$2);$$='task';}

View File

@ -156,4 +156,21 @@ describe('when parsing a gantt diagram it', function () {
'"test0", test1, test2'
);
});
it('should allow for a title and accDescription', function () {
const expectedTitle = 'Gantt Diagram';
const expectedAccDescription = 'Tasks for Q4';
const ganttString =
'gantt\n' +
`title ${expectedTitle}\n` +
`accDescription ${expectedAccDescription}\n` +
'dateFormat YYYY-MM-DD\n' +
'section Section\n' +
'A task :a1, 2014-01-01, 30d\n';
const output = parser.parse(ganttString);
expect(ganttDb.getTitle()).toBe(expectedTitle);
expect(ganttDb.getAccDescription()).toBe(expectedAccDescription);
});
});

View File

@ -2,11 +2,15 @@ import { log } from '../../logger';
import { random } from '../../utils';
import mermaidAPI from '../../mermaidAPI';
import * as configApi from '../../config';
import { getConfig } from '../../config';
import common from '../common/common';
let mainBranchName = getConfig().gitGraph.mainBranchName;
let commits = {};
let head = null;
let branches = { main: head };
let curBranch = 'main';
let branches = {};
branches[mainBranchName] = head;
let curBranch = mainBranchName;
let direction = 'LR';
let seq = 0;
@ -220,7 +224,6 @@ export const merge = function (otherBranch) {
export const checkout = function (branch) {
branch = common.sanitizeText(branch, configApi.getConfig());
console.info(branches);
if (typeof branches[branch] === 'undefined') {
let error = new Error(
'Trying to checkout branch which is not yet created. (Help try using "branch ' + branch + '")'
@ -238,9 +241,6 @@ export const checkout = function (branch) {
} else {
curBranch = branch;
const id = branches[curBranch];
console.log(id);
console.log('hi');
console.log(commits);
head = commits[id];
}
};
@ -320,8 +320,10 @@ export const prettyPrint = function () {
export const clear = function () {
commits = {};
head = null;
branches = { main: head };
curBranch = 'main';
let mainBranch = getConfig().gitGraph.mainBranchName;
branches = {};
branches[mainBranch] = null;
curBranch = mainBranch;
seq = 0;
};

View File

@ -1,18 +1,12 @@
/* eslint-disable */
import { curveBasis, line, select } from 'd3';
import { interpolateToCurve, getStylesFromArray, configureSvgSize } from '../../utils';
import db from './gitGraphAst';
//import * as db from './mockDb';
import gitGraphParser from './parser/gitGraph';
import { log } from '../../logger';
/* eslint-disable */
import { getConfig } from '../../config';
//import * as configApi from '../../config';
let allCommitsDict = {};
let branchNum;
//let conf = configApi.getConfig();
//const commitType = db.commitType;
const commitType = {
NORMAL: 0,
REVERSE: 1,
@ -29,89 +23,55 @@ const clear = () => {
commitPos = {};
allCommitsDict = {};
maxPos = 0;
lanes = []
lanes = [];
};
// let apiConfig = {};
// export const setConf = function(c) {
// apiConfig = c;
// };
/** @param svg */
function svgCreateDefs(svg) {
const config = getConfig().gitGraph;
svg
.append('defs')
.append('g')
.attr('id', 'def-commit')
.append('circle')
.attr('r', config.nodeRadius)
.attr('cx', 0)
.attr('cy', 0);
svg
.select('#def-commit')
.append('foreignObject')
.attr('width', config.nodeLabel.width)
.attr('height', config.nodeLabel.height)
.attr('x', config.nodeLabel.x)
.attr('y', config.nodeLabel.y)
.attr('class', 'node-label')
.attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility')
.append('p')
.html('');
}
/**
* @param svg
* @param points
* @param colorIdx
* @param interpolate
*/
/**
// Pass in the element and its pre-transform coords
* Draws a text, used for labels of the branches
*
* @param element
* @param coords
* @param {string} txt The text
* @returns {SVGElement}
*/
/**
* @param svg
* @param fromId
* @param toId
* @param direction
* @param color
*/
const drawText = (txt) => {
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
// svgLabel.setAttribute('style', style.replace('color:', 'fill:'));
let rows = [];
let rows = [];
if (typeof txt === 'string') {
rows = txt.split(/\\n|\n|<br\s*\/?>/gi);
} else if (Array.isArray(txt)) {
rows = txt;
} else {
rows = [];
}
for (let j = 0; j < rows.length; j++) {
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', '0');
tspan.setAttribute('class', 'row');
tspan.textContent = rows[j].trim();
svgLabel.appendChild(tspan);
// Handling of new lines in the label
if (typeof txt === 'string') {
rows = txt.split(/\\n|\n|<br\s*\/?>/gi);
} else if (Array.isArray(txt)) {
rows = txt;
} else {
rows = [];
}
/**
* @param svg
* @param selector
*/
for (let j = 0; j < rows.length; j++) {
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', '0');
tspan.setAttribute('class', 'row');
tspan.textContent = rows[j].trim();
svgLabel.appendChild(tspan);
}
/**
* @param svg
* @param selector
*/
return svgLabel;
}
};
/**
* Draws the commits with its symbol and labels. The function has tywo modes, one which only
* calculates the positions and one that does the actual drawing. This for a simple way getting the
* vertical leyering rcorrect in the graph.
*
* @param {any} svg
* @param {any} commits
* @param {any} modifyGraph
*/
const drawCommits = (svg, commits, modifyGraph) => {
const gitGraphConfig = getConfig().gitGraph;
const gBullets = svg.append('g').attr('class', 'commit-bullets');
const gLabels = svg.append('g').attr('class', 'commit-labels');
let pos = 0;
@ -119,20 +79,20 @@ const drawCommits = (svg, commits, modifyGraph) => {
const keys = Object.keys(commits);
const sortedKeys = keys.sort((a, b) => {
return commits[a].seq - commits[b].seq;
})
});
sortedKeys.forEach((key, index) => {
const commit = commits[key];
const y = branchPos[commit.branch].pos;
const x = pos + 10;
// Don't draw the commits now but calculate the positioning which is used by the branmch lines etc.
const x = pos + 10;
// Don't draw the commits now but calculate the positioning which is used by the branch lines etc.
if (modifyGraph) {
let typeClass;
switch(commit.type) {
switch (commit.type) {
case commitType.NORMAL:
typeClass = 'commit-normal';
break;
case commitType.REVERSE:
case commitType.REVERSE:
typeClass = 'commit-reverse';
break;
case commitType.HIGHLIGHT:
@ -147,51 +107,77 @@ const drawCommits = (svg, commits, modifyGraph) => {
if (commit.type === commitType.HIGHLIGHT) {
const circle = gBullets.append('rect');
circle.attr('x', x-10);
circle.attr('y', y-10);
circle.attr('x', x - 10);
circle.attr('y', y - 10);
circle.attr('height', 20);
circle.attr('width', 20);
circle.attr('class', 'commit ' + commit.id + ' commit-highlight' + branchPos[commit.branch].index + ' ' + typeClass+'-outer');
gBullets.append('rect')
.attr('x', x-6)
.attr('y', y-6)
.attr('height', 12)
.attr('width', 12)
.attr('class', 'commit ' + commit.id + ' commit' + branchPos[commit.branch].index + ' ' + typeClass+'-inner');
circle.attr(
'class',
'commit ' +
commit.id +
' commit-highlight' +
branchPos[commit.branch].index +
' ' +
typeClass +
'-outer'
);
gBullets
.append('rect')
.attr('x', x - 6)
.attr('y', y - 6)
.attr('height', 12)
.attr('width', 12)
.attr(
'class',
'commit ' +
commit.id +
' commit' +
branchPos[commit.branch].index +
' ' +
typeClass +
'-inner'
);
} else {
const circle = gBullets.append('circle');
circle.attr('cx', x);
circle.attr('cy', y);
circle.attr('r', commit.type === commitType.MERGE ? 9:10);
circle.attr('class', 'commit ' + commit.id + ' commit' + branchPos[commit.branch].index);
if(commit.type === commitType.MERGE) {
circle.attr('r', commit.type === commitType.MERGE ? 9 : 10);
circle.attr('class', 'commit ' + commit.id + ' commit' + branchPos[commit.branch].index);
if (commit.type === commitType.MERGE) {
const circle2 = gBullets.append('circle');
circle2.attr('cx', x);
circle2.attr('cy', y);
circle2.attr('r', 6);
circle2.attr('class', 'commit '+typeClass + ' ' + commit.id + ' commit' + branchPos[commit.branch].index);
circle2.attr(
'class',
'commit ' + typeClass + ' ' + commit.id + ' commit' + branchPos[commit.branch].index
);
}
if(commit.type === commitType.REVERSE) {
if (commit.type === commitType.REVERSE) {
const cross = gBullets.append('path');
cross
.attr('d', `M ${x-5},${y-5}L${x+5},${y+5}M${x-5},${y+5}L${x+5},${y-5}`)
.attr('class', 'commit '+typeClass + ' ' + commit.id + ' commit' + branchPos[commit.branch].index);
.attr('d', `M ${x - 5},${y - 5}L${x + 5},${y + 5}M${x - 5},${y + 5}L${x + 5},${y - 5}`)
.attr(
'class',
'commit ' + typeClass + ' ' + commit.id + ' commit' + branchPos[commit.branch].index
);
}
}
}
commitPos[commit.id] = {x: pos + 10, y: y};
commitPos[commit.id] = { x: pos + 10, y: y };
// The first iteration over the commits are for positioning purposes, this
// is required for drawing the lines. The circles and labels is drawn after the labels
// placing them on top of the lines.
if (modifyGraph) {
const px=4;
const py=2;
if(commit.type !== commitType.MERGE) {
const labelBkg = gLabels.insert('rect')
.attr('class', 'commit-label-bkg');
const px = 4;
const py = 2;
// Draw the commit label
if (commit.type !== commitType.MERGE && gitGraphConfig.showCommitLabel) {
const labelBkg = gLabels.insert('rect').attr('class', 'commit-label-bkg');
const text = gLabels.append('text')
const text = gLabels
.append('text')
.attr('x', pos)
.attr('y', y + 25)
.attr('class', 'commit-label')
@ -206,48 +192,52 @@ const drawCommits = (svg, commits, modifyGraph) => {
.attr('height', bbox.height + 2 * py);
text.attr('x', pos + 10 - bbox.width / 2);
}
if(commit.tag) {
if (commit.tag) {
const rect = gLabels.insert('polygon');
const hole = gLabels.append('circle');
const tag = gLabels.append('text')
// Note that we are delaying setting the x position until we know the width of the text
.attr('y', y - 16)
.attr('class', 'tag-label')
.text(commit.tag);
const tag = gLabels
.append('text')
// Note that we are delaying setting the x position until we know the width of the text
.attr('y', y - 16)
.attr('class', 'tag-label')
.text(commit.tag);
let tagBbox = tag.node().getBBox();
tag.attr('x', pos + 10 - tagBbox.width / 2);
const h2 = tagBbox.height/2
const ly = y - 19.2 ;
rect
.attr('class', 'tag-label-bkg')
.attr('points', `
${pos - tagBbox.width / 2 - px/2},${ly + py}
${pos - tagBbox.width / 2 - px/2},${ly - py}
const h2 = tagBbox.height / 2;
const ly = y - 19.2;
rect.attr('class', 'tag-label-bkg').attr(
'points',
`
${pos - tagBbox.width / 2 - px / 2},${ly + py}
${pos - tagBbox.width / 2 - px / 2},${ly - py}
${pos + 10 - tagBbox.width / 2 - px},${ly - h2 - py}
${pos + 10 + tagBbox.width / 2 + px},${ly - h2 - py}
${pos + 10 + tagBbox.width / 2 + px},${ly + h2 + py }
${pos + 10 - tagBbox.width / 2 - px},${ly + h2 + py}`);
${pos + 10 + tagBbox.width / 2 + px},${ly + h2 + py}
${pos + 10 - tagBbox.width / 2 - px},${ly + h2 + py}`
);
hole
.attr('cx', pos - tagBbox.width / 2 + px/2)
.attr('cx', pos - tagBbox.width / 2 + px / 2)
.attr('cy', ly)
.attr('r', 1.5)
.attr('class', 'tag-hole');
}
}
pos +=50;
if(pos>maxPos) {
pos += 50;
if (pos > maxPos) {
maxPos = pos;
}
});
}
};
/**
* Detect if there are other commits between commit1s x-position and commit2s x-position on the same branch as commit2.
* @param {*} commit1
* @param {*} commit2
* Detect if there are other commits between commit1s x-position and commit2s x-position on the same
* branch as commit2.
*
* @param {any} commit1
* @param {any} commit2
* @param allCommits
* @returns
*/
const hasOverlappingCommits = (commit1, commit2, allCommits) => {
@ -257,43 +247,62 @@ const hasOverlappingCommits = (commit1, commit2, allCommits) => {
// Find commits on the same branch as commit2
const keys = Object.keys(allCommits);
const overlappingComits = keys.filter((key) => {
return allCommits[key].branch === commit2.branch && allCommits[key].seq > commit1.seq && allCommits[key].seq < commit2.seq
return (
allCommits[key].branch === commit2.branch &&
allCommits[key].seq > commit1.seq &&
allCommits[key].seq < commit2.seq
);
});
return overlappingComits.length > 0;
}
};
/**
* This function find a lane in the y-axis that is not overlapping with any other lanes. This is
* used for drawing the lines between commits.
*
* @param {any} y1
* @param {any} y2
* @param {any} _depth
* @returns
*/
const findLane = (y1, y2, _depth) => {
const depth = _depth || 0;
const candidate = y1 + Math.abs(y1 - y2) / 2;
if(depth > 5) {
const candidate = y1 + Math.abs(y1 - y2) / 2;
if (depth > 5) {
return candidate;
}
let ok = true;
for(let i = 0; i < lanes.length; i++) {
if(Math.abs(lanes[i] - candidate) < 10) {
for (let i = 0; i < lanes.length; i++) {
if (Math.abs(lanes[i] - candidate) < 10) {
ok = false;
}
}
if(ok) {
if (ok) {
lanes.push(candidate);
return candidate;
}
const diff = Math.abs(y1 - y2);
return findLane(y1, y2-(diff/5), depth);
}
return findLane(y1, y2 - diff / 5, depth);
};
/**
* This function draw trhe lines between the commits. They were arrows initially.
*
* @param {any} svg
* @param {any} commit1
* @param {any} commit2
* @param {any} allCommits
*/
const drawArrow = (svg, commit1, commit2, allCommits) => {
const conf = getConfig();
const p1 = commitPos[commit1.id];
const p2 = commitPos[commit2.id];
const overlappingCommits = hasOverlappingCommits(commit1, commit2, allCommits);
log.debug('drawArrow', p1, p2, overlappingCommits, commit1.id, commit2.id);
// log.debug('drawArrow', p1, p2, overlappingCommits, commit1.id, commit2.id);
let url = '';
if (conf.arrowMarkerAbsolute) {
@ -310,28 +319,30 @@ const drawArrow = (svg, commit1, commit2, allCommits) => {
let arc = '';
let arc2 = '';
let radius = 0;
let offset = 0
let colorClassNum = branchPos[commit2.branch].index
let offset = 0;
let colorClassNum = branchPos[commit2.branch].index;
let lineDef;
if(overlappingCommits) {
arc = 'A 10 10, 0, 0, 0,';
arc2 = 'A 10 10, 0, 0, 1,';
radius = 10;
offset = 10;
if (overlappingCommits) {
arc = 'A 10 10, 0, 0, 0,';
arc2 = 'A 10 10, 0, 0, 1,';
radius = 10;
offset = 10;
// Figure out the color of the arrow,arrows going down take the color from the destination branch
colorClassNum = branchPos[commit2.branch].index;
colorClassNum = branchPos[commit2.branch].index;
const lineY = p1.y < p2.y ? findLane(p1.y, p2.y):findLane(p2.y, p1.y);
if(p1.y < p2.y) {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY-radius} ${arc} ${p1.x + offset} ${lineY} L ${p2.x-radius} ${lineY} ${arc2} ${p2.x} ${lineY+offset} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY+radius} ${arc2} ${p1.x + offset} ${lineY} L ${p2.x-radius} ${lineY} ${arc} ${p2.x} ${lineY-offset} L ${p2.x} ${p2.y}`;
}
const lineY = p1.y < p2.y ? findLane(p1.y, p2.y) : findLane(p2.y, p1.y);
if (p1.y < p2.y) {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY - radius} ${arc} ${p1.x + offset} ${lineY} L ${
p2.x - radius
} ${lineY} ${arc2} ${p2.x} ${lineY + offset} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY + radius} ${arc2} ${
p1.x + offset
} ${lineY} L ${p2.x - radius} ${lineY} ${arc} ${p2.x} ${lineY - offset} L ${p2.x} ${p2.y}`;
}
} else {
if(p1.y < p2.y) {
if (p1.y < p2.y) {
arc = 'A 20 20, 0, 0, 0,';
radius = 20;
offset = 20;
@ -339,26 +350,34 @@ const drawArrow = (svg, commit1, commit2, allCommits) => {
// Figure out the color of the arrow,arrows going down take the color from the destination branch
colorClassNum = branchPos[commit2.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y-radius} ${arc} ${p1.x + offset} ${p2.y} L ${p2.x} ${p2.y}`;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${p2.y} L ${
p2.x
} ${p2.y}`;
}
if(p1.y > p2.y) {
if (p1.y > p2.y) {
arc = 'A 20 20, 0, 0, 0,';
radius = 20;
offset = 20;
// Arrows going up take the color from the source branch
colorClassNum = branchPos[commit1.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p2.x-radius} ${p1.y} ${arc} ${p2.x} ${p1.y-offset} L ${p2.x} ${p2.y}`;
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${p1.y - offset} L ${
p2.x
} ${p2.y}`;
}
if(p1.y === p2.y) {
colorClassNum = branchPos[commit1.branch].index
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y-radius} ${arc} ${p1.x + offset} ${p2.y} L ${p2.x} ${p2.y}`;
if (p1.y === p2.y) {
colorClassNum = branchPos[commit1.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${p2.y} L ${
p2.x
} ${p2.y}`;
}
}
const arrow = svg.append('path').attr('d', lineDef)
.attr('class', 'arrow arrow' + colorClassNum)
}
const arrow = svg
.append('path')
.attr('d', lineDef)
.attr('class', 'arrow arrow' + colorClassNum);
};
const drawArrows = (svg, commits) => {
const gArrows = svg.append('g').attr('class', 'commit-arrows');
@ -367,123 +386,114 @@ const drawArrows = (svg, commits) => {
const k = Object.keys(commits);
k.forEach((key, index) => {
const commit = commits[key];
if(commit.parents && commit.parents.length>0) {
if (commit.parents && commit.parents.length > 0) {
commit.parents.forEach((parent) => {
drawArrow(gArrows, commits[parent], commit, commits);
});
}
});
}
};
/**
* This function adds the branches and the branches' labels to the svg.
*
* @param svg
* @param commitid
* @param branches
* @param direction
*/
const drawBranches = (svg, branches) => {
const g = svg.append('g')
branches.forEach((branch, index) => {
const pos = branchPos[branch.name].pos;
const line = g.append('line');
line.attr('x1', 0);
line.attr('y1', pos);
line.attr('x2', maxPos);
line.attr('y2', pos);
line.attr('class', 'branch branch'+index)
const gitGraphConfig = getConfig().gitGraph;
const g = svg.append('g');
branches.forEach((branch, index) => {
const pos = branchPos[branch.name].pos;
const line = g.append('line');
line.attr('x1', 0);
line.attr('y1', pos);
line.attr('x2', maxPos);
line.attr('y2', pos);
line.attr('class', 'branch branch' + index);
lanes.push(pos);
lanes.push(pos);
// Create the actual text element
const labelElement = drawText(branch.name);
// Create outer g, edgeLabel, this will be positioned after graph layout
const bkg = g.insert('rect');
const branchLabel = g.insert('g').attr('class', 'branchLabel');
let name = index === 0 ? gitGraphConfig.mainBranchName : branch.name;
// Create inner g, label, this will be positioned now for centering the text
const label = branchLabel.insert('g').attr('class', 'label branch-label'+index);
label.node().appendChild(labelElement);
let bbox = labelElement.getBBox();
bkg.attr('class', 'branchLabelBkg label' + index)
.attr('rx', 4)
.attr('ry', 4)
.attr('x', -bbox.width -4)
.attr('y', -bbox.height / 2 +8 )
.attr('width', bbox.width + 18)
.attr('height', bbox.height + 4);
// Create the actual text element
const labelElement = drawText(name);
// Create outer g, edgeLabel, this will be positioned after graph layout
const bkg = g.insert('rect');
const branchLabel = g.insert('g').attr('class', 'branchLabel');
label.attr('transform', 'translate(' + (-bbox.width -14) + ', ' + (pos - bbox.height/2-1) + ')');
bkg.attr('transform', 'translate(' + -19 + ', ' + (pos - bbox.height/2) + ')');
})
// Create inner g, label, this will be positioned now for centering the text
const label = branchLabel.insert('g').attr('class', 'label branch-label' + index);
label.node().appendChild(labelElement);
let bbox = labelElement.getBBox();
bkg
.attr('class', 'branchLabelBkg label' + index)
.attr('rx', 4)
.attr('ry', 4)
.attr('x', -bbox.width - 4)
.attr('y', -bbox.height / 2 + 8)
.attr('width', bbox.width + 18)
.attr('height', bbox.height + 4);
}
label.attr(
'transform',
'translate(' + (-bbox.width - 14) + ', ' + (pos - bbox.height / 2 - 1) + ')'
);
bkg.attr('transform', 'translate(' + -19 + ', ' + (pos - bbox.height / 2) + ')');
});
};
/**
* @param svg
* @param commit
* @param direction
* @param branchColor
* @param txt
* @param id
* @param ver
*/
export const draw = function (txt, id, ver) {
clear();
const conf = getConfig();
const config = conf.gitGraph;
const gitGraphConfig = getConfig().gitGraph;
// try {
const parser = gitGraphParser.parser;
parser.yy = db;
parser.yy.clear();
log.debug('in gitgraph renderer', txt + '\n', 'id:', id, ver);
log.debug('in gitgraph renderer', txt + '\n', 'id:', id, ver);
// // Parse the graph definition
parser.parse(txt + '\n');
// config = Object.assign(config, apiConfig, db.getOptions());
const direction = db.getDirection();
allCommitsDict = db.getCommits();
const branches = db.getBranchesAsObjArray();
// Position branches vertically
let pos=0;
let pos = 0;
branches.forEach((branch, index) => {
branchPos[branch.name] = {pos, index};
pos+=50;
branchPos[branch.name] = { pos, index };
pos += 50;
});
log.debug('brach pos ', branchPos);
log.debug('effective options', config, branches);
log.debug('commits', allCommitsDict);
const diagram = select(`[id="${id}"]`);
svgCreateDefs(diagram);
diagram
.append('defs')
.append('marker')
.attr('id', 'arrowhead')
.attr('refX',24)
.attr('refY', 10)
.attr('markerUnits', 'userSpaceOnUse')
.attr('markerWidth', 24)
.attr('markerHeight', 24)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 0 0 L 20 10 L 0 20 z'); // this is actual shape for arrowhead
drawCommits(diagram, allCommitsDict, false);
drawBranches(diagram, branches);
if (gitGraphConfig.showBranches) {
drawBranches(diagram, branches);
}
drawArrows(diagram, allCommitsDict);
drawCommits(diagram, allCommitsDict, true);
const padding = config.diagramPadding;
const padding = gitGraphConfig.diagramPadding;
const svgBounds = diagram.node().getBBox();
const width = svgBounds.width + padding * 2;
const height = svgBounds.height + padding * 2;
configureSvgSize(diagram, height, width, conf.useMaxWidth);
const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
// logger.debug(`viewBox ${vBox}`);
diagram.attr('viewBox', vBox);
};

View File

@ -2,7 +2,6 @@ import { log } from '../../logger';
import mermaidAPI from '../../mermaidAPI';
import * as configApi from '../../config';
import common from '../common/common';
const sanitizeText = (txt) => common.sanitizeText(txt, configApi.getConfig());
let sections = {};
let title = '';

View File

@ -21,6 +21,9 @@
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
"title"\s[^#\n;]+ return 'title';
"accDescription"\s[^#\n;]+ return 'accDescription';
(\r?\n)+ return 'NEWLINE';
\s+ /* skip all whitespace */
\#[^\n]* /* skip comments */
@ -90,7 +93,9 @@ start
directive
: openDirective typeDirective closeDirective
| openDirective typeDirective ':' argDirective closeDirective;
| openDirective typeDirective ':' argDirective closeDirective
| title {yy.setTitle($1.substring(6));$$=$1.substring(6);}
| accDescription {yy.setAccDescription($1.substring(15));$$=$1.substring(15);};
openDirective
: open_directive { yy.parseDirective('%%{', 'open_directive'); };
@ -191,6 +196,7 @@ relationship
| TRACES
{ $$=yy.Relationships.TRACES;};
requirementName: unqString | qString;
id : unqString | qString;
text : unqString | qString;

View File

@ -72,6 +72,29 @@ describe('when parsing requirement diagram it...', function () {
expect(Object.keys(requirementDb.getRelationships()).length).toBe(0);
});
it('will use a title and accDescription', function () {
const expectedTitle = 'test title';
const expectedAccDescription = 'my chart description';
const expectedDocRef = 'test_ref';
let lines = [
`requirementDiagram`,
``,
`title ${expectedTitle}`,
`accDescription ${expectedAccDescription}`,
`element test_name {`,
`type: test_type`,
`docref: test_ref`,
`}`,
];
let doc = lines.join('\n');
reqDiagram.parser.parse(doc);
expect(requirementDb.getTitle()).toBe(expectedTitle);
expect(requirementDb.getAccDescription()).toBe(expectedAccDescription);
});
it('will accept full relationship definition', function () {
const expectedSrc = 'a';
const expectedDest = 'b';

View File

@ -1,12 +1,17 @@
import * as configApi from '../../config';
import { log } from '../../logger';
import mermaidAPI from '../../mermaidAPI';
import common from '../common/common';
let relations = [];
let latestRequirement = {};
let requirements = {};
let latestElement = {};
let elements = {};
let title = '';
let accDescription = '';
const sanitizeText = (txt) => common.sanitizeText(txt, configApi.getConfig());
const RequirementType = {
REQUIREMENT: 'Requirement',
@ -134,6 +139,24 @@ const clear = () => {
elements = {};
};
export const setTitle = function (txt) {
let sanitizedText = sanitizeText(txt, configApi.getConfig());
title = sanitizedText;
};
export const getTitle = function () {
return title;
};
export const setAccDescription = function (txt) {
let sanitizedText = sanitizeText(txt, configApi.getConfig());
accDescription = sanitizedText;
};
export const getAccDescription = function () {
return accDescription;
};
export default {
RequirementType,
RiskLevel,
@ -149,6 +172,10 @@ export default {
setNewReqText,
setNewReqRisk,
setNewReqVerifyMethod,
setTitle,
getTitle,
setAccDescription,
getAccDescription,
addElement,
getElements,

View File

@ -9,6 +9,7 @@ import { parser } from './parser/requirementDiagram';
import requirementDb from './requirementDb';
import markers from './requirementMarkers';
import { getConfig } from '../../config';
import addSVGAccessibilityFields from '../../accessibility';
const conf = {};
let relCnt = 0;
@ -377,6 +378,8 @@ export const draw = (text, id) => {
configureSvgSize(svg, height, width, conf.useMaxWidth);
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
// Adds title and description to the requirements diagram
addSVGAccessibilityFields(parser.yy, svg, id);
};
export default {

View File

@ -21,7 +21,7 @@ describe('when parsing a sequenceDiagram', function () {
parser.yy = sequenceDb;
parser.yy.clear();
});
it('it should handle a sequenceDiagram definition', function () {
it('should handle a sequenceDiagram definition', function () {
const str = `
sequenceDiagram
Alice->Bob:Hello Bob, how are you?

View File

@ -272,20 +272,65 @@ const actorFont = (cnf) => {
};
/**
* Draws a message
* Process a message by adding its dimensions to the bound. It returns the Y coordinate of the
* message so it can be drawn later. We do not draw the message at this point so the arrowhead can
* be on top of the activation box.
*
* @param {any} g - The parent of the message element
* @param {any} diagram - The parent of the message element
* @param {any} msgModel - The model containing fields describing a message
* @returns {number} LineStarty - The Y coordinate at which the message line starts
*/
const drawMessage = function (g, msgModel) {
const boundMessage = function (diagram, msgModel) {
bounds.bumpVerticalPos(10);
const { startx, stopx, starty, message, type, sequenceIndex } = msgModel;
const { startx, stopx, message } = msgModel;
const lines = common.splitBreaks(message).length;
let textDims = utils.calculateTextDimensions(message, messageFont(conf));
const lineHeight = textDims.height / lines;
msgModel.height += lineHeight;
bounds.bumpVerticalPos(lineHeight);
let lineStarty;
let totalOffset = textDims.height - 10;
let textWidth = textDims.width;
if (startx === stopx) {
lineStarty = bounds.getVerticalPos() + totalOffset;
if (!conf.rightAngles) {
totalOffset += conf.boxMargin;
lineStarty = bounds.getVerticalPos() + totalOffset;
}
totalOffset += 30;
const dx = Math.max(textWidth / 2, conf.width / 2);
bounds.insert(
startx - dx,
bounds.getVerticalPos() - 10 + totalOffset,
stopx + dx,
bounds.getVerticalPos() + 30 + totalOffset
);
} else {
totalOffset += conf.boxMargin;
lineStarty = bounds.getVerticalPos() + totalOffset;
bounds.insert(startx, lineStarty - 10, stopx, lineStarty);
}
bounds.bumpVerticalPos(totalOffset);
msgModel.height += totalOffset;
msgModel.stopy = msgModel.starty + msgModel.height;
bounds.insert(msgModel.fromBounds, msgModel.starty, msgModel.toBounds, msgModel.stopy);
return lineStarty;
};
/**
* Draws a message. Note that the bounds have previously been updated by boundMessage.
*
* @param {any} diagram - The parent of the message element
* @param {any} msgModel - The model containing fields describing a message
* @param {float} lineStarty - The Y coordinate at which the message line starts
*/
const drawMessage = function (diagram, msgModel, lineStarty) {
const { startx, stopx, starty, message, type, sequenceIndex } = msgModel;
let textDims = utils.calculateTextDimensions(message, messageFont(conf));
const textObj = svgDraw.getTextObj();
textObj.x = startx;
textObj.y = starty + 10;
@ -301,17 +346,14 @@ const drawMessage = function (g, msgModel) {
textObj.textMargin = conf.wrapPadding;
textObj.tspan = false;
drawText(g, textObj);
let totalOffset = textDims.height - 10;
drawText(diagram, textObj);
let textWidth = textDims.width;
let line, lineStarty;
let line;
if (startx === stopx) {
lineStarty = bounds.getVerticalPos() + totalOffset;
if (conf.rightAngles) {
line = g
line = diagram
.append('path')
.attr(
'd',
@ -320,10 +362,7 @@ const drawMessage = function (g, msgModel) {
} H ${startx}`
);
} else {
totalOffset += conf.boxMargin;
lineStarty = bounds.getVerticalPos() + totalOffset;
line = g
line = diagram
.append('path')
.attr(
'd',
@ -345,24 +384,12 @@ const drawMessage = function (g, msgModel) {
(lineStarty + 20)
);
}
totalOffset += 30;
const dx = Math.max(textWidth / 2, conf.width / 2);
bounds.insert(
startx - dx,
bounds.getVerticalPos() - 10 + totalOffset,
stopx + dx,
bounds.getVerticalPos() + 30 + totalOffset
);
} else {
totalOffset += conf.boxMargin;
lineStarty = bounds.getVerticalPos() + totalOffset;
line = g.append('line');
line = diagram.append('line');
line.attr('x1', startx);
line.attr('y1', lineStarty);
line.attr('x2', stopx);
line.attr('y2', lineStarty);
bounds.insert(startx, lineStarty - 10, stopx, lineStarty);
}
// Make an SVG Container
// Draw the line
@ -407,7 +434,8 @@ const drawMessage = function (g, msgModel) {
// add node number
if (sequenceDb.showSequenceNumbers() || conf.showSequenceNumbers) {
line.attr('marker-start', 'url(' + url + '#sequencenumber)');
g.append('text')
diagram
.append('text')
.attr('x', startx)
.attr('y', lineStarty + 4)
.attr('font-family', 'sans-serif')
@ -417,10 +445,6 @@ const drawMessage = function (g, msgModel) {
.attr('class', 'sequenceNumber')
.text(sequenceIndex);
}
bounds.bumpVerticalPos(totalOffset);
msgModel.height += totalOffset;
msgModel.stopy = msgModel.starty + msgModel.height;
bounds.insert(msgModel.fromBounds, msgModel.starty, msgModel.toBounds, msgModel.stopy);
};
export const drawActors = function (diagram, actors, actorKeys, verticalPos) {
@ -613,6 +637,7 @@ export const draw = function (text, id) {
// Draw the messages/signals
let sequenceIndex = 1;
let messagesToDraw = Array();
messages.forEach(function (msg) {
let loopModel, noteModel, msgModel;
@ -722,7 +747,8 @@ export const draw = function (text, id) {
msgModel = msg.msgModel;
msgModel.starty = bounds.getVerticalPos();
msgModel.sequenceIndex = sequenceIndex;
drawMessage(diagram, msgModel);
let lineStarty = boundMessage(diagram, msgModel);
messagesToDraw.push({ messageModel: msgModel, lineStarty: lineStarty });
bounds.models.addMessage(msgModel);
} catch (e) {
log.error('error while drawing message', e);
@ -746,6 +772,8 @@ export const draw = function (text, id) {
}
});
messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStarty));
if (conf.mirrorActors) {
// Draw actors below diagram
bounds.bumpVerticalPos(conf.boxMargin * 2);

View File

@ -20,6 +20,8 @@
%x STATE_ID
%x ALIAS
%x SCALE
%x title
%x accDescription
%x NOTE
%x NOTE_ID
%x NOTE_TEXT
@ -58,6 +60,11 @@
<SCALE>\d+ return 'WIDTH';
<SCALE>\s+"width" {this.popState();}
title { this.begin("title");return 'title'; }
<title>(?!\n|;|#)*[^\n]* { this.popState(); return "title_value"; }
accDescription { this.begin("accDescription");return 'accDescription'; }
<accDescription>(?!\n|;|#)*[^\n]* { this.popState(); return "description_value"; }
<INITIAL,struct>"state"\s+ { /*console.log('Starting STATE zxzx'+yy.getDirection());*/this.pushState('STATE'); }
<STATE>.*"<<fork>>" {this.popState();yytext=yytext.slice(0,-8).trim(); /*console.warn('Fork Fork: ',yytext);*/return 'FORK';}
<STATE>.*"<<join>>" {this.popState();yytext=yytext.slice(0,-8).trim();/*console.warn('Fork Join: ',yytext);*/return 'JOIN';}
@ -193,6 +200,8 @@ statement
| note NOTE_TEXT AS ID
| directive
| direction
| title title_value { $$=$2.trim();yy.setTitle($$); }
| accDescription description_value { $$=$2.trim();yy.setAccDescription($$); }
;
directive

View File

@ -4,6 +4,8 @@ import mermaidAPI from '../../mermaidAPI';
import common from '../common/common';
import * as configApi from '../../config';
const sanitizeText = (txt) => common.sanitizeText(txt, configApi.getConfig());
const clone = (o) => JSON.parse(JSON.stringify(o));
let rootDoc = [];
@ -115,6 +117,25 @@ let startCnt = 0;
let endCnt = 0; // eslint-disable-line
// let stateCnt = 0;
let title = 'State diagram';
let description = '';
const setTitle = function (txt) {
title = sanitizeText(txt);
};
const getTitle = function () {
return title;
};
const setAccDescription = function (txt) {
description = sanitizeText(txt);
};
const getAccDescription = function () {
return description;
};
/**
* Function called by parser when a node definition has been found.
*
@ -280,4 +301,8 @@ export default {
getRootDocV2,
extract,
trimColon,
getTitle,
setTitle,
getAccDescription,
setAccDescription,
};

View File

@ -0,0 +1,376 @@
import { parser } from './parser/stateDiagram';
import stateDb from './stateDb';
describe('state diagram, ', function () {
describe('when parsing an info graph it', function () {
beforeEach(function () {
parser.yy = stateDb;
});
it('super simple', function () {
const str = `
stateDiagram-v2
[*] --> State1
State1 --> [*]
`;
parser.parse(str);
});
it('simple', function () {
const str = `stateDiagram-v2\n
State1 : this is another string
[*] --> State1
State1 --> [*]
`;
parser.parse(str);
const description = stateDb.getAccDescription();
expect(description).toBe('');
});
it('simple with accDescription', function () {
const str = `stateDiagram-v2\n
accDescription a simple description of the diagram
State1 : this is another string
[*] --> State1
State1 --> [*]
`;
parser.parse(str);
const description = stateDb.getAccDescription();
expect(description).toBe('a simple description of the diagram');
});
it('simple with title', function () {
const str = `stateDiagram-v2\n
title a simple title of the diagram
State1 : this is another string
[*] --> State1
State1 --> [*]
`;
parser.parse(str);
const title = stateDb.getTitle();
expect(title).toBe('a simple title of the diagram');
});
it('simple with directive', function () {
const str = `%%{init: {'logLevel': 0 }}%%
stateDiagram-v2\n
State1 : this is another string
[*] --> State1
State1 --> [*]
`;
parser.parse(str);
});
it('should handle relation definitions', function () {
const str = `stateDiagram-v2\n
[*] --> State1
State1 --> [*]
State1 : this is a string
State1 : this is another string
State1 --> State2
State2 --> [*]
`;
parser.parse(str);
});
it('hide empty description', function () {
const str = `stateDiagram-v2\n
hide empty description
[*] --> State1
State1 --> [*]
State1 : this is a string
State1 : this is another string
State1 --> State2
State2 --> [*]
`;
parser.parse(str);
});
it('handle "as" in state names', function () {
const str = `stateDiagram-v2
assemble
state assemble
`;
parser.parse(str);
});
it('handle "as" in state names 1', function () {
const str = `stateDiagram-v2
assemble
state assemble
`;
parser.parse(str);
});
it('handle "as" in state names 2', function () {
const str = `stateDiagram-v2
assembleas
state assembleas
`;
parser.parse(str);
});
it('handle "as" in state names 3', function () {
const str = `stateDiagram-v2
state "as" as as
`;
parser.parse(str);
});
it('scale', function () {
const str = `stateDiagram-v2\n
scale 350 width
[*] --> State1
State1 --> [*]
State1 : this is a string with - in it
State1 : this is another string
State1 --> State2
State2 --> [*]
`;
parser.parse(str);
});
it('description after second state', function () {
const str = `stateDiagram-v2\n
scale 350 width
[*] --> State1 : This is the description with - in it
State1 --> [*]
`;
parser.parse(str);
})
it('shall handle descriptions including minus signs', function () {
const str = `stateDiagram-v2\n
scale 350 width
[*] --> State1 : This is the description +-!
State1 --> [*]
`;
parser.parse(str);
});
it('should handle state statements', function () {
const str = `stateDiagram-v2\n
state Configuring {
[*] --> NewValueSelection
NewValueSelection --> NewValuePreview : EvNewValue
NewValuePreview --> NewValueSelection : EvNewValueRejected
NewValuePreview --> NewValueSelection : EvNewValueSaved1
}
`;
parser.parse(str);
});
it('should handle recursive state definitions', function () {
const str = `stateDiagram-v2\n
state Configuring {
[*] --> NewValueSelection
NewValueSelection --> NewValuePreview : EvNewValue
NewValuePreview --> NewValueSelection : EvNewValueRejected
NewValuePreview --> NewValueSelection : EvNewValueSaved
state NewValuePreview {
State1 --> State2
}
}
`;
parser.parse(str);
});
it('should handle multiple recursive state definitions', function () {
const str = `stateDiagram-v2\n
scale 350 width
[*] --> NotShooting
state NotShooting {
[*] --> Idle
Idle --> Configuring : EvConfig
Configuring --> Idle : EvConfig
}
state Configuring {
[*] --> NewValueSelection
NewValueSelection --> NewValuePreview : EvNewValue
NewValuePreview --> NewValueSelection : EvNewValueRejected
NewValuePreview --> NewValueSelection : EvNewValueSaved
state NewValuePreview {
State1 --> State2
}
}
`;
parser.parse(str);
});
it('should handle state deifintions with separation of id', function () {
const str = `stateDiagram-v2\n
state "Long state description" as state1
`;
parser.parse(str);
});
it('should handle state deifintions with separation of id', function () {
const str = `stateDiagram-v2
state "Not Shooting State" as NotShooting {
state "Idle mode" as Idle
state "Configuring mode" as Configuring
[*] --> Idle
Idle --> Configuring : EvConfig
Configuring --> Idle : EvConfig
}
`;
parser.parse(str);
});
it('should State definition with quotes', function () {
const str = `stateDiagram-v2\n
scale 600 width
[*] --> State1
State1 --> State2 : Succeeded
State1 --> [*] : Aborted
State2 --> State3 : Succeeded
State2 --> [*] : Aborted
state State3 {
state "Accumulate Enough Data\nLong State Name" as long1
long1 : Just a test
[*] --> long1
long1 --> long1 : New Data
long1 --> ProcessData : Enough Data
}
State3 --> State3 : Failed
State3 --> [*] : Succeeded / Save Result
State3 --> [*] : Aborted
`;
parser.parse(str);
});
it('should handle fork statements', function () {
const str = `stateDiagram-v2\n
state fork_state <<fork>>
[*] --> fork_state
fork_state --> State2
fork_state --> State3
state join_state <<join>>
State2 --> join_state
State3 --> join_state
join_state --> State4
State4 --> [*]
`;
parser.parse(str);
});
it('should handle concurrent state', function () {
const str = `stateDiagram-v2\n
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
`;
parser.parse(str);
});
it('should handle concurrent state', function () {
const str = `stateDiagram-v2\n
[*] --> Active
state Active {
[*] --> NumLockOff
--
[*] --> CapsLockOff
--
[*] --> ScrollLockOff
}
`;
parser.parse(str);
});
// it('should handle arrow directions definitions', function() {
// const str = `stateDiagram-v2\n
// [*] -up-> First
// First -right-> Second
// Second --> Third
// Third -left-> Last
// `;
// parser.parse(str);
// });
it('should handle note statements', function () {
const str = `stateDiagram-v2\n
[*] --> Active
Active --> Inactive
note left of Active : this is a short<br/>note
note right of Inactive
A note can also
be defined on
several lines
end note
`;
parser.parse(str);
});
it('should handle multiline notes with different line breaks', function () {
const str = `stateDiagram-v2
State1
note right of State1
Line1<br>Line2<br/>Line3<br />Line4<br />Line5
end note
`;
parser.parse(str);
});
it('should handle floating notes', function () {
const str = `stateDiagram-v2
foo: bar
note "This is a floating note" as N1
`;
parser.parse(str);
});
it('should handle floating notes', function () {
const str = `stateDiagram-v2\n
state foo
note "This is a floating note" as N1
`;
parser.parse(str);
});
it('should handle notes for composit states', function () {
const str = `stateDiagram-v2\n
[*] --> NotShooting
state "Not Shooting State" as NotShooting {
state "Idle mode" as Idle
state "Configuring mode" as Configuring
[*] --> Idle
Idle --> Configuring : EvConfig
Configuring --> Idle : EvConfig
}
note right of NotShooting : This is a note on a composite state
`;
parser.parse(str);
});
});
});

View File

@ -24,6 +24,32 @@ describe('state diagram, ', function () {
`;
parser.parse(str);
const description = stateDb.getAccDescription();
expect(description).toBe('');
});
it('simple with accDescription', function () {
const str = `stateDiagram\n
accDescription a simple description of the diagram
State1 : this is another string
[*] --> State1
State1 --> [*]
`;
parser.parse(str);
const description = stateDb.getAccDescription();
expect(description).toBe('a simple description of the diagram');
});
it('simple with title', function () {
const str = `stateDiagram\n
title a simple title of the diagram
State1 : this is another string
[*] --> State1
State1 --> [*]
`;
parser.parse(str);
const title = stateDb.getTitle();
expect(title).toBe('a simple title of the diagram');
});
it('simple with directive', function () {
const str = `%%{init: {'logLevel': 0 }}%%
@ -119,7 +145,7 @@ describe('state diagram, ', function () {
parser.parse(str);
});
it('shall handle descriptions inkluding minus signs', function () {
it('shall handle descriptions including minus signs', function () {
const str = `stateDiagram\n
scale 350 width
[*] --> State1 : This is the description +-!

View File

@ -7,6 +7,7 @@ import { render } from '../../dagre-wrapper/index.js';
import { log } from '../../logger';
import { configureSvgSize } from '../../utils';
import common from '../common/common';
import addSVGAccessibilityFields from '../../accessibility';
const conf = {};
export const setConf = function (cnf) {
@ -336,6 +337,7 @@ export const draw = function (text, id) {
label.insertBefore(rect, label.firstChild);
// }
}
addSVGAccessibilityFields(parser.yy, svg, id);
};
export default {

View File

@ -9,6 +9,7 @@ import { parser } from './parser/stateDiagram';
import { drawState, addTitleAndBox, drawEdge } from './shapes';
import { getConfig } from '../../config';
import { configureSvgSize } from '../../utils';
import addSVGAccessibilityFields from '../../accessibility';
parser.yy = stateDb;
@ -97,6 +98,7 @@ export const draw = function (text, id) {
'viewBox',
`${bounds.x - conf.padding} ${bounds.y - conf.padding} ` + width + ' ' + height
);
addSVGAccessibilityFields(parser.yy, diagram, id);
};
const getLabelWidth = (text) => {
return text ? text.length * conf.fontSizeFactor : 1;

View File

@ -72,14 +72,14 @@ function parse(text) {
const graphInit = utils.detectInit(text, cnf);
if (graphInit) {
reinitialize(graphInit);
log.debug('reinit ', graphInit);
log.info('reinit ', graphInit);
}
const graphType = utils.detectType(text, cnf);
let parser;
log.debug('Type ' + graphType);
switch (graphType) {
case 'git':
case 'gitGraph':
parser = gitGraphParser;
parser.parser.yy = gitGraphAst;
break;
@ -229,6 +229,9 @@ const render = function (id, _txt, cb, container) {
configApi.addDirective(graphInit);
}
let cnf = configApi.getConfig();
log.debug(cnf);
// Check the maximum allowed text size
if (_txt.length > cnf.maxTextSize) {
txt = 'graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa';
@ -422,7 +425,7 @@ const render = function (id, _txt, cb, container) {
try {
switch (graphType) {
case 'git':
case 'gitGraph':
// cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
//gitGraphRenderer.setConf(cnf.git);
gitGraphRenderer.draw(txt, id, false);

View File

@ -2,7 +2,7 @@ import classDiagram from './diagrams/class/styles';
import er from './diagrams/er/styles';
import flowchart from './diagrams/flowchart/styles';
import gantt from './diagrams/gantt/styles';
import git from './diagrams/git/styles';
import gitGraph from './diagrams/git/styles';
import info from './diagrams/info/styles';
import pie from './diagrams/pie/styles';
import requirement from './diagrams/requirement/styles';
@ -20,7 +20,7 @@ const themes = {
class: classDiagram,
stateDiagram,
state: stateDiagram,
git,
gitGraph,
info,
pie,
er,

View File

@ -206,14 +206,14 @@ class Theme {
this.git6 = darken(this.git6, 25);
this.git7 = darken(this.git7, 25);
}
this.gitInv0 = invert(this.git0);
this.gitInv1 = invert(this.git1);
this.gitInv2 = invert(this.git2);
this.gitInv3 = invert(this.git3);
this.gitInv4 = invert(this.git4);
this.gitInv5 = invert(this.git5);
this.gitInv6 = invert(this.git6);
this.gitInv7 = invert(this.git7);
this.gitInv0 = this.gitInv0 || invert(this.git0);
this.gitInv1 = this.gitInv1 || invert(this.git1);
this.gitInv2 = this.gitInv2 || invert(this.git2);
this.gitInv3 = this.gitInv3 || invert(this.git3);
this.gitInv4 = this.gitInv4 || invert(this.git4);
this.gitInv5 = this.gitInv5 || invert(this.git5);
this.gitInv6 = this.gitInv6 || invert(this.git6);
this.gitInv7 = this.gitInv7 || invert(this.git7);
this.branchLabelColor =
this.branchLabelColor || (this.darkMode ? 'black' : this.labelTextColor);
this.gitBranchLabel0 = this.gitBranchLabel0 || this.branchLabelColor;

View File

@ -197,14 +197,14 @@ class Theme {
this.git5 = lighten(this.pie6 || adjust(this.primaryColor, { h: -90 }), 10);
this.git6 = lighten(this.pie7 || adjust(this.primaryColor, { h: +60 }), 10);
this.git7 = lighten(this.pie8 || adjust(this.primaryColor, { h: +120 }), 20);
this.gitInv0 = invert(this.git0);
this.gitInv1 = invert(this.git1);
this.gitInv2 = invert(this.git2);
this.gitInv3 = invert(this.git3);
this.gitInv4 = invert(this.git4);
this.gitInv5 = invert(this.git5);
this.gitInv6 = invert(this.git6);
this.gitInv7 = invert(this.git7);
this.gitInv0 = this.gitInv0 || invert(this.git0);
this.gitInv1 = this.gitInv1 || invert(this.git1);
this.gitInv2 = this.gitInv2 || invert(this.git2);
this.gitInv3 = this.gitInv3 || invert(this.git3);
this.gitInv4 = this.gitInv4 || invert(this.git4);
this.gitInv5 = this.gitInv5 || invert(this.git5);
this.gitInv6 = this.gitInv6 || invert(this.git6);
this.gitInv7 = this.gitInv7 || invert(this.git7);
this.tagLabelColor = this.tagLabelColor || this.primaryTextColor;
this.tagLabelBackground = this.tagLabelBackground || this.primaryColor;

View File

@ -228,22 +228,22 @@ class Theme {
this.git6 = darken(this.git6, 25);
this.git7 = darken(this.git7, 25);
}
this.gitInv0 = darken(invert(this.git0), 25);
this.gitInv1 = invert(this.git1);
this.gitInv2 = invert(this.git2);
this.gitInv3 = invert(this.git3);
this.gitInv4 = invert(this.git4);
this.gitInv5 = invert(this.git5);
this.gitInv6 = invert(this.git6);
this.gitInv7 = invert(this.git7);
this.gitBranchLabel0 = invert(this.labelTextColor);
this.gitBranchLabel1 = this.labelTextColor;
this.gitBranchLabel2 = this.labelTextColor;
this.gitBranchLabel3 = invert(this.labelTextColor);
this.gitBranchLabel4 = this.labelTextColor;
this.gitBranchLabel5 = this.labelTextColor;
this.gitBranchLabel6 = this.labelTextColor;
this.gitBranchLabel7 = this.labelTextColor;
this.gitInv0 = this.gitInv0 || darken(invert(this.git0), 25);
this.gitInv1 = this.gitInv1 || invert(this.git1);
this.gitInv2 = this.gitInv2 || invert(this.git2);
this.gitInv3 = this.gitInv3 || invert(this.git3);
this.gitInv4 = this.gitInv4 || invert(this.git4);
this.gitInv5 = this.gitInv5 || invert(this.git5);
this.gitInv6 = this.gitInv6 || invert(this.git6);
this.gitInv7 = this.gitInv7 || invert(this.git7);
this.gitBranchLabel0 = this.gitBranchLabel0 || invert(this.labelTextColor);
this.gitBranchLabel1 = this.gitBranchLabel1 || this.labelTextColor;
this.gitBranchLabel2 = this.gitBranchLabel2 || this.labelTextColor;
this.gitBranchLabel3 = this.gitBranchLabel3 || invert(this.labelTextColor);
this.gitBranchLabel4 = this.gitBranchLabel4 || this.labelTextColor;
this.gitBranchLabel5 = this.gitBranchLabel5 || this.labelTextColor;
this.gitBranchLabel6 = this.gitBranchLabel6 || this.labelTextColor;
this.gitBranchLabel7 = this.gitBranchLabel7 || this.labelTextColor;
this.tagLabelColor = this.tagLabelColor || this.primaryTextColor;
this.tagLabelBackground = this.tagLabelBackground || this.primaryColor;

View File

@ -198,14 +198,14 @@ class Theme {
this.git6 = darken(this.git6, 25);
this.git7 = darken(this.git7, 25);
}
this.gitInv0 = invert(this.git0);
this.gitInv1 = invert(this.git1);
this.gitInv2 = invert(this.git2);
this.gitInv3 = invert(this.git3);
this.gitInv4 = invert(this.git4);
this.gitInv5 = invert(this.git5);
this.gitInv6 = invert(this.git6);
this.gitInv7 = invert(this.git7);
this.gitInv0 = this.gitInv0 || invert(this.git0);
this.gitInv1 = this.gitInv1 || invert(this.git1);
this.gitInv2 = this.gitInv2 || invert(this.git2);
this.gitInv3 = this.gitInv3 || invert(this.git3);
this.gitInv4 = this.gitInv4 || invert(this.git4);
this.gitInv5 = this.gitInv5 || invert(this.git5);
this.gitInv6 = this.gitInv6 || invert(this.git6);
this.gitInv7 = this.gitInv7 || invert(this.git7);
this.tagLabelColor = this.tagLabelColor || this.primaryTextColor;
this.tagLabelBackground = this.tagLabelBackground || this.primaryColor;

View File

@ -230,14 +230,14 @@ class Theme {
this.git6 = this.pie7 || adjust(this.primaryColor, { h: +60 });
this.git7 = this.pie8 || adjust(this.primaryColor, { h: +120 });
this.gitInv0 = invert(this.git0);
this.gitInv1 = invert(this.git1);
this.gitInv2 = invert(this.git2);
this.gitInv3 = invert(this.git3);
this.gitInv4 = invert(this.git4);
this.gitInv5 = invert(this.git5);
this.gitInv6 = invert(this.git6);
this.gitInv7 = invert(this.git7);
this.gitInv0 = this.gitInv0 || invert(this.git0);
this.gitInv1 = this.gitInv1 || invert(this.git1);
this.gitInv2 = this.gitInv2 || invert(this.git2);
this.gitInv3 = this.gitInv3 || invert(this.git3);
this.gitInv4 = this.gitInv4 || invert(this.git4);
this.gitInv5 = this.gitInv5 || invert(this.git5);
this.gitInv6 = this.gitInv6 || invert(this.git6);
this.gitInv7 = this.gitInv7 || invert(this.git7);
this.branchLabelColor = this.branchLabelColor || this.labelTextColor;
this.gitBranchLabel0 = this.branchLabelColor;

View File

@ -210,7 +210,7 @@ export const detectType = function (text, cnf) {
}
if (text.match(/^\s*gitGraph/)) {
return 'git';
return 'gitGraph';
}
if (text.match(/^\s*flowchart/)) {
return 'flowchart-v2';

View File

@ -214,7 +214,7 @@ Alice->Bob: hi`;
it('should handle a graph definition for gitGraph', function () {
const str = ' \n gitGraph TB:\nbfs1:queue';
const type = utils.detectType(str);
expect(type).toBe('git');
expect(type).toBe('gitGraph');
});
});
describe('when finding substring in array ', function () {

897
yarn.lock

File diff suppressed because it is too large Load Diff