Skip to content

Commit

Permalink
bug(ClassDiagram): Fixed a combination abstract and static modifiers …
Browse files Browse the repository at this point in the history
…() not working.
  • Loading branch information
TeaDrinkingProgrammer committed Apr 14, 2024
1 parent e570863 commit bfe2bec
Show file tree
Hide file tree
Showing 2 changed files with 230 additions and 28 deletions.
216 changes: 216 additions & 0 deletions packages/mermaid/src/diagrams/class/classTypes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const spyOn = vi.spyOn;

const staticCssStyle = 'text-decoration:underline;';
const abstractCssStyle = 'font-style:italic;';
const staticAbstractCssStyle = 'text-decoration:underline;font-style:italic;';

describe('given text representing a method, ', function () {
describe('when method has no parameters', function () {
Expand Down Expand Up @@ -57,6 +58,22 @@ describe('given text representing a method, ', function () {
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and abstract classifier', function () {
const str = `getTime()$*`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});

it('should return correct css for abstract and static classifier', function () {
const str = `getTime()*$`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});
});

describe('when method has single parameter value', function () {
Expand Down Expand Up @@ -110,6 +127,21 @@ describe('given text representing a method, ', function () {
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and abstract classifier', function () {
const str = `getTime(int)$*`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});
it('should return correct css for abstract and static classifier', function () {
const str = `getTime(int)*$`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});
});

describe('when method has single parameter type and name (type first)', function () {
Expand Down Expand Up @@ -163,6 +195,22 @@ describe('given text representing a method, ', function () {
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and abstract classifier', function () {
const str = `getTime(int count)$*`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});

it('should return correct css for abstract classifier', function () {
const str = `getTime(int count)*$`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});
});

describe('when method has single parameter type and name (name first)', function () {
Expand Down Expand Up @@ -216,6 +264,22 @@ describe('given text representing a method, ', function () {
expect(classMember.getDisplayDetails().displayText).toBe('getTime(count int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and abstract classifier', function () {
const str = `getTime(count int)$*`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(count int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});

it('should return correct css for abstract and static classifier', function () {
const str = `getTime(count int)*$`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(count int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});
});

describe('when method has multiple parameters', function () {
Expand Down Expand Up @@ -269,6 +333,22 @@ describe('given text representing a method, ', function () {
expect(classMember.getDisplayDetails().displayText).toBe('getTime(string text, int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and abstract classifier', function () {
const str = `getTime(string text, int count)$*`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(string text, int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});

it('should return correct css for abstract and static classifier', function () {
const str = `getTime(string text, int count)*$`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(string text, int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});
});

describe('when method has return type', function () {
Expand Down Expand Up @@ -322,6 +402,22 @@ describe('given text representing a method, ', function () {
expect(classMember.getDisplayDetails().displayText).toBe('getTime() : DateTime');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and 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(staticAbstractCssStyle);
});

it('should return correct css for abstract and 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(staticAbstractCssStyle);
});
});

describe('when method parameter is generic', function () {
Expand Down Expand Up @@ -375,6 +471,22 @@ describe('given text representing a method, ', function () {
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and 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(staticAbstractCssStyle);
});

it('should return correct css for abstract and 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(staticAbstractCssStyle);
});
});

describe('when method parameter contains two generic', function () {
Expand Down Expand Up @@ -428,6 +540,22 @@ describe('given text representing a method, ', function () {
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>, List<OT>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and abstract classifier', function () {
const str = `getTimes(List~T~, List~OT~)$*`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>, List<OT>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});

it('should return correct css for abstract and static classifier', function () {
const str = `getTimes(List~T~, List~OT~)*$`;

const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>, List<OT>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});
});

describe('when method parameter is a nested generic', function () {
Expand Down Expand Up @@ -481,6 +609,22 @@ describe('given text representing a method, ', function () {
expect(classMember.getDisplayDetails().displayText).toBe('getTimetableList(List<List<T>>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and 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(staticAbstractCssStyle);
});

it('should return correct css for abstract and 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(staticAbstractCssStyle);
});
});

describe('when method parameter is a composite generic', function () {
Expand Down Expand Up @@ -540,6 +684,20 @@ describe('given text representing a method, ', function () {
expect(classMember.getDisplayDetails().displayText).toBe(expectedMethodNameAndParameters);
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and abstract classifier', function () {
const str = methodNameAndParameters + '$*';
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(expectedMethodNameAndParameters);
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});

it('should return correct css for abstract and static classifier', function () {
const str = methodNameAndParameters + '*$';
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(expectedMethodNameAndParameters);
expect(classMember.getDisplayDetails().cssStyle).toBe(staticAbstractCssStyle);
});
});

describe('when method return type is generic', function () {
Expand Down Expand Up @@ -593,6 +751,22 @@ describe('given text representing a method, ', function () {
expect(classMember.getDisplayDetails().displayText).toBe('getTimes() : List<T>');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and 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(staticAbstractCssStyle);
});

it('should return correct css for abstract and 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(staticAbstractCssStyle);
});
});

describe('when method return type is a nested generic', function () {
Expand Down Expand Up @@ -660,6 +834,26 @@ describe('given text representing a method, ', function () {
);
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});

it('should return correct css for static and 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(staticAbstractCssStyle);
});

it('should return correct css for abstract and 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(staticAbstractCssStyle);
});
});

describe('--uncategorized tests--', function () {
Expand Down Expand Up @@ -759,4 +953,26 @@ describe('given text representing an attribute', () => {
expect(displayDetails.cssStyle).toBe(abstractCssStyle);
});
});

describe('when the attribute has static and abstract "$*" modifier', () => {
it('should parse the display text correctly and apply abstract css style', () => {
const str = 'name String$*';

const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails();

expect(displayDetails.displayText).toBe('name String');
expect(displayDetails.cssStyle).toBe(staticAbstractCssStyle);
});
});

describe('when the attribute has abstract and static "*$" modifier', () => {
it('should parse the display text correctly and apply abstract css style', () => {
const str = 'name String*$';

const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails();

expect(displayDetails.displayText).toBe('name String');
expect(displayDetails.cssStyle).toBe(staticAbstractCssStyle);
});
});
});
42 changes: 14 additions & 28 deletions packages/mermaid/src/diagrams/class/classTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,56 +76,42 @@ export class ClassMember {
let potentialClassifier = '';

if (this.memberType === 'method') {
const methodRegEx = /([#+~-])?(.+)\((.*)\)([\s$*])?(.*)([$*])?/;
const methodRegEx = /([#+~-])?(.+)\((.*)\)([$*]{0,2})(.*?)([$*]{0,2})$/;
const match = input.match(methodRegEx);
if (match) {
const detectedVisibility = match[1] ? match[1].trim() : '';

if (visibilityValues.includes(detectedVisibility)) {
this.visibility = detectedVisibility as Visibility;
}

this.visibility = (match[1] ? match[1].trim() : '') as Visibility;
this.id = match[2].trim();
this.parameters = match[3] ? match[3].trim() : '';
potentialClassifier = match[4] ? match[4].trim() : '';
this.returnType = match[5] ? match[5].trim() : '';

if (potentialClassifier === '') {
const lastChar = this.returnType.substring(this.returnType.length - 1);
if (lastChar.match(/[$*]/)) {
potentialClassifier = lastChar;
this.returnType = this.returnType.substring(0, this.returnType.length - 1);
}
potentialClassifier = match[6] ? match[6].trim() : '';
}
}
} else {
const length = input.length;
const firstChar = input.substring(0, 1);
const lastChar = input.substring(length - 1);
const fieldRegEx = /([#+~-])?(.*?)([$*]{0,2})$/;
const match = input.match(fieldRegEx);

if (visibilityValues.includes(firstChar)) {
this.visibility = firstChar as Visibility;
}

if (lastChar.match(/[$*]/)) {
potentialClassifier = lastChar;
if (match) {
this.visibility = (match[1] ? match[1].trim() : '') as Visibility;
this.id = match[2] ? match[2].trim() : '';
potentialClassifier = match[3] ? match[3].trim() : '';
}

this.id = input.substring(
this.visibility === '' ? 0 : 1,
potentialClassifier === '' ? length : length - 1
);
}

this.classifier = potentialClassifier;
}

parseClassifier() {
switch (this.classifier) {
case '*':
return 'font-style:italic;';
case '$':
return 'text-decoration:underline;';
case '*':
return 'font-style:italic;';
case '$*':
case '*$':
return 'text-decoration:underline;font-style:italic;';
default:
return '';
}
Expand Down

0 comments on commit bfe2bec

Please sign in to comment.