diff --git a/cypress/integration/rendering/classDiagram.spec.js b/cypress/integration/rendering/classDiagram.spec.js index 3f022b55de..078094519a 100644 --- a/cypress/integration/rendering/classDiagram.spec.js +++ b/cypress/integration/rendering/classDiagram.spec.js @@ -274,4 +274,19 @@ describe('Class diagram', () => { ); cy.get('svg'); }); + + it('11: should render a simple class diagram with return type on method', () => { + imgSnapshotTest( + ` + classDiagram + class Class10~T~ { + int[] id + test(int[] ids) bool + testArray() bool[] + } + `, + {} + ); + cy.get('svg'); + }); }); diff --git a/docs/classDiagram.md b/docs/classDiagram.md index dfadabdbf9..f0b3c3cf7c 100644 --- a/docs/classDiagram.md +++ b/docs/classDiagram.md @@ -29,7 +29,7 @@ Mermaid can render class diagrams. +bool is_wild +run() } - + ``` ```mermaid classDiagram @@ -52,8 +52,8 @@ Mermaid can render class diagrams. class Zebra{ +bool is_wild +run() - } - + } + ``` ## Syntax @@ -105,48 +105,52 @@ Naming convention: a class name should be composed of alphanumeric (unicode allo UML provides mechanisms to represent class members, such as attributes and methods, and additional information about them. -Mermaid distinguishes between attributes and functions/methods based on if the **parenthesis** `()` are present or not. The ones with `()` are treated as functions/methods, and others as attributes. +Mermaid distinguishes between attributes and functions/methods based on if the **parenthesis** `()` are present or not. The ones with `()` are treated as functions/methods, and others as attributes. To indicate a return type for a method, enclose the type within **square brackets** `[]` There are two ways to define the members of a class, and regardless of whichever syntax is used to define the members, the output will still be same. The two different ways are : -- Associate a member of a class using **:** (colon) followed by member name, useful to define one member at a time. For example: +- Associate a member of a class using **:** (colon) followed by member name, useful to define one member at a time. For example: ``` class BankAccount BankAccount : +String owner BankAccount : +BigDecimal balance - BankAccount : +deposit(amount) - BankAccount : +withdrawl(amount) + BankAccount : +deposit(amount) bool + BankAccount : +withdrawal(amount) ``` + ``` mermaid classDiagram class BankAccount BankAccount : +String owner BankAccount : +BigDecimal balance - BankAccount : +deposit(amount) + BankAccount : +deposit(amount) : bool BankAccount : +withdrawl(amount) -``` + ``` - Associate members of a class using **{}** brackets, where members are grouped within curly brackets. Suitable for defining multiple members at once. For example: ``` class BankAccount{ +String owner +BigDecimal balance - +deposit(amount) + +deposit(amount) bool +withdrawl(amount) } ``` ```mermaid - classDiagram + classDiagram class BankAccount{ +String owner +BigDecimal balance - +deposit(amount) + +deposit(amount) : bool +withdrawl(amount) } ``` +#### Return Type +Optionally you can end the method/function definition with the data type that will be returned + #### Visibility To specify the visibility of a class member (i.e. any attribute or method), these notations may be placed before the member's name, but it is optional: @@ -161,7 +165,7 @@ To specify the visibility of a class member (i.e. any attribute or method), thes ## Defining Relationship -A relationship is a general term covering the specific types of logical connections found on class and object diagrams. +A relationship is a general term covering the specific types of logical connections found on class and object diagrams. ``` [classA][Arrow][ClassB]:LabelText ``` @@ -174,7 +178,7 @@ Type | Description *-- | Composition o-- | Aggregation --> | Association --- | Link (Solid) +-- | Link (Solid) ..> | Dependency ..\|> | Realization .. | Link (Dashed) @@ -231,7 +235,7 @@ classO .. classP : Link(Dashed) ``` -## Labels on Relations +## Labels on Relations It is possible to add a label text to a relation: ``` @@ -252,7 +256,7 @@ classE o-- classF : association ## Cardinality / Multiplicity on relations Multiplicity or cardinality in class diagrams indicates the number of instances of one class linked to one instance of the other class. For example, one company will have one or more employees, but each employee works for just one company. -Multiplicity notations are placed near the ends of an association. +Multiplicity notations are placed near the ends of an association. The different cardinality options are : - `0..1` Zero or one @@ -280,7 +284,7 @@ classDiagram Student "1" --> "1..*" Course Galaxy --> "many" Star : Contains ``` -## Annotations on classes +## Annotations on classes It is possible to annotate classes with a specific marker text which is like meta-data for the class, giving a clear indication about its nature. Some common annotations examples could be: - `<>` To represent an Interface class @@ -359,7 +363,7 @@ class Shape{ 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. **Note**: This functionality is disabled when using `securityLevel='strict'` and enabled when using `securityLevel='loose'`. -You would define these actions on a separate line after all classes have been declared. +You would define these actions on a separate line after all classes have been declared. ``` action className "reference" "tooltip" @@ -460,7 +464,7 @@ Class | Description --- | --- g.classGroup text | Styles for general class text classGroup .title | Styles for general class title -g.classGroup rect | Styles for class diagram rectangle +g.classGroup rect | Styles for class diagram rectangle g.classGroup line | Styles for class diagram line .classLabel .box | Styles for class label box .classLabel .label | Styles for class label text diff --git a/docs/index.html b/docs/index.html index 7dc93708fc..356f323c74 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,7 +7,7 @@ - + + A summary of all options and their defaults is found [here](https://github.com/knsv/mermaid/blob/master/docs/mermaidAPI.md#mermaidapi-configuration-defaults). A description of each option follows below. diff --git a/package.json b/package.json index 5106b9cdb4..cb3f2461bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mermaid", - "version": "8.4.4", + "version": "8.4.5", "description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", "main": "dist/mermaid.core.js", "keywords": [ diff --git a/src/diagrams/class/classDiagram.spec.js b/src/diagrams/class/classDiagram.spec.js index 89bfdc01b8..8510b086d2 100644 --- a/src/diagrams/class/classDiagram.spec.js +++ b/src/diagrams/class/classDiagram.spec.js @@ -105,7 +105,7 @@ describe('class diagram, ', function () { parser.parse(str); }); - it('should handle parsing of method statements grouped by brackets', function () { + it('should handle parsing of method statements grouped by brackets', function () { const str = 'classDiagram\n' + 'class Dummy_Class {\n' + @@ -121,6 +121,36 @@ describe('class diagram, ', function () { parser.parse(str); }); + it('should handle return types on methods', function () { + const str = + 'classDiagram\n' + + 'Object <|-- ArrayList\n' + + 'Object : equals()\n' + + 'Object : -Object[] objects\n' + + 'Object : +getObjects() Object[]\n' + + 'ArrayList : Dummy elementData\n' + + 'ArrayList : getDummy() Dummy'; + + parser.parse(str); + }); + + it('should handle return types on methods grouped by brackets', function () { + const str = + 'classDiagram\n' + + 'class Dummy_Class {\n' + + 'string data\n' + + 'getDummy() Dummy\n' + + '}\n' + + '\n' + + 'class Flight {\n' + + ' int flightNumber\n' + + ' datetime departureTime\n' + + ' getDepartureTime() datetime\n' + + '}'; + + parser.parse(str); + }); + it('should handle parsing of separators', function () { const str = 'classDiagram\n' + diff --git a/src/diagrams/class/classRenderer.js b/src/diagrams/class/classRenderer.js index ca4bfba782..39a15a5bd3 100644 --- a/src/diagrams/class/classRenderer.js +++ b/src/diagrams/class/classRenderer.js @@ -288,23 +288,14 @@ const drawClass = function(elem, classDef) { } const addTspan = function(textEl, txt, isFirst) { + let isMethod = txt.indexOf(')') > 1; let displayText = txt; let cssStyle = ''; - let methodEnd = txt.indexOf(')') + 1; - - if (methodEnd > 1 && methodEnd <= txt.length) { - let classifier = txt.substring(methodEnd); - - switch (classifier) { - case '*': - cssStyle = 'font-style:italic;'; - break; - case '$': - cssStyle = 'text-decoration:underline;'; - break; - } - displayText = txt.substring(0, methodEnd); + if (isMethod) { + let method = buildDisplayTextForMethod(txt); + displayText = method.displayText; + cssStyle = method.cssStyle; } const tSpan = textEl @@ -321,6 +312,50 @@ const drawClass = function(elem, classDef) { } }; + const buildDisplayTextForMethod = function(txt) { + let regEx = /(\+|-|~|#)?(\w+)\s?\((\w+(<\w+>|\[\])?\s?(\w+)?)?\)\s?([*|$])?\s?(\w+(<\w+>|\[\])?)?/; + + let cssStyle = ''; + let displayText = txt; + let methodName = txt; + let classifier = ''; + + let parsedText = txt.match(regEx); + + if (parsedText) { + let visibility = parsedText[1] ? parsedText[1].trim() : ''; + methodName = parsedText[2] ? parsedText[2].trim() : ''; + let parameters = parsedText[3] ? parsedText[3].trim() : ''; + classifier = parsedText[6] ? parsedText[6].trim() : ''; + let returnType = parsedText[7] ? ' : ' + parsedText[7].trim() : ''; + + displayText = visibility + methodName + '(' + parameters + ')' + returnType; + } else { + let methodEnd = displayText.indexOf(')') + 1; + classifier = displayText.substring(methodEnd, methodEnd + 1); + if (classifier !== '' && classifier !== ' ') { + displayText = displayText.replace(classifier, ''); + } + } + + switch (classifier) { + case '*': + cssStyle = 'font-style:italic;'; + break; + case '$': + cssStyle = 'text-decoration:underline;'; + break; + } + + let method = { + methodname: methodName, + displayText: displayText, + cssStyle: cssStyle + }; + + return method; + }; + const id = classDef.id; const classInfo = { id: id,