mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-19 15:30:03 +02:00
Merge pull request #3335 from FlorianWoelki/feature/3171_erDiagram_more_symbols
Add generic and array symbols to `erDiagram`
This commit is contained in:
@@ -167,6 +167,21 @@ describe('Entity Relationship Diagram', () => {
|
|||||||
cy.get('svg');
|
cy.get('svg');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.only('should render entities with generic and array attributes', () => {
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
erDiagram
|
||||||
|
BOOK {
|
||||||
|
string title
|
||||||
|
string[] authors
|
||||||
|
type~T~ type
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ logLevel: 1 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
|
||||||
it('should render entities and attributes with big and small entity names', () => {
|
it('should render entities and attributes with big and small entity names', () => {
|
||||||
renderGraph(
|
renderGraph(
|
||||||
`
|
`
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { line, curveBasis } from 'd3';
|
import { line, curveBasis } from 'd3';
|
||||||
import utils from '../../utils';
|
import utils from '../../utils';
|
||||||
import { log } from '../../logger';
|
import { log } from '../../logger';
|
||||||
|
import { parseGenericTypes } from '../common/common';
|
||||||
|
|
||||||
let edgeCount = 0;
|
let edgeCount = 0;
|
||||||
export const drawEdge = function (elem, path, relation, conf, diagObj) {
|
export const drawEdge = function (elem, path, relation, conf, diagObj) {
|
||||||
@@ -412,29 +413,6 @@ const addTspan = function (textEl, txt, isFirst, conf) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes generics in typescript syntax
|
|
||||||
*
|
|
||||||
* @example <caption>Array of array of strings in typescript syntax</caption>
|
|
||||||
* // returns "Array<Array<string>>"
|
|
||||||
* parseGenericTypes('Array~Array~string~~');
|
|
||||||
*
|
|
||||||
* @param {string} text The text to convert
|
|
||||||
* @returns {string} The converted string
|
|
||||||
*/
|
|
||||||
const parseGenericTypes = function (text) {
|
|
||||||
let cleanedText = text;
|
|
||||||
|
|
||||||
if (text.indexOf('~') != -1) {
|
|
||||||
cleanedText = cleanedText.replace('~', '<');
|
|
||||||
cleanedText = cleanedText.replace('~', '>');
|
|
||||||
|
|
||||||
return parseGenericTypes(cleanedText);
|
|
||||||
} else {
|
|
||||||
return cleanedText;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives the styles for a classifier
|
* Gives the styles for a classifier
|
||||||
*
|
*
|
||||||
|
@@ -182,6 +182,29 @@ const getUrl = (useAbsolute) => {
|
|||||||
*/
|
*/
|
||||||
export const evaluate = (val) => (val === 'false' || val === false ? false : true);
|
export const evaluate = (val) => (val === 'false' || val === false ? false : true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes generics in typescript syntax
|
||||||
|
*
|
||||||
|
* @example <caption>Array of array of strings in typescript syntax</caption>
|
||||||
|
* // returns "Array<Array<string>>"
|
||||||
|
* parseGenericTypes('Array~Array~string~~');
|
||||||
|
*
|
||||||
|
* @param {string} text The text to convert
|
||||||
|
* @returns {string} The converted string
|
||||||
|
*/
|
||||||
|
export const parseGenericTypes = function (text) {
|
||||||
|
let cleanedText = text;
|
||||||
|
|
||||||
|
if (text.indexOf('~') != -1) {
|
||||||
|
cleanedText = cleanedText.replace('~', '<');
|
||||||
|
cleanedText = cleanedText.replace('~', '>');
|
||||||
|
|
||||||
|
return parseGenericTypes(cleanedText);
|
||||||
|
} else {
|
||||||
|
return cleanedText;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getRows,
|
getRows,
|
||||||
sanitizeText,
|
sanitizeText,
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { sanitizeText, removeScript, removeEscapes } from './common';
|
import { sanitizeText, removeScript, removeEscapes, parseGenericTypes } from './common';
|
||||||
|
|
||||||
describe('when securityLevel is antiscript, all script must be removed', function () {
|
describe('when securityLevel is antiscript, all script must be removed', function () {
|
||||||
/**
|
/**
|
||||||
@@ -103,3 +103,10 @@ describe('Sanitize text', function () {
|
|||||||
expect(result).not.toContain('javascript:alert(1)');
|
expect(result).not.toContain('javascript:alert(1)');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('generic parser', function () {
|
||||||
|
it('should parse generic types', function () {
|
||||||
|
const result = parseGenericTypes('test~T~');
|
||||||
|
expect(result).toEqual('test<T>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@@ -8,6 +8,7 @@ import { log } from '../../logger';
|
|||||||
import erMarkers from './erMarkers';
|
import erMarkers from './erMarkers';
|
||||||
import { configureSvgSize } from '../../utils';
|
import { configureSvgSize } from '../../utils';
|
||||||
import addSVGAccessibilityFields from '../../accessibility';
|
import addSVGAccessibilityFields from '../../accessibility';
|
||||||
|
import { parseGenericTypes } from '../common/common';
|
||||||
|
|
||||||
let conf = {};
|
let conf = {};
|
||||||
|
|
||||||
@@ -63,6 +64,8 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {
|
|||||||
const attrPrefix = `${entityTextNode.node().id}-attr-${attrNum}`;
|
const attrPrefix = `${entityTextNode.node().id}-attr-${attrNum}`;
|
||||||
let nodeHeight = 0;
|
let nodeHeight = 0;
|
||||||
|
|
||||||
|
const attributeType = parseGenericTypes(item.attributeType);
|
||||||
|
|
||||||
// Add a text node for the attribute type
|
// Add a text node for the attribute type
|
||||||
const typeNode = groupNode
|
const typeNode = groupNode
|
||||||
.append('text')
|
.append('text')
|
||||||
@@ -76,7 +79,7 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {
|
|||||||
'style',
|
'style',
|
||||||
'font-family: ' + getConfig().fontFamily + '; font-size: ' + attrFontSize + 'px'
|
'font-family: ' + getConfig().fontFamily + '; font-size: ' + attrFontSize + 'px'
|
||||||
)
|
)
|
||||||
.text(item.attributeType);
|
.text(attributeType);
|
||||||
|
|
||||||
// Add a text node for the attribute name
|
// Add a text node for the attribute name
|
||||||
const nameNode = groupNode
|
const nameNode = groupNode
|
||||||
|
@@ -29,7 +29,8 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
|||||||
"{" { this.begin("block"); return 'BLOCK_START'; }
|
"{" { this.begin("block"); return 'BLOCK_START'; }
|
||||||
<block>\s+ /* skip whitespace in block */
|
<block>\s+ /* skip whitespace in block */
|
||||||
<block>\b((?:PK)|(?:FK))\b return 'ATTRIBUTE_KEY'
|
<block>\b((?:PK)|(?:FK))\b return 'ATTRIBUTE_KEY'
|
||||||
<block>[A-Za-z][A-Za-z0-9\-_]* return 'ATTRIBUTE_WORD'
|
<block>(.*?)[~](.*?)*[~] return 'ATTRIBUTE_WORD';
|
||||||
|
<block>[A-Za-z][A-Za-z0-9\-_\[\]]* return 'ATTRIBUTE_WORD'
|
||||||
<block>\"[^"]*\" return 'COMMENT';
|
<block>\"[^"]*\" return 'COMMENT';
|
||||||
<block>[\n]+ /* nothing */
|
<block>[\n]+ /* nothing */
|
||||||
<block>"}" { this.popState(); return 'BLOCK_STOP'; }
|
<block>"}" { this.popState(); return 'BLOCK_STOP'; }
|
||||||
|
@@ -85,6 +85,31 @@ describe('when parsing ER diagram it...', function () {
|
|||||||
expect(entities[entity].attributes.length).toBe(3);
|
expect(entities[entity].attributes.length).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should allow an entity with attribute that has a generic type', function () {
|
||||||
|
const entity = 'BOOK';
|
||||||
|
const attribute1 = 'type~T~ type';
|
||||||
|
const attribute2 = 'option~T~ readable "comment"';
|
||||||
|
const attribute3 = 'string id PK';
|
||||||
|
|
||||||
|
erDiagram.parser.parse(
|
||||||
|
`erDiagram\n${entity} {\n${attribute1}\n${attribute2}\n${attribute3}\n}`
|
||||||
|
);
|
||||||
|
const entities = erDb.getEntities();
|
||||||
|
expect(Object.keys(entities).length).toBe(1);
|
||||||
|
expect(entities[entity].attributes.length).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow an entity with attribute that is an array', function () {
|
||||||
|
const entity = 'BOOK';
|
||||||
|
const attribute1 = 'string[] readers FK "comment"';
|
||||||
|
const attribute2 = 'string[] authors FK';
|
||||||
|
|
||||||
|
erDiagram.parser.parse(`erDiagram\n${entity} {\n${attribute1}\n${attribute2}\n}`);
|
||||||
|
const entities = erDb.getEntities();
|
||||||
|
expect(Object.keys(entities).length).toBe(1);
|
||||||
|
expect(entities[entity].attributes.length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
it('should allow an entity with multiple attributes to be defined', function () {
|
it('should allow an entity with multiple attributes to be defined', function () {
|
||||||
const entity = 'BOOK';
|
const entity = 'BOOK';
|
||||||
const attribute1 = 'string title';
|
const attribute1 = 'string title';
|
||||||
|
Reference in New Issue
Block a user