Merge branch 'develop' into sidv/esbuildV10

* develop: (57 commits)
  fix Lint
  Update CHANGELOG.md
  Update CHANGELOG.md
  fix: fix exports
  Fix readme link
  Regenerate mermaid docs
  Add deepdwn to cspell
  Add Deepdwn to native integrations list
  docs: Fix changelog
  docs: v10 breaking changes
  Remove `null` from diagrams before render
  fix docs diagram
  Updated version
  Minor cleanup to trigger build.
  Fix spellings
  Wrap option working in test case
  Fix typos
  Minor cleanup
  Removed the deprecated use of mindmap in Demo
  Minor cleanup
  ...
This commit is contained in:
Sidharth Vinod
2023-02-24 13:23:47 +05:30
77 changed files with 1156 additions and 781 deletions

View File

@@ -1,4 +1,4 @@
blank_issues_enabled: false
blank_issues_enabled: true
contact_links:
- name: GitHub Discussions
url: https://github.com/mermaid-js/mermaid/discussions

View File

@@ -1,6 +1,105 @@
# Change Log
# Changelog
// TODO: Populate changelog
## [10.0.0](https://github.com/mermaid-js/mermaid/releases/tag/v10.0.0)
### Mermaid is ESM only!
We've dropped CJS support. So, you will have to update your import scripts as follows.
```html
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
</script>
```
You can keep using v9 by adding the `@9` in the CDN URL.
```diff
- <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/mermaid@9/dist/mermaid.js"></script>
```
### mermaid.render is async and doesn't accept callbacks
```js
// < v10
mermaid.render('id', 'graph TD;\nA-->B', (svg, bindFunctions) => {
element.innerHTML = svg;
if (bindFunctions) {
bindFunctions(element);
}
});
// Shorter syntax
if (bindFunctions) {
bindFunctions(element);
}
// can be replaced with the `?.` shorthand
bindFunctions?.(element);
// >= v10 with async/await
const { svg, bindFunctions } = await mermaid.render('id', 'graph TD;\nA-->B');
element.innerHTML = svg;
bindFunctions?.(element);
// >= v10 with promise.then
mermaid.render('id', 'graph TD;A-->B').then(({ svg, bindFunctions }) => {
element.innerHTML = svg;
bindFunctions?.(element);
});
```
### mermaid.parse is async and ParseError is removed
```js
// < v10
mermaid.parse(text, parseError);
//>= v10
await mermaid.parse(text).catch(parseError);
// or
try {
await mermaid.parse(text);
} catch (err) {
parseError(err);
}
```
### Init deprecated and InitThrowsErrors removed
The config passed to `init` was not being used eariler.
It will now be used.
The `init` function is deprecated and will be removed in the next major release.
init currently works as a wrapper to `initialize` and `run`.
```js
// < v10
mermaid.init(config, selector, cb);
//>= v10
mermaid.initialize(config);
mermaid.run({
querySelector: selector,
postRenderCallback: cb,
suppressErrors: true,
});
```
```js
// < v10
mermaid.initThrowsErrors(config, selector, cb);
//>= v10
mermaid.initialize(config);
mermaid.run({
querySelector: selector,
postRenderCallback: cb,
suppressErrors: false,
});
```
// TODO: Populate changelog pre v10
- Config has a lot of changes
- globalReset resets to `defaultConfig` instead of current config. Use `reset` instead.

View File

@@ -8,7 +8,7 @@ Mermaid
Generate diagrams from markdown-like text.
<p>
<p align="center">
<a href="https://www.npmjs.com/package/vitest"><img src="https://img.shields.io/npm/v/mermaid?color=ff3670&label="></a>
<a href="https://www.npmjs.com/package/mermaid"><img src="https://img.shields.io/npm/v/mermaid?color=ff3670&label="></a>
<p>
<p align="center">

View File

@@ -8,7 +8,7 @@ Mermaid
通过解析类 Markdown 的文本语法来实现图表的创建和动态修改。
<p>
<p align="center">
<a href="https://www.npmjs.com/package/vitest"><img src="https://img.shields.io/npm/v/mermaid?color=ff3670&label="></a>
<a href="https://www.npmjs.com/package/mermaid"><img src="https://img.shields.io/npm/v/mermaid?color=ff3670&label="></a>
<p>
<p align="center">

View File

@@ -1,58 +0,0 @@
# A collection of updates that change the behavior
## Async
`parse`, `render` are now async.
## Lazy loading and asynchronisity
- Invalid dates are rendered as syntax error instead of returning best guess or the current date
## ParseError is removed
```js
//< v10.0.0
mermaid.parse(text, parseError);
//>= v10.0.0
await mermaid.parse(text).catch(parseError);
// or
try {
await mermaid.parse(text);
} catch (err) {
parseError(err);
}
```
## Init deprecated and InitThrowsErrors removed
The config passed to `init` was not being used eariler.
It will now be used.
The `init` function is deprecated and will be removed in the next major release.
init currently works as a wrapper to `initialize` and `run`.
```js
//< v10.0.0
mermaid.init(config, selector, cb);
//>= v10.0.0
mermaid.initialize(config);
mermaid.run({
querySelector: selector,
postRenderCallback: cb,
suppressErrors: true,
});
```
```js
//< v10.0.0
mermaid.initThrowsErrors(config, selector, cb);
//>= v10.0.0
mermaid.initialize(config);
mermaid.run({
querySelector: selector,
postRenderCallback: cb,
suppressErrors: false,
});
```

View File

@@ -27,6 +27,7 @@
"cuzon",
"cytoscape",
"dagre",
"deepdwn",
"descr",
"docsify",
"docsy",

View File

@@ -188,7 +188,7 @@ describe('Entity Relationship Diagram', () => {
erDiagram
CLUSTER {
varchar(99) name
string(255) description
string(255) description
}
`,
{ logLevel: 1 }

View File

@@ -670,6 +670,17 @@ title: Simple flowchart
---
flowchart TD
A --> B
`,
{ titleTopMargin: 0 }
);
});
it('3192: It should be possieble to render flowcharts with invisible edges', () => {
imgSnapshotTest(
`---
title: Simple flowchart with invisible edges
---
flowchart TD
A ~~~ B
`,
{ titleTopMargin: 0 }
);

View File

@@ -116,7 +116,11 @@ context('Sequence diagram', () => {
loop Loopy
Bob->>Alice: Pasten
end `,
{ wrap: true }
{
sequence: {
wrap: true,
},
}
);
});
context('font settings', () => {

View File

@@ -0,0 +1,46 @@
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
<style>
body {
font-family: 'trebuchet ms', verdana, arial;
}
</style>
</head>
<body>
<pre class="mermaid">
graph TB
subgraph One
a1-->a2-->a3
end
</pre>
<pre class="mermaid">
graph TB
a_a --> b_b:::apa --> c_c:::apa
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
class a_a apa;
</pre>
<pre class="mermaid">
graph TB
a_a(Aftonbladet) --> b_b[gorilla]:::apa --> c_c{chimp}:::apa -->a_a
a_a --> c --> d_d --> c_c
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
class a_a apa;
click a_a "http://www.aftonbladet.se" "apa"
</pre>
<script type="module">
import mermaid from '../../packages/mermaid/src/mermaid';
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
logLevel: 3,
flowchart: { curve: 'linear' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>
</body>
</html>

View File

@@ -46,7 +46,7 @@ const contentLoaded = async function () {
await mermaid2.registerExternalDiagrams([externalExample]);
mermaid2.initialize(graphObj.mermaid);
await mermaid2.init();
await mermaid2.run();
markRendered();
}
};

View File

@@ -17,7 +17,7 @@
<h1>Journey diagram demo</h1>
<pre class="mermaid">
---
title: My working day
title: My working day
---
journey
accTitle: Very simple journey demo

View File

@@ -8,41 +8,6 @@
[mermaidAPI](../modules/mermaidAPI.md).RenderResult
Function that renders an svg with a graph from a chart definition. Usage example below.
```javascript
mermaidAPI.initialize({
startOnLoad: true,
});
$(function () {
const graphDefinition = 'graph TB\na-->b';
const cb = function (svgGraph) {
console.log(svgGraph);
};
mermaidAPI.render('id1', graphDefinition, cb);
});
```
**`Param`**
The id for the SVG element (the element to be rendered)
**`Param`**
The text for the graph definition
**`Param`**
Callback which is called after rendering is finished with the svg code as in param.
**`Param`**
HTML element where the svg will be inserted. (Is usually element with the .mermaid class)
If no svgContainingElement is provided then the SVG element will be appended to the body.
Selector to element in which a div with the graph temporarily will be
inserted. If one is provided a hidden div will be inserted in the body of the page instead. The
element will be removed when rendering is completed.
## Properties
### bindFunctions
@@ -53,6 +18,15 @@ element will be removed when rendering is completed.
▸ (`element`): `void`
Bind function to be called after the svg has been inserted into the DOM.
This is necessary for adding event listeners to the elements in the svg.
```js
const { svg, bindFunctions } = mermaidAPI.render('id1', 'graph TD;A-->B');
div.innerHTML = svg;
bindFunctions?.(div); // To call bindFunctions only if it's present.
```
##### Parameters
| Name | Type |
@@ -65,7 +39,7 @@ element will be removed when rendering is completed.
#### Defined in
[mermaidAPI.ts:384](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L384)
[mermaidAPI.ts:91](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L91)
---
@@ -73,6 +47,8 @@ element will be removed when rendering is completed.
**svg**: `string`
The svg code for the rendered graph.
#### Defined in
[mermaidAPI.ts:383](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L383)
[mermaidAPI.ts:81](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L81)

View File

@@ -95,7 +95,7 @@ mermaid.initialize(config);
#### Defined in
[mermaidAPI.ts:668](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L668)
[mermaidAPI.ts:680](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L680)
## Functions
@@ -126,7 +126,7 @@ Return the last node appended
#### Defined in
[mermaidAPI.ts:291](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L291)
[mermaidAPI.ts:308](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L308)
---
@@ -152,7 +152,7 @@ the cleaned up svgCode
#### Defined in
[mermaidAPI.ts:242](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L242)
[mermaidAPI.ts:259](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L259)
---
@@ -178,7 +178,7 @@ the string with all the user styles
#### Defined in
[mermaidAPI.ts:171](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L171)
[mermaidAPI.ts:188](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L188)
---
@@ -201,7 +201,7 @@ the string with all the user styles
#### Defined in
[mermaidAPI.ts:219](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L219)
[mermaidAPI.ts:236](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L236)
---
@@ -228,7 +228,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
#### Defined in
[mermaidAPI.ts:155](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L155)
[mermaidAPI.ts:172](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L172)
---
@@ -248,7 +248,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
#### Defined in
[mermaidAPI.ts:135](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L135)
[mermaidAPI.ts:152](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L152)
---
@@ -268,7 +268,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
#### Defined in
[mermaidAPI.ts:106](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L106)
[mermaidAPI.ts:123](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L123)
---
@@ -294,7 +294,7 @@ Put the svgCode into an iFrame. Return the iFrame code
#### Defined in
[mermaidAPI.ts:270](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L270)
[mermaidAPI.ts:287](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L287)
---
@@ -319,4 +319,4 @@ Remove any existing elements from the given document
#### Defined in
[mermaidAPI.ts:341](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L341)
[mermaidAPI.ts:358](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L358)

View File

@@ -20,21 +20,24 @@ Please note that you can switch versions through the dropdown box at the top rig
For the majority of users, Using the [Live Editor](https://mermaid.live/) would be sufficient, however you may also opt to deploy mermaid as a dependency or using the [Mermaid API](./setup/README.md).
We have compiled some Video [Tutorials](./Tutorials.md) on how to use the mermaid Live Editor.
We have compiled some Video [Tutorials](./Tutorials.md) on how to use the Mermaid Live Editor.
### Installing and Hosting Mermaid on a Webpage
**Using the npm package:**
1. You will need to install `node v16`, which would have npm.
Requirements:
2. Download `yarn` using npm.
- Node >= 16
3. Enter the following command: `yarn add mermaid`.
4. At this point, you can add mermaid as a dev dependency using this command: `yarn add --dev mermaid`.
5. Alternatively, you can also deploy mermaid using the script tag in an HTML file with mermaid diagram descriptions as is shown in the example below.
```bash
# NPM
npm install mermaid
# Yarn
yarn add mermaid
# PNPM
pnpm add mermaid
```
**Hosting mermaid on a web page:**
@@ -42,7 +45,9 @@ We have compiled some Video [Tutorials](./Tutorials.md) on how to use the mermai
The easiest way to integrate mermaid on a web page requires two elements:
- A graph definition, inside `<pre>` tags labeled `class=mermaid`. Example:
- A graph definition, inside `<pre>` tags labeled `class=mermaid`.
Example:
```html
<pre class="mermaid">
@@ -53,14 +58,13 @@ The easiest way to integrate mermaid on a web page requires two elements:
</pre>
```
- Inclusion of the mermaid address in the html page body using a `script` tag as an ESM import, and the `mermaidAPI` call.
- The mermaid js script. Added using a `script` tag as an ESM import.
Example:
```html
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
</script>
```
@@ -71,9 +75,6 @@ Example:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>
<body>
<pre class="mermaid">
graph LR
@@ -83,7 +84,6 @@ Example:
</pre>
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
</script>
</body>
</html>
@@ -95,11 +95,12 @@ An id attribute is also added to mermaid tags without one.
Mermaid can load multiple diagrams, in the same page.
> Try it out, save this code as HTML and load it using any browser.(Except Internet Explorer, please don't use Internet Explorer.)
> Try it out, save this code as HTML and load it using any browser.
> (Except Internet Explorer, please don't use Internet Explorer.)
## Enabling Click Event and Tags in Nodes
A `securityLevel` configuration has to first be cleared, `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduce in version 8.2 as a security improvement, aimed at preventing malicious use.
A `securityLevel` configuration has to first be cleared. `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduce in version 8.2 as a security improvement, aimed at preventing malicious use.
**It is the site owner's responsibility to discriminate between trustworthy and untrustworthy user-bases and we encourage the use of discretion.**
@@ -107,7 +108,7 @@ A `securityLevel` configuration has to first be cleared, `securityLevel` sets th
| Parameter | Description | Type | Required | Values |
| ------------- | --------------------------------- | ------ | -------- | ------------------------------------------ |
| securityLevel | Level of trust for parsed diagram | String | Required | 'sandbox', 'strict', 'loose', 'antiscript' |
| securityLevel | Level of trust for parsed diagram | String | Optional | 'sandbox', 'strict', 'loose', 'antiscript' |
Values:
@@ -122,26 +123,17 @@ Values:
**If you are taking responsibility for the diagram source security you can set the `securityLevel` to a value of your choosing . This allows clicks and tags are allowed.**
**To change `securityLevel`, you have to call `mermaidAPI.initialize`:**
**To change `securityLevel`, you have to call `mermaid.initialize`:**
```javascript
mermaidAPI.initialize({
mermaid.initialize({
securityLevel: 'loose',
});
```
### Labels out of bounds
If you use dynamically loaded fonts that are loaded through CSS, such as Google fonts, mermaid should wait for the
whole page to load (dom + assets, particularly the fonts file).
```javascript
$(document).load(function () {
mermaid.initialize();
});
```
or
If you use dynamically loaded fonts that are loaded through CSS, such as fonts, mermaid should wait for the whole page to load (dom + assets, particularly the fonts file).
```javascript
$(document).ready(function () {
@@ -154,12 +146,54 @@ Not doing so will most likely result in mermaid rendering graphs that have label
If your page has other fonts in its body those might be used instead of the mermaid font. Specifying the font in your styling is a workaround for this.
```css
div.mermaid {
pre.mermaid {
font-family: 'trebuchet ms', verdana, arial;
}
```
### Calling `mermaid.init`
### Using `mermaid.run`
mermaid.run was added in v10 and is the preferred way of handling more complex integration.
By default, `mermaid.run` will be called when the document is ready, rendering all elements with `class="mermaid"`.
You can customize that behavior by calling `await mermaid.run(<config>)`.
`mermaid.initialize({startOnLoad: false})` will prevent `mermaid.run` from being called automatically after load.
Render all elements with querySelector ".someOtherClass"
```js
mermaid.initialize({ startOnLoad: false });
await mermaid.run({
querySelector: '.someOtherClass',
});
```
Render all elements passed as an array
```js
mermaid.initialize({ startOnLoad: false });
await mermaid.run({
nodes: [document.getElementById('someId'), document.getElementById('anotherId')],
});
await mermaid.run({
nodes: document.querySelectorAll('.yetAnotherClass'),
});
```
Render all `.mermaid` elements while suppressing any error
```js
mermaid.initialize({ startOnLoad: false });
await mermaid.run({
suppressErrors: true,
});
```
### Calling `mermaid.init` - Deprecated
> **Warning**
> mermaid.init is deprecated in v10 and will be removed in v11. Please use mermaid.run instead.
By default, `mermaid.init` will be called when the document is ready, finding all elements with
`class="mermaid"`. If you are adding content after mermaid is loaded, or otherwise need
@@ -192,25 +226,24 @@ mermaid fully supports webpack. Here is a [working demo](https://github.com/merm
## API usage
The main idea of the API is to be able to call a render function with the graph definition as a string. The render function
will render the graph and call a callback with the resulting SVG code. With this approach it is up to the site creator to
fetch the graph definition from the site (perhaps from a textarea), render it and place the graph somewhere in the site.
The main idea of the API is to be able to call a render function with the graph definition as a string. The render function will render the graph and call a callback with the resulting SVG code. With this approach it is up to the site creator to fetch the graph definition from the site (perhaps from a textarea), render it and place the graph somewhere in the site.
The example below show an outline of how this could be used. The example just logs the resulting SVG to the JavaScript console.
```html
<script type="module">
import mermaid from './mermaid.mjs';
mermaid.mermaidAPI.initialize({ startOnLoad: false });
$(async function () {
// Example of using the API var
import mermaid from './mermaid.esm.mjs';
mermaid.initialize({ startOnLoad: false });
// Example of using the render function
const drawDiagram = async function () {
element = document.querySelector('#graphDiv');
const insertSvg = function (svgCode, bindFunctions) {
element.innerHTML = svgCode;
};
const graphDefinition = 'graph TB\na-->b';
const graph = await mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg);
});
const { svg } = await mermaid.render('graphDiv', graphDefinition);
element.innerHTML = svg;
};
await drawDiagram();
</script>
```
@@ -223,17 +256,17 @@ The example code below is an extract of what mermaid does when using the API. Th
bind events to an SVG when using the API for rendering.
```javascript
const insertSvg = function (svgCode, bindFunctions) {
element.innerHTML = svgCode;
if (typeof callback !== 'undefined') {
callback(id);
// Example of using the bindFunctions
const drawDiagram = async function () {
element = document.querySelector('#graphDiv');
const graphDefinition = 'graph TB\na-->b';
const { svg, bindFunctions } = await mermaid.render('graphDiv', graphDefinition);
element.innerHTML = svg;
// This can also be written as `bindFunctions?.(element);` using the `?` shorthand.
if (bindFunctions) {
bindFunctions(element);
}
bindFunctions(element);
};
const id = 'theGraph';
mermaidAPI.render(id, txt, insertSvg, element);
```
1. The graph is generated using the render call.

View File

@@ -20,6 +20,7 @@ They also serve as proof of concept, for the variety of things that can be built
- [Gitea](https://gitea.io) (**Native support**)
- [Azure Devops](https://docs.microsoft.com/en-us/azure/devops/project/wiki/wiki-markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) (**Native support**)
- [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) (**Native support**)
- [Deepdwn](https://billiam.itch.io/deepdwn) (**Native support**)
- [Joplin](https://joplinapp.org) (**Native support**)
- [Swimm](https://swimm.io) (**Native support**)
- [Notion](https://notion.so) (**Native support**)
@@ -188,3 +189,6 @@ They also serve as proof of concept, for the variety of things that can be built
- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)
- [ExDoc](https://github.com/elixir-lang/ex_doc)
- [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs)
- [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io)
- [ui.mermaid(...)](https://nicegui.io/reference#mermaid_diagrams)
- [ui.markdown(..., extras=\['mermaid'\])](https://nicegui.io/reference#markdown_element)

View File

@@ -103,7 +103,7 @@ When writing the .html file, we give two instructions inside the html code to th
a. The mermaid code for the diagram we want to create.
b. The importing of mermaid library through the `mermaid.esm.js` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process .
b. The importing of mermaid library through the `mermaid.esm.mjs` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process .
**a. The embedded mermaid diagram definition inside a `<pre class="mermaid">`:**
@@ -135,7 +135,7 @@ b. The importing of mermaid library through the `mermaid.esm.js` or `mermaid.esm
```
**Notes**:
Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can place `mermaid.initialize()` inside `mermaid.esm.min.mjs` for brevity. However, doing the opposite lets you control when it starts looking for `<div>`tags inside the web page with `mermaid.initialize()`. This is useful when you think that not all `<div>` tags may have loaded on the execution of `mermaid.esm.min.mjs` file.
Rendering in Mermaid is initialized by `mermaid.initialize()` call. However, doing the opposite lets you control when it starts looking for `<pre>` tags inside the web page with `mermaid.initialize()`. This is useful when you think that not all `<pre>` tags may have loaded on the execution of `mermaid.esm.min.mjs` file.
`startOnLoad` is one of the parameters that can be defined by `mermaid.initialize()`
@@ -143,10 +143,6 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
| ----------- | --------------------------------- | ------- | ----------- |
| startOnLoad | Toggle for Rendering upon loading | Boolean | true, false |
### Adding external diagrams to mermaid
Please refer to the [Mindmap](../syntax/mindmap.md?id=integrating-with-your-librarywebsite) section for more information.
### Working Examples
**Here is a full working example of the mermaidAPI being called through the CDN:**

View File

@@ -391,6 +391,20 @@ flowchart LR
A == text ==> B
```
### An invisible link
This can be a useful tool in some instances where you want to alter the default positioning of a node.
```mermaid-example
flowchart LR
A ~~~ B
```
```mermaid
flowchart LR
A ~~~ B
```
### Chaining of links
It is possible declare many links in the same line as per below:

View File

@@ -1,14 +1,14 @@
{
"name": "mermaid",
"version": "10.0.0-rc.4",
"version": "10.0.1-rc.1",
"description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module",
"module": "./dist/mermaid.core.mjs",
"types": "./dist/mermaid.d.ts",
"exports": {
".": {
"import": "./dist/mermaid.core.mjs",
"types": "./dist/mermaid.d.ts"
"types": "./dist/mermaid.d.ts",
"import": "./dist/mermaid.core.mjs"
},
"./*": "./*"
},

View File

@@ -68,8 +68,8 @@ export class Diagram {
}
}
export const getDiagramFromText = async (txt: string): Promise<Diagram> => {
const type = detectType(txt, configApi.getConfig());
export const getDiagramFromText = async (text: string): Promise<Diagram> => {
const type = detectType(text, configApi.getConfig());
try {
// Trying to find the diagram
getDiagram(type);
@@ -83,5 +83,5 @@ export const getDiagramFromText = async (txt: string): Promise<Diagram> => {
const { id, diagram } = await loader();
registerDiagram(id, diagram);
}
return new Diagram(txt);
return new Diagram(text);
};

View File

@@ -243,6 +243,7 @@ const checkConfig = (config: MermaidConfig) => {
if (!config) {
return;
}
// @ts-expect-error Properties were removed in v10. Warning should exist.
if (config.lazyLoadedDiagrams || config.loadExternalDiagramsAtStartup) {
issueWarning('LAZY_LOAD_DEPRECATED');
}

View File

@@ -3,10 +3,6 @@
import DOMPurify from 'dompurify';
export interface MermaidConfig {
/** @deprecated use mermaid.registerLazyDiagrams instead */
lazyLoadedDiagrams?: string[];
/** @deprecated use mermaid.registerLazyDiagrams instead */
loadExternalDiagramsAtStartup?: boolean;
theme?: string;
themeVariables?: any;
themeCSS?: string;

View File

@@ -453,6 +453,9 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
case 'thick':
strokeClasses = 'edge-thickness-thick';
break;
case 'invisible':
strokeClasses = 'edge-thickness-thick';
break;
default:
strokeClasses = '';
}

View File

@@ -7,6 +7,7 @@ import type {
ExternalDiagramDefinition,
} from './types';
import { frontMatterRegex } from './frontmatter';
import { getDiagram, registerDiagram } from './diagramAPI';
import { UnknownDiagramError } from '../errors';
const directive = /%{2}{\s*(?:(\w+)\s*:|(\w+))\s*(?:(\w+)|((?:(?!}%{2}).|\r?\n)*))?\s*(?:}%{2})?/gi;
@@ -54,6 +55,39 @@ export const registerLazyLoadedDiagrams = (...diagrams: ExternalDiagramDefinitio
}
};
export const loadRegisteredDiagrams = async () => {
log.debug(`Loading registered diagrams`);
// Load all lazy loaded diagrams in parallel
const results = await Promise.allSettled(
Object.entries(detectors).map(async ([key, { detector, loader }]) => {
if (loader) {
try {
getDiagram(key);
} catch (error) {
try {
// Register diagram if it is not already registered
const { diagram, id } = await loader();
registerDiagram(id, diagram, detector);
} catch (err) {
// Remove failed diagram from detectors
log.error(`Failed to load external diagram with key ${key}. Removing from detectors.`);
delete detectors[key];
throw err;
}
}
}
})
);
const failed = results.filter((result) => result.status === 'rejected');
if (failed.length > 0) {
log.error(`Failed to load ${failed.length} external diagrams`);
for (const res of failed) {
log.error(res);
}
throw new Error(`Failed to load ${failed.length} external diagrams`);
}
};
export const addDetector = (key: string, detector: DiagramDetector, loader?: DiagramLoader) => {
if (detectors[key]) {
log.error(`Detector with key ${key} already exists`);

View File

@@ -1,104 +1,24 @@
import { registerDiagram } from './diagramAPI';
// @ts-ignore: TODO Fix ts errors
import gitGraphParser from '../diagrams/git/parser/gitGraph';
import { gitGraphDetector } from '../diagrams/git/gitGraphDetector';
import gitGraphDb from '../diagrams/git/gitGraphAst';
import gitGraphRenderer from '../diagrams/git/gitGraphRenderer';
import gitGraphStyles from '../diagrams/git/styles';
// @ts-ignore: TODO Fix ts errors
import c4Parser from '../diagrams/c4/parser/c4Diagram';
import { c4Detector } from '../diagrams/c4/c4Detector';
import c4Db from '../diagrams/c4/c4Db';
import c4Renderer from '../diagrams/c4/c4Renderer';
import c4Styles from '../diagrams/c4/styles';
// @ts-ignore: TODO Fix ts errors
import classParser from '../diagrams/class/parser/classDiagram';
import { classDetector } from '../diagrams/class/classDetector';
import { classDetectorV2 } from '../diagrams/class/classDetector-V2';
import classDb from '../diagrams/class/classDb';
import classRenderer from '../diagrams/class/classRenderer';
import classRendererV2 from '../diagrams/class/classRenderer-v2';
import classStyles from '../diagrams/class/styles';
// @ts-ignore: TODO Fix ts errors
import erParser from '../diagrams/er/parser/erDiagram';
import { erDetector } from '../diagrams/er/erDetector';
import erDb from '../diagrams/er/erDb';
import erRenderer from '../diagrams/er/erRenderer';
import erStyles from '../diagrams/er/styles';
// @ts-ignore: TODO Fix ts errors
import flowParser from '../diagrams/flowchart/parser/flow';
import { flowDetector } from '../diagrams/flowchart/flowDetector';
import { flowDetectorV2 } from '../diagrams/flowchart/flowDetector-v2';
import flowDb from '../diagrams/flowchart/flowDb';
import flowRenderer from '../diagrams/flowchart/flowRenderer';
import flowRendererV2 from '../diagrams/flowchart/flowRenderer-v2';
import flowStyles from '../diagrams/flowchart/styles';
// @ts-ignore: TODO Fix ts errors
import ganttParser from '../diagrams/gantt/parser/gantt';
import { ganttDetector } from '../diagrams/gantt/ganttDetector';
import ganttDb from '../diagrams/gantt/ganttDb';
import ganttRenderer from '../diagrams/gantt/ganttRenderer';
import ganttStyles from '../diagrams/gantt/styles';
// @ts-ignore: TODO Fix ts errors
import infoParser from '../diagrams/info/parser/info';
import infoDb from '../diagrams/info/infoDb';
import infoRenderer from '../diagrams/info/infoRenderer';
import { infoDetector } from '../diagrams/info/infoDetector';
import infoStyles from '../diagrams/info/styles';
// @ts-ignore: TODO Fix ts errors
import pieParser from '../diagrams/pie/parser/pie';
import { pieDetector } from '../diagrams/pie/pieDetector';
import pieDb from '../diagrams/pie/pieDb';
import pieRenderer from '../diagrams/pie/pieRenderer';
import pieStyles from '../diagrams/pie/styles';
// @ts-ignore: TODO Fix ts errors
import requirementParser from '../diagrams/requirement/parser/requirementDiagram';
import { requirementDetector } from '../diagrams/requirement/requirementDetector';
import requirementDb from '../diagrams/requirement/requirementDb';
import requirementRenderer from '../diagrams/requirement/requirementRenderer';
import requirementStyles from '../diagrams/requirement/styles';
// @ts-ignore: TODO Fix ts errors
import sequenceParser from '../diagrams/sequence/parser/sequenceDiagram';
import { sequenceDetector } from '../diagrams/sequence/sequenceDetector';
import sequenceDb from '../diagrams/sequence/sequenceDb';
import sequenceRenderer from '../diagrams/sequence/sequenceRenderer';
import sequenceStyles from '../diagrams/sequence/styles';
// @ts-ignore: TODO Fix ts errors
import stateParser from '../diagrams/state/parser/stateDiagram';
import { stateDetector } from '../diagrams/state/stateDetector';
import { stateDetectorV2 } from '../diagrams/state/stateDetector-V2';
import stateDb from '../diagrams/state/stateDb';
import stateRenderer from '../diagrams/state/stateRenderer';
import stateRendererV2 from '../diagrams/state/stateRenderer-v2';
import stateStyles from '../diagrams/state/styles';
// @ts-ignore: TODO Fix ts errors
import journeyParser from '../diagrams/user-journey/parser/journey';
import { journeyDetector } from '../diagrams/user-journey/journeyDetector';
import journeyDb from '../diagrams/user-journey/journeyDb';
import journeyRenderer from '../diagrams/user-journey/journeyRenderer';
import journeyStyles from '../diagrams/user-journey/styles';
import { setConfig } from '../config';
import errorRenderer from '../diagrams/error/errorRenderer';
import errorStyles from '../diagrams/error/styles';
import c4 from '../diagrams/c4/c4Detector';
import flowchart from '../diagrams/flowchart/flowDetector';
import flowchartV2 from '../diagrams/flowchart/flowDetector-v2';
import er from '../diagrams/er/erDetector';
import git from '../diagrams/git/gitGraphDetector';
import gantt from '../diagrams/gantt/ganttDetector';
import info from '../diagrams/info/infoDetector';
import pie from '../diagrams/pie/pieDetector';
import requirement from '../diagrams/requirement/requirementDetector';
import sequence from '../diagrams/sequence/sequenceDetector';
import classDiagram from '../diagrams/class/classDetector';
import classDiagramV2 from '../diagrams/class/classDetector-V2';
import state from '../diagrams/state/stateDetector';
import stateV2 from '../diagrams/state/stateDetector-V2';
import journey from '../diagrams/user-journey/journeyDetector';
import error from '../diagrams/error/errorDetector';
import flowchartElk from '../diagrams/flowchart/elk/detector';
import timeline from '../diagrams/timeline/detector';
import mindmap from '../diagrams/mindmap/detector';
import { registerLazyLoadedDiagrams } from './detectType';
// Lazy loaded diagrams
import timelineDetector from '../diagrams/timeline/detector';
import mindmapDetector from '../diagrams/mindmap/detector';
import { registerDiagram } from './diagramAPI';
let hasLoadedDiagrams = false;
export const addDiagrams = () => {
@@ -108,31 +28,6 @@ export const addDiagrams = () => {
// This is added here to avoid race-conditions.
// We could optimize the loading logic somehow.
hasLoadedDiagrams = true;
registerLazyLoadedDiagrams(flowchartElk, timelineDetector, mindmapDetector);
registerDiagram(
'error',
// Special diagram with error messages but setup as a regular diagram
{
db: {
clear: () => {
// Quite ok, clear needs to be there for error to work as a regular diagram
},
},
styles: errorStyles,
renderer: errorRenderer,
parser: {
parser: { yy: {} },
parse: () => {
// no op
},
},
init: () => {
// no op
},
},
(text) => text.toLowerCase().trim() === 'error'
);
registerDiagram(
'---',
// --- diagram type may appear if YAML front-matter is not parsed correctly
@@ -142,8 +37,8 @@ export const addDiagrams = () => {
// Quite ok, clear needs to be there for --- to work as a regular diagram
},
},
styles: errorStyles, // should never be used
renderer: errorRenderer, // should never be used
styles: {}, // should never be used
renderer: {}, // should never be used
parser: {
parser: { yy: {} },
parse: () => {
@@ -160,220 +55,25 @@ export const addDiagrams = () => {
return text.toLowerCase().trimStart().startsWith('---');
}
);
registerDiagram(
'c4',
{
parser: c4Parser,
db: c4Db,
renderer: c4Renderer,
styles: c4Styles,
init: (cnf) => {
c4Renderer.setConf(cnf.c4);
},
},
c4Detector
);
registerDiagram(
'class',
{
parser: classParser,
db: classDb,
renderer: classRenderer,
styles: classStyles,
init: (cnf) => {
if (!cnf.class) {
cnf.class = {};
}
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
classDb.clear();
},
},
classDetector
);
registerDiagram(
'classDiagram',
{
parser: classParser,
db: classDb,
renderer: classRendererV2,
styles: classStyles,
init: (cnf) => {
if (!cnf.class) {
cnf.class = {};
}
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
classDb.clear();
},
},
classDetectorV2
);
registerDiagram(
'er',
{
parser: erParser,
db: erDb,
renderer: erRenderer,
styles: erStyles,
},
erDetector
);
registerDiagram(
'gantt',
{
parser: ganttParser,
db: ganttDb,
renderer: ganttRenderer,
styles: ganttStyles,
},
ganttDetector
);
registerDiagram(
'info',
{
parser: infoParser,
db: infoDb,
renderer: infoRenderer,
styles: infoStyles,
},
infoDetector
);
registerDiagram(
'pie',
{
parser: pieParser,
db: pieDb,
renderer: pieRenderer,
styles: pieStyles,
},
pieDetector
);
registerDiagram(
'requirement',
{
parser: requirementParser,
db: requirementDb,
renderer: requirementRenderer,
styles: requirementStyles,
},
requirementDetector
);
registerDiagram(
'sequence',
{
parser: sequenceParser,
db: sequenceDb,
renderer: sequenceRenderer,
styles: sequenceStyles,
init: (cnf) => {
if (!cnf.sequence) {
cnf.sequence = {};
}
cnf.sequence.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
if ('sequenceDiagram' in cnf) {
throw new Error(
'`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.'
);
}
sequenceDb.setWrap(cnf.wrap);
sequenceRenderer.setConf(cnf.sequence);
},
},
sequenceDetector
);
registerDiagram(
'state',
{
parser: stateParser,
db: stateDb,
renderer: stateRenderer,
styles: stateStyles,
init: (cnf) => {
if (!cnf.state) {
cnf.state = {};
}
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
stateDb.clear();
},
},
stateDetector
);
registerDiagram(
'stateDiagram',
{
parser: stateParser,
db: stateDb,
renderer: stateRendererV2,
styles: stateStyles,
init: (cnf) => {
if (!cnf.state) {
cnf.state = {};
}
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
stateDb.clear();
},
},
stateDetectorV2
);
registerDiagram(
'journey',
{
parser: journeyParser,
db: journeyDb,
renderer: journeyRenderer,
styles: journeyStyles,
init: (cnf) => {
journeyRenderer.setConf(cnf.journey);
journeyDb.clear();
},
},
journeyDetector
);
registerDiagram(
'flowchart',
{
parser: flowParser,
db: flowDb,
renderer: flowRendererV2,
styles: flowStyles,
init: (cnf) => {
if (!cnf.flowchart) {
cnf.flowchart = {};
}
// TODO, broken as of 2022-09-14 (13809b50251845475e6dca65cc395761be38fbd2)
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
flowRenderer.setConf(cnf.flowchart);
flowDb.clear();
flowDb.setGen('gen-1');
},
},
flowDetector
);
registerDiagram(
'flowchart-v2',
{
parser: flowParser,
db: flowDb,
renderer: flowRendererV2,
styles: flowStyles,
init: (cnf) => {
if (!cnf.flowchart) {
cnf.flowchart = {};
}
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
// flowchart-v2 uses dagre-wrapper, which doesn't have access to flowchart cnf
setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } });
flowRendererV2.setConf(cnf.flowchart);
flowDb.clear();
flowDb.setGen('gen-2');
},
},
flowDetectorV2
);
registerDiagram(
'gitGraph',
{ parser: gitGraphParser, db: gitGraphDb, renderer: gitGraphRenderer, styles: gitGraphStyles },
gitGraphDetector
registerLazyLoadedDiagrams(
error,
c4,
classDiagram,
classDiagramV2,
er,
gantt,
info,
pie,
requirement,
sequence,
flowchart,
flowchartV2,
flowchartElk,
mindmap,
timeline,
git,
state,
stateV2,
journey
);
};

View File

@@ -2,8 +2,12 @@ import { detectType } from './detectType';
import { getDiagram, registerDiagram } from './diagramAPI';
import { addDiagrams } from './diagram-orchestration';
import { DiagramDetector } from './types';
import { getDiagramFromText } from '../Diagram';
addDiagrams();
beforeAll(async () => {
await getDiagramFromText('sequenceDiagram');
});
describe('DiagramAPI', () => {
it('should return default diagrams', () => {

View File

@@ -71,3 +71,9 @@ export const getDiagram = (name: string): DiagramDefinition => {
}
throw new Error(`Diagram ${name} not found.`);
};
export class DiagramNotFoundError extends Error {
constructor(message: string) {
super(`Diagram ${message} not found.`);
}
}

View File

@@ -1,5 +1,20 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { ExternalDiagramDefinition } from '../../diagram-api/types';
export const c4Detector: DiagramDetector = (txt) => {
const id = 'c4';
const detector = (txt: string) => {
return txt.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/) !== null;
};
const loader = async () => {
const { diagram } = await import('./c4Diagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,17 @@
// @ts-ignore: TODO Fix ts errors
import c4Parser from './parser/c4Diagram';
import c4Db from './c4Db';
import c4Renderer from './c4Renderer';
import c4Styles from './styles';
import { MermaidConfig } from '../../config.type';
import { DiagramDefinition } from '../../diagram-api/types';
export const diagram: DiagramDefinition = {
parser: c4Parser,
db: c4Db,
renderer: c4Renderer,
styles: c4Styles,
init: (cnf: MermaidConfig) => {
c4Renderer.setConf(cnf.c4);
},
};

View File

@@ -1,6 +1,8 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const classDetectorV2: DiagramDetector = (txt, config) => {
const id = 'classDiagram';
const detector: DiagramDetector = (txt, config) => {
// If we have configured to use dagre-wrapper then we should return true in this function for classDiagram code thus making it use the new class diagram
if (
txt.match(/^\s*classDiagram/) !== null &&
@@ -11,3 +13,16 @@ export const classDetectorV2: DiagramDetector = (txt, config) => {
// We have not opted to use the new renderer so we should return true if we detect a class diagram
return txt.match(/^\s*classDiagram-v2/) !== null;
};
const loader = async () => {
const { diagram } = await import('./classDiagram-v2');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -1,6 +1,8 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const classDetector: DiagramDetector = (txt, config) => {
const id = 'class';
const detector: DiagramDetector = (txt, config) => {
// If we have configured to use dagre-wrapper then we should never return true in this function
if (config?.class?.defaultRenderer === 'dagre-wrapper') {
return false;
@@ -8,3 +10,16 @@ export const classDetector: DiagramDetector = (txt, config) => {
// We have not opted to use the new renderer so we should return true if we detect a class diagram
return txt.match(/^\s*classDiagram/) !== null;
};
const loader = async () => {
const { diagram } = await import('./classDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,20 @@
import { DiagramDefinition } from '../../diagram-api/types';
// @ts-ignore: TODO Fix ts errors
import parser from './parser/classDiagram';
import db from './classDb';
import styles from './styles';
import renderer from './classRenderer-v2';
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
styles,
init: (cnf) => {
if (!cnf.class) {
cnf.class = {};
}
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
db.clear();
},
};

View File

@@ -0,0 +1,20 @@
import { DiagramDefinition } from '../../diagram-api/types';
// @ts-ignore: TODO Fix ts errors
import parser from './parser/classDiagram';
import db from './classDb';
import styles from './styles';
import renderer from './classRenderer';
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
styles,
init: (cnf) => {
if (!cnf.class) {
cnf.class = {};
}
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
db.clear();
},
};

View File

@@ -1,5 +1,20 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const erDetector: DiagramDetector = (txt) => {
const id = 'er';
const detector: DiagramDetector = (txt) => {
return txt.match(/^\s*erDiagram/) !== null;
};
const loader = async () => {
const { diagram } = await import('./erDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,12 @@
// @ts-ignore: TODO Fix ts errors
import erParser from './parser/erDiagram';
import erDb from './erDb';
import erRenderer from './erRenderer';
import erStyles from './styles';
export const diagram = {
parser: erParser,
db: erDb,
renderer: erRenderer,
styles: erStyles,
};

View File

@@ -81,7 +81,7 @@ start
document
: /* empty */ { $$ = [] }
| document line {$1.push($2);$$ = $1}
| document line {$1.push($2);$$ = $1}
;
line

View File

@@ -0,0 +1,20 @@
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
const id = 'error';
const detector: DiagramDetector = (text) => {
return text.toLowerCase().trim() === 'error';
};
const loader = async () => {
const { diagram } = await import('./errorDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,21 @@
import { DiagramDefinition } from '../../diagram-api/types';
import styles from './styles';
import renderer from './errorRenderer';
export const diagram: DiagramDefinition = {
db: {
clear: () => {
// Quite ok, clear needs to be there for error to work as a regular diagram
},
},
styles,
renderer,
parser: {
parser: { yy: {} },
parse: () => {
// no op
},
},
init: () => {
// no op
},
};

View File

@@ -677,6 +677,10 @@ const destructEndLink = (_str) => {
stroke = 'thick';
}
if (line[0] === '~') {
stroke = 'invisible';
}
let dots = countChar('.', line);
if (dots) {

View File

@@ -1,6 +1,9 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { ExternalDiagramDefinition } from '../../diagram-api/types';
export const flowDetectorV2: DiagramDetector = (txt, config) => {
const id = 'flowchart-v2';
const detector: DiagramDetector = (txt, config) => {
if (config?.flowchart?.defaultRenderer === 'dagre-d3') {
return false;
}
@@ -14,3 +17,16 @@ export const flowDetectorV2: DiagramDetector = (txt, config) => {
}
return txt.match(/^\s*flowchart/) !== null;
};
const loader = async () => {
const { diagram } = await import('./flowDiagram-v2');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -1,6 +1,8 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const flowDetector: DiagramDetector = (txt, config) => {
const id = 'flowchart';
const detector: DiagramDetector = (txt, config) => {
// If we have conferred to only use new flow charts this function should always return false
// as in not signalling true for a legacy flowchart
if (config?.flowchart?.defaultRenderer === 'dagre-wrapper') {
@@ -11,3 +13,16 @@ export const flowDetector: DiagramDetector = (txt, config) => {
}
return txt.match(/^\s*graph/) !== null;
};
const loader = async () => {
const { diagram } = await import('./flowDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,25 @@
// @ts-ignore: TODO Fix ts errors
import flowParser from './parser/flow';
import flowDb from './flowDb';
import flowRendererV2 from './flowRenderer-v2';
import flowStyles from './styles';
import { MermaidConfig } from '../../config.type';
import { setConfig } from '../../config';
export const diagram = {
parser: flowParser,
db: flowDb,
renderer: flowRendererV2,
styles: flowStyles,
init: (cnf: MermaidConfig) => {
if (!cnf.flowchart) {
cnf.flowchart = {};
}
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
// flowchart-v2 uses dagre-wrapper, which doesn't have access to flowchart cnf
setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } });
flowRendererV2.setConf(cnf.flowchart);
flowDb.clear();
flowDb.setGen('gen-2');
},
};

View File

@@ -0,0 +1,24 @@
// @ts-ignore: TODO Fix ts errors
import flowParser from './parser/flow';
import flowDb from './flowDb';
import flowRenderer from './flowRenderer';
import flowRendererV2 from './flowRenderer-v2';
import flowStyles from './styles';
import { MermaidConfig } from '../../config.type';
export const diagram = {
parser: flowParser,
db: flowDb,
renderer: flowRendererV2,
styles: flowStyles,
init: (cnf: MermaidConfig) => {
if (!cnf.flowchart) {
cnf.flowchart = {};
}
// TODO, broken as of 2022-09-14 (13809b50251845475e6dca65cc395761be38fbd2)
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
flowRenderer.setConf(cnf.flowchart);
flowDb.clear();
flowDb.setGen('gen-1');
},
};

View File

@@ -280,6 +280,11 @@ export const addEdges = function (edges, g, diagObj) {
edgeData.pattern = 'solid';
edgeData.style = 'stroke-width: 3.5px;fill:none;';
break;
case 'invisible':
edgeData.thickness = 'invisible';
edgeData.pattern = 'solid';
edgeData.style = 'stroke-width: 0;fill:none;';
break;
}
if (edge.style !== undefined) {
const styles = getStylesFromArray(edge.style);

View File

@@ -1,21 +1,24 @@
import flowDb from './flowDb';
import flowParser from './parser/flow';
import { parser } from './parser/flow';
import flowRenderer from './flowRenderer';
import { Diagram } from '../../Diagram';
import { addDiagrams } from '../../diagram-api/diagram-orchestration';
const diag = {
db: flowDb,
};
addDiagrams();
describe('when using mermaid and ', function () {
describe('when calling addEdges ', function () {
beforeEach(function () {
flowParser.parser.yy = flowDb;
parser.yy = flowDb;
flowDb.clear();
flowDb.setGen('gen-2');
});
it('should handle edges with text', function () {
const diag = new Diagram('graph TD;A-->|text ex|B;');
diag.db.getVertices();
const edges = diag.db.getEdges();
it('should handle edges with text', () => {
parser.parse('graph TD;A-->|text ex|B;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
@@ -29,10 +32,10 @@ describe('when using mermaid and ', function () {
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges without text', function () {
const diag = new Diagram('graph TD;A-->B;');
diag.db.getVertices();
const edges = diag.db.getEdges();
it('should handle edges without text', async function () {
parser.parse('graph TD;A-->B;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
@@ -45,10 +48,10 @@ describe('when using mermaid and ', function () {
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle open-ended edges', function () {
const diag = new Diagram('graph TD;A---B;');
diag.db.getVertices();
const edges = diag.db.getEdges();
it('should handle open-ended edges', () => {
parser.parse('graph TD;A---B;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
@@ -61,10 +64,10 @@ describe('when using mermaid and ', function () {
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with styles defined', function () {
const diag = new Diagram('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
diag.db.getVertices();
const edges = diag.db.getEdges();
it('should handle edges with styles defined', () => {
parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
@@ -77,10 +80,10 @@ describe('when using mermaid and ', function () {
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with interpolation defined', function () {
const diag = new Diagram('graph TD;A---B; linkStyle 0 interpolate basis');
diag.db.getVertices();
const edges = diag.db.getEdges();
it('should handle edges with interpolation defined', () => {
parser.parse('graph TD;A---B; linkStyle 0 interpolate basis');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
@@ -93,12 +96,10 @@ describe('when using mermaid and ', function () {
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with text and styles defined', function () {
const diag = new Diagram(
'graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;'
);
diag.db.getVertices();
const edges = diag.db.getEdges();
it('should handle edges with text and styles defined', () => {
parser.parse('graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
@@ -113,10 +114,10 @@ describe('when using mermaid and ', function () {
flowRenderer.addEdges(edges, mockG, diag);
});
it('should set fill to "none" by default when handling edges', function () {
const diag = new Diagram('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
diag.db.getVertices();
const edges = diag.db.getEdges();
it('should set fill to "none" by default when handling edges', () => {
parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
@@ -130,12 +131,10 @@ describe('when using mermaid and ', function () {
flowRenderer.addEdges(edges, mockG, diag);
});
it('should not set fill to none if fill is set in linkStyle', function () {
const diag = new Diagram(
'graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2,fill:blue;'
);
diag.db.getVertices();
const edges = diag.db.getEdges();
it('should not set fill to none if fill is set in linkStyle', () => {
parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2,fill:blue;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');

View File

@@ -121,6 +121,7 @@ that id.
\s*[xo<]?\-\-+[-xo>]\s* return 'LINK';
\s*[xo<]?\=\=+[=xo>]\s* return 'LINK';
\s*[xo<]?\-?\.+\-[xo>]?\s* return 'LINK';
\s*\~\~[\~]+\s* return 'LINK';
\s*[xo<]?\-\-\s* return 'START_LINK';
\s*[xo<]?\=\=\s* return 'START_LINK';
\s*[xo<]?\-\.\s* return 'START_LINK';

View File

@@ -1,5 +1,20 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const ganttDetector: DiagramDetector = (txt) => {
const id = 'gantt';
const detector: DiagramDetector = (txt) => {
return txt.match(/^\s*gantt/) !== null;
};
const loader = async () => {
const { diagram } = await import('./ganttDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,13 @@
// @ts-ignore: TODO Fix ts errors
import ganttParser from './parser/gantt';
import ganttDb from './ganttDb';
import ganttRenderer from './ganttRenderer';
import ganttStyles from './styles';
import { DiagramDefinition } from '../../diagram-api/types';
export const diagram: DiagramDefinition = {
parser: ganttParser,
db: ganttDb,
renderer: ganttRenderer,
styles: ganttStyles,
};

View File

@@ -1,5 +1,21 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { ExternalDiagramDefinition } from '../../diagram-api/types';
export const gitGraphDetector: DiagramDetector = (txt) => {
const id = 'gitGraph';
const detector: DiagramDetector = (txt) => {
return txt.match(/^\s*gitGraph/) !== null;
};
const loader = async () => {
const { diagram } = await import('./gitGraphDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,13 @@
// @ts-ignore: TODO Fix ts errors
import gitGraphParser from './parser/gitGraph';
import gitGraphDb from './gitGraphAst';
import gitGraphRenderer from './gitGraphRenderer';
import gitGraphStyles from './styles';
import { DiagramDefinition } from '../../diagram-api/types';
export const diagram: DiagramDefinition = {
parser: gitGraphParser,
db: gitGraphDb,
renderer: gitGraphRenderer,
styles: gitGraphStyles,
};

View File

@@ -1,5 +1,20 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const infoDetector: DiagramDetector = (txt) => {
const id = 'info';
const detector: DiagramDetector = (txt) => {
return txt.match(/^\s*info/) !== null;
};
const loader = async () => {
const { diagram } = await import('./infoDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,13 @@
import { DiagramDefinition } from '../../diagram-api/types';
// @ts-ignore: TODO Fix ts errors
import parser from './parser/info';
import db from './infoDb';
import styles from './styles';
import renderer from './infoRenderer';
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
styles,
};

View File

@@ -1,6 +1,20 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const pieDetector: DiagramDetector = (txt) => {
const logOutput = txt.match(/^\s*pie/) !== null || txt.match(/^\s*bar/) !== null;
return logOutput;
const id = 'pie';
const detector: DiagramDetector = (txt) => {
return txt.match(/^\s*pie/) !== null;
};
const loader = async () => {
const { diagram } = await import('./pieDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,13 @@
import { DiagramDefinition } from '../../diagram-api/types';
// @ts-ignore: TODO Fix ts errors
import parser from './parser/pie';
import db from './pieDb';
import styles from './styles';
import renderer from './pieRenderer';
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
styles,
};

View File

@@ -1,5 +1,20 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const requirementDetector: DiagramDetector = (txt) => {
const id = 'requirement';
const detector: DiagramDetector = (txt) => {
return txt.match(/^\s*requirement(Diagram)?/) !== null;
};
const loader = async () => {
const { diagram } = await import('./requirementDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,13 @@
import { DiagramDefinition } from '../../diagram-api/types';
// @ts-ignore: TODO Fix ts errors
import parser from './parser/requirementDiagram';
import db from './requirementDb';
import styles from './styles';
import renderer from './requirementRenderer';
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
styles,
};

View File

@@ -1,5 +1,20 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const sequenceDetector: DiagramDetector = (txt) => {
const id = 'sequence';
const detector: DiagramDetector = (txt) => {
return txt.match(/^\s*sequenceDiagram/) !== null;
};
const loader = async () => {
const { diagram } = await import('./sequenceDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -2,9 +2,14 @@ import { vi } from 'vitest';
import * as configApi from '../../config';
import mermaidAPI from '../../mermaidAPI';
import { Diagram } from '../../Diagram';
import { Diagram, getDiagramFromText } from '../../Diagram';
import { addDiagrams } from '../../diagram-api/diagram-orchestration';
beforeAll(async () => {
// Is required to load the sequence diagram
await getDiagramFromText('sequenceDiagram');
});
/**
* Sequence diagrams require their own very special version of a mocked d3 module
* diagrams/sequence/svgDraw uses statements like this with d3 nodes: (note the [0][0])
@@ -183,7 +188,7 @@ Alice->Bob:Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
await mermaidAPI.parse(str, diagram);
await mermaidAPI.parse(str);
const actors = diagram.db.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';

View File

@@ -0,0 +1,13 @@
import { DiagramDefinition } from '../../diagram-api/types';
// @ts-ignore: TODO Fix ts errors
import parser from './parser/sequenceDiagram';
import db from './sequenceDb';
import styles from './styles';
import renderer from './sequenceRenderer';
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
styles,
};

View File

@@ -117,7 +117,7 @@ describe('state parser can parse...', () => {
state "Big State 1" as bigState1 {
state "inner state 1" as inner1
inner2: inner state 2
inner1 --> inner2
inner1 --> inner2
}`;
stateDiagram.parser.parse(diagramText);
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());

View File

@@ -1,11 +1,29 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const stateDetectorV2: DiagramDetector = (text, config) => {
const id = 'stateDiagram';
const detector: DiagramDetector = (text, config) => {
if (text.match(/^\s*stateDiagram-v2/) !== null) {
return true;
}
if (text.match(/^\s*stateDiagram/) && config?.state?.defaultRenderer === 'dagre-wrapper') {
return true;
}
if (text.match(/^\s*stateDiagram/) && config?.state?.defaultRenderer === 'dagre-wrapper') {
return true;
}
return false;
};
const loader = async () => {
const { diagram } = await import('./stateDiagram-v2');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -1,6 +1,8 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const stateDetector: DiagramDetector = (txt, config) => {
const id = 'state';
const detector: DiagramDetector = (txt, config) => {
// If we have confirmed to only use new state diagrams this function should always return false
// as in not signalling true for a legacy state diagram
if (config?.state?.defaultRenderer === 'dagre-wrapper') {
@@ -8,3 +10,16 @@ export const stateDetector: DiagramDetector = (txt, config) => {
}
return txt.match(/^\s*stateDiagram/) !== null;
};
const loader = async () => {
const { diagram } = await import('./stateDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,20 @@
import { DiagramDefinition } from '../../diagram-api/types';
// @ts-ignore: TODO Fix ts errors
import parser from './parser/stateDiagram';
import db from './stateDb';
import styles from './styles';
import renderer from './stateRenderer-v2';
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
styles,
init: (cnf) => {
if (!cnf.state) {
cnf.state = {};
}
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
db.clear();
},
};

View File

@@ -0,0 +1,20 @@
import { DiagramDefinition } from '../../diagram-api/types';
// @ts-ignore: TODO Fix ts errors
import parser from './parser/stateDiagram';
import db from './stateDb';
import styles from './styles';
import renderer from './stateRenderer';
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
styles,
init: (cnf) => {
if (!cnf.state) {
cnf.state = {};
}
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
db.clear();
},
};

View File

@@ -1,5 +1,20 @@
import type { DiagramDetector } from '../../diagram-api/types';
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types';
export const journeyDetector: DiagramDetector = (txt) => {
const id = 'journey';
const detector: DiagramDetector = (txt) => {
return txt.match(/^\s*journey/) !== null;
};
const loader = async () => {
const { diagram } = await import('./journeyDiagram');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -0,0 +1,17 @@
import { DiagramDefinition } from '../../diagram-api/types';
// @ts-ignore: TODO Fix ts errors
import parser from './parser/journey';
import db from './journeyDb';
import styles from './styles';
import renderer from './journeyRenderer';
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
styles,
init: (cnf) => {
renderer.setConf(cnf.journey);
db.clear();
},
};

View File

@@ -17,7 +17,7 @@ const props = defineProps({
},
});
const svg = ref(null);
const svg = ref('');
let mut = null;
onMounted(async () => {

View File

@@ -2,6 +2,6 @@ import mermaid, { type MermaidConfig } from 'mermaid';
export const render = async (id: string, code: string, config: MermaidConfig): Promise<string> => {
mermaid.initialize(config);
const svg = await mermaid.render(id, code);
const { svg } = await mermaid.render(id, code);
return svg;
};

View File

@@ -14,21 +14,24 @@ Please note that you can switch versions through the dropdown box at the top rig
For the majority of users, Using the [Live Editor](https://mermaid.live/) would be sufficient, however you may also opt to deploy mermaid as a dependency or using the [Mermaid API](./setup/README.md).
We have compiled some Video [Tutorials](./Tutorials.md) on how to use the mermaid Live Editor.
We have compiled some Video [Tutorials](./Tutorials.md) on how to use the Mermaid Live Editor.
### Installing and Hosting Mermaid on a Webpage
**Using the npm package:**
1. You will need to install `node v16`, which would have npm.
Requirements:
2. Download `yarn` using npm.
- Node >= 16
3. Enter the following command: `yarn add mermaid`.
4. At this point, you can add mermaid as a dev dependency using this command: `yarn add --dev mermaid`.
5. Alternatively, you can also deploy mermaid using the script tag in an HTML file with mermaid diagram descriptions as is shown in the example below.
```bash
# NPM
npm install mermaid
# Yarn
yarn add mermaid
# PNPM
pnpm add mermaid
```
**Hosting mermaid on a web page:**
@@ -36,7 +39,9 @@ We have compiled some Video [Tutorials](./Tutorials.md) on how to use the mermai
The easiest way to integrate mermaid on a web page requires two elements:
- A graph definition, inside `<pre>` tags labeled `class=mermaid`. Example:
- A graph definition, inside `<pre>` tags labeled `class=mermaid`.
Example:
```html
<pre class="mermaid">
@@ -47,14 +52,13 @@ The easiest way to integrate mermaid on a web page requires two elements:
</pre>
```
- Inclusion of the mermaid address in the html page body using a `script` tag as an ESM import, and the `mermaidAPI` call.
- The mermaid js script. Added using a `script` tag as an ESM import.
Example:
```html
<script type="module">
import mermaid from '<CDN_URL>/mermaid@<MERMAID_VERSION>/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
</script>
```
@@ -65,9 +69,6 @@ Example:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>
<body>
<pre class="mermaid">
graph LR
@@ -77,7 +78,6 @@ Example:
</pre>
<script type="module">
import mermaid from '<CDN_URL>/mermaid@<MERMAID_VERSION>/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
</script>
</body>
</html>
@@ -89,11 +89,12 @@ An id attribute is also added to mermaid tags without one.
Mermaid can load multiple diagrams, in the same page.
> Try it out, save this code as HTML and load it using any browser.(Except Internet Explorer, please don't use Internet Explorer.)
> Try it out, save this code as HTML and load it using any browser.
> (Except Internet Explorer, please don't use Internet Explorer.)
## Enabling Click Event and Tags in Nodes
A `securityLevel` configuration has to first be cleared, `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduce in version 8.2 as a security improvement, aimed at preventing malicious use.
A `securityLevel` configuration has to first be cleared. `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduce in version 8.2 as a security improvement, aimed at preventing malicious use.
**It is the site owner's responsibility to discriminate between trustworthy and untrustworthy user-bases and we encourage the use of discretion.**
@@ -101,7 +102,7 @@ A `securityLevel` configuration has to first be cleared, `securityLevel` sets th
| Parameter | Description | Type | Required | Values |
| ------------- | --------------------------------- | ------ | -------- | ------------------------------------------ |
| securityLevel | Level of trust for parsed diagram | String | Required | 'sandbox', 'strict', 'loose', 'antiscript' |
| securityLevel | Level of trust for parsed diagram | String | Optional | 'sandbox', 'strict', 'loose', 'antiscript' |
Values:
@@ -117,26 +118,17 @@ This changes the default behaviour of mermaid so that after upgrade to 8.2, unle
**If you are taking responsibility for the diagram source security you can set the `securityLevel` to a value of your choosing . This allows clicks and tags are allowed.**
**To change `securityLevel`, you have to call `mermaidAPI.initialize`:**
**To change `securityLevel`, you have to call `mermaid.initialize`:**
```javascript
mermaidAPI.initialize({
mermaid.initialize({
securityLevel: 'loose',
});
```
### Labels out of bounds
If you use dynamically loaded fonts that are loaded through CSS, such as Google fonts, mermaid should wait for the
whole page to load (dom + assets, particularly the fonts file).
```javascript
$(document).load(function () {
mermaid.initialize();
});
```
or
If you use dynamically loaded fonts that are loaded through CSS, such as fonts, mermaid should wait for the whole page to load (dom + assets, particularly the fonts file).
```javascript
$(document).ready(function () {
@@ -149,12 +141,55 @@ Not doing so will most likely result in mermaid rendering graphs that have label
If your page has other fonts in its body those might be used instead of the mermaid font. Specifying the font in your styling is a workaround for this.
```css
div.mermaid {
pre.mermaid {
font-family: 'trebuchet ms', verdana, arial;
}
```
### Calling `mermaid.init`
### Using `mermaid.run`
mermaid.run was added in v10 and is the preferred way of handling more complex integration.
By default, `mermaid.run` will be called when the document is ready, rendering all elements with `class="mermaid"`.
You can customize that behavior by calling `await mermaid.run(<config>)`.
`mermaid.initialize({startOnLoad: false})` will prevent `mermaid.run` from being called automatically after load.
Render all elements with querySelector ".someOtherClass"
```js
mermaid.initialize({ startOnLoad: false });
await mermaid.run({
querySelector: '.someOtherClass',
});
```
Render all elements passed as an array
```js
mermaid.initialize({ startOnLoad: false });
await mermaid.run({
nodes: [document.getElementById('someId'), document.getElementById('anotherId')],
});
await mermaid.run({
nodes: document.querySelectorAll('.yetAnotherClass'),
});
```
Render all `.mermaid` elements while suppressing any error
```js
mermaid.initialize({ startOnLoad: false });
await mermaid.run({
suppressErrors: true,
});
```
### Calling `mermaid.init` - Deprecated
```warning
mermaid.init is deprecated in v10 and will be removed in v11. Please use mermaid.run instead.
```
By default, `mermaid.init` will be called when the document is ready, finding all elements with
`class="mermaid"`. If you are adding content after mermaid is loaded, or otherwise need
@@ -188,25 +223,24 @@ mermaid fully supports webpack. Here is a [working demo](https://github.com/merm
## API usage
The main idea of the API is to be able to call a render function with the graph definition as a string. The render function
will render the graph and call a callback with the resulting SVG code. With this approach it is up to the site creator to
fetch the graph definition from the site (perhaps from a textarea), render it and place the graph somewhere in the site.
The main idea of the API is to be able to call a render function with the graph definition as a string. The render function will render the graph and call a callback with the resulting SVG code. With this approach it is up to the site creator to fetch the graph definition from the site (perhaps from a textarea), render it and place the graph somewhere in the site.
The example below show an outline of how this could be used. The example just logs the resulting SVG to the JavaScript console.
```html
<script type="module">
import mermaid from './mermaid.mjs';
mermaid.mermaidAPI.initialize({ startOnLoad: false });
$(async function () {
// Example of using the API var
import mermaid from './mermaid.esm.mjs';
mermaid.initialize({ startOnLoad: false });
// Example of using the render function
const drawDiagram = async function () {
element = document.querySelector('#graphDiv');
const insertSvg = function (svgCode, bindFunctions) {
element.innerHTML = svgCode;
};
const graphDefinition = 'graph TB\na-->b';
const graph = await mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg);
});
const { svg } = await mermaid.render('graphDiv', graphDefinition);
element.innerHTML = svg;
};
await drawDiagram();
</script>
```
@@ -219,17 +253,17 @@ The example code below is an extract of what mermaid does when using the API. Th
bind events to an SVG when using the API for rendering.
```javascript
const insertSvg = function (svgCode, bindFunctions) {
element.innerHTML = svgCode;
if (typeof callback !== 'undefined') {
callback(id);
// Example of using the bindFunctions
const drawDiagram = async function () {
element = document.querySelector('#graphDiv');
const graphDefinition = 'graph TB\na-->b';
const { svg, bindFunctions } = await mermaid.render('graphDiv', graphDefinition);
element.innerHTML = svg;
// This can also be written as `bindFunctions?.(element);` using the `?` shorthand.
if (bindFunctions) {
bindFunctions(element);
}
bindFunctions(element);
};
const id = 'theGraph';
mermaidAPI.render(id, txt, insertSvg, element);
```
1. The graph is generated using the render call.

View File

@@ -14,6 +14,7 @@ They also serve as proof of concept, for the variety of things that can be built
- [Gitea](https://gitea.io) (**Native support**)
- [Azure Devops](https://docs.microsoft.com/en-us/azure/devops/project/wiki/wiki-markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) (**Native support**)
- [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) (**Native support**)
- [Deepdwn](https://billiam.itch.io/deepdwn) (**Native support**)
- [Joplin](https://joplinapp.org) (**Native support**)
- [Swimm](https://swimm.io) (**Native support**)
- [Notion](https://notion.so) (**Native support**)
@@ -182,3 +183,6 @@ They also serve as proof of concept, for the variety of things that can be built
- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)
- [ExDoc](https://github.com/elixir-lang/ex_doc)
- [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs)
- [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io)
- [ui.mermaid(...)](https://nicegui.io/reference#mermaid_diagrams)
- [ui.markdown(..., extras=['mermaid'])](https://nicegui.io/reference#markdown_element)

View File

@@ -86,7 +86,7 @@ When writing the .html file, we give two instructions inside the html code to th
a. The mermaid code for the diagram we want to create.
b. The importing of mermaid library through the `mermaid.esm.js` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process .
b. The importing of mermaid library through the `mermaid.esm.mjs` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process .
**a. The embedded mermaid diagram definition inside a `<pre class="mermaid">`:**
@@ -118,7 +118,7 @@ b. The importing of mermaid library through the `mermaid.esm.js` or `mermaid.esm
```
**Notes**:
Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can place `mermaid.initialize()` inside `mermaid.esm.min.mjs` for brevity. However, doing the opposite lets you control when it starts looking for `<div>`tags inside the web page with `mermaid.initialize()`. This is useful when you think that not all `<div>` tags may have loaded on the execution of `mermaid.esm.min.mjs` file.
Rendering in Mermaid is initialized by `mermaid.initialize()` call. However, doing the opposite lets you control when it starts looking for `<pre>` tags inside the web page with `mermaid.initialize()`. This is useful when you think that not all `<pre>` tags may have loaded on the execution of `mermaid.esm.min.mjs` file.
`startOnLoad` is one of the parameters that can be defined by `mermaid.initialize()`
@@ -126,10 +126,6 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
| ----------- | --------------------------------- | ------- | ----------- |
| startOnLoad | Toggle for Rendering upon loading | Boolean | true, false |
### Adding external diagrams to mermaid
Please refer to the [Mindmap](../syntax/mindmap.md?id=integrating-with-your-librarywebsite) section for more information.
### Working Examples
**Here is a full working example of the mermaidAPI being called through the CDN:**

View File

@@ -245,6 +245,15 @@ flowchart LR
A == text ==> B
```
### An invisible link
This can be a useful tool in some instances where you want to alter the default positioning of a node.
```mermaid-example
flowchart LR
A ~~~ B
```
### Chaining of links
It is possible declare many links in the same line as per below:

View File

@@ -1,6 +1,11 @@
import mermaid from './mermaid';
import { mermaidAPI } from './mermaidAPI';
import './diagram-api/diagram-orchestration';
import { addDiagrams } from './diagram-api/diagram-orchestration';
beforeAll(async () => {
addDiagrams();
});
const spyOn = vi.spyOn;
vi.mock('./mermaidAPI');
@@ -66,9 +71,9 @@ describe('when using mermaid and ', () => {
mermaid.registerExternalDiagrams(
[
{
id: 'dummy',
detector: (text) => /dummy/.test(text),
loader: () => Promise.reject('error'),
id: 'dummyError',
detector: (text) => /dummyError/.test(text),
loader: () => Promise.reject('dummyError'),
},
],
{ lazyLoad: false }

View File

@@ -7,11 +7,10 @@ import { MermaidConfig } from './config.type';
import { log } from './logger';
import utils from './utils';
import { mermaidAPI, ParseOptions, RenderResult } from './mermaidAPI';
import { registerLazyLoadedDiagrams } from './diagram-api/detectType';
import { registerLazyLoadedDiagrams, loadRegisteredDiagrams } from './diagram-api/detectType';
import type { ParseErrorFunction } from './Diagram';
import { isDetailedError } from './utils';
import type { DetailedError } from './utils';
import { registerDiagram } from './diagram-api/diagramAPI';
import { ExternalDiagramDefinition } from './diagram-api/types';
export type {
@@ -23,19 +22,22 @@ export type {
ParseOptions,
};
/**
* The options used when running mermaid.
*
* @param querySelector - The query selector to use when finding elements to render. Default: .mermaid
* @param nodes - The nodes to render. If this is set, querySelector will be ignored.
* @param postRenderCallback - A callback to call after each diagram is rendered.
* @param suppressErrors - If true, errors will be logged to the console, but not thrown. Default: false
*/
export interface RunOptions {
// Default: .mermaid
/**
* The query selector to use when finding elements to render. Default: `".mermaid"`.
*/
querySelector?: string;
/**
* The nodes to render. If this is set, `querySelector` will be ignored.
*/
nodes?: ArrayLike<HTMLElement>;
/**
* A callback to call after each diagram is rendered.
*/
postRenderCallback?: (id: string) => unknown;
/**
* If `true`, errors will be logged to the console, but not thrown. Default: `false`
*/
suppressErrors?: boolean;
}
@@ -64,30 +66,6 @@ const handleError = (error: unknown, errors: DetailedError[], parseError?: Parse
}
};
/**
* This is an internal function and should not be made public, as it will likely change.
* @internal
* @param diagrams - Array of {@link ExternalDiagramDefinition}.
*/
const loadExternalDiagrams = async (...diagrams: ExternalDiagramDefinition[]) => {
log.debug(`Loading ${diagrams.length} external diagrams`);
// Load all lazy loaded diagrams in parallel
const results = await Promise.allSettled(
diagrams.map(async ({ id, detector, loader }) => {
const { diagram } = await loader();
registerDiagram(id, diagram, detector);
})
);
const failed = results.filter((result) => result.status === 'rejected');
if (failed.length > 0) {
log.error(`Failed to load ${failed.length} external diagrams`);
for (const res of failed) {
log.error(res);
}
throw new Error(`Failed to load ${failed.length} external diagrams`);
}
};
/**
* ## run
*
@@ -251,7 +229,7 @@ const init = async function (
/**
* Used to register external diagram types.
* @param diagrams - Array of {@link ExternalDiagramDefinition}.
* @param opts - If opts.lazyLoad is true, the diagram will be loaded on demand.
* @param opts - If opts.lazyLoad is false, the diagrams will be loaded immediately.
*/
const registerExternalDiagrams = async (
diagrams: ExternalDiagramDefinition[],
@@ -261,10 +239,9 @@ const registerExternalDiagrams = async (
lazyLoad?: boolean;
} = {}
) => {
if (lazyLoad) {
registerLazyLoadedDiagrams(...diagrams);
} else {
await loadExternalDiagrams(...diagrams);
registerLazyLoadedDiagrams(...diagrams);
if (lazyLoad === false) {
await loadRegisteredDiagrams();
}
};

View File

@@ -74,6 +74,23 @@ export interface ParseOptions {
// @ts-ignore Could replicate the type definition in d3. This also makes it possible to use the untyped info from the js diagram files.
export type D3Element = any;
export interface RenderResult {
/**
* The svg code for the rendered graph.
*/
svg: string;
/**
* Bind function to be called after the svg has been inserted into the DOM.
* This is necessary for adding event listeners to the elements in the svg.
* ```js
* const { svg, bindFunctions } = mermaidAPI.render('id1', 'graph TD;A-->B');
* div.innerHTML = svg;
* bindFunctions?.(div); // To call bindFunctions only if it's present.
* ```
*/
bindFunctions?: (element: Element) => void;
}
/**
* Parse the text and validate the syntax.
* @param text - The mermaid diagram definition.
@@ -379,11 +396,6 @@ export const removeExistingElements = (
* @returns Returns the rendered element as a string containing the SVG definition.
*/
export interface RenderResult {
svg: string;
bindFunctions?: (element: Element) => void;
}
const render = async function (
id: string,
text: string,

View File

@@ -1,39 +1,7 @@
import classDiagram from './diagrams/class/styles';
import er from './diagrams/er/styles';
import error from './diagrams/error/styles';
import flowchart from './diagrams/flowchart/styles';
import gantt from './diagrams/gantt/styles';
// import gitGraph from './diagrams/git/styles';
import info from './diagrams/info/styles';
import pie from './diagrams/pie/styles';
import requirement from './diagrams/requirement/styles';
import sequence from './diagrams/sequence/styles';
import stateDiagram from './diagrams/state/styles';
import journey from './diagrams/user-journey/styles';
import c4 from './diagrams/c4/styles';
import { FlowChartStyleOptions } from './diagrams/flowchart/styles';
import type { FlowChartStyleOptions } from './diagrams/flowchart/styles';
import { log } from './logger';
// TODO @knut: Inject from registerDiagram.
const themes: Record<string, any> = {
flowchart,
'flowchart-v2': flowchart,
sequence,
gantt,
classDiagram,
'classDiagram-v2': classDiagram,
class: classDiagram,
stateDiagram,
state: stateDiagram,
// gitGraph,
info,
pie,
er,
error,
journey,
requirement,
c4,
};
const themes: Record<string, any> = {};
const getStyles = (
type: string,

45
pnpm-lock.yaml generated
View File

@@ -1166,7 +1166,6 @@ packages:
/@braintree/sanitize-url/6.0.0:
resolution: {integrity: sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w==}
dev: false
/@colors/colors/1.5.0:
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
@@ -2983,6 +2982,10 @@ packages:
resolution: {integrity: sha512-zmEmF5OIM3rb7SbLCFYoQhO4dGt2FRM9AMkxvA3LaADOF1n8in/zGJlWji9fmafLoNyz+FoL6FE0SLtGIArD7w==}
dev: true
/@types/lodash/4.14.189:
resolution: {integrity: sha512-kb9/98N6X8gyME9Cf7YaqIMvYGnBSWqEci6tiettE6iJWH1XdJz/PO8LB0GtLCG7x8dU3KWhZT+lA1a35127tA==}
dev: true
/@types/markdown-it/12.2.3:
resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==}
dependencies:
@@ -5424,12 +5427,10 @@ packages:
engines: {node: '>=12'}
dependencies:
internmap: 2.0.3
dev: false
/d3-axis/3.0.0:
resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==}
engines: {node: '>=12'}
dev: false
/d3-brush/3.0.0:
resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==}
@@ -5440,38 +5441,32 @@ packages:
d3-interpolate: 3.0.1
d3-selection: 3.0.0
d3-transition: 3.0.1_d3-selection@3.0.0
dev: false
/d3-chord/3.0.1:
resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==}
engines: {node: '>=12'}
dependencies:
d3-path: 3.0.1
dev: false
/d3-color/3.1.0:
resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
engines: {node: '>=12'}
dev: false
/d3-contour/4.0.0:
resolution: {integrity: sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==}
engines: {node: '>=12'}
dependencies:
d3-array: 3.2.0
dev: false
/d3-delaunay/6.0.2:
resolution: {integrity: sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==}
engines: {node: '>=12'}
dependencies:
delaunator: 5.0.0
dev: false
/d3-dispatch/3.0.1:
resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==}
engines: {node: '>=12'}
dev: false
/d3-drag/3.0.0:
resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==}
@@ -5479,7 +5474,6 @@ packages:
dependencies:
d3-dispatch: 3.0.1
d3-selection: 3.0.0
dev: false
/d3-dsv/3.0.1:
resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==}
@@ -5489,19 +5483,16 @@ packages:
commander: 7.2.0
iconv-lite: 0.6.3
rw: 1.3.3
dev: false
/d3-ease/3.0.1:
resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
engines: {node: '>=12'}
dev: false
/d3-fetch/3.0.1:
resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==}
engines: {node: '>=12'}
dependencies:
d3-dsv: 3.0.1
dev: false
/d3-force/3.0.0:
resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==}
@@ -5510,51 +5501,42 @@ packages:
d3-dispatch: 3.0.1
d3-quadtree: 3.0.1
d3-timer: 3.0.1
dev: false
/d3-format/3.1.0:
resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
engines: {node: '>=12'}
dev: false
/d3-geo/3.0.1:
resolution: {integrity: sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==}
engines: {node: '>=12'}
dependencies:
d3-array: 3.2.0
dev: false
/d3-hierarchy/3.1.2:
resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==}
engines: {node: '>=12'}
dev: false
/d3-interpolate/3.0.1:
resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
engines: {node: '>=12'}
dependencies:
d3-color: 3.1.0
dev: false
/d3-path/3.0.1:
resolution: {integrity: sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==}
engines: {node: '>=12'}
dev: false
/d3-polygon/3.0.1:
resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==}
engines: {node: '>=12'}
dev: false
/d3-quadtree/3.0.1:
resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==}
engines: {node: '>=12'}
dev: false
/d3-random/3.0.1:
resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==}
engines: {node: '>=12'}
dev: false
/d3-scale-chromatic/3.0.0:
resolution: {integrity: sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==}
@@ -5562,7 +5544,6 @@ packages:
dependencies:
d3-color: 3.1.0
d3-interpolate: 3.0.1
dev: false
/d3-scale/4.0.2:
resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
@@ -5573,38 +5554,32 @@ packages:
d3-interpolate: 3.0.1
d3-time: 3.0.0
d3-time-format: 4.1.0
dev: false
/d3-selection/3.0.0:
resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==}
engines: {node: '>=12'}
dev: false
/d3-shape/3.1.0:
resolution: {integrity: sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==}
engines: {node: '>=12'}
dependencies:
d3-path: 3.0.1
dev: false
/d3-time-format/4.1.0:
resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
engines: {node: '>=12'}
dependencies:
d3-time: 3.0.0
dev: false
/d3-time/3.0.0:
resolution: {integrity: sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==}
engines: {node: '>=12'}
dependencies:
d3-array: 3.2.0
dev: false
/d3-timer/3.0.1:
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
engines: {node: '>=12'}
dev: false
/d3-transition/3.0.1_d3-selection@3.0.0:
resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==}
@@ -5618,7 +5593,6 @@ packages:
d3-interpolate: 3.0.1
d3-selection: 3.0.0
d3-timer: 3.0.1
dev: false
/d3-zoom/3.0.0:
resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==}
@@ -5629,7 +5603,6 @@ packages:
d3-interpolate: 3.0.1
d3-selection: 3.0.0
d3-transition: 3.0.1_d3-selection@3.0.0
dev: false
/d3/7.8.2:
resolution: {integrity: sha512-WXty7qOGSHb7HR7CfOzwN1Gw04MUOzN8qh9ZUsvwycIMb4DYMpY9xczZ6jUorGtO6bR9BPMPaueIKwiDxu9uiQ==}
@@ -5665,7 +5638,6 @@ packages:
d3-timer: 3.0.1
d3-transition: 3.0.1_d3-selection@3.0.0
d3-zoom: 3.0.0
dev: false
/dagre-d3-es/7.0.8:
resolution: {integrity: sha512-eykdoYQ4FwCJinEYS0gPL2f2w+BPbSLvnQSJ3Ye1vAoPjdkq6xIMKBv+UkICd3qZE26wBKIn3p+6n0QC7R1LyA==}
@@ -5859,7 +5831,6 @@ packages:
resolution: {integrity: sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==}
dependencies:
robust-predicates: 3.0.1
dev: false
/delayed-stream/1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
@@ -7496,7 +7467,6 @@ packages:
/internmap/2.0.3:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'}
dev: false
/interpret/2.2.0:
resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==}
@@ -8453,7 +8423,6 @@ packages:
/khroma/2.0.0:
resolution: {integrity: sha512-2J8rDNlQWbtiNYThZRvmMv5yt44ZakX+Tz5ZIp/mN1pt4snn+m030Va5Z4v8xA0cQFDXBwO/8i42xL4QPsVk3g==}
dev: false
/kind-of/6.0.3:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
@@ -9327,7 +9296,6 @@ packages:
/moment-mini/2.29.4:
resolution: {integrity: sha512-uhXpYwHFeiTbY9KSgPPRoo1nt8OxNVdMVoTBYHfSEKeRkIkwGpO+gERmhuhBtzfaeOyTkykSrm2+noJBgqt3Hg==}
dev: false
/mri/1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
@@ -9430,7 +9398,6 @@ packages:
/non-layered-tidy-tree-layout/2.0.2:
resolution: {integrity: sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==}
dev: false
/normalize-package-data/2.5.0:
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
@@ -10439,7 +10406,6 @@ packages:
/robust-predicates/3.0.1:
resolution: {integrity: sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==}
dev: false
/rollup/3.15.0:
resolution: {integrity: sha512-F9hrCAhnp5/zx/7HYmftvsNBkMfLfk/dXUh73hPSM2E3CRgap65orDNJbLetoiUFwSAk6iHPLvBrZ5iHYvzqsg==}
@@ -10457,7 +10423,6 @@ packages:
/rw/1.3.3:
resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
dev: false
/rxjs/7.5.6:
resolution: {integrity: sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==}
@@ -11086,7 +11051,6 @@ packages:
/stylis/4.1.2:
resolution: {integrity: sha512-Nn2CCrG2ZaFziDxaZPN43CXqn+j7tcdjPFCkRBkFue8QYXC2HdEwnw5TCBo4yQZ2WxKYeSi0fdoOrtEqgDrXbA==}
dev: false
/supports-color/2.0.0:
resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==}
@@ -11655,7 +11619,6 @@ packages:
/uuid/9.0.0:
resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==}
hasBin: true
dev: false
/uvu/0.5.6:
resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==}