Update and add tests

This commit is contained in:
Justin Greywolf 2023-06-02 03:08:53 -07:00
parent 0aa09bfca5
commit b0b3c7f410
6 changed files with 617 additions and 614 deletions

View File

@ -114,11 +114,11 @@ export const clear = function () {
commonClear();
};
export const getClass = function (id: string) {
export const getClass = function (id: string): ClassNode {
return classes[id];
};
export const getClasses = function () {
export const getClasses = function (): ClassMap {
return classes;
};

View File

@ -93,20 +93,20 @@ export const addClasses = function (
log.info(classes);
keys.forEach(function (id) {
const vertex = classes[id];
const classNode = classes[id];
/**
* Variable for storing the classes for the vertex
* Variable for storing the css classes for the vertex
*/
let cssClassStr = '';
if (vertex.cssClasses.length > 0) {
cssClassStr = cssClassStr + ' ' + vertex.cssClasses.join(' ');
if (classNode.cssClasses.length > 0) {
cssClassStr = cssClassStr + ' ' + classNode.cssClasses.join(' ');
}
const styles = { labelStyle: '', style: '' }; //getStylesFromArray(vertex.styles);
// Use vertex id as text in the box if no text is provided by the graph definition
const vertexText = vertex.label ?? vertex.id;
const nodeText = classNode.label ?? classNode.id;
const radius = 0;
const shape = 'class_box';
@ -114,26 +114,26 @@ export const addClasses = function (
const node = {
labelStyle: styles.labelStyle,
shape: shape,
labelText: sanitizeText(vertexText),
classData: vertex,
labelText: sanitizeText(nodeText),
classData: classNode,
rx: radius,
ry: radius,
class: cssClassStr,
style: styles.style,
id: vertex.id,
domId: vertex.domId,
tooltip: diagObj.db.getTooltip(vertex.id, parent) || '',
haveCallback: vertex.haveCallback,
link: vertex.link,
width: vertex.type === 'group' ? 500 : undefined,
type: vertex.type,
id: classNode.id,
domId: classNode.domId,
tooltip: diagObj.db.getTooltip(classNode.id, parent) || '',
haveCallback: classNode.haveCallback,
link: classNode.link,
width: classNode.type === 'group' ? 500 : undefined,
type: classNode.type,
// TODO V10: Flowchart ? Keeping flowchart for backwards compatibility. Remove in next major release
padding: getConfig().flowchart?.padding ?? getConfig().class?.padding,
};
g.setNode(vertex.id, node);
g.setNode(classNode.id, node);
if (parent) {
g.setParent(vertex.id, parent);
g.setParent(classNode.id, parent);
}
log.info('setNode', node);

View File

@ -2,210 +2,600 @@ import { ClassMember } from './classTypes.js';
import { vi, describe, it, expect } from 'vitest';
const spyOn = vi.spyOn;
describe('given text representing member declaration, ', function () {
describe('when text is a method with no parameters', function () {
it('should parse simple method', function () {
const str = `getTime()`;
const staticCssStyle = 'text-decoration:underline;';
const abstractCssStyle = 'font-style:italic;';
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
describe('given text representing a member, ', function () {
describe('when parseMember is called as method', function () {
describe('when method has no parameters', function () {
it('should parse correctly', function () {
const str = `getTime()`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle public visibility', function () {
const str = `+getTime()`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime()');
});
it('should handle private visibility', function () {
const str = `-getTime()`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime()');
});
it('should handle protected visibility', function () {
const str = `#getTime()`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime()');
});
it('should handle internal visibility', function () {
const str = `~getTime()`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime()');
});
it('should return correct css for static classifier', function () {
const str = `getTime()$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTime()*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
it('should parse public visibiity', function () {
const str = `+getTime()`;
describe('when method has single parameter value', function () {
it('should parse correctly', function () {
const str = `getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime()');
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle public visibility', function () {
const str = `+getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime()');
});
it('should handle private visibility', function () {
const str = `-getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime()');
});
it('should handle protected visibility', function () {
const str = `#getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime()');
});
it('should handle internal visibility', function () {
const str = `~getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime()');
});
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().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTime(int)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
it('should parse private visibiity', function () {
const str = `-getTime()`;
describe('when method has single parameter type and name (type first)', function () {
it('should parse correctly', function () {
const str = `getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime()');
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle public visibility', function () {
const str = `+getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime()');
});
it('should handle private visibility', function () {
const str = `-getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime()');
});
it('should handle protected visibility', function () {
const str = `#getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime()');
});
it('should handle internal visibility', function () {
const str = `~getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime()');
});
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().cssStyle).toBe(staticCssStyle);
});
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()');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
it('should parse protected visibiity', function () {
const str = `#getTime()`;
describe('when method has single parameter type and name (name first)', function () {
it('should parse correctly', function () {
const str = `getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime()');
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle public visibility', function () {
const str = `+getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime()');
});
it('should handle private visibility', function () {
const str = `-getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime()');
});
it('should handle protected visibility', function () {
const str = `#getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime()');
});
it('should handle internal visibility', function () {
const str = `~getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime()');
});
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().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTime(count int)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
it('should parse internal visibiity', function () {
const str = `~getTime()`;
describe('when method has multiple parameters', function () {
it('should parse correctly', function () {
const str = `getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime()');
});
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should return correct css for static classifier', function () {
const str = `getTime()$`;
it('should handle public visibility', function () {
const str = `+getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().cssStyle).toBe('text-decoration:underline;');
});
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime()');
});
it('should return correct css for abstrtact', function () {
const str = `getTime()*`;
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().cssStyle).toBe('font-style:italic;');
});
});
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime()');
});
describe('when text is a method with parameters', function () {
it('should parse method with parameter type, as provided', function () {
const str = `getTime(String)`;
it('should handle protected visibility', function () {
const str = `#getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime()');
});
it('should parse method with parameter type and name, as provided', function () {
const str = `getTime(String time)`;
it('should handle internal visibility', function () {
const str = `~getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime()');
});
it('should parse method with parameters, as provided', function () {
const str = `getTime(String time, date Date)`;
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(str);
});
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for static method with parameter type, as provided', function () {
const str = `getTime(String)$`;
it('should return correct css for abstract classifier', function () {
const str = `getTime(string text, int count)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(String)');
expect(classMember.getDisplayDetails().cssStyle).toBe('text-decoration:underline;');
});
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('text-decoration:underline;');
});
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('text-decoration:underline;');
});
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('font-style:italic;');
});
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('font-style:italic;');
});
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('font-style:italic;');
});
});
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('text-decoration:underline;');
});
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('text-decoration:underline;');
});
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('text-decoration:underline;');
});
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('font-style:italic;');
});
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('font-style:italic;');
});
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('font-style:italic;');
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
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

@ -5,8 +5,8 @@ export interface ClassNode {
type: string;
label: string;
cssClasses: string[];
methods: string[];
members: string[];
methods: ClassMember[];
members: ClassMember[];
annotations: string[];
domId: string;
link?: string;

View File

@ -1,7 +1,6 @@
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) {
@ -372,81 +371,20 @@ export const drawNote = function (elem, note, conf, diagObj) {
return noteInfo;
};
export const parseMember = function (text) {
let displayText = '';
let cssStyle = '';
let returnType = '';
let visibility = '';
const firstChar = text.substring(0, 1);
const lastChar = text.substring(text.length - 1, text.length);
if (firstChar.match(/[#+~-]/)) {
visibility = firstChar;
}
const noClassifierRe = /[\s\w)~]/;
if (!lastChar.match(noClassifierRe)) {
cssStyle = parseClassifier(lastChar);
}
const startIndex = visibility === '' ? 0 : 1;
const endIndex = cssStyle === '' ? text.length : text.length - 1;
text = text.substring(startIndex, endIndex);
const methodStart = text.indexOf('(');
const methodEnd = text.indexOf(')');
const isMethod = methodStart > 1 && methodEnd > methodStart && methodEnd <= text.length;
if (isMethod) {
const methodName = text.substring(0, methodStart).trim();
const parameters = text.substring(methodStart + 1, methodEnd);
displayText = visibility + methodName + '(' + parseGenericTypes(parameters.trim()) + ')';
if (methodEnd < text.length) {
// special case: classifier after the closing parenthesis
let potentialClassifier = text.substring(methodEnd + 1, methodEnd + 2);
if (cssStyle === '' && !potentialClassifier.match(noClassifierRe)) {
cssStyle = parseClassifier(potentialClassifier);
returnType = text.substring(methodEnd + 2).trim();
} else {
returnType = text.substring(methodEnd + 1).trim();
}
if (returnType !== '') {
if (returnType.charAt(0) === ':') {
returnType = returnType.substring(1).trim();
}
returnType = ' : ' + parseGenericTypes(returnType);
displayText += returnType;
}
}
} else {
// finally - if all else fails, just send the text back as written (other than parsing for generic types)
displayText = visibility + parseGenericTypes(text);
}
return {
displayText,
cssStyle,
};
};
/**
* Adds a <tspan> for a member in a diagram
*
* @param {SVGElement} textEl The element to append to
* @param {string} txt The member
* @param {string} member The member
* @param {boolean} isFirst
* @param {{ padding: string; textHeight: string }} conf The configuration for the member
*/
const addTspan = function (textEl, txt, isFirst, conf) {
let member = parseMember(txt);
const addTspan = function (textEl, member, isFirst, conf) {
const displayText = member.getDisplayDetails().displayText;
const cssStyle = member.getDisplayDetails().cssStyle;
const tSpan = textEl.append('tspan').attr('x', conf.padding).text(displayText);
const tSpan = textEl.append('tspan').attr('x', conf.padding).text(member.displayText);
if (member.cssStyle !== '') {
if (cssStyle !== '') {
tSpan.attr('style', member.cssStyle);
}
@ -455,27 +393,9 @@ const addTspan = function (textEl, txt, isFirst, conf) {
}
};
/**
* Gives the styles for a classifier
*
* @param {'+' | '-' | '#' | '~' | '*' | '$'} classifier The classifier string
* @returns {string} Styling for the classifier
*/
const parseClassifier = function (classifier) {
switch (classifier) {
case '*':
return 'font-style:italic;';
case '$':
return 'text-decoration:underline;';
default:
return '';
}
};
export default {
getClassTitleString,
drawClass,
drawEdge,
drawNote,
parseMember,
};

View File

@ -1,341 +1,34 @@
import svgDraw from './svgDraw.js';
describe('given a string representing a class, ', function () {
it('should handle class names with generics', function () {
const classDef = {
id: 'Car',
type: 'T',
label: 'Car',
};
describe('when class name includes generic, ', function () {
it('should return correct text for generic', function () {
const classDef = {
id: 'Car',
type: 'T',
label: 'Car',
};
let actual = svgDraw.getClassTitleString(classDef);
expect(actual).toBe('Car<T>');
});
it('should handle class names with nested generics', function () {
const classDef = {
id: 'Car',
type: 'T~TT~',
label: 'Car',
};
let actual = svgDraw.getClassTitleString(classDef);
expect(actual).toBe('Car<T<T>>');
});
describe('when parsing member method', function () {
it('should handle simple declaration', function () {
const str = 'foo()';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo()');
expect(actual.cssStyle).toBe('');
let actual = svgDraw.getClassTitleString(classDef);
expect(actual).toBe('Car<T>');
});
it('should return correct text for nested generics', function () {
const classDef = {
id: 'Car',
type: 'T~TT~',
label: 'Car',
};
it('should handle declaration with parameters', function () {
const str = 'foo(int id)';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(int id)');
expect(actual.cssStyle).toBe('');
});
it('should handle declaration with multiple parameters', function () {
const str = 'foo(int id, object thing)';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(int id, object thing)');
expect(actual.cssStyle).toBe('');
});
it('should handle declaration with single item in parameters', function () {
const str = 'foo(id)';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(id)');
expect(actual.cssStyle).toBe('');
});
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('font-style:italic;');
});
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('font-style:italic;');
});
it('should correctly handle public visibility', function () {
const str = '+foo()';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('+foo()');
expect(actual.cssStyle).toBe('');
});
it('should correctly handle private visibility', function () {
const str = '-foo()';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('-foo()');
expect(actual.cssStyle).toBe('');
});
it('should correctly handle protected visibility', function () {
const str = '#foo()';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('#foo()');
expect(actual.cssStyle).toBe('');
});
it('should correctly handle package/internal visibility', function () {
const str = '~foo()';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('~foo()');
expect(actual.cssStyle).toBe('');
});
it('should handle abstract method', function () {
const str = 'foo()*';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo()');
expect(actual.cssStyle).toBe('font-style:italic;');
});
it('should handle abstract method 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('font-style:italic;');
});
it('should handle abstract 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('font-style:italic;');
});
it('should handle static method classifier', function () {
const str = 'foo()$';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo()');
expect(actual.cssStyle).toBe('text-decoration:underline;');
});
it('should handle static method classifier 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('text-decoration:underline;');
});
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('text-decoration:underline;');
});
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('text-decoration:underline;');
});
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('');
let actual = svgDraw.getClassTitleString(classDef);
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);
describe('when parsing member field', function () {
it('should handle simple field', function () {
const str = 'id';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('id');
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('text-decoration:underline;');
});
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('text-decoration:underline;');
});
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('text-decoration:underline;');
});
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('text-decoration:underline;');
});
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('');
expect(actual.displayText).toBe('');
});
});
});
describe('given a string representing class with no members, ', function () {
it('should have no members', function () {
const str = 'class Class10';
let actual = svgDraw.drawClass(str);
expect(actual.displayText).toBe('');
});
});