Merge branch 'develop' of github.com-mermaid:mermaid-js/mermaid into saurabh/refactor/convert-sequenceDb-to-class

This commit is contained in:
saurabhg772244
2025-02-15 22:56:53 +05:30
23 changed files with 1664 additions and 1206 deletions

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
`mermaidAPI.getDiagramFromText()` now returns a new db instance on each call for state diagrams

5
.github/lychee.toml vendored
View File

@@ -47,7 +47,10 @@ exclude = [
"https://(www.)?drupal.org", "https://(www.)?drupal.org",
# Swimm returns 404, eventhough the link is valid # Swimm returns 404, eventhough the link is valid
"https://docs.swimm.io" "https://docs.swimm.io",
# Timeout
"https://huehive.co"
] ]
# Exclude all private IPs from checking. # Exclude all private IPs from checking.

View File

@@ -7,9 +7,6 @@ on:
- master - master
- release/** - release/**
pull_request: pull_request:
issue_comment:
types:
- created
merge_group: merge_group:
concurrency: ${{ github.workflow }}-${{ github.ref }} concurrency: ${{ github.workflow }}-${{ github.ref }}
@@ -31,12 +28,10 @@ env:
) || ) ||
github.event.before github.event.before
}} }}
# Check if this is a new comment with '/visual-test'
RUN_VISUAL_TEST: >- RUN_VISUAL_TEST: >-
${{ github.event_name == 'issue_comment' && github.event.action == 'created' && contains(github.event.comment.body, '/visual-test') && github.event.issue.pull_request != null }} ${{ github.repository == 'mermaid-js/mermaid' && (github.event_name != 'pull_request' || !startsWith(github.head_ref, 'renovate/')) }}
jobs: jobs:
cache: cache:
if: ${{ github.event_name != 'issue_comment' || contains(github.event.comment.body, '/visual-test') }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1 image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
@@ -134,8 +129,6 @@ jobs:
# e.g. if this action was run from a fork # e.g. if this action was run from a fork
record: ${{ env.RUN_VISUAL_TEST == 'true' && secrets.CYPRESS_RECORD_KEY != '' }} record: ${{ env.RUN_VISUAL_TEST == 'true' && secrets.CYPRESS_RECORD_KEY != '' }}
env: env:
# Only set Argos environment variables if the visual test comment trigger is present
ARGOS_TOKEN: ${{ env.RUN_VISUAL_TEST == 'true' && secrets.ARGOS_TOKEN || '' }}
ARGOS_PARALLEL: ${{ env.RUN_VISUAL_TEST == 'true' }} ARGOS_PARALLEL: ${{ env.RUN_VISUAL_TEST == 'true' }}
ARGOS_PARALLEL_TOTAL: ${{ env.RUN_VISUAL_TEST == 'true' && strategy.job-total || 1 }} ARGOS_PARALLEL_TOTAL: ${{ env.RUN_VISUAL_TEST == 'true' && strategy.job-total || 1 }}
ARGOS_PARALLEL_INDEX: ${{ env.RUN_VISUAL_TEST == 'true' && matrix.containers || 1 }} ARGOS_PARALLEL_INDEX: ${{ env.RUN_VISUAL_TEST == 'true' && matrix.containers || 1 }}

View File

@@ -257,6 +257,34 @@ pie
### Git graph [experimental - <a href="https://mermaid.live/edit#pako:eNqNkMFugzAMhl8F-VyVAR1tOW_aA-zKxSSGRCMJCk6lCvHuNZPKZdM0n-zf3_8r8QIqaIIGMqnB8kfEybQ--y4VnLP8-9RF9Mpkmm40hmlnDKmvkPiH_kfS7nFo_VN0FAf6XwocQGgxa_nGsm1bYEOOWmik1dRjGrmF1q-Cpkkj07u2HCI0PY4zHQATh8-7V9BwTPSE3iwOEd1OjQE1iWkBvk_bzQY7s0Sq4Hs7bHqKo8iGeZqbPN_WR7mpSd1RHpvPVhuMbG7XOq_L-oJlRfW5wteq0qorrpe-PBW9Pr8UJcK6rg-BLYPQ">live editor</a>] ### Git graph [experimental - <a href="https://mermaid.live/edit#pako:eNqNkMFugzAMhl8F-VyVAR1tOW_aA-zKxSSGRCMJCk6lCvHuNZPKZdM0n-zf3_8r8QIqaIIGMqnB8kfEybQ--y4VnLP8-9RF9Mpkmm40hmlnDKmvkPiH_kfS7nFo_VN0FAf6XwocQGgxa_nGsm1bYEOOWmik1dRjGrmF1q-Cpkkj07u2HCI0PY4zHQATh8-7V9BwTPSE3iwOEd1OjQE1iWkBvk_bzQY7s0Sq4Hs7bHqKo8iGeZqbPN_WR7mpSd1RHpvPVhuMbG7XOq_L-oJlRfW5wteq0qorrpe-PBW9Pr8UJcK6rg-BLYPQ">live editor</a>]
```
gitGraph
commit
commit
branch develop
checkout develop
commit
commit
checkout main
merge develop
commit
commit
```
```mermaid
gitGraph
commit
commit
branch develop
checkout develop
commit
commit
checkout main
merge develop
commit
commit
```
### Bar chart (using gantt chart) [<a href="https://mermaid.js.org/syntax/gantt.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNptkU1vhCAQhv8KIenNugiI4rkf6bmXpvEyFVxJFDYyNt1u9r8X63Z7WQ9m5pknLzieaBeMpQ3dg0dsPUkPOhwteXZIXmJcbCT3xMAxkuh8Z8kIEclyMIB209fqKcwTICFvG4IvFy_oLrZ-g9F26ILfQgvNFN94VaRXQ1iWqpumZBcu1J8p1E1TXDx59eQNr5LyEqjJn6hv5QnGNlxevZJmdLLpy5xJSzut45biYCfb0iaVxvawjNjS1p-TCguG16PvaIPzYjO67e3BwX6GiTY9jPFKH43DMF_hGMDY1J4oHg-_f8hFTJFd8L3br3yZx4QHxENsdrt1nO8dDstH3oVpF50ZYMbhU6ud4qoGLqyqBJRCmO6j0HXPZdGbihUc6Pmc0QP49xD-b5X69ZQv2gjO81IwzWqhC1lKrjJ6pA3nVS7SMiVjrKirWlYp5fs3osgrWeo00lorLWvOzz8JVbXm">live editor</a>] ### Bar chart (using gantt chart) [<a href="https://mermaid.js.org/syntax/gantt.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNptkU1vhCAQhv8KIenNugiI4rkf6bmXpvEyFVxJFDYyNt1u9r8X63Z7WQ9m5pknLzieaBeMpQ3dg0dsPUkPOhwteXZIXmJcbCT3xMAxkuh8Z8kIEclyMIB209fqKcwTICFvG4IvFy_oLrZ-g9F26ILfQgvNFN94VaRXQ1iWqpumZBcu1J8p1E1TXDx59eQNr5LyEqjJn6hv5QnGNlxevZJmdLLpy5xJSzut45biYCfb0iaVxvawjNjS1p-TCguG16PvaIPzYjO67e3BwX6GiTY9jPFKH43DMF_hGMDY1J4oHg-_f8hFTJFd8L3br3yZx4QHxENsdrt1nO8dDstH3oVpF50ZYMbhU6ud4qoGLqyqBJRCmO6j0HXPZdGbihUc6Pmc0QP49xD-b5X69ZQv2gjO81IwzWqhC1lKrjJ6pA3nVS7SMiVjrKirWlYp5fs3osgrWeo00lorLWvOzz8JVbXm">live editor</a>]
``` ```

View File

@@ -23,12 +23,10 @@ export default eyesPlugin(
}); });
// copy any needed variables from process.env to config.env // copy any needed variables from process.env to config.env
config.env.useAppli = process.env.USE_APPLI ? true : false; config.env.useAppli = process.env.USE_APPLI ? true : false;
config.env.useArgos = !!process.env.CI && !!process.env.ARGOS_TOKEN; config.env.useArgos = process.env.RUN_VISUAL_TEST === 'true';
if (config.env.useArgos) { if (config.env.useArgos) {
registerArgosTask(on, config, { registerArgosTask(on, config);
token: 'fc3a35cf5200db928d65b2047861582d9444032b',
});
} else { } else {
addMatchImageSnapshotPlugin(on, config); addMatchImageSnapshotPlugin(on, config);
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

View File

@@ -52,28 +52,33 @@ Examples are provided in [Getting Started](../intro/getting-started.md)
[K8s.dev blog: Improve your documentation with Mermaid.js diagrams](https://www.kubernetes.dev/blog/2021/12/01/improve-your-documentation-with-mermaid.js-diagrams/) [K8s.dev blog: Improve your documentation with Mermaid.js diagrams](https://www.kubernetes.dev/blog/2021/12/01/improve-your-documentation-with-mermaid.js-diagrams/)
## Jupyter Integration with mermaid-js ## Jupyter / Python Integration with mermaid-js
Here's an example of Python integration with mermaid-js which uses the mermaid.ink service, that displays the graph in a Jupyter notebook. Here's an example of Python integration with mermaid-js which uses the mermaid.ink service, that displays the graph in a Jupyter notebook and save it as _.png_ image with the stated resolution (in this example, `dpi=1200`).
```python ```python
import base64 import base64
import io, requests
from IPython.display import Image, display from IPython.display import Image, display
from PIL import Image as im
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
def mm(graph): def mm(graph):
graphbytes = graph.encode("utf8") graphbytes = graph.encode("utf8")
base64_bytes = base64.urlsafe_b64encode(graphbytes) base64_bytes = base64.urlsafe_b64encode(graphbytes)
base64_string = base64_bytes.decode("ascii") base64_string = base64_bytes.decode("ascii")
display(Image(url="https://mermaid.ink/img/" + base64_string)) img = im.open(io.BytesIO(requests.get('https://mermaid.ink/img/' + base64_string).content))
plt.imshow(img)
plt.axis('off') # allow to hide axis
plt.savefig('image.png', dpi=1200)
mm(""" mm("""
graph LR; graph LR;
A--> B & C & D; A--> B & C & D
B--> A & E; B--> A & E
C--> A & E; C--> A & E
D--> A & E; D--> A & E
E--> B & C & D; E--> B & C & D
""") """)
``` ```
@@ -81,4 +86,4 @@ graph LR;
![Example graph of the Python integration](img/python-mermaid-integration.png) ![Example graph of the Python integration](img/python-mermaid-integration.png)
<!--- cspell:ignore Elle Jaoude Neurodiverse graphbytes ---> <!--- cspell:ignore Elle Jaoude Neurodiverse graphbytes imshow savefig --->

View File

@@ -92,7 +92,7 @@
"cypress": "^13.14.1", "cypress": "^13.14.1",
"cypress-image-snapshot": "^4.0.1", "cypress-image-snapshot": "^4.0.1",
"cypress-split": "^1.24.0", "cypress-split": "^1.24.0",
"esbuild": "^0.21.5", "esbuild": "^0.25.0",
"eslint": "^9.4.0", "eslint": "^9.4.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-cypress": "^3.3.0", "eslint-plugin-cypress": "^3.3.0",

View File

@@ -1,4 +1,4 @@
import stateDb from '../stateDb.js'; import { StateDB } from '../stateDb.js';
import stateDiagram from './stateDiagram.jison'; import stateDiagram from './stateDiagram.jison';
import { setConfig } from '../../../config.js'; import { setConfig } from '../../../config.js';
@@ -7,7 +7,9 @@ setConfig({
}); });
describe('state parser can parse...', () => { describe('state parser can parse...', () => {
let stateDb;
beforeEach(function () { beforeEach(function () {
stateDb = new StateDB();
stateDiagram.parser.yy = stateDb; stateDiagram.parser.yy = stateDb;
stateDiagram.parser.yy.clear(); stateDiagram.parser.yy.clear();
}); });
@@ -18,7 +20,6 @@ describe('state parser can parse...', () => {
const diagramText = `stateDiagram-v2 const diagramText = `stateDiagram-v2
state "Small State 1" as namedState1`; state "Small State 1" as namedState1`;
stateDiagram.parser.parse(diagramText); stateDiagram.parser.parse(diagramText);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const states = stateDiagram.parser.yy.getStates(); const states = stateDiagram.parser.yy.getStates();
expect(states.get('namedState1')).not.toBeUndefined(); expect(states.get('namedState1')).not.toBeUndefined();
@@ -31,7 +32,6 @@ describe('state parser can parse...', () => {
const diagramText = `stateDiagram-v2 const diagramText = `stateDiagram-v2
namedState1 : Small State 1`; namedState1 : Small State 1`;
stateDiagram.parser.parse(diagramText); stateDiagram.parser.parse(diagramText);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const states = stateDiagram.parser.yy.getStates(); const states = stateDiagram.parser.yy.getStates();
expect(states.get('namedState1')).not.toBeUndefined(); expect(states.get('namedState1')).not.toBeUndefined();
@@ -42,7 +42,6 @@ describe('state parser can parse...', () => {
const diagramText = `stateDiagram-v2 const diagramText = `stateDiagram-v2
namedState1:Small State 1`; namedState1:Small State 1`;
stateDiagram.parser.parse(diagramText); stateDiagram.parser.parse(diagramText);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const states = stateDiagram.parser.yy.getStates(); const states = stateDiagram.parser.yy.getStates();
expect(states.get('namedState1')).not.toBeUndefined(); expect(states.get('namedState1')).not.toBeUndefined();
@@ -60,7 +59,6 @@ describe('state parser can parse...', () => {
state assemblies state assemblies
`; `;
stateDiagram.parser.parse(diagramText); stateDiagram.parser.parse(diagramText);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const states = stateDiagram.parser.yy.getStates(); const states = stateDiagram.parser.yy.getStates();
expect(states.get('assemble')).not.toBeUndefined(); expect(states.get('assemble')).not.toBeUndefined();
expect(states.get('assemblies')).not.toBeUndefined(); expect(states.get('assemblies')).not.toBeUndefined();
@@ -71,7 +69,6 @@ describe('state parser can parse...', () => {
state "as" as as state "as" as as
`; `;
stateDiagram.parser.parse(diagramText); stateDiagram.parser.parse(diagramText);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const states = stateDiagram.parser.yy.getStates(); const states = stateDiagram.parser.yy.getStates();
expect(states.get('as')).not.toBeUndefined(); expect(states.get('as')).not.toBeUndefined();
expect(states.get('as').descriptions.join(' ')).toEqual('as'); expect(states.get('as').descriptions.join(' ')).toEqual('as');
@@ -96,7 +93,6 @@ describe('state parser can parse...', () => {
namedState2 --> bigState2: should point to \\nbigState2 container`; namedState2 --> bigState2: should point to \\nbigState2 container`;
stateDiagram.parser.parse(diagramText); stateDiagram.parser.parse(diagramText);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const states = stateDiagram.parser.yy.getStates(); const states = stateDiagram.parser.yy.getStates();
expect(states.get('namedState1')).not.toBeUndefined(); expect(states.get('namedState1')).not.toBeUndefined();
@@ -120,7 +116,6 @@ describe('state parser can parse...', () => {
inner1 --> inner2 inner1 --> inner2
}`; }`;
stateDiagram.parser.parse(diagramText); stateDiagram.parser.parse(diagramText);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const states = stateDiagram.parser.yy.getStates(); const states = stateDiagram.parser.yy.getStates();
expect(states.get('bigState1')).not.toBeUndefined(); expect(states.get('bigState1')).not.toBeUndefined();
@@ -137,7 +132,6 @@ describe('state parser can parse...', () => {
stateDiagram-v2 stateDiagram-v2
[*] --> ${prop} [*] --> ${prop}
${prop} --> [*]`); ${prop} --> [*]`);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const states = stateDiagram.parser.yy.getStates(); const states = stateDiagram.parser.yy.getStates();
expect(states.get(prop)).not.toBeUndefined(); expect(states.get(prop)).not.toBeUndefined();
}); });

View File

@@ -1,13 +1,15 @@
import stateDb from '../stateDb.js';
import stateDiagram from './stateDiagram.jison';
import { setConfig } from '../../../config.js'; import { setConfig } from '../../../config.js';
import { StateDB } from '../stateDb.js';
import stateDiagram from './stateDiagram.jison';
setConfig({ setConfig({
securityLevel: 'strict', securityLevel: 'strict',
}); });
describe('ClassDefs and classes when parsing a State diagram', () => { describe('ClassDefs and classes when parsing a State diagram', () => {
let stateDb;
beforeEach(function () { beforeEach(function () {
stateDb = new StateDB();
stateDiagram.parser.yy = stateDb; stateDiagram.parser.yy = stateDb;
stateDiagram.parser.yy.clear(); stateDiagram.parser.yy.clear();
}); });
@@ -16,7 +18,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
describe('defining (classDef)', () => { describe('defining (classDef)', () => {
it('has "classDef" as a keyword, an id, and can set a css style attribute', function () { it('has "classDef" as a keyword, an id, and can set a css style attribute', function () {
stateDiagram.parser.parse('stateDiagram-v2\n classDef exampleClass background:#bbb;'); stateDiagram.parser.parse('stateDiagram-v2\n classDef exampleClass background:#bbb;');
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const styleClasses = stateDb.getClasses(); const styleClasses = stateDb.getClasses();
expect(styleClasses.get('exampleClass').styles.length).toEqual(1); expect(styleClasses.get('exampleClass').styles.length).toEqual(1);
@@ -27,7 +28,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
stateDiagram.parser.parse( stateDiagram.parser.parse(
'stateDiagram-v2\n classDef exampleClass background:#bbb, font-weight:bold, font-style:italic;' 'stateDiagram-v2\n classDef exampleClass background:#bbb, font-weight:bold, font-style:italic;'
); );
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const styleClasses = stateDb.getClasses(); const styleClasses = stateDb.getClasses();
expect(styleClasses.get('exampleClass').styles.length).toEqual(3); expect(styleClasses.get('exampleClass').styles.length).toEqual(3);
@@ -41,7 +41,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
stateDiagram.parser.parse( stateDiagram.parser.parse(
'stateDiagram-v2\n classDef exampleStyleClass background:#bbb,border:1.5px solid red;' 'stateDiagram-v2\n classDef exampleStyleClass background:#bbb,border:1.5px solid red;'
); );
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const classes = stateDiagram.parser.yy.getClasses(); const classes = stateDiagram.parser.yy.getClasses();
expect(classes.get('exampleStyleClass').styles.length).toBe(2); expect(classes.get('exampleStyleClass').styles.length).toBe(2);
@@ -53,7 +52,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
stateDiagram.parser.parse( stateDiagram.parser.parse(
'stateDiagram-v2\n classDef exampleStyleClass background: #bbb,border:1.5px solid red;' 'stateDiagram-v2\n classDef exampleStyleClass background: #bbb,border:1.5px solid red;'
); );
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const classes = stateDiagram.parser.yy.getClasses(); const classes = stateDiagram.parser.yy.getClasses();
expect(classes.get('exampleStyleClass').styles.length).toBe(2); expect(classes.get('exampleStyleClass').styles.length).toBe(2);
@@ -65,7 +63,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
stateDiagram.parser.parse( stateDiagram.parser.parse(
'stateDiagram-v2\n classDef __proto__ background:#bbb,border:1.5px solid red;\n classDef constructor background:#bbb,border:1.5px solid red;' 'stateDiagram-v2\n classDef __proto__ background:#bbb,border:1.5px solid red;\n classDef constructor background:#bbb,border:1.5px solid red;'
); );
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const classes = stateDiagram.parser.yy.getClasses(); const classes = stateDiagram.parser.yy.getClasses();
expect(classes.get('__proto__').styles.length).toBe(2); expect(classes.get('__proto__').styles.length).toBe(2);
expect(classes.get('constructor').styles.length).toBe(2); expect(classes.get('constructor').styles.length).toBe(2);
@@ -81,7 +78,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
diagram += 'class a exampleStyleClass'; diagram += 'class a exampleStyleClass';
stateDiagram.parser.parse(diagram); stateDiagram.parser.parse(diagram);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const classes = stateDb.getClasses(); const classes = stateDb.getClasses();
expect(classes.get('exampleStyleClass').styles.length).toEqual(2); expect(classes.get('exampleStyleClass').styles.length).toEqual(2);
@@ -102,7 +98,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
diagram += 'class a_a exampleStyleClass'; diagram += 'class a_a exampleStyleClass';
stateDiagram.parser.parse(diagram); stateDiagram.parser.parse(diagram);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const classes = stateDiagram.parser.yy.getClasses(); const classes = stateDiagram.parser.yy.getClasses();
expect(classes.get('exampleStyleClass').styles.length).toBe(2); expect(classes.get('exampleStyleClass').styles.length).toBe(2);
@@ -122,7 +117,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
diagram += 'a --> b:::exampleStyleClass' + '\n'; diagram += 'a --> b:::exampleStyleClass' + '\n';
stateDiagram.parser.parse(diagram); stateDiagram.parser.parse(diagram);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const states = stateDiagram.parser.yy.getStates(); const states = stateDiagram.parser.yy.getStates();
const classes = stateDiagram.parser.yy.getClasses(); const classes = stateDiagram.parser.yy.getClasses();
@@ -161,7 +155,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
diagram += 'class a,b exampleStyleClass'; diagram += 'class a,b exampleStyleClass';
stateDiagram.parser.parse(diagram); stateDiagram.parser.parse(diagram);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
let classes = stateDiagram.parser.yy.getClasses(); let classes = stateDiagram.parser.yy.getClasses();
let states = stateDiagram.parser.yy.getStates(); let states = stateDiagram.parser.yy.getStates();
@@ -180,7 +173,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
diagram += 'class a,b,c, d, e exampleStyleClass'; diagram += 'class a,b,c, d, e exampleStyleClass';
stateDiagram.parser.parse(diagram); stateDiagram.parser.parse(diagram);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const classes = stateDiagram.parser.yy.getClasses(); const classes = stateDiagram.parser.yy.getClasses();
const states = stateDiagram.parser.yy.getStates(); const states = stateDiagram.parser.yy.getStates();
@@ -208,7 +200,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
diagram += '}\n'; diagram += '}\n';
stateDiagram.parser.parse(diagram); stateDiagram.parser.parse(diagram);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const states = stateDiagram.parser.yy.getStates(); const states = stateDiagram.parser.yy.getStates();
@@ -224,7 +215,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
stateDiagram.parser.parse(`stateDiagram-v2 stateDiagram.parser.parse(`stateDiagram-v2
id1 id1
style id1 background:#bbb`); style id1 background:#bbb`);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const data4Layout = stateDiagram.parser.yy.getData(); const data4Layout = stateDiagram.parser.yy.getData();
expect(data4Layout.nodes[0].cssStyles).toEqual(['background:#bbb']); expect(data4Layout.nodes[0].cssStyles).toEqual(['background:#bbb']);
@@ -234,7 +224,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
id1 id1
id2 id2
style id1,id2 background:#bbb`); style id1,id2 background:#bbb`);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const data4Layout = stateDiagram.parser.yy.getData(); const data4Layout = stateDiagram.parser.yy.getData();
expect(data4Layout.nodes[0].cssStyles).toEqual(['background:#bbb']); expect(data4Layout.nodes[0].cssStyles).toEqual(['background:#bbb']);
@@ -247,7 +236,6 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
id2 id2
style id1,id2 background:#bbb, font-weight:bold, font-style:italic;`); style id1,id2 background:#bbb, font-weight:bold, font-style:italic;`);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const data4Layout = stateDiagram.parser.yy.getData(); const data4Layout = stateDiagram.parser.yy.getData();
expect(data4Layout.nodes[0].cssStyles).toEqual([ expect(data4Layout.nodes[0].cssStyles).toEqual([

View File

@@ -1,6 +1,6 @@
import { line, curveBasis } from 'd3'; import { line, curveBasis } from 'd3';
import idCache from './id-cache.js'; import idCache from './id-cache.js';
import stateDb from './stateDb.js'; import { StateDB } from './stateDb.js';
import utils from '../../utils.js'; import utils from '../../utils.js';
import common from '../common/common.js'; import common from '../common/common.js';
import { getConfig } from '../../diagram-api/diagramAPI.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
@@ -414,13 +414,13 @@ let edgeCount = 0;
export const drawEdge = function (elem, path, relation) { export const drawEdge = function (elem, path, relation) {
const getRelationType = function (type) { const getRelationType = function (type) {
switch (type) { switch (type) {
case stateDb.relationType.AGGREGATION: case StateDB.relationType.AGGREGATION:
return 'aggregation'; return 'aggregation';
case stateDb.relationType.EXTENSION: case StateDB.relationType.EXTENSION:
return 'extension'; return 'extension';
case stateDb.relationType.COMPOSITION: case StateDB.relationType.COMPOSITION:
return 'composition'; return 'composition';
case stateDb.relationType.DEPENDENCY: case StateDB.relationType.DEPENDENCY:
return 'dependency'; return 'dependency';
} }
}; };
@@ -459,7 +459,7 @@ export const drawEdge = function (elem, path, relation) {
svgPath.attr( svgPath.attr(
'marker-end', 'marker-end',
'url(' + url + '#' + getRelationType(stateDb.relationType.DEPENDENCY) + 'End' + ')' 'url(' + url + '#' + getRelationType(StateDB.relationType.DEPENDENCY) + 'End' + ')'
); );
if (relation.title !== undefined) { if (relation.title !== undefined) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,9 @@
import stateDb from './stateDb.js'; import { StateDB } from './stateDb.js';
describe('State Diagram stateDb', () => { describe('State Diagram stateDb', () => {
let stateDb;
beforeEach(() => { beforeEach(() => {
stateDb.clear(); stateDb = new StateDB();
}); });
describe('addStyleClass', () => { describe('addStyleClass', () => {
@@ -20,8 +21,9 @@ describe('State Diagram stateDb', () => {
}); });
describe('addDescription to a state', () => { describe('addDescription to a state', () => {
let stateDb;
beforeEach(() => { beforeEach(() => {
stateDb.clear(); stateDb = new StateDB();
stateDb.addState('state1'); stateDb.addState('state1');
}); });
@@ -73,3 +75,25 @@ describe('State Diagram stateDb', () => {
}); });
}); });
}); });
describe('state db class', () => {
let stateDb;
beforeEach(() => {
stateDb = new StateDB();
});
// This is to ensure that functions used in state JISON are exposed as function from StateDb
it('should have functions used in flow JISON as own property', () => {
const functionsUsedInParser = [
'setRootDoc',
'trimColon',
'getDividerId',
'setAccTitle',
'setAccDescription',
'setDirection',
];
for (const fun of functionsUsedInParser) {
expect(Object.hasOwn(stateDb, fun)).toBe(true);
}
});
});

View File

@@ -1,11 +1,12 @@
import { parser } from './parser/stateDiagram.jison'; import stateDiagram, { parser } from './parser/stateDiagram.jison';
import stateDb from './stateDb.js'; import { StateDB } from './stateDb.js';
import stateDiagram from './parser/stateDiagram.jison';
describe('state diagram V2, ', function () { describe('state diagram V2, ', function () {
// TODO - these examples should be put into ./parser/stateDiagram.spec.js // TODO - these examples should be put into ./parser/stateDiagram.spec.js
describe('when parsing an info graph it', function () { describe('when parsing an info graph it', function () {
let stateDb;
beforeEach(function () { beforeEach(function () {
stateDb = new StateDB();
parser.yy = stateDb; parser.yy = stateDb;
stateDiagram.parser.yy = stateDb; stateDiagram.parser.yy = stateDb;
stateDiagram.parser.yy.clear(); stateDiagram.parser.yy.clear();
@@ -127,7 +128,6 @@ describe('state diagram V2, ', function () {
`; `;
stateDiagram.parser.parse(diagram); stateDiagram.parser.parse(diagram);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const rels = stateDb.getRelations(); const rels = stateDb.getRelations();
const rel_1_2 = rels.find((rel) => rel.id1 === 'State1' && rel.id2 === 'State2'); const rel_1_2 = rels.find((rel) => rel.id1 === 'State1' && rel.id2 === 'State2');
@@ -402,7 +402,6 @@ describe('state diagram V2, ', function () {
`; `;
stateDiagram.parser.parse(diagram); stateDiagram.parser.parse(diagram);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const states = stateDb.getStates(); const states = stateDb.getStates();
expect(states.get('Active').doc[0].id).toEqual('Idle'); expect(states.get('Active').doc[0].id).toEqual('Idle');

View File

@@ -1,13 +1,15 @@
import type { DiagramDefinition } from '../../diagram-api/types.js'; import type { DiagramDefinition } from '../../diagram-api/types.js';
// @ts-ignore: JISON doesn't support types // @ts-ignore: JISON doesn't support types
import parser from './parser/stateDiagram.jison'; import parser from './parser/stateDiagram.jison';
import db from './stateDb.js'; import { StateDB } from './stateDb.js';
import styles from './styles.js'; import styles from './styles.js';
import renderer from './stateRenderer-v3-unified.js'; import renderer from './stateRenderer-v3-unified.js';
export const diagram: DiagramDefinition = { export const diagram: DiagramDefinition = {
parser, parser,
db, get db() {
return new StateDB();
},
renderer, renderer,
styles, styles,
init: (cnf) => { init: (cnf) => {

View File

@@ -1,9 +1,11 @@
import { parser } from './parser/stateDiagram.jison'; import { parser } from './parser/stateDiagram.jison';
import stateDb from './stateDb.js'; import { StateDB } from './stateDb.js';
describe('state diagram, ', function () { describe('state diagram, ', function () {
describe('when parsing an info graph it', function () { describe('when parsing an info graph it', function () {
let stateDb;
beforeEach(function () { beforeEach(function () {
stateDb = new StateDB();
parser.yy = stateDb; parser.yy = stateDb;
}); });

View File

@@ -1,13 +1,15 @@
import type { DiagramDefinition } from '../../diagram-api/types.js'; import type { DiagramDefinition } from '../../diagram-api/types.js';
// @ts-ignore: JISON doesn't support types // @ts-ignore: JISON doesn't support types
import parser from './parser/stateDiagram.jison'; import parser from './parser/stateDiagram.jison';
import db from './stateDb.js'; import { StateDB } from './stateDb.js';
import styles from './styles.js'; import styles from './styles.js';
import renderer from './stateRenderer.js'; import renderer from './stateRenderer.js';
export const diagram: DiagramDefinition = { export const diagram: DiagramDefinition = {
parser, parser,
db, get db() {
return new StateDB();
},
renderer, renderer,
styles, styles,
init: (cnf) => { init: (cnf) => {

View File

@@ -36,7 +36,6 @@ export const getClasses = function (
text: string, text: string,
diagramObj: any diagramObj: any
): Map<string, DiagramStyleClassDef> { ): Map<string, DiagramStyleClassDef> {
diagramObj.db.extract(diagramObj.db.getRootDocV2());
return diagramObj.db.getClasses(); return diagramObj.db.getClasses();
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

View File

@@ -46,28 +46,33 @@ https://codepen.io/Ryuno-Ki/pen/LNxwgR
[K8s.dev blog: Improve your documentation with Mermaid.js diagrams](https://www.kubernetes.dev/blog/2021/12/01/improve-your-documentation-with-mermaid.js-diagrams/) [K8s.dev blog: Improve your documentation with Mermaid.js diagrams](https://www.kubernetes.dev/blog/2021/12/01/improve-your-documentation-with-mermaid.js-diagrams/)
## Jupyter Integration with mermaid-js ## Jupyter / Python Integration with mermaid-js
Here's an example of Python integration with mermaid-js which uses the mermaid.ink service, that displays the graph in a Jupyter notebook. Here's an example of Python integration with mermaid-js which uses the mermaid.ink service, that displays the graph in a Jupyter notebook and save it as _.png_ image with the stated resolution (in this example, `dpi=1200`).
```python ```python
import base64 import base64
import io, requests
from IPython.display import Image, display from IPython.display import Image, display
from PIL import Image as im
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
def mm(graph): def mm(graph):
graphbytes = graph.encode("utf8") graphbytes = graph.encode("utf8")
base64_bytes = base64.urlsafe_b64encode(graphbytes) base64_bytes = base64.urlsafe_b64encode(graphbytes)
base64_string = base64_bytes.decode("ascii") base64_string = base64_bytes.decode("ascii")
display(Image(url="https://mermaid.ink/img/" + base64_string)) img = im.open(io.BytesIO(requests.get('https://mermaid.ink/img/' + base64_string).content))
plt.imshow(img)
plt.axis('off') # allow to hide axis
plt.savefig('image.png', dpi=1200)
mm(""" mm("""
graph LR; graph LR;
A--> B & C & D; A--> B & C & D
B--> A & E; B--> A & E
C--> A & E; C--> A & E
D--> A & E; D--> A & E
E--> B & C & D; E--> B & C & D
""") """)
``` ```
@@ -75,4 +80,4 @@ graph LR;
![Example graph of the Python integration](img/python-mermaid-integration.png) ![Example graph of the Python integration](img/python-mermaid-integration.png)
<!--- cspell:ignore Elle Jaoude Neurodiverse graphbytes ---> <!--- cspell:ignore Elle Jaoude Neurodiverse graphbytes imshow savefig --->

View File

@@ -72,6 +72,7 @@ import { FlowDB } from './diagrams/flowchart/flowDb.js';
import { SequenceDB } from './diagrams/sequence/sequenceDb.js'; import { SequenceDB } from './diagrams/sequence/sequenceDb.js';
import { decodeEntities, encodeEntities } from './utils.js'; import { decodeEntities, encodeEntities } from './utils.js';
import { toBase64 } from './utils/base64.js'; import { toBase64 } from './utils/base64.js';
import { StateDB } from './diagrams/state/stateDb.js';
/** /**
* @see https://vitest.dev/guide/mocking.html Mock part of a module * @see https://vitest.dev/guide/mocking.html Mock part of a module
@@ -837,6 +838,31 @@ graph TD;A--x|text including URL space|B;`)
}); });
it('should not modify db when rendering different diagrams', async () => { it('should not modify db when rendering different diagrams', async () => {
const stateDiagram1 = await mermaidAPI.getDiagramFromText(
`stateDiagram
direction LR
[*] --> Still
Still --> [*]
Still --> Moving
Moving --> Still
Moving --> Crash
Crash --> [*]`
);
const stateDiagram2 = await mermaidAPI.getDiagramFromText(
`stateDiagram
direction TB
[*] --> Still
Still --> [*]
Still --> Moving
Moving --> Still
Moving --> Crash
Crash --> [*]`
);
expect(stateDiagram1.db).not.toBe(stateDiagram2.db);
assert(stateDiagram1.db instanceof StateDB);
assert(stateDiagram2.db instanceof StateDB);
expect(stateDiagram1.db.getDirection()).not.toEqual(stateDiagram2.db.getDirection());
const flowDiagram1 = await mermaidAPI.getDiagramFromText( const flowDiagram1 = await mermaidAPI.getDiagramFromText(
`flowchart LR `flowchart LR
A -- text --> B -- text2 --> C` A -- text --> B -- text2 --> C`

1509
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -103,5 +103,5 @@
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */
}, },
"exclude": ["node_modules", "dist", "coverage"] "exclude": ["**/node_modules/*", "**/dist/*", ".git", "coverage"]
} }