update classes to handle , in generic

This commit is contained in:
Justin Greywolf
2023-06-12 11:31:29 -07:00
parent f4ffd5c965
commit 164605b442
10 changed files with 645 additions and 613 deletions

View File

@@ -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 />

View File

@@ -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, '&lt;').replace(/>/g, '&gt;');
@@ -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, '&lt;').replace(/>/g, '&gt;');

View File

@@ -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', () => {

View File

@@ -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": "",

View File

@@ -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'));
}
}
};

View File

@@ -5,8 +5,7 @@ const spyOn = vi.spyOn;
const staticCssStyle = 'text-decoration:underline;';
const abstractCssStyle = 'font-style:italic;';
describe('given text representing a member, ', function () {
describe('when parseMember is called as method', function () {
describe('given text representing a method, ', function () {
describe('when method has no parameters', function () {
it('should parse correctly', function () {
const str = `getTime()`;
@@ -72,35 +71,35 @@ describe('given text representing a member, ', function () {
const str = `+getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime(int)');
});
it('should handle private visibility', function () {
const str = `-getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime(int)');
});
it('should handle protected visibility', function () {
const str = `#getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime(int)');
});
it('should handle internal visibility', function () {
const str = `~getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime(int)');
});
it('should return correct css for static classifier', function () {
const str = `getTime(int)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
@@ -108,7 +107,7 @@ describe('given text representing a member, ', function () {
const str = `getTime(int)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
@@ -125,35 +124,35 @@ describe('given text representing a member, ', function () {
const str = `+getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime(int count)');
});
it('should handle private visibility', function () {
const str = `-getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime(int count)');
});
it('should handle protected visibility', function () {
const str = `#getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime(int count)');
});
it('should handle internal visibility', function () {
const str = `~getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime(int count)');
});
it('should return correct css for static classifier', function () {
const str = `getTime(int count)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
@@ -161,7 +160,7 @@ describe('given text representing a member, ', function () {
const str = `getTime(int count)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
@@ -178,35 +177,35 @@ describe('given text representing a member, ', function () {
const str = `+getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime(count int)');
});
it('should handle private visibility', function () {
const str = `-getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime(count int)');
});
it('should handle protected visibility', function () {
const str = `#getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime(count int)');
});
it('should handle internal visibility', function () {
const str = `~getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime(count int)');
});
it('should return correct css for static classifier', function () {
const str = `getTime(count int)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(count int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
@@ -214,7 +213,7 @@ describe('given text representing a member, ', function () {
const str = `getTime(count int)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(count int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
@@ -231,35 +230,35 @@ describe('given text representing a member, ', function () {
const str = `+getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime()');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle private visibility', function () {
const str = `-getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime()');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle protected visibility', function () {
const str = `#getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime()');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle internal visibility', function () {
const str = `~getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime()');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should return correct css for static classifier', function () {
const str = `getTime(string text, int count)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(string text, int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
@@ -267,335 +266,346 @@ describe('given text representing a member, ', function () {
const str = `getTime(string text, int count)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(string text, int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method has return type', function () {
it('should parse correctly', function () {
const str = `getTime() DateTime`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime() : DateTime');
});
it('should handle public visibility', function () {
const str = `+getTime() DateTime`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime() : DateTime');
});
it('should handle private visibility', function () {
const str = `-getTime() DateTime`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime() : DateTime');
});
it('should handle protected visibility', function () {
const str = `#getTime() DateTime`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime() : DateTime');
});
it('should handle internal visibility', function () {
const str = `~getTime() DateTime`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime() : DateTime');
});
it('should return correct css for static classifier', function () {
const str = `getTime() DateTime$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime() : DateTime');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTime() DateTime*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime() : DateTime');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method parameter is generic', function () {
it('should parse correctly', function () {
const str = `getTimes(List~T~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>)');
});
it('should handle public visibility', function () {
const str = `+getTimes(List~T~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTimes(List<T>)');
});
it('should handle private visibility', function () {
const str = `-getTimes(List~T~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTimes(List<T>)');
});
it('should handle protected visibility', function () {
const str = `#getTimes(List~T~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTimes(List<T>)');
});
it('should handle internal visibility', function () {
const str = `~getTimes(List~T~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTimes(List<T>)');
});
it('should return correct css for static classifier', function () {
const str = `getTimes(List~T~)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTimes(List~T~)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List>List<T>>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method parameter is a nested generic', function () {
it('should parse correctly', function () {
const str = `getTimetableList(List~List~T~~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimetableList(List<List<T>>)');
});
it('should handle public visibility', function () {
const str = `+getTimetableList(List~List~T~~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTimetableList(List<List<T>>)');
});
it('should handle private visibility', function () {
const str = `-getTimetableList(List~List~T~~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTimetableList(List<List<T>>)');
});
it('should handle protected visibility', function () {
const str = `#getTimetableList(List~List~T~~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTimetableList(List<List<T>>)');
});
it('should handle internal visibility', function () {
const str = `~getTimetableList(List~List~T~~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTimetableList(List<List<T>>)');
});
it('should return correct css for static classifier', function () {
const str = `getTimetableList(List~List~T~~)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimetableList(List<List<T>>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTimetableList(List~List~T~~)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimetableList(List<List<T>>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method parameter is a composite generic', function () {
const methodNameAndParameters = 'getTimes(List~K, V~)';
const expectedMethodNameAndParameters = 'getTimes(List<K, V>)';
it('should parse correctly', function () {
const str = methodNameAndParameters;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(expectedMethodNameAndParameters);
});
it('should handle public visibility', function () {
const str = '+' + methodNameAndParameters;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'+' + expectedMethodNameAndParameters
);
});
it('should handle private visibility', function () {
const str = '-' + methodNameAndParameters;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'-' + expectedMethodNameAndParameters
);
});
it('should handle protected visibility', function () {
const str = '#' + methodNameAndParameters;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'#' + expectedMethodNameAndParameters
);
});
it('should handle internal visibility', function () {
const str = '~' + methodNameAndParameters;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'~' + expectedMethodNameAndParameters
);
});
it('should return correct css for static classifier', function () {
const str = methodNameAndParameters + '$';
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(expectedMethodNameAndParameters);
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = methodNameAndParameters + '*';
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(expectedMethodNameAndParameters);
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method return type is generic', function () {
it('should parse correctly', function () {
const str = `getTimes() List~T~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes() : List<T>');
});
it('should handle public visibility', function () {
const str = `+getTimes() List~T~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTimes() : List<T>');
});
it('should handle private visibility', function () {
const str = `-getTimes() List~T~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTimes() : List<T>');
});
it('should handle protected visibility', function () {
const str = `#getTimes() List~T~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTimes() : List<T>');
});
it('should handle internal visibility', function () {
const str = `~getTimes() List~T~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTimes() : List<T>');
});
it('should return correct css for static classifier', function () {
const str = `getTimes() List~T~$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes() : List<T>');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTimes() List~T~*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes() : List<T>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method return type is a nested generic', function () {
it('should parse correctly', function () {
const str = `getTimetableList() List~List~T~~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'getTimetableList() : List<List<T>>'
);
});
it('should handle public visibility', function () {
const str = `+getTimetableList() List~List~T~~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'+getTimetableList() : List<List<T>>'
);
});
it('should handle private visibility', function () {
const str = `-getTimetableList() List~List~T~~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'-getTimetableList() : List<List<T>>'
);
});
it('should handle protected visibility', function () {
const str = `#getTimetableList() List~List~T~~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'#getTimetableList() : List<List<T>>'
);
});
it('should handle internal visibility', function () {
const str = `~getTimetableList() List~List~T~~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'~getTimetableList() : List<List<T>>'
);
});
it('should return correct css for static classifier', function () {
const str = `getTimetableList() List~List~T~~$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'getTimetableList() : List<List<T>>'
);
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTimetableList() List~List~T~~*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'getTimetableList() : List<List<T>>'
);
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
});
});
// it('should return correct css for static method with parameter type, as provided', function () {
// const str = `getTime(String)$`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe('getTime(String)');
// expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
// });
// it('should return correct css for static method with parameter type and name, as provided', function () {
// const str = `getTime(String time)$`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe('getTime(String time)');
// expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
// });
// it('should return correct css for static method with parameters, as provided', function () {
// const str = `getTime(String time, date Date)$`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe('getTime(String time, date Date)');
// expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
// });
// it('should return correct css for abstract method with parameter type, as provided', function () {
// const str = `getTime(String)*`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe('getTime(String)');
// expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
// });
// it('should return correct css for abstract method with parameter type and name, as provided', function () {
// const str = `getTime(String time)*`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe('getTime(String time)');
// expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
// });
// it('should return correct css for abstract method with parameters, as provided', function () {
// const str = `getTime(String time, date Date)*`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe('getTime(String time, date Date)');
// expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
// });
// });
// describe('when text is a method with return type', function () {
// it('should parse simple method with no parameter', function () {
// const str = `getTime() String`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe(str);
// });
// it('should parse method with parameter type, as provided', function () {
// const str = `getTime(String) String`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe(str);
// });
// it('should parse method with parameter type and name, as provided', function () {
// const str = `getTime(String time) String`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe(str);
// });
// it('should parse method with parameters, as provided', function () {
// const str = `getTime(String time, date Date) String`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe(str);
// });
// it('should return correct css for static method with no parameter', function () {
// const str = `getTime() String$`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe('getTime() String');
// expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
// });
// it('should return correct css for static method with parameter type and name, as provided', function () {
// const str = `getTime(String time) String$`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe('getTime(String time) String');
// expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
// });
// it('should return correct css for static method with parameters, as provided', function () {
// const str = `getTime(String time, date Date)$ String`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe(
// 'getTime(String time, date Date) String'
// );
// expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
// });
// it('should return correct css for abstract method with parameter type, as provided', function () {
// const str = `getTime(String) String*`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe('getTime(String) String');
// expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
// });
// it('should return correct css for abstract method with parameter type and name, as provided', function () {
// const str = `getTime(String time) String*`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe('getTime(String time) String');
// expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
// });
// it('should return correct css for abstract method with parameters, as provided', function () {
// const str = `getTime(String time, date Date) String*`;
// const classMember = new ClassMember(str, 'method');
// expect(classMember.getDisplayDetails().displayText).toBe(
// 'getTime(String time, date Date) String'
// );
// expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
// });
// });
// it('should handle declaration with single item in parameters with extra spaces', function () {
// const str = ' foo ( id) ';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo(id)');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle method declaration with generic parameter', function () {
// const str = 'foo(List~int~)';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo(List<int>)');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle method declaration with normal and generic parameter', function () {
// const str = 'foo(int, List~int~)';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo(int, List<int>)');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle declaration with return value', function () {
// const str = 'foo(id) int';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo(id) : int');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle declaration with colon return value', function () {
// const str = 'foo(id) : int';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo(id) : int');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle declaration with generic return value', function () {
// const str = 'foo(id) List~int~';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo(id) : List<int>');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle declaration with colon generic return value', function () {
// const str = 'foo(id) : List~int~';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo(id) : List<int>');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle method declaration with all possible markup', function () {
// const str = '+foo ( List~int~ ids )* List~Item~';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('+foo(List<int> ids) : List<Item>');
// expect(actual.cssStyle).toBe(abstractCssStyle);
// });
// it('should handle method declaration with nested generics', function () {
// const str = '+foo ( List~List~int~~ ids )* List~List~Item~~';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('+foo(List<List<int>> ids) : List<List<Item>>');
// expect(actual.cssStyle).toBe(abstractCssStyle);
// });
// it('should handle static method classifier with colon and return type', function () {
// const str = 'foo(name: String): int$';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo(name: String) : int');
// expect(actual.cssStyle).toBe(staticCssStyle);
// });
// it('should handle static method classifier after parenthesis with return type', function () {
// const str = 'foo(name: String)$ int';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo(name: String) : int');
// expect(actual.cssStyle).toBe(staticCssStyle);
// });
// it('should ignore unknown character for classifier', function () {
// const str = 'foo()!';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo()');
// expect(actual.cssStyle).toBe('');
// });
// });
// it('should handle field with type', function () {
// const str = 'int id';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('int id');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle field with type (name first)', function () {
// const str = 'id: int';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('id: int');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle array field', function () {
// const str = 'int[] ids';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('int[] ids');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle array field (name first)', function () {
// const str = 'ids: int[]';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('ids: int[]');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle field with generic type', function () {
// const str = 'List~int~ ids';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('List<int> ids');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle field with generic type (name first)', function () {
// const str = 'ids: List~int~';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('ids: List<int>');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle static field', function () {
// const str = 'String foo$';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('String foo');
// expect(actual.cssStyle).toBe(staticCssStyle);
// });
// it('should handle static field (name first)', function () {
// const str = 'foo: String$';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo: String');
// expect(actual.cssStyle).toBe(staticCssStyle);
// });
// it('should handle static field with generic type', function () {
// const str = 'List~String~ foo$';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('List<String> foo');
// expect(actual.cssStyle).toBe(staticCssStyle);
// });
// it('should handle static field with generic type (name first)', function () {
// const str = 'foo: List~String~$';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('foo: List<String>');
// expect(actual.cssStyle).toBe(staticCssStyle);
// });
// it('should handle field with nested generic type', function () {
// const str = 'List~List~int~~ idLists';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('List<List<int>> idLists');
// expect(actual.cssStyle).toBe('');
// });
// it('should handle field with nested generic type (name first)', function () {
// const str = 'idLists: List~List~int~~';
// let actual = svgDraw.parseMember(str);
// expect(actual.displayText).toBe('idLists: List<List<int>>');
// expect(actual.cssStyle).toBe('');
// });
// });
// });

View File

@@ -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();

View File

@@ -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;

View File

@@ -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('');
});
});
});

View File

@@ -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);