From 7ba415dad1c11c3f294ed4bfac8aa8b643550496 Mon Sep 17 00:00:00 2001 From: Feroz Mujawar Date: Fri, 17 Jan 2025 21:23:30 +0530 Subject: [PATCH 1/7] edge flickering fix --- packages/mermaid/src/diagrams/flowchart/flowDb.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.ts b/packages/mermaid/src/diagrams/flowchart/flowDb.ts index 931347a4d..1e3f215c8 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDb.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDb.ts @@ -233,6 +233,8 @@ export const addSingleLink = function (_start: string, _end: string, type: any, } if (id) { edge.id = id; + } else { + edge.id = `${edge.start}-${edge.end}-${edge.length}`; } if (edges.length < (config.maxEdges ?? 500)) { From 64237fbaa74e40a5838c0577af8aceab92a40f70 Mon Sep 17 00:00:00 2001 From: Feroz Mujawar Date: Mon, 20 Jan 2025 19:59:46 +0530 Subject: [PATCH 2/7] updated addSingleLink for multiple outgoing edges to same end node --- packages/mermaid/src/diagrams/flowchart/flowDb.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.ts b/packages/mermaid/src/diagrams/flowchart/flowDb.ts index 1e3f215c8..d60dcc27b 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDb.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDb.ts @@ -234,7 +234,12 @@ export const addSingleLink = function (_start: string, _end: string, type: any, if (id) { edge.id = id; } else { - edge.id = `${edge.start}-${edge.end}-${edge.length}`; + const existingLinks = edges.filter((e) => e.start === edge.start && e.end === edge.end); + if (existingLinks.length === 0) { + edge.id = `${edge.start}-${edge.end}-${edge.length}`; + } else { + edge.id = `${edge.start}-${edge.end}-${existingLinks.length + 1}`; + } } if (edges.length < (config.maxEdges ?? 500)) { @@ -269,9 +274,11 @@ export const addLink = function (_start: string[], _end: string[], linkData: unk log.info('addLink', _start, _end, id); + let idIsUsed = false; for (const start of _start) { for (const end of _end) { - addSingleLink(start, end, linkData, id); + addSingleLink(start, end, linkData, !idIsUsed ? id : undefined); + idIsUsed = true; } } }; From 54a0dd0af6d46130df957b6a4ff2b50c717026cb Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Wed, 22 Jan 2025 01:09:49 +0100 Subject: [PATCH 3/7] Make flowchart edge Ids consistent across getEdges and getData --- .../mermaid/src/diagrams/flowchart/flowDb.ts | 17 ++++++++++++----- .../mermaid/src/diagrams/flowchart/types.ts | 1 + packages/mermaid/src/rendering-util/types.ts | 1 + 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.ts b/packages/mermaid/src/diagrams/flowchart/flowDb.ts index d60dcc27b..83c55fc9b 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDb.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDb.ts @@ -212,6 +212,7 @@ export const addSingleLink = function (_start: string, _end: string, type: any, text: '', labelType: 'text', classes: [], + isUserDefinedId: false, }; log.info('abc78 Got edge...', edge); const linkTextObj = type.text; @@ -233,12 +234,15 @@ export const addSingleLink = function (_start: string, _end: string, type: any, } if (id) { edge.id = id; + edge.isUserDefinedId = true; } else { const existingLinks = edges.filter((e) => e.start === edge.start && e.end === edge.end); if (existingLinks.length === 0) { - edge.id = `${edge.start}-${edge.end}-${edge.length}`; + edge.id = getEdgeId(edge.start, edge.end, { counter: 0, prefix: 'L' }); + //edge.id = `${edge.start}-${edge.end}-${edge.length}`; } else { - edge.id = `${edge.start}-${edge.end}-${existingLinks.length + 1}`; + edge.id = getEdgeId(edge.start, edge.end, { counter: existingLinks.length + 1, prefix: 'L' }); + //edge.id = `${edge.start}-${edge.end}-${existingLinks.length + 1}`; } } @@ -274,11 +278,13 @@ export const addLink = function (_start: string[], _end: string[], linkData: unk log.info('addLink', _start, _end, id); - let idIsUsed = false; + // for a group syntax like A e1@--> B & C, only the first edge should have an the userDefined id + // the rest of the edges should have auto generated ids + let isEdgeConsumed = false; for (const start of _start) { for (const end of _end) { - addSingleLink(start, end, linkData, !idIsUsed ? id : undefined); - idIsUsed = true; + addSingleLink(start, end, linkData, !isEdgeConsumed ? id : undefined); + isEdgeConsumed = true; } } }; @@ -1054,6 +1060,7 @@ export const getData = () => { } const edge: Edge = { id: getEdgeId(rawEdge.start, rawEdge.end, { counter: index, prefix: 'L' }, rawEdge.id), + isUserDefinedId: rawEdge.isUserDefinedId, start: rawEdge.start, end: rawEdge.end, type: rawEdge.type ?? 'normal', diff --git a/packages/mermaid/src/diagrams/flowchart/types.ts b/packages/mermaid/src/diagrams/flowchart/types.ts index 00acb6751..54156091b 100644 --- a/packages/mermaid/src/diagrams/flowchart/types.ts +++ b/packages/mermaid/src/diagrams/flowchart/types.ts @@ -53,6 +53,7 @@ export interface FlowText { } export interface FlowEdge { + isUserDefinedId: boolean; start: string; end: string; interpolate?: string; diff --git a/packages/mermaid/src/rendering-util/types.ts b/packages/mermaid/src/rendering-util/types.ts index 1f84c66c3..b11d2f314 100644 --- a/packages/mermaid/src/rendering-util/types.ts +++ b/packages/mermaid/src/rendering-util/types.ts @@ -125,6 +125,7 @@ export interface Edge { pattern?: string; thickness?: 'normal' | 'thick' | 'invisible' | 'dotted'; look?: string; + isUserDefinedId?: boolean; } export interface RectOptions { From 304f133227fce587bfb30fd052ad8296bde07c36 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 00:14:56 +0000 Subject: [PATCH 4/7] [autofix.ci] apply automated fixes --- docs/config/setup/interfaces/mermaid.LayoutData.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/config/setup/interfaces/mermaid.LayoutData.md b/docs/config/setup/interfaces/mermaid.LayoutData.md index 552a16a8d..46c9134e8 100644 --- a/docs/config/setup/interfaces/mermaid.LayoutData.md +++ b/docs/config/setup/interfaces/mermaid.LayoutData.md @@ -20,7 +20,7 @@ #### Defined in -[packages/mermaid/src/rendering-util/types.ts:147](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L147) +[packages/mermaid/src/rendering-util/types.ts:148](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L148) --- @@ -30,7 +30,7 @@ #### Defined in -[packages/mermaid/src/rendering-util/types.ts:146](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L146) +[packages/mermaid/src/rendering-util/types.ts:147](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L147) --- @@ -40,4 +40,4 @@ #### Defined in -[packages/mermaid/src/rendering-util/types.ts:145](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L145) +[packages/mermaid/src/rendering-util/types.ts:146](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L146) From c063b92cc9120895cbd36f5884e7c91cfcba1535 Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Wed, 22 Jan 2025 02:03:29 +0100 Subject: [PATCH 5/7] Handle more edge cases, and lint fixes --- .../mermaid/src/diagrams/flowchart/flowDb.ts | 16 ++++--- .../flowchart/parser/flow-node-data.spec.js | 45 ++++++++++++++++--- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.ts b/packages/mermaid/src/diagrams/flowchart/flowDb.ts index 83c55fc9b..053e6f73c 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDb.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDb.ts @@ -232,17 +232,16 @@ export const addSingleLink = function (_start: string, _end: string, type: any, edge.stroke = type.stroke; edge.length = type.length > 10 ? 10 : type.length; } - if (id) { + + if (id && !edges.some((e) => e.id === id)) { edge.id = id; edge.isUserDefinedId = true; } else { const existingLinks = edges.filter((e) => e.start === edge.start && e.end === edge.end); if (existingLinks.length === 0) { edge.id = getEdgeId(edge.start, edge.end, { counter: 0, prefix: 'L' }); - //edge.id = `${edge.start}-${edge.end}-${edge.length}`; } else { edge.id = getEdgeId(edge.start, edge.end, { counter: existingLinks.length + 1, prefix: 'L' }); - //edge.id = `${edge.start}-${edge.end}-${existingLinks.length + 1}`; } } @@ -280,11 +279,16 @@ export const addLink = function (_start: string[], _end: string[], linkData: unk // for a group syntax like A e1@--> B & C, only the first edge should have an the userDefined id // the rest of the edges should have auto generated ids - let isEdgeConsumed = false; for (const start of _start) { for (const end of _end) { - addSingleLink(start, end, linkData, !isEdgeConsumed ? id : undefined); - isEdgeConsumed = true; + //use the id only for last node in _start and and first node in _end + const isLastStart = start === _start[_start.length - 1]; + const isFirstEnd = end === _end[0]; + if (isLastStart && isFirstEnd) { + addSingleLink(start, end, linkData, id); + } else { + addSingleLink(start, end, linkData, undefined); + } } } }; diff --git a/packages/mermaid/src/diagrams/flowchart/parser/flow-node-data.spec.js b/packages/mermaid/src/diagrams/flowchart/parser/flow-node-data.spec.js index 0125572ae..2a987753c 100644 --- a/packages/mermaid/src/diagrams/flowchart/parser/flow-node-data.spec.js +++ b/packages/mermaid/src/diagrams/flowchart/parser/flow-node-data.spec.js @@ -251,7 +251,7 @@ describe('when parsing directions', function () { expect(data4Layout.nodes[0].shape).toEqual('squareRect'); expect(data4Layout.nodes[0].label).toEqual('This is a
multiline string'); }); - it(' should be possible to use } in strings', function () { + it('should be possible to use } in strings', function () { const res = flow.parser.parse(`flowchart TB A@{ label: "This is a string with }" @@ -264,7 +264,7 @@ describe('when parsing directions', function () { expect(data4Layout.nodes[0].shape).toEqual('squareRect'); expect(data4Layout.nodes[0].label).toEqual('This is a string with }'); }); - it(' should be possible to use @ in strings', function () { + it('should be possible to use @ in strings', function () { const res = flow.parser.parse(`flowchart TB A@{ label: "This is a string with @" @@ -277,7 +277,7 @@ describe('when parsing directions', function () { expect(data4Layout.nodes[0].shape).toEqual('squareRect'); expect(data4Layout.nodes[0].label).toEqual('This is a string with @'); }); - it(' should be possible to use @ in strings', function () { + it('should be possible to use @ in strings', function () { const res = flow.parser.parse(`flowchart TB A@{ label: "This is a string with}" @@ -291,7 +291,7 @@ describe('when parsing directions', function () { expect(data4Layout.nodes[0].label).toEqual('This is a string with}'); }); - it(' should be possible to use @ syntax to add labels on multi nodes', function () { + it('should be possible to use @ syntax to add labels on multi nodes', function () { const res = flow.parser.parse(`flowchart TB n2["label for n2"] & n4@{ label: "labe for n4"} & n5@{ label: "labe for n5"} `); @@ -343,7 +343,42 @@ describe('when parsing directions', function () { expect(data4Layout.nodes[9].label).toEqual('@for@ AS@'); expect(data4Layout.nodes[10].label).toEqual('@for@ AS@'); }); - it.skip(' should be possible to use @ syntax to add labels with trail spaces', function () { + + it('should handle unique edge creation with using @ and &', function () { + const res = flow.parser.parse(`flowchart TD + A & B e1@--> C & D + A1 e2@--> C1 & D1 + `); + + const data4Layout = flow.parser.yy.getData(); + expect(data4Layout.nodes.length).toBe(7); + expect(data4Layout.edges.length).toBe(6); + expect(data4Layout.edges[0].id).toEqual('L_A_C_0'); + expect(data4Layout.edges[1].id).toEqual('L_A_D_0'); + expect(data4Layout.edges[2].id).toEqual('e1'); + expect(data4Layout.edges[3].id).toEqual('L_B_D_0'); + expect(data4Layout.edges[4].id).toEqual('e2'); + expect(data4Layout.edges[5].id).toEqual('L_A1_D1_0'); + }); + + it('should handle redefine same edge ids again', function () { + const res = flow.parser.parse(`flowchart TD + A & B e1@--> C & D + A1 e1@--> C1 & D1 + `); + + const data4Layout = flow.parser.yy.getData(); + expect(data4Layout.nodes.length).toBe(7); + expect(data4Layout.edges.length).toBe(6); + expect(data4Layout.edges[0].id).toEqual('L_A_C_0'); + expect(data4Layout.edges[1].id).toEqual('L_A_D_0'); + expect(data4Layout.edges[2].id).toEqual('e1'); + expect(data4Layout.edges[3].id).toEqual('L_B_D_0'); + expect(data4Layout.edges[4].id).toEqual('L_A1_C1_0'); + expect(data4Layout.edges[5].id).toEqual('L_A1_D1_0'); + }); + + it.skip('should be possible to use @ syntax to add labels with trail spaces', function () { const res = flow.parser.parse( `flowchart TB n2["label for n2"] & n4@{ label: "labe for n4"} & n5@{ label: "labe for n5"} ` From e2e51010058c0bfc3adf0a5218f4ac8af81a004c Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Wed, 22 Jan 2025 10:57:57 +0100 Subject: [PATCH 6/7] Handle more override edge animate --- .../mermaid/src/diagrams/flowchart/flowDb.ts | 4 ++-- .../flowchart/parser/flow-node-data.spec.js | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.ts b/packages/mermaid/src/diagrams/flowchart/flowDb.ts index 053e6f73c..8c097d9fa 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDb.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDb.ts @@ -94,10 +94,10 @@ export const addVertex = function ( const edge = edges.find((e) => e.id === id); if (edge) { const edgeDoc = doc as EdgeMetaData; - if (edgeDoc?.animate) { + if (edgeDoc?.animate !== undefined) { edge.animate = edgeDoc.animate; } - if (edgeDoc?.animation) { + if (edgeDoc?.animation !== undefined) { edge.animation = edgeDoc.animation; } return; diff --git a/packages/mermaid/src/diagrams/flowchart/parser/flow-node-data.spec.js b/packages/mermaid/src/diagrams/flowchart/parser/flow-node-data.spec.js index 2a987753c..9f221f82f 100644 --- a/packages/mermaid/src/diagrams/flowchart/parser/flow-node-data.spec.js +++ b/packages/mermaid/src/diagrams/flowchart/parser/flow-node-data.spec.js @@ -378,6 +378,28 @@ describe('when parsing directions', function () { expect(data4Layout.edges[5].id).toEqual('L_A1_D1_0'); }); + it('should handle overriding edge animate again', function () { + const res = flow.parser.parse(`flowchart TD + A e1@--> B + C e2@--> D + E e3@--> F + e1@{ animate: true } + e2@{ animate: false } + e3@{ animate: true } + e3@{ animate: false } + `); + + const data4Layout = flow.parser.yy.getData(); + expect(data4Layout.nodes.length).toBe(6); + expect(data4Layout.edges.length).toBe(3); + expect(data4Layout.edges[0].id).toEqual('e1'); + expect(data4Layout.edges[0].animate).toEqual(true); + expect(data4Layout.edges[1].id).toEqual('e2'); + expect(data4Layout.edges[1].animate).toEqual(false); + expect(data4Layout.edges[2].id).toEqual('e3'); + expect(data4Layout.edges[2].animate).toEqual(false); + }); + it.skip('should be possible to use @ syntax to add labels with trail spaces', function () { const res = flow.parser.parse( `flowchart TB From 963efa64c794466dcd0f06bad6de6ba554d05a54 Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Wed, 22 Jan 2025 11:01:37 +0100 Subject: [PATCH 7/7] Added changeset --- .changeset/bright-ads-exist.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/bright-ads-exist.md diff --git a/.changeset/bright-ads-exist.md b/.changeset/bright-ads-exist.md new file mode 100644 index 000000000..ef2f76f4c --- /dev/null +++ b/.changeset/bright-ads-exist.md @@ -0,0 +1,5 @@ +--- +'mermaid': patch +--- + +Fixes for consistent edge id creation & handling edge cases for animate edge feature