sync last changes

This commit is contained in:
Emerson Bottero
2022-10-25 17:54:07 -03:00
112 changed files with 7426 additions and 2363 deletions

View File

@@ -16,26 +16,17 @@
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:jsdoc/recommended",
"plugin:json/recommended",
"plugin:markdown/recommended",
"plugin:@cspell/recommended",
"prettier"
],
"plugins": ["@typescript-eslint", "html", "jest", "jsdoc", "json"],
"plugins": ["@typescript-eslint", "no-only-tests", "html", "jest", "jsdoc", "json", "@cspell"],
"rules": {
"curly": "error",
"no-console": "error",
"no-prototype-builtins": "off",
"no-unused-vars": "off",
"jsdoc/check-indentation": "off",
"jsdoc/check-alignment": "off",
"jsdoc/check-line-alignment": "off",
"jsdoc/multiline-blocks": "off",
"jsdoc/newline-after-description": "off",
"jsdoc/tag-lines": "off",
"jsdoc/require-param-description": "off",
"jsdoc/require-param-type": "off",
"jsdoc/require-returns": "off",
"jsdoc/require-returns-description": "off",
"cypress/no-async-tests": "off",
"@typescript-eslint/ban-ts-comment": [
"error",
@@ -48,7 +39,21 @@
}
],
"json/*": ["error", "allowComments"],
"no-empty": ["error", { "allowEmptyCatch": true }]
"@cspell/spellchecker": [
"error",
{
"checkIdentifiers": false,
"checkStrings": false,
"checkStringTemplates": false
}
],
"no-empty": [
"error",
{
"allowEmptyCatch": true
}
],
"no-only-tests/no-only-tests": "error"
},
"overrides": [
{
@@ -57,6 +62,29 @@
"no-console": "off"
}
},
{
"files": ["*.{js,jsx,mjs,cjs}"],
"extends": ["plugin:jsdoc/recommended"],
"rules": {
"jsdoc/check-indentation": "off",
"jsdoc/check-alignment": "off",
"jsdoc/check-line-alignment": "off",
"jsdoc/multiline-blocks": "off",
"jsdoc/newline-after-description": "off",
"jsdoc/tag-lines": "off",
"jsdoc/require-param-description": "off",
"jsdoc/require-param-type": "off",
"jsdoc/require-returns": "off",
"jsdoc/require-returns-description": "off"
}
},
{
"files": ["*.{ts,tsx}"],
"plugins": ["tsdoc"],
"rules": {
"tsdoc/syntax": "error"
}
},
{
"files": ["*.spec.{ts,js}", "cypress/**", "demos/**", "**/docs/**"],
"rules": {

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
auto-install-peers=true

View File

@@ -1,7 +1,15 @@
import express from 'express';
import express, { NextFunction, Request, Response } from 'express';
import { createServer as createViteServer } from 'vite';
// import { getBuildConfig } from './build';
const cors = (req: Request, res: Response, next: NextFunction) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
};
async function createServer() {
const app = express();
@@ -12,6 +20,7 @@ async function createServer() {
appType: 'custom', // don't include Vite's default HTML handling middlewares
});
app.use(cors);
app.use(express.static('./packages/mermaid/dist'));
app.use(express.static('./packages/mermaid-example-diagram/dist'));
app.use(express.static('./packages/mermaid-mindmap/dist'));

View File

@@ -164,6 +164,7 @@ Class01 <|-- AveryLongClass : Cool
Class09 --> C2 : Where am I?
Class09 --* C3
Class09 --|> Class07
note "I love this diagram!\nDo you love it?"
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
@@ -174,6 +175,7 @@ class Class10 {
int id
size()
}
note for Class10 "Cool class\nI said it's very cool class!"
```
### State diagram [<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid.live/edit#pako:eNpdkEFvgzAMhf8K8nEqpYSNthx22Xbcqcexg0sCiZQQlDhIFeK_L8A6TfXp6fOz9ewJGssFVOAJSbwr7ByadGR1n8T6evpO0vQ1uZDSekOrXGFsPqJPO6q-2-imH8f_0TeHXm50lfelsAMjnEHFY6xpMdRAUhhRQxUlFy0GTTXU_RytYeAx-AdXZB1ULWovdoCB7OXWN1CRC-Ju-r3uz6UtchGHJqDbsPygU57iysb2reoWHpyOWBINvsqypb3vFMlw3TfWZF5xiY7keC6zkpUnZIUojwW-FAVvrvn51LLnvOXHQ84Q5nn-AVtLcwk">live editor</a>]

View File

@@ -13,7 +13,8 @@
"sandboxed",
"Sveidqvist",
"verdana",
"Visio"
"Visio",
"mermiad"
],
"ignoreWords": [
"Adamiecki",
@@ -38,7 +39,30 @@
"Podlite",
"redmine",
"sphinxcontrib",
"Tuleap"
"Tuleap",
"dagre",
"vitepress",
"docsify",
"colour",
"graphlib",
"acyclicer",
"ranksep",
"descr",
"substate",
"Ashish",
"bbox",
"techn",
"cytoscape",
"Lucida",
"Bilkent",
"cpettitt",
"antiscript",
"ts-nocheck",
"setupGraphViewbox",
"flatmap",
"Kaufmann",
"viewports",
"edgechromium"
],
"patterns": [
{

View File

@@ -45,7 +45,6 @@ export const imgSnapshotTest = (graphStr, _options, api = false, validation) =>
options.fontSize = '16px';
}
const useAppli = Cypress.env('useAppli');
//const useAppli = false;
cy.log('Hello ' + useAppli ? 'Appli' : 'image-snapshot');
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
@@ -59,7 +58,9 @@ export const imgSnapshotTest = (graphStr, _options, api = false, validation) =>
const url = mermaidUrl(graphStr, options, api);
cy.visit(url);
if (validation) cy.get('svg').should(validation);
if (validation) {
cy.get('svg').should(validation);
}
cy.get('svg');
// Default name to test title
@@ -107,7 +108,9 @@ export const urlSnapshotTest = (url, _options, api = false, validation) => {
}
cy.visit(url);
if (validation) cy.get('svg').should(validation);
if (validation) {
cy.get('svg').should(validation);
}
cy.get('body');
// Default name to test title

View File

@@ -21,7 +21,7 @@ describe('Git Graph diagram', () => {
// // Call Open on eyes to initialize a test session
// cy.eyesOpen({
// appName: 'Demo App',
// testName: 'Ultrafast grid demo',
// testName: 'UltraFast grid demo',
// });
// // check the login page with fluent api, see more info here

View File

@@ -478,4 +478,22 @@ describe('Class diagram V2', () => {
);
cy.get('svg');
});
it('18: should render a simple class diagram with notes', () => {
imgSnapshotTest(
`
classDiagram-v2
note "I love this diagram!\nDo you love it?"
class Class10 {
<<service>>
int id
size()
}
note for Class10 "Cool class\nI said it's very cool class!"
`,
{ logLevel: 1, flowchart: { htmlLabels: false } }
);
cy.get('svg');
});
});

View File

@@ -407,4 +407,21 @@ describe('Class diagram', () => {
// // expect(svg).to.not.have.attr('style');
// });
// });
it('19: should render a simple class diagram with notes', () => {
imgSnapshotTest(
`
classDiagram
note "I love this diagram!\nDo you love it?"
class Class10 {
<<service>>
int id
size()
}
note for Class10 "Cool class\nI said it's very cool class!"
`,
{ logLevel: 1 }
);
cy.get('svg');
});
});

View File

@@ -167,7 +167,7 @@ describe('Entity Relationship Diagram', () => {
cy.get('svg');
});
it.only('should render entities with generic and array attributes', () => {
it('should render entities with generic and array attributes', () => {
renderGraph(
`
erDiagram
@@ -255,4 +255,22 @@ describe('Entity Relationship Diagram', () => {
);
cy.get('svg');
});
it('should render entities with aliases', () => {
renderGraph(
`
erDiagram
T1 one or zero to one or more T2 : test
T2 one or many optionally to zero or one T3 : test
T3 zero or more to zero or many T4 : test
T4 many(0) to many(1) T5 : test
T5 many optionally to one T6 : test
T6 only one optionally to only one T1 : test
T4 0+ to 1+ T6 : test
T1 1 to 1 T3 : test
`,
{ logLevel: 1 }
);
cy.get('svg');
});
});

View File

@@ -56,50 +56,40 @@
<body>
<div>Security check</div>
<pre id="diagram" class="mermaid">
classDiagram
direction LR
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
flowchart TD
A --> B
B --> C
A --> C
</pre>
<pre id="diagram" class="mermaid2">
<pre id="diagram" class="mermaid">
mindmap
root
A
B
C
D
E
A2
B2
C2
D2
E2
child1((Circle))
grandchild 1
grandchild 2
child2(Round rectangle)
grandchild 3
grandchild 4
child3[Square]
grandchild 5
::icon(mdi mdi-fire)
gc6((grand<br/>child 6))
::icon(mdi mdi-fire)
gc7((grand<br/>grand<br/>child 8))
root((mindmap))
Origins
Long history
::icon(fa fa-book)
Popularisation
::icon(fa fa-book)
British popular psychology author Tony Buzan
Research
::icon(fa fa-book)
On effectivness<br/>and features
On Automatic creation
Uses
Creative techniques
Strategic planning
Argument mapping
Tools
Pen and paper
Mermaid
</pre>
<pre id="diagram" class="mermaid2">
example-diagram
<pre id="diagram" class="mermaid">
gantt
title Style today marker (vertical line should be 5px wide and half-transparent blue)
dateFormat YYYY-MM-DD
axisFormat %d
todayMarker stroke-width:5px,stroke:#00f,opacity:0.5
section Section1
Today: 1, -1h
</pre>
<!-- <div id="cy"></div> -->
@@ -113,16 +103,21 @@ mindmap
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'forest',
theme: 'base',
startOnLoad: true,
logLevel: 0,
// basePath: './packages/',
// themeVariables: { darkMode: true },
flowchart: {
useMaxWidth: false,
htmlLabels: true,
},
gantt: {
useMaxWidth: false,
},
useMaxWidth: false,
lazyLoadedDiagrams: [
'./mermaid-mindmap-detector.esm.mjs',
'./mermaid-example-diagram-detector.esm.mjs',
],
// lazyLoadedDiagrams: ['../../mermaid-mindmap/registry.ts'],
});
function callback() {
alert('It worked');
@@ -131,6 +126,10 @@ mindmap
console.error('In parse error:');
console.error(err);
};
// mermaid.test1('first_slow', 1200).then((r) => console.info(r));
// mermaid.test1('second_fast', 200).then((r) => console.info(r));
// mermaid.test1('third_fast', 200).then((r) => console.info(r));
// mermaid.test1('forth_slow', 1200).then((r) => console.info(r));
</script>
</body>
</html>

View File

@@ -120,7 +120,9 @@ const contentLoadedApi = function () {
(svgCode, bindFunctions) => {
div.innerHTML = svgCode;
if (bindFunctions) bindFunctions(div);
if (bindFunctions) {
bindFunctions(div);
}
},
div
);

View File

@@ -94,7 +94,7 @@
}
// var diagram = ` graph TD
// A --> B["&lt;a href='javasc`;
// A --> B["&lt;a href='javascript`;
// diagram += `ript#colon;xssAttack()'&gt;AAA&lt;/a&gt;"]`;
let diagram = ` graph TD
A --> B["<a href='javasc`;

View File

@@ -74,22 +74,22 @@
<pre class="mermaid">
gantt
title Hide today marker (vertical line should not be visible)
dateFormat YYYY-MM-DD
axisFormat %d
dateFormat Z
axisFormat %d/%m
todayMarker off
section Section1
Today: 1, -1h
Today: 1, -01:00, 5min
</pre>
<hr />
<pre class="mermaid">
gantt
title Style today marker (vertical line should be 5px wide and half-transparent blue)
dateFormat YYYY-MM-DD
axisFormat %d
dateFormat Z
axisFormat %d/%m
todayMarker stroke-width:5px,stroke:#00f,opacity:0.5
section Section1
Today: 1, -1h
Today: 1, -01:00, 5min
</pre>
<hr />

View File

@@ -0,0 +1,25 @@
const CustomMarkdown = (md) => {
const fence = md.renderer.rules.fence.bind(md.renderer.rules);
md.renderer.rules.fence = (tokens, index, options, env, slf) => {
const token = tokens[index];
if (token.info.trim() === 'warning') {
return `<div class="warning custom-block"><p class="custom-block-title">WARNING</p><p>${token.content}}</p></div>`;
}
if (token.info.trim() === 'note') {
return `<div class="tip custom-block"><p class="custom-block-title">NOTE</p><p>${token.content}}</p></div>`;
}
if (token.info.trim() === 'jison') {
return `<div class="language-"><button class="copy"></button><span class="lang">jison</span><pre><code>${token.content
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')}}</code></pre></div>`;
}
return fence(tokens, index, options, env, slf);
};
};
export default CustomMarkdown;

View File

@@ -1,17 +1,28 @@
import { version } from '../../../package.json';
import MermaidMarkdown from './mermaid-markdown-all';
import MermaidExample from './mermaid-markdown-all';
import { MermaidMarkdown } from 'vitepress-plugin-mermaid';
import CustomMarkdown from './blocks-markdown';
import { defineConfig } from 'vitepress';
const allMarkdownTransformers = {
config: async (md) => {
MermaidMarkdown(md);
await MermaidExample(md);
CustomMarkdown(md);
},
};
export default defineConfig({
lang: 'en-US',
title: 'Mermaid',
description: 'Create diagrams and visualizations using text and code.',
base: '/mermaid-docs/',
markdown: MermaidMarkdown,
base: '/mermaid-js/',
markdown: allMarkdownTransformers,
head: [['link', { rel: 'icon', type: 'image/x-icon', href: '/mermaid-js/favicon.ico' }]],
themeConfig: {
nav: nav(),
editLink: {
pattern: 'https://github.com/mermaid-js/mermaid/edit/develop/docs/:path',
pattern: 'https://github.com/mermaid-js/mermaid/edit/develop/packages/mermaid/src/docs/:path',
text: 'Edit this page on GitHub',
},

View File

@@ -1,23 +1,44 @@
import { MermaidMarkdown } from 'vitepress-plugin-mermaid';
// import { deflate } from 'pako';
// import { fromUint8Array } from 'js-base64';
import shiki from 'shiki';
export default {
config: async (md) => {
MermaidMarkdown(md);
// const serializeState = (state: State, serde: SerdeType = 'pako'): string => {
// if (serdes[serde] === undefined) {
// throw new Error(`Unknown serde type: ${serde}`);
// }
// const json = JSON.stringify(state);
// const serialized = serdes[serde].serialize(json);
// return `${serde}:${serialized}`;
// };
// const serialize = (state: string): string => {
// const data = new TextEncoder().encode(state);
// const compressed = deflate(data, { level: 9 });
// return fromUint8Array(compressed, true);
// };
const MermaidExample = async (md) => {
const fence = md.renderer.rules.fence.bind(md.renderer.rules);
const highlighter = await shiki.getHighlighter({ theme: 'material-palenight' });
md.renderer.rules.fence = (tokens, index, options, env, slf) => {
const token = tokens[index];
// console.log("==>",token.info);
if (token.info.trim() === 'mermaid-example') {
let code = highlighter.codeToHtml(token.content, { lang: 'mermaid' });
code = code.replace('#2e3440ff', 'transparent');
code = code.replace('#292D3E', 'transparent');
code =
'<h5>Code:</h5>' +
'<div class="language-mermaid"><button class="copy"></button><span class="lang">mermaid</span>' +
`<div class="language-mermaid">` +
// TODO: compute edit link!
// `<a class="edit" href="https://mermaid.live/edit#pako:${serialize(
// token.content
// )}" target=”_blank”>✒️</a>` +
`<button class="copy"></button><span class="lang">mermaid</span>` +
code +
'</div>';
@@ -28,5 +49,6 @@ export default {
}
return fence(tokens, index, options, env, slf);
};
},
};
export default MermaidExample;

View File

@@ -19,3 +19,9 @@
.vp-doc > div {
width: 100%;
}
a.edit {
margin: 12px;
position: relative;
top: 10px;
}

View File

@@ -21,17 +21,20 @@ For instance:
There are some jison specific sub steps here where the parser stores the data encountered when parsing the diagram, this data is later used by the renderer. You can during the parsing call a object provided to the parser by the user of the parser. This object can be called during parsing for storing data.
```jison
statement
: 'participant' actor { $$='actor'; }
| signal { $$='signal'; }
| note_statement { $$='note'; }
| 'title' message { yy.setTitle($2); }
;
```
In the extract of the grammar above, it is defined that a call to the setTitle method in the data object will be done when parsing and the title keyword is encountered.
> **Note**\
> Make sure that the `parseError` function for the parser is defined and calling `mermaid.parseError`. This way a common way of detecting parse errors is provided for the end-user.
```note
Make sure that the `parseError` function for the parser is defined and calling `mermaid.parseError`. This way a common way of detecting parse errors is provided for the end-user.
```
For more info look in the example diagram type:
@@ -123,8 +126,7 @@ Here some pointers on how to handle these different areas.
Here is example handling from flowcharts:
Jison:
```
```jison
/* lexical grammar */
%lex
%x open_directive
@@ -180,6 +182,8 @@ The syntax for adding title and description looks like this:
In a similar way to the directives the jison syntax are quite similar between the diagrams.
```jison
* lexical grammar */
%lex
%x acc_title
@@ -200,6 +204,8 @@ In a similar way to the directives the jison syntax are quite similar between th
| acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); }
| acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); }
```
The functions for setting title and description are provided by a common module. This is the import from flowDb.js:
import {

View File

@@ -52,8 +52,9 @@ Implementors can only modify configurations using directives, and cannot change
The Two types of directives: are `init` (or `initialize`) and `wrap`.
> **Note**\
> All directives are enclosed in `%%{ }%%`
```note
All directives are enclosed in `%%{ }%%`
```
Older versions of mermaid will not parse directives because `%%` will comment out the directive. This makes the update backwards-compatible.
@@ -65,8 +66,8 @@ Older versions of mermaid will not parse directives because `%%` will comment ou
| --------- | ----------------------- | --------- | -------- | ----------------------------------------------- |
| init | modifies configurations | Directive | Optional | Any parameters not included in the secure array |
> **Note**\
> init would be an argument-directive: `%%{init: { **insert argument here**}}%%`
```note
init would be an argument-directive: `%%{init: { **insert argument here**}}%%`
The json object that is passed as {**argument** } must be valid, quoted json or it will be ignored.
**for example**:
@@ -76,8 +77,7 @@ The json object that is passed as {**argument** } must be valid, quoted json or
Configurations that are passed through init cannot change the parameters in a secure array at a higher level. In the event of a collision, mermaid will give priority to secure arrays and parse the request without changing the values of those parameters in conflict.
When deployed within code, init is called before the graph/diagram description.
>
```
**for example**:
@@ -111,16 +111,15 @@ When deployed within code, init is called before the graph/diagram description.
| --------- | ----------------------------- | --------- | -------- | ---------- |
| wrap | a callable text-wrap function | Directive | Optional | %%{wrap}%% |
> **Note**\
> Wrap is a function that is currently only deployable for sequence diagrams.
```note
Wrap is a function that is currently only deployable for sequence diagrams.
Wrap respects a manually added \<br>, so if the user wants to break up their text, they have full control over line breaks by adding \<br> tags.
`Wrap respects a manually added <br>, so if the user wants to break up their text, they have full control over line breaks by adding <br> tags.`
It is a non-argument directive and can be executed thusly:
`%%{wrap}%%` .
>
```
**An example of text wrapping in a sequence diagram**:
@@ -162,12 +161,13 @@ Example of **object.Assign**:
| --------------- | ------------------------------------- | ----------- | --------------------------------------- | ---------- | ---------- |
| `setSiteConfig` | Sets the siteConfig to desired values | Put Request | Any Values, except ones in secure array | conf | siteConfig |
> **Note**\
> Sets the siteConfig. The siteConfig is a protected configuration for repeat use. Calls to reset() will reset
> the currentConfig to siteConfig. Calls to reset(configApi.defaultConfig) will reset siteConfig and currentConfig
> to the defaultConfig
> Note: currentConfig is set in this function。
> Default value: will mirror Global Config
```note
Sets the siteConfig. The siteConfig is a protected configuration for repeat use. Calls to reset() will reset
the currentConfig to siteConfig. Calls to reset(configApi.defaultConfig) will reset siteConfig and currentConfig
to the defaultConfig
Note: currentConfig is set in this function。
Default value: will mirror Global Config
```
## getSiteConfig
@@ -175,8 +175,9 @@ Example of **object.Assign**:
| --------------- | --------------------------------------------------- | ----------- | ---------------------------------- |
| `getSiteConfig` | Returns the current `siteConfig` base configuration | Get Request | Returns Any Values in `siteConfig` |
> **Note**\
> Returns any values in siteConfig.
```note
Returns any values in siteConfig.
```
## setConfig
@@ -184,10 +185,11 @@ Example of **object.Assign**:
| ----------- | ------------------------------------------ | ----------- | --------------------------------- | ---------- | ---------------------------------------------- |
| `setConfig` | Sets the `currentConfig` to desired values | Put Request | Any Values, those in secure array | conf | `currentConfig` merged with the sanitized conf |
> **Note**\
> Sets the currentConfig. The parameter conf is sanitized based on the siteConfig.secure keys. Any
> values found in conf with key found in siteConfig.secure will be replaced with the corresponding
> siteConfig value.
```note
Sets the currentConfig. The parameter conf is sanitized based on the siteConfig.secure keys. Any
values found in conf with key found in siteConfig.secure will be replaced with the corresponding
siteConfig value.
```
## getConfig
@@ -195,8 +197,9 @@ Example of **object.Assign**:
| ----------- | --------------------------- | ----------- | ------------------------------- |
| `getConfig` | Obtains the `currentConfig` | Get Request | Any Values from `currentConfig` |
> **Note**\
> Returns any values in currentConfig.
```note
Returns any values in currentConfig.
```
## sanitize
@@ -204,9 +207,10 @@ Example of **object.Assign**:
| ---------- | ---------------------------------------- | -------------- | ------ |
| `sanitize` | Sets the `siteConfig` to desired values. | Put Request(?) | None |
> **Note**\
> modifies options in-place
> Ensures options parameter does not attempt to override siteConfig secure keys.
```note
modifies options in-place
Ensures options parameter does not attempt to override siteConfig secure keys.
```
## reset
@@ -220,8 +224,8 @@ Example of **object.Assign**:
| --------- | ------------------------------------------------------------ | ---------- | -------- | -------------------------------------------- |
| `conf` | base set of values, which `currentConfig` could be reset to. | Dictionary | Required | Any Values, with respect to the secure Array |
> **Note**\
> default: current siteConfig (optional, default `getSiteConfig()`)
> s
```note
default: current siteConfig (optional, default `getSiteConfig()`)
```
## For more information, read [Setup](setup/README).

View File

@@ -14,7 +14,7 @@
#### Defined in
[config.ts:7](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/config.ts#L7)
[config.ts:7](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/config.ts#L7)
## Functions
@@ -36,7 +36,7 @@ Pushes in a directive to the configuration
#### Defined in
[config.ts:191](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/config.ts#L191)
[config.ts:191](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/config.ts#L191)
---
@@ -56,11 +56,11 @@ Pushes in a directive to the configuration
`MermaidConfig`
- The currentConfig
The currentConfig
#### Defined in
[config.ts:136](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/config.ts#L136)
[config.ts:136](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/config.ts#L136)
---
@@ -80,11 +80,11 @@ Pushes in a directive to the configuration
`MermaidConfig`
- The siteConfig
The siteConfig
#### Defined in
[config.ts:96](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/config.ts#L96)
[config.ts:96](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/config.ts#L96)
---
@@ -108,9 +108,9 @@ Pushes in a directive to the configuration
#### Parameters
| Name | Type | Default value |
| :------- | :-------------- | :------------ |
| `config` | `MermaidConfig` | `siteConfig` |
| Name | Type | Default value | Description |
| :------- | :-------------- | :------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `config` | `MermaidConfig` | `siteConfig` | base set of values, which currentConfig could be **reset** to. Defaults to the current siteConfig (e.g returned by [getSiteConfig](config.md#getsiteconfig)). |
#### Returns
@@ -118,7 +118,7 @@ Pushes in a directive to the configuration
#### Defined in
[config.ts:222](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/config.ts#L222)
[config.ts:223](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/config.ts#L223)
---
@@ -147,7 +147,7 @@ options in-place
#### Defined in
[config.ts:151](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/config.ts#L151)
[config.ts:151](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/config.ts#L151)
---
@@ -167,7 +167,7 @@ options in-place
#### Defined in
[config.ts:75](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/config.ts#L75)
[config.ts:75](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/config.ts#L75)
---
@@ -195,11 +195,11 @@ corresponding siteConfig value.
`MermaidConfig`
- The currentConfig merged with the sanitized conf
The currentConfig merged with the sanitized conf
#### Defined in
[config.ts:113](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/config.ts#L113)
[config.ts:113](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/config.ts#L113)
---
@@ -228,11 +228,11 @@ function _Default value: At default, will mirror Global Config_
`MermaidConfig`
- The siteConfig
The new siteConfig
#### Defined in
[config.ts:61](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/config.ts#L61)
[config.ts:61](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/config.ts#L61)
---
@@ -253,7 +253,7 @@ function _Default value: At default, will mirror Global Config_
#### Defined in
[config.ts:14](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/config.ts#L14)
[config.ts:14](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/config.ts#L14)
---
@@ -273,4 +273,4 @@ function _Default value: At default, will mirror Global Config_
#### Defined in
[config.ts:79](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/config.ts#L79)
[config.ts:79](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/config.ts#L79)

View File

@@ -14,7 +14,7 @@
#### Defined in
[defaultConfig.ts:1855](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/defaultConfig.ts#L1855)
[defaultConfig.ts:1884](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/defaultConfig.ts#L1884)
---
@@ -37,23 +37,20 @@ mermaid.initialize({ flowchart: { htmlLabels: false } });
**Example 2:**
```js
let config = {
```html
<script>
var config = {
startOnLoad: true,
flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' },
securityLevel: 'loose',
};
mermaid.initialize(config);
</script>
```
A summary of all options and their defaults is found [here](#mermaidapi-configuration-defaults).
A description of each option follows below.
**`Name`**
Configuration
#### Defined in
[defaultConfig.ts:31](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/defaultConfig.ts#L31)
[defaultConfig.ts:48](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/defaultConfig.ts#L48)

View File

@@ -16,11 +16,11 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi)
### <a id="mermaidapi" name="mermaidapi"></a> mermaidAPI
`Const` **mermaidAPI**: `Readonly`<{ `defaultConfig`: `MermaidConfig` = configApi.defaultConfig; `getConfig`: () => `MermaidConfig` = configApi.getConfig; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `Promise`<`void`> ; `parse`: (`text`: `string`, `parseError?`: `Function`) => `boolean` ; `parseDirective`: (`p`: `any`, `statement`: `string`, `context`: `string`, `type`: `string`) => `void` ; `render`: (`id`: `string`, `text`: `string`, `cb`: (`svgCode`: `string`, `bindFunctions?`: (`element`: `Element`) => `void`) => `void`, `container?`: `Element`) => `Promise`<`void`> ; `reset`: () => `void` ; `setConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.setConfig; `updateSiteConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.updateSiteConfig }>
`Const` **mermaidAPI**: `Readonly`<{ `defaultConfig`: `MermaidConfig` = configApi.defaultConfig; `getConfig`: () => `MermaidConfig` = configApi.getConfig; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `Promise`<`void`> ; `parse`: (`text`: `string`, `parseError?`: `ParseErrorFunction`) => `boolean` ; `parseDirective`: (`p`: `any`, `statement`: `string`, `context`: `string`, `type`: `string`) => `void` ; `render`: (`id`: `string`, `text`: `string`, `cb`: (`svgCode`: `string`, `bindFunctions?`: (`element`: `Element`) => `void`) => `void`, `container?`: `Element`) => `Promise`<`void`> ; `reset`: () => `void` ; `setConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.setConfig; `updateSiteConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.updateSiteConfig }>
#### Defined in
[mermaidAPI.ts:483](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/mermaidAPI.ts#L483)
[mermaidAPI.ts:483](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/mermaidAPI.ts#L483)
## Functions
@@ -40,7 +40,7 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi)
#### Defined in
[mermaidAPI.ts:73](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/mermaidAPI.ts#L73)
[mermaidAPI.ts:70](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/mermaidAPI.ts#L70)
---
@@ -60,4 +60,4 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi)
#### Defined in
[mermaidAPI.ts:47](https://github.com/emersonbottero/mermaid/blob/c8b377bf/packages/mermaid/src/mermaidAPI.ts#L47)
[mermaidAPI.ts:44](https://github.com/emersonbottero/mermaid/blob/563aff2d/packages/mermaid/src/mermaidAPI.ts#L44)

View File

@@ -156,8 +156,9 @@ You can create your own themes, by changing any of the given variables below. If
## Theme Variables Reference Table
> **Note**\
> Variables that are unique to some diagrams can be affected by changes in Theme Variables
```note
Variables that are unique to some diagrams can be affected by changes in Theme Variables
```
| Variable | Default/Base/Factor value | Calc | Description |
| -------------------- | ------------------------------ | ---- | -------------------------------------------------------------------------------------------------------------------------------- |

View File

@@ -119,9 +119,10 @@ Values:
- **antiscript**: html tags in text are allowed, (only script element is removed), click functionality is enabled
- **sandbox**: With this security level all rendering takes place in a sandboxed iframe. This prevent any JavaScript running in the context. This may hinder interactive functionality of the diagram like scripts, popups in sequence diagram or links to other tabs/targets etc.
> **Note**\
> This changes the default behaviour of mermaid so that after upgrade to 8.2, unless the `securityLevel` is not changed, tags in flowcharts are encoded as tags and clicking is disabled.
> **sandbox** security level is still in the beta version.
```note
This changes the default behaviour of mermaid so that after upgrade to 8.2, unless the `securityLevel` is not changed, tags in flowcharts are encoded as tags and clicking is disabled.
**sandbox** security level is still in the beta version.
```
**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.**
@@ -186,8 +187,9 @@ Or with no config object, and a jQuery selection:
mermaid.init(undefined, $('#someId .yetAnotherClass'));
```
> **Warning**\
> This type of integration is deprecated. Instead the preferred way of handling more complex integration is to use the mermaidAPI instead.
```warning
This type of integration is deprecated. Instead the preferred way of handling more complex integration is to use the mermaidAPI instead.
```
## Usage with webpack
@@ -341,8 +343,9 @@ on what kind of integration you use.
</script>
```
> **Note**\
> This is the preferred way of configuring mermaid.
```note
This is the preferred way of configuring mermaid.
```
### The following methods are deprecated and are kept only for backwards compatibility.
@@ -358,8 +361,9 @@ approach are:
mermaid.startOnLoad = true;
```
> **Warning**\
> This way of setting the configuration is deprecated. Instead the preferred way is to use the initialize method. This functionality is only kept for backwards compatibility.
```warning
This way of setting the configuration is deprecated. Instead the preferred way is to use the initialize method. This functionality is only kept for backwards compatibility.
```
## Using the mermaid_config
@@ -373,8 +377,9 @@ approach are:
mermaid_config.startOnLoad = true;
```
> **Warning**\
> This way of setting the configuration is deprecated. Instead the preferred way is to use the initialize method. This functionality is only kept for backwards compatibility.
```warning
This way of setting the configuration is deprecated. Instead the preferred way is to use the initialize method. This functionality is only kept for backwards compatibility.
```
## Using the mermaid.init call
@@ -387,5 +392,6 @@ To set some configuration via the mermaid object. The two parameters that are su
mermaid_config.startOnLoad = true;
```
> **Warning**\
> This way of setting the configuration is deprecated. Instead the preferred way is to use the initialize method. This functionality is only kept for backwards compatibility.
```warning
This way of setting the configuration is deprecated. Instead the preferred way is to use the initialize method. This functionality is only kept for backwards compatibility.
```

763
docs/sequenceDiagram.md Normal file
View File

@@ -0,0 +1,763 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in package/mermaid/src/docs.
# Sequence diagrams
> A Sequence diagram is an interaction diagram that shows how processes operate with one another and in what order.
Mermaid can render sequence diagrams.
```mermaid-example
sequenceDiagram
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
```
```mermaid
sequenceDiagram
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
```
```note
A note on nodes, the word "end" could potentially break the diagram, due to the way that the mermaid language is scripted.
If unavoidable, one must use parentheses(), quotation marks "", or brackets {},[], to enclose the word "end". i.e : (end), [end], {end}.
```
## Syntax
### Participants
The participants can be defined implicitly as in the first example on this page. The participants or actors are
rendered in order of appearance in the diagram source text. Sometimes you might want to show the participants in a
different order than how they appear in the first message. It is possible to specify the actor's order of
appearance by doing the following:
```mermaid-example
sequenceDiagram
participant Alice
participant Bob
Alice->>Bob: Hi Bob
Bob->>Alice: Hi Alice
```
```mermaid
sequenceDiagram
participant Alice
participant Bob
Alice->>Bob: Hi Bob
Bob->>Alice: Hi Alice
```
### Actors
If you specifically want to use the actor symbol instead of a rectangle with text you can do so by using actor statements as per below.
```mermaid-example
sequenceDiagram
actor Alice
actor Bob
Alice->>Bob: Hi Bob
Bob->>Alice: Hi Alice
```
```mermaid
sequenceDiagram
actor Alice
actor Bob
Alice->>Bob: Hi Bob
Bob->>Alice: Hi Alice
```
### Aliases
The actor can have a convenient identifier and a descriptive label.
```mermaid-example
sequenceDiagram
participant A as Alice
participant J as John
A->>J: Hello John, how are you?
J->>A: Great!
```
```mermaid
sequenceDiagram
participant A as Alice
participant J as John
A->>J: Hello John, how are you?
J->>A: Great!
```
## Messages
Messages can be of two displayed either solid or with a dotted line.
[Actor][Arrow][Actor]:Message text
There are eight types of arrows currently supported:
| Type | Description |
| ---- | ------------------------------------------------ |
| -> | Solid line without arrow |
| --> | Dotted line without arrow |
| ->> | Solid line with arrowhead |
| -->> | Dotted line with arrowhead |
| -x | Solid line with a cross at the end |
| --x | Dotted line with a cross at the end. |
| -) | Solid line with an open arrow at the end (async) |
| --) | Dotted line with a open arrow at the end (async) |
## Activations
It is possible to activate and deactivate an actor. (de)activation can be dedicated declarations:
```mermaid-example
sequenceDiagram
Alice->>John: Hello John, how are you?
activate John
John-->>Alice: Great!
deactivate John
```
```mermaid
sequenceDiagram
Alice->>John: Hello John, how are you?
activate John
John-->>Alice: Great!
deactivate John
```
There is also a shortcut notation by appending `+`/`-` suffix to the message arrow:
```mermaid-example
sequenceDiagram
Alice->>+John: Hello John, how are you?
John-->>-Alice: Great!
```
```mermaid
sequenceDiagram
Alice->>+John: Hello John, how are you?
John-->>-Alice: Great!
```
Activations can be stacked for same actor:
```mermaid-example
sequenceDiagram
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
John-->>-Alice: I feel great!
```
```mermaid
sequenceDiagram
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
John-->>-Alice: I feel great!
```
## Notes
It is possible to add notes to a sequence diagram. This is done by the notation
Note \[ right of | left of | over ] \[Actor]: Text in note content
See the example below:
```mermaid-example
sequenceDiagram
participant John
Note right of John: Text in note
```
```mermaid
sequenceDiagram
participant John
Note right of John: Text in note
```
It is also possible to create notes spanning two participants:
```mermaid-example
sequenceDiagram
Alice->John: Hello John, how are you?
Note over Alice,John: A typical interaction
```
```mermaid
sequenceDiagram
Alice->John: Hello John, how are you?
Note over Alice,John: A typical interaction
```
## Loops
It is possible to express loops in a sequence diagram. This is done by the notation
loop Loop text
... statements ...
end
See the example below:
```mermaid-example
sequenceDiagram
Alice->John: Hello John, how are you?
loop Every minute
John-->Alice: Great!
end
```
```mermaid
sequenceDiagram
Alice->John: Hello John, how are you?
loop Every minute
John-->Alice: Great!
end
```
## Alt
It is possible to express alternative paths in a sequence diagram. This is done by the notation
alt Describing text
... statements ...
else
... statements ...
end
or if there is sequence that is optional (if without else).
opt Describing text
... statements ...
end
See the example below:
```mermaid-example
sequenceDiagram
Alice->>Bob: Hello Bob, how are you?
alt is sick
Bob->>Alice: Not so good :(
else is well
Bob->>Alice: Feeling fresh like a daisy
end
opt Extra response
Bob->>Alice: Thanks for asking
end
```
```mermaid
sequenceDiagram
Alice->>Bob: Hello Bob, how are you?
alt is sick
Bob->>Alice: Not so good :(
else is well
Bob->>Alice: Feeling fresh like a daisy
end
opt Extra response
Bob->>Alice: Thanks for asking
end
```
## Parallel
It is possible to show actions that are happening in parallel.
This is done by the notation
par [Action 1]
... statements ...
and [Action 2]
... statements ...
and [Action N]
... statements ...
end
See the example below:
```mermaid-example
sequenceDiagram
par Alice to Bob
Alice->>Bob: Hello guys!
and Alice to John
Alice->>John: Hello guys!
end
Bob-->>Alice: Hi Alice!
John-->>Alice: Hi Alice!
```
```mermaid
sequenceDiagram
par Alice to Bob
Alice->>Bob: Hello guys!
and Alice to John
Alice->>John: Hello guys!
end
Bob-->>Alice: Hi Alice!
John-->>Alice: Hi Alice!
```
It is also possible to nest parallel blocks.
```mermaid-example
sequenceDiagram
par Alice to Bob
Alice->>Bob: Go help John
and Alice to John
Alice->>John: I want this done today
par John to Charlie
John->>Charlie: Can we do this today?
and John to Diana
John->>Diana: Can you help us today?
end
end
```
```mermaid
sequenceDiagram
par Alice to Bob
Alice->>Bob: Go help John
and Alice to John
Alice->>John: I want this done today
par John to Charlie
John->>Charlie: Can we do this today?
and John to Diana
John->>Diana: Can you help us today?
end
end
```
## Critical Region
It is possible to show actions that must happen automatically with conditional handling of circumstances.
This is done by the notation
critical [Action that must be performed]
... statements ...
option [Circumstance A]
... statements ...
option [Circumstance B]
... statements ...
end
See the example below:
```mermaid-example
sequenceDiagram
critical Establish a connection to the DB
Service-->DB: connect
option Network timeout
Service-->Service: Log error
option Credentials rejected
Service-->Service: Log different error
end
```
```mermaid
sequenceDiagram
critical Establish a connection to the DB
Service-->DB: connect
option Network timeout
Service-->Service: Log error
option Credentials rejected
Service-->Service: Log different error
end
```
It is also possible to have no options at all
```mermaid-example
sequenceDiagram
critical Establish a connection to the DB
Service-->DB: connect
end
```
```mermaid
sequenceDiagram
critical Establish a connection to the DB
Service-->DB: connect
end
```
This critical block can also be nested, equivalently to the `par` statement as seen above.
## Break
It is possible to indicate a stop of the sequence within the flow (usually used to model exceptions).
This is done by the notation
break [something happened]
... statements ...
end
See the example below:
```mermaid-example
sequenceDiagram
Consumer-->API: Book something
API-->BookingService: Start booking process
break when the booking process fails
API-->Consumer: show failure
end
API-->BillingService: Start billing process
```
```mermaid
sequenceDiagram
Consumer-->API: Book something
API-->BookingService: Start booking process
break when the booking process fails
API-->Consumer: show failure
end
API-->BillingService: Start billing process
```
## Background Highlighting
It is possible to highlight flows by providing colored background rects. This is done by the notation
The colors are defined using rgb and rgba syntax.
rect rgb(0, 255, 0)
... content ...
end
<!---->
rect rgba(0, 0, 255, .1)
... content ...
end
See the examples below:
```mermaid-example
sequenceDiagram
participant Alice
participant John
rect rgb(191, 223, 255)
note right of Alice: Alice calls John.
Alice->>+John: Hello John, how are you?
rect rgb(200, 150, 255)
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
end
John-->>-Alice: I feel great!
end
Alice ->>+ John: Did you want to go to the game tonight?
John -->>- Alice: Yeah! See you there.
```
```mermaid
sequenceDiagram
participant Alice
participant John
rect rgb(191, 223, 255)
note right of Alice: Alice calls John.
Alice->>+John: Hello John, how are you?
rect rgb(200, 150, 255)
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
end
John-->>-Alice: I feel great!
end
Alice ->>+ John: Did you want to go to the game tonight?
John -->>- Alice: Yeah! See you there.
```
## Comments
Comments can be entered within a sequence diagram, which will be ignored by the parser. Comments need to be on their own line, and must be prefaced with `%%` (double percent signs). Any text after the start of the comment to the next newline will be treated as a comment, including any diagram syntax
```mermaid-example
sequenceDiagram
Alice->>John: Hello John, how are you?
%% this is a comment
John-->>Alice: Great!
```
```mermaid
sequenceDiagram
Alice->>John: Hello John, how are you?
%% this is a comment
John-->>Alice: Great!
```
## Entity codes to escape characters
It is possible to escape characters using the syntax exemplified here.
```mermaid-example
sequenceDiagram
A->>B: I #9829; you!
B->>A: I #9829; you #infin; times more!
```
```mermaid
sequenceDiagram
A->>B: I #9829; you!
B->>A: I #9829; you #infin; times more!
```
Numbers given are base 10, so `#` can be encoded as `#35;`. It is also supported to use HTML character names.
Because semicolons can be used instead of line breaks to define the markup, you need to use `#59;` to include a semicolon in message text.
## sequenceNumbers
It is possible to get a sequence number attached to each arrow in a sequence diagram. This can be configured when adding mermaid to the website as shown below:
```html
<script>
mermaid.initialize({ sequence: { showSequenceNumbers: true } });
</script>
```
It can also be be turned on via the diagram code as in the diagram:
```mermaid-example
sequenceDiagram
autonumber
Alice->>John: Hello John, how are you?
loop Healthcheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts!
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
```
```mermaid
sequenceDiagram
autonumber
Alice->>John: Hello John, how are you?
loop Healthcheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts!
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
```
## Actor Menus
Actors can have popup-menus containing individualized links to external pages. For example, if an actor represented a web service, useful links might include a link to the service health dashboard, repo containing the code for the service, or a wiki page describing the service.
This can be configured by adding one or more link lines with the format:
link <actor>: <link-label> @ <link-url>
```mermaid-example
sequenceDiagram
participant Alice
participant John
link Alice: Dashboard @ https://dashboard.contoso.com/alice
link Alice: Wiki @ https://wiki.contoso.com/alice
link John: Dashboard @ https://dashboard.contoso.com/john
link John: Wiki @ https://wiki.contoso.com/john
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
```
```mermaid
sequenceDiagram
participant Alice
participant John
link Alice: Dashboard @ https://dashboard.contoso.com/alice
link Alice: Wiki @ https://wiki.contoso.com/alice
link John: Dashboard @ https://dashboard.contoso.com/john
link John: Wiki @ https://wiki.contoso.com/john
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
```
#### Advanced Menu Syntax
There is an advanced syntax that relies on JSON formatting. If you are comfortable with JSON format, then this exists as well.
This can be configured by adding the links lines with the format:
links <actor>: <json-formatted link-name link-url pairs>
An example is below:
```mermaid-example
sequenceDiagram
participant Alice
participant John
links Alice: {"Dashboard": "https://dashboard.contoso.com/alice", "Wiki": "https://wiki.contoso.com/alice"}
links John: {"Dashboard": "https://dashboard.contoso.com/john", "Wiki": "https://wiki.contoso.com/john"}
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
```
```mermaid
sequenceDiagram
participant Alice
participant John
links Alice: {"Dashboard": "https://dashboard.contoso.com/alice", "Wiki": "https://wiki.contoso.com/alice"}
links John: {"Dashboard": "https://dashboard.contoso.com/john", "Wiki": "https://wiki.contoso.com/john"}
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
```
## Styling
Styling of a sequence diagram is done by defining a number of css classes. During rendering these classes are extracted from the file located at src/themes/sequence.scss
### Classes used
| Class | Description |
| ------------ | ----------------------------------------------------------- |
| actor | Style for the actor box at the top of the diagram. |
| text.actor | Styles for text in the actor box at the top of the diagram. |
| actor-line | The vertical line for an actor. |
| messageLine0 | Styles for the solid message line. |
| messageLine1 | Styles for the dotted message line. |
| messageText | Defines styles for the text on the message arrows. |
| labelBox | Defines styles label to left in a loop. |
| labelText | Styles for the text in label for loops. |
| loopText | Styles for the text in the loop box. |
| loopLine | Defines styles for the lines in the loop box. |
| note | Styles for the note box. |
| noteText | Styles for the text on in the note boxes. |
### Sample stylesheet
```css
body {
background: white;
}
.actor {
stroke: #ccccff;
fill: #ececff;
}
text.actor {
fill: black;
stroke: none;
font-family: Helvetica;
}
.actor-line {
stroke: grey;
}
.messageLine0 {
stroke-width: 1.5;
stroke-dasharray: '2 2';
marker-end: 'url(#arrowhead)';
stroke: black;
}
.messageLine1 {
stroke-width: 1.5;
stroke-dasharray: '2 2';
stroke: black;
}
#arrowhead {
fill: black;
}
.messageText {
fill: black;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
font-size: 14px;
}
.labelBox {
stroke: #ccccff;
fill: #ececff;
}
.labelText {
fill: black;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
}
.loopText {
fill: black;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
}
.loopLine {
stroke-width: 2;
stroke-dasharray: '2 2';
marker-end: 'url(#arrowhead)';
stroke: #ccccff;
}
.note {
stroke: #decc93;
fill: #fff5ad;
}
.noteText {
fill: black;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
font-size: 14px;
}
```
## Configuration
Is it possible to adjust the margins for rendering the sequence diagram.
This is done by defining `mermaid.sequenceConfig` or by the CLI to use a json file with the configuration.
How to use the CLI is described in the [mermaidCLI](mermaidCLI) page.
`mermaid.sequenceConfig` can be set to a JSON string with config parameters or the corresponding object.
```javascript
mermaid.sequenceConfig = {
diagramMarginX: 50,
diagramMarginY: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
mirrorActors: true,
};
```
### Possible configuration parameters:
| Parameter | Description | Default value |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------ |
| mirrorActors | Turns on/off the rendering of actors below the diagram as well as above it | false |
| bottomMarginAdj | Adjusts how far down the graph ended. Wide borders styles with css could generate unwanted clipping which is why this config param exists. | 1 |
| actorFontSize | Sets the font size for the actor's description | 14 |
| actorFontFamily | Sets the font family for the actor's description | "Open Sans", sans-serif |
| actorFontWeight | Sets the font weight for the actor's description | "Open Sans", sans-serif |
| noteFontSize | Sets the font size for actor-attached notes | 14 |
| noteFontFamily | Sets the font family for actor-attached notes | "trebuchet ms", verdana, arial |
| noteFontWeight | Sets the font weight for actor-attached notes | "trebuchet ms", verdana, arial |
| noteAlign | Sets the text alignment for text in actor-attached notes | center |
| messageFontSize | Sets the font size for actor<->actor messages | 16 |
| messageFontFamily | Sets the font family for actor<->actor messages | "trebuchet ms", verdana, arial |
| messageFontWeight | Sets the font weight for actor<->actor messages | "trebuchet ms", verdana, arial |

View File

@@ -15,7 +15,9 @@ Mermaid can render class diagrams.
```mermaid-example
classDiagram
note "From Duck till Zebra"
Animal <|-- Duck
note for Duck "can fly\ncan swim\ncan dive\ncan help in debugging"
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
@@ -39,7 +41,9 @@ classDiagram
```mermaid
classDiagram
note "From Duck till Zebra"
Animal <|-- Duck
note for Duck "can fly\ncan swim\ncan dive\ncan help in debugging"
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
@@ -553,6 +557,10 @@ You would define these actions on a separate line after all classes have been de
- (_optional_) tooltip is a string to be displayed when hovering over element (note: The styles of the tooltip are set by the class .mermaidTooltip.)
- note: callback function will be called with the nodeId as parameter.
## Notes
It is possible to add notes on digram using `note "line1\nline2"` or note for class using `note for class "line1\nline2"`
### Examples
_URL Link:_

View File

@@ -114,10 +114,34 @@ Cardinality is a property that describes how many elements of another entity can
| `}o` | `o{` | Zero or more (no upper limit) |
| `}\|` | `\|{` | One or more (no upper limit) |
**Aliases**
| Value (left) | Value (right) | Alias for |
| :----------: | :-----------: | ------------ |
| one or zero | one or zero | Zero or one |
| zero or one | zero or one | Zero or one |
| one or more | one or more | One or more |
| one or many | one or many | One or more |
| many(1) | many(1) | One or more |
| 1+ | 1+ | One or more |
| zero or more | zero or more | Zero or more |
| zero or many | zero or many | Zero or more |
| many(0) | many(1) | Zero or more |
| 0+ | 0+ | Zero or more |
| only one | only one | Exactly one |
| 1 | 1 | Exactly one |
### Identification
Relationships may be classified as either _identifying_ or _non-identifying_ and these are rendered with either solid or dashed lines respectively. This is relevant when one of the entities in question can not have independent existence without the other. For example a firm that insures people to drive cars might need to store data on `NAMED-DRIVER`s. In modelling this we might start out by observing that a `CAR` can be driven by many `PERSON` instances, and a `PERSON` can drive many `CAR`s - both entities can exist without the other, so this is a non-identifying relationship that we might specify in Mermaid as: `PERSON }|..|{ CAR : "driver"`. Note the two dots in the middle of the relationship that will result in a dashed line being drawn between the two entities. But when this many-to-many relationship is resolved into two one-to-many relationships, we observe that a `NAMED-DRIVER` cannot exist without both a `PERSON` and a `CAR` - the relationships become identifying and would be specified using hyphens, which translate to a solid line:
**Aliases**
| Value | Alias for |
| :-----------: | :---------------: |
| to | _identifying_ |
| optionally to | _non-identifying_ |
```mermaid-example
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
@@ -222,6 +246,7 @@ erDiagram
string lastName
int age
}
MANUFACTURER only one to zero or more CAR
```
```mermaid
@@ -240,6 +265,7 @@ erDiagram
string lastName
int age
}
MANUFACTURER only one to zero or more CAR
```
### Other Things

View File

@@ -10,7 +10,7 @@ All Flowcharts are composed of **nodes**, the geometric shapes and **edges**, th
It can also accommodate different arrow types, multi directional arrows, and linking to and from subgraphs.
> **Important note**: Do not type the word "end" as a Flowchart node. Capitalize all or any one the letters to keep the flowchart from breaking, i.e, "End" or "END". Or you can apply this [workaround](https://github.com/mermaid-js/mermaid/issues/1444#issuecomment-639528897).\*\*
> **Important note**: Do not type the word "end" as a Flowchart node. Capitalize all or any one the letters to keep the flowchart from breaking, i.e, "End" or "END". Or you can apply this [workaround](https://github.com/mermaid-js/mermaid/issues/1444#issuecomment-639528897).
### A node (default)
@@ -787,10 +787,10 @@ Beginner's tip—a full example using interactive links in a html context:
</pre>
<script>
var callback = function () {
const callback = function () {
alert('A callback was triggered');
};
var config = {
const config = {
startOnLoad: true,
flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' },
securityLevel: 'loose',
@@ -882,13 +882,13 @@ A shorter form of adding a class is to attach the classname to the node using th
```mermaid-example
flowchart LR
A:::someclass --> B
classDef someclass fill:#f96;
classDef someclass fill:#f96
```
```mermaid
flowchart LR
A:::someclass --> B
classDef someclass fill:#f96;
classDef someclass fill:#f96
```
### Css classes

View File

@@ -32,7 +32,7 @@ Drawing a pie chart is really simple in mermaid.
- Start with `pie` keyword to begin the diagram
- `showData` to render the actual data values after the legend text. This is **_OPTIONAL_**
- Followed by `title` keyword and its value in string to give a title to the pie-chart. This is **_OPTIONAL_**
- Followed by dataSet
- Followed by dataSet. Pie slices will be ordered clockwise in the same order as the labels.
- `label` for a section in the pie diagram within `" "` quotes.
- Followed by `:` colon as separator
- Followed by `positive numeric value` (supported upto two decimal places)

View File

@@ -24,12 +24,11 @@ sequenceDiagram
Alice-)John: See you later!
```
> **Note**\
> A note on nodes, the word "end" could potentially break the diagram, due to the way that the mermaid language is scripted.
```note
A note on nodes, the word "end" could potentially break the diagram, due to the way that the mermaid language is scripted.
If unavoidable, one must use parentheses(), quotation marks "", or brackets {},\[], to enclose the word "end". i.e : (end), \[end], {end}.
>
If unavoidable, one must use parentheses(), quotation marks "", or brackets {},[], to enclose the word "end". i.e : (end), [end], {end}.
```
## Syntax

View File

@@ -7,7 +7,7 @@
"module": "dist/mermaid.core.mjs",
"types": "dist/mermaid.d.ts",
"type": "module",
"packageManager": "pnpm@7.13.2",
"packageManager": "pnpm@7.13.6",
"exports": {
".": {
"require": "./dist/mermaid.min.js",
@@ -63,77 +63,84 @@
]
},
"dependencies": {
"@braintree/sanitize-url": "^6.0.0",
"@types/node": "^18.8.1",
"@types/uuid": "^8.3.4",
"d3": "^7.0.0",
"dagre": "^0.8.5",
"dagre-d3": "^0.6.4",
"@braintree/sanitize-url": "6.0.1",
"@types/node": "18.11.0",
"@types/uuid": "8.3.4",
"d3": "7.6.1",
"dagre": "0.8.5",
"dagre-d3": "0.6.4",
"dompurify": "2.4.0",
"fast-clone": "^1.5.13",
"graphlib": "^2.1.8",
"khroma": "^2.0.0",
"lodash": "^4.17.21",
"moment-mini": "^2.24.0",
"non-layered-tidy-tree-layout": "^2.0.2",
"rollup": "^2.79.1",
"stylis": "^4.1.2",
"uuid": "^9.0.0"
"fast-clone": "1.5.13",
"graphlib": "2.1.8",
"khroma": "2.0.0",
"lodash": "4.17.21",
"moment-mini": "2.29.4",
"non-layered-tidy-tree-layout": "2.0.2",
"rollup": "2.79.1",
"stylis": "4.1.2",
"uuid": "9.0.0"
},
"devDependencies": {
"@applitools/eyes-cypress": "^3.27.1",
"@commitlint/cli": "^17.1.2",
"@commitlint/config-conventional": "^17.1.0",
"@types/d3": "^7.4.0",
"@types/dompurify": "^2.3.4",
"@types/eslint": "^8.4.6",
"@types/express": "^4.17.14",
"@types/jsdom": "^20.0.0",
"@types/lodash": "^4.14.186",
"@types/mdast": "^3.0.10",
"@types/prettier": "^2.7.1",
"@types/stylis": "^4.0.2",
"@typescript-eslint/eslint-plugin": "^5.39.0",
"@typescript-eslint/parser": "^5.39.0",
"@vitest/coverage-c8": "^0.23.4",
"@vitest/ui": "^0.23.4",
"concurrently": "^7.4.0",
"coveralls": "^3.1.1",
"cypress": "^10.0.0",
"cypress-image-snapshot": "^4.0.1",
"esbuild": "^0.15.10",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-html": "^7.1.0",
"eslint-plugin-jest": "^27.1.0",
"eslint-plugin-jsdoc": "^39.3.6",
"eslint-plugin-json": "^3.1.0",
"eslint-plugin-markdown": "^3.0.0",
"express": "^4.18.1",
"globby": "^13.1.2",
"husky": "^8.0.1",
"identity-obj-proxy": "^3.0.0",
"jest": "29.x",
"jison": "^0.4.18",
"jsdom": "^20.0.1",
"lint-staged": "^13.0.3",
"markdown-it": "^13.0.1",
"path-browserify": "^1.0.1",
"pnpm": "^7.13.2",
"prettier": "^2.7.1",
"prettier-plugin-jsdoc": "^0.4.2",
"remark": "^14.0.2",
"rimraf": "^3.0.2",
"start-server-and-test": "^1.14.0",
"ts-node": "^10.9.1",
"typescript": "^4.8.4",
"unist-util-flatmap": "^1.0.0",
"vite": "^3.1.4",
"vitest": "^0.23.4"
"@applitools/eyes-cypress": "3.27.5",
"@commitlint/cli": "17.1.2",
"@commitlint/config-conventional": "17.1.0",
"@cspell/eslint-plugin": "6.12.0",
"@types/d3": "7.4.0",
"@types/dompurify": "2.3.4",
"@types/eslint": "8.4.7",
"@types/express": "4.17.14",
"@types/jsdom": "20.0.0",
"@types/lodash": "4.14.186",
"@types/mdast": "3.0.10",
"@types/prettier": "2.7.1",
"@types/stylis": "4.0.2",
"@typescript-eslint/eslint-plugin": "5.40.1",
"@typescript-eslint/parser": "5.40.1",
"@vitest/coverage-c8": "0.24.3",
"@vitest/ui": "0.24.3",
"concurrently": "7.4.0",
"coveralls": "3.1.1",
"cypress": "10.10.0",
"cypress-image-snapshot": "4.0.1",
"documentation": "13.2.5",
"esbuild": "0.15.12",
"eslint": "8.25.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-cypress": "2.12.1",
"eslint-plugin-html": "7.1.0",
"eslint-plugin-jest": "27.1.3",
"eslint-plugin-jsdoc": "39.3.23",
"eslint-plugin-json": "3.1.0",
"eslint-plugin-markdown": "3.0.0",
"eslint-plugin-no-only-tests": "3.1.0",
"eslint-plugin-tsdoc": "0.2.17",
"express": "4.18.2",
"globby": "13.1.2",
"husky": "8.0.1",
"identity-obj-proxy": "3.0.0",
"jest": "29.2.1",
"jison": "0.4.18",
"jsdom": "20.0.1",
"lint-staged": "13.0.3",
"markdown-it": "13.0.1",
"path-browserify": "1.0.1",
"pnpm": "7.13.6",
"prettier": "2.7.1",
"prettier-plugin-jsdoc": "0.4.2",
"remark": "14.0.2",
"rimraf": "3.0.2",
"start-server-and-test": "1.14.0",
"ts-node": "10.9.1",
"typescript": "4.8.4",
"unist-util-flatmap": "1.0.0",
"vite": "3.1.8",
"vitepress": "1.0.0-alpha.22",
"vitepress-plugin-mermaid": "2.0.8",
"vitepress-plugin-search": "1.0.4-alpha.11",
"vitest": "0.24.3"
},
"resolutions": {
"d3": "^7.0.0"
"d3": "7.6.1"
},
"files": [
"dist"

View File

@@ -50,8 +50,8 @@
},
"dependencies": {},
"devDependencies": {
"concurrently": "^7.4.0",
"rimraf": "^3.0.2"
"concurrently": "7.4.0",
"rimraf": "3.0.2"
},
"resolutions": {
"d3": "^7.0.0"

View File

@@ -2,9 +2,9 @@
export const id = 'example-diagram';
/**
* Detector function that will be called by mermaid to determine if the diagram is this type of digram.
* Detector function that will be called by mermaid to determine if the diagram is this type of diagram.
*
* @param txt The diagram text will be passed to the detector
* @param txt - The diagram text will be passed to the detector
* @returns True if the diagram text matches a diagram of this type
*/

View File

@@ -16,7 +16,7 @@ export const draw = (text, id, version) => {
log.debug('Rendering example diagram\n' + text, 'Conf: ');
const THEME_COLOR_LIMIT = getConfig().themeVariables.THEME_COLOR_LIMIT;
const securityLevel = getConfig().securityLevel;
// Handle root and Document for when rendering in sanbox mode
// Handle root and Document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);

View File

@@ -35,18 +35,19 @@ export let setupGraphViewbox: (
/**
* Function called by mermaid that injects utility functions that help the diagram to be a good citizen.
* @param _log
* @param _setLogLevel
* @param _getConfig
* @param _sanitizeText
* @param _setupGraphViewbox
*
* @param _log - log from mermaid/src/diagramAPI.ts
* @param _setLogLevel - setLogLevel from mermaid/src/diagramAPI.ts
* @param _getConfig - getConfig from mermaid/src/diagramAPI.ts
* @param _sanitizeText - sanitizeText from mermaid/src/diagramAPI.ts
* @param _setupGraphViewbox - setupGraphViewbox from mermaid/src/diagramAPI.ts
*/
export const injectUtils = (
_log: Record<keyof typeof LEVELS, typeof console.log>,
_setLogLevel: any,
_getConfig: any,
_sanitizeText: any,
_setupGraphViewbox: any
_setLogLevel: typeof setLogLevel,
_getConfig: typeof getConfig,
_sanitizeText: typeof sanitizeText,
_setupGraphViewbox: typeof setupGraphViewbox
) => {
_log.debug('Mermaid utils injected into example-diagram');
log.trace = _log.trace;

View File

@@ -57,8 +57,8 @@
"non-layered-tidy-tree-layout": "^2.0.2"
},
"devDependencies": {
"concurrently": "^7.4.0",
"rimraf": "^3.0.2"
"concurrently": "7.4.0",
"rimraf": "3.0.2"
},
"resolutions": {
"d3": "^7.0.0"

View File

@@ -11,7 +11,7 @@ cytoscape.use(coseBilkent);
/**
* @param {any} svg The svg element to draw the diagram onto
* @param {object} mindmap The maindmap data and hierarchy
* @param {object} mindmap The mindmap data and hierarchy
* @param section
* @param {object} conf The configuration object
*/
@@ -52,7 +52,7 @@ function drawEdges(edgesEl, cy) {
/**
* @param {any} svg The svg element to draw the diagram onto
* @param {object} mindmap The maindmap data and hierarchy
* @param {object} mindmap The mindmap data and hierarchy
* @param section
* @param cy
* @param {object} conf The configuration object
@@ -96,7 +96,6 @@ function addNodes(mindmap, cy, conf, level) {
/**
* @param node
* @param conf
* @param cy
*/
function layoutMindmap(node, conf) {
return new Promise((resolve) => {
@@ -121,7 +120,7 @@ function layoutMindmap(node, conf) {
renderEl.remove();
addNodes(node, cy, conf, 0);
// Make cytoscape care about the dimensisions of the nodes
// Make cytoscape care about the dimensions of the nodes
cy.nodes().forEach(function (n) {
n.layoutDimensions = () => {
const data = n.data();
@@ -143,10 +142,7 @@ function layoutMindmap(node, conf) {
});
}
/**
* @param node
* @param cy
* @param positionedMindmap
* @param conf
*/
function positionNodes(cy) {
cy.nodes().map((node, id) => {
@@ -184,7 +180,7 @@ export const draw = async (text, id, version, diagObj) => {
log.debug('Renering info diagram\n' + text);
const securityLevel = getConfig().securityLevel;
// Handle root and Document for when rendering in sanbox mode
// Handle root and Document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);

View File

@@ -22,12 +22,10 @@ const genSections = (options) => {
}
.section-${i - 1} text {
fill: ${options['cScaleLabel' + i]};
// fill: ${options['gitInv' + i]};
}
.node-icon-${i - 1} {
font-size: 40px;
color: ${options['cScaleLabel' + i]};
// color: ${options['gitInv' + i]};
}
.section-edge-${i - 1}{
stroke: ${options['cScale' + i]};
@@ -36,7 +34,7 @@ const genSections = (options) => {
stroke-width: ${sw};
}
.section-${i - 1} line {
stroke: ${options['lineColor' + i]} ;
stroke: ${options['cScaleInv' + i]} ;
stroke-width: 3;
}

View File

@@ -31,7 +31,7 @@
"build:esbuild": "concurrently \"pnpm build:code\" \"pnpm build:types\"",
"build": "pnpm clean; pnpm build:esbuild",
"dev": "node .esbuild/serve.cjs",
"predocs:build": "rimraf docs",
"predocs:build": "rimraf docs && pnpm docs:code",
"docs:build": "ts-node-esm src/docs.mts",
"docs:verify": "pnpm docs:build --verify",
"docs:code": "typedoc --plugin typedoc-plugin-markdown --readme none --hideBreadcrumbs --hideInPageTOC --namedAnchors --out src/docs/config/setup --entryPointStrategy expand src/defaultConfig.ts src/config.ts src/mermaidAPI.ts",
@@ -80,58 +80,54 @@
"non-layered-tidy-tree-layout": "^2.0.2"
},
"devDependencies": {
"@applitools/eyes-cypress": "^3.25.7",
"@commitlint/cli": "^17.1.2",
"@commitlint/config-conventional": "^17.0.0",
"@types/d3": "^7.4.0",
"@types/dompurify": "^2.3.4",
"@types/eslint": "^8.4.6",
"@types/express": "^4.17.13",
"@types/jsdom": "^20.0.0",
"@types/lodash": "^4.14.185",
"@types/prettier": "^2.7.0",
"@types/stylis": "^4.0.2",
"@typescript-eslint/eslint-plugin": "^5.37.0",
"@typescript-eslint/parser": "^5.37.0",
"concurrently": "^7.4.0",
"coveralls": "^3.1.1",
"cypress": "^10.0.0",
"cypress-image-snapshot": "^4.0.1",
"esbuild": "^0.15.8",
"eslint": "^8.23.1",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-html": "^7.1.0",
"eslint-plugin-jest": "^27.0.4",
"eslint-plugin-jsdoc": "^39.3.6",
"eslint-plugin-json": "^3.1.0",
"eslint-plugin-markdown": "^3.0.0",
"express": "^4.18.1",
"globby": "^13.1.2",
"husky": "^8.0.0",
"identity-obj-proxy": "^3.0.0",
"jison": "^0.4.18",
"@applitools/eyes-cypress": "3.27.5",
"@commitlint/cli": "17.1.2",
"@commitlint/config-conventional": "17.1.0",
"@types/d3": "7.4.0",
"@types/dompurify": "2.3.4",
"@types/eslint": "8.4.7",
"@types/express": "4.17.14",
"@types/jsdom": "20.0.0",
"@types/lodash": "4.14.186",
"@types/prettier": "2.7.1",
"@types/stylis": "4.0.2",
"@typescript-eslint/eslint-plugin": "5.40.1",
"@typescript-eslint/parser": "5.40.1",
"concurrently": "7.4.0",
"coveralls": "3.1.1",
"cypress": "10.10.0",
"cypress-image-snapshot": "4.0.1",
"documentation": "13.2.5",
"esbuild": "0.15.12",
"eslint": "8.25.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-cypress": "2.12.1",
"eslint-plugin-html": "7.1.0",
"eslint-plugin-jest": "27.1.3",
"eslint-plugin-jsdoc": "39.3.23",
"eslint-plugin-json": "3.1.0",
"eslint-plugin-markdown": "3.0.0",
"express": "4.18.2",
"globby": "13.1.2",
"husky": "8.0.1",
"identity-obj-proxy": "3.0.0",
"jison": "0.4.18",
"js-base64": "3.7.2",
"jsdom": "^20.0.0",
"lint-staged": "^13.0.0",
"moment": "^2.23.0",
"path-browserify": "^1.0.1",
"prettier": "^2.7.1",
"prettier-plugin-jsdoc": "^0.4.2",
"remark": "^14.0.2",
"rimraf": "^3.0.2",
"start-server-and-test": "^1.12.6",
"ts-node": "^10.9.1",
"typescript": "^4.8.3",
"unist-util-flatmap": "^1.0.0",
"vite": "^3.1.4",
"vitepress": "^1.0.0-alpha.19",
"vitepress-plugin-mermaid": "^2.0.8",
"vitepress-plugin-search": "^1.0.4-alpha.11",
"jsdom": "20.0.1",
"lint-staged": "13.0.3",
"moment": "2.29.4",
"path-browserify": "1.0.1",
"prettier": "2.7.1",
"prettier-plugin-jsdoc": "0.4.2",
"remark": "14.0.2",
"rimraf": "3.0.2",
"shiki": "^0.11.1",
"stylis": "^4.1.2",
"typedoc": "^0.23.16",
"typedoc-plugin-markdown": "^3.13.6"
"start-server-and-test": "1.14.0",
"ts-node": "10.9.1",
"typedoc": "^0.23.18",
"typedoc-plugin-markdown": "^3.13.6",
"typescript": "4.8.4",
"unist-util-flatmap": "1.0.0"
},
"resolutions": {
"d3": "^7.0.0"

View File

@@ -2,15 +2,17 @@ import * as configApi from './config';
import { log } from './logger';
import { getDiagram, registerDiagram } from './diagram-api/diagramAPI';
import { detectType, getDiagramLoader } from './diagram-api/detectType';
import { isDetailedError } from './utils';
import { isDetailedError, type DetailedError } from './utils';
export type ParseErrorFunction = (err: string | DetailedError, hash?: any) => void;
export class Diagram {
type = 'graph';
parser;
renderer;
db;
private detectTypeFailed = false;
// eslint-disable-next-line @typescript-eslint/ban-types
constructor(public txt: string, parseError?: Function) {
constructor(public txt: string, parseError?: ParseErrorFunction) {
const cnf = configApi.getConfig();
this.txt = txt;
try {
@@ -37,8 +39,7 @@ export class Diagram {
this.parse(this.txt, parseError);
}
// eslint-disable-next-line @typescript-eslint/ban-types
parse(text: string, parseError?: Function): boolean {
parse(text: string, parseError?: ParseErrorFunction): boolean {
if (this.detectTypeFailed) {
return false;
}
@@ -53,23 +54,24 @@ export class Diagram {
return false;
}
// eslint-disable-next-line @typescript-eslint/ban-types
handleError(error: unknown, parseError?: Function) {
handleError(error: unknown, parseError?: ParseErrorFunction) {
// Is this the correct way to access mermiad's parseError()
// method ? (or global.mermaid.parseError()) ?
if (parseError) {
if (isDetailedError(error)) {
// handle case where error string and hash were
// wrapped in object like`const error = { str, hash };`
parseError(error.str, error.hash);
} else {
// assume it is just error string and pass it on
parseError(error);
}
} else {
if (parseError === undefined) {
// No mermaid.parseError() handler defined, so re-throw it
throw error;
}
if (isDetailedError(error)) {
// Handle case where error string and hash were
// wrapped in object like`const error = { str, hash };`
parseError(error.str, error.hash);
return;
}
// Otherwise, assume it is just an error string and pass it on
parseError(error as string);
}
getParser() {
@@ -81,8 +83,10 @@ export class Diagram {
}
}
// eslint-disable-next-line @typescript-eslint/ban-types
export const getDiagramFromText = async (txt: string, parseError?: Function): Promise<Diagram> => {
export const getDiagramFromText = async (
txt: string,
parseError?: ParseErrorFunction
): Promise<Diagram> => {
const type = detectType(txt, configApi.getConfig());
try {
// Trying to find the diagram

View File

@@ -6,17 +6,13 @@
import * as configApi from '../config';
import { vi } from 'vitest';
import { addDiagrams } from '../diagram-api/diagram-orchestration';
import Diagram from '../Diagram';
import Diagram, { type ParseErrorFunction } from '../Diagram';
// Normally, we could just do the following to get the original `parse()`
// implementation, however, requireActual returns a promise and it's not documented how to use withing mock file.
/**
* @param text
* @param parseError
*/
// eslint-disable-next-line @typescript-eslint/ban-types
function parse(text: string, parseError?: Function): boolean {
/** {@inheritDoc mermaidAPI.parse} */
function parse(text: string, parseError?: ParseErrorFunction): boolean {
addDiagrams();
const diagram = new Diagram(text, parseError);
return diagram.parse(text, parseError);

View File

@@ -56,7 +56,7 @@ export const updateCurrentConfig = (siteCfg: MermaidConfig, _directives: any[])
* function _Default value: At default, will mirror Global Config_
*
* @param conf - The base currentConfig to use as siteConfig
* @returns {object} - The siteConfig
* @returns The new siteConfig
*/
export const setSiteConfig = (conf: MermaidConfig): MermaidConfig => {
siteConfig = assignWithDepth({}, defaultConfig);
@@ -91,7 +91,7 @@ export const updateSiteConfig = (conf: MermaidConfig): MermaidConfig => {
*
* **Notes**: Returns **any** values in siteConfig.
*
* @returns {object} - The siteConfig
* @returns The siteConfig
*/
export const getSiteConfig = (): MermaidConfig => {
return assignWithDepth({}, siteConfig);
@@ -107,8 +107,8 @@ export const getSiteConfig = (): MermaidConfig => {
* keys. Any values found in conf with key found in siteConfig.secure will be replaced with the
* corresponding siteConfig value.
*
* @param {any} conf - The potential currentConfig
* @returns {any} - The currentConfig merged with the sanitized conf
* @param conf - The potential currentConfig
* @returns The currentConfig merged with the sanitized conf
*/
export const setConfig = (conf: MermaidConfig): MermaidConfig => {
// sanitize(conf);
@@ -131,7 +131,7 @@ export const setConfig = (conf: MermaidConfig): MermaidConfig => {
*
* **Notes**: Returns **any** the currentConfig
*
* @returns {any} - The currentConfig
* @returns The currentConfig
*/
export const getConfig = (): MermaidConfig => {
return assignWithDepth({}, currentConfig);
@@ -146,7 +146,7 @@ export const getConfig = (): MermaidConfig => {
* Ensures options parameter does not attempt to override siteConfig secure keys **Notes**: modifies
* options in-place
*
* @param {any} options - The potential setConfig parameter
* @param options - The potential setConfig parameter
*/
export const sanitize = (options: any) => {
// Checking that options are not in the list of excluded options
@@ -166,7 +166,7 @@ export const sanitize = (options: any) => {
}
});
// Check that there no attempts of xss, there should be no tags at all in the directive
// blocking data urls as base64 urls can contain svgs with inline script tags
// blocking data urls as base64 urls can contain svg's with inline script tags
Object.keys(options).forEach((key) => {
if (typeof options[key] === 'string') {
if (
@@ -186,7 +186,7 @@ export const sanitize = (options: any) => {
/**
* Pushes in a directive to the configuration
*
* @param {object} directive The directive to push in
* @param directive - The directive to push in
*/
export const addDirective = (directive: any) => {
if (directive.fontFamily) {
@@ -217,7 +217,8 @@ export const addDirective = (directive: any) => {
*
* **Notes**: (default: current siteConfig ) (optional, default `getSiteConfig()`)
*
* @param config
* @param config - base set of values, which currentConfig could be **reset** to.
* Defaults to the current siteConfig (e.g returned by {@link getSiteConfig}).
*/
export const reset = (config = siteConfig): void => {
// Replace current config with siteConfig

View File

@@ -44,7 +44,9 @@ function addHtmlLabel(node) {
const createLabel = (_vertexText, style, isTitle, isNode) => {
let vertexText = _vertexText || '';
if (typeof vertexText === 'object') vertexText = vertexText[0];
if (typeof vertexText === 'object') {
vertexText = vertexText[0];
}
if (evaluate(getConfig().flowchart.htmlLabels)) {
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
vertexText = vertexText.replace(/\\n|\n/g, '<br />');

View File

@@ -310,7 +310,7 @@ const cutPathAtIntersect = (_points, boundryNode) => {
// const node = clusterDb[edge.toCluster].node;
log.info('abc88 checking point', point, boundryNode);
// check if point is inside the boundry rect
// check if point is inside the boundary rect
if (!outsideNode(boundryNode, point) && !isInside) {
// First point inside the rect found
// Calc the intersection coord between the point anf the last point outside the rect
@@ -336,7 +336,9 @@ const cutPathAtIntersect = (_points, boundryNode) => {
log.warn('abc88 outside', point, lastPointOutside);
lastPointOutside = point;
// points.push(point);
if (!isInside) points.push(point);
if (!isInside) {
points.push(point);
}
}
});
log.warn('abc88 returning points', points);
@@ -429,7 +431,7 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
})
.curve(curve);
// Contruct stroke classes based on properties
// Construct stroke classes based on properties
let strokeClasses;
switch (edge.thickness) {
case 'normal':

View File

@@ -1,5 +1,5 @@
/*
* Borrowed with love from from dagrge-d3. Many thanks to cpettitt!
* Borrowed with love from from dagre-d3. Many thanks to cpettitt!
*/
import node from './intersect-node.js';

View File

@@ -28,7 +28,7 @@ function intersectLine(p1, p2, q1, q2) {
// Check signs of r3 and r4. If both point 3 and point 4 lie on
// same side of line 1, the line segments do not intersect.
if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {
return /*DONT_INTERSECT*/;
return /*DON'T_INTERSECT*/;
}
// Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
@@ -44,7 +44,7 @@ function intersectLine(p1, p2, q1, q2) {
// on same side of second line segment, the line segments do
// not intersect.
if (r1 !== 0 && r2 !== 0 && sameSign(r1, r2)) {
return /*DONT_INTERSECT*/;
return /*DON'T_INTERSECT*/;
}
// Line segments intersect: compute intersection point.

View File

@@ -23,7 +23,9 @@ const isDecendant = (id, ancenstorId) => {
' = ',
decendants[ancenstorId].indexOf(id) >= 0
);
if (decendants[ancenstorId].indexOf(id) >= 0) return true;
if (decendants[ancenstorId].indexOf(id) >= 0) {
return true;
}
return false;
};
@@ -32,19 +34,23 @@ const edgeInCluster = (edge, clusterId) => {
log.info('Decendants of ', clusterId, ' is ', decendants[clusterId]);
log.info('Edge is ', edge);
// Edges to/from the cluster is not in the cluster, they are in the parent
if (edge.v === clusterId) return false;
if (edge.w === clusterId) return false;
if (edge.v === clusterId) {
return false;
}
if (edge.w === clusterId) {
return false;
}
if (!decendants[clusterId]) {
log.debug('Tilt, ', clusterId, ',not in decendants');
return false;
}
if (decendants[clusterId].indexOf(edge.v) >= 0) return true;
if (isDecendant(edge.v, clusterId)) return true;
if (isDecendant(edge.w, clusterId)) return true;
if (decendants[clusterId].indexOf(edge.w) >= 0) return true;
return false;
return (
decendants[clusterId].indexOf(edge.v) >= 0 ||
isDecendant(edge.v, clusterId) ||
isDecendant(edge.w, clusterId) ||
decendants[clusterId].indexOf(edge.w) >= 0
);
};
const copy = (clusterId, graph, newGraph, rootId) => {
@@ -235,7 +241,7 @@ export const adjustClustersAndEdges = (graph, depth) => {
// Check if any edge leaves the cluster (not the actual cluster, that's a link from the box)
if (edge.v !== id && edge.w !== id) {
// Any edge where either the one of the nodes is decending to the cluster but not the other
// Any edge where either the one of the nodes is descending to the cluster but not the other
// if (decendants[id].indexOf(edge.v) < 0 && decendants[id].indexOf(edge.w) < 0) {
const d1 = isDecendant(edge.v, id);
@@ -306,8 +312,12 @@ export const adjustClustersAndEdges = (graph, depth) => {
v = getAnchorId(e.v);
w = getAnchorId(e.w);
graph.removeEdge(e.v, e.w, e.name);
if (v !== e.v) edge.fromCluster = e.v;
if (w !== e.w) edge.toCluster = e.w;
if (v !== e.v) {
edge.fromCluster = e.v;
}
if (w !== e.w) {
edge.toCluster = e.w;
}
log.warn('Fix Replacing with XXX', v, w, e.name);
graph.setEdge(v, w, edge, e.name);
}
@@ -446,7 +456,9 @@ export const extractor = (graph, depth) => {
};
const sorter = (graph, nodes) => {
if (nodes.length === 0) return [];
if (nodes.length === 0) {
return [];
}
let result = Object.assign(nodes);
nodes.forEach((node) => {
const children = graph.children(node);

View File

@@ -291,11 +291,15 @@ const cylinder = (parent, node) => {
(Math.abs(x) == node.width / 2 && Math.abs(pos.y - node.y) > node.height / 2 - ry))
) {
// ellipsis equation: x*x / a*a + y*y / b*b = 1
// solve for y to get adjustion value for pos.y
// solve for y to get adjusted value for pos.y
let y = ry * ry * (1 - (x * x) / (rx * rx));
if (y != 0) y = Math.sqrt(y);
if (y != 0) {
y = Math.sqrt(y);
}
y = ry - y;
if (point.y - node.y > 0) y = -y;
if (point.y - node.y > 0) {
y = -y;
}
pos.y += y;
}

View File

@@ -9,24 +9,26 @@ import { MermaidConfig } from './config.type';
* These are the default options which can be overridden with the initialization call like so:
*
* **Example 1:**
*
* ```js
* mermaid.initialize({ flowchart:{ htmlLabels: false } });
* ```
*
* **Example 2:**
* ```js
* var config = { startOnLoad:true, flowchart:{ useMaxWidth:true,
* htmlLabels:true, curve:'cardinal', },
*
* ```html
* <script>
* var config = {
* startOnLoad:true,
* flowchart:{ useMaxWidth:true, htmlLabels:true, curve:'cardinal'},
* securityLevel:'loose',
*
* }; mermaid.initialize(config);
* };
* mermaid.initialize(config);
* </script>
* ```
*
* A summary of all options and their defaults is found [here](#mermaidapi-configuration-defaults).
* A description of each option follows below.
*
* @name Configuration
*/
const config: Partial<MermaidConfig> = {
/**
@@ -36,8 +38,16 @@ const config: Partial<MermaidConfig> = {
* | --------- | --------------- | ------ | -------- | ---------------------------------------------- |
* | theme | Built in Themes | string | Optional | 'default', 'forest', 'dark', 'neutral', 'null' |
*
* **Notes:** To disable any pre-defined mermaid theme, use "null".<pre> "theme": "forest",
* "themeCSS": ".node rect { fill: red; }" </pre>
* **Notes:** To disable any pre-defined mermaid theme, use "null".
*
* @example
*
* ```js
* {
* "theme": "forest",
* "themeCSS": ".node rect { fill: red; }"
* }
* ```
*/
theme: 'default',
themeVariables: theme['default'].getThemeVariables(),
@@ -125,7 +135,7 @@ const config: Partial<MermaidConfig> = {
/**
* This option controls if the generated ids of nodes in the SVG are generated randomly or based
* on a seed. If set to false, the IDs are generated based on the current date and thus are not
* deterministic. This is the default behaviour.
* deterministic. This is the default behavior.
*
* **Notes**:
*
@@ -640,8 +650,8 @@ const config: Partial<MermaidConfig> = {
/**
* | Parameter | Description | Type | Required | Values |
* | ---------- | --------------------------- | ---- | -------- | ---------------- |
* | axisFormat | Datetime format of the axis | 3 | Required | Date in yy-mm-dd |
* | ---------- | ---------------------------- | ---- | -------- | ---------------- |
* | axisFormat | Date/time format of the axis | 3 | Required | Date in yy-mm-dd |
*
* **Notes:**
*
@@ -1174,7 +1184,7 @@ const config: Partial<MermaidConfig> = {
* | --------------- | ----------- | ------- | -------- | ------------------ |
* | c4BoundaryInRow | See Notes | Integer | Required | Any Positive Value |
*
* **Notes:** How many boundarys to place in each row.
* **Notes:** How many boundaries to place in each row.
*
* Default value: 2
*/
@@ -1839,8 +1849,12 @@ const config: Partial<MermaidConfig> = {
fontSize: 16,
};
if (config.class) config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
if (config.gitGraph) config.gitGraph.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
if (config.class) {
config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
}
if (config.gitGraph) {
config.gitGraph.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
}
const keyify = (obj: any, prefix = ''): string[] =>
Object.keys(obj).reduce((res: string[], el): string[] => {

View File

@@ -9,8 +9,11 @@ const anyComment = /\s*%%.*\n/gm;
const detectors: Record<string, DetectorRecord> = {};
/**
* @function detectType Detects the type of the graph text. Takes into consideration the possible
* existence of an %%init directive
* Detects the type of the graph text.
*
* Takes into consideration the possible existence of an `%%init` directive
*
* @param text - The text defining the graph. For example:
*
* ```mermaid
* %%{initialize: {"startOnLoad": true, logLevel: "fatal" }}%%
@@ -23,13 +26,9 @@ const detectors: Record<string, DetectorRecord> = {};
* f-->g
* g-->h
* ```
* @param {string} text The text defining the graph
* @param {{
* class: { defaultRenderer: string } | undefined;
* state: { defaultRenderer: string } | undefined;
* flowchart: { defaultRenderer: string } | undefined;
* }} [config]
* @returns {string} A graph definition key
*
* @param config - The mermaid config.
* @returns A graph definition key
*/
export const detectType = function (text: string, config?: MermaidConfig): string {
text = text.replace(directive, '').replace(anyComment, '\n');

View File

@@ -7,9 +7,9 @@ import { addStylesForDiagram } from '../styles';
import { DiagramDefinition, DiagramDetector } from './types';
/*
Packaging and exposing resources for externa diagrams so that they can import
diagramAPI and have access to selct parts of mermaid common code reqiored to
create diagrams worling like the internal diagrams.
Packaging and exposing resources for external diagrams so that they can import
diagramAPI and have access to select parts of mermaid common code required to
create diagrams working like the internal diagrams.
*/
export const log = _log;
export const setLogLevel = _setLogLevel;

View File

@@ -49,8 +49,9 @@ export const addRel = function (type, from, to, label, techn, descr, sprite, tag
to === null ||
label === undefined ||
label === null
)
) {
return;
}
let rel = {};
const old = rels.find((rel) => rel.from === from && rel.to === to);
@@ -111,7 +112,9 @@ export const addRel = function (type, from, to, label, techn, descr, sprite, tag
//type, alias, label, ?descr, ?sprite, ?tags, $link
export const addPersonOrSystem = function (typeC4Shape, alias, label, descr, sprite, tags, link) {
// Don't allow label nulling
if (alias === null || label === null) return;
if (alias === null || label === null) {
return;
}
let personOrSystem = {};
const old = c4ShapeArray.find((personOrSystem) => personOrSystem.alias === alias);
@@ -166,7 +169,9 @@ export const addPersonOrSystem = function (typeC4Shape, alias, label, descr, spr
//type, alias, label, ?techn, ?descr ?sprite, ?tags, $link
export const addContainer = function (typeC4Shape, alias, label, techn, descr, sprite, tags, link) {
// Don't allow label nulling
if (alias === null || label === null) return;
if (alias === null || label === null) {
return;
}
let container = {};
const old = c4ShapeArray.find((container) => container.alias === alias);
@@ -232,7 +237,9 @@ export const addContainer = function (typeC4Shape, alias, label, techn, descr, s
//type, alias, label, ?techn, ?descr ?sprite, ?tags, $link
export const addComponent = function (typeC4Shape, alias, label, techn, descr, sprite, tags, link) {
// Don't allow label nulling
if (alias === null || label === null) return;
if (alias === null || label === null) {
return;
}
let component = {};
const old = c4ShapeArray.find((component) => component.alias === alias);
@@ -300,7 +307,9 @@ export const addPersonOrSystemBoundary = function (alias, label, type, tags, lin
// if (parentBoundary === null) return;
// Don't allow label nulling
if (alias === null || label === null) return;
if (alias === null || label === null) {
return;
}
let boundary = {};
const old = boundarys.find((boundary) => boundary.alias === alias);
@@ -354,7 +363,9 @@ export const addContainerBoundary = function (alias, label, type, tags, link) {
// if (parentBoundary === null) return;
// Don't allow label nulling
if (alias === null || label === null) return;
if (alias === null || label === null) {
return;
}
let boundary = {};
const old = boundarys.find((boundary) => boundary.alias === alias);
@@ -417,7 +428,9 @@ export const addDeploymentNode = function (
// if (parentBoundary === null) return;
// Don't allow label nulling
if (alias === null || label === null) return;
if (alias === null || label === null) {
return;
}
let boundary = {};
const old = boundarys.find((boundary) => boundary.alias === alias);
@@ -646,8 +659,12 @@ export const updateLayoutConfig = function (typeC4Shape, c4ShapeInRowParam, c4Bo
c4BoundaryInRowValue = parseInt(c4BoundaryInRowParam);
}
if (c4ShapeInRowValue >= 1) c4ShapeInRow = c4ShapeInRowValue;
if (c4BoundaryInRowValue >= 1) c4BoundaryInRow = c4BoundaryInRowValue;
if (c4ShapeInRowValue >= 1) {
c4ShapeInRow = c4ShapeInRowValue;
}
if (c4BoundaryInRowValue >= 1) {
c4BoundaryInRow = c4BoundaryInRowValue;
}
};
export const getC4ShapeInRow = function () {
@@ -665,11 +682,13 @@ export const getParentBoundaryParse = function () {
};
export const getC4ShapeArray = function (parentBoundary) {
if (parentBoundary === undefined || parentBoundary === null) return c4ShapeArray;
else
if (parentBoundary === undefined || parentBoundary === null) {
return c4ShapeArray;
} else {
return c4ShapeArray.filter((personOrSystem) => {
return personOrSystem.parentBoundary === parentBoundary;
});
}
};
export const getC4Shape = function (alias) {
return c4ShapeArray.find((personOrSystem) => personOrSystem.alias === alias);
@@ -679,8 +698,11 @@ export const getC4ShapeKeys = function (parentBoundary) {
};
export const getBoundarys = function (parentBoundary) {
if (parentBoundary === undefined || parentBoundary === null) return boundarys;
else return boundarys.filter((boundary) => boundary.parentBoundary === parentBoundary);
if (parentBoundary === undefined || parentBoundary === null) {
return boundarys;
} else {
return boundarys.filter((boundary) => boundary.parentBoundary === parentBoundary);
}
};
export const getRels = function () {

View File

@@ -414,7 +414,9 @@ export const drawRels = function (diagram, rels, getC4ShapeObj, diagObj) {
let relTextWrap = rel.wrap && conf.wrap;
let relConf = messageFont(conf);
let diagramType = diagObj.db.getC4Type();
if (diagramType === 'C4Dynamic') rel.label.text = i + ': ' + rel.label.text;
if (diagramType === 'C4Dynamic') {
rel.label.text = i + ': ' + rel.label.text;
}
let textLimitWidth = calculateTextWidth(rel.label.text, relConf);
calcC4ShapeTextWH('label', rel, relTextWrap, relConf, textLimitWidth);
@@ -441,20 +443,26 @@ export const drawRels = function (diagram, rels, getC4ShapeObj, diagObj) {
* @param diagram
* @param parentBoundaryAlias
* @param parentBounds
* @param currentBoundarys
* @param currentBoundaries
* @param diagObj
*/
function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentBoundarys, diagObj) {
function drawInsideBoundary(
diagram,
parentBoundaryAlias,
parentBounds,
currentBoundaries,
diagObj
) {
let currentBounds = new Bounds(diagObj);
// Calculate the width limit of the boundar. label/type 的长度,
// Calculate the width limit of the boundary. label/type 的长度,
currentBounds.data.widthLimit =
parentBounds.data.widthLimit / Math.min(c4BoundaryInRow, currentBoundarys.length);
parentBounds.data.widthLimit / Math.min(c4BoundaryInRow, currentBoundaries.length);
// Math.min(
// conf.width * conf.c4ShapeInRow + conf.c4ShapeMargin * conf.c4ShapeInRow * 2,
// parentBounds.data.widthLimit / Math.min(conf.c4BoundaryInRow, currentBoundarys.length)
// parentBounds.data.widthLimit / Math.min(conf.c4BoundaryInRow, currentBoundaries.length)
// );
for (let i = 0; i < currentBoundarys.length; i++) {
let currentBoundary = currentBoundarys[i];
for (let i = 0; i < currentBoundaries.length; i++) {
let currentBoundary = currentBoundaries[i];
let Y = 0;
currentBoundary.image = { width: 0, height: 0, Y: 0 };
if (currentBoundary.sprite) {
@@ -508,13 +516,13 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
}
if (i == 0 || i % c4BoundaryInRow === 0) {
// Calculate the drawing start point of the currentBoundarys.
// Calculate the drawing start point of the currentBoundaries.
let _x = parentBounds.data.startx + conf.diagramMarginX;
let _y = parentBounds.data.stopy + conf.diagramMarginY + Y;
currentBounds.setData(_x, _x, _y, _y);
} else {
// Calculate the drawing start point of the currentBoundarys.
// Calculate the drawing start point of the currentBoundaries.
let _x =
currentBounds.data.stopx !== currentBounds.data.startx
? currentBounds.data.stopx + conf.diagramMarginX
@@ -540,8 +548,6 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
if (nextCurrentBoundarys.length > 0) {
// draw boundary inside currentBoundary
// bounds.init();
// parentBoundaryWidthLimit = bounds.data.stopx - bounds.startx;
drawInsideBoundary(
diagram,
parentBoundaryAlias,
@@ -551,7 +557,9 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
);
}
// draw boundary
if (currentBoundary.alias !== 'global') drawBoundary(diagram, currentBoundary, currentBounds);
if (currentBoundary.alias !== 'global') {
drawBoundary(diagram, currentBoundary, currentBounds);
}
parentBounds.data.stopy = Math.max(
currentBounds.data.stopy + conf.c4ShapeMargin,
parentBounds.data.stopy
@@ -576,7 +584,7 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
export const draw = function (_text, id, _version, diagObj) {
conf = configApi.getConfig().c4;
const securityLevel = configApi.getConfig().securityLevel;
// Handle root and Document for when rendering in sanbox mode
// Handle root and Document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
@@ -616,10 +624,10 @@ export const draw = function (_text, id, _version, diagObj) {
globalBoundaryMaxY = conf.diagramMarginY;
const title = diagObj.db.getTitle();
let currentBoundarys = diagObj.db.getBoundarys('');
let currentBoundaries = diagObj.db.getBoundarys('');
// switch (c4type) {
// case 'C4Context':
drawInsideBoundary(diagram, '', screenBounds, currentBoundarys, diagObj);
drawInsideBoundary(diagram, '', screenBounds, currentBoundaries, diagObj);
// break;
// }

View File

@@ -13,7 +13,9 @@ export const drawRect = function (elem, rectData) {
rectElem.attr('ry', rectData.ry);
if (rectData.attrs !== 'undefined' && rectData.attrs !== null) {
for (let attrKey in rectData.attrs) rectElem.attr(attrKey, rectData.attrs[attrKey]);
for (let attrKey in rectData.attrs) {
rectElem.attr(attrKey, rectData.attrs[attrKey]);
}
}
if (rectData.class !== 'undefined') {
@@ -231,9 +233,12 @@ export const drawRels = (elem, rels, conf) => {
line.attr('stroke-width', '1');
line.attr('stroke', strokeColor);
line.style('fill', 'none');
if (rel.type !== 'rel_b') line.attr('marker-end', 'url(' + url + '#arrowhead)');
if (rel.type === 'birel' || rel.type === 'rel_b')
if (rel.type !== 'rel_b') {
line.attr('marker-end', 'url(' + url + '#arrowhead)');
}
if (rel.type === 'birel' || rel.type === 'rel_b') {
line.attr('marker-start', 'url(' + url + '#arrowend)');
}
i = -1;
} else {
let line = relsElem.append('path');
@@ -256,10 +261,13 @@ export const drawRels = (elem, rels, conf) => {
.replaceAll('stopx', rel.endPoint.x)
.replaceAll('stopy', rel.endPoint.y)
);
if (rel.type !== 'rel_b') line.attr('marker-end', 'url(' + url + '#arrowhead)');
if (rel.type === 'birel' || rel.type === 'rel_b')
if (rel.type !== 'rel_b') {
line.attr('marker-end', 'url(' + url + '#arrowhead)');
}
if (rel.type === 'birel' || rel.type === 'rel_b') {
line.attr('marker-start', 'url(' + url + '#arrowend)');
}
}
let messageConf = conf.messageFont();
_drawTextCandidateFunc(conf)(
@@ -314,7 +322,9 @@ const drawBoundary = function (elem, boundary, conf) {
let fontColor = boundary.fontColor ? boundary.fontColor : 'black';
let attrsValue = { 'stroke-width': 1.0, 'stroke-dasharray': '7.0,7.0' };
if (boundary.nodeType) attrsValue = { 'stroke-width': 1.0 };
if (boundary.nodeType) {
attrsValue = { 'stroke-width': 1.0 };
}
let rectData = {
x: boundary.x,
y: boundary.y,

View File

@@ -16,6 +16,7 @@ const MERMAID_DOM_ID_PREFIX = 'classid-';
let relations = [];
let classes = {};
let notes = [];
let classCounter = 0;
let funs = [];
@@ -49,7 +50,9 @@ const splitClassNameAndType = function (id) {
export const addClass = function (id) {
let classId = splitClassNameAndType(id);
// Only add class if not exists
if (typeof classes[classId.className] !== 'undefined') return;
if (typeof classes[classId.className] !== 'undefined') {
return;
}
classes[classId.className] = {
id: classId.className,
@@ -82,6 +85,7 @@ export const lookUpDomId = function (id) {
export const clear = function () {
relations = [];
classes = {};
notes = [];
funs = [];
funs.push(setupToolTips);
commonClear();
@@ -98,6 +102,10 @@ export const getRelations = function () {
return relations;
};
export const getNotes = function () {
return notes;
};
export const addRelation = function (relation) {
log.debug('Adding relation: ' + JSON.stringify(relation));
addClass(relation.id1);
@@ -168,6 +176,15 @@ export const addMembers = function (className, members) {
}
};
export const addNote = function (text, className) {
const note = {
id: `note${notes.length}`,
class: className,
text: text,
};
notes.push(note);
};
export const cleanupLabel = function (label) {
if (label.substring(0, 1) === ':') {
return common.sanitizeText(label.substr(1).trim(), configApi.getConfig());
@@ -185,7 +202,9 @@ export const cleanupLabel = function (label) {
export const setCssClass = function (ids, className) {
ids.split(',').forEach(function (_id) {
let id = _id;
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
if (_id[0].match(/\d/)) {
id = MERMAID_DOM_ID_PREFIX + id;
}
if (typeof classes[id] !== 'undefined') {
classes[id].cssClasses.push(className);
}
@@ -220,7 +239,9 @@ export const setLink = function (ids, linkStr, target) {
const config = configApi.getConfig();
ids.split(',').forEach(function (_id) {
let id = _id;
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
if (_id[0].match(/\d/)) {
id = MERMAID_DOM_ID_PREFIX + id;
}
if (typeof classes[id] !== 'undefined') {
classes[id].link = utils.formatUrl(linkStr, config);
if (config.securityLevel === 'sandbox') {
@@ -369,7 +390,9 @@ export default {
clear,
getClass,
getClasses,
getNotes,
addAnnotation,
addNote,
getRelations,
addRelation,
getDirection,

View File

@@ -1,9 +1,13 @@
import type { DiagramDetector } from '../../diagram-api/types';
export const classDetectorV2: DiagramDetector = (txt, config) => {
// If we have confgured to use dagre-wrapper then we should return true in this function for classDiagram code thus making it use the new class diagram
if (txt.match(/^\s*classDiagram/) !== null && config?.class?.defaultRenderer === 'dagre-wrapper')
// 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 &&
config?.class?.defaultRenderer === 'dagre-wrapper'
) {
return true;
}
// 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;
};

View File

@@ -1,8 +1,10 @@
import type { DiagramDetector } from '../../diagram-api/types';
export const classDetector: DiagramDetector = (txt, config) => {
// If we have confgured to use dagre-wrapper then we should never return true in this function
if (config?.class?.defaultRenderer === 'dagre-wrapper') return false;
// 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;
}
// 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;
};

View File

@@ -529,6 +529,16 @@ foo()
parser.parse(str);
});
it('should handle "note for"', function () {
const str = 'classDiagram\n' + 'Class11 <|.. Class12\n' + 'note for Class11 "test"\n';
parser.parse(str);
});
it('should handle "note"', function () {
const str = 'classDiagram\n' + 'note "test"\n';
parser.parse(str);
});
});
describe('when fetching data from a classDiagram graph it', function () {

View File

@@ -64,6 +64,7 @@ export const addClasses = function (classes, g, _id, diagObj) {
// if (evaluate(getConfig().flowchart.htmlLabels)) {
// const node = {
// label: vertexText.replace(
// eslint-disable-next-line @cspell/spellchecker
// /fa[lrsb]?:fa-[\w-]+/g,
// s => `<i class='${s.replace(':', ' ')}'></i>`
// )
@@ -133,6 +134,99 @@ export const addClasses = function (classes, g, _id, diagObj) {
});
};
/**
* Function that adds the additional vertices (notes) found during parsing to the graph to be rendered.
*
* @param {{text: string; class: string; placement: number}[]} notes
* Object containing the additional vertices (notes).
* @param {SVGGElement} g The graph that is to be drawn.
* @param {number} startEdgeId starting index for note edge
* @param classes
*/
export const addNotes = function (notes, g, startEdgeId, classes) {
log.info(notes);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
notes.forEach(function (note, i) {
const vertex = note;
/**
* Variable for storing the classes for the vertex
*
* @type {string}
*/
let cssNoteStr = '';
const styles = { labelStyle: '', style: '' };
// Use vertex id as text in the box if no text is provided by the graph definition
let vertexText = vertex.text;
let radious = 0;
let _shape = 'note';
// Add the node
g.setNode(vertex.id, {
labelStyle: styles.labelStyle,
shape: _shape,
labelText: sanitizeText(vertexText),
noteData: vertex,
rx: radious,
ry: radious,
class: cssNoteStr,
style: styles.style,
id: vertex.id,
domId: vertex.id,
tooltip: '',
type: 'note',
padding: getConfig().flowchart.padding,
});
log.info('setNode', {
labelStyle: styles.labelStyle,
shape: _shape,
labelText: vertexText,
rx: radious,
ry: radious,
style: styles.style,
id: vertex.id,
type: 'note',
padding: getConfig().flowchart.padding,
});
if (!vertex.class || !(vertex.class in classes)) {
return;
}
const edgeId = startEdgeId + i;
const edgeData = {};
//Set relationship style and line type
edgeData.classes = 'relation';
edgeData.pattern = 'dotted';
edgeData.id = `edgeNote${edgeId}`;
// Set link type for rendering
edgeData.arrowhead = 'none';
log.info(`Note edge: ${JSON.stringify(edgeData)}, ${JSON.stringify(vertex)}`);
//Set edge extra labels
edgeData.startLabelRight = '';
edgeData.endLabelLeft = '';
//Set relation arrow types
edgeData.arrowTypeStart = 'none';
edgeData.arrowTypeEnd = 'none';
let style = 'fill:none';
let labelStyle = '';
edgeData.style = style;
edgeData.labelStyle = labelStyle;
edgeData.curve = interpolateToCurve(conf.curve, curveLinear);
// Add the edge to the graph
g.setEdge(vertex.id, vertex.class, edgeData, edgeId);
});
};
/**
* Add edges to graph based on parsed graph definition
*
@@ -304,10 +398,12 @@ export const draw = function (text, id, _version, diagObj) {
// Fetch the vertices/nodes and edges/links from the parsed graph definition
const classes = diagObj.db.getClasses();
const relations = diagObj.db.getRelations();
const notes = diagObj.db.getNotes();
log.info(relations);
addClasses(classes, g, id, diagObj);
addRelations(relations, g);
addNotes(notes, g, relations.length + 1, classes);
// Add custom shapes
// flowChartShapes.addToRenderV2(addShape);

View File

@@ -148,7 +148,7 @@ export const draw = function (text, id, _version, diagObj) {
log.info('Rendering diagram ' + text);
const securityLevel = getConfig().securityLevel;
// Handle root and Document for when rendering in sanbox mode
// Handle root and Document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
@@ -208,12 +208,42 @@ export const draw = function (text, id, _version, diagObj) {
);
});
const notes = diagObj.db.getNotes();
notes.forEach(function (note) {
log.debug(`Adding note: ${JSON.stringify(note)}`);
const node = svgDraw.drawNote(diagram, note, conf, diagObj);
idCache[node.id] = node;
// Add nodes to the graph. The first argument is the node id. The second is
// metadata about the node. In this case we're going to add labels to each of
// our nodes.
g.setNode(node.id, node);
if (note.class && note.class in classes) {
g.setEdge(
note.id,
getGraphId(note.class),
{
relation: {
id1: note.id,
id2: note.class,
relation: {
type1: 'none',
type2: 'none',
lineType: 10,
},
},
},
'DEFAULT'
);
}
});
dagre.layout(g);
g.nodes().forEach(function (v) {
if (typeof v !== 'undefined' && typeof g.node(v) !== 'undefined') {
log.debug('Node ' + v + ': ' + JSON.stringify(g.node(v)));
root
.select('#' + diagObj.db.lookUpDomId(v))
.select('#' + (diagObj.db.lookUpDomId(v) || v))
.attr(
'transform',
'translate(' +

View File

@@ -56,6 +56,8 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
"callback" return 'CALLBACK';
"link" return 'LINK';
"click" return 'CLICK';
"note for" return 'NOTE_FOR';
"note" return 'NOTE';
"<<" return 'ANNOTATION_START';
">>" return 'ANNOTATION_END';
[~] this.begin("generic");
@@ -263,6 +265,7 @@ statement
| annotationStatement
| clickStatement
| cssClassStatement
| noteStatement
| directive
| direction
| acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); }
@@ -300,6 +303,11 @@ relationStatement
| className STR relation STR className { $$ = {id1:$1, id2:$5, relation:$3, relationTitle1:$2, relationTitle2:$4} }
;
noteStatement
: NOTE_FOR className noteText { yy.addNote($3, $2); }
| NOTE noteText { yy.addNote($2); }
;
relation
: relationType lineType relationType { $$={type1:$1,type2:$3,lineType:$2}; }
| lineType relationType { $$={type1:'none',type2:$2,lineType:$1}; }
@@ -351,4 +359,6 @@ alphaNumToken : UNICODE_TEXT | NUM | ALPHA;
classLiteralName : BQUOTE_STR;
noteText : STR;
%%

View File

@@ -80,6 +80,10 @@ g.classGroup line {
stroke-dasharray: 3;
}
.dotted-line{
stroke-dasharray: 1 2;
}
#compositionStart, .composition {
fill: ${options.lineColor} !important;
stroke: ${options.lineColor} !important;

View File

@@ -9,13 +9,13 @@ export const drawEdge = function (elem, path, relation, conf, diagObj) {
switch (type) {
case diagObj.db.relationType.AGGREGATION:
return 'aggregation';
case diagObj.db.EXTENSION:
case diagObj.db.relationType.EXTENSION:
return 'extension';
case diagObj.db.COMPOSITION:
case diagObj.db.relationType.COMPOSITION:
return 'composition';
case diagObj.db.DEPENDENCY:
case diagObj.db.relationType.DEPENDENCY:
return 'dependency';
case diagObj.db.LOLLIPOP:
case diagObj.db.relationType.LOLLIPOP:
return 'lollipop';
}
};
@@ -55,6 +55,9 @@ export const drawEdge = function (elem, path, relation, conf, diagObj) {
if (relation.relation.lineType == 1) {
svgPath.attr('class', 'relation dashed-line');
}
if (relation.relation.lineType == 10) {
svgPath.attr('class', 'relation dotted-line');
}
if (relation.relation.type1 !== 'none') {
svgPath.attr(
'marker-start',
@@ -190,7 +193,9 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
let isFirst = true;
classDef.annotations.forEach(function (member) {
const titleText2 = title.append('tspan').text('«' + member + '»');
if (!isFirst) titleText2.attr('dy', conf.textHeight);
if (!isFirst) {
titleText2.attr('dy', conf.textHeight);
}
isFirst = false;
});
@@ -203,7 +208,9 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
const classTitle = title.append('tspan').text(classTitleString).attr('class', 'title');
// If class has annotations the title needs to have an offset of the text height
if (!isFirst) classTitle.attr('dy', conf.textHeight);
if (!isFirst) {
classTitle.attr('dy', conf.textHeight);
}
const titleHeight = title.node().getBBox().height;
@@ -284,6 +291,69 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
return classInfo;
};
/**
* Renders a note diagram
*
* @param {SVGSVGElement} elem The element to draw it into
* @param {{id: string; text: string; class: string;}} note
* @param conf
* @param diagObj
* @todo Add more information in the JSDOC here
*/
export const drawNote = function (elem, note, conf, diagObj) {
log.debug('Rendering note ', note, conf);
const id = note.id;
const noteInfo = {
id: id,
text: note.text,
width: 0,
height: 0,
};
// add class group
const g = elem.append('g').attr('id', id).attr('class', 'classGroup');
// add text
let text = g
.append('text')
.attr('y', conf.textHeight + conf.padding)
.attr('x', 0);
const lines = JSON.parse(`"${note.text}"`).split('\n');
lines.forEach(function (line) {
log.debug(`Adding line: ${line}`);
text.append('tspan').text(line).attr('class', 'title').attr('dy', conf.textHeight);
});
const noteBox = g.node().getBBox();
const rect = g
.insert('rect', ':first-child')
.attr('x', 0)
.attr('y', 0)
.attr('width', noteBox.width + 2 * conf.padding)
.attr(
'height',
noteBox.height + lines.length * conf.textHeight + conf.padding + 0.5 * conf.dividerMargin
);
const rectWidth = rect.node().getBBox().width;
// Center title
// We subtract the width of each text element from the class box width and divide it by 2
text.node().childNodes.forEach(function (x) {
x.setAttribute('x', (rectWidth - x.getBBox().width) / 2);
});
noteInfo.width = rectWidth;
noteInfo.height =
noteBox.height + lines.length * conf.textHeight + conf.padding + 0.5 * conf.dividerMargin;
return noteInfo;
};
export const parseMember = function (text) {
const fieldRegEx = /^(\+|-|~|#)?(\w+)(~\w+~|\[\])?\s+(\w+) *(\*|\$)?$/;
const methodRegEx = /^([+|\-|~|#])?(\w+) *\( *(.*)\) *(\*|\$)? *(\w*[~|[\]]*\s*\w*~?)$/;
@@ -347,7 +417,7 @@ const buildMethodDisplay = function (parsedText) {
};
const buildLegacyDisplay = function (text) {
// if for some reason we dont have any match, use old format to parse text
// if for some reason we don't have any match, use old format to parse text
let displayText = '';
let cssStyle = '';
let memberText = '';
@@ -435,5 +505,6 @@ const parseClassifier = function (classifier) {
export default {
drawClass,
drawEdge,
drawNote,
parseMember,
};

View File

@@ -4,11 +4,13 @@ import { MermaidConfig } from '../../config.type';
/**
* Gets the rows of lines in a string
*
* @param {string | undefined} s The string to check the lines for
* @returns {string[]} The rows in that string
* @param s - The string to check the lines for
* @returns The rows in that string
*/
export const getRows = (s?: string): string[] => {
if (!s) return [''];
if (!s) {
return [''];
}
const str = breakToPlaceholder(s).replace(/\\n/g, '#br#');
return str.split('#br#');
};
@@ -16,8 +18,8 @@ export const getRows = (s?: string): string[] => {
/**
* Removes script tags from a text
*
* @param {string} txt The text to sanitize
* @returns {string} The safer text
* @param txt - The text to sanitize
* @returns The safer text
*/
export const removeScript = (txt: string): string => {
return DOMPurify.sanitize(txt);
@@ -39,7 +41,9 @@ const sanitizeMore = (text: string, config: MermaidConfig) => {
};
export const sanitizeText = (text: string, config: MermaidConfig): string => {
if (!text) return text;
if (!text) {
return text;
}
if (config.dompurifyConfig) {
text = DOMPurify.sanitize(sanitizeMore(text, config), config.dompurifyConfig).toString();
} else {
@@ -52,7 +56,9 @@ export const sanitizeTextOrArray = (
a: string | string[] | string[][],
config: MermaidConfig
): string | string[] => {
if (typeof a === 'string') return sanitizeText(a, config);
if (typeof a === 'string') {
return sanitizeText(a, config);
}
// TODO: Refactor to avoid flat.
return a.flat().map((x: string) => sanitizeText(x, config));
};
@@ -62,8 +68,8 @@ export const lineBreakRegex = /<br\s*\/?>/gi;
/**
* Whether or not a text has any line breaks
*
* @param {string} text The text to test
* @returns {boolean} Whether or not the text has breaks
* @param text - The text to test
* @returns Whether or not the text has breaks
*/
export const hasBreaks = (text: string): boolean => {
return lineBreakRegex.test(text);
@@ -72,8 +78,8 @@ export const hasBreaks = (text: string): boolean => {
/**
* Splits on <br> tags
*
* @param {string} text Text to split
* @returns {string[]} List of lines as strings
* @param text - Text to split
* @returns List of lines as strings
*/
export const splitBreaks = (text: string): string[] => {
return text.split(lineBreakRegex);
@@ -82,8 +88,8 @@ export const splitBreaks = (text: string): string[] => {
/**
* Converts placeholders to line breaks in HTML
*
* @param {string} s HTML with placeholders
* @returns {string} HTML with breaks instead of placeholders
* @param s - HTML with placeholders
* @returns HTML with breaks instead of placeholders
*/
const placeholderToBreak = (s: string): string => {
return s.replace(/#br#/g, '<br/>');
@@ -92,8 +98,8 @@ const placeholderToBreak = (s: string): string => {
/**
* Opposite of `placeholderToBreak`, converts breaks to placeholders
*
* @param {string} s HTML string
* @returns {string} String with placeholders
* @param s - HTML string
* @returns String with placeholders
*/
const breakToPlaceholder = (s: string): string => {
return s.replace(lineBreakRegex, '#br#');
@@ -102,8 +108,8 @@ const breakToPlaceholder = (s: string): string => {
/**
* Gets the current URL
*
* @param {boolean} useAbsolute Whether to return the absolute URL or not
* @returns {string} The current URL
* @param useAbsolute - Whether to return the absolute URL or not
* @returns The current URL
*/
const getUrl = (useAbsolute: boolean): string => {
let url = '';
@@ -124,8 +130,8 @@ const getUrl = (useAbsolute: boolean): string => {
/**
* Converts a string/boolean into a boolean
*
* @param {string | boolean} val String or boolean to convert
* @returns {boolean} The result from the input
* @param val - String or boolean to convert
* @returns The result from the input
*/
export const evaluate = (val?: string | boolean): boolean =>
val === false || ['false', 'null', '0'].includes(String(val).trim().toLowerCase()) ? false : true;
@@ -133,12 +139,15 @@ export const evaluate = (val?: string | boolean): boolean =>
/**
* Makes generics in typescript syntax
*
* @example <caption>Array of array of strings in typescript syntax</caption>
* @example
* Array of array of strings in typescript syntax
*
* ```js
* // returns "Array<Array<string>>"
* parseGenericTypes('Array~Array~string~~');
*
* @param {string} text The text to convert
* @returns {string} The converted string
* ```
* @param text - The text to convert
* @returns The converted string
*/
export const parseGenericTypes = function (text: string): string {
let cleanedText = text;

View File

@@ -357,7 +357,7 @@ const drawEntities = function (svgNode, entities, graph) {
const rectNode = groupNode
.insert('rect', '#' + textId)
.attr('class', 'er entityBox')
.attr('fill', conf.fill)
.style('fill', conf.fill)
.attr('fill-opacity', '100%')
.attr('stroke', conf.stroke)
.attr('x', 0)
@@ -644,7 +644,7 @@ export const draw = function (text, id, _version, diagObj) {
// inserted - this represents the insertion point for relationship paths
const firstEntity = drawEntities(svg, diagObj.db.getEntities(), g);
// TODO: externalise the addition of entities to the graph - it's a bit 'buried' in the above
// TODO: externalize the addition of entities to the graph - it's a bit 'buried' in the above
// Add all the relationships to the graph
const relationships = addRelationships(diagObj.db.getRelationships(), g);

View File

@@ -36,15 +36,32 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
<block>[\n]+ /* nothing */
<block>"}" { this.popState(); return 'BLOCK_STOP'; }
<block>. return yytext[0];
"one or zero" return 'ZERO_OR_ONE';
"one or more" return 'ONE_OR_MORE';
"one or many" return 'ONE_OR_MORE';
"1+" return 'ONE_OR_MORE';
\|o return 'ZERO_OR_ONE';
"zero or one" return 'ZERO_OR_ONE';
"zero or more" return 'ZERO_OR_MORE';
"zero or many" return 'ZERO_OR_MORE';
"0+" return 'ZERO_OR_MORE';
\}o return 'ZERO_OR_MORE';
"many(0)" return 'ZERO_OR_MORE';
"many(1)" return 'ONE_OR_MORE';
"many" return 'ZERO_OR_MORE';
\}\| return 'ONE_OR_MORE';
"one" return 'ONLY_ONE';
"only one" return 'ONLY_ONE';
"1" return 'ONLY_ONE';
\|\| return 'ONLY_ONE';
o\| return 'ZERO_OR_ONE';
o\{ return 'ZERO_OR_MORE';
\|\{ return 'ONE_OR_MORE';
\.\. return 'NON_IDENTIFYING';
\-\- return 'IDENTIFYING';
"to" return 'IDENTIFYING';
"optionally to" return 'NON_IDENTIFYING';
\.\- return 'NON_IDENTIFYING';
\-\. return 'NON_IDENTIFYING';
[A-Za-z][A-Za-z0-9\-_]* return 'ALPHANUM';

View File

@@ -532,18 +532,100 @@ describe('when parsing ER diagram it...', function () {
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONE_OR_MORE);
});
it('should handle zero-or-one-to-zero-or-more relationships (aliases "one or zero" and "zero or many")', function () {
erDiagram.parser.parse('erDiagram\nA one or zero to many B : has');
const rels = erDb.getRelationships();
expect(Object.keys(erDb.getEntities()).length).toBe(2);
expect(rels.length).toBe(1);
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_MORE);
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_ONE);
});
it('should handle one-or-more-to-zero-or-one relationships (aliases "one or many" and "zero or one")', function () {
erDiagram.parser.parse('erDiagram\nA one or many optionally to zero or one B : has');
const rels = erDb.getRelationships();
expect(Object.keys(erDb.getEntities()).length).toBe(2);
expect(rels.length).toBe(1);
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_ONE);
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONE_OR_MORE);
});
it('should handle zero-or-more-to-zero-or-more relationships (aliases "zero or more" and "zero or many")', function () {
erDiagram.parser.parse('erDiagram\nA zero or more to zero or many B : has');
const rels = erDb.getRelationships();
expect(Object.keys(erDb.getEntities()).length).toBe(2);
expect(rels.length).toBe(1);
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_MORE);
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_MORE);
});
it('should handle zero-or-more-to-one-or-more relationships (aliases "many(0)" and "many(1)")', function () {
erDiagram.parser.parse('erDiagram\nA many(0) to many(1) B : has');
const rels = erDb.getRelationships();
expect(Object.keys(erDb.getEntities()).length).toBe(2);
expect(rels.length).toBe(1);
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONE_OR_MORE);
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_MORE);
});
it('should handle zero-or-more-to-only-one relationships (aliases "many(0)" and "many(1)")', function () {
erDiagram.parser.parse('erDiagram\nA many optionally to one B : has');
const rels = erDb.getRelationships();
expect(Object.keys(erDb.getEntities()).length).toBe(2);
expect(rels.length).toBe(1);
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONLY_ONE);
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_MORE);
});
it('should handle only-one-to-only-one relationships (aliases "only one" and "1+")', function () {
erDiagram.parser.parse('erDiagram\nA only one optionally to 1+ B : has');
const rels = erDb.getRelationships();
expect(Object.keys(erDb.getEntities()).length).toBe(2);
expect(rels.length).toBe(1);
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONE_OR_MORE);
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONLY_ONE);
});
it('should handle zero-or-more-to-only-one relationships (aliases "0+" and "1")', function () {
erDiagram.parser.parse('erDiagram\nA 0+ optionally to 1 B : has');
const rels = erDb.getRelationships();
expect(Object.keys(erDb.getEntities()).length).toBe(2);
expect(rels.length).toBe(1);
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONLY_ONE);
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_MORE);
});
it('should represent identifying relationships properly', function () {
erDiagram.parser.parse('erDiagram\nHOUSE ||--|{ ROOM : contains');
const rels = erDb.getRelationships();
expect(rels[0].relSpec.relType).toBe(erDb.Identification.IDENTIFYING);
});
it('should represent identifying relationships properly (alias "to")', function () {
erDiagram.parser.parse('erDiagram\nHOUSE one to one ROOM : contains');
const rels = erDb.getRelationships();
expect(rels[0].relSpec.relType).toBe(erDb.Identification.IDENTIFYING);
});
it('should represent non-identifying relationships properly', function () {
erDiagram.parser.parse('erDiagram\n PERSON ||..o{ POSSESSION : owns');
const rels = erDb.getRelationships();
expect(rels[0].relSpec.relType).toBe(erDb.Identification.NON_IDENTIFYING);
});
it('should represent non-identifying relationships properly (alias "optionally to")', function () {
erDiagram.parser.parse('erDiagram\n PERSON many optionally to many POSSESSION : owns');
const rels = erDb.getRelationships();
expect(rels[0].relSpec.relType).toBe(erDb.Identification.NON_IDENTIFYING);
});
it('should not accept a syntax error', function () {
const doc = 'erDiagram\nA xxx B : has';
expect(() => {

View File

@@ -8,7 +8,7 @@ let conf = {};
/**
* Merges the value of `conf` with the passed `cnf`
*
* @param {object} cnf Config to merge
* @param cnf - Config to merge
*/
export const setConf = function (cnf: any) {
conf = { ...conf, ...cnf };
@@ -17,11 +17,11 @@ export const setConf = function (cnf: any) {
/**
* Draws a an info picture in the tag with id: id based on the graph definition in text.
*
* @param text
* @param {string} id The text for the error
* @param {string} mermaidVersion The version
* @param _text - Mermaid graph definition.
* @param id - The text for the error
* @param mermaidVersion - The version
*/
export const draw = (text: string, id: string, mermaidVersion: string) => {
export const draw = (_text: string, id: string, mermaidVersion: string) => {
try {
log.debug('Renering svg for syntax error\n');

View File

@@ -279,11 +279,15 @@ function cylinder(parent, bbox, node) {
(Math.abs(x) == node.width / 2 && Math.abs(pos.y - node.y) > node.height / 2 - ry))
) {
// ellipsis equation: x*x / a*a + y*y / b*b = 1
// solve for y to get adjustion value for pos.y
// solve for y to get adjusted value for pos.y
let y = ry * ry * (1 - (x * x) / (rx * rx));
if (y != 0) y = Math.sqrt(y);
if (y != 0) {
y = Math.sqrt(y);
}
y = ry - y;
if (point.y - node.y > 0) y = -y;
if (point.y - node.y > 0) {
y = -y;
}
pos.y += y;
}

View File

@@ -119,7 +119,11 @@ export const addVertex = function (_id, text, type, style, classes, dir, props =
if (typeof dir !== 'undefined') {
vertices[id].dir = dir;
}
if (typeof vertices[id].props === 'undefined') {
vertices[id].props = props;
} else if (typeof props !== 'undefined') {
Object.assign(vertices[id].props, props);
}
};
/**
@@ -699,7 +703,9 @@ const destructLink = (_str, _startStr) => {
startInfo.type = info.type;
} else {
// x-- xyz --> - not supported
if (startInfo.type !== info.type) return { type: 'INVALID', stroke: 'INVALID' };
if (startInfo.type !== info.type) {
return { type: 'INVALID', stroke: 'INVALID' };
}
startInfo.type = 'double_' + startInfo.type;
}

View File

@@ -1,8 +1,9 @@
import type { DiagramDetector } from '../../diagram-api/types';
export const flowDetectorV2: DiagramDetector = (txt, config) => {
// If we have confgured to use dagre-wrapper then we should return true in this function for graph code thus making it use the new flowchart diagram
if (config?.flowchart?.defaultRenderer === 'dagre-wrapper' && txt.match(/^\s*graph/) !== null)
// If we have configured to use dagre-wrapper then we should return true in this function for graph code thus making it use the new flowchart diagram
if (config?.flowchart?.defaultRenderer === 'dagre-wrapper' && txt.match(/^\s*graph/) !== null) {
return true;
}
return txt.match(/^\s*flowchart/) !== null;
};

View File

@@ -1,8 +1,10 @@
import type { DiagramDetector } from '../../diagram-api/types';
export const flowDetector: DiagramDetector = (txt, config) => {
// If we have confired to only use new flow charts this function shohuld always return false
// If we have 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') return false;
if (config?.flowchart?.defaultRenderer === 'dagre-wrapper') {
return false;
}
return txt.match(/^\s*graph/) !== null;
};

View File

@@ -2,11 +2,7 @@ import flowDb from '../flowDb';
import flow from './flow';
import filter from 'lodash/filter';
import { setConfig } from '../../../config';
// import DOMPurify from 'dompurify';
// const domPurify = DOMPurify.createDOMPurify(window);
// const clean = DOMPurify.sanitize(dirty);
setConfig({
securityLevel: 'strict',
});

View File

@@ -153,7 +153,9 @@ export const isInvalidDate = function (date, dateFormat, excludes, includes) {
};
const checkTaskDates = function (task, dateFormat, excludes, includes) {
if (!excludes.length || task.manualEndTime) return;
if (!excludes.length || task.manualEndTime) {
return;
}
let startTime = moment(task.startTime, dateFormat, true);
startTime.add(1, 'd');
let endTime = moment(task.endTime, dateFormat, true);
@@ -229,7 +231,7 @@ const getStartDate = function (prevTime, dateFormat, str) {
* Parse a string as a moment duration.
*
* The string have to be compound by a value and a shorthand duration unit. For example `5d`
* representes 5 days.
* represents 5 days.
*
* Shorthand unit supported are:
*

View File

@@ -27,7 +27,7 @@ export const draw = function (text, id, version, diagObj) {
// parser.parse(text);
const securityLevel = getConfig().securityLevel;
// Handle root and Document for when rendering in sanbox mode
// Handle root and Document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
@@ -427,7 +427,9 @@ export const draw = function (text, id, version, diagObj) {
);
const maxTime = tasks.reduce((max, { endTime }) => (max ? Math.max(max, endTime) : endTime), 0);
const dateFormat = diagObj.db.getDateFormat();
if (!minTime || !maxTime) return;
if (!minTime || !maxTime) {
return;
}
const excludeRanges = [];
let range = null;
@@ -552,7 +554,9 @@ export const draw = function (text, id, version, diagObj) {
const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
tspan.setAttribute('alignment-baseline', 'central');
tspan.setAttribute('x', '10');
if (j > 0) tspan.setAttribute('dy', '1em');
if (j > 0) {
tspan.setAttribute('dy', '1em');
}
tspan.textContent = rows[j];
svgLabel.appendChild(tspan);
}

View File

@@ -65,17 +65,6 @@ describe('when parsing a gantt diagram it', function () {
expect(parserFnConstructor(str)).not.toThrow();
});
/**
* Beslutsflöde inligt nedan. Obs bla bla bla
*
* graph TD
* A[Hard pledge] -- text on link -->B(Round edge)
* B --> C{to do or not to do}
* C -->|Too| D[Result one]
* C -->|Doo| E[Result two]
*
* Params bapa - a unique bapap
*/
it('should handle a task definition', function () {
const str =
'gantt\n' +

View File

@@ -39,6 +39,7 @@ export const parseDirective = function (statement, context, type) {
// * @param currentCommit
// * @param otherCommit
// */
// eslint-disable-next-line @cspell/spellchecker
// function isfastforwardable(currentCommit, otherCommit) {
// log.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id);
// let cnt = 0;
@@ -384,21 +385,23 @@ export const checkout = function (branch) {
/**
* @param arr
* @param key
* @param newval
* @param newVal
*/
function upsert(arr, key, newval) {
function upsert(arr, key, newVal) {
const index = arr.indexOf(key);
if (index === -1) {
arr.push(newval);
arr.push(newVal);
} else {
arr.splice(index, 1, newval);
arr.splice(index, 1, newVal);
}
}
/** @param commitArr */
function prettyPrintCommitHistory(commitArr) {
const commit = commitArr.reduce((out, commit) => {
if (out.seq > commit.seq) return out;
if (out.seq > commit.seq) {
return out;
}
return commit;
}, commitArr[0]);
let line = '';
@@ -411,7 +414,9 @@ function prettyPrintCommitHistory(commitArr) {
});
const label = [line, commit.id, commit.seq];
for (let branch in branches) {
if (branches[branch] === commit.id) label.push(branch);
if (branches[branch] === commit.id) {
label.push(branch);
}
}
log.debug(label.join(' '));
if (commit.parents && commit.parents.length == 2) {
@@ -451,7 +456,9 @@ export const clear = function () {
export const getBranchesAsObjArray = function () {
const branchesArray = Object.values(branchesConfig)
.map((branchConfig, i) => {
if (branchConfig.order !== null) return branchConfig;
if (branchConfig.order !== null) {
return branchConfig;
}
return {
...branchConfig,
order: parseFloat(`0.${i}`, 10),

View File

@@ -218,18 +218,18 @@ function cloneNode(svg, selector) {
/**
* @param svg
* @param commitid
* @param commitId
* @param branches
* @param direction
*/
function renderCommitHistory(svg, commitid, branches, direction) {
function renderCommitHistory(svg, commitId, branches, direction) {
let commit;
const numCommits = Object.keys(allCommitsDict).length;
if (typeof commitid === 'string') {
if (typeof commitId === 'string') {
do {
commit = allCommitsDict[commitid];
commit = allCommitsDict[commitId];
logger.debug('in renderCommitHistory', commit.id, commit.seq);
if (svg.select('#node-' + commitid).size() > 0) {
if (svg.select('#node-' + commitId).size() > 0) {
return;
}
svg
@@ -291,15 +291,15 @@ function renderCommitHistory(svg, commitid, branches, direction) {
.attr('class', 'commit-msg')
.text(', ' + commit.message);
}
commitid = commit.parent;
} while (commitid && allCommitsDict[commitid]);
commitId = commit.parent;
} while (commitId && allCommitsDict[commitId]);
}
if (Array.isArray(commitid)) {
logger.debug('found merge commmit', commitid);
renderCommitHistory(svg, commitid[0], branches, direction);
if (Array.isArray(commitId)) {
logger.debug('found merge commmit', commitId);
renderCommitHistory(svg, commitId[0], branches, direction);
branchNum++;
renderCommitHistory(svg, commitid[1], branches, direction);
renderCommitHistory(svg, commitId[1], branches, direction);
branchNum--;
}
}
@@ -357,7 +357,9 @@ export const draw = function (txt, id, ver) {
branchNum++;
}
svg.attr('height', function () {
if (direction === 'BT') return Object.keys(allCommitsDict).length * config.nodeSpacing;
if (direction === 'BT') {
return Object.keys(allCommitsDict).length * config.nodeSpacing;
}
return (branches.length + 1) * config.branchOffset;
});
} catch (e) {

View File

@@ -496,7 +496,7 @@ const drawBranches = (svg, branches) => {
export const draw = function (txt, id, ver, diagObj) {
clear();
const conf = getConfig();
const gitGraphConfig = getConfig().gitGraph;
const gitGraphConfig = conf.gitGraph;
// try {
log.debug('in gitgraph renderer', txt + '\n', 'id:', id, ver);
@@ -523,7 +523,12 @@ export const draw = function (txt, id, ver, diagObj) {
drawCommits(diagram, allCommitsDict, true);
// Setup the view box and size of the svg element
setupGraphViewbox(undefined, diagram, gitGraphConfig.diagramPadding, conf.useMaxWidth);
setupGraphViewbox(
undefined,
diagram,
gitGraphConfig.diagramPadding,
gitGraphConfig.useMaxWidth ?? conf.useMaxWidth
);
};
export default {

View File

@@ -1,6 +1,6 @@
import { getConfig } from '../../config';
export default (dir, _branches, _commits) => {
export default (dir, _branches) => {
const config = getConfig().gitGraph;
const branches = [];
const commits = [];

View File

@@ -9,16 +9,15 @@ import { getConfig } from '../../config';
* @param {any} text
* @param {any} id
* @param {any} version
* @param diagObj
*/
export const draw = (text, id, version, diagObj) => {
export const draw = (text, id, version) => {
try {
// const parser = infoParser.parser;
// parser.yy = db;
log.debug('Rendering info diagram\n' + text);
const securityLevel = getConfig().securityLevel;
// Handle root and Document for when rendering in sanbox mode
// Handle root and Document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);

View File

@@ -21,7 +21,7 @@ export const draw = (txt, id, _version, diagObj) => {
log.debug('Rendering info diagram\n' + txt);
const securityLevel = configApi.getConfig().securityLevel;
// Handle root and Document for when rendering in sanbox mode
// Handle root and Document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
@@ -94,10 +94,22 @@ export const draw = (txt, id, _version, diagObj) => {
var color = scaleOrdinal().range(myGeneratedColors);
// Compute the position of each group on the pie:
var pie = d3pie().value(function (d) {
return d[1];
var pieData = Object.entries(data).map(function (el, idx) {
return {
order: idx,
name: el[0],
value: el[1],
};
});
var dataReady = pie(Object.entries(data));
var pie = d3pie()
.value(function (d) {
return d.value;
})
.sort(function (a, b) {
// Sort slices in clockwise direction
return a.order - b.order;
});
var dataReady = pie(pieData);
// Shape helper to build arcs:
var arcGenerator = arc().innerRadius(0).outerRadius(radius);
@@ -110,7 +122,7 @@ export const draw = (txt, id, _version, diagObj) => {
.append('path')
.attr('d', arcGenerator)
.attr('fill', function (d) {
return color(d.data[0]);
return color(d.data.name);
})
.attr('class', 'pieCircle');
@@ -122,7 +134,7 @@ export const draw = (txt, id, _version, diagObj) => {
.enter()
.append('text')
.text(function (d) {
return ((d.data[1] / sum) * 100).toFixed(0) + '%';
return ((d.data.value / sum) * 100).toFixed(0) + '%';
})
.attr('transform', function (d) {
return 'translate(' + arcGenerator.centroid(d) + ')';
@@ -166,9 +178,9 @@ export const draw = (txt, id, _version, diagObj) => {
.attr('y', legendRectSize - legendSpacing)
.text(function (d) {
if (diagObj.db.getShowData() || conf.showData || conf.pie.showData) {
return d.data[0] + ' [' + d.data[1] + ']';
return d.data.name + ' [' + d.data.value + ']';
} else {
return d.data[0];
return d.data.name;
}
});
} catch (e) {

View File

@@ -311,7 +311,7 @@ export const draw = (text, id, _version, diagObj) => {
diagObj.parser.parse(text);
const securityLevel = conf.securityLevel;
// Handle root and Document for when rendering in sanbox mode
// Handle root and Document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);

View File

@@ -26,7 +26,9 @@ export const parseDirective = function (statement, context, type) {
export const addActor = function (id, name, description, type) {
// Don't allow description nulling
const old = actors[id];
if (old && name === old.name && description == null) return;
if (old && name === old.name && description == null) {
return;
}
// Don't allow null descriptions, either
if (description == null || description.text == null) {

View File

@@ -10,6 +10,7 @@ import assignWithDepth from '../../assignWithDepth';
import utils from '../../utils';
import { configureSvgSize } from '../../setupGraphViewbox';
import addSVGAccessibilityFields from '../../accessibility';
import Diagram from '../../Diagram';
let conf = {};
@@ -100,8 +101,8 @@ export const bounds = {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const _self = this;
let cnt = 0;
/** @param {any} type */
function updateFn(type) {
/** @param type - Either `activation` or `undefined` */
function updateFn(type?: 'activation') {
return function updateItemBounds(item) {
cnt++;
// The loop sequenceItems is a stack so the biggest margins in the beginning of the sequenceItems
@@ -200,15 +201,25 @@ export const bounds = {
},
};
/** Options for drawing a note in {@link drawNote} */
interface NoteModel {
/** x axis start position */
startx: number;
/** y axis position */
starty: number;
/** the message to be shown */
message: string;
/** Set this with a custom width to override the default configured width. */
width: number;
}
/**
* Draws an note in the diagram with the attached line
*
* @param {any} elem - The diagram to draw to.
* @param {{ x: number; y: number; message: string; width: number }} noteModel - Startx: x axis
* start position, verticalPos: y axis position, messsage: the message to be shown, width: Set
* this with a custom width to override the default configured width.
* @param elem - The diagram to draw to.
* @param noteModel - Note model options.
*/
const drawNote = function (elem, noteModel) {
const drawNote = function (elem: any, noteModel: NoteModel) {
bounds.bumpVerticalPos(conf.boxMargin);
noteModel.height = conf.boxMargin;
noteModel.starty = bounds.getVerticalPos();
@@ -278,11 +289,11 @@ const actorFont = (cnf) => {
* message so it can be drawn later. We do not draw the message at this point so the arrowhead can
* be on top of the activation box.
*
* @param {any} diagram - The parent of the message element
* @param {any} msgModel - The model containing fields describing a message
* @returns {number} LineStarty - The Y coordinate at which the message line starts
* @param _diagram - The parent of the message element.
* @param msgModel - The model containing fields describing a message
* @returns `lineStartY` - The Y coordinate at which the message line starts
*/
const boundMessage = function (diagram, msgModel) {
function boundMessage(_diagram, msgModel): number {
bounds.bumpVerticalPos(10);
const { startx, stopx, message } = msgModel;
const lines = common.splitBreaks(message).length;
@@ -292,15 +303,15 @@ const boundMessage = function (diagram, msgModel) {
bounds.bumpVerticalPos(lineHeight);
let lineStarty;
let lineStartY;
let totalOffset = textDims.height - 10;
const textWidth = textDims.width;
if (startx === stopx) {
lineStarty = bounds.getVerticalPos() + totalOffset;
lineStartY = bounds.getVerticalPos() + totalOffset;
if (!conf.rightAngles) {
totalOffset += conf.boxMargin;
lineStarty = bounds.getVerticalPos() + totalOffset;
lineStartY = bounds.getVerticalPos() + totalOffset;
}
totalOffset += 30;
const dx = Math.max(textWidth / 2, conf.width / 2);
@@ -312,26 +323,26 @@ const boundMessage = function (diagram, msgModel) {
);
} else {
totalOffset += conf.boxMargin;
lineStarty = bounds.getVerticalPos() + totalOffset;
bounds.insert(startx, lineStarty - 10, stopx, lineStarty);
lineStartY = bounds.getVerticalPos() + totalOffset;
bounds.insert(startx, lineStartY - 10, stopx, lineStartY);
}
bounds.bumpVerticalPos(totalOffset);
msgModel.height += totalOffset;
msgModel.stopy = msgModel.starty + msgModel.height;
bounds.insert(msgModel.fromBounds, msgModel.starty, msgModel.toBounds, msgModel.stopy);
return lineStarty;
};
return lineStartY;
}
/**
* Draws a message. Note that the bounds have previously been updated by boundMessage.
*
* @param {any} diagram - The parent of the message element
* @param {any} msgModel - The model containing fields describing a message
* @param {number} lineStarty - The Y coordinate at which the message line starts
* @param diagObj
* @param diagram - The parent of the message element
* @param msgModel - The model containing fields describing a message
* @param lineStartY - The Y coordinate at which the message line starts
* @param diagObj - The diagram object.
*/
const drawMessage = function (diagram, msgModel, lineStarty, diagObj) {
const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Diagram) {
const { startx, stopx, starty, message, type, sequenceIndex, sequenceVisible } = msgModel;
const textDims = utils.calculateTextDimensions(message, messageFont(conf));
const textObj = svgDraw.getTextObj();
@@ -360,8 +371,8 @@ const drawMessage = function (diagram, msgModel, lineStarty, diagObj) {
.append('path')
.attr(
'd',
`M ${startx},${lineStarty} H ${startx + Math.max(conf.width / 2, textWidth / 2)} V ${
lineStarty + 25
`M ${startx},${lineStartY} H ${startx + Math.max(conf.width / 2, textWidth / 2)} V ${
lineStartY + 25
} H ${startx}`
);
} else {
@@ -372,27 +383,27 @@ const drawMessage = function (diagram, msgModel, lineStarty, diagObj) {
'M ' +
startx +
',' +
lineStarty +
lineStartY +
' C ' +
(startx + 60) +
',' +
(lineStarty - 10) +
(lineStartY - 10) +
' ' +
(startx + 60) +
',' +
(lineStarty + 30) +
(lineStartY + 30) +
' ' +
startx +
',' +
(lineStarty + 20)
(lineStartY + 20)
);
}
} else {
line = diagram.append('line');
line.attr('x1', startx);
line.attr('y1', lineStarty);
line.attr('y1', lineStartY);
line.attr('x2', stopx);
line.attr('y2', lineStarty);
line.attr('y2', lineStartY);
}
// Make an SVG Container
// Draw the line
@@ -440,7 +451,7 @@ const drawMessage = function (diagram, msgModel, lineStarty, diagObj) {
diagram
.append('text')
.attr('x', startx)
.attr('y', lineStarty + 4)
.attr('y', lineStartY + 4)
.attr('font-family', 'sans-serif')
.attr('font-size', '12px')
.attr('text-anchor', 'middle')
@@ -554,13 +565,6 @@ const activationBounds = function (actor, actors) {
return [left, right];
};
/**
* @param {any} loopWidths
* @param {any} msg
* @param {any} preMargin
* @param {any} postMargin
* @param {any} addLoopFn
*/
function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoopFn) {
bounds.bumpVerticalPos(preMargin);
let heightAdjust = postMargin;
@@ -584,15 +588,15 @@ function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoop
/**
* Draws a sequenceDiagram in the tag with id: id based on the graph definition in text.
*
* @param {any} _text The text of the diagram
* @param {any} id The id of the diagram which will be used as a DOM element id¨
* @param {any} _version Mermaid version from package.json
* @param {any} diagObj A stanard diagram containing the db and the text and type etc of the diagram
* @param _text - The text of the diagram
* @param id - The id of the diagram which will be used as a DOM element id¨
* @param _version - Mermaid version from package.json
* @param diagObj - A standard diagram containing the db and the text and type etc of the diagram
*/
export const draw = function (_text, id, _version, diagObj) {
export const draw = function (_text: string, id: string, _version: string, diagObj: Diagram) {
const { securityLevel, sequence } = configApi.getConfig();
conf = sequence;
// Handle root and Document for when rendering in sanbox mode
// Handle root and Document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
@@ -632,10 +636,10 @@ export const draw = function (_text, id, _version, diagObj) {
svgDraw.insertSequenceNumber(diagram);
/**
* @param {any} msg
* @param {any} verticalPos
* @param msg - The message to draw.
* @param verticalPos - The vertical position of the message.
*/
function activeEnd(msg, verticalPos) {
function activeEnd(msg: any, verticalPos: number) {
const activationData = bounds.endActivation(msg);
if (activationData.starty + 18 > verticalPos) {
activationData.starty = verticalPos - 6;
@@ -762,8 +766,11 @@ export const draw = function (_text, id, _version, diagObj) {
case diagObj.db.LINETYPE.AUTONUMBER:
sequenceIndex = msg.message.start || sequenceIndex;
sequenceIndexStep = msg.message.step || sequenceIndexStep;
if (msg.message.visible) diagObj.db.enableSequenceNumbers();
else diagObj.db.disableSequenceNumbers();
if (msg.message.visible) {
diagObj.db.enableSequenceNumbers();
} else {
diagObj.db.disableSequenceNumbers();
}
break;
case diagObj.db.LINETYPE.CRITICAL_START:
adjustLoopHeightForWrap(
@@ -811,8 +818,8 @@ export const draw = function (_text, id, _version, diagObj) {
msgModel.starty = bounds.getVerticalPos();
msgModel.sequenceIndex = sequenceIndex;
msgModel.sequenceVisible = diagObj.db.showSequenceNumbers();
const lineStarty = boundMessage(diagram, msgModel);
messagesToDraw.push({ messageModel: msgModel, lineStarty: lineStarty });
const lineStartY = boundMessage(diagram, msgModel);
messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY });
bounds.models.addMessage(msgModel);
} catch (e) {
log.error('error while drawing message', e);
@@ -836,7 +843,7 @@ export const draw = function (_text, id, _version, diagObj) {
}
});
messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStarty, diagObj));
messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStartY, diagObj));
if (conf.mirrorActors) {
// Draw actors below diagram
@@ -907,12 +914,16 @@ export const draw = function (_text, id, _version, diagObj) {
* It will enumerate each given message, and will determine its text width, in relation to the actor
* it originates from, and destined to.
*
* @param {any} actors - The actors map
* @param {Array} messages - A list of message objects to iterate
* @param diagObj
* @returns {any}
* @param actors - The actors map
* @param messages - A list of message objects to iterate
* @param diagObj - The diagram object.
* @returns The max message width of each actor.
*/
const getMaxMessageWidthPerActor = function (actors, messages, diagObj) {
function getMaxMessageWidthPerActor(
actors: { [id: string]: any },
messages: any[],
diagObj: Diagram
): { [id: string]: number } {
const maxMessageWidthPerActor = {};
messages.forEach(function (msg) {
@@ -1005,7 +1016,7 @@ const getMaxMessageWidthPerActor = function (actors, messages, diagObj) {
log.debug('maxMessageWidthPerActor:', maxMessageWidthPerActor);
return maxMessageWidthPerActor;
};
}
const getRequiredPopupWidth = function (actor) {
let requiredPopupWidth = 0;
@@ -1022,15 +1033,19 @@ const getRequiredPopupWidth = function (actor) {
};
/**
* This will calculate the optimal margin for each given actor, for a given actor->messageWidth map.
* This will calculate the optimal margin for each given actor,
* for a given actor → messageWidth map.
*
* An actor's margin is determined by the width of the actor, the width of the largest message that
* originates from it, and the configured conf.actorMargin.
*
* @param {any} actors - The actors map to calculate margins for
* @param {any} actorToMessageWidth - A map of actor key -> max message width it holds
* @param actors - The actors map to calculate margins for
* @param actorToMessageWidth - A map of actor key max message width it holds
*/
const calculateActorMargins = function (actors, actorToMessageWidth) {
function calculateActorMargins(
actors: { [id: string]: any },
actorToMessageWidth: ReturnType<typeof getMaxMessageWidthPerActor>
) {
let maxHeight = 0;
Object.keys(actors).forEach((prop) => {
const actor = actors[prop];
@@ -1071,7 +1086,7 @@ const calculateActorMargins = function (actors, actorToMessageWidth) {
}
return Math.max(maxHeight, conf.height);
};
}
const buildNoteModel = function (msg, actors, diagObj) {
const startx = actors[msg.from].x;

View File

@@ -31,7 +31,9 @@ const addPopupInteraction = (id, actorCnt) => {
addFunction(() => {
const arr = document.querySelectorAll(id);
// This will be the case when running in sandboxed mode
if (arr.length === 0) return;
if (arr.length === 0) {
return;
}
arr[0].addEventListener('mouseover', function () {
popupMenuUpFunc('actor' + actorCnt + '_popup');
});
@@ -322,7 +324,9 @@ export const drawLabel = function (elem, txtObject) {
let actorCnt = -1;
export const fixLifeLineHeights = (diagram, bounds) => {
if (!diagram.selectAll) return;
if (!diagram.selectAll) {
return;
}
diagram
.selectAll('.actor-line')
.attr('class', '200')
@@ -509,7 +513,7 @@ export const anchorElement = function (elem) {
*
* @param {any} elem - Element to append activation rect.
* @param {any} bounds - Activation box bounds.
* @param {any} verticalPos - Precise y cooridnate of bottom activation box edge.
* @param {any} verticalPos - Precise y coordinate of bottom activation box edge.
* @param {any} conf - Sequence diagram config object.
* @param {any} actorActivations - Number of activations on the actor.
*/
@@ -527,10 +531,10 @@ export const drawActivation = function (elem, bounds, verticalPos, conf, actorAc
/**
* Draws a loop in the diagram
*
* @param {any} elem - Elemenet to append the loop to.
* @param {any} elem - Element to append the loop to.
* @param {any} loopModel - LoopModel of the given loop.
* @param {any} labelText - Text within the loop.
* @param {any} conf - Diagrom configuration
* @param {any} conf - Diagram configuration
* @returns {any}
*/
export const drawLoop = function (elem, loopModel, labelText, conf) {

View File

@@ -137,7 +137,7 @@ export const drawDescrState = (g, stateDef) => {
/** Adds the creates a box around the existing content and adds a panel for the id on top of the content. */
/**
* Function that creates an title row and a frame around a substate for a composit state diagram.
* Function that creates an title row and a frame around a substate for a composite state diagram.
* The function returns a new d3 svg object with updated width and height properties;
*
* @param {any} g The d3 svg object for the substate to framed
@@ -178,7 +178,7 @@ export const addTitleAndBox = (g, stateDef, altBkg) => {
// descrLine.attr('x2', graphBox.width + getConfig().state.padding);
if (stateDef.doc) {
// cnsole.warn(
// console.warn(
// stateDef.id,
// 'orgX: ',
// orgX,
@@ -217,7 +217,9 @@ export const addTitleAndBox = (g, stateDef, altBkg) => {
.attr('rx', '0');
title.attr('x', startX + pad);
if (titleWidth <= orgWidth) title.attr('x', orgX + (width - dblPad) / 2 - titleWidth / 2 + pad);
if (titleWidth <= orgWidth) {
title.attr('x', orgX + (width - dblPad) / 2 - titleWidth / 2 + pad);
}
// Title background
g.insert('rect', ':first-child')
@@ -379,14 +381,27 @@ export const drawState = function (elem, stateDef) {
const g = elem.append('g').attr('id', id).attr('class', 'stateGroup');
if (stateDef.type === 'start') drawStartState(g);
if (stateDef.type === 'end') drawEndState(g);
if (stateDef.type === 'fork' || stateDef.type === 'join') drawForkJoinState(g, stateDef);
if (stateDef.type === 'note') drawNote(stateDef.note.text, g);
if (stateDef.type === 'divider') drawDivider(g);
if (stateDef.type === 'default' && stateDef.descriptions.length === 0)
if (stateDef.type === 'start') {
drawStartState(g);
}
if (stateDef.type === 'end') {
drawEndState(g);
}
if (stateDef.type === 'fork' || stateDef.type === 'join') {
drawForkJoinState(g, stateDef);
}
if (stateDef.type === 'note') {
drawNote(stateDef.note.text, g);
}
if (stateDef.type === 'divider') {
drawDivider(g);
}
if (stateDef.type === 'default' && stateDef.descriptions.length === 0) {
drawSimpleState(g, stateDef);
if (stateDef.type === 'default' && stateDef.descriptions.length > 0) drawDescrState(g, stateDef);
}
if (stateDef.type === 'default' && stateDef.descriptions.length > 0) {
drawDescrState(g, stateDef);
}
const stateBox = g.node().getBBox();
stateInfo.width = stateBox.width + 2 * getConfig().state.padding;

View File

@@ -148,7 +148,9 @@ export const addState = function (id, type, doc, descr, note) {
}
if (descr) {
log.info('Adding state ', id, descr);
if (typeof descr === 'string') addDescription(id, descr.trim());
if (typeof descr === 'string') {
addDescription(id, descr.trim());
}
if (typeof descr === 'object') {
descr.forEach((des) => addDescription(id, des.trim()));

View File

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

View File

@@ -1,8 +1,10 @@
import type { DiagramDetector } from '../../diagram-api/types';
export const stateDetector: DiagramDetector = (txt, config) => {
// If we have confired to only use new state diagrams this function should always return false
// 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') return false;
if (config?.state?.defaultRenderer === 'dagre-wrapper') {
return false;
}
return txt.match(/^\s*stateDiagram/) !== null;
};

View File

@@ -56,7 +56,7 @@ const setupNode = (g, parent, node, altFlag) => {
};
}
// Build of the array of description strings accordinging
// Build of the array of description strings according
if (node.description) {
if (Array.isArray(nodeDb[node.id].description)) {
// There already is an array of strings,add to it

View File

@@ -47,7 +47,7 @@ const insertMarkers = function (elem) {
export const draw = function (text, id, _version, diagObj) {
conf = getConfig().state;
const securityLevel = getConfig().securityLevel;
// Handle root and Document for when rendering in sanbox mode
// Handle root and Document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
@@ -120,7 +120,7 @@ const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument, diagObj) =
}
// Set an object for the graph label
if (parentId)
if (parentId) {
graph.setGraph({
rankdir: 'LR',
multigraph: true,
@@ -133,7 +133,7 @@ const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument, diagObj) =
// ranksep: 5,
// nodesep: 1
});
else {
} else {
graph.setGraph({
rankdir: 'TB',
multigraph: true,
@@ -268,7 +268,9 @@ const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument, diagObj) =
let pWidth = 0;
let pShift = 0;
if (parent) {
if (parent.parentElement) pWidth = parent.parentElement.getBBox().width;
if (parent.parentElement) {
pWidth = parent.parentElement.getBBox().width;
}
pShift = parseInt(parent.getAttribute('data-x-shift'), 10);
if (Number.isNaN(pShift)) {
pShift = 0;

View File

@@ -15,7 +15,7 @@ export const setConf = function (cnf) {
const actors = {};
/** @param {any} diagram */
/** @param diagram - The diagram to draw to. */
function drawActorLegend(diagram) {
const conf = getConfig().journey;
// Draw the actors
@@ -54,7 +54,7 @@ export const draw = function (text, id, version, diagObj) {
diagObj.parser.parse(text + '\n');
const securityLevel = getConfig().securityLevel;
// Handle root and Document for when rendering in sanbox mode
// Handle root and Document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
@@ -74,7 +74,9 @@ export const draw = function (text, id, version, diagObj) {
const title = diagObj.db.getDiagramTitle();
const actorNames = diagObj.db.getActors();
for (const member in actors) delete actors[member];
for (const member in actors) {
delete actors[member];
}
let actorPos = 0;
actorNames.forEach((actorName) => {
actors[actorName] = {
@@ -155,8 +157,8 @@ export const bounds = {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const _self = this;
let cnt = 0;
/** @param {any} type */
function updateFn(type) {
/** @param type - Set to `activation` if activation */
function updateFn(type?: 'activation') {
return function updateItemBounds(item) {
cnt++;
// The loop sequenceItems is a stack so the biggest margins in the beginning of the sequenceItems
@@ -261,7 +263,7 @@ export const drawTasks = function (diagram, tasks, verticalPos) {
// Draw the box with the attached line
svgDraw.drawTask(diagram, task, conf);
bounds.insert(task.x, task.y, task.x + task.width + conf.taskMargin, 300 + 5 * 30); // stopy is the length of the descenders.
bounds.insert(task.x, task.y, task.x + task.width + conf.taskMargin, 300 + 5 * 30); // stopY is the length of the descenders.
}
};

View File

@@ -218,7 +218,7 @@ export const drawSection = function (elem, section, conf) {
let taskCount = -1;
/**
* Draws an actor in the diagram with the attaced line
* Draws an actor in the diagram with the attached line
*
* @param {any} elem The HTML element
* @param {any} task The task to render

View File

@@ -9,7 +9,9 @@ Mermaid can render class diagrams.
```mermaid-example
classDiagram
note "From Duck till Zebra"
Animal <|-- Duck
note for Duck "can fly\ncan swim\ncan dive\ncan help in debugging"
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
@@ -375,6 +377,10 @@ click className href "url" "tooltip"
- (_optional_) tooltip is a string to be displayed when hovering over element (note: The styles of the tooltip are set by the class .mermaidTooltip.)
- note: callback function will be called with the nodeId as parameter.
## Notes
It is possible to add notes on digram using `note "line1\nline2"` or note for class using `note for class "line1\nline2"`
### Examples
_URL Link:_

View File

@@ -85,10 +85,34 @@ Cardinality is a property that describes how many elements of another entity can
| `}o` | `o{` | Zero or more (no upper limit) |
| `}\|` | `\|{` | One or more (no upper limit) |
**Aliases**
| Value (left) | Value (right) | Alias for |
| :----------: | :-----------: | ------------ |
| one or zero | one or zero | Zero or one |
| zero or one | zero or one | Zero or one |
| one or more | one or more | One or more |
| one or many | one or many | One or more |
| many(1) | many(1) | One or more |
| 1+ | 1+ | One or more |
| zero or more | zero or more | Zero or more |
| zero or many | zero or many | Zero or more |
| many(0) | many(1) | Zero or more |
| 0+ | 0+ | Zero or more |
| only one | only one | Exactly one |
| 1 | 1 | Exactly one |
### Identification
Relationships may be classified as either _identifying_ or _non-identifying_ and these are rendered with either solid or dashed lines respectively. This is relevant when one of the entities in question can not have independent existence without the other. For example a firm that insures people to drive cars might need to store data on `NAMED-DRIVER`s. In modelling this we might start out by observing that a `CAR` can be driven by many `PERSON` instances, and a `PERSON` can drive many `CAR`s - both entities can exist without the other, so this is a non-identifying relationship that we might specify in Mermaid as: `PERSON }|..|{ CAR : "driver"`. Note the two dots in the middle of the relationship that will result in a dashed line being drawn between the two entities. But when this many-to-many relationship is resolved into two one-to-many relationships, we observe that a `NAMED-DRIVER` cannot exist without both a `PERSON` and a `CAR` - the relationships become identifying and would be specified using hyphens, which translate to a solid line:
**Aliases**
| Value | Alias for |
| :-----------: | :---------------: |
| to | _identifying_ |
| optionally to | _non-identifying_ |
```mmd
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
@@ -155,6 +179,7 @@ erDiagram
string lastName
int age
}
MANUFACTURER only one to zero or more CAR
```
### Other Things

View File

@@ -19,7 +19,7 @@ Drawing a pie chart is really simple in mermaid.
- Start with `pie` keyword to begin the diagram
- `showData` to render the actual data values after the legend text. This is **_OPTIONAL_**
- Followed by `title` keyword and its value in string to give a title to the pie-chart. This is **_OPTIONAL_**
- Followed by dataSet
- Followed by dataSet. Pie slices will be ordered clockwise in the same order as the labels.
- `label` for a section in the pie diagram within `" "` quotes.
- Followed by `:` colon as separator
- Followed by `positive numeric value` (supported upto two decimal places)

View File

@@ -27,7 +27,7 @@ export const log: Record<keyof typeof LEVELS, typeof console.log> = {
/**
* Sets a log level
*
* @param {LogLevel} [level="fatal"] The level to set the logging to. Default is `"fatal"`
* @param level - The level to set the logging to. Default is `"fatal"`
*/
export const setLogLevel = function (level: keyof typeof LEVELS | number | string = 'fatal') {
let numericLevel: number = LEVELS.fatal;
@@ -80,10 +80,10 @@ export const setLogLevel = function (level: keyof typeof LEVELS | number | strin
/**
* Returns a format with the timestamp and the log level
*
* @param {LogLevel} level The level for the log format
* @returns {string} The format with the timestamp and log level
* @param level - The level for the log format
* @returns The format with the timestamp and log level
*/
const format = (level: string): string => {
const format = (level: Uppercase<LogLevel>): string => {
const time = moment().format('ss.SSS');
return `%c${time} : ${level} : `;
};

View File

@@ -8,6 +8,7 @@ import utils from './utils';
import { mermaidAPI } from './mermaidAPI';
import { addDetector } from './diagram-api/detectType';
import { isDetailedError } from './utils';
import type { ParseErrorFunction } from './Diagram';
/**
* ## init
@@ -18,12 +19,6 @@ import { isDetailedError } from './utils';
* elements with the attribute already set. This way the init function can be triggered several
* times.
*
* Optionally, `init` can accept in the second argument one of the following:
*
* - A DOM Node
* - An array of DOM nodes (as would come from a jQuery selector)
* - A W3C selector, a la `.mermaid`
*
* ```mermaid
* graph LR;
* a(Find elements)-->b{Processed}
@@ -33,9 +28,12 @@ import { isDetailedError } from './utils';
*
* Renders the mermaid diagrams
*
* @param config
* @param nodes
* @param callback
* @param config - **Deprecated**, please set configuration in {@link initialize}.
* @param nodes - **Default**: `.mermaid`. One of the following:
* - A DOM Node
* - An array of DOM nodes (as would come from a jQuery selector)
* - A W3C selector, a la `.mermaid`
* @param callback - Called once for each rendered diagram's id.
*/
const init = async function (
config?: MermaidConfig,
@@ -62,7 +60,7 @@ const init = async function (
log.warn(e.str);
}
if (mermaid.parseError) {
mermaid.parseError(e);
mermaid.parseError(e as string);
}
}
};
@@ -142,7 +140,9 @@ const initThrowsErrors = async function (
if (typeof callback !== 'undefined') {
callback(id);
}
if (bindFunctions) bindFunctions(element);
if (bindFunctions) {
bindFunctions(element);
}
},
element
);
@@ -199,7 +199,7 @@ if (typeof document !== 'undefined') {
* This is provided for environments where the mermaid object can't directly have a new member added
* to it (eg. dart interop wrapper). (Initially there is no parseError member of mermaid).
*
* @param {function (err, hash)} newParseErrorHandler New parseError() callback.
* @param newParseErrorHandler - New parseError() callback.
*/
const setParseErrorHandler = function (newParseErrorHandler: (err: any, hash: any) => void) {
mermaid.parseError = newParseErrorHandler;
@@ -212,8 +212,7 @@ const parse = (txt: string) => {
const mermaid: {
startOnLoad: boolean;
diagrams: any;
// eslint-disable-next-line @typescript-eslint/ban-types
parseError?: Function;
parseError?: ParseErrorFunction;
mermaidAPI: typeof mermaidAPI;
parse: typeof parse;
render: typeof mermaidAPI.render;

Some files were not shown because too many files have changed in this diff Show More