mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-19 23:39:50 +02:00
update classes to handle , in generic
This commit is contained in:
@@ -80,6 +80,7 @@
|
||||
Class01 : #size()
|
||||
Class01 : -int chimp
|
||||
Class01 : +int gorilla
|
||||
Class01 : +abstractAttribute string*
|
||||
class Class10~T~ {
|
||||
<<service>>
|
||||
int id
|
||||
@@ -122,6 +123,8 @@
|
||||
classDiagram
|
||||
direction LR
|
||||
Animal ()-- Dog
|
||||
Animal ()-- Cat
|
||||
note for Cat "should have no members area"
|
||||
Dog : bark()
|
||||
Dog : species()
|
||||
</pre>
|
||||
@@ -151,6 +154,7 @@
|
||||
~InternalProperty : string
|
||||
~AnotherInternalProperty : List~List~string~~
|
||||
}
|
||||
class People~List~Person~~
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
|
@@ -5,7 +5,6 @@ import { getConfig } from '../config.js';
|
||||
import intersect from './intersect/index.js';
|
||||
import createLabel from './createLabel.js';
|
||||
import note from './shapes/note.js';
|
||||
import { parseMember } from '../diagrams/class/svgDraw.js';
|
||||
import { evaluate } from '../diagrams/common/common.js';
|
||||
|
||||
const question = async (parent, node) => {
|
||||
@@ -806,8 +805,8 @@ const class_box = (parent, node) => {
|
||||
maxWidth = classTitleBBox.width;
|
||||
}
|
||||
const classAttributes = [];
|
||||
node.classData.members.forEach((str) => {
|
||||
const parsedInfo = parseMember(str);
|
||||
node.classData.members.forEach((member) => {
|
||||
const parsedInfo = member.getDisplayDetails();
|
||||
let parsedText = parsedInfo.displayText;
|
||||
if (getConfig().flowchart.htmlLabels) {
|
||||
parsedText = parsedText.replace(/</g, '<').replace(/>/g, '>');
|
||||
@@ -840,8 +839,8 @@ const class_box = (parent, node) => {
|
||||
maxHeight += lineHeight;
|
||||
|
||||
const classMethods = [];
|
||||
node.classData.methods.forEach((str) => {
|
||||
const parsedInfo = parseMember(str);
|
||||
node.classData.methods.forEach((member) => {
|
||||
const parsedInfo = member.getDisplayDetails();
|
||||
let displayText = parsedInfo.displayText;
|
||||
if (getConfig().flowchart.htmlLabels) {
|
||||
displayText = displayText.replace(/</g, '<').replace(/>/g, '>');
|
||||
|
@@ -4,6 +4,9 @@ import classParser from './classParser.js';
|
||||
import { vi, describe, it, expect } from 'vitest';
|
||||
const spyOn = vi.spyOn;
|
||||
|
||||
const staticCssStyle = 'text-decoration:underline;';
|
||||
const abstractCssStyle = 'font-style:italic;';
|
||||
|
||||
describe('given a basic class diagram, ', function () {
|
||||
describe('when parsing class definition', function () {
|
||||
beforeEach(function () {
|
||||
@@ -127,7 +130,7 @@ describe('given a basic class diagram, ', function () {
|
||||
const c1 = classParser.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('member1');
|
||||
expect(c1.members[0].getDisplayDetails().displayText).toBe('member1');
|
||||
});
|
||||
|
||||
it('should parse a class with a text label, member and annotation', () => {
|
||||
@@ -142,7 +145,7 @@ describe('given a basic class diagram, ', function () {
|
||||
const c1 = classParser.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('int member1');
|
||||
expect(c1.members[0].getDisplayDetails().displayText).toBe('int member1');
|
||||
expect(c1.annotations.length).toBe(1);
|
||||
expect(c1.annotations[0]).toBe('interface');
|
||||
});
|
||||
@@ -168,7 +171,7 @@ describe('given a basic class diagram, ', function () {
|
||||
|
||||
const c1 = classParser.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members[0]).toBe('int member1');
|
||||
expect(c1.members[0].getDisplayDetails().displayText).toBe('int member1');
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
});
|
||||
|
||||
@@ -315,8 +318,8 @@ class C13["With Città foreign language"]
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
'int testMember\n' +
|
||||
'string fooMember\n' +
|
||||
'test()\n' +
|
||||
'string fooMember\n' +
|
||||
'foo()\n' +
|
||||
'}';
|
||||
parser.parse(str);
|
||||
@@ -324,10 +327,10 @@ class C13["With Città foreign language"]
|
||||
const actual = parser.yy.getClass('Class1');
|
||||
expect(actual.members.length).toBe(2);
|
||||
expect(actual.methods.length).toBe(2);
|
||||
expect(actual.members[0]).toBe('int testMember');
|
||||
expect(actual.members[1]).toBe('string fooMember');
|
||||
expect(actual.methods[0]).toBe('test()');
|
||||
expect(actual.methods[1]).toBe('foo()');
|
||||
expect(actual.members[0].getDisplayDetails().displayText).toBe('int testMember');
|
||||
expect(actual.members[1].getDisplayDetails().displayText).toBe('string fooMember');
|
||||
expect(actual.methods[0].getDisplayDetails().displayText).toBe('test()');
|
||||
expect(actual.methods[1].getDisplayDetails().displayText).toBe('foo()');
|
||||
});
|
||||
|
||||
it('should parse a class with a text label and members', () => {
|
||||
@@ -337,7 +340,7 @@ class C13["With Città foreign language"]
|
||||
const c1 = classParser.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('+member1');
|
||||
expect(c1.members[0].getDisplayDetails().displayText).toBe('+member1');
|
||||
});
|
||||
|
||||
it('should parse a class with a text label, members and annotation', () => {
|
||||
@@ -352,7 +355,7 @@ class C13["With Città foreign language"]
|
||||
const c1 = classParser.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('+member1');
|
||||
expect(c1.members[0].getDisplayDetails().displayText).toBe('+member1');
|
||||
expect(c1.annotations.length).toBe(1);
|
||||
expect(c1.annotations[0]).toBe('interface');
|
||||
});
|
||||
@@ -655,10 +658,10 @@ describe('given a class diagram with members and methods ', function () {
|
||||
const actual = parser.yy.getClass('actual');
|
||||
expect(actual.members.length).toBe(4);
|
||||
expect(actual.methods.length).toBe(0);
|
||||
expect(actual.members[0]).toBe('-int privateMember');
|
||||
expect(actual.members[1]).toBe('+int publicMember');
|
||||
expect(actual.members[2]).toBe('#int protectedMember');
|
||||
expect(actual.members[3]).toBe('~int privatePackage');
|
||||
expect(actual.members[0].getDisplayDetails().displayText).toBe('-int privateMember');
|
||||
expect(actual.members[1].getDisplayDetails().displayText).toBe('+int publicMember');
|
||||
expect(actual.members[2].getDisplayDetails().displayText).toBe('#int protectedMember');
|
||||
expect(actual.members[3].getDisplayDetails().displayText).toBe('~int privatePackage');
|
||||
});
|
||||
|
||||
it('should handle generic types', function () {
|
||||
@@ -711,7 +714,9 @@ describe('given a class diagram with members and methods ', function () {
|
||||
expect(actual.annotations.length).toBe(0);
|
||||
expect(actual.members.length).toBe(0);
|
||||
expect(actual.methods.length).toBe(1);
|
||||
expect(actual.methods[0]).toBe('someMethod()*');
|
||||
const method = actual.methods[0];
|
||||
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
|
||||
expect(method.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
|
||||
});
|
||||
|
||||
it('should handle static methods', function () {
|
||||
@@ -722,7 +727,9 @@ describe('given a class diagram with members and methods ', function () {
|
||||
expect(actual.annotations.length).toBe(0);
|
||||
expect(actual.members.length).toBe(0);
|
||||
expect(actual.methods.length).toBe(1);
|
||||
expect(actual.methods[0]).toBe('someMethod()$');
|
||||
const method = actual.methods[0];
|
||||
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
|
||||
expect(method.getDisplayDetails().cssStyle).toBe(staticCssStyle);
|
||||
});
|
||||
|
||||
it('should handle generic types in arguments', function () {
|
||||
@@ -1167,10 +1174,10 @@ describe('given a class diagram with relationships, ', function () {
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.members.length).toBe(2);
|
||||
expect(testClass.methods.length).toBe(2);
|
||||
expect(testClass.members[0]).toBe('int : test');
|
||||
expect(testClass.members[1]).toBe('string : foo');
|
||||
expect(testClass.methods[0]).toBe('test()');
|
||||
expect(testClass.methods[1]).toBe('foo()');
|
||||
expect(testClass.members[0].getDisplayDetails().displayText).toBe('int : test');
|
||||
expect(testClass.members[1].getDisplayDetails().displayText).toBe('string : foo');
|
||||
expect(testClass.methods[0].getDisplayDetails().displayText).toBe('test()');
|
||||
expect(testClass.methods[1].getDisplayDetails().displayText).toBe('foo()');
|
||||
});
|
||||
|
||||
it('should handle abstract methods', function () {
|
||||
@@ -1181,7 +1188,9 @@ describe('given a class diagram with relationships, ', function () {
|
||||
expect(testClass.annotations.length).toBe(0);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
expect(testClass.methods[0]).toBe('someMethod()*');
|
||||
const method = testClass.methods[0];
|
||||
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
|
||||
expect(method.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
|
||||
});
|
||||
|
||||
it('should handle static methods', function () {
|
||||
@@ -1192,7 +1201,9 @@ describe('given a class diagram with relationships, ', function () {
|
||||
expect(testClass.annotations.length).toBe(0);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
expect(testClass.methods[0]).toBe('someMethod()$');
|
||||
const method = testClass.methods[0];
|
||||
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
|
||||
expect(method.getDisplayDetails().cssStyle).toBe(staticCssStyle);
|
||||
});
|
||||
|
||||
it('should associate link and css appropriately', function () {
|
||||
@@ -1418,8 +1429,8 @@ class Class2
|
||||
const c1 = classParser.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('+member1');
|
||||
|
||||
const member = c1.members[0];
|
||||
expect(member.getDisplayDetails().displayText).toBe('+member1');
|
||||
const c2 = classParser.getClass('C2');
|
||||
expect(c2.label).toBe('C2');
|
||||
});
|
||||
@@ -1435,9 +1446,10 @@ class Class2
|
||||
const c1 = classParser.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('+member1');
|
||||
expect(c1.annotations.length).toBe(1);
|
||||
expect(c1.annotations[0]).toBe('interface');
|
||||
const member = c1.members[0];
|
||||
expect(member.getDisplayDetails().displayText).toBe('+member1');
|
||||
|
||||
const c2 = classParser.getClass('C2');
|
||||
expect(c2.label).toBe('C2');
|
||||
@@ -1454,8 +1466,9 @@ C1 --> C2
|
||||
const c1 = classParser.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('+member1');
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
const member = c1.members[0];
|
||||
expect(member.getDisplayDetails().displayText).toBe('+member1');
|
||||
});
|
||||
|
||||
it('should parse a class with text label and css class', () => {
|
||||
@@ -1470,8 +1483,9 @@ cssClass "C1" styleClass
|
||||
const c1 = classParser.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('+member1');
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
const member = c1.members[0];
|
||||
expect(member.getDisplayDetails().displayText).toBe('+member1');
|
||||
});
|
||||
|
||||
it('should parse two classes with text labels and css classes', () => {
|
||||
|
@@ -39,7 +39,12 @@ describe('when parsing class diagram', function () {
|
||||
"id": "Student",
|
||||
"label": "Student",
|
||||
"members": [
|
||||
"-idCard : IdCard",
|
||||
ClassMember {
|
||||
"classifier": "",
|
||||
"id": "idCard : IdCard",
|
||||
"memberType": "attribute",
|
||||
"visibility": "-",
|
||||
},
|
||||
],
|
||||
"methods": [],
|
||||
"type": "",
|
||||
|
@@ -21,6 +21,7 @@ import {
|
||||
ClassMap,
|
||||
NamespaceMap,
|
||||
NamespaceNode,
|
||||
ClassMember,
|
||||
} from './classTypes.js';
|
||||
|
||||
const MERMAID_DOM_ID_PREFIX = 'classId-';
|
||||
@@ -186,9 +187,9 @@ export const addMember = function (className: string, member: string) {
|
||||
theClass.annotations.push(sanitizeText(memberString.substring(2, memberString.length - 2)));
|
||||
} else if (memberString.indexOf(')') > 0) {
|
||||
//its a method
|
||||
theClass.methods.push(sanitizeText(memberString));
|
||||
theClass.methods.push(new ClassMember(memberString, 'method'));
|
||||
} else if (memberString) {
|
||||
theClass.members.push(sanitizeText(memberString));
|
||||
theClass.members.push(new ClassMember(memberString, 'attribute'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -26,13 +26,18 @@ export class ClassMember {
|
||||
|
||||
constructor(input: string, memberType: string) {
|
||||
this.memberType = memberType;
|
||||
this.visibility = '';
|
||||
this.classifier = '';
|
||||
this.parseMember(input);
|
||||
}
|
||||
|
||||
getDisplayDetails() {
|
||||
let displayText = this.visibility + parseGenericTypes(this.id);
|
||||
if (this.memberType === 'method') {
|
||||
displayText += '(' + parseGenericTypes(this.parameters.trim()) + ')' + ' ' + this.returnType;
|
||||
displayText += '(' + parseGenericTypes(this.parameters.trim()) + ')';
|
||||
if (this.returnType) {
|
||||
displayText += ' : ' + parseGenericTypes(this.returnType);
|
||||
}
|
||||
}
|
||||
|
||||
displayText = displayText.trim();
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { line, curveBasis } from 'd3';
|
||||
import utils from '../../utils.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { parseGenericTypes } from '../common/common.js';
|
||||
|
||||
let edgeCount = 0;
|
||||
export const drawEdge = function (elem, path, relation, conf, diagObj) {
|
||||
@@ -302,7 +303,7 @@ export const getClassTitleString = function (classDef) {
|
||||
let classTitleString = classDef.id;
|
||||
|
||||
if (classDef.type) {
|
||||
classTitleString += '<' + classDef.type + '>';
|
||||
classTitleString += '<' + parseGenericTypes(classDef.type) + '>';
|
||||
}
|
||||
|
||||
return classTitleString;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import svgDraw from './svgDraw.js';
|
||||
import { JSDOM } from 'jsdom';
|
||||
|
||||
describe('given a string representing a class, ', function () {
|
||||
describe('when class name includes generic, ', function () {
|
||||
@@ -15,7 +16,7 @@ describe('given a string representing a class, ', function () {
|
||||
it('should return correct text for nested generics', function () {
|
||||
const classDef = {
|
||||
id: 'Car',
|
||||
type: 'T~TT~',
|
||||
type: 'T~T~',
|
||||
label: 'Car',
|
||||
};
|
||||
|
||||
@@ -23,12 +24,4 @@ describe('given a string representing a class, ', function () {
|
||||
expect(actual).toBe('Car<T<T>>');
|
||||
});
|
||||
});
|
||||
describe('when class has no members, ', function () {
|
||||
it('should have no members', function () {
|
||||
const str = 'class Class10';
|
||||
let actual = svgDraw.drawClass(str);
|
||||
|
||||
expect(actual.displayText).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -189,7 +189,7 @@ export const parseGenericTypes = function (text: string): string {
|
||||
|
||||
do {
|
||||
cleanedText = newCleanedText;
|
||||
newCleanedText = cleanedText.replace(/~([^\s,:;]+)~/, '<$1>');
|
||||
newCleanedText = cleanedText.replace(/~([^:;]+)~/, '<$1>');
|
||||
} while (newCleanedText != cleanedText);
|
||||
|
||||
return parseGenericTypes(newCleanedText);
|
||||
|
Reference in New Issue
Block a user