Merge branch 'develop' into refactor-accessibility

This commit is contained in:
Sidharth Vinod 2023-07-02 13:04:09 +05:30 committed by GitHub
commit 2a1759aab4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 2118 additions and 218 deletions

View File

@ -1,6 +1,15 @@
codecov:
branch: develop
comment: comment:
layout: 'reach, diff, flags, files' layout: 'reach, diff, flags, files'
behavior: default behavior: default
require_changes: false # if true: only post the comment if coverage changes require_changes: false # if true: only post the comment if coverage changes
require_base: no # [yes :: must have a base report to post] require_base: no # [yes :: must have a base report to post]
require_head: yes # [yes :: must have a head report to post] require_head: yes # [yes :: must have a head report to post]
coverage:
status:
project:
default:
threshold: 1%

View File

@ -2,13 +2,13 @@ name: Build Vitepress docs
on: on:
pull_request: pull_request:
merge_group:
permissions: permissions:
contents: read contents: read
jobs: jobs:
# Build job build-docs:
build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout

View File

@ -2,6 +2,7 @@ name: Build
on: on:
push: {} push: {}
merge_group:
pull_request: pull_request:
types: types:
- opened - opened
@ -12,7 +13,7 @@ permissions:
contents: read contents: read
jobs: jobs:
build: build-mermaid:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:

View File

@ -14,7 +14,7 @@ permissions:
contents: read contents: read
jobs: jobs:
check: check-readme:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository

View File

@ -1,15 +1,16 @@
on: on:
push: {} push:
merge_group:
pull_request: pull_request:
types: types:
- opened - opened
- synchronize - synchronize
- ready_for_review - ready_for_review
name: Static analysis name: Static analysis on Test files
jobs: jobs:
test: check-tests:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: check tests name: check tests
if: github.repository_owner == 'mermaid-js' if: github.repository_owner == 'mermaid-js'

View File

@ -19,7 +19,7 @@ env:
USE_APPLI: ${{ secrets.APPLITOOLS_API_KEY && 'true' || '' }} USE_APPLI: ${{ secrets.APPLITOOLS_API_KEY && 'true' || '' }}
jobs: jobs:
test: e2e-applitools:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:

View File

@ -1,12 +1,15 @@
name: E2E name: E2E
on: [push, pull_request] on:
push:
pull_request:
merge_group:
permissions: permissions:
contents: read contents: read
jobs: jobs:
build: e2e:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false

View File

@ -1,7 +1,8 @@
name: Lint name: Lint
on: on:
push: {} push:
merge_group:
pull_request: pull_request:
types: types:
- opened - opened

View File

@ -19,7 +19,7 @@ concurrency:
jobs: jobs:
# Build job # Build job
build: build-docs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
@ -48,11 +48,11 @@ jobs:
path: packages/mermaid/src/vitepress/.vitepress/dist path: packages/mermaid/src/vitepress/.vitepress/dist
# Deployment job # Deployment job
deploy: deploy-docs:
environment: environment:
name: github-pages name: github-pages
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build needs: build-docs
steps: steps:
- name: Deploy to GitHub Pages - name: Deploy to GitHub Pages
id: deployment id: deployment

View File

@ -6,7 +6,7 @@ on:
- 'release/**' - 'release/**'
jobs: jobs:
publish: publish-preview:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@ -1,12 +1,12 @@
name: Unit Tests name: Unit Tests
on: [push, pull_request] on: [push, pull_request, merge_group]
permissions: permissions:
contents: read contents: read
jobs: jobs:
build: unit-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
@ -49,9 +49,3 @@ jobs:
name: mermaid-codecov name: mermaid-codecov
fail_ci_if_error: true fail_ci_if_error: true
verbose: true verbose: true
# Coveralls is throwing 500. Disabled for now.
# - name: Upload Coverage to Coveralls
# uses: coverallsapp/github-action@v2
# with:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# flag-name: unit

View File

@ -5,7 +5,7 @@ on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
build: update-browser-list:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@ -6,3 +6,4 @@ coverage
pnpm-lock.yaml pnpm-lock.yaml
stats stats
packages/mermaid/src/docs/.vitepress/components.d.ts packages/mermaid/src/docs/.vitepress/components.d.ts
.nyc_output

View File

@ -0,0 +1,13 @@
/**
* Mocked Sankey diagram renderer
*/
import { vi } from 'vitest';
export const draw = vi.fn().mockImplementation(() => {
return '';
});
export default {
draw,
};

View File

@ -106,6 +106,7 @@
"rehype", "rehype",
"roledescription", "roledescription",
"sandboxed", "sandboxed",
"sankey",
"setupgraphviewbox", "setupgraphviewbox",
"shiki", "shiki",
"sidharth", "sidharth",

View File

@ -0,0 +1,144 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js';
describe('Sankey Diagram', () => {
it('should render a simple example', () => {
imgSnapshotTest(
`
sankey-beta
sourceNode,targetNode,10
`,
{}
);
});
describe('when given a linkColor', function () {
this.beforeAll(() => {
cy.wrap(
`sankey-beta
a,b,10
`
).as('graph');
});
it('links should use hex color', function () {
renderGraph(this.graph, { sankey: { linkColor: '#636465' } });
cy.get('.link path').should((link) => {
expect(link.attr('stroke')).to.equal('#636465');
});
});
it('links should be the same color as source node', function () {
renderGraph(this.graph, { sankey: { linkColor: 'source' } });
cy.get('.link path').then((link) => {
cy.get('.node[id="node-1"] rect').should((node) =>
expect(link.attr('stroke')).to.equal(node.attr('fill'))
);
});
});
it('links should be the same color as target node', function () {
renderGraph(this.graph, { sankey: { linkColor: 'target' } });
cy.get('.link path').then((link) => {
cy.get('.node[id="node-2"] rect').should((node) =>
expect(link.attr('stroke')).to.equal(node.attr('fill'))
);
});
});
it('links must be gradient', function () {
renderGraph(this.graph, { sankey: { linkColor: 'gradient' } });
cy.get('.link path').should((link) => {
expect(link.attr('stroke')).to.equal('url(#linearGradient-3)');
});
});
});
describe('when given a nodeAlignment', function () {
this.beforeAll(() => {
cy.wrap(
`
sankey-beta
a,b,8
b,c,8
c,d,8
d,e,8
x,c,4
c,y,4
`
).as('graph');
});
this.afterEach(() => {
cy.get('.node[id="node-1"]').should((node) => {
expect(node.attr('x')).to.equal('0');
});
cy.get('.node[id="node-2"]').should((node) => {
expect(node.attr('x')).to.equal('100');
});
cy.get('.node[id="node-3"]').should((node) => {
expect(node.attr('x')).to.equal('200');
});
cy.get('.node[id="node-4"]').should((node) => {
expect(node.attr('x')).to.equal('300');
});
cy.get('.node[id="node-5"]').should((node) => {
expect(node.attr('x')).to.equal('400');
});
});
it('should justify nodes', function () {
renderGraph(this.graph, {
sankey: { nodeAlignment: 'justify', width: 410, useMaxWidth: false },
});
cy.get('.node[id="node-6"]').should((node) => {
expect(node.attr('x')).to.equal('0');
});
cy.get('.node[id="node-7"]').should((node) => {
expect(node.attr('x')).to.equal('400');
});
});
it('should align nodes left', function () {
renderGraph(this.graph, {
sankey: { nodeAlignment: 'left', width: 410, useMaxWidth: false },
});
cy.get('.node[id="node-6"]').should((node) => {
expect(node.attr('x')).to.equal('0');
});
cy.get('.node[id="node-7"]').should((node) => {
expect(node.attr('x')).to.equal('300');
});
});
it('should align nodes right', function () {
renderGraph(this.graph, {
sankey: { nodeAlignment: 'right', width: 410, useMaxWidth: false },
});
cy.get('.node[id="node-6"]').should((node) => {
expect(node.attr('x')).to.equal('100');
});
cy.get('.node[id="node-7"]').should((node) => {
expect(node.attr('x')).to.equal('400');
});
});
it('should center nodes', function () {
renderGraph(this.graph, {
sankey: { nodeAlignment: 'center', width: 410, useMaxWidth: false },
});
cy.get('.node[id="node-6"]').should((node) => {
expect(node.attr('x')).to.equal('100');
});
cy.get('.node[id="node-7"]').should((node) => {
expect(node.attr('x')).to.equal('300');
});
});
});
});

View File

@ -154,6 +154,29 @@
</pre> </pre>
<hr /> <hr />
<pre class="mermaid">
classDiagram
A1 --> B1
namespace A {
class A1 {
+foo : string
}
class A2 {
+bar : int
}
}
namespace B {
class B1 {
+foo : bool
}
class B2 {
+bar : float
}
}
A2 --> B2
</pre>
<hr />
<script type="module"> <script type="module">
import mermaid from './mermaid.esm.mjs'; import mermaid from './mermaid.esm.mjs';
mermaid.initialize({ mermaid.initialize({

View File

@ -75,6 +75,9 @@
<li> <li>
<h2><a href="./zenuml.html">ZenUML</a></h2> <h2><a href="./zenuml.html">ZenUML</a></h2>
</li> </li>
<li>
<h2><a href="./sankey.html">Sankey</a></h2>
</li>
</ul> </ul>
</body> </body>
</html> </html>

108
demos/sankey.html Normal file
View File

@ -0,0 +1,108 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>States Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
<style>
div.mermaid {
/* font-family: 'trebuchet ms', verdana, arial; */
font-family: 'Courier New', Courier, monospace !important;
}
</style>
</head>
<body>
<h1>Sankey diagram demos</h1>
<h2>Energy flow</h2>
<pre class="mermaid">
sankey-beta
Agricultural 'waste',Bio-conversion,124.729
Bio-conversion,Liquid,0.597
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
Biofuel imports,Liquid,35
Biomass imports,Solid,35
Coal imports,Coal,11.606
Coal reserves,Coal,63.965
Coal,Solid,75.571
District heating,Industry,10.639
District heating,Heating and cooling - commercial,22.505
District heating,Heating and cooling - homes,46.184
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
Electricity grid,Industry,342.165
Electricity grid,Road transport,37.797
Electricity grid,Agriculture,4.412
Electricity grid,Heating and cooling - commercial,40.858
Electricity grid,Losses,56.691
Electricity grid,Rail transport,7.863
Electricity grid,Lighting & appliances - commercial,90.008
Electricity grid,Lighting & appliances - homes,93.494
Gas imports,Ngas,40.719
Gas reserves,Ngas,82.233
Gas,Heating and cooling - commercial,0.129
Gas,Losses,1.401
Gas,Thermal generation,151.891
Gas,Agriculture,2.096
Gas,Industry,48.58
Geothermal,Electricity grid,7.013
H2 conversion,H2,20.897
H2 conversion,Losses,6.242
H2,Road transport,20.897
Hydro,Electricity grid,6.995
Liquid,Industry,121.066
Liquid,International shipping,128.69
Liquid,Road transport,135.835
Liquid,Domestic aviation,14.458
Liquid,International aviation,206.267
Liquid,Agriculture,3.64
Liquid,National navigation,33.218
Liquid,Rail transport,4.413
Marine algae,Bio-conversion,4.375
Ngas,Gas,122.952
Nuclear,Thermal generation,839.978
Oil imports,Oil,504.287
Oil reserves,Oil,107.703
Oil,Liquid,611.99
Other waste,Solid,56.587
Other waste,Bio-conversion,77.81
Pumped heat,Heating and cooling - homes,193.026
Pumped heat,Heating and cooling - commercial,70.672
Solar PV,Electricity grid,59.901
Solar Thermal,Heating and cooling - homes,19.263
Solar,Solar Thermal,19.263
Solar,Solar PV,59.901
Solid,Agriculture,0.882
Solid,Thermal generation,400.12
Solid,Industry,46.477
Thermal generation,Electricity grid,525.531
Thermal generation,Losses,787.129
Thermal generation,District heating,79.329
Tidal,Electricity grid,9.452
UK land based bioenergy,Bio-conversion,182.01
Wave,Electricity grid,19.013
Wind,Electricity grid,289.366
</pre>
<script type="module">
import mermaid from './mermaid.esm.mjs';
mermaid.initialize({
theme: 'default',
logLevel: 3,
securityLevel: 'loose',
sankey: {
title: 'Hey, this is Sankey-Beta',
width: 1200,
height: 600,
linkColor: 'gradient',
nodeAlignment: 'justify',
},
});
</script>
</body>
</html>

View File

@ -1,9 +1,36 @@
version: '3.9' version: '3.9'
services: services:
mermaid: mermaid:
image: node:20.3.1-alpine3.18 image: node:18.16.1-alpine3.18
stdin_open: true stdin_open: true
tty: true tty: true
working_dir: /mermaid working_dir: /mermaid
mem_limit: '2G'
environment:
- NODE_OPTIONS=--max_old_space_size=2048
volumes: volumes:
- ./:/mermaid - ./:/mermaid
- root_cache:/root/.cache
- root_local:/root/.local
- root_npm:/root/.npm
ports:
- 9000:9000
- 3333:3333
cypress:
image: cypress/included:12.16.0
stdin_open: true
tty: true
working_dir: /mermaid
mem_limit: '2G'
entrypoint: cypress
environment:
- DISPLAY
volumes:
- ./:/mermaid
- /tmp/.X11-unix:/tmp/.X11-unix
network_mode: host
volumes:
root_cache:
root_local:
root_npm:

View File

@ -14,7 +14,7 @@
#### Defined in #### Defined in
[defaultConfig.ts:2293](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L2293) [defaultConfig.ts:2300](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L2300)
--- ---

View File

@ -73,9 +73,9 @@ To make a custom theme, modify `themeVariables` via `init`.
You will need to use the [base](#available-themes) theme as it is the only modifiable theme. You will need to use the [base](#available-themes) theme as it is the only modifiable theme.
| Parameter | Description | Type | Properties | | Parameter | Description | Type | Properties |
| -------------- | ------------------------------------ | ------ | --------------------------------------------------------------------------------------------------- | | -------------- | ------------------------------------ | ------ | ----------------------------------------------------------------------------------- |
| themeVariables | Modifiable with the `init` directive | Object | `primaryColor`, `primaryTextColor`, `lineColor` ([see full list](#theme-variables-reference-table)) | | themeVariables | Modifiable with the `init` directive | Object | `primaryColor`, `primaryTextColor`, `lineColor` ([see full list](#theme-variables)) |
Example of modifying `themeVariables` using the `init` directive: Example of modifying `themeVariables` using the `init` directive:

View File

@ -161,6 +161,8 @@ They also serve as proof of concept, for the variety of things that can be built
- [Nano Mermaid](https://github.com/Yash-Singh1/nano-mermaid) - [Nano Mermaid](https://github.com/Yash-Singh1/nano-mermaid)
- [CKEditor](https://github.com/ckeditor/ckeditor5) - [CKEditor](https://github.com/ckeditor/ckeditor5)
- [CKEditor 5 Mermaid plugin](https://github.com/ckeditor/ckeditor5-mermaid) - [CKEditor 5 Mermaid plugin](https://github.com/ckeditor/ckeditor5-mermaid)
- [Standard Notes](https://standardnotes.com/)
- [sn-mermaid](https://github.com/nienow/sn-mermaid)
## Document Generation ## Document Generation

View File

@ -6,8 +6,8 @@
# Announcements # Announcements
## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do/) ## [Sequence diagrams, the only good thing UML brought to software development](https://www.mermaidchart.com/blog/posts/sequence-diagrams-the-good-thing-uml-brought-to-software-development/)
8 June 2023 · 7 mins 15 June 2023 · 12 mins
A quadrant chart is a useful diagram that helps users visualize data and identify patterns in a data set. Sequence diagrams really shine when youre documenting different parts of a system and the various ways these parts interact with each other.

View File

@ -6,6 +6,12 @@
# Blog # Blog
## [Sequence diagrams, the only good thing UML brought to software development](https://www.mermaidchart.com/blog/posts/sequence-diagrams-the-good-thing-uml-brought-to-software-development/)
15 June 2023 · 12 mins
Sequence diagrams really shine when youre documenting different parts of a system and the various ways these parts interact with each other.
## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do/) ## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do/)
8 June 2023 · 7 mins 8 June 2023 · 7 mins

View File

@ -25,25 +25,25 @@ Mermaid can render Gantt diagrams as SVG, PNG or a MarkDown link that can be pas
```mermaid-example ```mermaid-example
gantt gantt
title A Gantt Diagram title A Gantt Diagram
dateFormat YYYY-MM-DD dateFormat YYYY-MM-DD
section Section section Section
A task :a1, 2014-01-01, 30d A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d Another task :after a1, 20d
section Another section Another
Task in sec :2014-01-12 , 12d Task in Another :2014-01-12, 12d
another task : 24d another task :24d
``` ```
```mermaid ```mermaid
gantt gantt
title A Gantt Diagram title A Gantt Diagram
dateFormat YYYY-MM-DD dateFormat YYYY-MM-DD
section Section section Section
A task :a1, 2014-01-01, 30d A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d Another task :after a1, 20d
section Another section Another
Task in sec :2014-01-12 , 12d Task in Another :2014-01-12, 12d
another task : 24d another task :24d
``` ```
## Syntax ## Syntax
@ -117,17 +117,17 @@ gantt
It is possible to set multiple dependencies separated by space: It is possible to set multiple dependencies separated by space:
```mermaid-example ```mermaid-example
gantt gantt
apple :a, 2017-07-20, 1w apple :a, 2017-07-20, 1w
banana :crit, b, 2017-07-23, 1d banana :crit, b, 2017-07-23, 1d
cherry :active, c, after b a, 1d cherry :active, c, after b a, 1d
``` ```
```mermaid ```mermaid
gantt gantt
apple :a, 2017-07-20, 1w apple :a, 2017-07-20, 1w
banana :crit, b, 2017-07-23, 1d banana :crit, b, 2017-07-23, 1d
cherry :active, c, after b a, 1d cherry :active, c, after b a, 1d
``` ```
### Title ### Title
@ -146,22 +146,22 @@ You can add milestones to the diagrams. Milestones differ from tasks as they rep
```mermaid-example ```mermaid-example
gantt gantt
dateFormat HH:mm dateFormat HH:mm
axisFormat %H:%M axisFormat %H:%M
Initial milestone : milestone, m1, 17:49,2min Initial milestone : milestone, m1, 17:49, 2m
taska2 : 10min Task A : 10m
taska3 : 5min Task B : 5m
Final milestone : milestone, m2, 18:14, 2min Final milestone : milestone, m2, 18:08, 4m
``` ```
```mermaid ```mermaid
gantt gantt
dateFormat HH:mm dateFormat HH:mm
axisFormat %H:%M axisFormat %H:%M
Initial milestone : milestone, m1, 17:49,2min Initial milestone : milestone, m1, 17:49, 2m
taska2 : 10min Task A : 10m
taska3 : 5min Task B : 5m
Final milestone : milestone, m2, 18:14, 2min Final milestone : milestone, m2, 18:08, 4m
``` ```
## Setting dates ## Setting dates
@ -296,29 +296,27 @@ Comments can be entered within a gantt chart, which will be ignored by the parse
```mermaid-example ```mermaid-example
gantt gantt
title A Gantt Diagram title A Gantt Diagram
%% this is a comment %% This is a comment
dateFormat YYYY-MM-DD dateFormat YYYY-MM-DD
section Section section Section
A task :a1, 2014-01-01, 30d A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d Another task :after a1, 20d
section Another section Another
Task in sec :2014-01-12 , 12d Task in Another :2014-01-12, 12d
another task : 24d another task :24d
``` ```
```mermaid ```mermaid
gantt gantt
title A Gantt Diagram title A Gantt Diagram
%% this is a comment %% This is a comment
dateFormat YYYY-MM-DD dateFormat YYYY-MM-DD
section Section section Section
A task :a1, 2014-01-01, 30d A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d Another task :after a1, 20d
section Another section Another
Task in sec :2014-01-12 , 12d Task in Another :2014-01-12, 12d
another task : 24d another task :24d
``` ```
## Styling ## Styling
@ -440,7 +438,7 @@ Beginner's tip—a full example using interactive links in an html context:
dateFormat YYYY-MM-DD dateFormat YYYY-MM-DD
section Clickable section Clickable
Visit mermaidjs :active, cl1, 2014-01-07, 3d Visit mermaidjs :active, cl1, 2014-01-07, 3d
Print arguments :cl2, after cl1, 3d Print arguments :cl2, after cl1, 3d
Print task :cl3, after cl2, 3d Print task :cl3, after cl2, 3d

510
docs/syntax/sankey.md Normal file
View File

@ -0,0 +1,510 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/sankey.md](../../packages/mermaid/src/docs/syntax/sankey.md).
# Sankey diagrams
> A sankey diagram is a visualization used to depict a flow from one set of values to another.
::: warning
This is an experimental diagram. Its syntax are very close to plain CSV, but it is to be extended in the nearest future.
:::
The things being connected are called nodes and the connections are called links.
## Example
This example taken from [observable](https://observablehq.com/@d3/sankey/2?collection=@d3/d3-sankey). It may be rendered a little bit differently, though, in terms of size and colors.
```mermaid-example
sankey-beta
Agricultural 'waste',Bio-conversion,124.729
Bio-conversion,Liquid,0.597
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
Biofuel imports,Liquid,35
Biomass imports,Solid,35
Coal imports,Coal,11.606
Coal reserves,Coal,63.965
Coal,Solid,75.571
District heating,Industry,10.639
District heating,Heating and cooling - commercial,22.505
District heating,Heating and cooling - homes,46.184
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
Electricity grid,Industry,342.165
Electricity grid,Road transport,37.797
Electricity grid,Agriculture,4.412
Electricity grid,Heating and cooling - commercial,40.858
Electricity grid,Losses,56.691
Electricity grid,Rail transport,7.863
Electricity grid,Lighting & appliances - commercial,90.008
Electricity grid,Lighting & appliances - homes,93.494
Gas imports,Ngas,40.719
Gas reserves,Ngas,82.233
Gas,Heating and cooling - commercial,0.129
Gas,Losses,1.401
Gas,Thermal generation,151.891
Gas,Agriculture,2.096
Gas,Industry,48.58
Geothermal,Electricity grid,7.013
H2 conversion,H2,20.897
H2 conversion,Losses,6.242
H2,Road transport,20.897
Hydro,Electricity grid,6.995
Liquid,Industry,121.066
Liquid,International shipping,128.69
Liquid,Road transport,135.835
Liquid,Domestic aviation,14.458
Liquid,International aviation,206.267
Liquid,Agriculture,3.64
Liquid,National navigation,33.218
Liquid,Rail transport,4.413
Marine algae,Bio-conversion,4.375
Ngas,Gas,122.952
Nuclear,Thermal generation,839.978
Oil imports,Oil,504.287
Oil reserves,Oil,107.703
Oil,Liquid,611.99
Other waste,Solid,56.587
Other waste,Bio-conversion,77.81
Pumped heat,Heating and cooling - homes,193.026
Pumped heat,Heating and cooling - commercial,70.672
Solar PV,Electricity grid,59.901
Solar Thermal,Heating and cooling - homes,19.263
Solar,Solar Thermal,19.263
Solar,Solar PV,59.901
Solid,Agriculture,0.882
Solid,Thermal generation,400.12
Solid,Industry,46.477
Thermal generation,Electricity grid,525.531
Thermal generation,Losses,787.129
Thermal generation,District heating,79.329
Tidal,Electricity grid,9.452
UK land based bioenergy,Bio-conversion,182.01
Wave,Electricity grid,19.013
Wind,Electricity grid,289.366
```
```mermaid
sankey-beta
Agricultural 'waste',Bio-conversion,124.729
Bio-conversion,Liquid,0.597
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
Biofuel imports,Liquid,35
Biomass imports,Solid,35
Coal imports,Coal,11.606
Coal reserves,Coal,63.965
Coal,Solid,75.571
District heating,Industry,10.639
District heating,Heating and cooling - commercial,22.505
District heating,Heating and cooling - homes,46.184
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
Electricity grid,Industry,342.165
Electricity grid,Road transport,37.797
Electricity grid,Agriculture,4.412
Electricity grid,Heating and cooling - commercial,40.858
Electricity grid,Losses,56.691
Electricity grid,Rail transport,7.863
Electricity grid,Lighting & appliances - commercial,90.008
Electricity grid,Lighting & appliances - homes,93.494
Gas imports,Ngas,40.719
Gas reserves,Ngas,82.233
Gas,Heating and cooling - commercial,0.129
Gas,Losses,1.401
Gas,Thermal generation,151.891
Gas,Agriculture,2.096
Gas,Industry,48.58
Geothermal,Electricity grid,7.013
H2 conversion,H2,20.897
H2 conversion,Losses,6.242
H2,Road transport,20.897
Hydro,Electricity grid,6.995
Liquid,Industry,121.066
Liquid,International shipping,128.69
Liquid,Road transport,135.835
Liquid,Domestic aviation,14.458
Liquid,International aviation,206.267
Liquid,Agriculture,3.64
Liquid,National navigation,33.218
Liquid,Rail transport,4.413
Marine algae,Bio-conversion,4.375
Ngas,Gas,122.952
Nuclear,Thermal generation,839.978
Oil imports,Oil,504.287
Oil reserves,Oil,107.703
Oil,Liquid,611.99
Other waste,Solid,56.587
Other waste,Bio-conversion,77.81
Pumped heat,Heating and cooling - homes,193.026
Pumped heat,Heating and cooling - commercial,70.672
Solar PV,Electricity grid,59.901
Solar Thermal,Heating and cooling - homes,19.263
Solar,Solar Thermal,19.263
Solar,Solar PV,59.901
Solid,Agriculture,0.882
Solid,Thermal generation,400.12
Solid,Industry,46.477
Thermal generation,Electricity grid,525.531
Thermal generation,Losses,787.129
Thermal generation,District heating,79.329
Tidal,Electricity grid,9.452
UK land based bioenergy,Bio-conversion,182.01
Wave,Electricity grid,19.013
Wind,Electricity grid,289.366
```
::: details
```mermaid-example
sankey-beta
Agricultural 'waste',Bio-conversion,124.729
Bio-conversion,Liquid,0.597
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
Biofuel imports,Liquid,35
Biomass imports,Solid,35
Coal imports,Coal,11.606
Coal reserves,Coal,63.965
Coal,Solid,75.571
District heating,Industry,10.639
District heating,Heating and cooling - commercial,22.505
District heating,Heating and cooling - homes,46.184
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
Electricity grid,Industry,342.165
Electricity grid,Road transport,37.797
Electricity grid,Agriculture,4.412
Electricity grid,Heating and cooling - commercial,40.858
Electricity grid,Losses,56.691
Electricity grid,Rail transport,7.863
Electricity grid,Lighting & appliances - commercial,90.008
Electricity grid,Lighting & appliances - homes,93.494
Gas imports,Ngas,40.719
Gas reserves,Ngas,82.233
Gas,Heating and cooling - commercial,0.129
Gas,Losses,1.401
Gas,Thermal generation,151.891
Gas,Agriculture,2.096
Gas,Industry,48.58
Geothermal,Electricity grid,7.013
H2 conversion,H2,20.897
H2 conversion,Losses,6.242
H2,Road transport,20.897
Hydro,Electricity grid,6.995
Liquid,Industry,121.066
Liquid,International shipping,128.69
Liquid,Road transport,135.835
Liquid,Domestic aviation,14.458
Liquid,International aviation,206.267
Liquid,Agriculture,3.64
Liquid,National navigation,33.218
Liquid,Rail transport,4.413
Marine algae,Bio-conversion,4.375
Ngas,Gas,122.952
Nuclear,Thermal generation,839.978
Oil imports,Oil,504.287
Oil reserves,Oil,107.703
Oil,Liquid,611.99
Other waste,Solid,56.587
Other waste,Bio-conversion,77.81
Pumped heat,Heating and cooling - homes,193.026
Pumped heat,Heating and cooling - commercial,70.672
Solar PV,Electricity grid,59.901
Solar Thermal,Heating and cooling - homes,19.263
Solar,Solar Thermal,19.263
Solar,Solar PV,59.901
Solid,Agriculture,0.882
Solid,Thermal generation,400.12
Solid,Industry,46.477
Thermal generation,Electricity grid,525.531
Thermal generation,Losses,787.129
Thermal generation,District heating,79.329
Tidal,Electricity grid,9.452
UK land based bioenergy,Bio-conversion,182.01
Wave,Electricity grid,19.013
Wind,Electricity grid,289.366
```
```mermaid
sankey-beta
Agricultural 'waste',Bio-conversion,124.729
Bio-conversion,Liquid,0.597
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
Biofuel imports,Liquid,35
Biomass imports,Solid,35
Coal imports,Coal,11.606
Coal reserves,Coal,63.965
Coal,Solid,75.571
District heating,Industry,10.639
District heating,Heating and cooling - commercial,22.505
District heating,Heating and cooling - homes,46.184
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
Electricity grid,Industry,342.165
Electricity grid,Road transport,37.797
Electricity grid,Agriculture,4.412
Electricity grid,Heating and cooling - commercial,40.858
Electricity grid,Losses,56.691
Electricity grid,Rail transport,7.863
Electricity grid,Lighting & appliances - commercial,90.008
Electricity grid,Lighting & appliances - homes,93.494
Gas imports,Ngas,40.719
Gas reserves,Ngas,82.233
Gas,Heating and cooling - commercial,0.129
Gas,Losses,1.401
Gas,Thermal generation,151.891
Gas,Agriculture,2.096
Gas,Industry,48.58
Geothermal,Electricity grid,7.013
H2 conversion,H2,20.897
H2 conversion,Losses,6.242
H2,Road transport,20.897
Hydro,Electricity grid,6.995
Liquid,Industry,121.066
Liquid,International shipping,128.69
Liquid,Road transport,135.835
Liquid,Domestic aviation,14.458
Liquid,International aviation,206.267
Liquid,Agriculture,3.64
Liquid,National navigation,33.218
Liquid,Rail transport,4.413
Marine algae,Bio-conversion,4.375
Ngas,Gas,122.952
Nuclear,Thermal generation,839.978
Oil imports,Oil,504.287
Oil reserves,Oil,107.703
Oil,Liquid,611.99
Other waste,Solid,56.587
Other waste,Bio-conversion,77.81
Pumped heat,Heating and cooling - homes,193.026
Pumped heat,Heating and cooling - commercial,70.672
Solar PV,Electricity grid,59.901
Solar Thermal,Heating and cooling - homes,19.263
Solar,Solar Thermal,19.263
Solar,Solar PV,59.901
Solid,Agriculture,0.882
Solid,Thermal generation,400.12
Solid,Industry,46.477
Thermal generation,Electricity grid,525.531
Thermal generation,Losses,787.129
Thermal generation,District heating,79.329
Tidal,Electricity grid,9.452
UK land based bioenergy,Bio-conversion,182.01
Wave,Electricity grid,19.013
Wind,Electricity grid,289.366
```
:::
## Syntax
The idea behind syntax is that a user types `sankey-beta` keyword first, then pastes raw CSV below and get the result.
It implements CSV standard as [described here](https://www.ietf.org/rfc/rfc4180.txt) with subtle **differences**:
- CSV must contain **3 columns only**
- It is **allowed** to have **empty lines** without comma separators for visual purposes
### Basic
It is implied that 3 columns inside CSV should represent `source`, `target` and `value` accordingly:
```mermaid-example
sankey-beta
%% source,target,value
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
```
```mermaid
sankey-beta
%% source,target,value
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
```
```mermaid-example
sankey-beta
%% source,target,value
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
```
```mermaid
sankey-beta
%% source,target,value
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
```
### Empty Lines
CSV does not support empty lines without comma delimeters by default. But you can add them if needed:
```mermaid-example
sankey-beta
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
```
```mermaid
sankey-beta
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
```
```mermaid-example
sankey-beta
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
```
```mermaid
sankey-beta
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
```
### Commas
If you need to have a comma, wrap it in double quotes:
```mermaid-example
sankey-beta
Pumped heat,"Heating and cooling, homes",193.026
Pumped heat,"Heating and cooling, commercial",70.672
```
```mermaid
sankey-beta
Pumped heat,"Heating and cooling, homes",193.026
Pumped heat,"Heating and cooling, commercial",70.672
```
```mermaid-example
sankey-beta
Pumped heat,"Heating and cooling, homes",193.026
Pumped heat,"Heating and cooling, commercial",70.672
```
```mermaid
sankey-beta
Pumped heat,"Heating and cooling, homes",193.026
Pumped heat,"Heating and cooling, commercial",70.672
```
### Double Quotes
If you need to have double quote, put a pair of them inside quoted string:
```mermaid-example
sankey-beta
Pumped heat,"Heating and cooling, ""homes""",193.026
Pumped heat,"Heating and cooling, ""commercial""",70.672
```
```mermaid
sankey-beta
Pumped heat,"Heating and cooling, ""homes""",193.026
Pumped heat,"Heating and cooling, ""commercial""",70.672
```
```mermaid-example
sankey-beta
Pumped heat,"Heating and cooling, ""homes""",193.026
Pumped heat,"Heating and cooling, ""commercial""",70.672
```
```mermaid
sankey-beta
Pumped heat,"Heating and cooling, ""homes""",193.026
Pumped heat,"Heating and cooling, ""commercial""",70.672
```
## Configuration
You can customize link colors, node alignments and diagram dimensions.
```html
<script>
const config = {
startOnLoad: true,
securityLevel: 'loose',
sankey: {
width: 800,
height: 400,
linkColor: 'source',
nodeAlignment: 'left',
},
};
mermaid.initialize(config);
</script>
```
### Links Coloring
You can adjust links' color by setting `linkColor` to one of those:
- `source` - link will be of a source node color
- `target` - link will be of a target node color
- `gradient` - link color will be smoothly transient between source and target node colors
- hex code of color, like `#a1a1a1`
### Node Alignment
Graph layout can be changed by setting `nodeAlignment` to:
- `justify`
- `center`
- `left`
- `right`

View File

@ -487,7 +487,7 @@ where
- the second _property_ is `color` and its _value_ is `white` - the second _property_ is `color` and its _value_ is `white`
- the third _property_ is `font-weight` and its _value_ is `bold` - the third _property_ is `font-weight` and its _value_ is `bold`
- the fourth _property_ is `stroke-width` and its _value_ is `2px` - the fourth _property_ is `stroke-width` and its _value_ is `2px`
- the fifth _property_ is `stroke` and its _value_ is `yello` - the fifth _property_ is `stroke` and its _value_ is `yellow`
### Apply classDef styles to states ### Apply classDef styles to states

View File

@ -1,7 +1,7 @@
{ {
"name": "mermaid-monorepo", "name": "mermaid-monorepo",
"private": true, "private": true,
"version": "10.2.3", "version": "10.2.4",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", "description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module", "type": "module",
"packageManager": "pnpm@8.6.5", "packageManager": "pnpm@8.6.5",
@ -22,7 +22,7 @@
"build:watch": "pnpm build:vite --watch", "build:watch": "pnpm build:vite --watch",
"build": "pnpm run -r clean && pnpm build:types && pnpm build:vite", "build": "pnpm run -r clean && pnpm build:types && pnpm build:vite",
"dev": "concurrently \"pnpm build:vite --watch\" \"ts-node-esm .vite/server.ts\"", "dev": "concurrently \"pnpm build:vite --watch\" \"ts-node-esm .vite/server.ts\"",
"dev:coverage": "VITE_COVERAGE=true pnpm dev", "dev:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm dev",
"release": "pnpm build", "release": "pnpm build",
"lint": "eslint --cache --cache-strategy content --ignore-path .gitignore . && pnpm lint:jison && prettier --cache --check .", "lint": "eslint --cache --cache-strategy content --ignore-path .gitignore . && pnpm lint:jison && prettier --cache --check .",
"lint:fix": "eslint --cache --cache-strategy content --fix --ignore-path .gitignore . && prettier --write . && ts-node-esm scripts/fixCSpell.ts", "lint:fix": "eslint --cache --cache-strategy content --fix --ignore-path .gitignore . && prettier --write . && ts-node-esm scripts/fixCSpell.ts",
@ -31,7 +31,8 @@
"cypress": "cypress run", "cypress": "cypress run",
"cypress:open": "cypress open", "cypress:open": "cypress open",
"e2e": "start-server-and-test dev http://localhost:9000/ cypress", "e2e": "start-server-and-test dev http://localhost:9000/ cypress",
"e2e:coverage": "VITE_COVERAGE=true pnpm e2e", "coverage:cypress:clean": "rimraf .nyc_output coverage/cypress",
"e2e:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm e2e",
"coverage:merge": "ts-node-esm scripts/coverage.ts", "coverage:merge": "ts-node-esm scripts/coverage.ts",
"coverage": "pnpm test:coverage --run && pnpm e2e:coverage && pnpm coverage:merge", "coverage": "pnpm test:coverage --run && pnpm e2e:coverage && pnpm coverage:merge",
"ci": "vitest run", "ci": "vitest run",
@ -77,7 +78,7 @@
"@types/rollup-plugin-visualizer": "^4.2.1", "@types/rollup-plugin-visualizer": "^4.2.1",
"@typescript-eslint/eslint-plugin": "^5.59.0", "@typescript-eslint/eslint-plugin": "^5.59.0",
"@typescript-eslint/parser": "^5.59.0", "@typescript-eslint/parser": "^5.59.0",
"@vitest/coverage-istanbul": "^0.32.2", "@vitest/coverage-v8": "^0.32.2",
"@vitest/spy": "^0.32.2", "@vitest/spy": "^0.32.2",
"@vitest/ui": "^0.32.2", "@vitest/ui": "^0.32.2",
"concurrently": "^8.0.1", "concurrently": "^8.0.1",

View File

@ -1,6 +1,6 @@
{ {
"name": "mermaid", "name": "mermaid",
"version": "10.2.3", "version": "10.2.4",
"description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", "description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module", "type": "module",
"module": "./dist/mermaid.core.mjs", "module": "./dist/mermaid.core.mjs",
@ -53,13 +53,16 @@
}, },
"dependencies": { "dependencies": {
"@braintree/sanitize-url": "^6.0.2", "@braintree/sanitize-url": "^6.0.2",
"@types/d3-scale": "^4.0.3",
"@types/d3-scale-chromatic": "^3.0.0",
"cytoscape": "^3.23.0", "cytoscape": "^3.23.0",
"cytoscape-cose-bilkent": "^4.1.0", "cytoscape-cose-bilkent": "^4.1.0",
"cytoscape-fcose": "^2.1.0", "cytoscape-fcose": "^2.1.0",
"d3": "^7.4.0", "d3": "^7.4.0",
"d3-sankey": "^0.12.3",
"dagre-d3-es": "7.0.10", "dagre-d3-es": "7.0.10",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"dompurify": "3.0.3", "dompurify": "3.0.4",
"elkjs": "^0.8.2", "elkjs": "^0.8.2",
"khroma": "^2.0.0", "khroma": "^2.0.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
@ -73,6 +76,7 @@
"devDependencies": { "devDependencies": {
"@types/cytoscape": "^3.19.9", "@types/cytoscape": "^3.19.9",
"@types/d3": "^7.4.0", "@types/d3": "^7.4.0",
"@types/d3-sankey": "^0.12.1",
"@types/d3-selection": "^3.0.5", "@types/d3-selection": "^3.0.5",
"@types/dompurify": "^3.0.2", "@types/dompurify": "^3.0.2",
"@types/jsdom": "^21.1.1", "@types/jsdom": "^21.1.1",

View File

@ -20,7 +20,7 @@
* of src to dst in order. * of src to dst in order.
* @param {any} dst - The destination of the merge * @param {any} dst - The destination of the merge
* @param {any} src - The source object(s) to merge into destination * @param {any} src - The source object(s) to merge into destination
* @param {{ depth: number; clobber: boolean }} [config={ depth: 2, clobber: false }] - Depth: depth * @param {{ depth: number; clobber: boolean }} [config] - Depth: depth
* to traverse within src and dst for merging - clobber: should dissimilar types clobber (default: * to traverse within src and dst for merging - clobber: should dissimilar types clobber (default:
* { depth: 2, clobber: false }). Default is `{ depth: 2, clobber: false }` * { depth: 2, clobber: false }). Default is `{ depth: 2, clobber: false }`
* @returns {any} * @returns {any}

View File

@ -32,6 +32,7 @@ export interface MermaidConfig {
mindmap?: MindmapDiagramConfig; mindmap?: MindmapDiagramConfig;
gitGraph?: GitGraphDiagramConfig; gitGraph?: GitGraphDiagramConfig;
c4?: C4DiagramConfig; c4?: C4DiagramConfig;
sankey?: SankeyDiagramConfig;
dompurifyConfig?: DOMPurify.Config; dompurifyConfig?: DOMPurify.Config;
wrap?: boolean; wrap?: boolean;
fontSize?: number; fontSize?: number;
@ -411,6 +412,26 @@ export interface FlowchartDiagramConfig extends BaseDiagramConfig {
wrappingWidth?: number; wrappingWidth?: number;
} }
export enum SankeyLinkColor {
source = 'source',
target = 'target',
gradient = 'gradient',
}
export enum SankeyNodeAlignment {
left = 'left',
right = 'right',
center = 'center',
justify = 'justify',
}
export interface SankeyDiagramConfig extends BaseDiagramConfig {
width?: number;
height?: number;
linkColor?: SankeyLinkColor | string;
nodeAlignment?: SankeyNodeAlignment;
}
export interface FontConfig { export interface FontConfig {
fontSize?: string | number; fontSize?: string | number;
fontFamily?: string; fontFamily?: string;

View File

@ -1,5 +1,5 @@
import theme from './themes/index.js'; import theme from './themes/index.js';
import { MermaidConfig } from './config.type.js'; import { MermaidConfig, SankeyLinkColor, SankeyNodeAlignment } from './config.type.js';
/** /**
* **Configuration methods in Mermaid version 8.6.0 have been updated, to learn more[[click * **Configuration methods in Mermaid version 8.6.0 have been updated, to learn more[[click
* here](8.6.0_docs.md)].** * here](8.6.0_docs.md)].**
@ -2270,6 +2270,13 @@ const config: Partial<MermaidConfig> = {
padding: 10, padding: 10,
maxNodeWidth: 200, maxNodeWidth: 200,
}, },
sankey: {
width: 800,
height: 400,
linkColor: SankeyLinkColor.gradient,
nodeAlignment: SankeyNodeAlignment.justify,
useMaxWidth: false,
},
fontSize: 16, fontSize: 16,
}; };

View File

@ -18,6 +18,7 @@ import errorDiagram from '../diagrams/error/errorDiagram.js';
import flowchartElk from '../diagrams/flowchart/elk/detector.js'; import flowchartElk from '../diagrams/flowchart/elk/detector.js';
import timeline from '../diagrams/timeline/detector.js'; import timeline from '../diagrams/timeline/detector.js';
import mindmap from '../diagrams/mindmap/detector.js'; import mindmap from '../diagrams/mindmap/detector.js';
import sankey from '../diagrams/sankey/sankeyDetector.js';
import { registerLazyLoadedDiagrams } from './detectType.js'; import { registerLazyLoadedDiagrams } from './detectType.js';
import { registerDiagram } from './diagramAPI.js'; import { registerDiagram } from './diagramAPI.js';
@ -79,6 +80,7 @@ export const addDiagrams = () => {
stateV2, stateV2,
state, state,
journey, journey,
quadrantChart quadrantChart,
sankey
); );
}; };

View File

@ -448,9 +448,8 @@ const getNamespaces = function (): NamespaceMap {
export const addClassesToNamespace = function (id: string, classNames: string[]) { export const addClassesToNamespace = function (id: string, classNames: string[]) {
if (namespaces[id] !== undefined) { if (namespaces[id] !== undefined) {
classNames.map((className) => { classNames.map((className) => {
classes[className].parent = id;
namespaces[id].classes[className] = classes[className]; namespaces[id].classes[className] = classes[className];
delete classes[className];
classCounter--;
}); });
} }
}; };

View File

@ -1373,9 +1373,54 @@ class Class2
parser.parse(str); parser.parse(str);
const testNamespace = parser.yy.getNamespace('Namespace1'); const testNamespace = parser.yy.getNamespace('Namespace1');
const testClasses = parser.yy.getClasses();
expect(Object.keys(testNamespace.classes).length).toBe(2); expect(Object.keys(testNamespace.classes).length).toBe(2);
expect(Object.keys(testNamespace.children).length).toBe(0); expect(Object.keys(testNamespace.children).length).toBe(0);
expect(testNamespace.classes['Class1'].id).toBe('Class1'); expect(testNamespace.classes['Class1'].id).toBe('Class1');
expect(Object.keys(testClasses).length).toBe(2);
});
it('should add relations between classes of different namespaces', function () {
const str = `classDiagram
A1 --> B1
namespace A {
class A1 {
+foo : string
}
class A2 {
+bar : int
}
}
namespace B {
class B1 {
+foo : bool
}
class B2 {
+bar : float
}
}
A2 --> B2`;
parser.parse(str);
const testNamespaceA = parser.yy.getNamespace('A');
const testNamespaceB = parser.yy.getNamespace('B');
const testClasses = parser.yy.getClasses();
const testRelations = parser.yy.getRelations();
expect(Object.keys(testNamespaceA.classes).length).toBe(2);
expect(testNamespaceA.classes['A1'].members[0]).toBe('+foo : string');
expect(testNamespaceA.classes['A2'].members[0]).toBe('+bar : int');
expect(Object.keys(testNamespaceB.classes).length).toBe(2);
expect(testNamespaceB.classes['B1'].members[0]).toBe('+foo : bool');
expect(testNamespaceB.classes['B2'].members[0]).toBe('+bar : float');
expect(Object.keys(testClasses).length).toBe(4);
expect(testClasses['A1'].parent).toBe('A');
expect(testClasses['A2'].parent).toBe('A');
expect(testClasses['B1'].parent).toBe('B');
expect(testClasses['B2'].parent).toBe('B');
expect(testRelations[0].id1).toBe('A1');
expect(testRelations[0].id2).toBe('B1');
expect(testRelations[1].id1).toBe('A2');
expect(testRelations[1].id2).toBe('B2');
}); });
}); });

View File

@ -93,52 +93,51 @@ export const addClasses = function (
log.info(classes); log.info(classes);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition // Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
keys.forEach(function (id) { keys
const vertex = classes[id]; .filter((id) => classes[id].parent == parent)
.forEach(function (id) {
const vertex = classes[id];
/** /**
* Variable for storing the classes for the vertex * Variable for storing the classes for the vertex
*/ */
let cssClassStr = ''; const cssClassStr = vertex.cssClasses.join(' ');
if (vertex.cssClasses.length > 0) {
cssClassStr = cssClassStr + ' ' + vertex.cssClasses.join(' ');
}
const styles = { labelStyle: '', style: '' }; //getStylesFromArray(vertex.styles); const styles = { labelStyle: '', style: '' }; //getStylesFromArray(vertex.styles);
// Use vertex id as text in the box if no text is provided by the graph definition // Use vertex id as text in the box if no text is provided by the graph definition
const vertexText = vertex.label ?? vertex.id; const vertexText = vertex.label ?? vertex.id;
const radius = 0; const radius = 0;
const shape = 'class_box'; const shape = 'class_box';
// Add the node // Add the node
const node = { const node = {
labelStyle: styles.labelStyle, labelStyle: styles.labelStyle,
shape: shape, shape: shape,
labelText: sanitizeText(vertexText), labelText: sanitizeText(vertexText),
classData: vertex, classData: vertex,
rx: radius, rx: radius,
ry: radius, ry: radius,
class: cssClassStr, class: cssClassStr,
style: styles.style, style: styles.style,
id: vertex.id, id: vertex.id,
domId: vertex.domId, domId: vertex.domId,
tooltip: diagObj.db.getTooltip(vertex.id, parent) || '', tooltip: diagObj.db.getTooltip(vertex.id, parent) || '',
haveCallback: vertex.haveCallback, haveCallback: vertex.haveCallback,
link: vertex.link, link: vertex.link,
width: vertex.type === 'group' ? 500 : undefined, width: vertex.type === 'group' ? 500 : undefined,
type: vertex.type, type: vertex.type,
// TODO V10: Flowchart ? Keeping flowchart for backwards compatibility. Remove in next major release // TODO V10: Flowchart ? Keeping flowchart for backwards compatibility. Remove in next major release
padding: getConfig().flowchart?.padding ?? getConfig().class?.padding, padding: getConfig().flowchart?.padding ?? getConfig().class?.padding,
}; };
g.setNode(vertex.id, node); g.setNode(vertex.id, node);
if (parent) { if (parent) {
g.setParent(vertex.id, parent); g.setParent(vertex.id, parent);
} }
log.info('setNode', node); log.info('setNode', node);
}); });
}; };
/** /**

View File

@ -7,6 +7,7 @@ export interface ClassNode {
members: string[]; members: string[];
annotations: string[]; annotations: string[];
domId: string; domId: string;
parent?: string;
link?: string; link?: string;
linkTarget?: string; linkTarget?: string;
haveCallback?: boolean; haveCallback?: boolean;

View File

@ -338,4 +338,20 @@ describe('[Style] when parsing', () => {
expect(edges[0].type).toBe('arrow_point'); expect(edges[0].type).toBe('arrow_point');
}); });
it('should handle multiple vertices with style', function () {
const res = flow.parser.parse(`
graph TD
classDef C1 stroke-dasharray:4
classDef C2 stroke-dasharray:6
A & B:::C1 & D:::C1 --> E:::C2
`);
const vert = flow.parser.yy.getVertices();
expect(vert['A'].classes.length).toBe(0);
expect(vert['B'].classes[0]).toBe('C1');
expect(vert['D'].classes[0]).toBe('C1');
expect(vert['E'].classes[0]).toBe('C2');
});
}); });

View File

@ -359,7 +359,7 @@ statement
separator: NEWLINE | SEMI | EOF ; separator: NEWLINE | SEMI | EOF ;
verticeStatement: verticeStatement link node verticeStatement: verticeStatement link node
{ /* console.warn('vs',$1.stmt,$3); */ yy.addLink($1.stmt,$3,$2); $$ = { stmt: $3, nodes: $3.concat($1.nodes) } } { /* console.warn('vs',$1.stmt,$3); */ yy.addLink($1.stmt,$3,$2); $$ = { stmt: $3, nodes: $3.concat($1.nodes) } }
| verticeStatement link node spaceList | verticeStatement link node spaceList
@ -368,12 +368,16 @@ verticeStatement: verticeStatement link node
|node { /*console.warn('noda', $1);*/ $$ = {stmt: $1, nodes:$1 }} |node { /*console.warn('noda', $1);*/ $$ = {stmt: $1, nodes:$1 }}
; ;
node: vertex node: styledVertex
{ /* console.warn('nod', $1); */ $$ = [$1];} { /* console.warn('nod', $1); */ $$ = [$1];}
| node spaceList AMP spaceList vertex | node spaceList AMP spaceList styledVertex
{ $$ = $1.concat($5); /* console.warn('pip', $1[0], $5, $$); */ } { $$ = $1.concat($5); /* console.warn('pip', $1[0], $5, $$); */ }
;
styledVertex: vertex
{ /* console.warn('nod', $1); */ $$ = $1;}
| vertex STYLE_SEPARATOR idString | vertex STYLE_SEPARATOR idString
{$$ = [$1];yy.setClass($1,$3)} {$$ = $1;yy.setClass($1,$3)}
; ;
vertex: idString SQS text SQE vertex: idString SQS text SQE

View File

@ -0,0 +1,99 @@
%% There are leading and trailing spaces, do not crop
Agricultural 'waste',Bio-conversion,124.729
%% line with a comment
%% Normal line
Bio-conversion,Liquid,0.597
%% Line with unquoted sankey keyword
sankey,target,10
%% Quoted sankey keyword
"sankey",target,10
%% Another normal line
Bio-conversion,Losses,26.862
%% Line with integer amount
Bio-conversion,Solid,280
%% Some blank lines in the middle of CSV
%% Another normal line
Bio-conversion,Gas,81.144
%% Quoted line
"Biofuel imports",Liquid,35
%% Quoted line with escaped quotes inside
"""Biomass imports""",Solid,35
%% Lines containing commas inside
%% Quoted and unquoted values should be equal in terms of graph
"District heating","Heating and cooling, commercial",22.505
District heating,"Heating and cooling, homes",46.184
%% A bunch of lines, normal CSV
Coal imports,Coal,11.606
Coal reserves,Coal,63.965
Coal,Solid,75.571
District heating,Industry,10.639
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
Electricity grid,Industry,342.165
Electricity grid,Road transport,37.797
Electricity grid,Agriculture,4.412
Electricity grid,Heating and cooling - commercial,40.858
Electricity grid,Losses,56.691
Electricity grid,Rail transport,7.863
Electricity grid,Lighting & appliances - commercial,90.008
Electricity grid,Lighting & appliances - homes,93.494
Gas imports,Ngas,40.719
Gas reserves,Ngas,82.233
Gas,Heating and cooling - commercial,0.129
Gas,Losses,1.401
Gas,Thermal generation,151.891
Gas,Agriculture,2.096
Gas,Industry,48.58
Geothermal,Electricity grid,7.013
H2 conversion,H2,20.897
H2 conversion,Losses,6.242
H2,Road transport,20.897
Hydro,Electricity grid,6.995
Liquid,Industry,121.066
Liquid,International shipping,128.69
Liquid,Road transport,135.835
Liquid,Domestic aviation,14.458
Liquid,International aviation,206.267
Liquid,Agriculture,3.64
Liquid,National navigation,33.218
Liquid,Rail transport,4.413
Marine algae,Bio-conversion,4.375
Ngas,Gas,122.952
Nuclear,Thermal generation,839.978
Oil imports,Oil,504.287
Oil reserves,Oil,107.703
Oil,Liquid,611.99
Other waste,Solid,56.587
Other waste,Bio-conversion,77.81
Pumped heat,Heating and cooling - homes,193.026
Pumped heat,Heating and cooling - commercial,70.672
Solar PV,Electricity grid,59.901
Solar Thermal,Heating and cooling - homes,19.263
Solar,Solar Thermal,19.263
Solar,Solar PV,59.901
Solid,Agriculture,0.882
Solid,Thermal generation,400.12
Solid,Industry,46.477
Thermal generation,Electricity grid,525.531
Thermal generation,Losses,787.129
Thermal generation,District heating,79.329
Tidal,Electricity grid,9.452
UK land based bioenergy,Bio-conversion,182.01
"""Wave""",Electricity grid,19.013
"""Wind""",Electricity grid,289.366
%% lines at the end, do not remove
Can't render this file because it has a wrong number of fields in line 2.

View File

@ -0,0 +1,69 @@
/** mermaid */
//---------------------------------------------------------
// We support csv format as defined here:
// https://www.ietf.org/rfc/rfc4180.txt
// There are some minor changes for compliance with jison
// We also parse only 3 columns: source,target,value
// And allow blank lines for visual purposes
//---------------------------------------------------------
%lex
%options case-insensitive
%options easy_keword_rules
%x escaped_text
%x csv
// as per section 6.1 of RFC 2234 [2]
COMMA \u002C
CR \u000D
LF \u000A
CRLF \u000D\u000A
ESCAPED_QUOTE \u0022
DQUOTE \u0022
TEXTDATA [\u0020-\u0021\u0023-\u002B\u002D-\u007E]
%%
<INITIAL>"sankey-beta" { this.pushState('csv'); return 'SANKEY'; }
<INITIAL,csv><<EOF>> { return 'EOF' } // match end of file
<INITIAL,csv>({CRLF}|{LF}) { return 'NEWLINE' }
<INITIAL,csv>{COMMA} { return 'COMMA' }
<INITIAL,csv>{DQUOTE} { this.pushState('escaped_text'); return 'DQUOTE'; }
<INITIAL,csv>{TEXTDATA}* { return 'NON_ESCAPED_TEXT' }
<INITIAL,csv,escaped_text>{DQUOTE}(?!{DQUOTE}) {this.popState('escaped_text'); return 'DQUOTE'; } // unescaped DQUOTE closes string
<INITIAL,csv,escaped_text>({TEXTDATA}|{COMMA}|{CR}|{LF}|{DQUOTE}{DQUOTE})* { return 'ESCAPED_TEXT'; }
/lex
%start start
%% // language grammar
start: SANKEY NEWLINE csv opt_eof;
csv: record csv_tail;
csv_tail: NEWLINE csv | ;
opt_eof: EOF | ;
record
: field\[source] COMMA field\[target] COMMA field\[value] {
const source = yy.findOrCreateNode($source.trim().replaceAll('""', '"'));
const target = yy.findOrCreateNode($target.trim().replaceAll('""', '"'));
const value = parseFloat($value.trim());
yy.addLink(source,target,value);
} // parse only 3 fields, this is not part of CSV standard
;
field
: escaped { $$=$escaped; }
| non_escaped { $$=$non_escaped; }
;
escaped: DQUOTE ESCAPED_TEXT DQUOTE { $$=$ESCAPED_TEXT; };
non_escaped: NON_ESCAPED_TEXT { $$=$NON_ESCAPED_TEXT; };

View File

@ -0,0 +1,24 @@
// @ts-ignore: jison doesn't export types
import sankey from './sankey.jison';
import db from '../sankeyDB.js';
import { cleanupComments } from '../../../diagram-api/comments.js';
import { prepareTextForParsing } from '../sankeyUtils.js';
import * as fs from 'fs';
import * as path from 'path';
describe('Sankey diagram', function () {
describe('when parsing an info graph it', function () {
beforeEach(function () {
sankey.parser.yy = db;
sankey.parser.yy.clear();
});
it('parses csv', async () => {
const csv = path.resolve(__dirname, './energy.csv');
const data = fs.readFileSync(csv, 'utf8');
const graphDefinition = prepareTextForParsing(cleanupComments('sankey-beta\n\n ' + data));
sankey.parser.parse(graphDefinition);
});
});
});

View File

@ -0,0 +1,81 @@
import * as configApi from '../../config.js';
import common from '../common/common.js';
import {
setAccTitle,
getAccTitle,
getAccDescription,
setAccDescription,
setDiagramTitle,
getDiagramTitle,
clear as commonClear,
} from '../../commonDb.js';
// Sankey diagram represented by nodes and links between those nodes
let links: SankeyLink[] = [];
// Array of nodes guarantees their order
let nodes: SankeyNode[] = [];
// We also have to track nodes uniqueness (by ID)
let nodesMap: Record<string, SankeyNode> = {};
const clear = (): void => {
links = [];
nodes = [];
nodesMap = {};
commonClear();
};
class SankeyLink {
constructor(public source: SankeyNode, public target: SankeyNode, public value: number = 0) {}
}
/**
* @param source - Node where the link starts
* @param target - Node where the link ends
* @param value - number, float or integer, describes the amount to be passed
*/
const addLink = (source: SankeyNode, target: SankeyNode, value: number): void => {
links.push(new SankeyLink(source, target, value));
};
class SankeyNode {
constructor(public ID: string) {}
}
const findOrCreateNode = (ID: string): SankeyNode => {
ID = common.sanitizeText(ID, configApi.getConfig());
if (!nodesMap[ID]) {
nodesMap[ID] = new SankeyNode(ID);
nodes.push(nodesMap[ID]);
}
return nodesMap[ID];
};
const getNodes = () => nodes;
const getLinks = () => links;
const getGraph = () => ({
nodes: nodes.map((node) => ({ id: node.ID })),
links: links.map((link) => ({
source: link.source.ID,
target: link.target.ID,
value: link.value,
})),
});
export default {
nodesMap,
getConfig: () => configApi.getConfig().sankey,
getNodes,
getLinks,
getGraph,
addLink,
findOrCreateNode,
getAccTitle,
setAccTitle,
getAccDescription,
setAccDescription,
getDiagramTitle,
setDiagramTitle,
clear,
};

View File

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

View File

@ -0,0 +1,15 @@
import { DiagramDefinition } from '../../diagram-api/types.js';
// @ts-ignore: jison doesn't export types
import parser from './parser/sankey.jison';
import db from './sankeyDB.js';
import renderer from './sankeyRenderer.js';
import { prepareTextForParsing } from './sankeyUtils.js';
const originalParse = parser.parse.bind(parser);
parser.parse = (text: string) => originalParse(prepareTextForParsing(text));
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
};

View File

@ -0,0 +1,205 @@
import { Diagram } from '../../Diagram.js';
import * as configApi from '../../config.js';
import {
select as d3select,
scaleOrdinal as d3scaleOrdinal,
schemeTableau10 as d3schemeTableau10,
} from 'd3';
import {
sankey as d3Sankey,
sankeyLinkHorizontal as d3SankeyLinkHorizontal,
sankeyLeft as d3SankeyLeft,
sankeyRight as d3SankeyRight,
sankeyCenter as d3SankeyCenter,
sankeyJustify as d3SankeyJustify,
SankeyNode as d3SankeyNode,
} from 'd3-sankey';
import { configureSvgSize } from '../../setupGraphViewbox.js';
import { Uid } from '../../rendering-util/uid.js';
import { SankeyLinkColor, SankeyNodeAlignment } from '../../config.type.js';
// Map config options to alignment functions
const alignmentsMap: Record<
SankeyNodeAlignment,
(node: d3SankeyNode<object, object>, n: number) => number
> = {
[SankeyNodeAlignment.left]: d3SankeyLeft,
[SankeyNodeAlignment.right]: d3SankeyRight,
[SankeyNodeAlignment.center]: d3SankeyCenter,
[SankeyNodeAlignment.justify]: d3SankeyJustify,
};
/**
* Draws Sankey diagram.
*
* @param text - The text of the diagram
* @param id - The id of the diagram which will be used as a DOM element id¨
* @param _version - Mermaid version from package.json
* @param diagObj - A standard diagram containing the db and the text and type etc of the diagram
*/
export const draw = function (text: string, id: string, _version: string, diagObj: Diagram): void {
// Get Sankey config
const { securityLevel, sankey: conf } = configApi.getConfig();
const defaultSankeyConfig = configApi!.defaultConfig!.sankey!;
// TODO:
// This code repeats for every diagram
// Figure out what is happening there, probably it should be separated
// The main thing is svg object that is a d3 wrapper for svg operations
//
let sandboxElement: any;
if (securityLevel === 'sandbox') {
sandboxElement = d3select('#i' + id);
}
const root =
securityLevel === 'sandbox'
? d3select(sandboxElement.nodes()[0].contentDocument.body)
: d3select('body');
// @ts-ignore TODO root.select is not callable
const svg = securityLevel === 'sandbox' ? root.select(`[id="${id}"]`) : d3select(`[id="${id}"]`);
// Establish svg dimensions and get width and height
//
const width = conf?.width || defaultSankeyConfig.width!;
const height = conf?.height || defaultSankeyConfig.width!;
const useMaxWidth = conf?.useMaxWidth || defaultSankeyConfig.useMaxWidth!;
const nodeAlignment = conf?.nodeAlignment || defaultSankeyConfig.nodeAlignment!;
// FIX: using max width prevents height from being set, is it intended?
// to add height directly one can use `svg.attr('height', height)`
//
// @ts-ignore TODO: svg type vs selection mismatch
configureSvgSize(svg, height, width, useMaxWidth);
// Prepare data for construction based on diagObj.db
// This must be a mutable object with `nodes` and `links` properties:
//
// {
// "nodes": [ { "id": "Alice" }, { "id": "Bob" }, { "id": "Carol" } ],
// "links": [ { "source": "Alice", "target": "Bob", "value": 23 }, { "source": "Bob", "target": "Carol", "value": 43 } ]
// }
//
// @ts-ignore TODO: db should be coerced to sankey DB type
const graph = diagObj.db.getGraph();
// Get alignment function
const nodeAlign = alignmentsMap[nodeAlignment];
// Construct and configure a Sankey generator
// That will be a function that calculates nodes and links dimensions
//
const nodeWidth = 10;
const sankey = d3Sankey()
.nodeId((d: any) => d.id) // we use 'id' property to identify node
.nodeWidth(nodeWidth)
.nodePadding(10)
.nodeAlign(nodeAlign)
.extent([
[0, 0],
[width, height],
]);
// Compute the Sankey layout: calculate nodes and links positions
// Our `graph` object will be mutated by this and enriched with other properties
//
sankey(graph);
// Get color scheme for the graph
const colorScheme = d3scaleOrdinal(d3schemeTableau10);
// Create rectangles for nodes
svg
.append('g')
.attr('class', 'nodes')
.selectAll('.node')
.data(graph.nodes)
.join('g')
.attr('class', 'node')
.attr('id', (d: any) => (d.uid = Uid.next('node-')).id)
.attr('transform', function (d: any) {
return 'translate(' + d.x0 + ',' + d.y0 + ')';
})
.attr('x', (d: any) => d.x0)
.attr('y', (d: any) => d.y0)
.append('rect')
.attr('height', (d: any) => {
return d.y1 - d.y0;
})
.attr('width', (d: any) => d.x1 - d.x0)
.attr('fill', (d: any) => colorScheme(d.id));
// Create labels for nodes
svg
.append('g')
.attr('class', 'node-labels')
.attr('font-family', 'sans-serif')
.attr('font-size', 14)
.selectAll('text')
.data(graph.nodes)
.join('text')
.attr('x', (d: any) => (d.x0 < width / 2 ? d.x1 + 6 : d.x0 - 6))
.attr('y', (d: any) => (d.y1 + d.y0) / 2)
.attr('dy', '0.35em')
.attr('text-anchor', (d: any) => (d.x0 < width / 2 ? 'start' : 'end'))
.text((d: any) => d.id);
// Creates the paths that represent the links.
const link = svg
.append('g')
.attr('class', 'links')
.attr('fill', 'none')
.attr('stroke-opacity', 0.5)
.selectAll('.link')
.data(graph.links)
.join('g')
.attr('class', 'link')
.style('mix-blend-mode', 'multiply');
const linkColor = conf?.linkColor || SankeyLinkColor.gradient;
if (linkColor === SankeyLinkColor.gradient) {
const gradient = link
.append('linearGradient')
.attr('id', (d: any) => (d.uid = Uid.next('linearGradient-')).id)
.attr('gradientUnits', 'userSpaceOnUse')
.attr('x1', (d: any) => d.source.x1)
.attr('x2', (d: any) => d.target.x0);
gradient
.append('stop')
.attr('offset', '0%')
.attr('stop-color', (d: any) => colorScheme(d.source.id));
gradient
.append('stop')
.attr('offset', '100%')
.attr('stop-color', (d: any) => colorScheme(d.target.id));
}
let coloring: any;
switch (linkColor) {
case SankeyLinkColor.gradient:
coloring = (d: any) => d.uid;
break;
case SankeyLinkColor.source:
coloring = (d: any) => colorScheme(d.source.id);
break;
case SankeyLinkColor.target:
coloring = (d: any) => colorScheme(d.target.id);
break;
default:
coloring = linkColor;
}
link
.append('path')
.attr('d', d3SankeyLinkHorizontal())
.attr('stroke', coloring)
.attr('stroke-width', (d: any) => Math.max(1, d.width));
};
export default {
draw,
};

View File

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

View File

@ -358,7 +358,7 @@ const setupDoc = (g, parentParsedItem, doc, diagramStates, diagramDb, altFlag) =
* Look through all of the documents (docs) in the parsedItems * Look through all of the documents (docs) in the parsedItems
* Because is a _document_ direction, the default direction is not necessarily the same as the overall default _diagram_ direction. * Because is a _document_ direction, the default direction is not necessarily the same as the overall default _diagram_ direction.
* @param {object[]} parsedItem - the parsed statement item to look through * @param {object[]} parsedItem - the parsed statement item to look through
* @param [defaultDir=DEFAULT_NESTED_DOC_DIR] - the direction to use if none is found * @param [defaultDir] - the direction to use if none is found
* @returns {string} * @returns {string}
*/ */
const getDir = (parsedItem, defaultDir = DEFAULT_NESTED_DOC_DIR) => { const getDir = (parsedItem, defaultDir = DEFAULT_NESTED_DOC_DIR) => {

View File

@ -138,6 +138,7 @@ function sidebarSyntax() {
{ text: 'Mindmaps 🔥', link: '/syntax/mindmap' }, { text: 'Mindmaps 🔥', link: '/syntax/mindmap' },
{ text: 'Timeline 🔥', link: '/syntax/timeline' }, { text: 'Timeline 🔥', link: '/syntax/timeline' },
{ text: 'Zenuml 🔥', link: '/syntax/zenuml' }, { text: 'Zenuml 🔥', link: '/syntax/zenuml' },
{ text: 'Sankey 🔥', link: '/syntax/sankey' },
{ text: 'Other Examples', link: '/syntax/examples' }, { text: 'Other Examples', link: '/syntax/examples' },
], ],
}, },

View File

@ -18,7 +18,7 @@ async function download(url: string, fileName: URL) {
const image = await fetch(url); const image = await fetch(url);
await writeFile(fileName, Buffer.from(await image.arrayBuffer())); await writeFile(fileName, Buffer.from(await image.arrayBuffer()));
} catch (error) { } catch (error) {
console.error(error); console.error('failed to load', url, error);
} }
} }
@ -26,10 +26,13 @@ async function fetchAvatars() {
await mkdir(fileURLToPath(new URL(getAvatarPath('none'))).replace('none.png', ''), { await mkdir(fileURLToPath(new URL(getAvatarPath('none'))).replace('none.png', ''), {
recursive: true, recursive: true,
}); });
contributors = JSON.parse(await readFile(pathContributors, { encoding: 'utf-8' })); contributors = JSON.parse(await readFile(pathContributors, { encoding: 'utf-8' }));
for (const name of contributors) { let avatars = contributors.map((name) => {
await download(`https://github.com/${name}.png?size=100`, getAvatarPath(name)); download(`https://github.com/${name}.png?size=100`, getAvatarPath(name));
} });
await Promise.all(avatars);
} }
fetchAvatars(); fetchAvatars();

View File

@ -10,23 +10,27 @@ interface Contributor {
async function fetchContributors() { async function fetchContributors() {
const collaborators: string[] = []; const collaborators: string[] = [];
let page = 1; try {
let data: Contributor[] = []; let page = 1;
do { let data: Contributor[] = [];
const response = await fetch( do {
`https://api.github.com/repos/mermaid-js/mermaid/contributors?per_page=100&page=${page}`, const response = await fetch(
{ `https://api.github.com/repos/mermaid-js/mermaid/contributors?per_page=100&page=${page}`,
method: 'GET', {
headers: { method: 'GET',
'content-type': 'application/json', headers: {
}, 'content-type': 'application/json',
} },
); }
data = await response.json(); );
collaborators.push(...data.map((i) => i.login)); data = await response.json();
console.log(`Fetched page ${page}`); collaborators.push(...data.map((i) => i.login));
page++; console.log(`Fetched page ${page}`);
} while (data.length === 100); page++;
} while (data.length === 100);
} catch (e) {
/* contributors fetching failure must not hinder docs development */
}
return collaborators.filter((name) => !name.includes('[bot]')); return collaborators.filter((name) => !name.includes('[bot]'));
} }

View File

@ -55,9 +55,9 @@ To make a custom theme, modify `themeVariables` via `init`.
You will need to use the [base](#available-themes) theme as it is the only modifiable theme. You will need to use the [base](#available-themes) theme as it is the only modifiable theme.
| Parameter | Description | Type | Properties | | Parameter | Description | Type | Properties |
| -------------- | ------------------------------------ | ------ | --------------------------------------------------------------------------------------------------- | | -------------- | ------------------------------------ | ------ | ----------------------------------------------------------------------------------- |
| themeVariables | Modifiable with the `init` directive | Object | `primaryColor`, `primaryTextColor`, `lineColor` ([see full list](#theme-variables-reference-table)) | | themeVariables | Modifiable with the `init` directive | Object | `primaryColor`, `primaryTextColor`, `lineColor` ([see full list](#theme-variables)) |
Example of modifying `themeVariables` using the `init` directive: Example of modifying `themeVariables` using the `init` directive:

View File

@ -155,6 +155,8 @@ They also serve as proof of concept, for the variety of things that can be built
- [Nano Mermaid](https://github.com/Yash-Singh1/nano-mermaid) - [Nano Mermaid](https://github.com/Yash-Singh1/nano-mermaid)
- [CKEditor](https://github.com/ckeditor/ckeditor5) - [CKEditor](https://github.com/ckeditor/ckeditor5)
- [CKEditor 5 Mermaid plugin](https://github.com/ckeditor/ckeditor5-mermaid) - [CKEditor 5 Mermaid plugin](https://github.com/ckeditor/ckeditor5-mermaid)
- [Standard Notes](https://standardnotes.com/)
- [sn-mermaid](https://github.com/nienow/sn-mermaid)
## Document Generation ## Document Generation

View File

@ -1,7 +1,7 @@
# Announcements # Announcements
## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do/) ## [Sequence diagrams, the only good thing UML brought to software development](https://www.mermaidchart.com/blog/posts/sequence-diagrams-the-good-thing-uml-brought-to-software-development/)
8 June 2023 · 7 mins 15 June 2023 · 12 mins
A quadrant chart is a useful diagram that helps users visualize data and identify patterns in a data set. Sequence diagrams really shine when youre documenting different parts of a system and the various ways these parts interact with each other.

View File

@ -1,5 +1,11 @@
# Blog # Blog
## [Sequence diagrams, the only good thing UML brought to software development](https://www.mermaidchart.com/blog/posts/sequence-diagrams-the-good-thing-uml-brought-to-software-development/)
15 June 2023 · 12 mins
Sequence diagrams really shine when youre documenting different parts of a system and the various ways these parts interact with each other.
## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do/) ## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do/)
8 June 2023 · 7 mins 8 June 2023 · 7 mins

View File

@ -19,13 +19,13 @@ Mermaid can render Gantt diagrams as SVG, PNG or a MarkDown link that can be pas
```mermaid-example ```mermaid-example
gantt gantt
title A Gantt Diagram title A Gantt Diagram
dateFormat YYYY-MM-DD dateFormat YYYY-MM-DD
section Section section Section
A task :a1, 2014-01-01, 30d A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d Another task :after a1, 20d
section Another section Another
Task in sec :2014-01-12 , 12d Task in Another :2014-01-12, 12d
another task : 24d another task :24d
``` ```
## Syntax ## Syntax
@ -66,10 +66,10 @@ gantt
It is possible to set multiple dependencies separated by space: It is possible to set multiple dependencies separated by space:
```mermaid-example ```mermaid-example
gantt gantt
apple :a, 2017-07-20, 1w apple :a, 2017-07-20, 1w
banana :crit, b, 2017-07-23, 1d banana :crit, b, 2017-07-23, 1d
cherry :active, c, after b a, 1d cherry :active, c, after b a, 1d
``` ```
### Title ### Title
@ -88,12 +88,12 @@ You can add milestones to the diagrams. Milestones differ from tasks as they rep
```mermaid-example ```mermaid-example
gantt gantt
dateFormat HH:mm dateFormat HH:mm
axisFormat %H:%M axisFormat %H:%M
Initial milestone : milestone, m1, 17:49,2min Initial milestone : milestone, m1, 17:49, 2m
taska2 : 10min Task A : 10m
taska3 : 5min Task B : 5m
Final milestone : milestone, m2, 18:14, 2min Final milestone : milestone, m2, 18:08, 4m
``` ```
## Setting dates ## Setting dates
@ -214,15 +214,14 @@ Comments can be entered within a gantt chart, which will be ignored by the parse
```mermaid ```mermaid
gantt gantt
title A Gantt Diagram title A Gantt Diagram
%% this is a comment %% This is a comment
dateFormat YYYY-MM-DD dateFormat YYYY-MM-DD
section Section section Section
A task :a1, 2014-01-01, 30d A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d Another task :after a1, 20d
section Another section Another
Task in sec :2014-01-12 , 12d Task in Another :2014-01-12, 12d
another task : 24d another task :24d
``` ```
## Styling ## Styling
@ -350,7 +349,7 @@ Beginner's tip—a full example using interactive links in an html context:
dateFormat YYYY-MM-DD dateFormat YYYY-MM-DD
section Clickable section Clickable
Visit mermaidjs :active, cl1, 2014-01-07, 3d Visit mermaidjs :active, cl1, 2014-01-07, 3d
Print arguments :cl2, after cl1, 3d Print arguments :cl2, after cl1, 3d
Print task :cl3, after cl2, 3d Print task :cl3, after cl2, 3d

View File

@ -0,0 +1,292 @@
# Sankey diagrams
> A sankey diagram is a visualization used to depict a flow from one set of values to another.
::: warning
This is an experimental diagram. Its syntax are very close to plain CSV, but it is to be extended in the nearest future.
:::
The things being connected are called nodes and the connections are called links.
## Example
This example taken from [observable](https://observablehq.com/@d3/sankey/2?collection=@d3/d3-sankey). It may be rendered a little bit differently, though, in terms of size and colors.
```mermaid
sankey-beta
Agricultural 'waste',Bio-conversion,124.729
Bio-conversion,Liquid,0.597
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
Biofuel imports,Liquid,35
Biomass imports,Solid,35
Coal imports,Coal,11.606
Coal reserves,Coal,63.965
Coal,Solid,75.571
District heating,Industry,10.639
District heating,Heating and cooling - commercial,22.505
District heating,Heating and cooling - homes,46.184
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
Electricity grid,Industry,342.165
Electricity grid,Road transport,37.797
Electricity grid,Agriculture,4.412
Electricity grid,Heating and cooling - commercial,40.858
Electricity grid,Losses,56.691
Electricity grid,Rail transport,7.863
Electricity grid,Lighting & appliances - commercial,90.008
Electricity grid,Lighting & appliances - homes,93.494
Gas imports,Ngas,40.719
Gas reserves,Ngas,82.233
Gas,Heating and cooling - commercial,0.129
Gas,Losses,1.401
Gas,Thermal generation,151.891
Gas,Agriculture,2.096
Gas,Industry,48.58
Geothermal,Electricity grid,7.013
H2 conversion,H2,20.897
H2 conversion,Losses,6.242
H2,Road transport,20.897
Hydro,Electricity grid,6.995
Liquid,Industry,121.066
Liquid,International shipping,128.69
Liquid,Road transport,135.835
Liquid,Domestic aviation,14.458
Liquid,International aviation,206.267
Liquid,Agriculture,3.64
Liquid,National navigation,33.218
Liquid,Rail transport,4.413
Marine algae,Bio-conversion,4.375
Ngas,Gas,122.952
Nuclear,Thermal generation,839.978
Oil imports,Oil,504.287
Oil reserves,Oil,107.703
Oil,Liquid,611.99
Other waste,Solid,56.587
Other waste,Bio-conversion,77.81
Pumped heat,Heating and cooling - homes,193.026
Pumped heat,Heating and cooling - commercial,70.672
Solar PV,Electricity grid,59.901
Solar Thermal,Heating and cooling - homes,19.263
Solar,Solar Thermal,19.263
Solar,Solar PV,59.901
Solid,Agriculture,0.882
Solid,Thermal generation,400.12
Solid,Industry,46.477
Thermal generation,Electricity grid,525.531
Thermal generation,Losses,787.129
Thermal generation,District heating,79.329
Tidal,Electricity grid,9.452
UK land based bioenergy,Bio-conversion,182.01
Wave,Electricity grid,19.013
Wind,Electricity grid,289.366
```
::: details
```mermaid-example
sankey-beta
Agricultural 'waste',Bio-conversion,124.729
Bio-conversion,Liquid,0.597
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
Biofuel imports,Liquid,35
Biomass imports,Solid,35
Coal imports,Coal,11.606
Coal reserves,Coal,63.965
Coal,Solid,75.571
District heating,Industry,10.639
District heating,Heating and cooling - commercial,22.505
District heating,Heating and cooling - homes,46.184
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
Electricity grid,Industry,342.165
Electricity grid,Road transport,37.797
Electricity grid,Agriculture,4.412
Electricity grid,Heating and cooling - commercial,40.858
Electricity grid,Losses,56.691
Electricity grid,Rail transport,7.863
Electricity grid,Lighting & appliances - commercial,90.008
Electricity grid,Lighting & appliances - homes,93.494
Gas imports,Ngas,40.719
Gas reserves,Ngas,82.233
Gas,Heating and cooling - commercial,0.129
Gas,Losses,1.401
Gas,Thermal generation,151.891
Gas,Agriculture,2.096
Gas,Industry,48.58
Geothermal,Electricity grid,7.013
H2 conversion,H2,20.897
H2 conversion,Losses,6.242
H2,Road transport,20.897
Hydro,Electricity grid,6.995
Liquid,Industry,121.066
Liquid,International shipping,128.69
Liquid,Road transport,135.835
Liquid,Domestic aviation,14.458
Liquid,International aviation,206.267
Liquid,Agriculture,3.64
Liquid,National navigation,33.218
Liquid,Rail transport,4.413
Marine algae,Bio-conversion,4.375
Ngas,Gas,122.952
Nuclear,Thermal generation,839.978
Oil imports,Oil,504.287
Oil reserves,Oil,107.703
Oil,Liquid,611.99
Other waste,Solid,56.587
Other waste,Bio-conversion,77.81
Pumped heat,Heating and cooling - homes,193.026
Pumped heat,Heating and cooling - commercial,70.672
Solar PV,Electricity grid,59.901
Solar Thermal,Heating and cooling - homes,19.263
Solar,Solar Thermal,19.263
Solar,Solar PV,59.901
Solid,Agriculture,0.882
Solid,Thermal generation,400.12
Solid,Industry,46.477
Thermal generation,Electricity grid,525.531
Thermal generation,Losses,787.129
Thermal generation,District heating,79.329
Tidal,Electricity grid,9.452
UK land based bioenergy,Bio-conversion,182.01
Wave,Electricity grid,19.013
Wind,Electricity grid,289.366
```
:::
## Syntax
The idea behind syntax is that a user types `sankey-beta` keyword first, then pastes raw CSV below and get the result.
It implements CSV standard as [described here](https://www.ietf.org/rfc/rfc4180.txt) with subtle **differences**:
- CSV must contain **3 columns only**
- It is **allowed** to have **empty lines** without comma separators for visual purposes
### Basic
It is implied that 3 columns inside CSV should represent `source`, `target` and `value` accordingly:
```mermaid-example
sankey-beta
%% source,target,value
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
```
```mermaid
sankey-beta
%% source,target,value
Electricity grid,Over generation / exports,104.453
Electricity grid,Heating and cooling - homes,113.726
Electricity grid,H2 conversion,27.14
```
### Empty Lines
CSV does not support empty lines without comma delimeters by default. But you can add them if needed:
```mermaid-example
sankey-beta
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
```
```mermaid
sankey-beta
Bio-conversion,Losses,26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
```
### Commas
If you need to have a comma, wrap it in double quotes:
```mermaid-example
sankey-beta
Pumped heat,"Heating and cooling, homes",193.026
Pumped heat,"Heating and cooling, commercial",70.672
```
```mermaid
sankey-beta
Pumped heat,"Heating and cooling, homes",193.026
Pumped heat,"Heating and cooling, commercial",70.672
```
### Double Quotes
If you need to have double quote, put a pair of them inside quoted string:
```mermaid-example
sankey-beta
Pumped heat,"Heating and cooling, ""homes""",193.026
Pumped heat,"Heating and cooling, ""commercial""",70.672
```
```mermaid
sankey-beta
Pumped heat,"Heating and cooling, ""homes""",193.026
Pumped heat,"Heating and cooling, ""commercial""",70.672
```
## Configuration
You can customize link colors, node alignments and diagram dimensions.
```html
<script>
const config = {
startOnLoad: true,
securityLevel: 'loose',
sankey: {
width: 800,
height: 400,
linkColor: 'source',
nodeAlignment: 'left',
},
};
mermaid.initialize(config);
</script>
```
### Links Coloring
You can adjust links' color by setting `linkColor` to one of those:
- `source` - link will be of a source node color
- `target` - link will be of a target node color
- `gradient` - link color will be smoothly transient between source and target node colors
- hex code of color, like `#a1a1a1`
### Node Alignment
Graph layout can be changed by setting `nodeAlignment` to:
- `justify`
- `center`
- `left`
- `right`

View File

@ -304,7 +304,7 @@ where
- the second _property_ is `color` and its _value_ is `white` - the second _property_ is `color` and its _value_ is `white`
- the third _property_ is `font-weight` and its _value_ is `bold` - the third _property_ is `font-weight` and its _value_ is `bold`
- the fourth _property_ is `stroke-width` and its _value_ is `2px` - the fourth _property_ is `stroke-width` and its _value_ is `2px`
- the fifth _property_ is `stroke` and its _value_ is `yello` - the fifth _property_ is `stroke` and its _value_ is `yellow`
### Apply classDef styles to states ### Apply classDef styles to states

View File

@ -0,0 +1,18 @@
export class Uid {
private static count = 0;
id: string;
href: string;
public static next(name: string): Uid {
return new Uid(name + ++Uid.count);
}
constructor(id: string) {
this.id = id;
this.href = `#${id}`;
}
toString(): string {
return 'url(' + this.href + ')';
}
}

93
pnpm-lock.yaml generated
View File

@ -62,7 +62,7 @@ importers:
'@typescript-eslint/parser': '@typescript-eslint/parser':
specifier: ^5.59.0 specifier: ^5.59.0
version: 5.59.0(eslint@8.39.0)(typescript@5.1.3) version: 5.59.0(eslint@8.39.0)(typescript@5.1.3)
'@vitest/coverage-istanbul': '@vitest/coverage-v8':
specifier: ^0.32.2 specifier: ^0.32.2
version: 0.32.2(vitest@0.32.2) version: 0.32.2(vitest@0.32.2)
'@vitest/spy': '@vitest/spy':
@ -194,6 +194,12 @@ importers:
'@braintree/sanitize-url': '@braintree/sanitize-url':
specifier: ^6.0.2 specifier: ^6.0.2
version: 6.0.2 version: 6.0.2
'@types/d3-scale':
specifier: ^4.0.3
version: 4.0.3
'@types/d3-scale-chromatic':
specifier: ^3.0.0
version: 3.0.0
cytoscape: cytoscape:
specifier: ^3.23.0 specifier: ^3.23.0
version: 3.23.0 version: 3.23.0
@ -206,6 +212,9 @@ importers:
d3: d3:
specifier: ^7.4.0 specifier: ^7.4.0
version: 7.8.2 version: 7.8.2
d3-sankey:
specifier: ^0.12.3
version: 0.12.3
dagre-d3-es: dagre-d3-es:
specifier: 7.0.10 specifier: 7.0.10
version: 7.0.10 version: 7.0.10
@ -213,8 +222,8 @@ importers:
specifier: ^1.11.7 specifier: ^1.11.7
version: 1.11.7 version: 1.11.7
dompurify: dompurify:
specifier: 3.0.3 specifier: 3.0.4
version: 3.0.3 version: 3.0.4
elkjs: elkjs:
specifier: ^0.8.2 specifier: ^0.8.2
version: 0.8.2 version: 0.8.2
@ -249,6 +258,9 @@ importers:
'@types/d3': '@types/d3':
specifier: ^7.4.0 specifier: ^7.4.0
version: 7.4.0 version: 7.4.0
'@types/d3-sankey':
specifier: ^0.12.1
version: 0.12.1
'@types/d3-selection': '@types/d3-selection':
specifier: ^3.0.5 specifier: ^3.0.5
version: 3.0.5 version: 3.0.5
@ -3482,7 +3494,7 @@ packages:
slash: 3.0.0 slash: 3.0.0
string-length: 4.0.2 string-length: 4.0.2
strip-ansi: 6.0.1 strip-ansi: 6.0.1
v8-to-istanbul: 9.0.1 v8-to-istanbul: 9.1.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@ -3984,6 +3996,10 @@ packages:
'@types/d3-color': 3.1.0 '@types/d3-color': 3.1.0
dev: true dev: true
/@types/d3-path@1.0.9:
resolution: {integrity: sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ==}
dev: true
/@types/d3-path@3.0.0: /@types/d3-path@3.0.0:
resolution: {integrity: sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==} resolution: {integrity: sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==}
dev: true dev: true
@ -4000,20 +4016,30 @@ packages:
resolution: {integrity: sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==} resolution: {integrity: sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==}
dev: true dev: true
/@types/d3-scale-chromatic@3.0.0: /@types/d3-sankey@0.12.1:
resolution: {integrity: sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==} resolution: {integrity: sha512-10X6l6lXB42udBNX9/fDN+kJuooifSMk7+x4U9815eobavldqis4wDdFQUQjMazh+qlzsUZsGzXKxfWFUVt+3w==}
dependencies:
'@types/d3-shape': 1.3.8
dev: true dev: true
/@types/d3-scale@4.0.2: /@types/d3-scale-chromatic@3.0.0:
resolution: {integrity: sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==} resolution: {integrity: sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==}
/@types/d3-scale@4.0.3:
resolution: {integrity: sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ==}
dependencies: dependencies:
'@types/d3-time': 3.0.0 '@types/d3-time': 3.0.0
dev: true
/@types/d3-selection@3.0.5: /@types/d3-selection@3.0.5:
resolution: {integrity: sha512-xCB0z3Hi8eFIqyja3vW8iV01+OHGYR2di/+e+AiOcXIOrY82lcvWW8Ke1DYE/EUVMsBl4Db9RppSBS3X1U6J0w==} resolution: {integrity: sha512-xCB0z3Hi8eFIqyja3vW8iV01+OHGYR2di/+e+AiOcXIOrY82lcvWW8Ke1DYE/EUVMsBl4Db9RppSBS3X1U6J0w==}
dev: true dev: true
/@types/d3-shape@1.3.8:
resolution: {integrity: sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==}
dependencies:
'@types/d3-path': 1.0.9
dev: true
/@types/d3-shape@3.1.0: /@types/d3-shape@3.1.0:
resolution: {integrity: sha512-jYIYxFFA9vrJ8Hd4Se83YI6XF+gzDL1aC5DCsldai4XYYiVNdhtpGbA/GM6iyQ8ayhSp3a148LY34hy7A4TxZA==} resolution: {integrity: sha512-jYIYxFFA9vrJ8Hd4Se83YI6XF+gzDL1aC5DCsldai4XYYiVNdhtpGbA/GM6iyQ8ayhSp3a148LY34hy7A4TxZA==}
dependencies: dependencies:
@ -4026,7 +4052,6 @@ packages:
/@types/d3-time@3.0.0: /@types/d3-time@3.0.0:
resolution: {integrity: sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==} resolution: {integrity: sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==}
dev: true
/@types/d3-timer@3.0.0: /@types/d3-timer@3.0.0:
resolution: {integrity: sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==} resolution: {integrity: sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==}
@ -4069,7 +4094,7 @@ packages:
'@types/d3-polygon': 3.0.0 '@types/d3-polygon': 3.0.0
'@types/d3-quadtree': 3.0.2 '@types/d3-quadtree': 3.0.2
'@types/d3-random': 3.0.1 '@types/d3-random': 3.0.1
'@types/d3-scale': 4.0.2 '@types/d3-scale': 4.0.3
'@types/d3-scale-chromatic': 3.0.0 '@types/d3-scale-chromatic': 3.0.0
'@types/d3-selection': 3.0.5 '@types/d3-selection': 3.0.5
'@types/d3-shape': 3.1.0 '@types/d3-shape': 3.1.0
@ -4879,17 +4904,22 @@ packages:
vue: 3.3.4 vue: 3.3.4
dev: true dev: true
/@vitest/coverage-istanbul@0.32.2(vitest@0.32.2): /@vitest/coverage-v8@0.32.2(vitest@0.32.2):
resolution: {integrity: sha512-B5VSvfzwTsDt9HjFmQ4sZ2tQHivmHJpAoG/BJwNNQeBtSCSdY1L6tfCjwZLo7ryOmZEDA3ck/DAmHCUZqa+MWA==} resolution: {integrity: sha512-/+V3nB3fyeuuSeKxCfi6XmWjDIxpky7AWSkGVfaMjAk7di8igBwRsThLjultwIZdTDH1RAxpjmCXEfSqsMFZOA==}
peerDependencies: peerDependencies:
vitest: '>=0.32.0 <1' vitest: '>=0.32.0 <1'
dependencies: dependencies:
'@ampproject/remapping': 2.2.1
'@bcoe/v8-coverage': 0.2.3
istanbul-lib-coverage: 3.2.0 istanbul-lib-coverage: 3.2.0
istanbul-lib-instrument: 5.2.1
istanbul-lib-report: 3.0.0 istanbul-lib-report: 3.0.0
istanbul-lib-source-maps: 4.0.1 istanbul-lib-source-maps: 4.0.1
istanbul-reports: 3.1.5 istanbul-reports: 3.1.5
magic-string: 0.30.0
picocolors: 1.0.0
std-env: 3.3.2
test-exclude: 6.0.0 test-exclude: 6.0.0
v8-to-istanbul: 9.1.0
vitest: 0.32.2(@vitest/ui@0.32.2)(jsdom@22.0.0) vitest: 0.32.2(@vitest/ui@0.32.2)(jsdom@22.0.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -7139,6 +7169,12 @@ packages:
lodash: 4.17.21 lodash: 4.17.21
dev: false dev: false
/d3-array@2.12.1:
resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==}
dependencies:
internmap: 1.0.1
dev: false
/d3-array@3.2.0: /d3-array@3.2.0:
resolution: {integrity: sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==} resolution: {integrity: sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -7256,6 +7292,10 @@ packages:
d3-color: 3.1.0 d3-color: 3.1.0
dev: false dev: false
/d3-path@1.0.9:
resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==}
dev: false
/d3-path@3.0.1: /d3-path@3.0.1:
resolution: {integrity: sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==} resolution: {integrity: sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -7276,6 +7316,13 @@ packages:
engines: {node: '>=12'} engines: {node: '>=12'}
dev: false dev: false
/d3-sankey@0.12.3:
resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==}
dependencies:
d3-array: 2.12.1
d3-shape: 1.3.7
dev: false
/d3-scale-chromatic@3.0.0: /d3-scale-chromatic@3.0.0:
resolution: {integrity: sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==} resolution: {integrity: sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -7300,6 +7347,12 @@ packages:
engines: {node: '>=12'} engines: {node: '>=12'}
dev: false dev: false
/d3-shape@1.3.7:
resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==}
dependencies:
d3-path: 1.0.9
dev: false
/d3-shape@3.1.0: /d3-shape@3.1.0:
resolution: {integrity: sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==} resolution: {integrity: sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -7704,8 +7757,8 @@ packages:
domelementtype: 2.3.0 domelementtype: 2.3.0
dev: true dev: true
/dompurify@3.0.3: /dompurify@3.0.4:
resolution: {integrity: sha512-axQ9zieHLnAnHh0sfAamKYiqXMJAVwu+LM/alQ7WDagoWessyWvMSFyW65CqF3owufNu8HBcE4cM2Vflu7YWcQ==} resolution: {integrity: sha512-ae0mA+Qiqp6C29pqZX3fQgK+F91+F7wobM/v8DRzDqJdZJELXiFUx4PP4pK/mzUS0xkiSEx3Ncd9gr69jg3YsQ==}
dev: false dev: false
/domutils@3.0.1: /domutils@3.0.1:
@ -9535,6 +9588,10 @@ packages:
side-channel: 1.0.4 side-channel: 1.0.4
dev: true dev: true
/internmap@1.0.1:
resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==}
dev: false
/internmap@2.0.3: /internmap@2.0.3:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -14700,8 +14757,8 @@ packages:
/v8-compile-cache-lib@3.0.1: /v8-compile-cache-lib@3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
/v8-to-istanbul@9.0.1: /v8-to-istanbul@9.1.0:
resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==} resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==}
engines: {node: '>=10.12.0'} engines: {node: '>=10.12.0'}
dependencies: dependencies:
'@jridgewell/trace-mapping': 0.3.17 '@jridgewell/trace-mapping': 0.3.17

81
run
View File

@ -1,40 +1,93 @@
#!/bin/bash #!/bin/bash
RUN="docker-compose run --rm" RUN="docker-compose run --rm"
ansi() { echo -e "\e[${1}m${*:2}\e[0m"; }
bold() { ansi 1 "$@"; }
# italic() { ansi 3 "$@"; }
underline() { ansi 4 "$@"; }
# strikethrough() { ansi 9 "$@"; }
# red() { ansi 31 "$@"; }
name=$(basename $0)
command=$1 command=$1
args=${@:2} args=${@:2}
case $command in case $command in
sh) sh)
$RUN mermaid sh $args $RUN mermaid sh -c "npx $args"
;; ;;
install) pnpm)
$RUN mermaid sh -c "npx pnpm install" $RUN mermaid sh -c "npx pnpm $args"
;; ;;
test) dev)
$RUN mermaid sh -c "npx pnpm test" $RUN --service-ports mermaid sh -c "npx pnpm run dev"
;; ;;
lint) docs:dev)
$RUN mermaid sh -c "npx pnpm -w run lint:fix" $RUN --service-ports mermaid sh -c "cd packages/mermaid/src/docs && npx pnpm prefetch && npx vitepress --port 3333 --host"
;;
cypress)
$RUN cypress $args
;; ;;
help) help)
# Alignment of help message must be as it is, it will be nice looking when printed
usage=$(
cat <<EOF cat <<EOF
Run commonly used commands within docker containers
$0 install # Equvalent of pnpm install $(bold MERMAID LOCAL DOCKER DEVELOPMENT)
$0 lint # Equvalent of pnpm -w run lint:fix
$0 sh # Open sh inside docker container for development Welcome! Thank you for joining the development.
This is a script for running commands within docker containers at ease.
__________________________________________________________________________________________
Development quick start guide:
$(bold ./$name pnpm install) # Install packages
$(bold ./$name dev) # Run dev server with examples, open http://localhost:9000
$(bold ./$name pnpm vitest) # Run watcher for unit tests
$(bold ./$name cypress) # Run integration tests (after starting dev server)
$(bold ./$name pnpm build) # Prepare it for production
$(bold ./$name docs:dev) # Then add documentation, open http://localhost:3333
__________________________________________________________________________________________
Commands:
$(bold ./$name pnpm) # Run any 'pnpm' command
$(bold ./$name dev) # Run dev server with examples, open http://localhost:9000
$(bold ./$name docs:dev) # For docs contributions, open http://localhost:3333
$(bold ./$name cypress) # Run integration tests
$(bold ./$name sh) # Open 'sh' inside docker container for development
$(bold ./$name help) # Show this help
__________________________________________________________________________________________
Examples of frequiently used commands:
$(bold ./$name pnpm add --filter mermaid) $(underline package)
Add package to mermaid
$(bold git diff --name-only develop \| xargs ./$name pnpm prettier --write)
Prettify everything you added so far
$(bold ./$name cypress open --project .)
Open cypress interactive GUI
$(bold ./$name cypress run --spec cypress/integration/rendering/)$(underline test.spec.ts)
Run specific test in cypress\n
$0 help # Show this help
EOF EOF
)
echo -n -e "$usage"
;; ;;
*) *)
$0 help $name help
;; ;;
esac esac

View File

@ -17,7 +17,7 @@ export default defineConfig({
// TODO: should we move this to a mermaid-core package? // TODO: should we move this to a mermaid-core package?
setupFiles: ['packages/mermaid/src/tests/setup.ts'], setupFiles: ['packages/mermaid/src/tests/setup.ts'],
coverage: { coverage: {
provider: 'istanbul', provider: 'v8',
reporter: ['text', 'json', 'html', 'lcov'], reporter: ['text', 'json', 'html', 'lcov'],
reportsDirectory: './coverage/vitest', reportsDirectory: './coverage/vitest',
exclude: ['**/node_modules/**', '**/tests/**', '**/__mocks__/**'], exclude: ['**/node_modules/**', '**/tests/**', '**/__mocks__/**'],