diff --git a/.vite/build.ts b/.vite/build.ts
index 6c7e85827..1261e375b 100644
--- a/.vite/build.ts
+++ b/.vite/build.ts
@@ -41,11 +41,6 @@ const packageOptions = {
packageName: 'mermaid-mindmap',
file: 'detector.ts',
},
- 'mermaid-flowchart-v3': {
- name: 'mermaid-flowchart-v3',
- packageName: 'mermaid-flowchart-v3',
- file: 'detector.ts',
- },
// 'mermaid-example-diagram-detector': {
// name: 'mermaid-example-diagram-detector',
// packageName: 'mermaid-example-diagram',
@@ -125,7 +120,6 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
if (watch && config.build) {
config.build.watch = {
include: [
- 'packages/mermaid-flowchart-v3/src/**',
'packages/mermaid-mindmap/src/**',
'packages/mermaid/src/**',
// 'packages/mermaid-example-diagram/src/**',
@@ -154,7 +148,6 @@ const main = async () => {
if (watch) {
build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' }));
if (!mermaidOnly) {
- build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-flowchart-v3' }));
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-mindmap' }));
// build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
}
diff --git a/cSpell.json b/cSpell.json
index c6660c4dc..a90bff4a5 100644
--- a/cSpell.json
+++ b/cSpell.json
@@ -13,6 +13,7 @@
"bbox",
"bilkent",
"bisheng",
+ "blrs",
"braintree",
"brkt",
"brolin",
diff --git a/cypress/integration/rendering/flowchart-elk.spec.js b/cypress/integration/rendering/flowchart-elk.spec.js
new file mode 100644
index 000000000..9b741abfe
--- /dev/null
+++ b/cypress/integration/rendering/flowchart-elk.spec.js
@@ -0,0 +1,687 @@
+import { imgSnapshotTest, renderGraph } from '../../helpers/util';
+
+describe('Flowchart ELK', () => {
+ it('1-elk: should render a simple flowchart', () => {
+ imgSnapshotTest(
+ `flowchart-elk TD
+ A[Christmas] -->|Get money| B(Go shopping)
+ B --> C{Let me think}
+ C -->|One| D[Laptop]
+ C -->|Two| E[iPhone]
+ C -->|Three| F[fa:fa-car Car]
+ `,
+ {}
+ );
+ imgSnapshotTest(
+ `flowchart TD
+ A[Christmas] -->|Get money| B(Go shopping)
+ B --> C{Let me think}
+ C -->|One| D[Laptop]
+ C -->|Two| E[iPhone]
+ C -->|Three| F[fa:fa-car Car]
+ `,
+ { flowchart: { defaultRenderer: 'elk' } }
+ );
+ });
+
+ it('2-elk: should render a simple flowchart with diagramPadding set to 0', () => {
+ imgSnapshotTest(
+ `flowchart-elk TD
+ A[Christmas] -->|Get money| B(Go shopping)
+ B --> C{Let me think}
+ %% this is a comment
+ C -->|One| D[Laptop]
+ C -->|Two| E[iPhone]
+ C -->|Three| F[fa:fa-car Car]
+ `,
+ { flowchart: { diagramPadding: 0 } }
+ );
+ });
+
+ it('3-elk: a link with correct arrowhead to a subgraph', () => {
+ imgSnapshotTest(
+ `flowchart-elk TD
+ P1
+ P1 -->P1.5
+ subgraph P1.5
+ P2
+ P2.5(( A ))
+ P3
+ end
+ P2 --> P4
+ P3 --> P6
+ P1.5 --> P5
+ `,
+ {}
+ );
+ });
+
+ it('4-elk: Length of edges', () => {
+ imgSnapshotTest(
+ `flowchart-elk TD
+ L1 --- L2
+ L2 --- C
+ M1 ---> C
+ R1 .-> R2
+ R2 <.-> C
+ C -->|Label 1| E1
+ C <-- Label 2 ---> E2
+ C ----> E3
+ C <-...-> E4
+ C ======> E5
+ `,
+ {}
+ );
+ });
+ it('5-elk: should render escaped without html labels', () => {
+ imgSnapshotTest(
+ `flowchart-elk TD
+ a["Haiya"]---->b
+ `,
+ { htmlLabels: false, flowchart: { htmlLabels: false } }
+ );
+ });
+ it('6-elk: should render non-escaped with html labels', () => {
+ imgSnapshotTest(
+ `flowchart-elk TD
+ a["Haiya"]===>b
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('7-elk: should render a flowchart when useMaxWidth is true (default)', () => {
+ renderGraph(
+ `flowchart-elk TD
+ A[Christmas] -->|Get money| B(Go shopping)
+ B --> C{Let me think}
+ C -->|One| D[Laptop]
+ C -->|Two| E[iPhone]
+ C -->|Three| F[fa:fa-car Car]
+ `,
+ { flowchart: { useMaxWidth: true } }
+ );
+ cy.get('svg').should((svg) => {
+ expect(svg).to.have.attr('width', '100%');
+ // expect(svg).to.have.attr('height');
+ // use within because the absolute value can be slightly different depending on the environment ±5%
+ // const height = parseFloat(svg.attr('height'));
+ // expect(height).to.be.within(446 * 0.95, 446 * 1.05);
+ const style = svg.attr('style');
+ expect(style).to.match(/^max-width: [\d.]+px;$/);
+ const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
+ expect(maxWidthValue).to.be.within(290 * 0.95 - 1, 290 * 1.05);
+ });
+ });
+ it('8-elk: should render a flowchart when useMaxWidth is false', () => {
+ renderGraph(
+ `flowchart-elk TD
+ A[Christmas] -->|Get money| B(Go shopping)
+ B --> C{Let me think}
+ C -->|One| D[Laptop]
+ C -->|Two| E[iPhone]
+ C -->|Three| F[fa:fa-car Car]
+ `,
+ { flowchart: { useMaxWidth: false } }
+ );
+ cy.get('svg').should((svg) => {
+ // const height = parseFloat(svg.attr('height'));
+ const width = parseFloat(svg.attr('width'));
+ // use within because the absolute value can be slightly different depending on the environment ±5%
+ // expect(height).to.be.within(446 * 0.95, 446 * 1.05);
+ expect(width).to.be.within(290 * 0.95 - 1, 290 * 1.05);
+ expect(svg).to.not.have.attr('style');
+ });
+ });
+
+ it('V2 - 16: Render Stadium shape', () => {
+ imgSnapshotTest(
+ ` flowchart-elk TD
+ A([stadium shape test])
+ A -->|Get money| B([Go shopping])
+ B --> C([Let me think...
Do I want something for work,
something to spend every free second with,
or something to get around?])
+ C -->|One| D([Laptop])
+ C -->|Two| E([iPhone])
+ C -->|Three| F([Car
wroom wroom])
+ click A "index.html#link-clicked" "link test"
+ click B testClick "click test"
+ classDef someclass fill:#f96;
+ class A someclass;
+ class C someclass;
+ `,
+ { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
+ );
+ });
+
+ it('50-elk: handle nested subgraphs in reverse order', () => {
+ imgSnapshotTest(
+ `flowchart-elk LR
+ a -->b
+ subgraph A
+ B
+ end
+ subgraph B
+ b
+ end
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+
+ it('51-elk: handle nested subgraphs in reverse order', () => {
+ imgSnapshotTest(
+ `flowchart-elk LR
+ a -->b
+ subgraph A
+ B
+ end
+ subgraph B
+ b
+ end
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+
+ it('52-elk: handle nested subgraphs in several levels', () => {
+ imgSnapshotTest(
+ `flowchart-elk TB
+ b-->B
+ a-->c
+ subgraph O
+ A
+ end
+ subgraph B
+ c
+ end
+ subgraph A
+ a
+ b
+ B
+ end
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+
+ it('53-elk: handle nested subgraphs with edges in and out', () => {
+ imgSnapshotTest(
+ `flowchart-elk TB
+ internet
+ nat
+ routeur
+ lb1
+ lb2
+ compute1
+ compute2
+ subgraph project
+ routeur
+ nat
+ subgraph subnet1
+ compute1
+ lb1
+ end
+ subgraph subnet2
+ compute2
+ lb2
+ end
+ end
+ internet --> routeur
+ routeur --> subnet1 & subnet2
+ subnet1 & subnet2 --> nat --> internet
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+
+ it('54-elk: handle nested subgraphs with outgoing links', () => {
+ imgSnapshotTest(
+ `flowchart-elk TD
+ subgraph main
+ subgraph subcontainer
+ subcontainer-child
+ end
+ subcontainer-child--> subcontainer-sibling
+ end
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+
+ it('55-elk: handle nested subgraphs with outgoing links 2', () => {
+ imgSnapshotTest(
+ `flowchart-elk TD
+
+subgraph one[One]
+ subgraph sub_one[Sub One]
+ _sub_one
+ end
+ subgraph sub_two[Sub Two]
+ _sub_two
+ end
+ _one
+end
+
+%% here, either the first or the second one
+sub_one --> sub_two
+_one --> b
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+
+ it('56-elk: handle nested subgraphs with outgoing links 3', () => {
+ imgSnapshotTest(
+ `flowchart-elk TB
+ subgraph container_Beta
+ process_C-->Process_D
+ end
+ subgraph container_Alpha
+ process_A-->process_B
+ process_A-->|messages|process_C
+ end
+ process_B-->|via_AWSBatch|container_Beta
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('57-elk: handle nested subgraphs with outgoing links 4', () => {
+ imgSnapshotTest(
+ `flowchart-elk LR
+subgraph A
+a -->b
+end
+subgraph B
+b
+end
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+
+ it('57-elk: handle nested subgraphs with outgoing links 2', () => {
+ imgSnapshotTest(
+ `flowchart-elk TB
+ c1-->a2
+ subgraph one
+ a1-->a2
+ end
+ subgraph two
+ b1-->b2
+ end
+ subgraph three
+ c1-->c2
+ end
+ one --> two
+ three --> two
+ two --> c2
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('57.x: handle nested subgraphs with outgoing links 5', () => {
+ imgSnapshotTest(
+ `%% this does not produce the desired result
+flowchart-elk TB
+ subgraph container_Beta
+ process_C-->Process_D
+ end
+ subgraph container_Alpha
+ process_A-->process_B
+ process_B-->|via_AWSBatch|container_Beta
+ process_A-->|messages|process_C
+ end
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('58-elk: handle styling with style expressions', () => {
+ imgSnapshotTest(
+ `
+ flowchart-elk LR
+ id1(Start)-->id2(Stop)
+ style id1 fill:#f9f,stroke:#333,stroke-width:4px
+ style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('59-elk: handle styling of subgraphs and links', () => {
+ imgSnapshotTest(
+ `
+flowchart-elk TD
+ A[Christmas] ==> D
+ A[Christmas] -->|Get money| B(Go shopping)
+ A[Christmas] ==> C
+ subgraph T ["Test"]
+ A
+ B
+ C
+ end
+
+ classDef Test fill:#F84E68,stroke:#333,color:white;
+ class A,T Test
+ classDef TestSub fill:green;
+ class T TestSub
+ linkStyle 0,1 color:orange, stroke: orange;
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('60-elk: handle styling for all node shapes - v2', () => {
+ imgSnapshotTest(
+ `
+ flowchart-elk LR
+ A[red text] -->|default style| B(blue text)
+ C([red text]) -->|default style| D[[blue text]]
+ E[(red text)] -->|default style| F((blue text))
+ G>red text] -->|default style| H{blue text}
+ I{{red text}} -->|default style| J[/blue text/]
+ K[\\ red text\\] -->|default style| L[/blue text\\]
+ M[\\ red text/] -->|default style| N[blue text];
+ O(((red text))) -->|default style| P(((blue text)));
+ linkStyle default color:Sienna;
+ style A stroke:#ff0000,fill:#ffcccc,color:#ff0000;
+ style B stroke:#0000ff,fill:#ccccff,color:#0000ff;
+ style C stroke:#ff0000,fill:#ffcccc,color:#ff0000;
+ style D stroke:#0000ff,fill:#ccccff,color:#0000ff;
+ style E stroke:#ff0000,fill:#ffcccc,color:#ff0000;
+ style F stroke:#0000ff,fill:#ccccff,color:#0000ff;
+ style G stroke:#ff0000,fill:#ffcccc,color:#ff0000;
+ style H stroke:#0000ff,fill:#ccccff,color:#0000ff;
+ style I stroke:#ff0000,fill:#ffcccc,color:#ff0000;
+ style J stroke:#0000ff,fill:#ccccff,color:#0000ff;
+ style K stroke:#ff0000,fill:#ffcccc,color:#ff0000;
+ style L stroke:#0000ff,fill:#ccccff,color:#0000ff;
+ style M stroke:#ff0000,fill:#ffcccc,color:#ff0000;
+ style N stroke:#0000ff,fill:#ccccff,color:#0000ff;
+ style O stroke:#ff0000,fill:#ffcccc,color:#ff0000;
+ style P stroke:#0000ff,fill:#ccccff,color:#0000ff;
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', logLevel: 2 }
+ );
+ });
+ it('61-elk: fontawesome icons in edge labels', () => {
+ imgSnapshotTest(
+ `
+ flowchart-elk TD
+ C -->|fa:fa-car Car| F[fa:fa-car Car]
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('62-elk: should render styled subgraphs', () => {
+ imgSnapshotTest(
+ `
+ flowchart-elk TB
+ A
+ B
+ subgraph foo[Foo SubGraph]
+ C
+ D
+ end
+ subgraph bar[Bar SubGraph]
+ E
+ F
+ end
+ G
+
+ A-->B
+ B-->C
+ C-->D
+ B-->D
+ D-->E
+ E-->A
+ E-->F
+ F-->D
+ F-->G
+ B-->G
+ G-->D
+
+ style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred
+ style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('63-elk: title on subgraphs should be themable', () => {
+ imgSnapshotTest(
+ `
+ %%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
+ flowchart-elk LR
+ subgraph A
+ a --> b
+ end
+ subgraph B
+ i -->f
+ end
+ A --> B
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('65-elk: text-color from classes', () => {
+ imgSnapshotTest(
+ `
+ flowchart-elk LR
+ classDef dark fill:#000,stroke:#000,stroke-width:4px,color:#fff
+ Lorem --> Ipsum --> Dolor
+ class Lorem,Dolor dark
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('66-elk: More nested subgraph cases (TB)', () => {
+ imgSnapshotTest(
+ `
+flowchart-elk TB
+ subgraph two
+ b1
+ end
+ subgraph three
+ c2
+ end
+
+ three --> two
+ two --> c2
+
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('67-elk: More nested subgraph cases (RL)', () => {
+ imgSnapshotTest(
+ `
+flowchart-elk RL
+ subgraph two
+ b1
+ end
+ subgraph three
+ c2
+ end
+
+ three --> two
+ two --> c2
+
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('68-elk: More nested subgraph cases (BT)', () => {
+ imgSnapshotTest(
+ `
+flowchart-elk BT
+ subgraph two
+ b1
+ end
+ subgraph three
+ c2
+ end
+
+ three --> two
+ two --> c2
+
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('69-elk: More nested subgraph cases (LR)', () => {
+ imgSnapshotTest(
+ `
+flowchart-elk LR
+ subgraph two
+ b1
+ end
+ subgraph three
+ c2
+ end
+
+ three --> two
+ two --> c2
+
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('70-elk: Handle nested subgraph cases (TB) link out and link between subgraphs', () => {
+ imgSnapshotTest(
+ `
+flowchart-elk TB
+ subgraph S1
+ sub1 -->sub2
+ end
+ subgraph S2
+ sub4
+ end
+ S1 --> S2
+ sub1 --> sub4
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('71-elk: Handle nested subgraph cases (RL) link out and link between subgraphs', () => {
+ imgSnapshotTest(
+ `
+flowchart-elk RL
+ subgraph S1
+ sub1 -->sub2
+ end
+ subgraph S2
+ sub4
+ end
+ S1 --> S2
+ sub1 --> sub4
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('72-elk: Handle nested subgraph cases (BT) link out and link between subgraphs', () => {
+ imgSnapshotTest(
+ `
+flowchart-elk BT
+ subgraph S1
+ sub1 -->sub2
+ end
+ subgraph S2
+ sub4
+ end
+ S1 --> S2
+ sub1 --> sub4
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('74-elk: Handle nested subgraph cases (RL) link out and link between subgraphs', () => {
+ imgSnapshotTest(
+ `
+flowchart-elk RL
+ subgraph S1
+ sub1 -->sub2
+ end
+ subgraph S2
+ sub4
+ end
+ S1 --> S2
+ sub1 --> sub4
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('74-elk: Handle labels for multiple edges from and to the same couple of nodes', () => {
+ imgSnapshotTest(
+ `
+flowchart-elk RL
+ subgraph one
+ a1 -- l1 --> a2
+ a1 -- l2 --> a2
+ end
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+
+ it('76-elk: handle unicode encoded character with HTML labels true', () => {
+ imgSnapshotTest(
+ `flowchart-elk TB
+ a{{"Lorem 'ipsum' dolor 'sit' amet, 'consectetur' adipiscing 'elit'."}}
+ --> b{{"Lorem #quot;ipsum#quot; dolor #quot;sit#quot; amet,#quot;consectetur#quot; adipiscing #quot;elit#quot;."}}
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+
+ it('2050-elk: handling of different rendering direction in subgraphs', () => {
+ imgSnapshotTest(
+ `
+ flowchart-elk LR
+
+ subgraph TOP
+ direction TB
+ subgraph B1
+ direction RL
+ i1 -->f1
+ end
+ subgraph B2
+ direction BT
+ i2 -->f2
+ end
+ end
+ A --> TOP --> B
+ B1 --> B2
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+
+ it('2388-elk: handling default in the node name', () => {
+ imgSnapshotTest(
+ `
+ flowchart-elk LR
+ default-index.js --> dot.template.js
+ index.js --> module-utl.js
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('2824-elk: Clipping of edges', () => {
+ imgSnapshotTest(
+ `
+ flowchart-elk TD
+ A --> B
+ A --> C
+ B --> C
+ `,
+ { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
+ );
+ });
+ it('1433-elk: should render a titled flowchart with titleTopMargin set to 0', () => {
+ imgSnapshotTest(
+ `---
+title: Simple flowchart
+---
+flowchart-elk TD
+A --> B
+`,
+ { titleTopMargin: 0 }
+ );
+ });
+});
diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html
index 5e1f4d76b..afc12dbe9 100644
--- a/cypress/platform/knsv2.html
+++ b/cypress/platform/knsv2.html
@@ -63,6 +63,13 @@ graph TB
c --> d
+flowchart-elk TB + a --> b + a --> c + b --> d + c --> d ++
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%% flowchart TB %% I could not figure out how to use double quotes in labels in Mermaid @@ -238,10 +245,9 @@ sequenceDiagram