From 3549ffc4ac867cbebf146057b4c49641db503846 Mon Sep 17 00:00:00 2001 From: eopaant Date: Sun, 30 Apr 2023 13:19:35 -0500 Subject: [PATCH 1/4] add master detail relationship support --- packages/mermaid/src/diagrams/er/erDb.js | 1 + packages/mermaid/src/diagrams/er/erMarkers.js | 26 +++++++++++++++++++ .../mermaid/src/diagrams/er/erRenderer.js | 6 +++++ .../src/diagrams/er/parser/erDiagram.jison | 2 ++ .../src/diagrams/er/parser/erDiagram.spec.js | 9 +++++++ 5 files changed, 44 insertions(+) diff --git a/packages/mermaid/src/diagrams/er/erDb.js b/packages/mermaid/src/diagrams/er/erDb.js index 5f2af0da1..2f5116cbf 100644 --- a/packages/mermaid/src/diagrams/er/erDb.js +++ b/packages/mermaid/src/diagrams/er/erDb.js @@ -20,6 +20,7 @@ const Cardinality = { ZERO_OR_MORE: 'ZERO_OR_MORE', ONE_OR_MORE: 'ONE_OR_MORE', ONLY_ONE: 'ONLY_ONE', + MD_PARENT: 'MD_PARENT', }; const Identification = { diff --git a/packages/mermaid/src/diagrams/er/erMarkers.js b/packages/mermaid/src/diagrams/er/erMarkers.js index 948411772..48cafae65 100644 --- a/packages/mermaid/src/diagrams/er/erMarkers.js +++ b/packages/mermaid/src/diagrams/er/erMarkers.js @@ -7,6 +7,8 @@ const ERMarkers = { ONE_OR_MORE_END: 'ONE_OR_MORE_END', ZERO_OR_MORE_START: 'ZERO_OR_MORE_START', ZERO_OR_MORE_END: 'ZERO_OR_MORE_END', + MD_PARENT_END: 'MD_PARENT_END', + MD_PARENT_START: 'MD_PARENT_START', }; /** @@ -18,6 +20,30 @@ const ERMarkers = { const insertMarkers = function (elem, conf) { let marker; + elem + .append('defs') + .append('marker') + .attr('id', ERMarkers.MD_PARENT_START) + .attr('refX', 0) + .attr('refY', 7) + .attr('markerWidth', 190) + .attr('markerHeight', 240) + .attr('orient', 'auto') + .append('path') + .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z'); + + elem + .append('defs') + .append('marker') + .attr('id', ERMarkers.MD_PARENT_END) + .attr('refX', 19) + .attr('refY', 7) + .attr('markerWidth', 20) + .attr('markerHeight', 28) + .attr('orient', 'auto') + .append('path') + .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z'); + elem .append('defs') .append('marker') diff --git a/packages/mermaid/src/diagrams/er/erRenderer.js b/packages/mermaid/src/diagrams/er/erRenderer.js index 87d7ac607..93e22732a 100644 --- a/packages/mermaid/src/diagrams/er/erRenderer.js +++ b/packages/mermaid/src/diagrams/er/erRenderer.js @@ -478,6 +478,9 @@ const drawRelationshipFromLayout = function (svg, rel, g, insert, diagObj) { case diagObj.db.Cardinality.ONLY_ONE: svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')'); break; + case diagObj.db.Cardinality.MD_PARENT: + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.MD_PARENT_END + ')'); + break; } switch (rel.relSpec.cardB) { @@ -502,6 +505,9 @@ const drawRelationshipFromLayout = function (svg, rel, g, insert, diagObj) { case diagObj.db.Cardinality.ONLY_ONE: svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_START + ')'); break; + case diagObj.db.Cardinality.MD_PARENT: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.MD_PARENT_START + ')'); + break; } // Now label the relationship diff --git a/packages/mermaid/src/diagrams/er/parser/erDiagram.jison b/packages/mermaid/src/diagrams/er/parser/erDiagram.jison index 8ffa87c63..0c6820b49 100644 --- a/packages/mermaid/src/diagrams/er/parser/erDiagram.jison +++ b/packages/mermaid/src/diagrams/er/parser/erDiagram.jison @@ -57,6 +57,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili o\| return 'ZERO_OR_ONE'; o\{ return 'ZERO_OR_MORE'; \|\{ return 'ONE_OR_MORE'; +\s*u return 'MD_PARENT'; \.\. return 'NON_IDENTIFYING'; \-\- return 'IDENTIFYING'; "to" return 'IDENTIFYING'; @@ -170,6 +171,7 @@ cardinality | 'ZERO_OR_MORE' { $$ = yy.Cardinality.ZERO_OR_MORE; } | 'ONE_OR_MORE' { $$ = yy.Cardinality.ONE_OR_MORE; } | 'ONLY_ONE' { $$ = yy.Cardinality.ONLY_ONE; } + | 'MD_PARENT' { $$ = yy.Cardinality.MD_PARENT; } ; relType diff --git a/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js b/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js index 904521d50..6fdc9eaa7 100644 --- a/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js +++ b/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js @@ -718,5 +718,14 @@ describe('when parsing ER diagram it...', function () { const rels = erDb.getRelationships(); expect(rels[0].roleA).toBe('places'); }); + + it('should represent parent-child relationship correctly', function () { + erDiagram.parser.parse('erDiagram\nPROJECT u--o{ TEAM_MEMBER : "parent"'); + const rels = erDb.getRelationships(); + expect(Object.keys(erDb.getEntities()).length).toBe(2); + expect(rels.length).toBe(1); + expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.MD_PARENT); + expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_MORE); + }); }); }); From 18571052ad7cae38e3dc3c0b5ac114282e50da41 Mon Sep 17 00:00:00 2001 From: eopaant Date: Mon, 1 May 2023 22:34:36 -0500 Subject: [PATCH 2/4] added style to reflect true aggregation --- packages/mermaid/src/diagrams/er/styles.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/mermaid/src/diagrams/er/styles.js b/packages/mermaid/src/diagrams/er/styles.js index 42dbcebde..08ea2e851 100644 --- a/packages/mermaid/src/diagrams/er/styles.js +++ b/packages/mermaid/src/diagrams/er/styles.js @@ -33,6 +33,17 @@ const getStyles = (options) => font-size: 18px; fill: ${options.textColor}; } + #MD_PARENT_START { + fill: #f5f5f5 !important; + stroke: ${options.lineColor} !important; + stroke-width: 1; + } + #MD_PARENT_END { + fill: #f5f5f5 !important; + stroke: ${options.lineColor} !important; + stroke-width: 1; + } + `; export default getStyles; From a1e64c21020d36c474d27ab76abb441106387f34 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Sun, 7 May 2023 18:05:43 +0100 Subject: [PATCH 3/4] test: fix classDiagramGrammer unit test The classDiagramGrammer.spec.ts unit test had some bad filepath manipulation that fails on UNIX platforms. Instead, we can use the recommended method from the Node.JS documentation, see https://nodejs.org/api/esm.html#importmetaurl. Fixes: 221640aa258c9e8f97e8113a15a52097cb2d1cf8 --- .../mermaid/src/diagrams/class/classDiagramGrammar.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/diagrams/class/classDiagramGrammar.spec.ts b/packages/mermaid/src/diagrams/class/classDiagramGrammar.spec.ts index eae09603f..0d6fe200c 100644 --- a/packages/mermaid/src/diagrams/class/classDiagramGrammar.spec.ts +++ b/packages/mermaid/src/diagrams/class/classDiagramGrammar.spec.ts @@ -1,10 +1,10 @@ import { readFile } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; // @ts-ignore - no types import { LALRGenerator } from 'jison'; -import path from 'path'; const getAbsolutePath = (relativePath: string) => { - return new URL(path.join(__dirname, relativePath)).pathname; + return fileURLToPath(new URL(relativePath, import.meta.url)); }; describe('class diagram grammar', function () { From c6c3b07c33369b0cd8e91133c35b491f95b3bf38 Mon Sep 17 00:00:00 2001 From: rhysd Date: Sun, 7 May 2023 22:20:49 +0900 Subject: [PATCH 4/4] Fix missing `await` in usage document --- docs/config/usage.md | 4 ++-- packages/mermaid/src/docs/config/usage.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/config/usage.md b/docs/config/usage.md index 1069ffa5f..0ab60012f 100644 --- a/docs/config/usage.md +++ b/docs/config/usage.md @@ -348,10 +348,10 @@ mermaid.parseError = function (err, hash) { displayErrorInGui(err); }; -const textFieldUpdated = function () { +const textFieldUpdated = async function () { const textStr = getTextFromFormField('code'); - if (mermaid.parse(textStr)) { + if (await mermaid.parse(textStr)) { reRender(textStr); } }; diff --git a/packages/mermaid/src/docs/config/usage.md b/packages/mermaid/src/docs/config/usage.md index 211a06af7..1c2b5a39b 100644 --- a/packages/mermaid/src/docs/config/usage.md +++ b/packages/mermaid/src/docs/config/usage.md @@ -345,10 +345,10 @@ mermaid.parseError = function (err, hash) { displayErrorInGui(err); }; -const textFieldUpdated = function () { +const textFieldUpdated = async function () { const textStr = getTextFromFormField('code'); - if (mermaid.parse(textStr)) { + if (await mermaid.parse(textStr)) { reRender(textStr); } };