mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-02-04 07:13:25 +08:00
merge MERMAID/develop into branch
This commit is contained in:
commit
599d035daf
@ -16,26 +16,17 @@
|
|||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended",
|
"eslint:recommended",
|
||||||
"plugin:@typescript-eslint/recommended",
|
"plugin:@typescript-eslint/recommended",
|
||||||
"plugin:jsdoc/recommended",
|
|
||||||
"plugin:json/recommended",
|
"plugin:json/recommended",
|
||||||
"plugin:markdown/recommended",
|
"plugin:markdown/recommended",
|
||||||
|
"plugin:@cspell/recommended",
|
||||||
"prettier"
|
"prettier"
|
||||||
],
|
],
|
||||||
"plugins": ["@typescript-eslint", "html", "jest", "jsdoc", "json"],
|
"plugins": ["@typescript-eslint", "no-only-tests", "html", "jest", "jsdoc", "json", "@cspell"],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"curly": "error",
|
||||||
"no-console": "error",
|
"no-console": "error",
|
||||||
"no-prototype-builtins": "off",
|
"no-prototype-builtins": "off",
|
||||||
"no-unused-vars": "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",
|
"cypress/no-async-tests": "off",
|
||||||
"@typescript-eslint/ban-ts-comment": [
|
"@typescript-eslint/ban-ts-comment": [
|
||||||
"error",
|
"error",
|
||||||
@ -48,7 +39,21 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"json/*": ["error", "allowComments"],
|
"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": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
@ -57,6 +62,29 @@
|
|||||||
"no-console": "off"
|
"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/**"],
|
"files": ["*.spec.{ts,js}", "cypress/**", "demos/**", "**/docs/**"],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
18
.github/dependabot.yml
vendored
18
.github/dependabot.yml
vendored
@ -1,18 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: npm
|
|
||||||
open-pull-requests-limit: 10
|
|
||||||
directory: /
|
|
||||||
target-branch: develop
|
|
||||||
versioning-strategy: increase
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
day: monday
|
|
||||||
time: '07:00'
|
|
||||||
- package-ecosystem: github-actions
|
|
||||||
directory: /
|
|
||||||
target-branch: develop
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
day: monday
|
|
||||||
time: '07:00'
|
|
4
.github/workflows/docs.yml
vendored
4
.github/workflows/docs.yml
vendored
@ -16,9 +16,9 @@ jobs:
|
|||||||
name: 'Docs: Spellcheck'
|
name: 'Docs: Spellcheck'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
name: Check out the code
|
name: Check out the code
|
||||||
- uses: actions/setup-node@v1
|
- uses: actions/setup-node@v3
|
||||||
name: Setup node
|
name: Setup node
|
||||||
with:
|
with:
|
||||||
node-version: '16'
|
node-version: '16'
|
||||||
|
@ -1,7 +1,15 @@
|
|||||||
import express from 'express';
|
import express, { NextFunction, Request, Response } from 'express';
|
||||||
import { createServer as createViteServer } from 'vite';
|
import { createServer as createViteServer } from 'vite';
|
||||||
// import { getBuildConfig } from './build';
|
// 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() {
|
async function createServer() {
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
@ -12,6 +20,7 @@ async function createServer() {
|
|||||||
appType: 'custom', // don't include Vite's default HTML handling middlewares
|
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/dist'));
|
||||||
app.use(express.static('./packages/mermaid-example-diagram/dist'));
|
app.use(express.static('./packages/mermaid-example-diagram/dist'));
|
||||||
app.use(express.static('./packages/mermaid-mindmap/dist'));
|
app.use(express.static('./packages/mermaid-mindmap/dist'));
|
||||||
|
@ -164,6 +164,7 @@ Class01 <|-- AveryLongClass : Cool
|
|||||||
Class09 --> C2 : Where am I?
|
Class09 --> C2 : Where am I?
|
||||||
Class09 --* C3
|
Class09 --* C3
|
||||||
Class09 --|> Class07
|
Class09 --|> Class07
|
||||||
|
note "I love this diagram!\nDo you love it?"
|
||||||
Class07 : equals()
|
Class07 : equals()
|
||||||
Class07 : Object[] elementData
|
Class07 : Object[] elementData
|
||||||
Class01 : size()
|
Class01 : size()
|
||||||
@ -174,6 +175,7 @@ class Class10 {
|
|||||||
int id
|
int id
|
||||||
size()
|
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>]
|
### 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>]
|
||||||
|
29
cSpell.json
29
cSpell.json
@ -13,7 +13,8 @@
|
|||||||
"sandboxed",
|
"sandboxed",
|
||||||
"Sveidqvist",
|
"Sveidqvist",
|
||||||
"verdana",
|
"verdana",
|
||||||
"Visio"
|
"Visio",
|
||||||
|
"mermiad"
|
||||||
],
|
],
|
||||||
"ignoreWords": [
|
"ignoreWords": [
|
||||||
"Adamiecki",
|
"Adamiecki",
|
||||||
@ -38,7 +39,31 @@
|
|||||||
"Podlite",
|
"Podlite",
|
||||||
"redmine",
|
"redmine",
|
||||||
"sphinxcontrib",
|
"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",
|
||||||
|
"statediagram"
|
||||||
],
|
],
|
||||||
"patterns": [
|
"patterns": [
|
||||||
{
|
{
|
||||||
|
@ -45,7 +45,6 @@ export const imgSnapshotTest = (graphStr, _options, api = false, validation) =>
|
|||||||
options.fontSize = '16px';
|
options.fontSize = '16px';
|
||||||
}
|
}
|
||||||
const useAppli = Cypress.env('useAppli');
|
const useAppli = Cypress.env('useAppli');
|
||||||
//const useAppli = false;
|
|
||||||
cy.log('Hello ' + useAppli ? 'Appli' : 'image-snapshot');
|
cy.log('Hello ' + useAppli ? 'Appli' : 'image-snapshot');
|
||||||
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
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);
|
const url = mermaidUrl(graphStr, options, api);
|
||||||
|
|
||||||
cy.visit(url);
|
cy.visit(url);
|
||||||
if (validation) cy.get('svg').should(validation);
|
if (validation) {
|
||||||
|
cy.get('svg').should(validation);
|
||||||
|
}
|
||||||
cy.get('svg');
|
cy.get('svg');
|
||||||
// Default name to test title
|
// Default name to test title
|
||||||
|
|
||||||
@ -107,7 +108,9 @@ export const urlSnapshotTest = (url, _options, api = false, validation) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cy.visit(url);
|
cy.visit(url);
|
||||||
if (validation) cy.get('svg').should(validation);
|
if (validation) {
|
||||||
|
cy.get('svg').should(validation);
|
||||||
|
}
|
||||||
cy.get('body');
|
cy.get('body');
|
||||||
// Default name to test title
|
// Default name to test title
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ describe('Git Graph diagram', () => {
|
|||||||
// // Call Open on eyes to initialize a test session
|
// // Call Open on eyes to initialize a test session
|
||||||
// cy.eyesOpen({
|
// cy.eyesOpen({
|
||||||
// appName: 'Demo App',
|
// appName: 'Demo App',
|
||||||
// testName: 'Ultrafast grid demo',
|
// testName: 'UltraFast grid demo',
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// // check the login page with fluent api, see more info here
|
// // check the login page with fluent api, see more info here
|
||||||
|
@ -478,4 +478,22 @@ describe('Class diagram V2', () => {
|
|||||||
);
|
);
|
||||||
cy.get('svg');
|
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');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -407,4 +407,21 @@ describe('Class diagram', () => {
|
|||||||
// // expect(svg).to.not.have.attr('style');
|
// // 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');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -167,7 +167,7 @@ describe('Entity Relationship Diagram', () => {
|
|||||||
cy.get('svg');
|
cy.get('svg');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.only('should render entities with generic and array attributes', () => {
|
it('should render entities with generic and array attributes', () => {
|
||||||
renderGraph(
|
renderGraph(
|
||||||
`
|
`
|
||||||
erDiagram
|
erDiagram
|
||||||
@ -255,4 +255,22 @@ describe('Entity Relationship Diagram', () => {
|
|||||||
);
|
);
|
||||||
cy.get('svg');
|
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');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -56,50 +56,40 @@
|
|||||||
<body>
|
<body>
|
||||||
<div>Security check</div>
|
<div>Security check</div>
|
||||||
<pre id="diagram" class="mermaid">
|
<pre id="diagram" class="mermaid">
|
||||||
classDiagram
|
flowchart TD
|
||||||
direction LR
|
A --> B
|
||||||
class Student {
|
B --> C
|
||||||
-idCard : IdCard
|
A --> C
|
||||||
}
|
|
||||||
class IdCard{
|
|
||||||
-id : int
|
|
||||||
-name : string
|
|
||||||
}
|
|
||||||
class Bike{
|
|
||||||
-id : int
|
|
||||||
-name : string
|
|
||||||
}
|
|
||||||
Student "1" --o "1" IdCard : carries
|
|
||||||
Student "1" --o "1" Bike : rides
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram" class="mermaid2">
|
<pre id="diagram" class="mermaid">
|
||||||
mindmap
|
mindmap
|
||||||
root
|
root((mindmap))
|
||||||
A
|
Origins
|
||||||
B
|
Long history
|
||||||
C
|
::icon(fa fa-book)
|
||||||
D
|
Popularisation
|
||||||
E
|
::icon(fa fa-book)
|
||||||
A2
|
British popular psychology author Tony Buzan
|
||||||
B2
|
Research
|
||||||
C2
|
::icon(fa fa-book)
|
||||||
D2
|
On effectivness<br/>and features
|
||||||
E2
|
On Automatic creation
|
||||||
child1((Circle))
|
Uses
|
||||||
grandchild 1
|
Creative techniques
|
||||||
grandchild 2
|
Strategic planning
|
||||||
child2(Round rectangle)
|
Argument mapping
|
||||||
grandchild 3
|
Tools
|
||||||
grandchild 4
|
Pen and paper
|
||||||
child3[Square]
|
Mermaid
|
||||||
grandchild 5
|
|
||||||
::icon(mdi mdi-fire)
|
|
||||||
gc6((grand<br/>child 6))
|
|
||||||
::icon(mdi mdi-fire)
|
|
||||||
gc7((grand<br/>grand<br/>child 8))
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram" class="mermaid2">
|
<pre id="diagram" class="mermaid">
|
||||||
example-diagram
|
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>
|
</pre>
|
||||||
|
|
||||||
<!-- <div id="cy"></div> -->
|
<!-- <div id="cy"></div> -->
|
||||||
@ -113,16 +103,21 @@ mindmap
|
|||||||
// console.error('Mermaid error: ', err);
|
// console.error('Mermaid error: ', err);
|
||||||
};
|
};
|
||||||
mermaid.initialize({
|
mermaid.initialize({
|
||||||
theme: 'forest',
|
theme: 'base',
|
||||||
startOnLoad: true,
|
startOnLoad: true,
|
||||||
logLevel: 0,
|
logLevel: 0,
|
||||||
// basePath: './packages/',
|
flowchart: {
|
||||||
// themeVariables: { darkMode: true },
|
useMaxWidth: false,
|
||||||
|
htmlLabels: true,
|
||||||
|
},
|
||||||
|
gantt: {
|
||||||
|
useMaxWidth: false,
|
||||||
|
},
|
||||||
|
useMaxWidth: false,
|
||||||
lazyLoadedDiagrams: [
|
lazyLoadedDiagrams: [
|
||||||
'./mermaid-mindmap-detector.esm.mjs',
|
'./mermaid-mindmap-detector.esm.mjs',
|
||||||
'./mermaid-example-diagram-detector.esm.mjs',
|
'./mermaid-example-diagram-detector.esm.mjs',
|
||||||
],
|
],
|
||||||
// lazyLoadedDiagrams: ['../../mermaid-mindmap/registry.ts'],
|
|
||||||
});
|
});
|
||||||
function callback() {
|
function callback() {
|
||||||
alert('It worked');
|
alert('It worked');
|
||||||
@ -131,6 +126,10 @@ mindmap
|
|||||||
console.error('In parse error:');
|
console.error('In parse error:');
|
||||||
console.error(err);
|
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>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -120,7 +120,9 @@ const contentLoadedApi = function () {
|
|||||||
(svgCode, bindFunctions) => {
|
(svgCode, bindFunctions) => {
|
||||||
div.innerHTML = svgCode;
|
div.innerHTML = svgCode;
|
||||||
|
|
||||||
if (bindFunctions) bindFunctions(div);
|
if (bindFunctions) {
|
||||||
|
bindFunctions(div);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
div
|
div
|
||||||
);
|
);
|
||||||
|
@ -94,7 +94,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// var diagram = ` graph TD
|
// var diagram = ` graph TD
|
||||||
// A --> B["<a href='javasc`;
|
// A --> B["<a href='javascript`;
|
||||||
// diagram += `ript#colon;xssAttack()'>AAA</a>"]`;
|
// diagram += `ript#colon;xssAttack()'>AAA</a>"]`;
|
||||||
let diagram = ` graph TD
|
let diagram = ` graph TD
|
||||||
A --> B["<a href='javasc`;
|
A --> B["<a href='javasc`;
|
||||||
|
@ -74,22 +74,22 @@
|
|||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
gantt
|
gantt
|
||||||
title Hide today marker (vertical line should not be visible)
|
title Hide today marker (vertical line should not be visible)
|
||||||
dateFormat YYYY-MM-DD
|
dateFormat Z
|
||||||
axisFormat %d
|
axisFormat %d/%m
|
||||||
todayMarker off
|
todayMarker off
|
||||||
section Section1
|
section Section1
|
||||||
Today: 1, -1h
|
Today: 1, -01:00, 5min
|
||||||
</pre>
|
</pre>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
gantt
|
gantt
|
||||||
title Style today marker (vertical line should be 5px wide and half-transparent blue)
|
title Style today marker (vertical line should be 5px wide and half-transparent blue)
|
||||||
dateFormat YYYY-MM-DD
|
dateFormat Z
|
||||||
axisFormat %d
|
axisFormat %d/%m
|
||||||
todayMarker stroke-width:5px,stroke:#00f,opacity:0.5
|
todayMarker stroke-width:5px,stroke:#00f,opacity:0.5
|
||||||
section Section1
|
section Section1
|
||||||
Today: 1, -1h
|
Today: 1, -01:00, 5min
|
||||||
</pre>
|
</pre>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
|
@ -11,7 +11,9 @@ Mermaid can render class diagrams.
|
|||||||
|
|
||||||
```mermaid-example
|
```mermaid-example
|
||||||
classDiagram
|
classDiagram
|
||||||
|
note "From Duck till Zebra"
|
||||||
Animal <|-- Duck
|
Animal <|-- Duck
|
||||||
|
note for Duck "can fly\ncan swim\ncan dive\ncan help in debugging"
|
||||||
Animal <|-- Fish
|
Animal <|-- Fish
|
||||||
Animal <|-- Zebra
|
Animal <|-- Zebra
|
||||||
Animal : +int age
|
Animal : +int age
|
||||||
@ -35,7 +37,9 @@ classDiagram
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
classDiagram
|
classDiagram
|
||||||
|
note "From Duck till Zebra"
|
||||||
Animal <|-- Duck
|
Animal <|-- Duck
|
||||||
|
note for Duck "can fly\ncan swim\ncan dive\ncan help in debugging"
|
||||||
Animal <|-- Fish
|
Animal <|-- Fish
|
||||||
Animal <|-- Zebra
|
Animal <|-- Zebra
|
||||||
Animal : +int age
|
Animal : +int age
|
||||||
@ -549,6 +553,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.)
|
- (_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.
|
- 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
|
### Examples
|
||||||
|
|
||||||
_URL Link:_
|
_URL Link:_
|
||||||
|
@ -110,10 +110,34 @@ Cardinality is a property that describes how many elements of another entity can
|
|||||||
| `}o` | `o{` | Zero or more (no upper limit) |
|
| `}o` | `o{` | Zero or more (no upper limit) |
|
||||||
| `}\|` | `\|{` | One 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
|
### 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:
|
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
|
```mermaid-example
|
||||||
erDiagram
|
erDiagram
|
||||||
CAR ||--o{ NAMED-DRIVER : allows
|
CAR ||--o{ NAMED-DRIVER : allows
|
||||||
@ -218,6 +242,7 @@ erDiagram
|
|||||||
string lastName
|
string lastName
|
||||||
int age
|
int age
|
||||||
}
|
}
|
||||||
|
MANUFACTURER only one to zero or more CAR
|
||||||
```
|
```
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
@ -236,6 +261,7 @@ erDiagram
|
|||||||
string lastName
|
string lastName
|
||||||
int age
|
int age
|
||||||
}
|
}
|
||||||
|
MANUFACTURER only one to zero or more CAR
|
||||||
```
|
```
|
||||||
|
|
||||||
### Other Things
|
### Other Things
|
||||||
|
@ -315,13 +315,13 @@ flowchart LR
|
|||||||
### Dotted link
|
### Dotted link
|
||||||
|
|
||||||
```mermaid-example
|
```mermaid-example
|
||||||
flowchart LR;
|
flowchart LR
|
||||||
A-.->B;
|
A-.->B
|
||||||
```
|
```
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR;
|
flowchart LR
|
||||||
A-.->B;
|
A-.->B
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dotted link with text
|
### Dotted link with text
|
||||||
@ -866,13 +866,13 @@ A shorter form of adding a class is to attach the classname to the node using th
|
|||||||
```mermaid-example
|
```mermaid-example
|
||||||
flowchart LR
|
flowchart LR
|
||||||
A:::someclass --> B
|
A:::someclass --> B
|
||||||
classDef someclass fill:#f96;
|
classDef someclass fill:#f96
|
||||||
```
|
```
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR
|
flowchart LR
|
||||||
A:::someclass --> B
|
A:::someclass --> B
|
||||||
classDef someclass fill:#f96;
|
classDef someclass fill:#f96
|
||||||
```
|
```
|
||||||
|
|
||||||
### Css classes
|
### Css classes
|
||||||
@ -895,14 +895,14 @@ below:
|
|||||||
**Example definition**
|
**Example definition**
|
||||||
|
|
||||||
```mermaid-example
|
```mermaid-example
|
||||||
flowchart LR;
|
flowchart LR
|
||||||
A-->B[AAA<span>BBB</span>]
|
A-->B[AAA<span>BBB</span>]
|
||||||
B-->D
|
B-->D
|
||||||
class A cssClass
|
class A cssClass
|
||||||
```
|
```
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR;
|
flowchart LR
|
||||||
A-->B[AAA<span>BBB</span>]
|
A-->B[AAA<span>BBB</span>]
|
||||||
B-->D
|
B-->D
|
||||||
class A cssClass
|
class A cssClass
|
||||||
@ -924,7 +924,7 @@ The icons are accessed via the syntax fa:#icon class name#.
|
|||||||
flowchart TD
|
flowchart TD
|
||||||
B["fab:fa-twitter for peace"]
|
B["fab:fa-twitter for peace"]
|
||||||
B-->C[fa:fa-ban forbidden]
|
B-->C[fa:fa-ban forbidden]
|
||||||
B-->D(fa:fa-spinner);
|
B-->D(fa:fa-spinner)
|
||||||
B-->E(A fa:fa-camera-retro perhaps?)
|
B-->E(A fa:fa-camera-retro perhaps?)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -932,7 +932,7 @@ flowchart TD
|
|||||||
flowchart TD
|
flowchart TD
|
||||||
B["fab:fa-twitter for peace"]
|
B["fab:fa-twitter for peace"]
|
||||||
B-->C[fa:fa-ban forbidden]
|
B-->C[fa:fa-ban forbidden]
|
||||||
B-->D(fa:fa-spinner);
|
B-->D(fa:fa-spinner)
|
||||||
B-->E(A fa:fa-camera-retro perhaps?)
|
B-->E(A fa:fa-camera-retro perhaps?)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -15,6 +15,14 @@
|
|||||||
name="viewport"
|
name="viewport"
|
||||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
|
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
|
||||||
/>
|
/>
|
||||||
|
<meta property="og:title" content="Mermaid" />
|
||||||
|
<meta property="og:url" content="https://mermaid-js.github.io/mermaid/" />
|
||||||
|
<meta property="og:image" content="https://mermaid-js.github.io/mermaid/img/header.png" />
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content="Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs."
|
||||||
|
/>
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
<!-- <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css"> -->
|
<!-- <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css"> -->
|
||||||
<link rel="stylesheet" href="theme.css" />
|
<link rel="stylesheet" href="theme.css" />
|
||||||
<link
|
<link
|
||||||
@ -28,12 +36,27 @@
|
|||||||
></script>
|
></script>
|
||||||
<script>
|
<script>
|
||||||
const require = {
|
const require = {
|
||||||
paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs' },
|
paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs' },
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs/loader.min.js"></script>
|
<script
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs/editor/editor.main.nls.js"></script>
|
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.1/min/vs/loader.min.js"
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs/editor/editor.main.js"></script>
|
integrity="sha512-6bIYsGqvLpAiEBXPdRQeFf5cueeBECtAKJjIHer3BhBZNTV3WLcLA8Tm3pDfxUwTMIS+kAZwTUvJ1IrMdX8C5w=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.1/min/vs/editor/editor.main.nls.min.js"
|
||||||
|
integrity="sha512-CCv+DKWw+yZhxf4Z+ExT6HC5G+3S45TeMTYcJyYbdrv4BpK2vyALJ4FoVR/KGWDIPu7w4tNCOC9MJQIkYPR5FA=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.1/min/vs/editor/editor.main.min.js"
|
||||||
|
integrity="sha512-u4eMtetNbBJvHXdLXs2kWZvJiVlg3cmkVcxrLzSPa1eNFuHygPYvyMWyK9PsD6Eq2MZSo+mTyjds8uuhPzVxHA=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
></script>
|
||||||
<script>
|
<script>
|
||||||
exports = {};
|
exports = {};
|
||||||
</script>
|
</script>
|
||||||
@ -57,6 +80,7 @@
|
|||||||
let parser = new DOMParser();
|
let parser = new DOMParser();
|
||||||
let currentCodeExample = 0;
|
let currentCodeExample = 0;
|
||||||
let colorize = [];
|
let colorize = [];
|
||||||
|
let num = 0;
|
||||||
|
|
||||||
function colorizeEverything(html) {
|
function colorizeEverything(html) {
|
||||||
initEditor(monaco);
|
initEditor(monaco);
|
||||||
@ -127,8 +151,9 @@
|
|||||||
hook.afterEach(function (html, next) {
|
hook.afterEach(function (html, next) {
|
||||||
next(html);
|
next(html);
|
||||||
(async () => {
|
(async () => {
|
||||||
while (!window.hasOwnProperty('monaco'))
|
while (!window.hasOwnProperty('monaco')) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
}
|
||||||
colorizeEverything(html).then(
|
colorizeEverything(html).then(
|
||||||
(newHTML) =>
|
(newHTML) =>
|
||||||
(document.querySelector('article.markdown-section').innerHTML = newHTML)
|
(document.querySelector('article.markdown-section').innerHTML = newHTML)
|
||||||
@ -146,7 +171,9 @@
|
|||||||
startOnLoad: false,
|
startOnLoad: false,
|
||||||
themeCSS: '.label { font-family: Source Sans Pro,Helvetica Neue,Arial,sans-serif; }',
|
themeCSS: '.label { font-family: Source Sans Pro,Helvetica Neue,Arial,sans-serif; }',
|
||||||
};
|
};
|
||||||
if (isDarkMode) conf.theme = 'dark';
|
if (isDarkMode) {
|
||||||
|
conf.theme = 'dark';
|
||||||
|
}
|
||||||
mermaid.initialize(conf);
|
mermaid.initialize(conf);
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
@ -28,7 +28,7 @@ Drawing a pie chart is really simple in mermaid.
|
|||||||
- Start with `pie` keyword to begin the diagram
|
- Start with `pie` keyword to begin the diagram
|
||||||
- `showData` to render the actual data values after the legend text. This is **_OPTIONAL_**
|
- `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 `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.
|
- `label` for a section in the pie diagram within `" "` quotes.
|
||||||
- Followed by `:` colon as separator
|
- Followed by `:` colon as separator
|
||||||
- Followed by `positive numeric value` (supported upto two decimal places)
|
- Followed by `positive numeric value` (supported upto two decimal places)
|
||||||
|
@ -97,7 +97,7 @@ Messages can be of two displayed either solid or with a dotted line.
|
|||||||
|
|
||||||
[Actor][Arrow][Actor]:Message text
|
[Actor][Arrow][Actor]:Message text
|
||||||
|
|
||||||
There are six types of arrows currently supported:
|
There are eight types of arrows currently supported:
|
||||||
|
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
| ---- | ------------------------------------------------ |
|
| ---- | ------------------------------------------------ |
|
||||||
|
145
package.json
145
package.json
@ -7,7 +7,7 @@
|
|||||||
"module": "dist/mermaid.core.mjs",
|
"module": "dist/mermaid.core.mjs",
|
||||||
"types": "dist/mermaid.d.ts",
|
"types": "dist/mermaid.d.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"packageManager": "pnpm@7.13.2",
|
"packageManager": "pnpm@7.13.6",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"require": "./dist/mermaid.min.js",
|
"require": "./dist/mermaid.min.js",
|
||||||
@ -70,81 +70,84 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@braintree/sanitize-url": "^6.0.0",
|
"@braintree/sanitize-url": "6.0.1",
|
||||||
"@types/node": "^18.8.1",
|
"@types/node": "18.11.0",
|
||||||
"@types/uuid": "^8.3.4",
|
"@types/uuid": "8.3.4",
|
||||||
"d3": "^7.0.0",
|
"d3": "7.6.1",
|
||||||
"dagre": "^0.8.5",
|
"dagre": "0.8.5",
|
||||||
"dagre-d3": "^0.6.4",
|
"dagre-d3": "0.6.4",
|
||||||
"dompurify": "2.4.0",
|
"dompurify": "2.4.0",
|
||||||
"fast-clone": "^1.5.13",
|
"fast-clone": "1.5.13",
|
||||||
"graphlib": "^2.1.8",
|
"graphlib": "2.1.8",
|
||||||
"khroma": "^2.0.0",
|
"khroma": "2.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "4.17.21",
|
||||||
"moment-mini": "^2.24.0",
|
"moment-mini": "2.29.4",
|
||||||
"non-layered-tidy-tree-layout": "^2.0.2",
|
"non-layered-tidy-tree-layout": "2.0.2",
|
||||||
"rollup": "^2.79.1",
|
"rollup": "2.79.1",
|
||||||
"stylis": "^4.1.2",
|
"stylis": "4.1.2",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@applitools/eyes-cypress": "^3.27.1",
|
"@applitools/eyes-cypress": "3.27.5",
|
||||||
"@commitlint/cli": "^17.1.2",
|
"@commitlint/cli": "17.1.2",
|
||||||
"@commitlint/config-conventional": "^17.1.0",
|
"@commitlint/config-conventional": "17.1.0",
|
||||||
"@types/d3": "^7.4.0",
|
"@cspell/eslint-plugin": "6.12.0",
|
||||||
"@types/dompurify": "^2.3.4",
|
"@types/d3": "7.4.0",
|
||||||
"@types/eslint": "^8.4.6",
|
"@types/dompurify": "2.3.4",
|
||||||
"@types/express": "^4.17.14",
|
"@types/eslint": "8.4.7",
|
||||||
"@types/jsdom": "^20.0.0",
|
"@types/express": "4.17.14",
|
||||||
"@types/lodash": "^4.14.186",
|
"@types/jsdom": "20.0.0",
|
||||||
"@types/mdast": "^3.0.10",
|
"@types/lodash": "4.14.186",
|
||||||
"@types/prettier": "^2.7.1",
|
"@types/mdast": "3.0.10",
|
||||||
"@types/stylis": "^4.0.2",
|
"@types/prettier": "2.7.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.39.0",
|
"@types/stylis": "4.0.2",
|
||||||
"@typescript-eslint/parser": "^5.39.0",
|
"@typescript-eslint/eslint-plugin": "5.40.1",
|
||||||
"@vitest/coverage-c8": "^0.23.4",
|
"@typescript-eslint/parser": "5.40.1",
|
||||||
"@vitest/ui": "^0.23.4",
|
"@vitest/coverage-c8": "0.24.3",
|
||||||
"concurrently": "^7.4.0",
|
"@vitest/ui": "0.24.3",
|
||||||
"coveralls": "^3.1.1",
|
"concurrently": "7.4.0",
|
||||||
"cypress": "^10.0.0",
|
"coveralls": "3.1.1",
|
||||||
"cypress-image-snapshot": "^4.0.1",
|
"cypress": "10.10.0",
|
||||||
"documentation": "13.2.0",
|
"cypress-image-snapshot": "4.0.1",
|
||||||
"esbuild": "^0.15.10",
|
"documentation": "13.2.5",
|
||||||
"eslint": "^8.24.0",
|
"esbuild": "0.15.12",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint": "8.25.0",
|
||||||
"eslint-plugin-cypress": "^2.12.1",
|
"eslint-config-prettier": "8.5.0",
|
||||||
"eslint-plugin-html": "^7.1.0",
|
"eslint-plugin-cypress": "2.12.1",
|
||||||
"eslint-plugin-jest": "^27.1.0",
|
"eslint-plugin-html": "7.1.0",
|
||||||
"eslint-plugin-jsdoc": "^39.3.6",
|
"eslint-plugin-jest": "27.1.3",
|
||||||
"eslint-plugin-json": "^3.1.0",
|
"eslint-plugin-jsdoc": "39.3.23",
|
||||||
"eslint-plugin-markdown": "^3.0.0",
|
"eslint-plugin-json": "3.1.0",
|
||||||
"express": "^4.18.1",
|
"eslint-plugin-markdown": "3.0.0",
|
||||||
"globby": "^13.1.2",
|
"eslint-plugin-no-only-tests": "3.1.0",
|
||||||
"husky": "^8.0.1",
|
"eslint-plugin-tsdoc": "0.2.17",
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"express": "4.18.2",
|
||||||
"jest": "29.x",
|
"globby": "13.1.2",
|
||||||
"jison": "^0.4.18",
|
"husky": "8.0.1",
|
||||||
"jsdom": "^20.0.1",
|
"identity-obj-proxy": "3.0.0",
|
||||||
"lint-staged": "^13.0.3",
|
"jest": "29.2.1",
|
||||||
"markdown-it": "^13.0.1",
|
"jison": "0.4.18",
|
||||||
"path-browserify": "^1.0.1",
|
"jsdom": "20.0.1",
|
||||||
"pnpm": "^7.13.2",
|
"lint-staged": "13.0.3",
|
||||||
"prettier": "^2.7.1",
|
"markdown-it": "13.0.1",
|
||||||
"prettier-plugin-jsdoc": "^0.4.2",
|
"path-browserify": "1.0.1",
|
||||||
"remark": "^14.0.2",
|
"pnpm": "7.13.6",
|
||||||
"rimraf": "^3.0.2",
|
"prettier": "2.7.1",
|
||||||
"start-server-and-test": "^1.14.0",
|
"prettier-plugin-jsdoc": "0.4.2",
|
||||||
"ts-node": "^10.9.1",
|
"remark": "14.0.2",
|
||||||
"typescript": "^4.8.4",
|
"rimraf": "3.0.2",
|
||||||
"unist-util-flatmap": "^1.0.0",
|
"start-server-and-test": "1.14.0",
|
||||||
"vite": "^3.1.4",
|
"ts-node": "10.9.1",
|
||||||
"vitepress": "^1.0.0-alpha.19",
|
"typescript": "4.8.4",
|
||||||
"vitepress-plugin-mermaid": "^2.0.8",
|
"unist-util-flatmap": "1.0.0",
|
||||||
"vitepress-plugin-search": "^1.0.4-alpha.11",
|
"vite": "3.1.8",
|
||||||
"vitest": "^0.23.4"
|
"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": {
|
"resolutions": {
|
||||||
"d3": "^7.0.0"
|
"d3": "7.6.1"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
@ -50,8 +50,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^7.4.0",
|
"concurrently": "7.4.0",
|
||||||
"rimraf": "^3.0.2"
|
"rimraf": "3.0.2"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"d3": "^7.0.0"
|
"d3": "^7.0.0"
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
export const id = 'example-diagram';
|
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
|
* @returns True if the diagram text matches a diagram of this type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ export const draw = (text, id, version) => {
|
|||||||
log.debug('Rendering example diagram\n' + text, 'Conf: ');
|
log.debug('Rendering example diagram\n' + text, 'Conf: ');
|
||||||
const THEME_COLOR_LIMIT = getConfig().themeVariables.THEME_COLOR_LIMIT;
|
const THEME_COLOR_LIMIT = getConfig().themeVariables.THEME_COLOR_LIMIT;
|
||||||
const securityLevel = getConfig().securityLevel;
|
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;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
sandboxElement = select('#i' + id);
|
||||||
|
@ -35,18 +35,19 @@ export let setupGraphViewbox: (
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called by mermaid that injects utility functions that help the diagram to be a good citizen.
|
* Function called by mermaid that injects utility functions that help the diagram to be a good citizen.
|
||||||
* @param _log
|
*
|
||||||
* @param _setLogLevel
|
* @param _log - log from mermaid/src/diagramAPI.ts
|
||||||
* @param _getConfig
|
* @param _setLogLevel - setLogLevel from mermaid/src/diagramAPI.ts
|
||||||
* @param _sanitizeText
|
* @param _getConfig - getConfig from mermaid/src/diagramAPI.ts
|
||||||
* @param _setupGraphViewbox
|
* @param _sanitizeText - sanitizeText from mermaid/src/diagramAPI.ts
|
||||||
|
* @param _setupGraphViewbox - setupGraphViewbox from mermaid/src/diagramAPI.ts
|
||||||
*/
|
*/
|
||||||
export const injectUtils = (
|
export const injectUtils = (
|
||||||
_log: Record<keyof typeof LEVELS, typeof console.log>,
|
_log: Record<keyof typeof LEVELS, typeof console.log>,
|
||||||
_setLogLevel: any,
|
_setLogLevel: typeof setLogLevel,
|
||||||
_getConfig: any,
|
_getConfig: typeof getConfig,
|
||||||
_sanitizeText: any,
|
_sanitizeText: typeof sanitizeText,
|
||||||
_setupGraphViewbox: any
|
_setupGraphViewbox: typeof setupGraphViewbox
|
||||||
) => {
|
) => {
|
||||||
_log.debug('Mermaid utils injected into example-diagram');
|
_log.debug('Mermaid utils injected into example-diagram');
|
||||||
log.trace = _log.trace;
|
log.trace = _log.trace;
|
||||||
|
@ -57,8 +57,8 @@
|
|||||||
"non-layered-tidy-tree-layout": "^2.0.2"
|
"non-layered-tidy-tree-layout": "^2.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^7.4.0",
|
"concurrently": "7.4.0",
|
||||||
"rimraf": "^3.0.2"
|
"rimraf": "3.0.2"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"d3": "^7.0.0"
|
"d3": "^7.0.0"
|
||||||
|
@ -11,7 +11,7 @@ cytoscape.use(coseBilkent);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {any} svg The svg element to draw the diagram onto
|
* @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 section
|
||||||
* @param {object} conf The configuration object
|
* @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 {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 section
|
||||||
* @param cy
|
* @param cy
|
||||||
* @param {object} conf The configuration object
|
* @param {object} conf The configuration object
|
||||||
@ -96,7 +96,6 @@ function addNodes(mindmap, cy, conf, level) {
|
|||||||
/**
|
/**
|
||||||
* @param node
|
* @param node
|
||||||
* @param conf
|
* @param conf
|
||||||
* @param cy
|
|
||||||
*/
|
*/
|
||||||
function layoutMindmap(node, conf) {
|
function layoutMindmap(node, conf) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@ -121,7 +120,7 @@ function layoutMindmap(node, conf) {
|
|||||||
renderEl.remove();
|
renderEl.remove();
|
||||||
addNodes(node, cy, conf, 0);
|
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) {
|
cy.nodes().forEach(function (n) {
|
||||||
n.layoutDimensions = () => {
|
n.layoutDimensions = () => {
|
||||||
const data = n.data();
|
const data = n.data();
|
||||||
@ -143,10 +142,7 @@ function layoutMindmap(node, conf) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param node
|
|
||||||
* @param cy
|
* @param cy
|
||||||
* @param positionedMindmap
|
|
||||||
* @param conf
|
|
||||||
*/
|
*/
|
||||||
function positionNodes(cy) {
|
function positionNodes(cy) {
|
||||||
cy.nodes().map((node, id) => {
|
cy.nodes().map((node, id) => {
|
||||||
@ -184,7 +180,7 @@ export const draw = async (text, id, version, diagObj) => {
|
|||||||
log.debug('Renering info diagram\n' + text);
|
log.debug('Renering info diagram\n' + text);
|
||||||
|
|
||||||
const securityLevel = getConfig().securityLevel;
|
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;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
sandboxElement = select('#i' + id);
|
||||||
|
@ -22,12 +22,10 @@ const genSections = (options) => {
|
|||||||
}
|
}
|
||||||
.section-${i - 1} text {
|
.section-${i - 1} text {
|
||||||
fill: ${options['cScaleLabel' + i]};
|
fill: ${options['cScaleLabel' + i]};
|
||||||
// fill: ${options['gitInv' + i]};
|
|
||||||
}
|
}
|
||||||
.node-icon-${i - 1} {
|
.node-icon-${i - 1} {
|
||||||
font-size: 40px;
|
font-size: 40px;
|
||||||
color: ${options['cScaleLabel' + i]};
|
color: ${options['cScaleLabel' + i]};
|
||||||
// color: ${options['gitInv' + i]};
|
|
||||||
}
|
}
|
||||||
.section-edge-${i - 1}{
|
.section-edge-${i - 1}{
|
||||||
stroke: ${options['cScale' + i]};
|
stroke: ${options['cScale' + i]};
|
||||||
@ -36,7 +34,7 @@ const genSections = (options) => {
|
|||||||
stroke-width: ${sw};
|
stroke-width: ${sw};
|
||||||
}
|
}
|
||||||
.section-${i - 1} line {
|
.section-${i - 1} line {
|
||||||
stroke: ${options['lineColor' + i]} ;
|
stroke: ${options['cScaleInv' + i]} ;
|
||||||
stroke-width: 3;
|
stroke-width: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,51 +75,51 @@
|
|||||||
"stylis": "^4.1.2"
|
"stylis": "^4.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@applitools/eyes-cypress": "^3.25.7",
|
"@applitools/eyes-cypress": "3.27.5",
|
||||||
"@commitlint/cli": "^17.1.2",
|
"@commitlint/cli": "17.1.2",
|
||||||
"@commitlint/config-conventional": "^17.0.0",
|
"@commitlint/config-conventional": "17.1.0",
|
||||||
"@types/d3": "^7.4.0",
|
"@types/d3": "7.4.0",
|
||||||
"@types/dompurify": "^2.3.4",
|
"@types/dompurify": "2.3.4",
|
||||||
"@types/eslint": "^8.4.6",
|
"@types/eslint": "8.4.7",
|
||||||
"@types/express": "^4.17.13",
|
"@types/express": "4.17.14",
|
||||||
"@types/jsdom": "^20.0.0",
|
"@types/jsdom": "20.0.0",
|
||||||
"@types/lodash": "^4.14.185",
|
"@types/lodash": "4.14.186",
|
||||||
"@types/prettier": "^2.7.0",
|
"@types/prettier": "2.7.1",
|
||||||
"@types/stylis": "^4.0.2",
|
"@types/stylis": "4.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.37.0",
|
"@typescript-eslint/eslint-plugin": "5.40.1",
|
||||||
"@typescript-eslint/parser": "^5.37.0",
|
"@typescript-eslint/parser": "5.40.1",
|
||||||
"concurrently": "^7.4.0",
|
"concurrently": "7.4.0",
|
||||||
"coveralls": "^3.1.1",
|
"coveralls": "3.1.1",
|
||||||
"cypress": "^10.0.0",
|
"cypress": "10.10.0",
|
||||||
"cypress-image-snapshot": "^4.0.1",
|
"cypress-image-snapshot": "4.0.1",
|
||||||
"documentation": "13.2.0",
|
"documentation": "13.2.5",
|
||||||
"esbuild": "^0.15.8",
|
"esbuild": "0.15.12",
|
||||||
"eslint": "^8.23.1",
|
"eslint": "8.25.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "8.5.0",
|
||||||
"eslint-plugin-cypress": "^2.12.1",
|
"eslint-plugin-cypress": "2.12.1",
|
||||||
"eslint-plugin-html": "^7.1.0",
|
"eslint-plugin-html": "7.1.0",
|
||||||
"eslint-plugin-jest": "^27.0.4",
|
"eslint-plugin-jest": "27.1.3",
|
||||||
"eslint-plugin-jsdoc": "^39.3.6",
|
"eslint-plugin-jsdoc": "39.3.23",
|
||||||
"eslint-plugin-json": "^3.1.0",
|
"eslint-plugin-json": "3.1.0",
|
||||||
"eslint-plugin-markdown": "^3.0.0",
|
"eslint-plugin-markdown": "3.0.0",
|
||||||
"express": "^4.18.1",
|
"express": "4.18.2",
|
||||||
"globby": "^13.1.2",
|
"globby": "13.1.2",
|
||||||
"husky": "^8.0.0",
|
"husky": "8.0.1",
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "3.0.0",
|
||||||
"jison": "^0.4.18",
|
"jison": "0.4.18",
|
||||||
"js-base64": "3.7.2",
|
"js-base64": "3.7.2",
|
||||||
"jsdom": "^20.0.0",
|
"jsdom": "20.0.1",
|
||||||
"lint-staged": "^13.0.0",
|
"lint-staged": "13.0.3",
|
||||||
"moment": "^2.23.0",
|
"moment": "2.29.4",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "1.0.1",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "2.7.1",
|
||||||
"prettier-plugin-jsdoc": "^0.4.2",
|
"prettier-plugin-jsdoc": "0.4.2",
|
||||||
"remark": "^14.0.2",
|
"remark": "14.0.2",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "3.0.2",
|
||||||
"start-server-and-test": "^1.12.6",
|
"start-server-and-test": "1.14.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "10.9.1",
|
||||||
"typescript": "^4.8.3",
|
"typescript": "4.8.4",
|
||||||
"unist-util-flatmap": "^1.0.0"
|
"unist-util-flatmap": "1.0.0"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"d3": "^7.0.0"
|
"d3": "^7.0.0"
|
||||||
|
@ -2,15 +2,17 @@ import * as configApi from './config';
|
|||||||
import { log } from './logger';
|
import { log } from './logger';
|
||||||
import { getDiagram, registerDiagram } from './diagram-api/diagramAPI';
|
import { getDiagram, registerDiagram } from './diagram-api/diagramAPI';
|
||||||
import { detectType, getDiagramLoader } from './diagram-api/detectType';
|
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 {
|
export class Diagram {
|
||||||
type = 'graph';
|
type = 'graph';
|
||||||
parser;
|
parser;
|
||||||
renderer;
|
renderer;
|
||||||
db;
|
db;
|
||||||
private detectTypeFailed = false;
|
private detectTypeFailed = false;
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
constructor(public txt: string, parseError?: ParseErrorFunction) {
|
||||||
constructor(public txt: string, parseError?: Function) {
|
|
||||||
const cnf = configApi.getConfig();
|
const cnf = configApi.getConfig();
|
||||||
this.txt = txt;
|
this.txt = txt;
|
||||||
try {
|
try {
|
||||||
@ -37,8 +39,7 @@ export class Diagram {
|
|||||||
this.parse(this.txt, parseError);
|
this.parse(this.txt, parseError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
parse(text: string, parseError?: ParseErrorFunction): boolean {
|
||||||
parse(text: string, parseError?: Function): boolean {
|
|
||||||
if (this.detectTypeFailed) {
|
if (this.detectTypeFailed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -53,23 +54,24 @@ export class Diagram {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
handleError(error: unknown, parseError?: ParseErrorFunction) {
|
||||||
handleError(error: unknown, parseError?: Function) {
|
|
||||||
// Is this the correct way to access mermiad's parseError()
|
// Is this the correct way to access mermiad's parseError()
|
||||||
// method ? (or global.mermaid.parseError()) ?
|
// method ? (or global.mermaid.parseError()) ?
|
||||||
if (parseError) {
|
|
||||||
if (isDetailedError(error)) {
|
if (parseError === undefined) {
|
||||||
// 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 {
|
|
||||||
// No mermaid.parseError() handler defined, so re-throw it
|
// No mermaid.parseError() handler defined, so re-throw it
|
||||||
throw error;
|
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() {
|
getParser() {
|
||||||
@ -81,8 +83,10 @@ export class Diagram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
export const getDiagramFromText = async (
|
||||||
export const getDiagramFromText = async (txt: string, parseError?: Function): Promise<Diagram> => {
|
txt: string,
|
||||||
|
parseError?: ParseErrorFunction
|
||||||
|
): Promise<Diagram> => {
|
||||||
const type = detectType(txt, configApi.getConfig());
|
const type = detectType(txt, configApi.getConfig());
|
||||||
try {
|
try {
|
||||||
// Trying to find the diagram
|
// Trying to find the diagram
|
||||||
|
@ -6,17 +6,13 @@
|
|||||||
import * as configApi from '../config';
|
import * as configApi from '../config';
|
||||||
import { vi } from 'vitest';
|
import { vi } from 'vitest';
|
||||||
import { addDiagrams } from '../diagram-api/diagram-orchestration';
|
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()`
|
// 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.
|
// implementation, however, requireActual returns a promise and it's not documented how to use withing mock file.
|
||||||
|
|
||||||
/**
|
/** {@inheritDoc mermaidAPI.parse} */
|
||||||
* @param text
|
function parse(text: string, parseError?: ParseErrorFunction): boolean {
|
||||||
* @param parseError
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
||||||
function parse(text: string, parseError?: Function): boolean {
|
|
||||||
addDiagrams();
|
addDiagrams();
|
||||||
const diagram = new Diagram(text, parseError);
|
const diagram = new Diagram(text, parseError);
|
||||||
return diagram.parse(text, parseError);
|
return diagram.parse(text, parseError);
|
||||||
|
@ -56,7 +56,7 @@ export const updateCurrentConfig = (siteCfg: MermaidConfig, _directives: any[])
|
|||||||
* function _Default value: At default, will mirror Global Config_
|
* function _Default value: At default, will mirror Global Config_
|
||||||
*
|
*
|
||||||
* @param conf - The base currentConfig to use as siteConfig
|
* @param conf - The base currentConfig to use as siteConfig
|
||||||
* @returns {object} - The siteConfig
|
* @returns The new siteConfig
|
||||||
*/
|
*/
|
||||||
export const setSiteConfig = (conf: MermaidConfig): MermaidConfig => {
|
export const setSiteConfig = (conf: MermaidConfig): MermaidConfig => {
|
||||||
siteConfig = assignWithDepth({}, defaultConfig);
|
siteConfig = assignWithDepth({}, defaultConfig);
|
||||||
@ -91,7 +91,7 @@ export const updateSiteConfig = (conf: MermaidConfig): MermaidConfig => {
|
|||||||
*
|
*
|
||||||
* **Notes**: Returns **any** values in siteConfig.
|
* **Notes**: Returns **any** values in siteConfig.
|
||||||
*
|
*
|
||||||
* @returns {object} - The siteConfig
|
* @returns The siteConfig
|
||||||
*/
|
*/
|
||||||
export const getSiteConfig = (): MermaidConfig => {
|
export const getSiteConfig = (): MermaidConfig => {
|
||||||
return assignWithDepth({}, siteConfig);
|
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
|
* keys. Any values found in conf with key found in siteConfig.secure will be replaced with the
|
||||||
* corresponding siteConfig value.
|
* corresponding siteConfig value.
|
||||||
*
|
*
|
||||||
* @param {any} conf - The potential currentConfig
|
* @param conf - The potential currentConfig
|
||||||
* @returns {any} - The currentConfig merged with the sanitized conf
|
* @returns The currentConfig merged with the sanitized conf
|
||||||
*/
|
*/
|
||||||
export const setConfig = (conf: MermaidConfig): MermaidConfig => {
|
export const setConfig = (conf: MermaidConfig): MermaidConfig => {
|
||||||
// sanitize(conf);
|
// sanitize(conf);
|
||||||
@ -131,7 +131,7 @@ export const setConfig = (conf: MermaidConfig): MermaidConfig => {
|
|||||||
*
|
*
|
||||||
* **Notes**: Returns **any** the currentConfig
|
* **Notes**: Returns **any** the currentConfig
|
||||||
*
|
*
|
||||||
* @returns {any} - The currentConfig
|
* @returns The currentConfig
|
||||||
*/
|
*/
|
||||||
export const getConfig = (): MermaidConfig => {
|
export const getConfig = (): MermaidConfig => {
|
||||||
return assignWithDepth({}, currentConfig);
|
return assignWithDepth({}, currentConfig);
|
||||||
@ -146,7 +146,7 @@ export const getConfig = (): MermaidConfig => {
|
|||||||
* Ensures options parameter does not attempt to override siteConfig secure keys **Notes**: modifies
|
* Ensures options parameter does not attempt to override siteConfig secure keys **Notes**: modifies
|
||||||
* options in-place
|
* options in-place
|
||||||
*
|
*
|
||||||
* @param {any} options - The potential setConfig parameter
|
* @param options - The potential setConfig parameter
|
||||||
*/
|
*/
|
||||||
export const sanitize = (options: any) => {
|
export const sanitize = (options: any) => {
|
||||||
// Checking that options are not in the list of excluded options
|
// 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
|
// 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) => {
|
Object.keys(options).forEach((key) => {
|
||||||
if (typeof options[key] === 'string') {
|
if (typeof options[key] === 'string') {
|
||||||
if (
|
if (
|
||||||
@ -186,7 +186,7 @@ export const sanitize = (options: any) => {
|
|||||||
/**
|
/**
|
||||||
* Pushes in a directive to the configuration
|
* 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) => {
|
export const addDirective = (directive: any) => {
|
||||||
if (directive.fontFamily) {
|
if (directive.fontFamily) {
|
||||||
@ -217,7 +217,8 @@ export const addDirective = (directive: any) => {
|
|||||||
*
|
*
|
||||||
* **Notes**: (default: current siteConfig ) (optional, default `getSiteConfig()`)
|
* **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 => {
|
export const reset = (config = siteConfig): void => {
|
||||||
// Replace current config with siteConfig
|
// Replace current config with siteConfig
|
||||||
|
@ -44,7 +44,9 @@ function addHtmlLabel(node) {
|
|||||||
|
|
||||||
const createLabel = (_vertexText, style, isTitle, isNode) => {
|
const createLabel = (_vertexText, style, isTitle, isNode) => {
|
||||||
let vertexText = _vertexText || '';
|
let vertexText = _vertexText || '';
|
||||||
if (typeof vertexText === 'object') vertexText = vertexText[0];
|
if (typeof vertexText === 'object') {
|
||||||
|
vertexText = vertexText[0];
|
||||||
|
}
|
||||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||||
vertexText = vertexText.replace(/\\n|\n/g, '<br />');
|
vertexText = vertexText.replace(/\\n|\n/g, '<br />');
|
||||||
|
@ -310,7 +310,7 @@ const cutPathAtIntersect = (_points, boundryNode) => {
|
|||||||
// const node = clusterDb[edge.toCluster].node;
|
// const node = clusterDb[edge.toCluster].node;
|
||||||
log.info('abc88 checking point', point, boundryNode);
|
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) {
|
if (!outsideNode(boundryNode, point) && !isInside) {
|
||||||
// First point inside the rect found
|
// First point inside the rect found
|
||||||
// Calc the intersection coord between the point anf the last point outside the rect
|
// 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);
|
log.warn('abc88 outside', point, lastPointOutside);
|
||||||
lastPointOutside = point;
|
lastPointOutside = point;
|
||||||
// points.push(point);
|
// points.push(point);
|
||||||
if (!isInside) points.push(point);
|
if (!isInside) {
|
||||||
|
points.push(point);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
log.warn('abc88 returning points', points);
|
log.warn('abc88 returning points', points);
|
||||||
@ -429,7 +431,7 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
|
|||||||
})
|
})
|
||||||
.curve(curve);
|
.curve(curve);
|
||||||
|
|
||||||
// Contruct stroke classes based on properties
|
// Construct stroke classes based on properties
|
||||||
let strokeClasses;
|
let strokeClasses;
|
||||||
switch (edge.thickness) {
|
switch (edge.thickness) {
|
||||||
case 'normal':
|
case 'normal':
|
||||||
|
@ -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';
|
import node from './intersect-node.js';
|
||||||
|
@ -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
|
// 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.
|
// same side of line 1, the line segments do not intersect.
|
||||||
if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {
|
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
|
// 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
|
// on same side of second line segment, the line segments do
|
||||||
// not intersect.
|
// not intersect.
|
||||||
if (r1 !== 0 && r2 !== 0 && sameSign(r1, r2)) {
|
if (r1 !== 0 && r2 !== 0 && sameSign(r1, r2)) {
|
||||||
return /*DONT_INTERSECT*/;
|
return /*DON'T_INTERSECT*/;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line segments intersect: compute intersection point.
|
// Line segments intersect: compute intersection point.
|
||||||
|
@ -23,7 +23,9 @@ const isDecendant = (id, ancenstorId) => {
|
|||||||
' = ',
|
' = ',
|
||||||
decendants[ancenstorId].indexOf(id) >= 0
|
decendants[ancenstorId].indexOf(id) >= 0
|
||||||
);
|
);
|
||||||
if (decendants[ancenstorId].indexOf(id) >= 0) return true;
|
if (decendants[ancenstorId].indexOf(id) >= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@ -32,19 +34,23 @@ const edgeInCluster = (edge, clusterId) => {
|
|||||||
log.info('Decendants of ', clusterId, ' is ', decendants[clusterId]);
|
log.info('Decendants of ', clusterId, ' is ', decendants[clusterId]);
|
||||||
log.info('Edge is ', edge);
|
log.info('Edge is ', edge);
|
||||||
// Edges to/from the cluster is not in the cluster, they are in the parent
|
// Edges to/from the cluster is not in the cluster, they are in the parent
|
||||||
if (edge.v === clusterId) return false;
|
if (edge.v === clusterId) {
|
||||||
if (edge.w === clusterId) return false;
|
return false;
|
||||||
|
}
|
||||||
|
if (edge.w === clusterId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!decendants[clusterId]) {
|
if (!decendants[clusterId]) {
|
||||||
log.debug('Tilt, ', clusterId, ',not in decendants');
|
log.debug('Tilt, ', clusterId, ',not in decendants');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (decendants[clusterId].indexOf(edge.v) >= 0) return true;
|
return (
|
||||||
if (isDecendant(edge.v, clusterId)) return true;
|
decendants[clusterId].indexOf(edge.v) >= 0 ||
|
||||||
if (isDecendant(edge.w, clusterId)) return true;
|
isDecendant(edge.v, clusterId) ||
|
||||||
if (decendants[clusterId].indexOf(edge.w) >= 0) return true;
|
isDecendant(edge.w, clusterId) ||
|
||||||
|
decendants[clusterId].indexOf(edge.w) >= 0
|
||||||
return false;
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const copy = (clusterId, graph, newGraph, rootId) => {
|
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)
|
// 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) {
|
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) {
|
// if (decendants[id].indexOf(edge.v) < 0 && decendants[id].indexOf(edge.w) < 0) {
|
||||||
|
|
||||||
const d1 = isDecendant(edge.v, id);
|
const d1 = isDecendant(edge.v, id);
|
||||||
@ -306,8 +312,12 @@ export const adjustClustersAndEdges = (graph, depth) => {
|
|||||||
v = getAnchorId(e.v);
|
v = getAnchorId(e.v);
|
||||||
w = getAnchorId(e.w);
|
w = getAnchorId(e.w);
|
||||||
graph.removeEdge(e.v, e.w, e.name);
|
graph.removeEdge(e.v, e.w, e.name);
|
||||||
if (v !== e.v) edge.fromCluster = e.v;
|
if (v !== e.v) {
|
||||||
if (w !== e.w) edge.toCluster = e.w;
|
edge.fromCluster = e.v;
|
||||||
|
}
|
||||||
|
if (w !== e.w) {
|
||||||
|
edge.toCluster = e.w;
|
||||||
|
}
|
||||||
log.warn('Fix Replacing with XXX', v, w, e.name);
|
log.warn('Fix Replacing with XXX', v, w, e.name);
|
||||||
graph.setEdge(v, w, edge, e.name);
|
graph.setEdge(v, w, edge, e.name);
|
||||||
}
|
}
|
||||||
@ -446,7 +456,9 @@ export const extractor = (graph, depth) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const sorter = (graph, nodes) => {
|
const sorter = (graph, nodes) => {
|
||||||
if (nodes.length === 0) return [];
|
if (nodes.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
let result = Object.assign(nodes);
|
let result = Object.assign(nodes);
|
||||||
nodes.forEach((node) => {
|
nodes.forEach((node) => {
|
||||||
const children = graph.children(node);
|
const children = graph.children(node);
|
||||||
|
@ -291,11 +291,15 @@ const cylinder = (parent, node) => {
|
|||||||
(Math.abs(x) == node.width / 2 && Math.abs(pos.y - node.y) > node.height / 2 - ry))
|
(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
|
// 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));
|
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;
|
y = ry - y;
|
||||||
if (point.y - node.y > 0) y = -y;
|
if (point.y - node.y > 0) {
|
||||||
|
y = -y;
|
||||||
|
}
|
||||||
|
|
||||||
pos.y += y;
|
pos.y += y;
|
||||||
}
|
}
|
||||||
|
@ -8,19 +8,27 @@ import { MermaidConfig } from './config.type';
|
|||||||
*
|
*
|
||||||
* These are the default options which can be overridden with the initialization call like so:
|
* These are the default options which can be overridden with the initialization call like so:
|
||||||
*
|
*
|
||||||
* **Example 1:**<pre> mermaid.initialize({ flowchart:{ htmlLabels: false } }); </pre>
|
* **Example 1:**
|
||||||
*
|
*
|
||||||
* **Example 2:**<pre> <script> var config = { startOnLoad:true, flowchart:{ useMaxWidth:true,
|
* ```js
|
||||||
* htmlLabels:true, curve:'cardinal', },
|
* mermaid.initialize({ flowchart:{ htmlLabels: false } });
|
||||||
|
* ```
|
||||||
*
|
*
|
||||||
|
* **Example 2:**
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <script>
|
||||||
|
* var config = {
|
||||||
|
* startOnLoad:true,
|
||||||
|
* flowchart:{ useMaxWidth:true, htmlLabels:true, curve:'cardinal'},
|
||||||
* securityLevel:'loose',
|
* securityLevel:'loose',
|
||||||
*
|
* };
|
||||||
* }; mermaid.initialize(config); </script> </pre>
|
* mermaid.initialize(config);
|
||||||
|
* </script>
|
||||||
|
* ```
|
||||||
*
|
*
|
||||||
* A summary of all options and their defaults is found [here](#mermaidapi-configuration-defaults).
|
* A summary of all options and their defaults is found [here](#mermaidapi-configuration-defaults).
|
||||||
* A description of each option follows below.
|
* A description of each option follows below.
|
||||||
*
|
|
||||||
* @name Configuration
|
|
||||||
*/
|
*/
|
||||||
const config: Partial<MermaidConfig> = {
|
const config: Partial<MermaidConfig> = {
|
||||||
/**
|
/**
|
||||||
@ -30,8 +38,16 @@ const config: Partial<MermaidConfig> = {
|
|||||||
* | --------- | --------------- | ------ | -------- | ---------------------------------------------- |
|
* | --------- | --------------- | ------ | -------- | ---------------------------------------------- |
|
||||||
* | theme | Built in Themes | string | Optional | 'default', 'forest', 'dark', 'neutral', 'null' |
|
* | theme | Built in Themes | string | Optional | 'default', 'forest', 'dark', 'neutral', 'null' |
|
||||||
*
|
*
|
||||||
* **Notes:** To disable any pre-defined mermaid theme, use "null".<pre> "theme": "forest",
|
* **Notes:** To disable any pre-defined mermaid theme, use "null".
|
||||||
* "themeCSS": ".node rect { fill: red; }" </pre>
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* {
|
||||||
|
* "theme": "forest",
|
||||||
|
* "themeCSS": ".node rect { fill: red; }"
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
theme: 'default',
|
theme: 'default',
|
||||||
themeVariables: theme['default'].getThemeVariables(),
|
themeVariables: theme['default'].getThemeVariables(),
|
||||||
@ -119,7 +135,7 @@ const config: Partial<MermaidConfig> = {
|
|||||||
/**
|
/**
|
||||||
* This option controls if the generated ids of nodes in the SVG are generated randomly or based
|
* 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
|
* 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**:
|
* **Notes**:
|
||||||
*
|
*
|
||||||
@ -634,8 +650,8 @@ const config: Partial<MermaidConfig> = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* | Parameter | Description | Type | Required | Values |
|
* | 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:**
|
* **Notes:**
|
||||||
*
|
*
|
||||||
@ -1168,7 +1184,7 @@ const config: Partial<MermaidConfig> = {
|
|||||||
* | --------------- | ----------- | ------- | -------- | ------------------ |
|
* | --------------- | ----------- | ------- | -------- | ------------------ |
|
||||||
* | c4BoundaryInRow | See Notes | Integer | Required | Any Positive Value |
|
* | 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
|
* Default value: 2
|
||||||
*/
|
*/
|
||||||
@ -1833,8 +1849,12 @@ const config: Partial<MermaidConfig> = {
|
|||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config.class) config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
|
if (config.class) {
|
||||||
if (config.gitGraph) config.gitGraph.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
|
config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
|
||||||
|
}
|
||||||
|
if (config.gitGraph) {
|
||||||
|
config.gitGraph.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
|
||||||
|
}
|
||||||
|
|
||||||
const keyify = (obj: any, prefix = ''): string[] =>
|
const keyify = (obj: any, prefix = ''): string[] =>
|
||||||
Object.keys(obj).reduce((res: string[], el): string[] => {
|
Object.keys(obj).reduce((res: string[], el): string[] => {
|
||||||
|
@ -9,8 +9,11 @@ const anyComment = /\s*%%.*\n/gm;
|
|||||||
const detectors: Record<string, DetectorRecord> = {};
|
const detectors: Record<string, DetectorRecord> = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function detectType Detects the type of the graph text. Takes into consideration the possible
|
* Detects the type of the graph text.
|
||||||
* existence of an %%init directive
|
*
|
||||||
|
* Takes into consideration the possible existence of an `%%init` directive
|
||||||
|
*
|
||||||
|
* @param text - The text defining the graph. For example:
|
||||||
*
|
*
|
||||||
* ```mermaid
|
* ```mermaid
|
||||||
* %%{initialize: {"startOnLoad": true, logLevel: "fatal" }}%%
|
* %%{initialize: {"startOnLoad": true, logLevel: "fatal" }}%%
|
||||||
@ -23,13 +26,9 @@ const detectors: Record<string, DetectorRecord> = {};
|
|||||||
* f-->g
|
* f-->g
|
||||||
* g-->h
|
* g-->h
|
||||||
* ```
|
* ```
|
||||||
* @param {string} text The text defining the graph
|
*
|
||||||
* @param {{
|
* @param config - The mermaid config.
|
||||||
* class: { defaultRenderer: string } | undefined;
|
* @returns A graph definition key
|
||||||
* state: { defaultRenderer: string } | undefined;
|
|
||||||
* flowchart: { defaultRenderer: string } | undefined;
|
|
||||||
* }} [config]
|
|
||||||
* @returns {string} A graph definition key
|
|
||||||
*/
|
*/
|
||||||
export const detectType = function (text: string, config?: MermaidConfig): string {
|
export const detectType = function (text: string, config?: MermaidConfig): string {
|
||||||
text = text.replace(directive, '').replace(anyComment, '\n');
|
text = text.replace(directive, '').replace(anyComment, '\n');
|
||||||
|
@ -7,9 +7,9 @@ import { addStylesForDiagram } from '../styles';
|
|||||||
import { DiagramDefinition, DiagramDetector } from './types';
|
import { DiagramDefinition, DiagramDetector } from './types';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Packaging and exposing resources for externa diagrams so that they can import
|
Packaging and exposing resources for external diagrams so that they can import
|
||||||
diagramAPI and have access to selct parts of mermaid common code reqiored to
|
diagramAPI and have access to select parts of mermaid common code required to
|
||||||
create diagrams worling like the internal diagrams.
|
create diagrams working like the internal diagrams.
|
||||||
*/
|
*/
|
||||||
export const log = _log;
|
export const log = _log;
|
||||||
export const setLogLevel = _setLogLevel;
|
export const setLogLevel = _setLogLevel;
|
||||||
|
@ -49,8 +49,9 @@ export const addRel = function (type, from, to, label, techn, descr, sprite, tag
|
|||||||
to === null ||
|
to === null ||
|
||||||
label === undefined ||
|
label === undefined ||
|
||||||
label === null
|
label === null
|
||||||
)
|
) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let rel = {};
|
let rel = {};
|
||||||
const old = rels.find((rel) => rel.from === from && rel.to === to);
|
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
|
//type, alias, label, ?descr, ?sprite, ?tags, $link
|
||||||
export const addPersonOrSystem = function (typeC4Shape, alias, label, descr, sprite, tags, link) {
|
export const addPersonOrSystem = function (typeC4Shape, alias, label, descr, sprite, tags, link) {
|
||||||
// Don't allow label nulling
|
// Don't allow label nulling
|
||||||
if (alias === null || label === null) return;
|
if (alias === null || label === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let personOrSystem = {};
|
let personOrSystem = {};
|
||||||
const old = c4ShapeArray.find((personOrSystem) => personOrSystem.alias === alias);
|
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
|
//type, alias, label, ?techn, ?descr ?sprite, ?tags, $link
|
||||||
export const addContainer = function (typeC4Shape, alias, label, techn, descr, sprite, tags, link) {
|
export const addContainer = function (typeC4Shape, alias, label, techn, descr, sprite, tags, link) {
|
||||||
// Don't allow label nulling
|
// Don't allow label nulling
|
||||||
if (alias === null || label === null) return;
|
if (alias === null || label === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let container = {};
|
let container = {};
|
||||||
const old = c4ShapeArray.find((container) => container.alias === alias);
|
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
|
//type, alias, label, ?techn, ?descr ?sprite, ?tags, $link
|
||||||
export const addComponent = function (typeC4Shape, alias, label, techn, descr, sprite, tags, link) {
|
export const addComponent = function (typeC4Shape, alias, label, techn, descr, sprite, tags, link) {
|
||||||
// Don't allow label nulling
|
// Don't allow label nulling
|
||||||
if (alias === null || label === null) return;
|
if (alias === null || label === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let component = {};
|
let component = {};
|
||||||
const old = c4ShapeArray.find((component) => component.alias === alias);
|
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;
|
// if (parentBoundary === null) return;
|
||||||
|
|
||||||
// Don't allow label nulling
|
// Don't allow label nulling
|
||||||
if (alias === null || label === null) return;
|
if (alias === null || label === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let boundary = {};
|
let boundary = {};
|
||||||
const old = boundarys.find((boundary) => boundary.alias === alias);
|
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;
|
// if (parentBoundary === null) return;
|
||||||
|
|
||||||
// Don't allow label nulling
|
// Don't allow label nulling
|
||||||
if (alias === null || label === null) return;
|
if (alias === null || label === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let boundary = {};
|
let boundary = {};
|
||||||
const old = boundarys.find((boundary) => boundary.alias === alias);
|
const old = boundarys.find((boundary) => boundary.alias === alias);
|
||||||
@ -417,7 +428,9 @@ export const addDeploymentNode = function (
|
|||||||
// if (parentBoundary === null) return;
|
// if (parentBoundary === null) return;
|
||||||
|
|
||||||
// Don't allow label nulling
|
// Don't allow label nulling
|
||||||
if (alias === null || label === null) return;
|
if (alias === null || label === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let boundary = {};
|
let boundary = {};
|
||||||
const old = boundarys.find((boundary) => boundary.alias === alias);
|
const old = boundarys.find((boundary) => boundary.alias === alias);
|
||||||
@ -646,8 +659,12 @@ export const updateLayoutConfig = function (typeC4Shape, c4ShapeInRowParam, c4Bo
|
|||||||
c4BoundaryInRowValue = parseInt(c4BoundaryInRowParam);
|
c4BoundaryInRowValue = parseInt(c4BoundaryInRowParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c4ShapeInRowValue >= 1) c4ShapeInRow = c4ShapeInRowValue;
|
if (c4ShapeInRowValue >= 1) {
|
||||||
if (c4BoundaryInRowValue >= 1) c4BoundaryInRow = c4BoundaryInRowValue;
|
c4ShapeInRow = c4ShapeInRowValue;
|
||||||
|
}
|
||||||
|
if (c4BoundaryInRowValue >= 1) {
|
||||||
|
c4BoundaryInRow = c4BoundaryInRowValue;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getC4ShapeInRow = function () {
|
export const getC4ShapeInRow = function () {
|
||||||
@ -665,11 +682,13 @@ export const getParentBoundaryParse = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getC4ShapeArray = function (parentBoundary) {
|
export const getC4ShapeArray = function (parentBoundary) {
|
||||||
if (parentBoundary === undefined || parentBoundary === null) return c4ShapeArray;
|
if (parentBoundary === undefined || parentBoundary === null) {
|
||||||
else
|
return c4ShapeArray;
|
||||||
|
} else {
|
||||||
return c4ShapeArray.filter((personOrSystem) => {
|
return c4ShapeArray.filter((personOrSystem) => {
|
||||||
return personOrSystem.parentBoundary === parentBoundary;
|
return personOrSystem.parentBoundary === parentBoundary;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
export const getC4Shape = function (alias) {
|
export const getC4Shape = function (alias) {
|
||||||
return c4ShapeArray.find((personOrSystem) => personOrSystem.alias === alias);
|
return c4ShapeArray.find((personOrSystem) => personOrSystem.alias === alias);
|
||||||
@ -679,8 +698,11 @@ export const getC4ShapeKeys = function (parentBoundary) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getBoundarys = function (parentBoundary) {
|
export const getBoundarys = function (parentBoundary) {
|
||||||
if (parentBoundary === undefined || parentBoundary === null) return boundarys;
|
if (parentBoundary === undefined || parentBoundary === null) {
|
||||||
else return boundarys.filter((boundary) => boundary.parentBoundary === parentBoundary);
|
return boundarys;
|
||||||
|
} else {
|
||||||
|
return boundarys.filter((boundary) => boundary.parentBoundary === parentBoundary);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRels = function () {
|
export const getRels = function () {
|
||||||
|
@ -414,7 +414,9 @@ export const drawRels = function (diagram, rels, getC4ShapeObj, diagObj) {
|
|||||||
let relTextWrap = rel.wrap && conf.wrap;
|
let relTextWrap = rel.wrap && conf.wrap;
|
||||||
let relConf = messageFont(conf);
|
let relConf = messageFont(conf);
|
||||||
let diagramType = diagObj.db.getC4Type();
|
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);
|
let textLimitWidth = calculateTextWidth(rel.label.text, relConf);
|
||||||
calcC4ShapeTextWH('label', rel, relTextWrap, relConf, textLimitWidth);
|
calcC4ShapeTextWH('label', rel, relTextWrap, relConf, textLimitWidth);
|
||||||
|
|
||||||
@ -441,20 +443,26 @@ export const drawRels = function (diagram, rels, getC4ShapeObj, diagObj) {
|
|||||||
* @param diagram
|
* @param diagram
|
||||||
* @param parentBoundaryAlias
|
* @param parentBoundaryAlias
|
||||||
* @param parentBounds
|
* @param parentBounds
|
||||||
* @param currentBoundarys
|
* @param currentBoundaries
|
||||||
* @param diagObj
|
* @param diagObj
|
||||||
*/
|
*/
|
||||||
function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentBoundarys, diagObj) {
|
function drawInsideBoundary(
|
||||||
|
diagram,
|
||||||
|
parentBoundaryAlias,
|
||||||
|
parentBounds,
|
||||||
|
currentBoundaries,
|
||||||
|
diagObj
|
||||||
|
) {
|
||||||
let currentBounds = new Bounds(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 =
|
currentBounds.data.widthLimit =
|
||||||
parentBounds.data.widthLimit / Math.min(c4BoundaryInRow, currentBoundarys.length);
|
parentBounds.data.widthLimit / Math.min(c4BoundaryInRow, currentBoundaries.length);
|
||||||
// Math.min(
|
// Math.min(
|
||||||
// conf.width * conf.c4ShapeInRow + conf.c4ShapeMargin * conf.c4ShapeInRow * 2,
|
// 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++) {
|
for (let i = 0; i < currentBoundaries.length; i++) {
|
||||||
let currentBoundary = currentBoundarys[i];
|
let currentBoundary = currentBoundaries[i];
|
||||||
let Y = 0;
|
let Y = 0;
|
||||||
currentBoundary.image = { width: 0, height: 0, Y: 0 };
|
currentBoundary.image = { width: 0, height: 0, Y: 0 };
|
||||||
if (currentBoundary.sprite) {
|
if (currentBoundary.sprite) {
|
||||||
@ -508,13 +516,13 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i == 0 || i % c4BoundaryInRow === 0) {
|
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 _x = parentBounds.data.startx + conf.diagramMarginX;
|
||||||
let _y = parentBounds.data.stopy + conf.diagramMarginY + Y;
|
let _y = parentBounds.data.stopy + conf.diagramMarginY + Y;
|
||||||
|
|
||||||
currentBounds.setData(_x, _x, _y, _y);
|
currentBounds.setData(_x, _x, _y, _y);
|
||||||
} else {
|
} else {
|
||||||
// Calculate the drawing start point of the currentBoundarys.
|
// Calculate the drawing start point of the currentBoundaries.
|
||||||
let _x =
|
let _x =
|
||||||
currentBounds.data.stopx !== currentBounds.data.startx
|
currentBounds.data.stopx !== currentBounds.data.startx
|
||||||
? currentBounds.data.stopx + conf.diagramMarginX
|
? currentBounds.data.stopx + conf.diagramMarginX
|
||||||
@ -540,8 +548,6 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
|
|||||||
|
|
||||||
if (nextCurrentBoundarys.length > 0) {
|
if (nextCurrentBoundarys.length > 0) {
|
||||||
// draw boundary inside currentBoundary
|
// draw boundary inside currentBoundary
|
||||||
// bounds.init();
|
|
||||||
// parentBoundaryWidthLimit = bounds.data.stopx - bounds.startx;
|
|
||||||
drawInsideBoundary(
|
drawInsideBoundary(
|
||||||
diagram,
|
diagram,
|
||||||
parentBoundaryAlias,
|
parentBoundaryAlias,
|
||||||
@ -551,7 +557,9 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
// draw boundary
|
// draw boundary
|
||||||
if (currentBoundary.alias !== 'global') drawBoundary(diagram, currentBoundary, currentBounds);
|
if (currentBoundary.alias !== 'global') {
|
||||||
|
drawBoundary(diagram, currentBoundary, currentBounds);
|
||||||
|
}
|
||||||
parentBounds.data.stopy = Math.max(
|
parentBounds.data.stopy = Math.max(
|
||||||
currentBounds.data.stopy + conf.c4ShapeMargin,
|
currentBounds.data.stopy + conf.c4ShapeMargin,
|
||||||
parentBounds.data.stopy
|
parentBounds.data.stopy
|
||||||
@ -576,7 +584,7 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
|
|||||||
export const draw = function (_text, id, _version, diagObj) {
|
export const draw = function (_text, id, _version, diagObj) {
|
||||||
conf = configApi.getConfig().c4;
|
conf = configApi.getConfig().c4;
|
||||||
const securityLevel = configApi.getConfig().securityLevel;
|
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;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
sandboxElement = select('#i' + id);
|
||||||
@ -616,10 +624,10 @@ export const draw = function (_text, id, _version, diagObj) {
|
|||||||
globalBoundaryMaxY = conf.diagramMarginY;
|
globalBoundaryMaxY = conf.diagramMarginY;
|
||||||
|
|
||||||
const title = diagObj.db.getTitle();
|
const title = diagObj.db.getTitle();
|
||||||
let currentBoundarys = diagObj.db.getBoundarys('');
|
let currentBoundaries = diagObj.db.getBoundarys('');
|
||||||
// switch (c4type) {
|
// switch (c4type) {
|
||||||
// case 'C4Context':
|
// case 'C4Context':
|
||||||
drawInsideBoundary(diagram, '', screenBounds, currentBoundarys, diagObj);
|
drawInsideBoundary(diagram, '', screenBounds, currentBoundaries, diagObj);
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
@ -13,7 +13,9 @@ export const drawRect = function (elem, rectData) {
|
|||||||
rectElem.attr('ry', rectData.ry);
|
rectElem.attr('ry', rectData.ry);
|
||||||
|
|
||||||
if (rectData.attrs !== 'undefined' && rectData.attrs !== null) {
|
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') {
|
if (rectData.class !== 'undefined') {
|
||||||
@ -231,9 +233,12 @@ export const drawRels = (elem, rels, conf) => {
|
|||||||
line.attr('stroke-width', '1');
|
line.attr('stroke-width', '1');
|
||||||
line.attr('stroke', strokeColor);
|
line.attr('stroke', strokeColor);
|
||||||
line.style('fill', 'none');
|
line.style('fill', 'none');
|
||||||
if (rel.type !== 'rel_b') line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
if (rel.type !== 'rel_b') {
|
||||||
if (rel.type === 'birel' || 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)');
|
line.attr('marker-start', 'url(' + url + '#arrowend)');
|
||||||
|
}
|
||||||
i = -1;
|
i = -1;
|
||||||
} else {
|
} else {
|
||||||
let line = relsElem.append('path');
|
let line = relsElem.append('path');
|
||||||
@ -256,10 +261,13 @@ export const drawRels = (elem, rels, conf) => {
|
|||||||
.replaceAll('stopx', rel.endPoint.x)
|
.replaceAll('stopx', rel.endPoint.x)
|
||||||
.replaceAll('stopy', rel.endPoint.y)
|
.replaceAll('stopy', rel.endPoint.y)
|
||||||
);
|
);
|
||||||
if (rel.type !== 'rel_b') line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
if (rel.type !== 'rel_b') {
|
||||||
if (rel.type === 'birel' || 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)');
|
line.attr('marker-start', 'url(' + url + '#arrowend)');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let messageConf = conf.messageFont();
|
let messageConf = conf.messageFont();
|
||||||
_drawTextCandidateFunc(conf)(
|
_drawTextCandidateFunc(conf)(
|
||||||
@ -314,7 +322,9 @@ const drawBoundary = function (elem, boundary, conf) {
|
|||||||
let fontColor = boundary.fontColor ? boundary.fontColor : 'black';
|
let fontColor = boundary.fontColor ? boundary.fontColor : 'black';
|
||||||
|
|
||||||
let attrsValue = { 'stroke-width': 1.0, 'stroke-dasharray': '7.0,7.0' };
|
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 = {
|
let rectData = {
|
||||||
x: boundary.x,
|
x: boundary.x,
|
||||||
y: boundary.y,
|
y: boundary.y,
|
||||||
|
@ -16,6 +16,7 @@ const MERMAID_DOM_ID_PREFIX = 'classid-';
|
|||||||
|
|
||||||
let relations = [];
|
let relations = [];
|
||||||
let classes = {};
|
let classes = {};
|
||||||
|
let notes = [];
|
||||||
let classCounter = 0;
|
let classCounter = 0;
|
||||||
|
|
||||||
let funs = [];
|
let funs = [];
|
||||||
@ -49,7 +50,9 @@ const splitClassNameAndType = function (id) {
|
|||||||
export const addClass = function (id) {
|
export const addClass = function (id) {
|
||||||
let classId = splitClassNameAndType(id);
|
let classId = splitClassNameAndType(id);
|
||||||
// Only add class if not exists
|
// Only add class if not exists
|
||||||
if (typeof classes[classId.className] !== 'undefined') return;
|
if (typeof classes[classId.className] !== 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
classes[classId.className] = {
|
classes[classId.className] = {
|
||||||
id: classId.className,
|
id: classId.className,
|
||||||
@ -82,6 +85,7 @@ export const lookUpDomId = function (id) {
|
|||||||
export const clear = function () {
|
export const clear = function () {
|
||||||
relations = [];
|
relations = [];
|
||||||
classes = {};
|
classes = {};
|
||||||
|
notes = [];
|
||||||
funs = [];
|
funs = [];
|
||||||
funs.push(setupToolTips);
|
funs.push(setupToolTips);
|
||||||
commonClear();
|
commonClear();
|
||||||
@ -98,6 +102,10 @@ export const getRelations = function () {
|
|||||||
return relations;
|
return relations;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getNotes = function () {
|
||||||
|
return notes;
|
||||||
|
};
|
||||||
|
|
||||||
export const addRelation = function (relation) {
|
export const addRelation = function (relation) {
|
||||||
log.debug('Adding relation: ' + JSON.stringify(relation));
|
log.debug('Adding relation: ' + JSON.stringify(relation));
|
||||||
addClass(relation.id1);
|
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) {
|
export const cleanupLabel = function (label) {
|
||||||
if (label.substring(0, 1) === ':') {
|
if (label.substring(0, 1) === ':') {
|
||||||
return common.sanitizeText(label.substr(1).trim(), configApi.getConfig());
|
return common.sanitizeText(label.substr(1).trim(), configApi.getConfig());
|
||||||
@ -185,7 +202,9 @@ export const cleanupLabel = function (label) {
|
|||||||
export const setCssClass = function (ids, className) {
|
export const setCssClass = function (ids, className) {
|
||||||
ids.split(',').forEach(function (_id) {
|
ids.split(',').forEach(function (_id) {
|
||||||
let id = _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') {
|
if (typeof classes[id] !== 'undefined') {
|
||||||
classes[id].cssClasses.push(className);
|
classes[id].cssClasses.push(className);
|
||||||
}
|
}
|
||||||
@ -220,7 +239,9 @@ export const setLink = function (ids, linkStr, target) {
|
|||||||
const config = configApi.getConfig();
|
const config = configApi.getConfig();
|
||||||
ids.split(',').forEach(function (_id) {
|
ids.split(',').forEach(function (_id) {
|
||||||
let id = _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') {
|
if (typeof classes[id] !== 'undefined') {
|
||||||
classes[id].link = utils.formatUrl(linkStr, config);
|
classes[id].link = utils.formatUrl(linkStr, config);
|
||||||
if (config.securityLevel === 'sandbox') {
|
if (config.securityLevel === 'sandbox') {
|
||||||
@ -369,7 +390,9 @@ export default {
|
|||||||
clear,
|
clear,
|
||||||
getClass,
|
getClass,
|
||||||
getClasses,
|
getClasses,
|
||||||
|
getNotes,
|
||||||
addAnnotation,
|
addAnnotation,
|
||||||
|
addNote,
|
||||||
getRelations,
|
getRelations,
|
||||||
addRelation,
|
addRelation,
|
||||||
getDirection,
|
getDirection,
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/types';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const classDetectorV2: DiagramDetector = (txt, config) => {
|
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 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')
|
if (
|
||||||
|
txt.match(/^\s*classDiagram/) !== null &&
|
||||||
|
config?.class?.defaultRenderer === 'dagre-wrapper'
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
// We have not opted to use the new renderer so we should return true if we detect a class diagram
|
// 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;
|
return txt.match(/^\s*classDiagram-v2/) !== null;
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/types';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const classDetector: DiagramDetector = (txt, config) => {
|
export const classDetector: DiagramDetector = (txt, config) => {
|
||||||
// If we have confgured to use dagre-wrapper then we should never return true in this function
|
// 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;
|
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
|
// 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;
|
return txt.match(/^\s*classDiagram/) !== null;
|
||||||
};
|
};
|
||||||
|
@ -529,6 +529,16 @@ foo()
|
|||||||
|
|
||||||
parser.parse(str);
|
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 () {
|
describe('when fetching data from a classDiagram graph it', function () {
|
||||||
|
@ -64,6 +64,7 @@ export const addClasses = function (classes, g, _id, diagObj) {
|
|||||||
// if (evaluate(getConfig().flowchart.htmlLabels)) {
|
// if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||||
// const node = {
|
// const node = {
|
||||||
// label: vertexText.replace(
|
// label: vertexText.replace(
|
||||||
|
// eslint-disable-next-line @cspell/spellchecker
|
||||||
// /fa[lrsb]?:fa-[\w-]+/g,
|
// /fa[lrsb]?:fa-[\w-]+/g,
|
||||||
// s => `<i class='${s.replace(':', ' ')}'></i>`
|
// 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
|
* 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
|
// Fetch the vertices/nodes and edges/links from the parsed graph definition
|
||||||
const classes = diagObj.db.getClasses();
|
const classes = diagObj.db.getClasses();
|
||||||
const relations = diagObj.db.getRelations();
|
const relations = diagObj.db.getRelations();
|
||||||
|
const notes = diagObj.db.getNotes();
|
||||||
|
|
||||||
log.info(relations);
|
log.info(relations);
|
||||||
addClasses(classes, g, id, diagObj);
|
addClasses(classes, g, id, diagObj);
|
||||||
addRelations(relations, g);
|
addRelations(relations, g);
|
||||||
|
addNotes(notes, g, relations.length + 1, classes);
|
||||||
|
|
||||||
// Add custom shapes
|
// Add custom shapes
|
||||||
// flowChartShapes.addToRenderV2(addShape);
|
// flowChartShapes.addToRenderV2(addShape);
|
||||||
|
@ -148,7 +148,7 @@ export const draw = function (text, id, _version, diagObj) {
|
|||||||
log.info('Rendering diagram ' + text);
|
log.info('Rendering diagram ' + text);
|
||||||
|
|
||||||
const securityLevel = getConfig().securityLevel;
|
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;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
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);
|
dagre.layout(g);
|
||||||
g.nodes().forEach(function (v) {
|
g.nodes().forEach(function (v) {
|
||||||
if (typeof v !== 'undefined' && typeof g.node(v) !== 'undefined') {
|
if (typeof v !== 'undefined' && typeof g.node(v) !== 'undefined') {
|
||||||
log.debug('Node ' + v + ': ' + JSON.stringify(g.node(v)));
|
log.debug('Node ' + v + ': ' + JSON.stringify(g.node(v)));
|
||||||
root
|
root
|
||||||
.select('#' + diagObj.db.lookUpDomId(v))
|
.select('#' + (diagObj.db.lookUpDomId(v) || v))
|
||||||
.attr(
|
.attr(
|
||||||
'transform',
|
'transform',
|
||||||
'translate(' +
|
'translate(' +
|
||||||
|
@ -56,6 +56,8 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
|||||||
"callback" return 'CALLBACK';
|
"callback" return 'CALLBACK';
|
||||||
"link" return 'LINK';
|
"link" return 'LINK';
|
||||||
"click" return 'CLICK';
|
"click" return 'CLICK';
|
||||||
|
"note for" return 'NOTE_FOR';
|
||||||
|
"note" return 'NOTE';
|
||||||
"<<" return 'ANNOTATION_START';
|
"<<" return 'ANNOTATION_START';
|
||||||
">>" return 'ANNOTATION_END';
|
">>" return 'ANNOTATION_END';
|
||||||
[~] this.begin("generic");
|
[~] this.begin("generic");
|
||||||
@ -263,6 +265,7 @@ statement
|
|||||||
| annotationStatement
|
| annotationStatement
|
||||||
| clickStatement
|
| clickStatement
|
||||||
| cssClassStatement
|
| cssClassStatement
|
||||||
|
| noteStatement
|
||||||
| directive
|
| directive
|
||||||
| direction
|
| direction
|
||||||
| acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); }
|
| 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} }
|
| 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
|
relation
|
||||||
: relationType lineType relationType { $$={type1:$1,type2:$3,lineType:$2}; }
|
: relationType lineType relationType { $$={type1:$1,type2:$3,lineType:$2}; }
|
||||||
| lineType relationType { $$={type1:'none',type2:$2,lineType:$1}; }
|
| lineType relationType { $$={type1:'none',type2:$2,lineType:$1}; }
|
||||||
@ -351,4 +359,6 @@ alphaNumToken : UNICODE_TEXT | NUM | ALPHA;
|
|||||||
|
|
||||||
classLiteralName : BQUOTE_STR;
|
classLiteralName : BQUOTE_STR;
|
||||||
|
|
||||||
|
noteText : STR;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
@ -80,6 +80,10 @@ g.classGroup line {
|
|||||||
stroke-dasharray: 3;
|
stroke-dasharray: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dotted-line{
|
||||||
|
stroke-dasharray: 1 2;
|
||||||
|
}
|
||||||
|
|
||||||
#compositionStart, .composition {
|
#compositionStart, .composition {
|
||||||
fill: ${options.lineColor} !important;
|
fill: ${options.lineColor} !important;
|
||||||
stroke: ${options.lineColor} !important;
|
stroke: ${options.lineColor} !important;
|
||||||
|
@ -9,13 +9,13 @@ export const drawEdge = function (elem, path, relation, conf, diagObj) {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case diagObj.db.relationType.AGGREGATION:
|
case diagObj.db.relationType.AGGREGATION:
|
||||||
return 'aggregation';
|
return 'aggregation';
|
||||||
case diagObj.db.EXTENSION:
|
case diagObj.db.relationType.EXTENSION:
|
||||||
return 'extension';
|
return 'extension';
|
||||||
case diagObj.db.COMPOSITION:
|
case diagObj.db.relationType.COMPOSITION:
|
||||||
return 'composition';
|
return 'composition';
|
||||||
case diagObj.db.DEPENDENCY:
|
case diagObj.db.relationType.DEPENDENCY:
|
||||||
return 'dependency';
|
return 'dependency';
|
||||||
case diagObj.db.LOLLIPOP:
|
case diagObj.db.relationType.LOLLIPOP:
|
||||||
return 'lollipop';
|
return 'lollipop';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -55,6 +55,9 @@ export const drawEdge = function (elem, path, relation, conf, diagObj) {
|
|||||||
if (relation.relation.lineType == 1) {
|
if (relation.relation.lineType == 1) {
|
||||||
svgPath.attr('class', 'relation dashed-line');
|
svgPath.attr('class', 'relation dashed-line');
|
||||||
}
|
}
|
||||||
|
if (relation.relation.lineType == 10) {
|
||||||
|
svgPath.attr('class', 'relation dotted-line');
|
||||||
|
}
|
||||||
if (relation.relation.type1 !== 'none') {
|
if (relation.relation.type1 !== 'none') {
|
||||||
svgPath.attr(
|
svgPath.attr(
|
||||||
'marker-start',
|
'marker-start',
|
||||||
@ -190,7 +193,9 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
|
|||||||
let isFirst = true;
|
let isFirst = true;
|
||||||
classDef.annotations.forEach(function (member) {
|
classDef.annotations.forEach(function (member) {
|
||||||
const titleText2 = title.append('tspan').text('«' + member + '»');
|
const titleText2 = title.append('tspan').text('«' + member + '»');
|
||||||
if (!isFirst) titleText2.attr('dy', conf.textHeight);
|
if (!isFirst) {
|
||||||
|
titleText2.attr('dy', conf.textHeight);
|
||||||
|
}
|
||||||
isFirst = false;
|
isFirst = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -203,7 +208,9 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
|
|||||||
const classTitle = title.append('tspan').text(classTitleString).attr('class', 'title');
|
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 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;
|
const titleHeight = title.node().getBBox().height;
|
||||||
|
|
||||||
@ -284,6 +291,69 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
|
|||||||
return classInfo;
|
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) {
|
export const parseMember = function (text) {
|
||||||
const fieldRegEx = /^(\+|-|~|#)?(\w+)(~\w+~|\[\])?\s+(\w+) *(\*|\$)?$/;
|
const fieldRegEx = /^(\+|-|~|#)?(\w+)(~\w+~|\[\])?\s+(\w+) *(\*|\$)?$/;
|
||||||
const methodRegEx = /^([+|\-|~|#])?(\w+) *\( *(.*)\) *(\*|\$)? *(\w*[~|[\]]*\s*\w*~?)$/;
|
const methodRegEx = /^([+|\-|~|#])?(\w+) *\( *(.*)\) *(\*|\$)? *(\w*[~|[\]]*\s*\w*~?)$/;
|
||||||
@ -347,7 +417,7 @@ const buildMethodDisplay = function (parsedText) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const buildLegacyDisplay = function (text) {
|
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 displayText = '';
|
||||||
let cssStyle = '';
|
let cssStyle = '';
|
||||||
let memberText = '';
|
let memberText = '';
|
||||||
@ -435,5 +505,6 @@ const parseClassifier = function (classifier) {
|
|||||||
export default {
|
export default {
|
||||||
drawClass,
|
drawClass,
|
||||||
drawEdge,
|
drawEdge,
|
||||||
|
drawNote,
|
||||||
parseMember,
|
parseMember,
|
||||||
};
|
};
|
||||||
|
@ -4,11 +4,13 @@ import { MermaidConfig } from '../../config.type';
|
|||||||
/**
|
/**
|
||||||
* Gets the rows of lines in a string
|
* Gets the rows of lines in a string
|
||||||
*
|
*
|
||||||
* @param {string | undefined} s The string to check the lines for
|
* @param s - The string to check the lines for
|
||||||
* @returns {string[]} The rows in that string
|
* @returns The rows in that string
|
||||||
*/
|
*/
|
||||||
export const getRows = (s?: string): string[] => {
|
export const getRows = (s?: string): string[] => {
|
||||||
if (!s) return [''];
|
if (!s) {
|
||||||
|
return [''];
|
||||||
|
}
|
||||||
const str = breakToPlaceholder(s).replace(/\\n/g, '#br#');
|
const str = breakToPlaceholder(s).replace(/\\n/g, '#br#');
|
||||||
return str.split('#br#');
|
return str.split('#br#');
|
||||||
};
|
};
|
||||||
@ -16,8 +18,8 @@ export const getRows = (s?: string): string[] => {
|
|||||||
/**
|
/**
|
||||||
* Removes script tags from a text
|
* Removes script tags from a text
|
||||||
*
|
*
|
||||||
* @param {string} txt The text to sanitize
|
* @param txt - The text to sanitize
|
||||||
* @returns {string} The safer text
|
* @returns The safer text
|
||||||
*/
|
*/
|
||||||
export const removeScript = (txt: string): string => {
|
export const removeScript = (txt: string): string => {
|
||||||
return DOMPurify.sanitize(txt);
|
return DOMPurify.sanitize(txt);
|
||||||
@ -39,7 +41,9 @@ const sanitizeMore = (text: string, config: MermaidConfig) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const sanitizeText = (text: string, config: MermaidConfig): string => {
|
export const sanitizeText = (text: string, config: MermaidConfig): string => {
|
||||||
if (!text) return text;
|
if (!text) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
if (config.dompurifyConfig) {
|
if (config.dompurifyConfig) {
|
||||||
text = DOMPurify.sanitize(sanitizeMore(text, config), config.dompurifyConfig).toString();
|
text = DOMPurify.sanitize(sanitizeMore(text, config), config.dompurifyConfig).toString();
|
||||||
} else {
|
} else {
|
||||||
@ -52,7 +56,9 @@ export const sanitizeTextOrArray = (
|
|||||||
a: string | string[] | string[][],
|
a: string | string[] | string[][],
|
||||||
config: MermaidConfig
|
config: MermaidConfig
|
||||||
): string | string[] => {
|
): string | string[] => {
|
||||||
if (typeof a === 'string') return sanitizeText(a, config);
|
if (typeof a === 'string') {
|
||||||
|
return sanitizeText(a, config);
|
||||||
|
}
|
||||||
// TODO: Refactor to avoid flat.
|
// TODO: Refactor to avoid flat.
|
||||||
return a.flat().map((x: string) => sanitizeText(x, config));
|
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
|
* Whether or not a text has any line breaks
|
||||||
*
|
*
|
||||||
* @param {string} text The text to test
|
* @param text - The text to test
|
||||||
* @returns {boolean} Whether or not the text has breaks
|
* @returns Whether or not the text has breaks
|
||||||
*/
|
*/
|
||||||
export const hasBreaks = (text: string): boolean => {
|
export const hasBreaks = (text: string): boolean => {
|
||||||
return lineBreakRegex.test(text);
|
return lineBreakRegex.test(text);
|
||||||
@ -72,8 +78,8 @@ export const hasBreaks = (text: string): boolean => {
|
|||||||
/**
|
/**
|
||||||
* Splits on <br> tags
|
* Splits on <br> tags
|
||||||
*
|
*
|
||||||
* @param {string} text Text to split
|
* @param text - Text to split
|
||||||
* @returns {string[]} List of lines as strings
|
* @returns List of lines as strings
|
||||||
*/
|
*/
|
||||||
export const splitBreaks = (text: string): string[] => {
|
export const splitBreaks = (text: string): string[] => {
|
||||||
return text.split(lineBreakRegex);
|
return text.split(lineBreakRegex);
|
||||||
@ -82,8 +88,8 @@ export const splitBreaks = (text: string): string[] => {
|
|||||||
/**
|
/**
|
||||||
* Converts placeholders to line breaks in HTML
|
* Converts placeholders to line breaks in HTML
|
||||||
*
|
*
|
||||||
* @param {string} s HTML with placeholders
|
* @param s - HTML with placeholders
|
||||||
* @returns {string} HTML with breaks instead of placeholders
|
* @returns HTML with breaks instead of placeholders
|
||||||
*/
|
*/
|
||||||
const placeholderToBreak = (s: string): string => {
|
const placeholderToBreak = (s: string): string => {
|
||||||
return s.replace(/#br#/g, '<br/>');
|
return s.replace(/#br#/g, '<br/>');
|
||||||
@ -92,8 +98,8 @@ const placeholderToBreak = (s: string): string => {
|
|||||||
/**
|
/**
|
||||||
* Opposite of `placeholderToBreak`, converts breaks to placeholders
|
* Opposite of `placeholderToBreak`, converts breaks to placeholders
|
||||||
*
|
*
|
||||||
* @param {string} s HTML string
|
* @param s - HTML string
|
||||||
* @returns {string} String with placeholders
|
* @returns String with placeholders
|
||||||
*/
|
*/
|
||||||
const breakToPlaceholder = (s: string): string => {
|
const breakToPlaceholder = (s: string): string => {
|
||||||
return s.replace(lineBreakRegex, '#br#');
|
return s.replace(lineBreakRegex, '#br#');
|
||||||
@ -102,8 +108,8 @@ const breakToPlaceholder = (s: string): string => {
|
|||||||
/**
|
/**
|
||||||
* Gets the current URL
|
* Gets the current URL
|
||||||
*
|
*
|
||||||
* @param {boolean} useAbsolute Whether to return the absolute URL or not
|
* @param useAbsolute - Whether to return the absolute URL or not
|
||||||
* @returns {string} The current URL
|
* @returns The current URL
|
||||||
*/
|
*/
|
||||||
const getUrl = (useAbsolute: boolean): string => {
|
const getUrl = (useAbsolute: boolean): string => {
|
||||||
let url = '';
|
let url = '';
|
||||||
@ -124,8 +130,8 @@ const getUrl = (useAbsolute: boolean): string => {
|
|||||||
/**
|
/**
|
||||||
* Converts a string/boolean into a boolean
|
* Converts a string/boolean into a boolean
|
||||||
*
|
*
|
||||||
* @param {string | boolean} val String or boolean to convert
|
* @param val - String or boolean to convert
|
||||||
* @returns {boolean} The result from the input
|
* @returns The result from the input
|
||||||
*/
|
*/
|
||||||
export const evaluate = (val?: string | boolean): boolean =>
|
export const evaluate = (val?: string | boolean): boolean =>
|
||||||
val === false || ['false', 'null', '0'].includes(String(val).trim().toLowerCase()) ? false : true;
|
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
|
* 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>>"
|
* // returns "Array<Array<string>>"
|
||||||
* parseGenericTypes('Array~Array~string~~');
|
* parseGenericTypes('Array~Array~string~~');
|
||||||
*
|
* ```
|
||||||
* @param {string} text The text to convert
|
* @param text - The text to convert
|
||||||
* @returns {string} The converted string
|
* @returns The converted string
|
||||||
*/
|
*/
|
||||||
export const parseGenericTypes = function (text: string): string {
|
export const parseGenericTypes = function (text: string): string {
|
||||||
let cleanedText = text;
|
let cleanedText = text;
|
||||||
|
@ -357,7 +357,7 @@ const drawEntities = function (svgNode, entities, graph) {
|
|||||||
const rectNode = groupNode
|
const rectNode = groupNode
|
||||||
.insert('rect', '#' + textId)
|
.insert('rect', '#' + textId)
|
||||||
.attr('class', 'er entityBox')
|
.attr('class', 'er entityBox')
|
||||||
.attr('fill', conf.fill)
|
.style('fill', conf.fill)
|
||||||
.attr('fill-opacity', '100%')
|
.attr('fill-opacity', '100%')
|
||||||
.attr('stroke', conf.stroke)
|
.attr('stroke', conf.stroke)
|
||||||
.attr('x', 0)
|
.attr('x', 0)
|
||||||
@ -644,7 +644,7 @@ export const draw = function (text, id, _version, diagObj) {
|
|||||||
// inserted - this represents the insertion point for relationship paths
|
// inserted - this represents the insertion point for relationship paths
|
||||||
const firstEntity = drawEntities(svg, diagObj.db.getEntities(), g);
|
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
|
// Add all the relationships to the graph
|
||||||
const relationships = addRelationships(diagObj.db.getRelationships(), g);
|
const relationships = addRelationships(diagObj.db.getRelationships(), g);
|
||||||
|
@ -36,15 +36,32 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
|||||||
<block>[\n]+ /* nothing */
|
<block>[\n]+ /* nothing */
|
||||||
<block>"}" { this.popState(); return 'BLOCK_STOP'; }
|
<block>"}" { this.popState(); return 'BLOCK_STOP'; }
|
||||||
<block>. return yytext[0];
|
<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';
|
\|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';
|
\}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';
|
\}\| return 'ONE_OR_MORE';
|
||||||
|
"one" return 'ONLY_ONE';
|
||||||
|
"only one" return 'ONLY_ONE';
|
||||||
|
"1" return 'ONLY_ONE';
|
||||||
\|\| return 'ONLY_ONE';
|
\|\| return 'ONLY_ONE';
|
||||||
o\| return 'ZERO_OR_ONE';
|
o\| return 'ZERO_OR_ONE';
|
||||||
o\{ return 'ZERO_OR_MORE';
|
o\{ return 'ZERO_OR_MORE';
|
||||||
\|\{ return 'ONE_OR_MORE';
|
\|\{ return 'ONE_OR_MORE';
|
||||||
\.\. return 'NON_IDENTIFYING';
|
\.\. return 'NON_IDENTIFYING';
|
||||||
\-\- return 'IDENTIFYING';
|
\-\- return 'IDENTIFYING';
|
||||||
|
"to" return 'IDENTIFYING';
|
||||||
|
"optionally to" return 'NON_IDENTIFYING';
|
||||||
\.\- return 'NON_IDENTIFYING';
|
\.\- return 'NON_IDENTIFYING';
|
||||||
\-\. return 'NON_IDENTIFYING';
|
\-\. return 'NON_IDENTIFYING';
|
||||||
[A-Za-z][A-Za-z0-9\-_]* return 'ALPHANUM';
|
[A-Za-z][A-Za-z0-9\-_]* return 'ALPHANUM';
|
||||||
|
@ -532,18 +532,100 @@ describe('when parsing ER diagram it...', function () {
|
|||||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONE_OR_MORE);
|
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 () {
|
it('should represent identifying relationships properly', function () {
|
||||||
erDiagram.parser.parse('erDiagram\nHOUSE ||--|{ ROOM : contains');
|
erDiagram.parser.parse('erDiagram\nHOUSE ||--|{ ROOM : contains');
|
||||||
const rels = erDb.getRelationships();
|
const rels = erDb.getRelationships();
|
||||||
expect(rels[0].relSpec.relType).toBe(erDb.Identification.IDENTIFYING);
|
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 () {
|
it('should represent non-identifying relationships properly', function () {
|
||||||
erDiagram.parser.parse('erDiagram\n PERSON ||..o{ POSSESSION : owns');
|
erDiagram.parser.parse('erDiagram\n PERSON ||..o{ POSSESSION : owns');
|
||||||
const rels = erDb.getRelationships();
|
const rels = erDb.getRelationships();
|
||||||
expect(rels[0].relSpec.relType).toBe(erDb.Identification.NON_IDENTIFYING);
|
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 () {
|
it('should not accept a syntax error', function () {
|
||||||
const doc = 'erDiagram\nA xxx B : has';
|
const doc = 'erDiagram\nA xxx B : has';
|
||||||
expect(() => {
|
expect(() => {
|
||||||
|
@ -8,7 +8,7 @@ let conf = {};
|
|||||||
/**
|
/**
|
||||||
* Merges the value of `conf` with the passed `cnf`
|
* 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) {
|
export const setConf = function (cnf: any) {
|
||||||
conf = { ...conf, ...cnf };
|
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.
|
* Draws a an info picture in the tag with id: id based on the graph definition in text.
|
||||||
*
|
*
|
||||||
* @param text
|
* @param _text - Mermaid graph definition.
|
||||||
* @param {string} id The text for the error
|
* @param id - The text for the error
|
||||||
* @param {string} mermaidVersion The version
|
* @param mermaidVersion - The version
|
||||||
*/
|
*/
|
||||||
export const draw = (text: string, id: string, mermaidVersion: string) => {
|
export const draw = (_text: string, id: string, mermaidVersion: string) => {
|
||||||
try {
|
try {
|
||||||
log.debug('Renering svg for syntax error\n');
|
log.debug('Renering svg for syntax error\n');
|
||||||
|
|
||||||
|
@ -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))
|
(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
|
// 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));
|
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;
|
y = ry - y;
|
||||||
if (point.y - node.y > 0) y = -y;
|
if (point.y - node.y > 0) {
|
||||||
|
y = -y;
|
||||||
|
}
|
||||||
|
|
||||||
pos.y += y;
|
pos.y += y;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,11 @@ export const addVertex = function (_id, text, type, style, classes, dir, props =
|
|||||||
if (typeof dir !== 'undefined') {
|
if (typeof dir !== 'undefined') {
|
||||||
vertices[id].dir = dir;
|
vertices[id].dir = dir;
|
||||||
}
|
}
|
||||||
|
if (typeof vertices[id].props === 'undefined') {
|
||||||
vertices[id].props = props;
|
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;
|
startInfo.type = info.type;
|
||||||
} else {
|
} else {
|
||||||
// x-- xyz --> - not supported
|
// 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;
|
startInfo.type = 'double_' + startInfo.type;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/types';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const flowDetectorV2: DiagramDetector = (txt, config) => {
|
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 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)
|
if (config?.flowchart?.defaultRenderer === 'dagre-wrapper' && txt.match(/^\s*graph/) !== null) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return txt.match(/^\s*flowchart/) !== null;
|
return txt.match(/^\s*flowchart/) !== null;
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/types';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const flowDetector: DiagramDetector = (txt, config) => {
|
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
|
// 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;
|
return txt.match(/^\s*graph/) !== null;
|
||||||
};
|
};
|
||||||
|
@ -2,11 +2,7 @@ import flowDb from '../flowDb';
|
|||||||
import flow from './flow';
|
import flow from './flow';
|
||||||
import filter from 'lodash/filter';
|
import filter from 'lodash/filter';
|
||||||
import { setConfig } from '../../../config';
|
import { setConfig } from '../../../config';
|
||||||
// import DOMPurify from 'dompurify';
|
|
||||||
|
|
||||||
// const domPurify = DOMPurify.createDOMPurify(window);
|
|
||||||
|
|
||||||
// const clean = DOMPurify.sanitize(dirty);
|
|
||||||
setConfig({
|
setConfig({
|
||||||
securityLevel: 'strict',
|
securityLevel: 'strict',
|
||||||
});
|
});
|
||||||
|
@ -153,7 +153,9 @@ export const isInvalidDate = function (date, dateFormat, excludes, includes) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const checkTaskDates = function (task, 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);
|
let startTime = moment(task.startTime, dateFormat, true);
|
||||||
startTime.add(1, 'd');
|
startTime.add(1, 'd');
|
||||||
let endTime = moment(task.endTime, dateFormat, true);
|
let endTime = moment(task.endTime, dateFormat, true);
|
||||||
@ -229,7 +231,7 @@ const getStartDate = function (prevTime, dateFormat, str) {
|
|||||||
* Parse a string as a moment duration.
|
* Parse a string as a moment duration.
|
||||||
*
|
*
|
||||||
* The string have to be compound by a value and a shorthand duration unit. For example `5d`
|
* 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:
|
* Shorthand unit supported are:
|
||||||
*
|
*
|
||||||
|
@ -27,7 +27,7 @@ export const draw = function (text, id, version, diagObj) {
|
|||||||
// parser.parse(text);
|
// parser.parse(text);
|
||||||
|
|
||||||
const securityLevel = getConfig().securityLevel;
|
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;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
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 maxTime = tasks.reduce((max, { endTime }) => (max ? Math.max(max, endTime) : endTime), 0);
|
||||||
const dateFormat = diagObj.db.getDateFormat();
|
const dateFormat = diagObj.db.getDateFormat();
|
||||||
if (!minTime || !maxTime) return;
|
if (!minTime || !maxTime) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const excludeRanges = [];
|
const excludeRanges = [];
|
||||||
let range = null;
|
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');
|
const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||||
tspan.setAttribute('alignment-baseline', 'central');
|
tspan.setAttribute('alignment-baseline', 'central');
|
||||||
tspan.setAttribute('x', '10');
|
tspan.setAttribute('x', '10');
|
||||||
if (j > 0) tspan.setAttribute('dy', '1em');
|
if (j > 0) {
|
||||||
|
tspan.setAttribute('dy', '1em');
|
||||||
|
}
|
||||||
tspan.textContent = rows[j];
|
tspan.textContent = rows[j];
|
||||||
svgLabel.appendChild(tspan);
|
svgLabel.appendChild(tspan);
|
||||||
}
|
}
|
||||||
|
@ -65,17 +65,6 @@ describe('when parsing a gantt diagram it', function () {
|
|||||||
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
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 () {
|
it('should handle a task definition', function () {
|
||||||
const str =
|
const str =
|
||||||
'gantt\n' +
|
'gantt\n' +
|
||||||
|
@ -39,6 +39,7 @@ export const parseDirective = function (statement, context, type) {
|
|||||||
// * @param currentCommit
|
// * @param currentCommit
|
||||||
// * @param otherCommit
|
// * @param otherCommit
|
||||||
// */
|
// */
|
||||||
|
// eslint-disable-next-line @cspell/spellchecker
|
||||||
// function isfastforwardable(currentCommit, otherCommit) {
|
// function isfastforwardable(currentCommit, otherCommit) {
|
||||||
// log.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id);
|
// log.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id);
|
||||||
// let cnt = 0;
|
// let cnt = 0;
|
||||||
@ -384,21 +385,23 @@ export const checkout = function (branch) {
|
|||||||
/**
|
/**
|
||||||
* @param arr
|
* @param arr
|
||||||
* @param key
|
* @param key
|
||||||
* @param newval
|
* @param newVal
|
||||||
*/
|
*/
|
||||||
function upsert(arr, key, newval) {
|
function upsert(arr, key, newVal) {
|
||||||
const index = arr.indexOf(key);
|
const index = arr.indexOf(key);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
arr.push(newval);
|
arr.push(newVal);
|
||||||
} else {
|
} else {
|
||||||
arr.splice(index, 1, newval);
|
arr.splice(index, 1, newVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param commitArr */
|
/** @param commitArr */
|
||||||
function prettyPrintCommitHistory(commitArr) {
|
function prettyPrintCommitHistory(commitArr) {
|
||||||
const commit = commitArr.reduce((out, commit) => {
|
const commit = commitArr.reduce((out, commit) => {
|
||||||
if (out.seq > commit.seq) return out;
|
if (out.seq > commit.seq) {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
return commit;
|
return commit;
|
||||||
}, commitArr[0]);
|
}, commitArr[0]);
|
||||||
let line = '';
|
let line = '';
|
||||||
@ -411,7 +414,9 @@ function prettyPrintCommitHistory(commitArr) {
|
|||||||
});
|
});
|
||||||
const label = [line, commit.id, commit.seq];
|
const label = [line, commit.id, commit.seq];
|
||||||
for (let branch in branches) {
|
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(' '));
|
log.debug(label.join(' '));
|
||||||
if (commit.parents && commit.parents.length == 2) {
|
if (commit.parents && commit.parents.length == 2) {
|
||||||
@ -451,7 +456,9 @@ export const clear = function () {
|
|||||||
export const getBranchesAsObjArray = function () {
|
export const getBranchesAsObjArray = function () {
|
||||||
const branchesArray = Object.values(branchesConfig)
|
const branchesArray = Object.values(branchesConfig)
|
||||||
.map((branchConfig, i) => {
|
.map((branchConfig, i) => {
|
||||||
if (branchConfig.order !== null) return branchConfig;
|
if (branchConfig.order !== null) {
|
||||||
|
return branchConfig;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...branchConfig,
|
...branchConfig,
|
||||||
order: parseFloat(`0.${i}`, 10),
|
order: parseFloat(`0.${i}`, 10),
|
||||||
|
@ -218,18 +218,18 @@ function cloneNode(svg, selector) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param svg
|
* @param svg
|
||||||
* @param commitid
|
* @param commitId
|
||||||
* @param branches
|
* @param branches
|
||||||
* @param direction
|
* @param direction
|
||||||
*/
|
*/
|
||||||
function renderCommitHistory(svg, commitid, branches, direction) {
|
function renderCommitHistory(svg, commitId, branches, direction) {
|
||||||
let commit;
|
let commit;
|
||||||
const numCommits = Object.keys(allCommitsDict).length;
|
const numCommits = Object.keys(allCommitsDict).length;
|
||||||
if (typeof commitid === 'string') {
|
if (typeof commitId === 'string') {
|
||||||
do {
|
do {
|
||||||
commit = allCommitsDict[commitid];
|
commit = allCommitsDict[commitId];
|
||||||
logger.debug('in renderCommitHistory', commit.id, commit.seq);
|
logger.debug('in renderCommitHistory', commit.id, commit.seq);
|
||||||
if (svg.select('#node-' + commitid).size() > 0) {
|
if (svg.select('#node-' + commitId).size() > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
svg
|
svg
|
||||||
@ -291,15 +291,15 @@ function renderCommitHistory(svg, commitid, branches, direction) {
|
|||||||
.attr('class', 'commit-msg')
|
.attr('class', 'commit-msg')
|
||||||
.text(', ' + commit.message);
|
.text(', ' + commit.message);
|
||||||
}
|
}
|
||||||
commitid = commit.parent;
|
commitId = commit.parent;
|
||||||
} while (commitid && allCommitsDict[commitid]);
|
} while (commitId && allCommitsDict[commitId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(commitid)) {
|
if (Array.isArray(commitId)) {
|
||||||
logger.debug('found merge commmit', commitid);
|
logger.debug('found merge commmit', commitId);
|
||||||
renderCommitHistory(svg, commitid[0], branches, direction);
|
renderCommitHistory(svg, commitId[0], branches, direction);
|
||||||
branchNum++;
|
branchNum++;
|
||||||
renderCommitHistory(svg, commitid[1], branches, direction);
|
renderCommitHistory(svg, commitId[1], branches, direction);
|
||||||
branchNum--;
|
branchNum--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -357,7 +357,9 @@ export const draw = function (txt, id, ver) {
|
|||||||
branchNum++;
|
branchNum++;
|
||||||
}
|
}
|
||||||
svg.attr('height', function () {
|
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;
|
return (branches.length + 1) * config.branchOffset;
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -496,7 +496,7 @@ const drawBranches = (svg, branches) => {
|
|||||||
export const draw = function (txt, id, ver, diagObj) {
|
export const draw = function (txt, id, ver, diagObj) {
|
||||||
clear();
|
clear();
|
||||||
const conf = getConfig();
|
const conf = getConfig();
|
||||||
const gitGraphConfig = getConfig().gitGraph;
|
const gitGraphConfig = conf.gitGraph;
|
||||||
// try {
|
// try {
|
||||||
log.debug('in gitgraph renderer', txt + '\n', 'id:', id, ver);
|
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);
|
drawCommits(diagram, allCommitsDict, true);
|
||||||
|
|
||||||
// Setup the view box and size of the svg element
|
// 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 {
|
export default {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { getConfig } from '../../config';
|
import { getConfig } from '../../config';
|
||||||
|
|
||||||
export default (dir, _branches, _commits) => {
|
export default (dir, _branches) => {
|
||||||
const config = getConfig().gitGraph;
|
const config = getConfig().gitGraph;
|
||||||
const branches = [];
|
const branches = [];
|
||||||
const commits = [];
|
const commits = [];
|
||||||
|
@ -9,16 +9,15 @@ import { getConfig } from '../../config';
|
|||||||
* @param {any} text
|
* @param {any} text
|
||||||
* @param {any} id
|
* @param {any} id
|
||||||
* @param {any} version
|
* @param {any} version
|
||||||
* @param diagObj
|
|
||||||
*/
|
*/
|
||||||
export const draw = (text, id, version, diagObj) => {
|
export const draw = (text, id, version) => {
|
||||||
try {
|
try {
|
||||||
// const parser = infoParser.parser;
|
// const parser = infoParser.parser;
|
||||||
// parser.yy = db;
|
// parser.yy = db;
|
||||||
log.debug('Rendering info diagram\n' + text);
|
log.debug('Rendering info diagram\n' + text);
|
||||||
|
|
||||||
const securityLevel = getConfig().securityLevel;
|
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;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
sandboxElement = select('#i' + id);
|
||||||
|
@ -21,7 +21,7 @@ export const draw = (txt, id, _version, diagObj) => {
|
|||||||
log.debug('Rendering info diagram\n' + txt);
|
log.debug('Rendering info diagram\n' + txt);
|
||||||
|
|
||||||
const securityLevel = configApi.getConfig().securityLevel;
|
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;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
sandboxElement = select('#i' + id);
|
||||||
@ -94,10 +94,22 @@ export const draw = (txt, id, _version, diagObj) => {
|
|||||||
var color = scaleOrdinal().range(myGeneratedColors);
|
var color = scaleOrdinal().range(myGeneratedColors);
|
||||||
|
|
||||||
// Compute the position of each group on the pie:
|
// Compute the position of each group on the pie:
|
||||||
var pie = d3pie().value(function (d) {
|
var pieData = Object.entries(data).map(function (el, idx) {
|
||||||
return d[1];
|
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:
|
// Shape helper to build arcs:
|
||||||
var arcGenerator = arc().innerRadius(0).outerRadius(radius);
|
var arcGenerator = arc().innerRadius(0).outerRadius(radius);
|
||||||
@ -110,7 +122,7 @@ export const draw = (txt, id, _version, diagObj) => {
|
|||||||
.append('path')
|
.append('path')
|
||||||
.attr('d', arcGenerator)
|
.attr('d', arcGenerator)
|
||||||
.attr('fill', function (d) {
|
.attr('fill', function (d) {
|
||||||
return color(d.data[0]);
|
return color(d.data.name);
|
||||||
})
|
})
|
||||||
.attr('class', 'pieCircle');
|
.attr('class', 'pieCircle');
|
||||||
|
|
||||||
@ -122,7 +134,7 @@ export const draw = (txt, id, _version, diagObj) => {
|
|||||||
.enter()
|
.enter()
|
||||||
.append('text')
|
.append('text')
|
||||||
.text(function (d) {
|
.text(function (d) {
|
||||||
return ((d.data[1] / sum) * 100).toFixed(0) + '%';
|
return ((d.data.value / sum) * 100).toFixed(0) + '%';
|
||||||
})
|
})
|
||||||
.attr('transform', function (d) {
|
.attr('transform', function (d) {
|
||||||
return 'translate(' + arcGenerator.centroid(d) + ')';
|
return 'translate(' + arcGenerator.centroid(d) + ')';
|
||||||
@ -166,9 +178,9 @@ export const draw = (txt, id, _version, diagObj) => {
|
|||||||
.attr('y', legendRectSize - legendSpacing)
|
.attr('y', legendRectSize - legendSpacing)
|
||||||
.text(function (d) {
|
.text(function (d) {
|
||||||
if (diagObj.db.getShowData() || conf.showData || conf.pie.showData) {
|
if (diagObj.db.getShowData() || conf.showData || conf.pie.showData) {
|
||||||
return d.data[0] + ' [' + d.data[1] + ']';
|
return d.data.name + ' [' + d.data.value + ']';
|
||||||
} else {
|
} else {
|
||||||
return d.data[0];
|
return d.data.name;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -311,7 +311,7 @@ export const draw = (text, id, _version, diagObj) => {
|
|||||||
diagObj.parser.parse(text);
|
diagObj.parser.parse(text);
|
||||||
|
|
||||||
const securityLevel = conf.securityLevel;
|
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;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
sandboxElement = select('#i' + id);
|
||||||
|
@ -26,7 +26,9 @@ export const parseDirective = function (statement, context, type) {
|
|||||||
export const addActor = function (id, name, description, type) {
|
export const addActor = function (id, name, description, type) {
|
||||||
// Don't allow description nulling
|
// Don't allow description nulling
|
||||||
const old = actors[id];
|
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
|
// Don't allow null descriptions, either
|
||||||
if (description == null || description.text == null) {
|
if (description == null || description.text == null) {
|
||||||
|
@ -10,6 +10,7 @@ import assignWithDepth from '../../assignWithDepth';
|
|||||||
import utils from '../../utils';
|
import utils from '../../utils';
|
||||||
import { configureSvgSize } from '../../setupGraphViewbox';
|
import { configureSvgSize } from '../../setupGraphViewbox';
|
||||||
import addSVGAccessibilityFields from '../../accessibility';
|
import addSVGAccessibilityFields from '../../accessibility';
|
||||||
|
import Diagram from '../../Diagram';
|
||||||
|
|
||||||
let conf = {};
|
let conf = {};
|
||||||
|
|
||||||
@ -100,8 +101,8 @@ export const bounds = {
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
const _self = this;
|
const _self = this;
|
||||||
let cnt = 0;
|
let cnt = 0;
|
||||||
/** @param {any} type */
|
/** @param type - Either `activation` or `undefined` */
|
||||||
function updateFn(type) {
|
function updateFn(type?: 'activation') {
|
||||||
return function updateItemBounds(item) {
|
return function updateItemBounds(item) {
|
||||||
cnt++;
|
cnt++;
|
||||||
// The loop sequenceItems is a stack so the biggest margins in the beginning of the sequenceItems
|
// 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
|
* Draws an note in the diagram with the attached line
|
||||||
*
|
*
|
||||||
* @param {any} elem - The diagram to draw to.
|
* @param elem - The diagram to draw to.
|
||||||
* @param {{ x: number; y: number; message: string; width: number }} noteModel - Startx: x axis
|
* @param noteModel - Note model options.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
const drawNote = function (elem, noteModel) {
|
const drawNote = function (elem: any, noteModel: NoteModel) {
|
||||||
bounds.bumpVerticalPos(conf.boxMargin);
|
bounds.bumpVerticalPos(conf.boxMargin);
|
||||||
noteModel.height = conf.boxMargin;
|
noteModel.height = conf.boxMargin;
|
||||||
noteModel.starty = bounds.getVerticalPos();
|
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
|
* 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.
|
* be on top of the activation box.
|
||||||
*
|
*
|
||||||
* @param {any} diagram - The parent of the message element
|
* @param _diagram - The parent of the message element.
|
||||||
* @param {any} msgModel - The model containing fields describing a message
|
* @param msgModel - The model containing fields describing a message
|
||||||
* @returns {number} LineStarty - The Y coordinate at which the message line starts
|
* @returns `lineStartY` - The Y coordinate at which the message line starts
|
||||||
*/
|
*/
|
||||||
const boundMessage = function (diagram, msgModel) {
|
function boundMessage(_diagram, msgModel): number {
|
||||||
bounds.bumpVerticalPos(10);
|
bounds.bumpVerticalPos(10);
|
||||||
const { startx, stopx, message } = msgModel;
|
const { startx, stopx, message } = msgModel;
|
||||||
const lines = common.splitBreaks(message).length;
|
const lines = common.splitBreaks(message).length;
|
||||||
@ -292,15 +303,15 @@ const boundMessage = function (diagram, msgModel) {
|
|||||||
|
|
||||||
bounds.bumpVerticalPos(lineHeight);
|
bounds.bumpVerticalPos(lineHeight);
|
||||||
|
|
||||||
let lineStarty;
|
let lineStartY;
|
||||||
let totalOffset = textDims.height - 10;
|
let totalOffset = textDims.height - 10;
|
||||||
const textWidth = textDims.width;
|
const textWidth = textDims.width;
|
||||||
|
|
||||||
if (startx === stopx) {
|
if (startx === stopx) {
|
||||||
lineStarty = bounds.getVerticalPos() + totalOffset;
|
lineStartY = bounds.getVerticalPos() + totalOffset;
|
||||||
if (!conf.rightAngles) {
|
if (!conf.rightAngles) {
|
||||||
totalOffset += conf.boxMargin;
|
totalOffset += conf.boxMargin;
|
||||||
lineStarty = bounds.getVerticalPos() + totalOffset;
|
lineStartY = bounds.getVerticalPos() + totalOffset;
|
||||||
}
|
}
|
||||||
totalOffset += 30;
|
totalOffset += 30;
|
||||||
const dx = Math.max(textWidth / 2, conf.width / 2);
|
const dx = Math.max(textWidth / 2, conf.width / 2);
|
||||||
@ -312,26 +323,26 @@ const boundMessage = function (diagram, msgModel) {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
totalOffset += conf.boxMargin;
|
totalOffset += conf.boxMargin;
|
||||||
lineStarty = bounds.getVerticalPos() + totalOffset;
|
lineStartY = bounds.getVerticalPos() + totalOffset;
|
||||||
bounds.insert(startx, lineStarty - 10, stopx, lineStarty);
|
bounds.insert(startx, lineStartY - 10, stopx, lineStartY);
|
||||||
}
|
}
|
||||||
bounds.bumpVerticalPos(totalOffset);
|
bounds.bumpVerticalPos(totalOffset);
|
||||||
msgModel.height += totalOffset;
|
msgModel.height += totalOffset;
|
||||||
msgModel.stopy = msgModel.starty + msgModel.height;
|
msgModel.stopy = msgModel.starty + msgModel.height;
|
||||||
bounds.insert(msgModel.fromBounds, msgModel.starty, msgModel.toBounds, msgModel.stopy);
|
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.
|
* Draws a message. Note that the bounds have previously been updated by boundMessage.
|
||||||
*
|
*
|
||||||
* @param {any} diagram - The parent of the message element
|
* @param diagram - The parent of the message element
|
||||||
* @param {any} msgModel - The model containing fields describing a message
|
* @param msgModel - The model containing fields describing a message
|
||||||
* @param {number} lineStarty - The Y coordinate at which the message line starts
|
* @param lineStartY - The Y coordinate at which the message line starts
|
||||||
* @param diagObj
|
* @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 { startx, stopx, starty, message, type, sequenceIndex, sequenceVisible } = msgModel;
|
||||||
const textDims = utils.calculateTextDimensions(message, messageFont(conf));
|
const textDims = utils.calculateTextDimensions(message, messageFont(conf));
|
||||||
const textObj = svgDraw.getTextObj();
|
const textObj = svgDraw.getTextObj();
|
||||||
@ -360,8 +371,8 @@ const drawMessage = function (diagram, msgModel, lineStarty, diagObj) {
|
|||||||
.append('path')
|
.append('path')
|
||||||
.attr(
|
.attr(
|
||||||
'd',
|
'd',
|
||||||
`M ${startx},${lineStarty} H ${startx + Math.max(conf.width / 2, textWidth / 2)} V ${
|
`M ${startx},${lineStartY} H ${startx + Math.max(conf.width / 2, textWidth / 2)} V ${
|
||||||
lineStarty + 25
|
lineStartY + 25
|
||||||
} H ${startx}`
|
} H ${startx}`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -372,27 +383,27 @@ const drawMessage = function (diagram, msgModel, lineStarty, diagObj) {
|
|||||||
'M ' +
|
'M ' +
|
||||||
startx +
|
startx +
|
||||||
',' +
|
',' +
|
||||||
lineStarty +
|
lineStartY +
|
||||||
' C ' +
|
' C ' +
|
||||||
(startx + 60) +
|
(startx + 60) +
|
||||||
',' +
|
',' +
|
||||||
(lineStarty - 10) +
|
(lineStartY - 10) +
|
||||||
' ' +
|
' ' +
|
||||||
(startx + 60) +
|
(startx + 60) +
|
||||||
',' +
|
',' +
|
||||||
(lineStarty + 30) +
|
(lineStartY + 30) +
|
||||||
' ' +
|
' ' +
|
||||||
startx +
|
startx +
|
||||||
',' +
|
',' +
|
||||||
(lineStarty + 20)
|
(lineStartY + 20)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
line = diagram.append('line');
|
line = diagram.append('line');
|
||||||
line.attr('x1', startx);
|
line.attr('x1', startx);
|
||||||
line.attr('y1', lineStarty);
|
line.attr('y1', lineStartY);
|
||||||
line.attr('x2', stopx);
|
line.attr('x2', stopx);
|
||||||
line.attr('y2', lineStarty);
|
line.attr('y2', lineStartY);
|
||||||
}
|
}
|
||||||
// Make an SVG Container
|
// Make an SVG Container
|
||||||
// Draw the line
|
// Draw the line
|
||||||
@ -440,7 +451,7 @@ const drawMessage = function (diagram, msgModel, lineStarty, diagObj) {
|
|||||||
diagram
|
diagram
|
||||||
.append('text')
|
.append('text')
|
||||||
.attr('x', startx)
|
.attr('x', startx)
|
||||||
.attr('y', lineStarty + 4)
|
.attr('y', lineStartY + 4)
|
||||||
.attr('font-family', 'sans-serif')
|
.attr('font-family', 'sans-serif')
|
||||||
.attr('font-size', '12px')
|
.attr('font-size', '12px')
|
||||||
.attr('text-anchor', 'middle')
|
.attr('text-anchor', 'middle')
|
||||||
@ -554,13 +565,6 @@ const activationBounds = function (actor, actors) {
|
|||||||
return [left, right];
|
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) {
|
function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoopFn) {
|
||||||
bounds.bumpVerticalPos(preMargin);
|
bounds.bumpVerticalPos(preMargin);
|
||||||
let heightAdjust = postMargin;
|
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.
|
* 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 _text - The text of the diagram
|
||||||
* @param {any} id The id of the diagram which will be used as a DOM element id¨
|
* @param id - The id of the diagram which will be used as a DOM element id¨
|
||||||
* @param {any} _version Mermaid version from package.json
|
* @param _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 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();
|
const { securityLevel, sequence } = configApi.getConfig();
|
||||||
conf = sequence;
|
conf = sequence;
|
||||||
// Handle root and Document for when rendering in sanbox mode
|
// Handle root and Document for when rendering in sandbox mode
|
||||||
let sandboxElement;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
sandboxElement = select('#i' + id);
|
||||||
@ -632,10 +636,10 @@ export const draw = function (_text, id, _version, diagObj) {
|
|||||||
svgDraw.insertSequenceNumber(diagram);
|
svgDraw.insertSequenceNumber(diagram);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {any} msg
|
* @param msg - The message to draw.
|
||||||
* @param {any} verticalPos
|
* @param verticalPos - The vertical position of the message.
|
||||||
*/
|
*/
|
||||||
function activeEnd(msg, verticalPos) {
|
function activeEnd(msg: any, verticalPos: number) {
|
||||||
const activationData = bounds.endActivation(msg);
|
const activationData = bounds.endActivation(msg);
|
||||||
if (activationData.starty + 18 > verticalPos) {
|
if (activationData.starty + 18 > verticalPos) {
|
||||||
activationData.starty = verticalPos - 6;
|
activationData.starty = verticalPos - 6;
|
||||||
@ -762,8 +766,11 @@ export const draw = function (_text, id, _version, diagObj) {
|
|||||||
case diagObj.db.LINETYPE.AUTONUMBER:
|
case diagObj.db.LINETYPE.AUTONUMBER:
|
||||||
sequenceIndex = msg.message.start || sequenceIndex;
|
sequenceIndex = msg.message.start || sequenceIndex;
|
||||||
sequenceIndexStep = msg.message.step || sequenceIndexStep;
|
sequenceIndexStep = msg.message.step || sequenceIndexStep;
|
||||||
if (msg.message.visible) diagObj.db.enableSequenceNumbers();
|
if (msg.message.visible) {
|
||||||
else diagObj.db.disableSequenceNumbers();
|
diagObj.db.enableSequenceNumbers();
|
||||||
|
} else {
|
||||||
|
diagObj.db.disableSequenceNumbers();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case diagObj.db.LINETYPE.CRITICAL_START:
|
case diagObj.db.LINETYPE.CRITICAL_START:
|
||||||
adjustLoopHeightForWrap(
|
adjustLoopHeightForWrap(
|
||||||
@ -811,8 +818,8 @@ export const draw = function (_text, id, _version, diagObj) {
|
|||||||
msgModel.starty = bounds.getVerticalPos();
|
msgModel.starty = bounds.getVerticalPos();
|
||||||
msgModel.sequenceIndex = sequenceIndex;
|
msgModel.sequenceIndex = sequenceIndex;
|
||||||
msgModel.sequenceVisible = diagObj.db.showSequenceNumbers();
|
msgModel.sequenceVisible = diagObj.db.showSequenceNumbers();
|
||||||
const lineStarty = boundMessage(diagram, msgModel);
|
const lineStartY = boundMessage(diagram, msgModel);
|
||||||
messagesToDraw.push({ messageModel: msgModel, lineStarty: lineStarty });
|
messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY });
|
||||||
bounds.models.addMessage(msgModel);
|
bounds.models.addMessage(msgModel);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error('error while drawing message', 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) {
|
if (conf.mirrorActors) {
|
||||||
// Draw actors below diagram
|
// 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 will enumerate each given message, and will determine its text width, in relation to the actor
|
||||||
* it originates from, and destined to.
|
* it originates from, and destined to.
|
||||||
*
|
*
|
||||||
* @param {any} actors - The actors map
|
* @param actors - The actors map
|
||||||
* @param {Array} messages - A list of message objects to iterate
|
* @param messages - A list of message objects to iterate
|
||||||
* @param diagObj
|
* @param diagObj - The diagram object.
|
||||||
* @returns {any}
|
* @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 = {};
|
const maxMessageWidthPerActor = {};
|
||||||
|
|
||||||
messages.forEach(function (msg) {
|
messages.forEach(function (msg) {
|
||||||
@ -1005,7 +1016,7 @@ const getMaxMessageWidthPerActor = function (actors, messages, diagObj) {
|
|||||||
|
|
||||||
log.debug('maxMessageWidthPerActor:', maxMessageWidthPerActor);
|
log.debug('maxMessageWidthPerActor:', maxMessageWidthPerActor);
|
||||||
return maxMessageWidthPerActor;
|
return maxMessageWidthPerActor;
|
||||||
};
|
}
|
||||||
|
|
||||||
const getRequiredPopupWidth = function (actor) {
|
const getRequiredPopupWidth = function (actor) {
|
||||||
let requiredPopupWidth = 0;
|
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
|
* 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.
|
* originates from it, and the configured conf.actorMargin.
|
||||||
*
|
*
|
||||||
* @param {any} actors - The actors map to calculate margins for
|
* @param actors - The actors map to calculate margins for
|
||||||
* @param {any} actorToMessageWidth - A map of actor key -> max message width it holds
|
* @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;
|
let maxHeight = 0;
|
||||||
Object.keys(actors).forEach((prop) => {
|
Object.keys(actors).forEach((prop) => {
|
||||||
const actor = actors[prop];
|
const actor = actors[prop];
|
||||||
@ -1071,7 +1086,7 @@ const calculateActorMargins = function (actors, actorToMessageWidth) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Math.max(maxHeight, conf.height);
|
return Math.max(maxHeight, conf.height);
|
||||||
};
|
}
|
||||||
|
|
||||||
const buildNoteModel = function (msg, actors, diagObj) {
|
const buildNoteModel = function (msg, actors, diagObj) {
|
||||||
const startx = actors[msg.from].x;
|
const startx = actors[msg.from].x;
|
||||||
|
@ -31,7 +31,9 @@ const addPopupInteraction = (id, actorCnt) => {
|
|||||||
addFunction(() => {
|
addFunction(() => {
|
||||||
const arr = document.querySelectorAll(id);
|
const arr = document.querySelectorAll(id);
|
||||||
// This will be the case when running in sandboxed mode
|
// 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 () {
|
arr[0].addEventListener('mouseover', function () {
|
||||||
popupMenuUpFunc('actor' + actorCnt + '_popup');
|
popupMenuUpFunc('actor' + actorCnt + '_popup');
|
||||||
});
|
});
|
||||||
@ -322,7 +324,9 @@ export const drawLabel = function (elem, txtObject) {
|
|||||||
let actorCnt = -1;
|
let actorCnt = -1;
|
||||||
|
|
||||||
export const fixLifeLineHeights = (diagram, bounds) => {
|
export const fixLifeLineHeights = (diagram, bounds) => {
|
||||||
if (!diagram.selectAll) return;
|
if (!diagram.selectAll) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
diagram
|
diagram
|
||||||
.selectAll('.actor-line')
|
.selectAll('.actor-line')
|
||||||
.attr('class', '200')
|
.attr('class', '200')
|
||||||
@ -509,7 +513,7 @@ export const anchorElement = function (elem) {
|
|||||||
*
|
*
|
||||||
* @param {any} elem - Element to append activation rect.
|
* @param {any} elem - Element to append activation rect.
|
||||||
* @param {any} bounds - Activation box bounds.
|
* @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} conf - Sequence diagram config object.
|
||||||
* @param {any} actorActivations - Number of activations on the actor.
|
* @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
|
* 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} loopModel - LoopModel of the given loop.
|
||||||
* @param {any} labelText - Text within the loop.
|
* @param {any} labelText - Text within the loop.
|
||||||
* @param {any} conf - Diagrom configuration
|
* @param {any} conf - Diagram configuration
|
||||||
* @returns {any}
|
* @returns {any}
|
||||||
*/
|
*/
|
||||||
export const drawLoop = function (elem, loopModel, labelText, conf) {
|
export const drawLoop = function (elem, loopModel, labelText, conf) {
|
||||||
|
@ -36,7 +36,7 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
|
|||||||
expect(styleClasses['exampleClass'].styles[2]).toEqual('font-style:italic');
|
expect(styleClasses['exampleClass'].styles[2]).toEqual('font-style:italic');
|
||||||
});
|
});
|
||||||
|
|
||||||
// need to look at what the lexer is doing. see the work on the chevotrain parser
|
// need to look at what the lexer is doing
|
||||||
it('an attribute can have a dot in the style', function () {
|
it('an attribute can have a dot in the style', function () {
|
||||||
stateDiagram.parser.parse(
|
stateDiagram.parser.parse(
|
||||||
'stateDiagram-v2\n classDef exampleStyleClass background:#bbb,border:1.5px solid red;'
|
'stateDiagram-v2\n classDef exampleStyleClass background:#bbb,border:1.5px solid red;'
|
||||||
|
@ -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. */
|
/** 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;
|
* 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
|
* @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);
|
// descrLine.attr('x2', graphBox.width + getConfig().state.padding);
|
||||||
|
|
||||||
if (stateDef.doc) {
|
if (stateDef.doc) {
|
||||||
// cnsole.warn(
|
// console.warn(
|
||||||
// stateDef.id,
|
// stateDef.id,
|
||||||
// 'orgX: ',
|
// 'orgX: ',
|
||||||
// orgX,
|
// orgX,
|
||||||
@ -217,7 +217,9 @@ export const addTitleAndBox = (g, stateDef, altBkg) => {
|
|||||||
.attr('rx', '0');
|
.attr('rx', '0');
|
||||||
|
|
||||||
title.attr('x', startX + pad);
|
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
|
// Title background
|
||||||
g.insert('rect', ':first-child')
|
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');
|
const g = elem.append('g').attr('id', id).attr('class', 'stateGroup');
|
||||||
|
|
||||||
if (stateDef.type === 'start') drawStartState(g);
|
if (stateDef.type === 'start') {
|
||||||
if (stateDef.type === 'end') drawEndState(g);
|
drawStartState(g);
|
||||||
if (stateDef.type === 'fork' || stateDef.type === 'join') drawForkJoinState(g, stateDef);
|
}
|
||||||
if (stateDef.type === 'note') drawNote(stateDef.note.text, g);
|
if (stateDef.type === 'end') {
|
||||||
if (stateDef.type === 'divider') drawDivider(g);
|
drawEndState(g);
|
||||||
if (stateDef.type === 'default' && stateDef.descriptions.length === 0)
|
}
|
||||||
|
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);
|
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();
|
const stateBox = g.node().getBBox();
|
||||||
stateInfo.width = stateBox.width + 2 * getConfig().state.padding;
|
stateInfo.width = stateBox.width + 2 * getConfig().state.padding;
|
||||||
|
@ -228,7 +228,9 @@ export const addState = function (
|
|||||||
|
|
||||||
if (descr) {
|
if (descr) {
|
||||||
log.info('Setting state description', id, descr);
|
log.info('Setting state description', id, descr);
|
||||||
if (typeof descr === 'string') addDescription(id, descr.trim());
|
if (typeof descr === 'string') {
|
||||||
|
addDescription(id, descr.trim());
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof descr === 'object') {
|
if (typeof descr === 'object') {
|
||||||
descr.forEach((des) => addDescription(id, des.trim()));
|
descr.forEach((des) => addDescription(id, des.trim()));
|
||||||
@ -437,7 +439,7 @@ const getDividerId = () => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the parser comes across a (style) class definition
|
* Called when the parser comes across a (style) class definition
|
||||||
* @example classDef someclass fill:#f96;
|
* @example classDef my-style fill:#f96;
|
||||||
*
|
*
|
||||||
* @param {string} id - the id of this (style) class
|
* @param {string} id - the id of this (style) class
|
||||||
* @param {string} styleAttributes - the string with 1 or more style attributes (each separated by a comma)
|
* @param {string} styleAttributes - the string with 1 or more style attributes (each separated by a comma)
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/types';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const stateDetectorV2: DiagramDetector = (text, config) => {
|
export const stateDetectorV2: DiagramDetector = (text, config) => {
|
||||||
if (text.match(/^\s*stateDiagram-v2/) !== null) return true;
|
if (text.match(/^\s*stateDiagram-v2/) !== null) {
|
||||||
if (text.match(/^\s*stateDiagram/) && config?.state?.defaultRenderer === 'dagre-wrapper')
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
if (text.match(/^\s*stateDiagram/) && config?.state?.defaultRenderer === 'dagre-wrapper') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import type { DiagramDetector } from '../../diagram-api/types';
|
import type { DiagramDetector } from '../../diagram-api/types';
|
||||||
|
|
||||||
export const stateDetector: DiagramDetector = (txt, config) => {
|
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
|
// 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;
|
return txt.match(/^\s*stateDiagram/) !== null;
|
||||||
};
|
};
|
||||||
|
@ -89,7 +89,9 @@ export const setConf = function (cnf) {
|
|||||||
*/
|
*/
|
||||||
export const getClasses = function (text, diagramObj) {
|
export const getClasses = function (text, diagramObj) {
|
||||||
log.trace('Extracting classes');
|
log.trace('Extracting classes');
|
||||||
if (diagramClasses.length > 0) return diagramClasses; // we have already extracted the classes
|
if (diagramClasses.length > 0) {
|
||||||
|
return diagramClasses; // we have already extracted the classes
|
||||||
|
}
|
||||||
|
|
||||||
diagramObj.db.clear();
|
diagramObj.db.clear();
|
||||||
try {
|
try {
|
||||||
@ -113,11 +115,14 @@ export const getClasses = function (text, diagramObj) {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function getClassesFromDbInfo(dbInfoItem) {
|
function getClassesFromDbInfo(dbInfoItem) {
|
||||||
if (typeof dbInfoItem === 'undefined' || dbInfoItem === null) return '';
|
if (typeof dbInfoItem === 'undefined' || dbInfoItem === null) {
|
||||||
else {
|
return '';
|
||||||
|
} else {
|
||||||
if (dbInfoItem.classes) {
|
if (dbInfoItem.classes) {
|
||||||
return dbInfoItem.classes.join(' ');
|
return dbInfoItem.classes.join(' ');
|
||||||
} else return '';
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,9 +156,15 @@ const setupNode = (g, parent, parsedItem, diagramDb, altFlag) => {
|
|||||||
|
|
||||||
if (itemId !== 'root') {
|
if (itemId !== 'root') {
|
||||||
let shape = SHAPE_STATE;
|
let shape = SHAPE_STATE;
|
||||||
if (parsedItem.start === true) shape = SHAPE_START;
|
if (parsedItem.start === true) {
|
||||||
if (parsedItem.start === false) shape = SHAPE_END;
|
shape = SHAPE_START;
|
||||||
if (parsedItem.type !== DEFAULT_STATE_TYPE) shape = parsedItem.type;
|
}
|
||||||
|
if (parsedItem.start === false) {
|
||||||
|
shape = SHAPE_END;
|
||||||
|
}
|
||||||
|
if (parsedItem.type !== DEFAULT_STATE_TYPE) {
|
||||||
|
shape = parsedItem.type;
|
||||||
|
}
|
||||||
|
|
||||||
// Add the node to our list (nodeDb)
|
// Add the node to our list (nodeDb)
|
||||||
if (!nodeDb[itemId]) {
|
if (!nodeDb[itemId]) {
|
||||||
@ -382,7 +393,9 @@ export const draw = function (text, id, _version, diag) {
|
|||||||
nodeDb = {};
|
nodeDb = {};
|
||||||
// Fetch the default direction, use TD if none was found
|
// Fetch the default direction, use TD if none was found
|
||||||
let dir = diag.db.getDirection();
|
let dir = diag.db.getDirection();
|
||||||
if (typeof dir === 'undefined') dir = DEFAULT_DIAGRAM_DIRECTION;
|
if (typeof dir === 'undefined') {
|
||||||
|
dir = DEFAULT_DIAGRAM_DIRECTION;
|
||||||
|
}
|
||||||
|
|
||||||
const { securityLevel, state: conf } = getConfig();
|
const { securityLevel, state: conf } = getConfig();
|
||||||
const nodeSpacing = conf.nodeSpacing || 50;
|
const nodeSpacing = conf.nodeSpacing || 50;
|
||||||
|
@ -47,7 +47,7 @@ const insertMarkers = function (elem) {
|
|||||||
export const draw = function (text, id, _version, diagObj) {
|
export const draw = function (text, id, _version, diagObj) {
|
||||||
conf = getConfig().state;
|
conf = getConfig().state;
|
||||||
const securityLevel = getConfig().securityLevel;
|
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;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
sandboxElement = select('#i' + id);
|
||||||
@ -120,7 +120,7 @@ const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument, diagObj) =
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set an object for the graph label
|
// Set an object for the graph label
|
||||||
if (parentId)
|
if (parentId) {
|
||||||
graph.setGraph({
|
graph.setGraph({
|
||||||
rankdir: 'LR',
|
rankdir: 'LR',
|
||||||
multigraph: true,
|
multigraph: true,
|
||||||
@ -133,7 +133,7 @@ const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument, diagObj) =
|
|||||||
// ranksep: 5,
|
// ranksep: 5,
|
||||||
// nodesep: 1
|
// nodesep: 1
|
||||||
});
|
});
|
||||||
else {
|
} else {
|
||||||
graph.setGraph({
|
graph.setGraph({
|
||||||
rankdir: 'TB',
|
rankdir: 'TB',
|
||||||
multigraph: true,
|
multigraph: true,
|
||||||
@ -268,7 +268,9 @@ const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument, diagObj) =
|
|||||||
let pWidth = 0;
|
let pWidth = 0;
|
||||||
let pShift = 0;
|
let pShift = 0;
|
||||||
if (parent) {
|
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);
|
pShift = parseInt(parent.getAttribute('data-x-shift'), 10);
|
||||||
if (Number.isNaN(pShift)) {
|
if (Number.isNaN(pShift)) {
|
||||||
pShift = 0;
|
pShift = 0;
|
||||||
|
@ -15,7 +15,7 @@ export const setConf = function (cnf) {
|
|||||||
|
|
||||||
const actors = {};
|
const actors = {};
|
||||||
|
|
||||||
/** @param {any} diagram */
|
/** @param diagram - The diagram to draw to. */
|
||||||
function drawActorLegend(diagram) {
|
function drawActorLegend(diagram) {
|
||||||
const conf = getConfig().journey;
|
const conf = getConfig().journey;
|
||||||
// Draw the actors
|
// Draw the actors
|
||||||
@ -54,7 +54,7 @@ export const draw = function (text, id, version, diagObj) {
|
|||||||
diagObj.parser.parse(text + '\n');
|
diagObj.parser.parse(text + '\n');
|
||||||
|
|
||||||
const securityLevel = getConfig().securityLevel;
|
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;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
sandboxElement = select('#i' + id);
|
||||||
@ -74,7 +74,9 @@ export const draw = function (text, id, version, diagObj) {
|
|||||||
const title = diagObj.db.getDiagramTitle();
|
const title = diagObj.db.getDiagramTitle();
|
||||||
|
|
||||||
const actorNames = diagObj.db.getActors();
|
const actorNames = diagObj.db.getActors();
|
||||||
for (const member in actors) delete actors[member];
|
for (const member in actors) {
|
||||||
|
delete actors[member];
|
||||||
|
}
|
||||||
let actorPos = 0;
|
let actorPos = 0;
|
||||||
actorNames.forEach((actorName) => {
|
actorNames.forEach((actorName) => {
|
||||||
actors[actorName] = {
|
actors[actorName] = {
|
||||||
@ -155,8 +157,8 @@ export const bounds = {
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
const _self = this;
|
const _self = this;
|
||||||
let cnt = 0;
|
let cnt = 0;
|
||||||
/** @param {any} type */
|
/** @param type - Set to `activation` if activation */
|
||||||
function updateFn(type) {
|
function updateFn(type?: 'activation') {
|
||||||
return function updateItemBounds(item) {
|
return function updateItemBounds(item) {
|
||||||
cnt++;
|
cnt++;
|
||||||
// The loop sequenceItems is a stack so the biggest margins in the beginning of the sequenceItems
|
// 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
|
// Draw the box with the attached line
|
||||||
svgDraw.drawTask(diagram, task, conf);
|
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.
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ export const drawSection = function (elem, section, conf) {
|
|||||||
|
|
||||||
let taskCount = -1;
|
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} elem The HTML element
|
||||||
* @param {any} task The task to render
|
* @param {any} task The task to render
|
||||||
|
@ -35,7 +35,7 @@ import { exec } from 'child_process';
|
|||||||
import { globby } from 'globby';
|
import { globby } from 'globby';
|
||||||
import { JSDOM } from 'jsdom';
|
import { JSDOM } from 'jsdom';
|
||||||
import type { Code, Root } from 'mdast';
|
import type { Code, Root } from 'mdast';
|
||||||
import { join, dirname } from 'path';
|
import { posix, dirname } from 'path';
|
||||||
import prettier from 'prettier';
|
import prettier from 'prettier';
|
||||||
import { remark } from 'remark';
|
import { remark } from 'remark';
|
||||||
// @ts-ignore No typescript declaration file
|
// @ts-ignore No typescript declaration file
|
||||||
@ -210,30 +210,28 @@ const transformHtml = (filename: string) => {
|
|||||||
copyTransformedContents(filename, !verifyOnly, formattedHTML);
|
copyTransformedContents(filename, !verifyOnly, formattedHTML);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getFilesFromGlobs = async (globs: string[]): Promise<string[]> => {
|
||||||
|
return await globby(globs, { dot: true });
|
||||||
|
};
|
||||||
|
|
||||||
/** Main method (entry point) */
|
/** Main method (entry point) */
|
||||||
(async () => {
|
(async () => {
|
||||||
if (verifyOnly) {
|
if (verifyOnly) {
|
||||||
console.log('Verifying that all files are in sync with the source files');
|
console.log('Verifying that all files are in sync with the source files');
|
||||||
}
|
}
|
||||||
const sourceDirGlob = join('.', SOURCE_DOCS_DIR, '**');
|
const sourceDirGlob = posix.join('.', SOURCE_DOCS_DIR, '**');
|
||||||
const includeFilesStartingWithDot = true;
|
const action = verifyOnly ? 'Verifying' : 'Transforming';
|
||||||
|
|
||||||
console.log('Transforming markdown files...');
|
const mdFiles = await getFilesFromGlobs([posix.join(sourceDirGlob, '*.md')]);
|
||||||
const mdFiles = await globby([join(sourceDirGlob, '*.md')], {
|
console.log(`${action} ${mdFiles.length} markdown files...`);
|
||||||
dot: includeFilesStartingWithDot,
|
|
||||||
});
|
|
||||||
mdFiles.forEach(transformMarkdown);
|
mdFiles.forEach(transformMarkdown);
|
||||||
|
|
||||||
console.log('Transforming html files...');
|
const htmlFiles = await getFilesFromGlobs([posix.join(sourceDirGlob, '*.html')]);
|
||||||
const htmlFiles = await globby([join(sourceDirGlob, '*.html')], {
|
console.log(`${action} ${htmlFiles.length} html files...`);
|
||||||
dot: includeFilesStartingWithDot,
|
|
||||||
});
|
|
||||||
htmlFiles.forEach(transformHtml);
|
htmlFiles.forEach(transformHtml);
|
||||||
|
|
||||||
console.log('Transforming all other files...');
|
const otherFiles = await getFilesFromGlobs([sourceDirGlob, '!**/*.md', '!**/*.html']);
|
||||||
const otherFiles = await globby([sourceDirGlob, '!**/*.md', '!**/*.html'], {
|
console.log(`${action} ${otherFiles.length} other files...`);
|
||||||
dot: includeFilesStartingWithDot,
|
|
||||||
});
|
|
||||||
otherFiles.forEach((file: string) => {
|
otherFiles.forEach((file: string) => {
|
||||||
copyTransformedContents(file, !verifyOnly); // no transformation
|
copyTransformedContents(file, !verifyOnly); // no transformation
|
||||||
});
|
});
|
||||||
@ -244,7 +242,7 @@ const transformHtml = (filename: string) => {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
if (git) {
|
if (git) {
|
||||||
console.log('Adding changes in ${FINAL_DOCS_DIR} folder to git');
|
console.log(`Adding changes in ${FINAL_DOCS_DIR} folder to git`);
|
||||||
exec('git add docs');
|
exec('git add docs');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,9 @@ Mermaid can render class diagrams.
|
|||||||
|
|
||||||
```mermaid-example
|
```mermaid-example
|
||||||
classDiagram
|
classDiagram
|
||||||
|
note "From Duck till Zebra"
|
||||||
Animal <|-- Duck
|
Animal <|-- Duck
|
||||||
|
note for Duck "can fly\ncan swim\ncan dive\ncan help in debugging"
|
||||||
Animal <|-- Fish
|
Animal <|-- Fish
|
||||||
Animal <|-- Zebra
|
Animal <|-- Zebra
|
||||||
Animal : +int age
|
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.)
|
- (_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.
|
- 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
|
### Examples
|
||||||
|
|
||||||
_URL Link:_
|
_URL Link:_
|
||||||
|
@ -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) |
|
| `}o` | `o{` | Zero or more (no upper limit) |
|
||||||
| `}\|` | `\|{` | One 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
|
### 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:
|
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
|
```mmd
|
||||||
erDiagram
|
erDiagram
|
||||||
CAR ||--o{ NAMED-DRIVER : allows
|
CAR ||--o{ NAMED-DRIVER : allows
|
||||||
@ -155,6 +179,7 @@ erDiagram
|
|||||||
string lastName
|
string lastName
|
||||||
int age
|
int age
|
||||||
}
|
}
|
||||||
|
MANUFACTURER only one to zero or more CAR
|
||||||
```
|
```
|
||||||
|
|
||||||
### Other Things
|
### Other Things
|
||||||
|
@ -198,8 +198,8 @@ flowchart LR
|
|||||||
### Dotted link
|
### Dotted link
|
||||||
|
|
||||||
```mermaid-example
|
```mermaid-example
|
||||||
flowchart LR;
|
flowchart LR
|
||||||
A-.->B;
|
A-.->B
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dotted link with text
|
### Dotted link with text
|
||||||
@ -587,7 +587,7 @@ A shorter form of adding a class is to attach the classname to the node using th
|
|||||||
```mermaid-example
|
```mermaid-example
|
||||||
flowchart LR
|
flowchart LR
|
||||||
A:::someclass --> B
|
A:::someclass --> B
|
||||||
classDef someclass fill:#f96;
|
classDef someclass fill:#f96
|
||||||
```
|
```
|
||||||
|
|
||||||
### Css classes
|
### Css classes
|
||||||
@ -610,7 +610,7 @@ below:
|
|||||||
**Example definition**
|
**Example definition**
|
||||||
|
|
||||||
```mermaid-example
|
```mermaid-example
|
||||||
flowchart LR;
|
flowchart LR
|
||||||
A-->B[AAA<span>BBB</span>]
|
A-->B[AAA<span>BBB</span>]
|
||||||
B-->D
|
B-->D
|
||||||
class A cssClass
|
class A cssClass
|
||||||
@ -634,7 +634,7 @@ The icons are accessed via the syntax fa:#icon class name#.
|
|||||||
flowchart TD
|
flowchart TD
|
||||||
B["fab:fa-twitter for peace"]
|
B["fab:fa-twitter for peace"]
|
||||||
B-->C[fa:fa-ban forbidden]
|
B-->C[fa:fa-ban forbidden]
|
||||||
B-->D(fa:fa-spinner);
|
B-->D(fa:fa-spinner)
|
||||||
B-->E(A fa:fa-camera-retro perhaps?)
|
B-->E(A fa:fa-camera-retro perhaps?)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -15,6 +15,14 @@
|
|||||||
name="viewport"
|
name="viewport"
|
||||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
|
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
|
||||||
/>
|
/>
|
||||||
|
<meta property="og:title" content="Mermaid" />
|
||||||
|
<meta property="og:url" content="https://mermaid-js.github.io/mermaid/" />
|
||||||
|
<meta property="og:image" content="https://mermaid-js.github.io/mermaid/img/header.png" />
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content="Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs."
|
||||||
|
/>
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
<!-- <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css"> -->
|
<!-- <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css"> -->
|
||||||
<link rel="stylesheet" href="theme.css" />
|
<link rel="stylesheet" href="theme.css" />
|
||||||
<link
|
<link
|
||||||
@ -28,12 +36,27 @@
|
|||||||
></script>
|
></script>
|
||||||
<script>
|
<script>
|
||||||
const require = {
|
const require = {
|
||||||
paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs' },
|
paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs' },
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs/loader.min.js"></script>
|
<script
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs/editor/editor.main.nls.js"></script>
|
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.1/min/vs/loader.min.js"
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs/editor/editor.main.js"></script>
|
integrity="sha512-6bIYsGqvLpAiEBXPdRQeFf5cueeBECtAKJjIHer3BhBZNTV3WLcLA8Tm3pDfxUwTMIS+kAZwTUvJ1IrMdX8C5w=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.1/min/vs/editor/editor.main.nls.min.js"
|
||||||
|
integrity="sha512-CCv+DKWw+yZhxf4Z+ExT6HC5G+3S45TeMTYcJyYbdrv4BpK2vyALJ4FoVR/KGWDIPu7w4tNCOC9MJQIkYPR5FA=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.1/min/vs/editor/editor.main.min.js"
|
||||||
|
integrity="sha512-u4eMtetNbBJvHXdLXs2kWZvJiVlg3cmkVcxrLzSPa1eNFuHygPYvyMWyK9PsD6Eq2MZSo+mTyjds8uuhPzVxHA=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
></script>
|
||||||
<script>
|
<script>
|
||||||
exports = {};
|
exports = {};
|
||||||
</script>
|
</script>
|
||||||
@ -57,6 +80,7 @@
|
|||||||
let parser = new DOMParser();
|
let parser = new DOMParser();
|
||||||
let currentCodeExample = 0;
|
let currentCodeExample = 0;
|
||||||
let colorize = [];
|
let colorize = [];
|
||||||
|
let num = 0;
|
||||||
|
|
||||||
function colorizeEverything(html) {
|
function colorizeEverything(html) {
|
||||||
initEditor(monaco);
|
initEditor(monaco);
|
||||||
@ -127,8 +151,9 @@
|
|||||||
hook.afterEach(function (html, next) {
|
hook.afterEach(function (html, next) {
|
||||||
next(html);
|
next(html);
|
||||||
(async () => {
|
(async () => {
|
||||||
while (!window.hasOwnProperty('monaco'))
|
while (!window.hasOwnProperty('monaco')) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
}
|
||||||
colorizeEverything(html).then(
|
colorizeEverything(html).then(
|
||||||
(newHTML) =>
|
(newHTML) =>
|
||||||
(document.querySelector('article.markdown-section').innerHTML = newHTML)
|
(document.querySelector('article.markdown-section').innerHTML = newHTML)
|
||||||
@ -146,7 +171,9 @@
|
|||||||
startOnLoad: false,
|
startOnLoad: false,
|
||||||
themeCSS: '.label { font-family: Source Sans Pro,Helvetica Neue,Arial,sans-serif; }',
|
themeCSS: '.label { font-family: Source Sans Pro,Helvetica Neue,Arial,sans-serif; }',
|
||||||
};
|
};
|
||||||
if (isDarkMode) conf.theme = 'dark';
|
if (isDarkMode) {
|
||||||
|
conf.theme = 'dark';
|
||||||
|
}
|
||||||
mermaid.initialize(conf);
|
mermaid.initialize(conf);
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
@ -19,7 +19,7 @@ Drawing a pie chart is really simple in mermaid.
|
|||||||
- Start with `pie` keyword to begin the diagram
|
- Start with `pie` keyword to begin the diagram
|
||||||
- `showData` to render the actual data values after the legend text. This is **_OPTIONAL_**
|
- `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 `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.
|
- `label` for a section in the pie diagram within `" "` quotes.
|
||||||
- Followed by `:` colon as separator
|
- Followed by `:` colon as separator
|
||||||
- Followed by `positive numeric value` (supported upto two decimal places)
|
- Followed by `positive numeric value` (supported upto two decimal places)
|
||||||
|
@ -66,7 +66,7 @@ Messages can be of two displayed either solid or with a dotted line.
|
|||||||
[Actor][Arrow][Actor]:Message text
|
[Actor][Arrow][Actor]:Message text
|
||||||
```
|
```
|
||||||
|
|
||||||
There are six types of arrows currently supported:
|
There are eight types of arrows currently supported:
|
||||||
|
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
| ---- | ------------------------------------------------ |
|
| ---- | ------------------------------------------------ |
|
||||||
|
@ -27,7 +27,7 @@ export const log: Record<keyof typeof LEVELS, typeof console.log> = {
|
|||||||
/**
|
/**
|
||||||
* Sets a log level
|
* 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') {
|
export const setLogLevel = function (level: keyof typeof LEVELS | number | string = 'fatal') {
|
||||||
let numericLevel: number = LEVELS.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
|
* Returns a format with the timestamp and the log level
|
||||||
*
|
*
|
||||||
* @param {LogLevel} level The level for the log format
|
* @param level - The level for the log format
|
||||||
* @returns {string} The format with the timestamp and log level
|
* @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');
|
const time = moment().format('ss.SSS');
|
||||||
return `%c${time} : ${level} : `;
|
return `%c${time} : ${level} : `;
|
||||||
};
|
};
|
||||||
|
@ -8,6 +8,7 @@ import utils from './utils';
|
|||||||
import { mermaidAPI } from './mermaidAPI';
|
import { mermaidAPI } from './mermaidAPI';
|
||||||
import { addDetector } from './diagram-api/detectType';
|
import { addDetector } from './diagram-api/detectType';
|
||||||
import { isDetailedError } from './utils';
|
import { isDetailedError } from './utils';
|
||||||
|
import type { ParseErrorFunction } from './Diagram';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## init
|
* ## init
|
||||||
@ -18,12 +19,6 @@ import { isDetailedError } from './utils';
|
|||||||
* elements with the attribute already set. This way the init function can be triggered several
|
* elements with the attribute already set. This way the init function can be triggered several
|
||||||
* times.
|
* 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
|
* ```mermaid
|
||||||
* graph LR;
|
* graph LR;
|
||||||
* a(Find elements)-->b{Processed}
|
* a(Find elements)-->b{Processed}
|
||||||
@ -33,9 +28,12 @@ import { isDetailedError } from './utils';
|
|||||||
*
|
*
|
||||||
* Renders the mermaid diagrams
|
* Renders the mermaid diagrams
|
||||||
*
|
*
|
||||||
* @param config
|
* @param config - **Deprecated**, please set configuration in {@link initialize}.
|
||||||
* @param nodes
|
* @param nodes - **Default**: `.mermaid`. One of the following:
|
||||||
* @param callback
|
* - 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 (
|
const init = async function (
|
||||||
config?: MermaidConfig,
|
config?: MermaidConfig,
|
||||||
@ -62,7 +60,7 @@ const init = async function (
|
|||||||
log.warn(e.str);
|
log.warn(e.str);
|
||||||
}
|
}
|
||||||
if (mermaid.parseError) {
|
if (mermaid.parseError) {
|
||||||
mermaid.parseError(e);
|
mermaid.parseError(e as string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -142,7 +140,9 @@ const initThrowsErrors = async function (
|
|||||||
if (typeof callback !== 'undefined') {
|
if (typeof callback !== 'undefined') {
|
||||||
callback(id);
|
callback(id);
|
||||||
}
|
}
|
||||||
if (bindFunctions) bindFunctions(element);
|
if (bindFunctions) {
|
||||||
|
bindFunctions(element);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
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
|
* 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).
|
* 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) {
|
const setParseErrorHandler = function (newParseErrorHandler: (err: any, hash: any) => void) {
|
||||||
mermaid.parseError = newParseErrorHandler;
|
mermaid.parseError = newParseErrorHandler;
|
||||||
@ -212,8 +212,7 @@ const parse = (txt: string) => {
|
|||||||
const mermaid: {
|
const mermaid: {
|
||||||
startOnLoad: boolean;
|
startOnLoad: boolean;
|
||||||
diagrams: any;
|
diagrams: any;
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
parseError?: ParseErrorFunction;
|
||||||
parseError?: Function;
|
|
||||||
mermaidAPI: typeof mermaidAPI;
|
mermaidAPI: typeof mermaidAPI;
|
||||||
parse: typeof parse;
|
parse: typeof parse;
|
||||||
render: typeof mermaidAPI.render;
|
render: typeof mermaidAPI.render;
|
||||||
|
@ -9,8 +9,6 @@
|
|||||||
* page or do something completely different.
|
* page or do something completely different.
|
||||||
*
|
*
|
||||||
* In addition to the render function, a number of behavioral configuration options are available.
|
* In addition to the render function, a number of behavioral configuration options are available.
|
||||||
*
|
|
||||||
* @name mermaidAPI
|
|
||||||
*/
|
*/
|
||||||
import { select } from 'd3';
|
import { select } from 'd3';
|
||||||
import { compile, serialize, stringify } from 'stylis';
|
import { compile, serialize, stringify } from 'stylis';
|
||||||
@ -21,7 +19,7 @@ import { addDiagrams } from './diagram-api/diagram-orchestration';
|
|||||||
import classDb from './diagrams/class/classDb';
|
import classDb from './diagrams/class/classDb';
|
||||||
import flowDb from './diagrams/flowchart/flowDb';
|
import flowDb from './diagrams/flowchart/flowDb';
|
||||||
import ganttDb from './diagrams/gantt/ganttDb';
|
import ganttDb from './diagrams/gantt/ganttDb';
|
||||||
import Diagram, { getDiagramFromText } from './Diagram';
|
import Diagram, { getDiagramFromText, type ParseErrorFunction } from './Diagram';
|
||||||
import errorRenderer from './diagrams/error/errorRenderer';
|
import errorRenderer from './diagrams/error/errorRenderer';
|
||||||
import { attachFunctions } from './interactionDb';
|
import { attachFunctions } from './interactionDb';
|
||||||
import { log, setLogLevel } from './logger';
|
import { log, setLogLevel } from './logger';
|
||||||
@ -36,11 +34,10 @@ import { evaluate } from './diagrams/common/common';
|
|||||||
const CLASSDEF_DIAGRAMS = ['graph', 'flowchart', 'flowchart-v2', 'stateDiagram'];
|
const CLASSDEF_DIAGRAMS = ['graph', 'flowchart', 'flowchart-v2', 'stateDiagram'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param text
|
* @param text - The mermaid diagram definition.
|
||||||
* @param parseError
|
* @param parseError - If set, handles errors.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
function parse(text: string, parseError?: ParseErrorFunction): boolean {
|
||||||
function parse(text: string, parseError?: Function): boolean {
|
|
||||||
addDiagrams();
|
addDiagrams();
|
||||||
const diagram = new Diagram(text, parseError);
|
const diagram = new Diagram(text, parseError);
|
||||||
return diagram.parse(text, parseError);
|
return diagram.parse(text, parseError);
|
||||||
@ -103,14 +100,13 @@ export const decodeEntities = function (text: string): string {
|
|||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @param {string} id The id of the element to be rendered
|
* @param id - The id of the element to be rendered
|
||||||
* @param {string} text The graph definition
|
* @param text - The graph definition
|
||||||
* @param {(svgCode: string, bindFunctions?: (element: Element) => void) => void} cb Callback which
|
* @param cb - Callback which is called after rendering is finished with the svg code as param.
|
||||||
* is called after rendering is finished with the svg code as inparam.
|
* @param container - Selector to element in which a div with the graph temporarily will be
|
||||||
* @param {Element} container Selector to element in which a div with the graph temporarily will be
|
|
||||||
* inserted. If one is provided a hidden div will be inserted in the body of the page instead. The
|
* inserted. If one is provided a hidden div will be inserted in the body of the page instead. The
|
||||||
* element will be removed when rendering is completed.
|
* element will be removed when rendering is completed.
|
||||||
* @returns {void}
|
* @returns - Resolves when finished rendering.
|
||||||
*/
|
*/
|
||||||
const render = async function (
|
const render = async function (
|
||||||
id: string,
|
id: string,
|
||||||
@ -145,7 +141,7 @@ const render = async function (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cnf.securityLevel === 'sandbox') {
|
if (cnf.securityLevel === 'sandbox') {
|
||||||
// IF we are in sandboxed mode, we do everyting mermaid related
|
// IF we are in sandboxed mode, we do everything mermaid related
|
||||||
// in a sandboxed div
|
// in a sandboxed div
|
||||||
const iframe = select(container)
|
const iframe = select(container)
|
||||||
.append('iframe')
|
.append('iframe')
|
||||||
@ -194,7 +190,7 @@ const render = async function (
|
|||||||
// d+id it will contain a svg with the id "id"
|
// d+id it will contain a svg with the id "id"
|
||||||
|
|
||||||
if (cnf.securityLevel === 'sandbox') {
|
if (cnf.securityLevel === 'sandbox') {
|
||||||
// IF we are in sandboxed mode, we do everyting mermaid related
|
// IF we are in sandboxed mode, we do everything mermaid related
|
||||||
// in a sandboxed div
|
// in a sandboxed div
|
||||||
const iframe = select('body')
|
const iframe = select('body')
|
||||||
.append('iframe')
|
.append('iframe')
|
||||||
@ -243,7 +239,7 @@ const render = async function (
|
|||||||
let userStyles = '';
|
let userStyles = '';
|
||||||
// user provided theme CSS
|
// user provided theme CSS
|
||||||
// If you add more configuration driven data into the user styles make sure that the value is
|
// If you add more configuration driven data into the user styles make sure that the value is
|
||||||
// sanitized bye the santiizeCSS function
|
// sanitized bye the sanitizeCSS function
|
||||||
if (cnf.themeCSS !== undefined) {
|
if (cnf.themeCSS !== undefined) {
|
||||||
userStyles += `\n${cnf.themeCSS}`;
|
userStyles += `\n${cnf.themeCSS}`;
|
||||||
}
|
}
|
||||||
@ -392,11 +388,15 @@ const parseDirective = function (p: any, statement: string, context: string, typ
|
|||||||
currentDirective = {};
|
currentDirective = {};
|
||||||
break;
|
break;
|
||||||
case 'type_directive':
|
case 'type_directive':
|
||||||
if (!currentDirective) throw new Error('currentDirective is undefined');
|
if (!currentDirective) {
|
||||||
|
throw new Error('currentDirective is undefined');
|
||||||
|
}
|
||||||
currentDirective.type = statement.toLowerCase();
|
currentDirective.type = statement.toLowerCase();
|
||||||
break;
|
break;
|
||||||
case 'arg_directive':
|
case 'arg_directive':
|
||||||
if (!currentDirective) throw new Error('currentDirective is undefined');
|
if (!currentDirective) {
|
||||||
|
throw new Error('currentDirective is undefined');
|
||||||
|
}
|
||||||
currentDirective.args = JSON.parse(statement);
|
currentDirective.args = JSON.parse(statement);
|
||||||
break;
|
break;
|
||||||
case 'close_directive':
|
case 'close_directive':
|
||||||
@ -454,7 +454,7 @@ const handleDirective = function (p: any, directive: any, type: string): void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @param {MermaidConfig} options */
|
/** @param options - Initial Mermaid options */
|
||||||
async function initialize(options: MermaidConfig) {
|
async function initialize(options: MermaidConfig) {
|
||||||
// Handle legacy location of font-family configuration
|
// Handle legacy location of font-family configuration
|
||||||
if (options?.fontFamily) {
|
if (options?.fontFamily) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { log } from './logger';
|
import { log } from './logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applys d3 attributes
|
* Applies d3 attributes
|
||||||
*
|
*
|
||||||
* @param {any} d3Elem D3 Element to apply the attributes onto
|
* @param {any} d3Elem D3 Element to apply the attributes onto
|
||||||
* @param {[string, string][]} attrs Object.keys equivalent format of key to value mapping of attributes
|
* @param {[string, string][]} attrs Object.keys equivalent format of key to value mapping of attributes
|
||||||
@ -26,6 +26,7 @@ export const calculateSvgSizeAttrs = function (height, width, useMaxWidth) {
|
|||||||
attrs.set('width', '100%');
|
attrs.set('width', '100%');
|
||||||
attrs.set('style', `max-width: ${width}px;`);
|
attrs.set('style', `max-width: ${width}px;`);
|
||||||
} else {
|
} else {
|
||||||
|
attrs.set('height', height);
|
||||||
attrs.set('width', width);
|
attrs.set('width', width);
|
||||||
}
|
}
|
||||||
return attrs;
|
return attrs;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file Values that have been hardcoded in src/diagrams/er/styles.js. These can be used by
|
* Values that have been hardcoded in src/diagrams/er/styles.js. These can be used by
|
||||||
* theme-_._ files to maintain display styles until themes, styles, renderers are revised. --
|
* theme-_._ files to maintain display styles until themes, styles, renderers are revised. --
|
||||||
* 2022-09-22
|
* 2022-09-22
|
||||||
*/
|
*/
|
||||||
|
@ -126,7 +126,7 @@ class Theme {
|
|||||||
this.specialStateColor = this.lineColor;
|
this.specialStateColor = this.lineColor;
|
||||||
|
|
||||||
/* Color Scale */
|
/* Color Scale */
|
||||||
/* Each color-set will have a background, a forgroupnd and a border color */
|
/* Each color-set will have a background, a foreground and a border color */
|
||||||
this.cScale0 = this.cScale0 || this.primaryColor;
|
this.cScale0 = this.cScale0 || this.primaryColor;
|
||||||
this.cScale1 = this.cScale1 || this.secondaryColor;
|
this.cScale1 = this.cScale1 || this.secondaryColor;
|
||||||
this.cScale2 = this.cScale2 || this.tertiaryColor;
|
this.cScale2 = this.cScale2 || this.tertiaryColor;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user