diff --git a/packages/mermaid/src/dagre-wrapper/edges.js b/packages/mermaid/src/dagre-wrapper/edges.js index f89b4422be..aced3f5af5 100644 --- a/packages/mermaid/src/dagre-wrapper/edges.js +++ b/packages/mermaid/src/dagre-wrapper/edges.js @@ -522,6 +522,7 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph default: strokeClasses = ''; } + switch (edge.pattern) { case 'solid': strokeClasses += ' edge-pattern-solid'; @@ -586,6 +587,9 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph case 'extension': svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-extensionStart' + ')'); break; + case 'realization': + svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-realizationStart' + ')'); + break; case 'composition': svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-compositionStart' + ')'); break; @@ -616,6 +620,9 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph case 'extension': svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-extensionEnd' + ')'); break; + case 'realization': + svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-realizationEnd' + ')'); + break; case 'composition': svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-compositionEnd' + ')'); break; diff --git a/packages/mermaid/src/dagre-wrapper/markers.js b/packages/mermaid/src/dagre-wrapper/markers.js index 051c987f62..2948645d34 100644 --- a/packages/mermaid/src/dagre-wrapper/markers.js +++ b/packages/mermaid/src/dagre-wrapper/markers.js @@ -11,6 +11,7 @@ const insertMarkers = (elem, markerArray, type, id) => { const extension = (elem, type, id) => { log.trace('Making markers for ', id); + elem .append('defs') .append('marker') @@ -38,6 +39,36 @@ const extension = (elem, type, id) => { .attr('d', 'M 1,1 V 13 L18,7 Z'); // this is actual shape for arrowhead }; +const realization = (elem, type, id) => { + log.trace('Making markers for ', id); + + elem + .append('defs') + .append('marker') + .attr('id', type + '-realizationStart') + .attr('class', 'marker realization ' + type) + .attr('refX', 18) + .attr('refY', 7) + .attr('markerWidth', 190) + .attr('markerHeight', 240) + .attr('orient', 'auto') + .append('path') + .attr('d', 'M 1,7 L18,13 V 1 Z'); + + elem + .append('defs') + .append('marker') + .attr('id', type + '-realizationEnd') + .attr('class', 'marker realization ' + type) + .attr('refX', 1) + .attr('refY', 7) + .attr('markerWidth', 20) + .attr('markerHeight', 28) + .attr('orient', 'auto') + .append('path') + .attr('d', 'M 1,1 V 13 L18,7 Z'); // this is actual shape for arrowhead +}; + const composition = (elem, type) => { elem .append('defs') @@ -282,6 +313,7 @@ const barb = (elem, type) => { // TODO rename the class diagram markers to something shape descriptive and semantic free const markers = { extension, + realization, composition, aggregation, dependency, diff --git a/packages/mermaid/src/diagrams/class/classDb.ts b/packages/mermaid/src/diagrams/class/classDb.ts index c9a202aa43..1873fd770e 100644 --- a/packages/mermaid/src/diagrams/class/classDb.ts +++ b/packages/mermaid/src/diagrams/class/classDb.ts @@ -366,6 +366,7 @@ export const relationType = { COMPOSITION: 2, DEPENDENCY: 3, LOLLIPOP: 4, + REALIZATION: 5, }; const setupToolTips = function (element: Element) { diff --git a/packages/mermaid/src/diagrams/class/classDiagram.spec.ts b/packages/mermaid/src/diagrams/class/classDiagram.spec.ts index 532c8aaa7a..f5339fee8b 100644 --- a/packages/mermaid/src/diagrams/class/classDiagram.spec.ts +++ b/packages/mermaid/src/diagrams/class/classDiagram.spec.ts @@ -1193,16 +1193,18 @@ describe('given a class diagram with relationships, ', function () { }); it('should handle relation definitions with type only on right side', function () { - const str = 'classDiagram\n' + 'Class1 --|> Class02'; + const str = 'classDiagram\n' + 'Class1 --|> Class2'; parser.parse(str); const relations = parser.yy.getRelations(); + const class1 = parser.yy.getClass('Class1'); + const class2 = parser.yy.getClass('Class2'); - expect(parser.yy.getClass('Class1').id).toBe('Class1'); - expect(parser.yy.getClass('Class02').id).toBe('Class02'); + expect(class1.id).toBe('Class1'); + expect(class2.id).toBe('Class2'); expect(relations[0].relation.type1).toBe('none'); - expect(relations[0].relation.type2).toBe(classDb.relationType.EXTENSION); + expect(relations[0].relation.type2).toBe(classDb.relationType.REALIZATION); expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE); }); diff --git a/packages/mermaid/src/diagrams/class/classRenderer-v2.ts b/packages/mermaid/src/diagrams/class/classRenderer-v2.ts index b581252bfa..59667bbdc6 100644 --- a/packages/mermaid/src/diagrams/class/classRenderer-v2.ts +++ b/packages/mermaid/src/diagrams/class/classRenderer-v2.ts @@ -354,7 +354,7 @@ export const draw = async function (text: string, id: string, _version: string, await render( element, g, - ['aggregation', 'extension', 'composition', 'dependency', 'lollipop'], + ['aggregation', 'extension', 'realization', 'composition', 'dependency', 'lollipop'], 'classDiagram', id ); @@ -406,6 +406,9 @@ function getArrowMarker(type: number) { case 4: marker = 'lollipop'; break; + case 5: + marker = 'realization'; + break; default: marker = 'none'; } diff --git a/packages/mermaid/src/diagrams/class/parser/classDiagram.jison b/packages/mermaid/src/diagrams/class/parser/classDiagram.jison index 9c67e306ec..14663ab300 100644 --- a/packages/mermaid/src/diagrams/class/parser/classDiagram.jison +++ b/packages/mermaid/src/diagrams/class/parser/classDiagram.jison @@ -121,28 +121,37 @@ line was introduced with 'click'. <*>"_parent" return 'LINK_TARGET'; <*>"_top" return 'LINK_TARGET'; -<*>\s*\<\| return 'EXTENSION'; -<*>\s*\|\> return 'EXTENSION'; -<*>\s*\> return 'DEPENDENCY'; -<*>\s*\< return 'DEPENDENCY'; -<*>\s*\* return 'COMPOSITION'; -<*>\s*o return 'AGGREGATION'; -<*>\s*\(\) return 'LOLLIPOP'; -<*>\-\- return 'LINE'; -<*>\.\. return 'DOTTED_LINE'; -<*>":"{1}[^:\n;]+ return 'LABEL'; -<*>":"{3} return 'STYLE_SEPARATOR'; -<*>\- return 'MINUS'; -<*>"." return 'DOT'; -<*>\+ return 'PLUS'; -<*>\% return 'PCT'; -<*>"=" return 'EQUALS'; -<*>\= return 'EQUALS'; -<*>\w+ return 'ALPHA'; -<*>"[" return 'SQS'; -<*>"]" return 'SQE'; -<*>[!"#$%&'*+,-.`?\\/] return 'PUNCTUATION'; -<*>[0-9]+ return 'NUM'; +[`] this.popState(); +[^`]+ return "BQUOTE_STR"; +<*>[`] this.begin("bqstring"); + +<*>"_self" return 'LINK_TARGET'; +<*>"_blank" return 'LINK_TARGET'; +<*>"_parent" return 'LINK_TARGET'; +<*>"_top" return 'LINK_TARGET'; + +<*>\s*\<\| return 'EXTENSION'; +<*>\s*\|\> return 'REALIZATION'; +<*>\s*\> return 'DEPENDENCY'; +<*>\s*\< return 'DEPENDENCY'; +<*>\s*\* return 'COMPOSITION'; +<*>\s*o return 'AGGREGATION'; +<*>\s*\(\) return 'LOLLIPOP'; +<*>\-\- return 'LINE'; +<*>\.\. return 'DOTTED_LINE'; +<*>":"{1}[^:\n;]+ return 'LABEL'; +<*>":"{3} return 'STYLE_SEPARATOR'; +<*>\- return 'MINUS'; +<*>"." return 'DOT'; +<*>\+ return 'PLUS'; +<*>\% return 'PCT'; +<*>"=" return 'EQUALS'; +<*>\= return 'EQUALS'; +<*>\w+ return 'ALPHA'; +<*>"[" return 'SQS'; +<*>"]" return 'SQE'; +<*>[!"#$%&'*+,-.`?\\/] return 'PUNCTUATION'; +<*>[0-9]+ return 'NUM'; <*>[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]| [\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]| [\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]| @@ -368,6 +377,7 @@ relation relationType : AGGREGATION { $$=yy.relationType.AGGREGATION;} | EXTENSION { $$=yy.relationType.EXTENSION;} + | REALIZATION { $$=yy.relationType.REALIZATION;} | COMPOSITION { $$=yy.relationType.COMPOSITION;} | DEPENDENCY { $$=yy.relationType.DEPENDENCY;} | LOLLIPOP { $$=yy.relationType.LOLLIPOP;} diff --git a/packages/mermaid/src/diagrams/class/styles.js b/packages/mermaid/src/diagrams/class/styles.js index f12f609f91..db65b9b4af 100644 --- a/packages/mermaid/src/diagrams/class/styles.js +++ b/packages/mermaid/src/diagrams/class/styles.js @@ -120,6 +120,18 @@ g.classGroup line { stroke-width: 1; } +#realizationStart, .realization { + fill: transparent !important; + stroke: ${options.lineColor} !important; + stroke-width: 1; +} + +#realizationEnd, .realization { + fill: transparent !important; + stroke: ${options.lineColor} !important; + stroke-width: 1; +} + #aggregationStart, .aggregation { fill: transparent !important; stroke: ${options.lineColor} !important; diff --git a/packages/mermaid/src/diagrams/class/svgDraw.js b/packages/mermaid/src/diagrams/class/svgDraw.js index d6ed7bca4e..1ae6f543b0 100644 --- a/packages/mermaid/src/diagrams/class/svgDraw.js +++ b/packages/mermaid/src/diagrams/class/svgDraw.js @@ -9,6 +9,8 @@ export const drawEdge = function (elem, path, relation, conf, diagObj) { switch (type) { case diagObj.db.relationType.AGGREGATION: return 'aggregation'; + case diagObj.db.relationType.REALIZATION: + return 'realization'; case diagObj.db.relationType.EXTENSION: return 'extension'; case diagObj.db.relationType.COMPOSITION: