mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-11-07 22:34:17 +01:00
Merge branch 'develop' into sidv/deprecateMermaidAPI
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
NODE_OPTIONS=--max_old_space_size=8192 pnpm run pre-commit
|
NODE_OPTIONS="--max_old_space_size=8192" pnpm run pre-commit
|
||||||
|
|||||||
@@ -118,8 +118,8 @@ describe('Configuration', () => {
|
|||||||
it('should not taint the initial configuration when using multiple directives', () => {
|
it('should not taint the initial configuration when using multiple directives', () => {
|
||||||
const url = 'http://localhost:9000/regression/issue-1874.html';
|
const url = 'http://localhost:9000/regression/issue-1874.html';
|
||||||
cy.visit(url);
|
cy.visit(url);
|
||||||
|
cy.window().should('have.property', 'rendered', true);
|
||||||
cy.get('svg');
|
cy.get('svg').should('be.visible');
|
||||||
cy.matchImageSnapshot(
|
cy.matchImageSnapshot(
|
||||||
'configuration.spec-should-not-taint-initial-configuration-when-using-multiple-directives'
|
'configuration.spec-should-not-taint-initial-configuration-when-using-multiple-directives'
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -844,3 +844,42 @@ end
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Title and arrow styling #4813', () => {
|
||||||
|
it('should render a flowchart with title', () => {
|
||||||
|
const titleString = 'Test Title';
|
||||||
|
renderGraph(
|
||||||
|
`---
|
||||||
|
title: ${titleString}
|
||||||
|
---
|
||||||
|
flowchart LR
|
||||||
|
A-->B
|
||||||
|
A-->C`,
|
||||||
|
{ flowchart: { defaultRenderer: 'elk' } }
|
||||||
|
);
|
||||||
|
cy.get('svg').should((svg) => {
|
||||||
|
const title = svg[0].querySelector('text');
|
||||||
|
expect(title.textContent).to.contain(titleString);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Render with stylized arrows', () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
flowchart LR
|
||||||
|
A-->B
|
||||||
|
B-.-oC
|
||||||
|
C==xD
|
||||||
|
D ~~~ A`,
|
||||||
|
{ flowchart: { defaultRenderer: 'elk' } }
|
||||||
|
);
|
||||||
|
cy.get('svg').should((svg) => {
|
||||||
|
const edges = svg[0].querySelectorAll('.edges path');
|
||||||
|
console.log(edges);
|
||||||
|
expect(edges[0]).to.have.attr('pattern', 'solid');
|
||||||
|
expect(edges[1]).to.have.attr('pattern', 'dotted');
|
||||||
|
expect(edges[2]).to.have.css('stroke-width', '3.5px');
|
||||||
|
expect(edges[3]).to.have.css('stroke-width', '1.5px');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -760,6 +760,51 @@ A ~~~ B
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('3258: Should render subgraphs with main graph nodeSpacing and rankSpacing', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`---
|
||||||
|
title: Subgraph nodeSpacing and rankSpacing example
|
||||||
|
---
|
||||||
|
flowchart LR
|
||||||
|
X --> Y
|
||||||
|
subgraph X
|
||||||
|
direction LR
|
||||||
|
A
|
||||||
|
C
|
||||||
|
end
|
||||||
|
subgraph Y
|
||||||
|
B
|
||||||
|
D
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
{ flowchart: { nodeSpacing: 1, rankSpacing: 1 } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('3258: Should render subgraphs with large nodeSpacing and rankSpacing', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`---
|
||||||
|
title: Subgraph nodeSpacing and rankSpacing example
|
||||||
|
config:
|
||||||
|
flowchart:
|
||||||
|
nodeSpacing: 250
|
||||||
|
rankSpacing: 250
|
||||||
|
---
|
||||||
|
flowchart LR
|
||||||
|
X --> Y
|
||||||
|
subgraph X
|
||||||
|
direction LR
|
||||||
|
A
|
||||||
|
C
|
||||||
|
end
|
||||||
|
subgraph Y
|
||||||
|
B
|
||||||
|
D
|
||||||
|
end
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
describe('Markdown strings flowchart (#4220)', () => {
|
describe('Markdown strings flowchart (#4220)', () => {
|
||||||
describe('html labels', () => {
|
describe('html labels', () => {
|
||||||
it('With styling and classes', () => {
|
it('With styling and classes', () => {
|
||||||
@@ -904,6 +949,18 @@ end
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not auto wrap when markdownAutoWrap is false', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`flowchart TD
|
||||||
|
angular_velocity["\`**angular_velocity**
|
||||||
|
*angular_displacement / duration*
|
||||||
|
[rad/s, 1/s]
|
||||||
|
{vector}\`"]
|
||||||
|
frequency["frequency\n(1 / period_duration)\n[Hz, 1/s]"]`,
|
||||||
|
{ markdownAutoWrap: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe('Subgraph title margins', () => {
|
describe('Subgraph title margins', () => {
|
||||||
it('Should render subgraphs with title margins set (LR)', () => {
|
it('Should render subgraphs with title margins set (LR)', () => {
|
||||||
|
|||||||
@@ -1013,4 +1013,450 @@ gitGraph TB:
|
|||||||
{ gitGraph: { parallelCommits: true } }
|
{ gitGraph: { parallelCommits: true } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
describe('Git-Graph Bottom-to-Top Orientation Tests', () => {
|
||||||
|
it('50: should render a simple gitgraph with commit on main branch | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id: "1"
|
||||||
|
commit id: "2"
|
||||||
|
commit id: "3"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('51: should render a simple gitgraph with commit on main branch with Id | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id: "One"
|
||||||
|
commit id: "Two"
|
||||||
|
commit id: "Three"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('52: should render a simple gitgraph with different commitTypes on main branch | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id: "Normal Commit"
|
||||||
|
commit id: "Reverse Commit" type: REVERSE
|
||||||
|
commit id: "Highlight Commit" type: HIGHLIGHT
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('53: should render a simple gitgraph with tags commitTypes on main branch | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id: "Normal Commit with tag" tag: "v1.0.0"
|
||||||
|
commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1"
|
||||||
|
commit id: "Highlight Commit" type: HIGHLIGHT tag: "8.8.4"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('54: should render a simple gitgraph with two branches | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id: "1"
|
||||||
|
commit id: "2"
|
||||||
|
branch develop
|
||||||
|
checkout develop
|
||||||
|
commit id: "3"
|
||||||
|
commit id: "4"
|
||||||
|
checkout main
|
||||||
|
commit id: "5"
|
||||||
|
commit id: "6"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('55: should render a simple gitgraph with two branches and merge commit | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id: "1"
|
||||||
|
commit id: "2"
|
||||||
|
branch develop
|
||||||
|
checkout develop
|
||||||
|
commit id: "3"
|
||||||
|
commit id: "4"
|
||||||
|
checkout main
|
||||||
|
merge develop
|
||||||
|
commit id: "5"
|
||||||
|
commit id: "6"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('56: should render a simple gitgraph with three branches and tagged merge commit | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id: "1"
|
||||||
|
commit id: "2"
|
||||||
|
branch nice_feature
|
||||||
|
checkout nice_feature
|
||||||
|
commit id: "3"
|
||||||
|
checkout main
|
||||||
|
commit id: "4"
|
||||||
|
checkout nice_feature
|
||||||
|
branch very_nice_feature
|
||||||
|
checkout very_nice_feature
|
||||||
|
commit id: "5"
|
||||||
|
checkout main
|
||||||
|
commit id: "6"
|
||||||
|
checkout nice_feature
|
||||||
|
commit id: "7"
|
||||||
|
checkout main
|
||||||
|
merge nice_feature id: "12345" tag: "my merge commit"
|
||||||
|
checkout very_nice_feature
|
||||||
|
commit id: "8"
|
||||||
|
checkout main
|
||||||
|
commit id: "9"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('57: should render a simple gitgraph with more than 8 branches & overriding variables | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
|
||||||
|
'gitBranchLabel0': '#ffffff',
|
||||||
|
'gitBranchLabel1': '#ffffff',
|
||||||
|
'gitBranchLabel2': '#ffffff',
|
||||||
|
'gitBranchLabel3': '#ffffff',
|
||||||
|
'gitBranchLabel4': '#ffffff',
|
||||||
|
'gitBranchLabel5': '#ffffff',
|
||||||
|
'gitBranchLabel6': '#ffffff',
|
||||||
|
'gitBranchLabel7': '#ffffff',
|
||||||
|
} } }%%
|
||||||
|
gitGraph BT:
|
||||||
|
checkout main
|
||||||
|
branch branch1
|
||||||
|
branch branch2
|
||||||
|
branch branch3
|
||||||
|
branch branch4
|
||||||
|
branch branch5
|
||||||
|
branch branch6
|
||||||
|
branch branch7
|
||||||
|
branch branch8
|
||||||
|
branch branch9
|
||||||
|
checkout branch1
|
||||||
|
commit id: "1"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('58: should render a simple gitgraph with rotated labels | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'gitGraph': {
|
||||||
|
'rotateCommitLabel': true
|
||||||
|
} } }%%
|
||||||
|
gitGraph BT:
|
||||||
|
commit id: "75f7219e83b321cd3fdde7dcf83bc7c1000a6828"
|
||||||
|
commit id: "0db4784daf82736dec4569e0dc92980d328c1f2e"
|
||||||
|
commit id: "7067e9973f9eaa6cd4a4b723c506d1eab598e83e"
|
||||||
|
commit id: "66972321ad6c199013b5b31f03b3a86fa3f9817d"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('59: should render a simple gitgraph with horizontal labels | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'gitGraph': {
|
||||||
|
'rotateCommitLabel': false
|
||||||
|
} } }%%
|
||||||
|
gitGraph BT:
|
||||||
|
commit id: "Alpha"
|
||||||
|
commit id: "Beta"
|
||||||
|
commit id: "Gamma"
|
||||||
|
commit id: "Delta"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('60: should render a simple gitgraph with cherry pick commit | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gitGraph BT:
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
commit id:"ONE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"B"
|
||||||
|
checkout main
|
||||||
|
commit id:"TWO"
|
||||||
|
cherry-pick id:"A"
|
||||||
|
commit id:"THREE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"C"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('61: should render a gitgraph with cherry pick commit with custom tag | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gitGraph BT:
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
commit id:"ONE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"B"
|
||||||
|
checkout main
|
||||||
|
commit id:"TWO"
|
||||||
|
cherry-pick id:"A" tag: "snapshot"
|
||||||
|
commit id:"THREE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"C"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('62: should render a gitgraph with cherry pick commit with no tag | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gitGraph BT:
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
commit id:"ONE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"B"
|
||||||
|
checkout main
|
||||||
|
commit id:"TWO"
|
||||||
|
cherry-pick id:"A" tag: ""
|
||||||
|
commit id:"THREE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"C"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('63: should render a simple gitgraph with two cherry pick commit | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gitGraph BT:
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
commit id:"ONE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"B"
|
||||||
|
branch featureA
|
||||||
|
commit id:"FIX"
|
||||||
|
commit id: "FIX-2"
|
||||||
|
checkout main
|
||||||
|
commit id:"TWO"
|
||||||
|
cherry-pick id:"A"
|
||||||
|
commit id:"THREE"
|
||||||
|
cherry-pick id:"FIX"
|
||||||
|
checkout develop
|
||||||
|
commit id:"C"
|
||||||
|
merge featureA
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('64: should render commits for more than 8 branches | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gitGraph BT:
|
||||||
|
checkout main
|
||||||
|
%% Make sure to manually set the ID of all commits, for consistent visual tests
|
||||||
|
commit id: "1-abcdefg"
|
||||||
|
checkout main
|
||||||
|
branch branch1
|
||||||
|
commit id: "2-abcdefg"
|
||||||
|
checkout main
|
||||||
|
merge branch1
|
||||||
|
branch branch2
|
||||||
|
commit id: "3-abcdefg"
|
||||||
|
checkout main
|
||||||
|
merge branch2
|
||||||
|
branch branch3
|
||||||
|
commit id: "4-abcdefg"
|
||||||
|
checkout main
|
||||||
|
merge branch3
|
||||||
|
branch branch4
|
||||||
|
commit id: "5-abcdefg"
|
||||||
|
checkout main
|
||||||
|
merge branch4
|
||||||
|
branch branch5
|
||||||
|
commit id: "6-abcdefg"
|
||||||
|
checkout main
|
||||||
|
merge branch5
|
||||||
|
branch branch6
|
||||||
|
commit id: "7-abcdefg"
|
||||||
|
checkout main
|
||||||
|
merge branch6
|
||||||
|
branch branch7
|
||||||
|
commit id: "8-abcdefg"
|
||||||
|
checkout main
|
||||||
|
merge branch7
|
||||||
|
branch branch8
|
||||||
|
commit id: "9-abcdefg"
|
||||||
|
checkout main
|
||||||
|
merge branch8
|
||||||
|
branch branch9
|
||||||
|
commit id: "10-abcdefg"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('65: should render a simple gitgraph with three branches,custom merge commit id,tag,type | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id: "1"
|
||||||
|
commit id: "2"
|
||||||
|
branch nice_feature
|
||||||
|
checkout nice_feature
|
||||||
|
commit id: "3"
|
||||||
|
checkout main
|
||||||
|
commit id: "4"
|
||||||
|
checkout nice_feature
|
||||||
|
branch very_nice_feature
|
||||||
|
checkout very_nice_feature
|
||||||
|
commit id: "5"
|
||||||
|
checkout main
|
||||||
|
commit id: "6"
|
||||||
|
checkout nice_feature
|
||||||
|
commit id: "7"
|
||||||
|
checkout main
|
||||||
|
merge nice_feature id: "customID" tag: "customTag" type: REVERSE
|
||||||
|
checkout very_nice_feature
|
||||||
|
commit id: "8"
|
||||||
|
checkout main
|
||||||
|
commit id: "9"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('66: should render a simple gitgraph with a title | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`---
|
||||||
|
title: simple gitGraph
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit id: "1-abcdefg"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('67: should render a simple gitgraph overlapping commits | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id:"s1"
|
||||||
|
commit id:"s2"
|
||||||
|
branch branch1
|
||||||
|
commit id:"s3"
|
||||||
|
commit id:"s4"
|
||||||
|
checkout main
|
||||||
|
commit id:"s5"
|
||||||
|
checkout branch1
|
||||||
|
commit id:"s6"
|
||||||
|
commit id:"s7"
|
||||||
|
merge main
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('68: should render a simple gitgraph with two branches from same commit | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id:"1-abcdefg"
|
||||||
|
commit id:"2-abcdefg"
|
||||||
|
branch feature-001
|
||||||
|
commit id:"3-abcdefg"
|
||||||
|
commit id:"4-abcdefg"
|
||||||
|
checkout main
|
||||||
|
branch feature-002
|
||||||
|
commit id:"5-abcdefg"
|
||||||
|
checkout feature-001
|
||||||
|
merge feature-002
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('69: should render GitGraph with branch that is not used immediately | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id:"1-abcdefg"
|
||||||
|
branch x
|
||||||
|
checkout main
|
||||||
|
commit id:"2-abcdefg"
|
||||||
|
checkout x
|
||||||
|
commit id:"3-abcdefg"
|
||||||
|
checkout main
|
||||||
|
merge x
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('70: should render GitGraph with branch and sub-branch neither of which used immediately | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id:"1-abcdefg"
|
||||||
|
branch x
|
||||||
|
checkout main
|
||||||
|
commit id:"2-abcdefg"
|
||||||
|
checkout x
|
||||||
|
commit id:"3-abcdefg"
|
||||||
|
checkout main
|
||||||
|
merge x
|
||||||
|
checkout x
|
||||||
|
branch y
|
||||||
|
checkout x
|
||||||
|
commit id:"4-abcdefg"
|
||||||
|
checkout y
|
||||||
|
commit id:"5-abcdefg"
|
||||||
|
checkout x
|
||||||
|
merge y
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('71: should render GitGraph with parallel commits | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
commit id:"1-abcdefg"
|
||||||
|
commit id:"2-abcdefg"
|
||||||
|
branch develop
|
||||||
|
commit id:"3-abcdefg"
|
||||||
|
commit id:"4-abcdefg"
|
||||||
|
checkout main
|
||||||
|
branch feature
|
||||||
|
commit id:"5-abcdefg"
|
||||||
|
commit id:"6-abcdefg"
|
||||||
|
checkout main
|
||||||
|
commit id:"7-abcdefg"
|
||||||
|
commit id:"8-abcdefg"
|
||||||
|
`,
|
||||||
|
{ gitGraph: { parallelCommits: true } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('72: should render GitGraph with unconnected branches and parallel commits | Vertical Branch - Bottom-to-top', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`gitGraph BT:
|
||||||
|
branch dev
|
||||||
|
branch v2
|
||||||
|
branch feat
|
||||||
|
commit id:"1-abcdefg"
|
||||||
|
commit id:"2-abcdefg"
|
||||||
|
checkout main
|
||||||
|
commit id:"3-abcdefg"
|
||||||
|
checkout dev
|
||||||
|
commit id:"4-abcdefg"
|
||||||
|
checkout v2
|
||||||
|
commit id:"5-abcdefg"
|
||||||
|
checkout main
|
||||||
|
commit id:"6-abcdefg"
|
||||||
|
`,
|
||||||
|
{ gitGraph: { parallelCommits: true } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,7 +21,11 @@ sequenceDiagram
|
|||||||
mermaid.initialize({
|
mermaid.initialize({
|
||||||
theme: 'base',
|
theme: 'base',
|
||||||
themeVariables: {},
|
themeVariables: {},
|
||||||
startOnLoad: true,
|
startOnLoad: false,
|
||||||
});
|
});
|
||||||
|
await mermaid.run();
|
||||||
|
if (window.Cypress) {
|
||||||
|
window.rendered = true;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1591,6 +1591,33 @@
|
|||||||
</pre>
|
</pre>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Subgraph nodeSpacing and rankSpacing example
|
||||||
|
config:
|
||||||
|
flowchart:
|
||||||
|
nodeSpacing: 1
|
||||||
|
rankSpacing: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
flowchart LR
|
||||||
|
|
||||||
|
X --> Y
|
||||||
|
|
||||||
|
subgraph X
|
||||||
|
direction LR
|
||||||
|
A
|
||||||
|
C
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Y
|
||||||
|
direction LR
|
||||||
|
B
|
||||||
|
D
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
<hr />
|
||||||
|
|
||||||
<h1 id="link-clicked">Anchor for "link-clicked" test</h1>
|
<h1 id="link-clicked">Anchor for "link-clicked" test</h1>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
|
|||||||
182
demos/git.html
182
demos/git.html
@@ -40,6 +40,19 @@
|
|||||||
checkout main
|
checkout main
|
||||||
merge newbranch
|
merge newbranch
|
||||||
</pre>
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Simple "branch and merge" (bottom-to-top)
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
branch newbranch
|
||||||
|
checkout newbranch
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
merge newbranch
|
||||||
|
</pre
|
||||||
|
>
|
||||||
<h2>Continuous development graph</h2>
|
<h2>Continuous development graph</h2>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
---
|
---
|
||||||
@@ -73,6 +86,23 @@
|
|||||||
checkout main
|
checkout main
|
||||||
merge develop
|
merge develop
|
||||||
</pre>
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Continuous development (bottom-to-top)
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
branch develop
|
||||||
|
checkout develop
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
merge develop
|
||||||
|
checkout develop
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
merge develop
|
||||||
|
</pre
|
||||||
|
>
|
||||||
<h2>Merge feature to advanced main graph</h2>
|
<h2>Merge feature to advanced main graph</h2>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
---
|
---
|
||||||
@@ -100,6 +130,20 @@
|
|||||||
commit
|
commit
|
||||||
merge newbranch
|
merge newbranch
|
||||||
</pre>
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Merge feature to advanced main (bottom-to-top)
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
branch newbranch
|
||||||
|
checkout newbranch
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
commit
|
||||||
|
merge newbranch
|
||||||
|
</pre
|
||||||
|
>
|
||||||
<h2>Two-way merges</h2>
|
<h2>Two-way merges</h2>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
---
|
---
|
||||||
@@ -137,6 +181,25 @@
|
|||||||
checkout main
|
checkout main
|
||||||
merge develop
|
merge develop
|
||||||
</pre>
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Two-way merges (bottom-to-top)
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
branch develop
|
||||||
|
checkout develop
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
merge develop
|
||||||
|
commit
|
||||||
|
checkout develop
|
||||||
|
merge main
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
merge develop
|
||||||
|
</pre
|
||||||
|
>
|
||||||
<h2>Cherry-pick from branch graph</h2>
|
<h2>Cherry-pick from branch graph</h2>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
---
|
---
|
||||||
@@ -170,6 +233,22 @@
|
|||||||
checkout main
|
checkout main
|
||||||
cherry-pick id: "Pick me"
|
cherry-pick id: "Pick me"
|
||||||
</pre>
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Cherry-pick from branch (bottom-to-top)
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
branch newbranch
|
||||||
|
checkout newbranch
|
||||||
|
commit id: "Pick me"
|
||||||
|
checkout main
|
||||||
|
commit
|
||||||
|
checkout newbranch
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
cherry-pick id: "Pick me"
|
||||||
|
</pre>
|
||||||
<h2>Cherry-pick from main graph</h2>
|
<h2>Cherry-pick from main graph</h2>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
---
|
---
|
||||||
@@ -199,6 +278,21 @@
|
|||||||
commit
|
commit
|
||||||
cherry-pick id: "A"
|
cherry-pick id: "A"
|
||||||
</pre>
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Cherry-pick from main (bottom-to-top)
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
branch develop
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
commit id:"A"
|
||||||
|
checkout develop
|
||||||
|
commit
|
||||||
|
cherry-pick id: "A"
|
||||||
|
</pre
|
||||||
|
>
|
||||||
<h2>Cherry-pick then merge graph</h2>
|
<h2>Cherry-pick then merge graph</h2>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
---
|
---
|
||||||
@@ -234,6 +328,24 @@
|
|||||||
cherry-pick id: "Pick me"
|
cherry-pick id: "Pick me"
|
||||||
merge newbranch
|
merge newbranch
|
||||||
</pre>
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Cherry-pick then merge (bottom-to-top)
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
branch newbranch
|
||||||
|
checkout newbranch
|
||||||
|
commit id: "Pick me"
|
||||||
|
checkout main
|
||||||
|
commit
|
||||||
|
checkout newbranch
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
cherry-pick id: "Pick me"
|
||||||
|
merge newbranch
|
||||||
|
</pre
|
||||||
|
>
|
||||||
<h2>Merge from main onto undeveloped branch graph</h2>
|
<h2>Merge from main onto undeveloped branch graph</h2>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
---
|
---
|
||||||
@@ -261,6 +373,20 @@
|
|||||||
checkout develop
|
checkout develop
|
||||||
merge main
|
merge main
|
||||||
</pre>
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Merge from main onto undeveloped branch (bottom-to-top)
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
branch develop
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
commit
|
||||||
|
checkout develop
|
||||||
|
merge main
|
||||||
|
</pre
|
||||||
|
>
|
||||||
<h2>Merge from main onto developed branch graph</h2>
|
<h2>Merge from main onto developed branch graph</h2>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
---
|
---
|
||||||
@@ -290,6 +416,21 @@
|
|||||||
commit
|
commit
|
||||||
merge main
|
merge main
|
||||||
</pre>
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Merge from main onto developed branch (bottom-to-top)
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
branch develop
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
commit
|
||||||
|
checkout develop
|
||||||
|
commit
|
||||||
|
merge main
|
||||||
|
</pre
|
||||||
|
>
|
||||||
<h2>Two branches from same commit graph</h2>
|
<h2>Two branches from same commit graph</h2>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
---
|
---
|
||||||
@@ -323,6 +464,23 @@
|
|||||||
checkout feature-001
|
checkout feature-001
|
||||||
merge feature-002
|
merge feature-002
|
||||||
</pre>
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Two branches from same commit (bottom-to-top)
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
branch feature-001
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
branch feature-002
|
||||||
|
commit
|
||||||
|
checkout feature-001
|
||||||
|
merge feature-002
|
||||||
|
</pre
|
||||||
|
>
|
||||||
<h2>Three branches and a cherry-pick from each graph</h2>
|
<h2>Three branches and a cherry-pick from each graph</h2>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
---
|
---
|
||||||
@@ -372,6 +530,30 @@
|
|||||||
commit id:"C"
|
commit id:"C"
|
||||||
merge featureA
|
merge featureA
|
||||||
</pre>
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
---
|
||||||
|
title: Three branches and a cherry-pick from each (bottom-to-top)
|
||||||
|
---
|
||||||
|
gitGraph BT:
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
commit id:"ONE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"B"
|
||||||
|
branch featureA
|
||||||
|
commit id:"FIX"
|
||||||
|
commit id: "FIX-2"
|
||||||
|
checkout main
|
||||||
|
commit id:"TWO"
|
||||||
|
cherry-pick id:"A"
|
||||||
|
commit id:"THREE"
|
||||||
|
cherry-pick id:"FIX"
|
||||||
|
checkout develop
|
||||||
|
commit id:"C"
|
||||||
|
merge featureA
|
||||||
|
</pre>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import mermaid from './mermaid.esm.mjs';
|
import mermaid from './mermaid.esm.mjs';
|
||||||
const ALLOWED_TAGS = [
|
const ALLOWED_TAGS = [
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ Pushes in a directive to the configuration
|
|||||||
| --------- | ------------------------- | ----------- | ------------------------------ |
|
| --------- | ------------------------- | ----------- | ------------------------------ |
|
||||||
| getConfig | Obtains the currentConfig | Get Request | Any Values from current Config |
|
| getConfig | Obtains the currentConfig | Get Request | Any Values from current Config |
|
||||||
|
|
||||||
**Notes**: Returns **any** the currentConfig
|
**Notes**: Avoid calling this function repeatedly. Instead, store the result in a variable and use it, and pass it down to function calls.
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
|
|
||||||
|
|||||||
@@ -852,6 +852,16 @@ Formatting:
|
|||||||
|
|
||||||
This feature is applicable to node labels, edge labels, and subgraph labels.
|
This feature is applicable to node labels, edge labels, and subgraph labels.
|
||||||
|
|
||||||
|
The auto wrapping can be disabled by using
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
markdownAutoWrap: false
|
||||||
|
---
|
||||||
|
graph LR
|
||||||
|
```
|
||||||
|
|
||||||
## Interaction
|
## Interaction
|
||||||
|
|
||||||
It is possible to bind a click event to a node, the click can lead to either a javascript callback or to a link which will be opened in a new browser tab.
|
It is possible to bind a click event to a node, the click can lead to either a javascript callback or to a link which will be opened in a new browser tab.
|
||||||
|
|||||||
@@ -836,9 +836,9 @@ Here, we have changed the default main branch name to `MetroLine1`.
|
|||||||
|
|
||||||
## Orientation (v10.3.0+)
|
## Orientation (v10.3.0+)
|
||||||
|
|
||||||
Mermaid supports two graph orientations: **Left-to-Right** (default) and **Top-to-Bottom**.
|
Mermaid supports three graph orientations: **Left-to-Right** (default), **Top-to-Bottom**, and **Bottom-to-Top**.
|
||||||
|
|
||||||
You can set this with either `LR:` (for [**Left-to-Right**](#left-to-right-default-lr)) or `TB:` (for [**Top-to-Bottom**](#top-to-bottom-tb)) after `gitGraph`.
|
You can set this with either `LR:` (for [**Left-to-Right**](#left-to-right-default-lr)), `TB:` (for [**Top-to-Bottom**](#top-to-bottom-tb)) or `BT:` (for [**Bottom-to-Top**](#bottom-to-top-bt)) after `gitGraph`.
|
||||||
|
|
||||||
### Left to Right (default, `LR:`)
|
### Left to Right (default, `LR:`)
|
||||||
|
|
||||||
@@ -916,6 +916,44 @@ Usage example:
|
|||||||
commit
|
commit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Bottom to Top (`BT:`) (v\<MERMAID_RELEASE_VERSION>+)
|
||||||
|
|
||||||
|
In `BT` (**Bottom-to-Top**) orientation, the commits run from bottom to top of the graph and branches are arranged side-by-side.
|
||||||
|
|
||||||
|
To orient the graph this way, you need to add `BT:` after gitGraph.
|
||||||
|
|
||||||
|
Usage example:
|
||||||
|
|
||||||
|
```mermaid-example
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
branch develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
merge develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
branch develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
merge develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
```
|
||||||
|
|
||||||
## Parallel commits (v10.8.0+)
|
## Parallel commits (v10.8.0+)
|
||||||
|
|
||||||
Commits in Mermaid display temporal information in gitgraph by default. For example if two commits are one commit away from its parent, the commit that was made earlier is rendered closer to its parent. You can turn this off by enabling the `parallelCommits` flag.
|
Commits in Mermaid display temporal information in gitgraph by default. For example if two commits are one commit away from its parent, the commit that was made earlier is rendered closer to its parent. You can turn this off by enabling the `parallelCommits` flag.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @ts-ignore: JISON typing missing
|
// @ts-ignore: JISON typing missing
|
||||||
import parser from '../../mermaid/src/diagrams/flowchart/parser/flow.jison';
|
import parser from '../../mermaid/src/diagrams/flowchart/parser/flow.jison';
|
||||||
import * as db from '../../mermaid/src/diagrams/flowchart/flowDb.js';
|
import db from '../../mermaid/src/diagrams/flowchart/flowDb.js';
|
||||||
import styles from '../../mermaid/src/diagrams/flowchart/styles.js';
|
import styles from '../../mermaid/src/diagrams/flowchart/styles.js';
|
||||||
import renderer from './flowRenderer-elk.js';
|
import renderer from './flowRenderer-elk.js';
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { findCommonAncestor } from './render-utils.js';
|
|||||||
import { labelHelper } from '../../mermaid/src/dagre-wrapper/shapes/util.js';
|
import { labelHelper } from '../../mermaid/src/dagre-wrapper/shapes/util.js';
|
||||||
import { getConfig } from '../../mermaid/src/config.js';
|
import { getConfig } from '../../mermaid/src/config.js';
|
||||||
import { log } from '../../mermaid/src/logger.js';
|
import { log } from '../../mermaid/src/logger.js';
|
||||||
|
import utils from '../../mermaid/src/utils.js';
|
||||||
import { setupGraphViewbox } from '../../mermaid/src/setupGraphViewbox.js';
|
import { setupGraphViewbox } from '../../mermaid/src/setupGraphViewbox.js';
|
||||||
import common from '../../mermaid/src/diagrams/common/common.js';
|
import common from '../../mermaid/src/diagrams/common/common.js';
|
||||||
import { interpolateToCurve, getStylesFromArray } from '../../mermaid/src/utils.js';
|
import { interpolateToCurve, getStylesFromArray } from '../../mermaid/src/utils.js';
|
||||||
@@ -655,6 +656,11 @@ const insertEdge = function (edgesEl, edge, edgeData, diagObj, parentLookupDb, i
|
|||||||
.attr('d', curve(points))
|
.attr('d', curve(points))
|
||||||
.attr('class', 'path ' + edgeData.classes)
|
.attr('class', 'path ' + edgeData.classes)
|
||||||
.attr('fill', 'none');
|
.attr('fill', 'none');
|
||||||
|
Object.entries(edgeData).forEach(([key, value]) => {
|
||||||
|
if (key !== 'classes') {
|
||||||
|
edgePath.attr(key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
const edgeG = edgesEl.insert('g').attr('class', 'edgeLabel');
|
const edgeG = edgesEl.insert('g').attr('class', 'edgeLabel');
|
||||||
const edgeWithLabel = select(edgeG.node().appendChild(edge.labelEl));
|
const edgeWithLabel = select(edgeG.node().appendChild(edge.labelEl));
|
||||||
const box = edgeWithLabel.node().firstChild.getBoundingClientRect();
|
const box = edgeWithLabel.node().firstChild.getBoundingClientRect();
|
||||||
@@ -702,21 +708,15 @@ const insertChildren = (nodeArray, parentLookupDb) => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export const draw = async function (text, id, _version, diagObj) {
|
export const draw = async function (text, id, _version, diagObj) {
|
||||||
// Add temporary render element
|
const { securityLevel, flowchart: conf } = getConfig();
|
||||||
diagObj.db.clear();
|
|
||||||
nodeDb = {};
|
nodeDb = {};
|
||||||
portPos = {};
|
portPos = {};
|
||||||
diagObj.db.setGen('gen-2');
|
|
||||||
// Parse the graph definition
|
|
||||||
diagObj.parser.parse(text);
|
|
||||||
|
|
||||||
const renderEl = select('body').append('div').attr('style', 'height:400px').attr('id', 'cy');
|
const renderEl = select('body').append('div').attr('style', 'height:400px').attr('id', 'cy');
|
||||||
let graph = {
|
let graph = {
|
||||||
id: 'root',
|
id: 'root',
|
||||||
layoutOptions: {
|
layoutOptions: {
|
||||||
'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
|
'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
|
||||||
'org.eclipse.elk.padding': '[top=100, left=100, bottom=110, right=110]',
|
'elk.layered.spacing.edgeNodeBetweenLayers': conf?.nodeSpacing ? `${conf.nodeSpacing}` : '30',
|
||||||
'elk.layered.spacing.edgeNodeBetweenLayers': '30',
|
|
||||||
// 'elk.layered.mergeEdges': 'true',
|
// 'elk.layered.mergeEdges': 'true',
|
||||||
'elk.direction': 'DOWN',
|
'elk.direction': 'DOWN',
|
||||||
// 'elk.ports.sameLayerEdges': true,
|
// 'elk.ports.sameLayerEdges': true,
|
||||||
@@ -744,7 +744,6 @@ export const draw = async function (text, id, _version, diagObj) {
|
|||||||
graph.layoutOptions['elk.direction'] = 'LEFT';
|
graph.layoutOptions['elk.direction'] = 'LEFT';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const { securityLevel, flowchart: conf } = getConfig();
|
|
||||||
|
|
||||||
// Find the root dom node to ne used in rendering
|
// Find the root dom node to ne used in rendering
|
||||||
// Handle root and document for when rendering in sandbox mode
|
// Handle root and document for when rendering in sandbox mode
|
||||||
@@ -759,7 +758,6 @@ export const draw = async function (text, id, _version, diagObj) {
|
|||||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||||
|
|
||||||
const svg = root.select(`[id="${id}"]`);
|
const svg = root.select(`[id="${id}"]`);
|
||||||
|
|
||||||
// Define the supported markers for the diagram
|
// Define the supported markers for the diagram
|
||||||
const markers = ['point', 'circle', 'cross'];
|
const markers = ['point', 'circle', 'cross'];
|
||||||
|
|
||||||
@@ -841,6 +839,7 @@ export const draw = async function (text, id, _version, diagObj) {
|
|||||||
log.info('after layout', JSON.stringify(graph, null, 2));
|
log.info('after layout', JSON.stringify(graph, null, 2));
|
||||||
const g = await elk.layout(graph);
|
const g = await elk.layout(graph);
|
||||||
drawNodes(0, 0, g.children, svg, subGraphsEl, diagObj, 0);
|
drawNodes(0, 0, g.children, svg, subGraphsEl, diagObj, 0);
|
||||||
|
utils.insertTitle(svg, 'flowchartTitleText', conf.titleTopMargin, diagObj.db.getDiagramTitle());
|
||||||
log.info('after layout', g);
|
log.info('after layout', g);
|
||||||
g.edges?.map((edge) => {
|
g.edges?.map((edge) => {
|
||||||
insertEdge(edgesEl, edge, edge.edgeData, diagObj, parentLookupDb, id);
|
insertEdge(edgesEl, edge, edge.edgeData, diagObj, parentLookupDb, id);
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ export const setConfig = (conf: MermaidConfig): MermaidConfig => {
|
|||||||
* | --------- | ------------------------- | ----------- | ------------------------------ |
|
* | --------- | ------------------------- | ----------- | ------------------------------ |
|
||||||
* | getConfig | Obtains the currentConfig | Get Request | Any Values from current Config |
|
* | getConfig | Obtains the currentConfig | Get Request | Any Values from current Config |
|
||||||
*
|
*
|
||||||
* **Notes**: Returns **any** the currentConfig
|
* **Notes**: Avoid calling this function repeatedly. Instead, store the result in a variable and use it, and pass it down to function calls.
|
||||||
*
|
*
|
||||||
* @returns The currentConfig
|
* @returns The currentConfig
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ export interface MermaidConfig {
|
|||||||
dompurifyConfig?: DOMPurifyConfiguration;
|
dompurifyConfig?: DOMPurifyConfiguration;
|
||||||
wrap?: boolean;
|
wrap?: boolean;
|
||||||
fontSize?: number;
|
fontSize?: number;
|
||||||
|
markdownAutoWrap?: boolean;
|
||||||
/**
|
/**
|
||||||
* Suppresses inserting 'Syntax error' diagram in the DOM.
|
* Suppresses inserting 'Syntax error' diagram in the DOM.
|
||||||
* This is useful when you want to control how to handle syntax errors in your application.
|
* This is useful when you want to control how to handle syntax errors in your application.
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const rect = (parent, node) => {
|
|||||||
// .appendChild(createLabel(node.labelText, node.labelStyle, undefined, true));
|
// .appendChild(createLabel(node.labelText, node.labelStyle, undefined, true));
|
||||||
const text =
|
const text =
|
||||||
node.labelType === 'markdown'
|
node.labelType === 'markdown'
|
||||||
? createText(label, node.labelText, { style: node.labelStyle, useHtmlLabels })
|
? createText(label, node.labelText, { style: node.labelStyle, useHtmlLabels }, siteConfig)
|
||||||
: label.node().appendChild(createLabel(node.labelText, node.labelStyle, undefined, true));
|
: label.node().appendChild(createLabel(node.labelText, node.labelStyle, undefined, true));
|
||||||
|
|
||||||
// Get the size of the label
|
// Get the size of the label
|
||||||
|
|||||||
@@ -18,15 +18,21 @@ export const clear = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const insertEdgeLabel = (elem, edge) => {
|
export const insertEdgeLabel = (elem, edge) => {
|
||||||
const useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
|
const config = getConfig();
|
||||||
|
const useHtmlLabels = evaluate(config.flowchart.htmlLabels);
|
||||||
// Create the actual text element
|
// Create the actual text element
|
||||||
const labelElement =
|
const labelElement =
|
||||||
edge.labelType === 'markdown'
|
edge.labelType === 'markdown'
|
||||||
? createText(elem, edge.label, {
|
? createText(
|
||||||
style: edge.labelStyle,
|
elem,
|
||||||
useHtmlLabels,
|
edge.label,
|
||||||
addSvgBackground: true,
|
{
|
||||||
})
|
style: edge.labelStyle,
|
||||||
|
useHtmlLabels,
|
||||||
|
addSvgBackground: true,
|
||||||
|
},
|
||||||
|
config
|
||||||
|
)
|
||||||
: createLabel(edge.label, edge.labelStyle);
|
: createLabel(edge.label, edge.labelStyle);
|
||||||
|
|
||||||
// Create outer g, edgeLabel, this will be positioned after graph layout
|
// Create outer g, edgeLabel, this will be positioned after graph layout
|
||||||
|
|||||||
@@ -54,6 +54,14 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
|
|||||||
if (node && node.clusterNode) {
|
if (node && node.clusterNode) {
|
||||||
// const children = graph.children(v);
|
// const children = graph.children(v);
|
||||||
log.info('Cluster identified', v, node.width, graph.node(v));
|
log.info('Cluster identified', v, node.width, graph.node(v));
|
||||||
|
// `node.graph.setGraph` applies the graph configurations such as nodeSpacing to subgraphs as without this the default values would be used
|
||||||
|
// We override only the `ranksep` and `nodesep` configurations to allow for setting subgraph spacing while avoiding overriding other properties
|
||||||
|
const { ranksep, nodesep } = graph.graph();
|
||||||
|
node.graph.setGraph({
|
||||||
|
...node.graph.graph(),
|
||||||
|
ranksep,
|
||||||
|
nodesep,
|
||||||
|
});
|
||||||
const o = await recursiveRender(
|
const o = await recursiveRender(
|
||||||
nodes,
|
nodes,
|
||||||
node.graph,
|
node.graph,
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ import { evaluate, sanitizeText } from '../../diagrams/common/common.js';
|
|||||||
import { decodeEntities } from '../../utils.js';
|
import { decodeEntities } from '../../utils.js';
|
||||||
|
|
||||||
export const labelHelper = async (parent, node, _classes, isNode) => {
|
export const labelHelper = async (parent, node, _classes, isNode) => {
|
||||||
|
const config = getConfig();
|
||||||
let classes;
|
let classes;
|
||||||
const useHtmlLabels = node.useHtmlLabels || evaluate(getConfig().flowchart.htmlLabels);
|
const useHtmlLabels = node.useHtmlLabels || evaluate(config.flowchart.htmlLabels);
|
||||||
if (!_classes) {
|
if (!_classes) {
|
||||||
classes = 'node default';
|
classes = 'node default';
|
||||||
} else {
|
} else {
|
||||||
@@ -35,26 +36,26 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
|
|||||||
let text;
|
let text;
|
||||||
if (node.labelType === 'markdown') {
|
if (node.labelType === 'markdown') {
|
||||||
// text = textNode;
|
// text = textNode;
|
||||||
text = createText(label, sanitizeText(decodeEntities(labelText), getConfig()), {
|
text = createText(
|
||||||
useHtmlLabels,
|
label,
|
||||||
width: node.width || getConfig().flowchart.wrappingWidth,
|
sanitizeText(decodeEntities(labelText), config),
|
||||||
classes: 'markdown-node-label',
|
{
|
||||||
});
|
useHtmlLabels,
|
||||||
|
width: node.width || config.flowchart.wrappingWidth,
|
||||||
|
classes: 'markdown-node-label',
|
||||||
|
},
|
||||||
|
config
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
text = textNode.appendChild(
|
text = textNode.appendChild(
|
||||||
createLabel(
|
createLabel(sanitizeText(decodeEntities(labelText), config), node.labelStyle, false, isNode)
|
||||||
sanitizeText(decodeEntities(labelText), getConfig()),
|
|
||||||
node.labelStyle,
|
|
||||||
false,
|
|
||||||
isNode
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Get the size of the label
|
// Get the size of the label
|
||||||
let bbox = text.getBBox();
|
let bbox = text.getBBox();
|
||||||
const halfPadding = node.padding / 2;
|
const halfPadding = node.padding / 2;
|
||||||
|
|
||||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
if (evaluate(config.flowchart.htmlLabels)) {
|
||||||
const div = text.children[0];
|
const div = text.children[0];
|
||||||
const dv = select(text);
|
const dv = select(text);
|
||||||
|
|
||||||
@@ -76,8 +77,8 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
|
|||||||
|
|
||||||
if (noImgText) {
|
if (noImgText) {
|
||||||
// default size if no text
|
// default size if no text
|
||||||
const bodyFontSize = getConfig().fontSize
|
const bodyFontSize = config.fontSize
|
||||||
? getConfig().fontSize
|
? config.fontSize
|
||||||
: window.getComputedStyle(document.body).fontSize;
|
: window.getComputedStyle(document.body).fontSize;
|
||||||
const enlargingFactor = 5;
|
const enlargingFactor = 5;
|
||||||
const width = parseInt(bodyFontSize, 10) * enlargingFactor + 'px';
|
const width = parseInt(bodyFontSize, 10) * enlargingFactor + 'px';
|
||||||
|
|||||||
@@ -346,11 +346,9 @@ export const renderKatex = async (text: string, config: MermaidConfig): Promise<
|
|||||||
.split(lineBreakRegex)
|
.split(lineBreakRegex)
|
||||||
.map((line) =>
|
.map((line) =>
|
||||||
hasKatex(line)
|
hasKatex(line)
|
||||||
? `
|
? `<div style="display: flex; align-items: center; justify-content: center; white-space: nowrap;">
|
||||||
<div style="display: flex; align-items: center; justify-content: center; white-space: nowrap;">
|
|
||||||
${line}
|
${line}
|
||||||
</div>
|
</div>`
|
||||||
`
|
|
||||||
: `<div>${line}</div>`
|
: `<div>${line}</div>`
|
||||||
)
|
)
|
||||||
.join('')
|
.join('')
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ describe('when parsing a gitGraph', function () {
|
|||||||
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
|
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle set direction', function () {
|
it('should handle set direction top to bottom', function () {
|
||||||
const str = 'gitGraph TB:\n' + 'commit\n';
|
const str = 'gitGraph TB:\n' + 'commit\n';
|
||||||
|
|
||||||
parser.parse(str);
|
parser.parse(str);
|
||||||
@@ -66,6 +66,18 @@ describe('when parsing a gitGraph', function () {
|
|||||||
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
|
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle set direction bottom to top', function () {
|
||||||
|
const str = 'gitGraph BT:\n' + 'commit\n';
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
const commits = parser.yy.getCommits();
|
||||||
|
|
||||||
|
expect(Object.keys(commits).length).toBe(1);
|
||||||
|
expect(parser.yy.getCurrentBranch()).toBe('main');
|
||||||
|
expect(parser.yy.getDirection()).toBe('BT');
|
||||||
|
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
it('should checkout a branch', function () {
|
it('should checkout a branch', function () {
|
||||||
const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n';
|
const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n';
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ let commitPos = {};
|
|||||||
let lanes = [];
|
let lanes = [];
|
||||||
let maxPos = 0;
|
let maxPos = 0;
|
||||||
let dir = 'LR';
|
let dir = 'LR';
|
||||||
|
let defaultPos = 30;
|
||||||
const clear = () => {
|
const clear = () => {
|
||||||
branchPos = {};
|
branchPos = {};
|
||||||
commitPos = {};
|
commitPos = {};
|
||||||
@@ -77,7 +78,7 @@ const findClosestParent = (parents) => {
|
|||||||
let maxPosition = 0;
|
let maxPosition = 0;
|
||||||
|
|
||||||
parents.forEach((parent) => {
|
parents.forEach((parent) => {
|
||||||
const parentPosition = dir === 'TB' ? commitPos[parent].y : commitPos[parent].x;
|
const parentPosition = dir === 'TB' || dir === 'BT' ? commitPos[parent].y : commitPos[parent].x;
|
||||||
if (parentPosition >= maxPosition) {
|
if (parentPosition >= maxPosition) {
|
||||||
closestParent = parent;
|
closestParent = parent;
|
||||||
maxPosition = parentPosition;
|
maxPosition = parentPosition;
|
||||||
@@ -87,6 +88,83 @@ const findClosestParent = (parents) => {
|
|||||||
return closestParent || undefined;
|
return closestParent || undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the closest parent from the parents list passed as argument for Bottom-to-Top orientation.
|
||||||
|
* The parents list comes from an individual commit. The closest parent is actually
|
||||||
|
* the one farther down the graph, since that means it is closer to its child.
|
||||||
|
*
|
||||||
|
* @param {string[]} parents
|
||||||
|
* @returns {string | undefined}
|
||||||
|
*/
|
||||||
|
const findClosestParentBT = (parents) => {
|
||||||
|
let closestParent = '';
|
||||||
|
let maxPosition = Infinity;
|
||||||
|
|
||||||
|
parents.forEach((parent) => {
|
||||||
|
const parentPosition = commitPos[parent].y;
|
||||||
|
if (parentPosition <= maxPosition) {
|
||||||
|
closestParent = parent;
|
||||||
|
maxPosition = parentPosition;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return closestParent || undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the position of the commit elements when the orientation is set to BT-Parallel.
|
||||||
|
* This is needed to render the chart in Bottom-to-Top mode while keeping the parallel
|
||||||
|
* commits in the correct position. First, it finds the correct position of the root commit
|
||||||
|
* using the findClosestParent method. Then, it uses the findClosestParentBT to set the position
|
||||||
|
* of the remaining commits.
|
||||||
|
*
|
||||||
|
* @param {any} sortedKeys
|
||||||
|
* @param {any} commits
|
||||||
|
* @param {any} defaultPos
|
||||||
|
* @param {any} commitStep
|
||||||
|
* @param {any} layoutOffset
|
||||||
|
*/
|
||||||
|
const setParallelBTPos = (sortedKeys, commits, defaultPos, commitStep, layoutOffset) => {
|
||||||
|
let curPos = defaultPos;
|
||||||
|
let maxPosition = defaultPos;
|
||||||
|
let roots = [];
|
||||||
|
sortedKeys.forEach((key) => {
|
||||||
|
const commit = commits[key];
|
||||||
|
if (commit.parents.length) {
|
||||||
|
const closestParent = findClosestParent(commit.parents);
|
||||||
|
curPos = commitPos[closestParent].y + commitStep;
|
||||||
|
if (curPos >= maxPosition) {
|
||||||
|
maxPosition = curPos;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
roots.push(commit);
|
||||||
|
}
|
||||||
|
const x = branchPos[commit.branch].pos;
|
||||||
|
const y = curPos + layoutOffset;
|
||||||
|
commitPos[commit.id] = { x: x, y: y };
|
||||||
|
});
|
||||||
|
curPos = maxPosition;
|
||||||
|
roots.forEach((commit) => {
|
||||||
|
const posWithOffset = curPos + defaultPos;
|
||||||
|
const y = posWithOffset;
|
||||||
|
const x = branchPos[commit.branch].pos;
|
||||||
|
commitPos[commit.id] = { x: x, y: y };
|
||||||
|
});
|
||||||
|
sortedKeys.forEach((key) => {
|
||||||
|
const commit = commits[key];
|
||||||
|
if (commit.parents.length) {
|
||||||
|
const closestParent = findClosestParentBT(commit.parents);
|
||||||
|
curPos = commitPos[closestParent].y - commitStep;
|
||||||
|
if (curPos <= maxPosition) {
|
||||||
|
maxPosition = curPos;
|
||||||
|
}
|
||||||
|
const x = branchPos[commit.branch].pos;
|
||||||
|
const y = curPos - layoutOffset;
|
||||||
|
commitPos[commit.id] = { x: x, y: y };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws the commits with its symbol and labels. The function has two modes, one which only
|
* Draws the commits with its symbol and labels. The function has two modes, one which only
|
||||||
* calculates the positions and one that does the actual drawing. This for a simple way getting the
|
* calculates the positions and one that does the actual drawing. This for a simple way getting the
|
||||||
@@ -102,39 +180,54 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
|||||||
const gLabels = svg.append('g').attr('class', 'commit-labels');
|
const gLabels = svg.append('g').attr('class', 'commit-labels');
|
||||||
let pos = 0;
|
let pos = 0;
|
||||||
|
|
||||||
if (dir === 'TB') {
|
if (dir === 'TB' || dir === 'BT') {
|
||||||
pos = 30;
|
pos = defaultPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = Object.keys(commits);
|
const keys = Object.keys(commits);
|
||||||
const sortedKeys = keys.sort((a, b) => {
|
|
||||||
return commits[a].seq - commits[b].seq;
|
|
||||||
});
|
|
||||||
|
|
||||||
const isParallelCommits = gitGraphConfig.parallelCommits;
|
const isParallelCommits = gitGraphConfig.parallelCommits;
|
||||||
const layoutOffset = 10;
|
const layoutOffset = 10;
|
||||||
const commitStep = 40;
|
const commitStep = 40;
|
||||||
|
let sortedKeys =
|
||||||
|
dir !== 'BT' || (dir === 'BT' && isParallelCommits)
|
||||||
|
? keys.sort((a, b) => {
|
||||||
|
return commits[a].seq - commits[b].seq;
|
||||||
|
})
|
||||||
|
: keys
|
||||||
|
.sort((a, b) => {
|
||||||
|
return commits[a].seq - commits[b].seq;
|
||||||
|
})
|
||||||
|
.reverse();
|
||||||
|
|
||||||
|
if (dir === 'BT' && isParallelCommits) {
|
||||||
|
setParallelBTPos(sortedKeys, commits, pos, commitStep, layoutOffset);
|
||||||
|
sortedKeys = sortedKeys.reverse();
|
||||||
|
}
|
||||||
sortedKeys.forEach((key) => {
|
sortedKeys.forEach((key) => {
|
||||||
const commit = commits[key];
|
const commit = commits[key];
|
||||||
|
|
||||||
if (isParallelCommits) {
|
if (isParallelCommits) {
|
||||||
if (commit.parents.length) {
|
if (commit.parents.length) {
|
||||||
const closestParent = findClosestParent(commit.parents);
|
const closestParent =
|
||||||
pos =
|
dir === 'BT' ? findClosestParentBT(commit.parents) : findClosestParent(commit.parents);
|
||||||
dir === 'TB'
|
|
||||||
? commitPos[closestParent].y + commitStep
|
|
||||||
: commitPos[closestParent].x + commitStep;
|
|
||||||
} else {
|
|
||||||
pos = 0;
|
|
||||||
if (dir === 'TB') {
|
if (dir === 'TB') {
|
||||||
pos = 30;
|
pos = commitPos[closestParent].y + commitStep;
|
||||||
|
} else if (dir === 'BT') {
|
||||||
|
pos = commitPos[key].y - commitStep;
|
||||||
|
} else {
|
||||||
|
pos = commitPos[closestParent].x + commitStep;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dir === 'TB') {
|
||||||
|
pos = defaultPos;
|
||||||
|
} else if (dir === 'BT') {
|
||||||
|
pos = commitPos[key].y - commitStep;
|
||||||
|
} else {
|
||||||
|
pos = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const posWithOffset = dir === 'BT' && isParallelCommits ? pos : pos + layoutOffset;
|
||||||
const posWithOffset = pos + layoutOffset;
|
const y = dir === 'TB' || dir === 'BT' ? posWithOffset : branchPos[commit.branch].pos;
|
||||||
const y = dir === 'TB' ? posWithOffset : branchPos[commit.branch].pos;
|
const x = dir === 'TB' || dir === 'BT' ? branchPos[commit.branch].pos : posWithOffset;
|
||||||
const x = dir === 'TB' ? branchPos[commit.branch].pos : posWithOffset;
|
|
||||||
|
|
||||||
// Don't draw the commits now but calculate the positioning which is used by the branch lines etc.
|
// Don't draw the commits now but calculate the positioning which is used by the branch lines etc.
|
||||||
if (modifyGraph) {
|
if (modifyGraph) {
|
||||||
@@ -258,7 +351,7 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dir === 'TB') {
|
if (dir === 'TB' || dir === 'BT') {
|
||||||
commitPos[commit.id] = { x: x, y: posWithOffset };
|
commitPos[commit.id] = { x: x, y: posWithOffset };
|
||||||
} else {
|
} else {
|
||||||
commitPos[commit.id] = { x: posWithOffset, y: y };
|
commitPos[commit.id] = { x: posWithOffset, y: y };
|
||||||
@@ -295,16 +388,14 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
|||||||
.attr('width', bbox.width + 2 * py)
|
.attr('width', bbox.width + 2 * py)
|
||||||
.attr('height', bbox.height + 2 * py);
|
.attr('height', bbox.height + 2 * py);
|
||||||
|
|
||||||
if (dir === 'TB') {
|
if (dir === 'TB' || dir === 'BT') {
|
||||||
labelBkg.attr('x', x - (bbox.width + 4 * px + 5)).attr('y', y - 12);
|
labelBkg.attr('x', x - (bbox.width + 4 * px + 5)).attr('y', y - 12);
|
||||||
text.attr('x', x - (bbox.width + 4 * px)).attr('y', y + bbox.height - 12);
|
text.attr('x', x - (bbox.width + 4 * px)).attr('y', y + bbox.height - 12);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
if (dir !== 'TB') {
|
|
||||||
text.attr('x', posWithOffset - bbox.width / 2);
|
text.attr('x', posWithOffset - bbox.width / 2);
|
||||||
}
|
}
|
||||||
if (gitGraphConfig.rotateCommitLabel) {
|
if (gitGraphConfig.rotateCommitLabel) {
|
||||||
if (dir === 'TB') {
|
if (dir === 'TB' || dir === 'BT') {
|
||||||
text.attr('transform', 'rotate(' + -45 + ', ' + x + ', ' + y + ')');
|
text.attr('transform', 'rotate(' + -45 + ', ' + x + ', ' + y + ')');
|
||||||
labelBkg.attr('transform', 'rotate(' + -45 + ', ' + x + ', ' + y + ')');
|
labelBkg.attr('transform', 'rotate(' + -45 + ', ' + x + ', ' + y + ')');
|
||||||
} else {
|
} else {
|
||||||
@@ -348,7 +439,7 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
|||||||
.attr('r', 1.5)
|
.attr('r', 1.5)
|
||||||
.attr('class', 'tag-hole');
|
.attr('class', 'tag-hole');
|
||||||
|
|
||||||
if (dir === 'TB') {
|
if (dir === 'TB' || dir === 'BT') {
|
||||||
rect
|
rect
|
||||||
.attr('class', 'tag-label-bkg')
|
.attr('class', 'tag-label-bkg')
|
||||||
.attr(
|
.attr(
|
||||||
@@ -373,7 +464,7 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pos += commitStep + layoutOffset;
|
pos = dir === 'BT' && isParallelCommits ? pos + commitStep : pos + commitStep + layoutOffset;
|
||||||
if (pos > maxPos) {
|
if (pos > maxPos) {
|
||||||
maxPos = pos;
|
maxPos = pos;
|
||||||
}
|
}
|
||||||
@@ -389,7 +480,6 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
|||||||
*
|
*
|
||||||
* @param {any} commitA
|
* @param {any} commitA
|
||||||
* @param {any} commitB
|
* @param {any} commitB
|
||||||
* @param branchToGetCurve
|
|
||||||
* @param p1
|
* @param p1
|
||||||
* @param p2
|
* @param p2
|
||||||
* @param allCommits
|
* @param allCommits
|
||||||
@@ -402,7 +492,7 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
|||||||
* return true
|
* return true
|
||||||
*/
|
*/
|
||||||
const shouldRerouteArrow = (commitA, commitB, p1, p2, allCommits) => {
|
const shouldRerouteArrow = (commitA, commitB, p1, p2, allCommits) => {
|
||||||
const commitBIsFurthest = dir === 'TB' ? p1.x < p2.x : p1.y < p2.y;
|
const commitBIsFurthest = dir === 'TB' || dir === 'BT' ? p1.x < p2.x : p1.y < p2.y;
|
||||||
const branchToGetCurve = commitBIsFurthest ? commitB.branch : commitA.branch;
|
const branchToGetCurve = commitBIsFurthest ? commitB.branch : commitA.branch;
|
||||||
const isOnBranchToGetCurve = (x) => x.branch === branchToGetCurve;
|
const isOnBranchToGetCurve = (x) => x.branch === branchToGetCurve;
|
||||||
const isBetweenCommits = (x) => x.seq > commitA.seq && x.seq < commitB.seq;
|
const isBetweenCommits = (x) => x.seq > commitA.seq && x.seq < commitB.seq;
|
||||||
@@ -485,6 +575,21 @@ const drawArrow = (svg, commitA, commitB, allCommits) => {
|
|||||||
p1.y + offset
|
p1.y + offset
|
||||||
} L ${lineX} ${p2.y - radius} ${arc2} ${lineX - offset} ${p2.y} L ${p2.x} ${p2.y}`;
|
} L ${lineX} ${p2.y - radius} ${arc2} ${lineX - offset} ${p2.y} L ${p2.x} ${p2.y}`;
|
||||||
}
|
}
|
||||||
|
} else if (dir === 'BT') {
|
||||||
|
if (p1.x < p2.x) {
|
||||||
|
// Source commit is on branch position left of destination commit
|
||||||
|
// so render arrow rightward with colour of destination branch
|
||||||
|
lineDef = `M ${p1.x} ${p1.y} L ${lineX - radius} ${p1.y} ${arc} ${lineX} ${
|
||||||
|
p1.y - offset
|
||||||
|
} L ${lineX} ${p2.y + radius} ${arc2} ${lineX + offset} ${p2.y} L ${p2.x} ${p2.y}`;
|
||||||
|
} else {
|
||||||
|
// Source commit is on branch position right of destination commit
|
||||||
|
// so render arrow leftward with colour of source branch
|
||||||
|
colorClassNum = branchPos[commitA.branch].index;
|
||||||
|
lineDef = `M ${p1.x} ${p1.y} L ${lineX + radius} ${p1.y} ${arc2} ${lineX} ${
|
||||||
|
p1.y - offset
|
||||||
|
} L ${lineX} ${p2.y + radius} ${arc} ${lineX - offset} ${p2.y} L ${p2.x} ${p2.y}`;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (p1.y < p2.y) {
|
if (p1.y < p2.y) {
|
||||||
// Source commit is on branch positioned above destination commit
|
// Source commit is on branch positioned above destination commit
|
||||||
@@ -524,7 +629,6 @@ const drawArrow = (svg, commitA, commitB, allCommits) => {
|
|||||||
arc2 = 'A 20 20, 0, 0, 1,';
|
arc2 = 'A 20 20, 0, 0, 1,';
|
||||||
radius = 20;
|
radius = 20;
|
||||||
offset = 20;
|
offset = 20;
|
||||||
|
|
||||||
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
|
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
|
||||||
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc2} ${p1.x - offset} ${
|
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc2} ${p1.x - offset} ${
|
||||||
p2.y
|
p2.y
|
||||||
@@ -536,6 +640,38 @@ const drawArrow = (svg, commitA, commitB, allCommits) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p1.x === p2.x) {
|
||||||
|
lineDef = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
|
||||||
|
}
|
||||||
|
} else if (dir === 'BT') {
|
||||||
|
if (p1.x < p2.x) {
|
||||||
|
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
|
||||||
|
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y + radius} ${arc2} ${p1.x + offset} ${
|
||||||
|
p2.y
|
||||||
|
} L ${p2.x} ${p2.y}`;
|
||||||
|
} else {
|
||||||
|
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${
|
||||||
|
p1.y - offset
|
||||||
|
} L ${p2.x} ${p2.y}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p1.x > p2.x) {
|
||||||
|
arc = 'A 20 20, 0, 0, 0,';
|
||||||
|
arc2 = 'A 20 20, 0, 0, 1,';
|
||||||
|
radius = 20;
|
||||||
|
offset = 20;
|
||||||
|
|
||||||
|
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
|
||||||
|
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y + radius} ${arc} ${p1.x - offset} ${
|
||||||
|
p2.y
|
||||||
|
} L ${p2.x} ${p2.y}`;
|
||||||
|
} else {
|
||||||
|
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${
|
||||||
|
p1.y - offset
|
||||||
|
} L ${p2.x} ${p2.y}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (p1.x === p2.x) {
|
if (p1.x === p2.x) {
|
||||||
lineDef = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
|
lineDef = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
|
||||||
}
|
}
|
||||||
@@ -607,12 +743,16 @@ const drawBranches = (svg, branches) => {
|
|||||||
line.attr('class', 'branch branch' + adjustIndexForTheme);
|
line.attr('class', 'branch branch' + adjustIndexForTheme);
|
||||||
|
|
||||||
if (dir === 'TB') {
|
if (dir === 'TB') {
|
||||||
line.attr('y1', 30);
|
line.attr('y1', defaultPos);
|
||||||
line.attr('x1', pos);
|
line.attr('x1', pos);
|
||||||
line.attr('y2', maxPos);
|
line.attr('y2', maxPos);
|
||||||
line.attr('x2', pos);
|
line.attr('x2', pos);
|
||||||
|
} else if (dir === 'BT') {
|
||||||
|
line.attr('y1', maxPos);
|
||||||
|
line.attr('x1', pos);
|
||||||
|
line.attr('y2', defaultPos);
|
||||||
|
line.attr('x2', pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
lanes.push(pos);
|
lanes.push(pos);
|
||||||
|
|
||||||
let name = branch.name;
|
let name = branch.name;
|
||||||
@@ -646,8 +786,10 @@ const drawBranches = (svg, branches) => {
|
|||||||
if (dir === 'TB') {
|
if (dir === 'TB') {
|
||||||
bkg.attr('x', pos - bbox.width / 2 - 10).attr('y', 0);
|
bkg.attr('x', pos - bbox.width / 2 - 10).attr('y', 0);
|
||||||
label.attr('transform', 'translate(' + (pos - bbox.width / 2 - 5) + ', ' + 0 + ')');
|
label.attr('transform', 'translate(' + (pos - bbox.width / 2 - 5) + ', ' + 0 + ')');
|
||||||
}
|
} else if (dir === 'BT') {
|
||||||
if (dir !== 'TB') {
|
bkg.attr('x', pos - bbox.width / 2 - 10).attr('y', maxPos);
|
||||||
|
label.attr('transform', 'translate(' + (pos - bbox.width / 2 - 5) + ', ' + maxPos + ')');
|
||||||
|
} else {
|
||||||
bkg.attr('transform', 'translate(' + -19 + ', ' + (pos - bbox.height / 2) + ')');
|
bkg.attr('transform', 'translate(' + -19 + ', ' + (pos - bbox.height / 2) + ')');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -681,7 +823,10 @@ export const draw = function (txt, id, ver, diagObj) {
|
|||||||
let bbox = labelElement.getBBox();
|
let bbox = labelElement.getBBox();
|
||||||
|
|
||||||
branchPos[branch.name] = { pos, index };
|
branchPos[branch.name] = { pos, index };
|
||||||
pos += 50 + (gitGraphConfig.rotateCommitLabel ? 40 : 0) + (dir === 'TB' ? bbox.width / 2 : 0);
|
pos +=
|
||||||
|
50 +
|
||||||
|
(gitGraphConfig.rotateCommitLabel ? 40 : 0) +
|
||||||
|
(dir === 'TB' || dir === 'BT' ? bbox.width / 2 : 0);
|
||||||
label.remove();
|
label.remove();
|
||||||
branchLabel.remove();
|
branchLabel.remove();
|
||||||
g.remove();
|
g.remove();
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ cherry\-pick(?=\s|$) return 'CHERRY_PICK';
|
|||||||
checkout(?=\s|$) return 'CHECKOUT';
|
checkout(?=\s|$) return 'CHECKOUT';
|
||||||
"LR" return 'DIR';
|
"LR" return 'DIR';
|
||||||
"TB" return 'DIR';
|
"TB" return 'DIR';
|
||||||
|
"BT" return 'DIR';
|
||||||
":" return ':';
|
":" return ':';
|
||||||
"^" return 'CARET'
|
"^" return 'CARET'
|
||||||
"options"\r?\n this.begin("options"); //
|
"options"\r?\n this.begin("options"); //
|
||||||
|
|||||||
@@ -196,11 +196,16 @@ export const drawNode = function (
|
|||||||
// Create the wrapped text element
|
// Create the wrapped text element
|
||||||
const textElem = nodeElem.append('g');
|
const textElem = nodeElem.append('g');
|
||||||
const description = node.descr.replace(/(<br\/*>)/g, '\n');
|
const description = node.descr.replace(/(<br\/*>)/g, '\n');
|
||||||
const newEl = createText(textElem, description, {
|
const newEl = createText(
|
||||||
useHtmlLabels: htmlLabels,
|
textElem,
|
||||||
width: node.width,
|
description,
|
||||||
classes: 'mindmap-node-label',
|
{
|
||||||
});
|
useHtmlLabels: htmlLabels,
|
||||||
|
width: node.width,
|
||||||
|
classes: 'mindmap-node-label',
|
||||||
|
},
|
||||||
|
conf
|
||||||
|
);
|
||||||
|
|
||||||
if (!htmlLabels) {
|
if (!htmlLabels) {
|
||||||
textElem
|
textElem
|
||||||
|
|||||||
@@ -537,6 +537,16 @@ Formatting:
|
|||||||
|
|
||||||
This feature is applicable to node labels, edge labels, and subgraph labels.
|
This feature is applicable to node labels, edge labels, and subgraph labels.
|
||||||
|
|
||||||
|
The auto wrapping can be disabled by using
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
markdownAutoWrap: false
|
||||||
|
---
|
||||||
|
graph LR
|
||||||
|
```
|
||||||
|
|
||||||
## Interaction
|
## Interaction
|
||||||
|
|
||||||
It is possible to bind a click event to a node, the click can lead to either a javascript callback or to a link which will be opened in a new browser tab.
|
It is possible to bind a click event to a node, the click can lead to either a javascript callback or to a link which will be opened in a new browser tab.
|
||||||
|
|||||||
@@ -519,9 +519,9 @@ Here, we have changed the default main branch name to `MetroLine1`.
|
|||||||
|
|
||||||
## Orientation (v10.3.0+)
|
## Orientation (v10.3.0+)
|
||||||
|
|
||||||
Mermaid supports two graph orientations: **Left-to-Right** (default) and **Top-to-Bottom**.
|
Mermaid supports three graph orientations: **Left-to-Right** (default), **Top-to-Bottom**, and **Bottom-to-Top**.
|
||||||
|
|
||||||
You can set this with either `LR:` (for [**Left-to-Right**](#left-to-right-default-lr)) or `TB:` (for [**Top-to-Bottom**](#top-to-bottom-tb)) after `gitGraph`.
|
You can set this with either `LR:` (for [**Left-to-Right**](#left-to-right-default-lr)), `TB:` (for [**Top-to-Bottom**](#top-to-bottom-tb)) or `BT:` (for [**Bottom-to-Top**](#bottom-to-top-bt)) after `gitGraph`.
|
||||||
|
|
||||||
### Left to Right (default, `LR:`)
|
### Left to Right (default, `LR:`)
|
||||||
|
|
||||||
@@ -569,6 +569,29 @@ Usage example:
|
|||||||
commit
|
commit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Bottom to Top (`BT:`) (v<MERMAID_RELEASE_VERSION>+)
|
||||||
|
|
||||||
|
In `BT` (**Bottom-to-Top**) orientation, the commits run from bottom to top of the graph and branches are arranged side-by-side.
|
||||||
|
|
||||||
|
To orient the graph this way, you need to add `BT:` after gitGraph.
|
||||||
|
|
||||||
|
Usage example:
|
||||||
|
|
||||||
|
```mermaid-example
|
||||||
|
gitGraph BT:
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
branch develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
checkout main
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
merge develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
```
|
||||||
|
|
||||||
## Parallel commits (v10.8.0+)
|
## Parallel commits (v10.8.0+)
|
||||||
|
|
||||||
Commits in Mermaid display temporal information in gitgraph by default. For example if two commits are one commit away from its parent, the commit that was made earlier is rendered closer to its parent. You can turn this off by enabling the `parallelCommits` flag.
|
Commits in Mermaid display temporal information in gitgraph by default. For example if two commits are one commit away from its parent, the commit that was made earlier is rendered closer to its parent. You can turn this off by enabling the `parallelCommits` flag.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
// @ts-nocheck TODO: Fix types
|
// @ts-nocheck TODO: Fix types
|
||||||
|
import type { MermaidConfig } from '../config.type.js';
|
||||||
import type { Group } from '../diagram-api/types.js';
|
import type { Group } from '../diagram-api/types.js';
|
||||||
import type { D3TSpanElement, D3TextElement } from '../diagrams/common/commonTypes.js';
|
import type { D3TSpanElement, D3TextElement } from '../diagrams/common/commonTypes.js';
|
||||||
import { log } from '../logger.js';
|
import { log } from '../logger.js';
|
||||||
@@ -21,8 +22,7 @@ function addHtmlSpan(element, node, width, classes, addBackground = false) {
|
|||||||
const label = node.label;
|
const label = node.label;
|
||||||
const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';
|
const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';
|
||||||
div.html(
|
div.html(
|
||||||
`
|
`<span class="${labelClass} ${classes}" ` +
|
||||||
<span class="${labelClass} ${classes}" ` +
|
|
||||||
(node.labelStyle ? 'style="' + node.labelStyle + '"' : '') +
|
(node.labelStyle ? 'style="' + node.labelStyle + '"' : '') +
|
||||||
'>' +
|
'>' +
|
||||||
label +
|
label +
|
||||||
@@ -181,14 +181,14 @@ export const createText = (
|
|||||||
isNode = true,
|
isNode = true,
|
||||||
width = 200,
|
width = 200,
|
||||||
addSvgBackground = false,
|
addSvgBackground = false,
|
||||||
} = {}
|
} = {},
|
||||||
|
config: MermaidConfig
|
||||||
) => {
|
) => {
|
||||||
log.info('createText', text, style, isTitle, classes, useHtmlLabels, isNode, addSvgBackground);
|
log.info('createText', text, style, isTitle, classes, useHtmlLabels, isNode, addSvgBackground);
|
||||||
if (useHtmlLabels) {
|
if (useHtmlLabels) {
|
||||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||||
// text = text.replace(/\\n|\n/g, '<br />');
|
|
||||||
const htmlText = markdownToHTML(text);
|
const htmlText = markdownToHTML(text, config);
|
||||||
// log.info('markdownToHTML' + text, markdownToHTML(text));
|
|
||||||
const node = {
|
const node = {
|
||||||
isNode,
|
isNode,
|
||||||
label: decodeEntities(htmlText).replace(
|
label: decodeEntities(htmlText).replace(
|
||||||
@@ -200,7 +200,7 @@ export const createText = (
|
|||||||
const vertexNode = addHtmlSpan(el, node, width, classes, addSvgBackground);
|
const vertexNode = addHtmlSpan(el, node, width, classes, addSvgBackground);
|
||||||
return vertexNode;
|
return vertexNode;
|
||||||
} else {
|
} else {
|
||||||
const structuredText = markdownToLines(text);
|
const structuredText = markdownToLines(text, config);
|
||||||
const svgLabel = createFormattedText(width, el, structuredText, addSvgBackground);
|
const svgLabel = createFormattedText(width, el, structuredText, addSvgBackground);
|
||||||
return svgLabel;
|
return svgLabel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable no-irregular-whitespace */
|
||||||
import { markdownToLines, markdownToHTML } from './handle-markdown-text.js';
|
import { markdownToLines, markdownToHTML } from './handle-markdown-text.js';
|
||||||
import { test, expect } from 'vitest';
|
import { test, expect } from 'vitest';
|
||||||
|
|
||||||
@@ -203,6 +204,31 @@ Word!`;
|
|||||||
expect(output).toEqual(expectedOutput);
|
expect(output).toEqual(expectedOutput);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('markdownToLines - No auto wrapping', () => {
|
||||||
|
expect(
|
||||||
|
markdownToLines(
|
||||||
|
`Hello, how do
|
||||||
|
you do?`,
|
||||||
|
{ markdownAutoWrap: false }
|
||||||
|
)
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"content": "Hello, how do",
|
||||||
|
"type": "normal",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"content": "you do?",
|
||||||
|
"type": "normal",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
test('markdownToHTML - Basic test', () => {
|
test('markdownToHTML - Basic test', () => {
|
||||||
const input = `This is regular text
|
const input = `This is regular text
|
||||||
Here is a new line
|
Here is a new line
|
||||||
@@ -262,3 +288,13 @@ test('markdownToHTML - Unsupported formatting', () => {
|
|||||||
- l3`)
|
- l3`)
|
||||||
).toMatchInlineSnapshot('"<p>Hello</p>Unsupported markdown: list"');
|
).toMatchInlineSnapshot('"<p>Hello</p>Unsupported markdown: list"');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('markdownToHTML - no auto wrapping', () => {
|
||||||
|
expect(
|
||||||
|
markdownToHTML(
|
||||||
|
`Hello, how do
|
||||||
|
you do?`,
|
||||||
|
{ markdownAutoWrap: false }
|
||||||
|
)
|
||||||
|
).toMatchInlineSnapshot('"<p>Hello, how do<br/>you do?</p>"');
|
||||||
|
});
|
||||||
|
|||||||
@@ -2,24 +2,28 @@ import type { Content } from 'mdast';
|
|||||||
import { fromMarkdown } from 'mdast-util-from-markdown';
|
import { fromMarkdown } from 'mdast-util-from-markdown';
|
||||||
import { dedent } from 'ts-dedent';
|
import { dedent } from 'ts-dedent';
|
||||||
import type { MarkdownLine, MarkdownWordType } from './types.js';
|
import type { MarkdownLine, MarkdownWordType } from './types.js';
|
||||||
|
import type { MermaidConfig } from '../config.type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param markdown - markdown to process
|
* @param markdown - markdown to process
|
||||||
* @returns processed markdown
|
* @returns processed markdown
|
||||||
*/
|
*/
|
||||||
function preprocessMarkdown(markdown: string): string {
|
function preprocessMarkdown(markdown: string, { markdownAutoWrap }: MermaidConfig): string {
|
||||||
// Replace multiple newlines with a single newline
|
// Replace multiple newlines with a single newline
|
||||||
const withoutMultipleNewlines = markdown.replace(/\n{2,}/g, '\n');
|
const withoutMultipleNewlines = markdown.replace(/\n{2,}/g, '\n');
|
||||||
// Remove extra spaces at the beginning of each line
|
// Remove extra spaces at the beginning of each line
|
||||||
const withoutExtraSpaces = dedent(withoutMultipleNewlines);
|
const withoutExtraSpaces = dedent(withoutMultipleNewlines);
|
||||||
|
if (markdownAutoWrap === false) {
|
||||||
|
return withoutExtraSpaces.replace(/ /g, ' ');
|
||||||
|
}
|
||||||
return withoutExtraSpaces;
|
return withoutExtraSpaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param markdown - markdown to split into lines
|
* @param markdown - markdown to split into lines
|
||||||
*/
|
*/
|
||||||
export function markdownToLines(markdown: string): MarkdownLine[] {
|
export function markdownToLines(markdown: string, config: MermaidConfig = {}): MarkdownLine[] {
|
||||||
const preprocessedMarkdown = preprocessMarkdown(markdown);
|
const preprocessedMarkdown = preprocessMarkdown(markdown, config);
|
||||||
const { children } = fromMarkdown(preprocessedMarkdown);
|
const { children } = fromMarkdown(preprocessedMarkdown);
|
||||||
const lines: MarkdownLine[] = [[]];
|
const lines: MarkdownLine[] = [[]];
|
||||||
let currentLine = 0;
|
let currentLine = 0;
|
||||||
@@ -56,11 +60,14 @@ export function markdownToLines(markdown: string): MarkdownLine[] {
|
|||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function markdownToHTML(markdown: string) {
|
export function markdownToHTML(markdown: string, { markdownAutoWrap }: MermaidConfig = {}) {
|
||||||
const { children } = fromMarkdown(markdown);
|
const { children } = fromMarkdown(markdown);
|
||||||
|
|
||||||
function output(node: Content): string {
|
function output(node: Content): string {
|
||||||
if (node.type === 'text') {
|
if (node.type === 'text') {
|
||||||
|
if (markdownAutoWrap === false) {
|
||||||
|
return node.value.replace(/\n/g, '<br/>').replace(/ /g, ' ');
|
||||||
|
}
|
||||||
return node.value.replace(/\n/g, '<br/>');
|
return node.value.replace(/\n/g, '<br/>');
|
||||||
} else if (node.type === 'strong') {
|
} else if (node.type === 'strong') {
|
||||||
return `<strong>${node.children.map(output).join('')}</strong>`;
|
return `<strong>${node.children.map(output).join('')}</strong>`;
|
||||||
|
|||||||
@@ -243,6 +243,9 @@ properties:
|
|||||||
fontSize:
|
fontSize:
|
||||||
type: number
|
type: number
|
||||||
default: 16
|
default: 16
|
||||||
|
markdownAutoWrap:
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
suppressErrorRendering:
|
suppressErrorRendering:
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
|
|||||||
Reference in New Issue
Block a user