Add support for changing the length of edges

Resolves #637, resolves #1495.

The syntax for edges is extended to allow for extra
dashes/equals signs/dots (depending on the edge type). Each added
character increases the length of the edge by one rank level, as
follows:

Length            |    1   |    2    |     3    |
------------------|:------:|:-------:|:--------:|
Normal            |  `---` |  `----` |  `-----` |
Normal with arrow |  `-->` |  `--->` |  `---->` |
Thick             |  `===` |  `====` |  `=====` |
Thick with arrow  |  `==>` |  `===>` |  `====>` |
Dotted            |  `-.-` |  `-..-` |  `-...-` |
Dotted with arrow | `-.->` | `-..->` | `-...->` |

This features leverages the `minlen` property exposed by Dagre which was
not previously available when using Mermaid.
This commit is contained in:
Mattéo Delabre
2020-08-07 01:20:44 +02:00
parent a97cc62d0a
commit 01344a991d
14 changed files with 870 additions and 898 deletions

View File

@@ -110,6 +110,7 @@ export const addSingleLink = function(_start, _end, type, linktext) {
if (typeof type !== 'undefined') {
edge.type = type.type;
edge.stroke = type.stroke;
edge.length = type.length;
}
edges.push(edge);
};
@@ -498,97 +499,92 @@ export const firstGraph = () => {
};
const destructStartLink = _str => {
const str = _str.trim();
let str = _str.trim();
let type = 'arrow_open';
switch (str) {
case '<--':
return { type: 'arrow_point', stroke: 'normal' };
case 'x--':
return { type: 'arrow_cross', stroke: 'normal' };
case 'o--':
return { type: 'arrow_circle', stroke: 'normal' };
case '<-.':
return { type: 'arrow_point', stroke: 'dotted' };
case 'x-.':
return { type: 'arrow_cross', stroke: 'dotted' };
case 'o-.':
return { type: 'arrow_circle', stroke: 'dotted' };
case '<==':
return { type: 'arrow_point', stroke: 'thick' };
case 'x==':
return { type: 'arrow_cross', stroke: 'thick' };
case 'o==':
return { type: 'arrow_circle', stroke: 'thick' };
case '--':
return { type: 'arrow_open', stroke: 'normal' };
case '==':
return { type: 'arrow_open', stroke: 'thick' };
case '-.':
return { type: 'arrow_open', stroke: 'dotted' };
switch (str[0]) {
case '<':
type = 'arrow_point';
str = str.slice(1);
break;
case 'x':
type = 'arrow_cross';
str = str.slice(1);
break;
case 'o':
type = 'arrow_circle';
str = str.slice(1);
break;
}
let stroke = 'normal';
if (str.indexOf('=') !== -1) {
stroke = 'thick';
}
if (str.indexOf('.') !== -1) {
stroke = 'dotted';
}
return { type, stroke };
};
const countChar = (char, str) => {
const length = str.length;
let count = 0;
for (let i = 0; i < length; ++i) {
if (str[i] === char) {
++count;
}
}
return count;
};
const destructEndLink = _str => {
const str = _str.trim();
let line = str.slice(0, -1);
let type = 'arrow_open';
switch (str) {
case '--x':
return { type: 'arrow_cross', stroke: 'normal' };
case '-->':
return { type: 'arrow_point', stroke: 'normal' };
case '<-->':
return { type: 'double_arrow_point', stroke: 'normal' };
case 'x--x':
return { type: 'double_arrow_cross', stroke: 'normal' };
case 'o--o':
return { type: 'double_arrow_circle', stroke: 'normal' };
case 'o.-o':
return { type: 'double_arrow_circle', stroke: 'dotted' };
case '<==>':
return { type: 'double_arrow_point', stroke: 'thick' };
case 'o==o':
return { type: 'double_arrow_circle', stroke: 'thick' };
case 'x==x':
return { type: 'double_arrow_cross', stroke: 'thick' };
case 'x.-x':
return { type: 'double_arrow_cross', stroke: 'dotted' };
case 'x-.-x':
return { type: 'double_arrow_cross', stroke: 'dotted' };
case '<.->':
return { type: 'double_arrow_point', stroke: 'dotted' };
case '<-.->':
return { type: 'double_arrow_point', stroke: 'dotted' };
case 'o-.-o':
return { type: 'double_arrow_circle', stroke: 'dotted' };
case '--o':
return { type: 'arrow_circle', stroke: 'normal' };
case '---':
return { type: 'arrow_open', stroke: 'normal' };
case '-.-x':
return { type: 'arrow_cross', stroke: 'dotted' };
case '-.->':
return { type: 'arrow_point', stroke: 'dotted' };
case '-.-o':
return { type: 'arrow_circle', stroke: 'dotted' };
case '-.-':
return { type: 'arrow_open', stroke: 'dotted' };
case '.-x':
return { type: 'arrow_cross', stroke: 'dotted' };
case '.->':
return { type: 'arrow_point', stroke: 'dotted' };
case '.-o':
return { type: 'arrow_circle', stroke: 'dotted' };
case '.-':
return { type: 'arrow_open', stroke: 'dotted' };
case '==x':
return { type: 'arrow_cross', stroke: 'thick' };
case '==>':
return { type: 'arrow_point', stroke: 'thick' };
case '==o':
return { type: 'arrow_circle', stroke: 'thick' };
case '===':
return { type: 'arrow_open', stroke: 'thick' };
switch (str.slice(-1)) {
case 'x':
type = 'arrow_cross';
if (str[0] === 'x') {
type = 'double_' + type;
line = line.slice(1);
}
break;
case '>':
type = 'arrow_point';
if (str[0] === '<') {
type = 'double_' + type;
line = line.slice(1);
}
break;
case 'o':
type = 'arrow_circle';
if (str[0] === 'o') {
type = 'double_' + type;
line = line.slice(1);
}
break;
}
let stroke = 'normal';
let length = line.length - 1;
if (line[0] === '=') {
stroke = 'thick';
}
let dots = countChar('.', line);
if (dots) {
stroke = 'dotted';
length = dots;
}
return { type, stroke, length };
};
const destructLink = (_str, _startStr) => {
@@ -602,7 +598,7 @@ const destructLink = (_str, _startStr) => {
}
if (startInfo.type === 'arrow_open') {
// -- xyz --> - take arrow type form ending
// -- xyz --> - take arrow type from ending
startInfo.type = info.type;
} else {
// x-- xyz --> - not supported
@@ -615,6 +611,7 @@ const destructLink = (_str, _startStr) => {
startInfo.type = 'double_arrow_point';
}
startInfo.length = info.length;
return startInfo;
}

View File

@@ -244,6 +244,7 @@ export const addEdges = function(edges, g) {
edgeData.id = linkId;
edgeData.class = linkNameStart + ' ' + linkNameEnd;
edgeData.minlen = edge.length || 1;
// Add the edge to the graph
g.setEdge(edge.start, edge.end, edgeData, cnt);

View File

@@ -25,6 +25,8 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it("should handle angle bracket ' > ' as direction LR", function() {
@@ -43,6 +45,8 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it("should handle angle bracket ' < ' as direction RL", function() {
@@ -61,6 +65,8 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it("should handle caret ' ^ ' as direction BT", function() {
@@ -77,8 +83,11 @@ describe('[Arrows] when parsing', () => {
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].length).toBe(1);
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it("should handle lower-case 'v' as direction TB", function() {
@@ -97,6 +106,8 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it('should handle a nodes and edges and a space between link and node', function() {
@@ -112,6 +123,8 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it('should handle a nodes and edges, a space between link and node and each line ending without semicolon', function() {
@@ -127,6 +140,8 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it('should handle statements ending without semicolon', function() {
@@ -142,9 +157,11 @@ describe('[Arrows] when parsing', () => {
expect(edges[1].end).toBe('C');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
describe('it should multi directional arrows', function() {
describe('it should handle multi directional arrows', function() {
describe('point', function() {
it('should handle double edged nodes and edges', function() {
const res = flow.parser.parse('graph TD;\nA<-->B;');
@@ -159,6 +176,8 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes with text', function() {
@@ -173,8 +192,9 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes and edges on thick arrows', function() {
@@ -189,8 +209,9 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes with text on thick arrows', function() {
@@ -205,8 +226,9 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes and edges on dotted arrows', function() {
@@ -221,8 +243,9 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes with text on dotted arrows', function() {
@@ -237,8 +260,9 @@ describe('[Arrows] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(1);
});
});
});

View File

@@ -53,6 +53,8 @@ describe('[Edges] when parsing', () => {
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_cross');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes with text', function() {
@@ -67,8 +69,9 @@ describe('[Edges] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_cross');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes and edges on thick arrows', function() {
@@ -83,11 +86,12 @@ describe('[Edges] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_cross');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes with text on thick arrows XYZ1', function() {
it('should handle double edged nodes with text on thick arrows', function() {
const res = flow.parser.parse('graph TD;\nA x== text ==x B;');
const vert = flow.parser.yy.getVertices();
@@ -99,8 +103,9 @@ describe('[Edges] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_cross');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes and edges on dotted arrows', function() {
@@ -115,8 +120,9 @@ describe('[Edges] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_cross');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes with text on dotted arrows', function() {
@@ -131,8 +137,9 @@ describe('[Edges] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_cross');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(1);
});
});
@@ -150,6 +157,8 @@ describe('[Edges] when parsing', () => {
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_circle');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes with text', function() {
@@ -164,8 +173,9 @@ describe('[Edges] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_circle');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes and edges on thick arrows', function() {
@@ -180,8 +190,9 @@ describe('[Edges] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_circle');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes with text on thick arrows', function() {
@@ -196,8 +207,9 @@ describe('[Edges] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_circle');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes and edges on dotted arrows', function() {
@@ -212,8 +224,9 @@ describe('[Edges] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_circle');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(1);
});
it('should handle double edged nodes with text on dotted arrows', function() {
@@ -228,8 +241,9 @@ describe('[Edges] when parsing', () => {
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_circle');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(1);
});
});
@@ -245,9 +259,359 @@ describe('[Edges] when parsing', () => {
expect(edges.length).toBe(2);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_open');
expect(edges[0].text).toBe('This is the 123 s text');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
expect(edges[1].start).toBe('A');
expect(edges[1].end).toBe('B');
expect(edges[1].type).toBe('arrow_open');
expect(edges[1].text).toBe('This is the second edge');
expect(edges[1].stroke).toBe('normal');
expect(edges[1].length).toBe(1);
});
describe('edge length', function() {
for (let length = 1; length <= 3; ++length) {
it(`should handle normal edges with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA -${'-'.repeat(length)}- B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_open');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle normal labelled edges with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA -- Label -${'-'.repeat(length)}- B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_open');
expect(edges[0].text).toBe('Label');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle normal edges with arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA -${'-'.repeat(length)}> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle normal labelled edges with arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA -- Label -${'-'.repeat(length)}> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('Label');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle normal edges with double arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA <-${'-'.repeat(length)}> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle normal labelled edges with double arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA <-- Label -${'-'.repeat(length)}> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].text).toBe('Label');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle thick edges with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA =${'='.repeat(length)}= B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_open');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle thick labelled edges with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA == Label =${'='.repeat(length)}= B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_open');
expect(edges[0].text).toBe('Label');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle thick edges with arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA =${'='.repeat(length)}> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle thick labelled edges with arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA == Label =${'='.repeat(length)}> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('Label');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle thick edges with double arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA <=${'='.repeat(length)}> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle thick labelled edges with double arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA <== Label =${'='.repeat(length)}> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].text).toBe('Label');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle dotted edges with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA -${'.'.repeat(length)}- B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_open');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle dotted labelled edges with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA -. Label ${'.'.repeat(length)}- B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_open');
expect(edges[0].text).toBe('Label');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle dotted edges with arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA -${'.'.repeat(length)}-> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle dotted labelled edges with arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA -. Label ${'.'.repeat(length)}-> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow_point');
expect(edges[0].text).toBe('Label');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle dotted edges with double arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA <-${'.'.repeat(length)}-> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(length);
});
}
for (let length = 1; length <= 3; ++length) {
it(`should handle dotted edges with double arrows with length ${length}`, function() {
const res = flow.parser.parse(`graph TD;\nA <-. Label ${'.'.repeat(length)}-> B;`);
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('double_arrow_point');
expect(edges[0].text).toBe('Label');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(length);
});
}
});
});

View File

@@ -61,46 +61,12 @@
";" return 'SEMI';
"," return 'COMMA';
"*" return 'MULT';
\s*\-\-[x]\s* return 'LINK';
\s*\-\-\>\s* return 'LINK';
\s*\<\-\-\>\s* return 'LINK';
\s*[x]\-\-[x]\s* return 'LINK';
\s*[o]\-\-[o]\s* return 'LINK';
\s*[o]\.\-[o]\s* return 'LINK';
\s*\<\=\=\>\s* return 'LINK';
\s*[o]\=\=[o]\s* return 'LINK';
\s*[x]\=\=[x]\s* return 'LINK';
\s*[x].\-[x]\s* return 'LINK';
\s*[x]\-\.\-[x]\s* return 'LINK';
\s*\<\.\-\>\s* return 'LINK';
\s*\<\-\.\-\>\s* return 'LINK';
\s*[o]\-\.\-[o]\s* return 'LINK';
\s*\-\-[o]\s* return 'LINK';
\s*\-\-\-\s* return 'LINK';
\s*\-\.\-[x]\s* return 'LINK';
\s*\-\.\-\>\s* return 'LINK';
\s*\-\.\-[o]\s* return 'LINK';
\s*\-\.\-\s* return 'LINK';
\s*.\-[x]\s* return 'LINK';
\s*\.\-\>\s* return 'LINK';
\s*\.\-[o]\s* return 'LINK';
\s*\.\-\s* return 'LINK';
\s*\=\=[x]\s* return 'LINK';
\s*\=\=\>\s* return 'LINK';
\s*\=\=[o]\s* return 'LINK';
\s*\=\=[\=]\s* return 'LINK';
\s*\<\-\-\s* return 'START_LINK';
\s*[x]\-\-\s* return 'START_LINK';
\s*[o]\-\-\s* return 'START_LINK';
\s*\<\-\.\s* return 'START_LINK';
\s*[x]\-\.\s* return 'START_LINK';
\s*[o]\-\.\s* return 'START_LINK';
\s*\<\=\=\s* return 'START_LINK';
\s*[x]\=\=\s* return 'START_LINK';
\s*[o]\=\=\s* return 'START_LINK';
\s*\-\-\s* return 'START_LINK';
\s*\-\.\s* return 'START_LINK';
\s*\=\=\s* return 'START_LINK';
\s*[xo<]?\-\-+[-xo>]\s* return 'LINK';
\s*[xo<]?\=\=+[=xo>]\s* return 'LINK';
\s*[xo<]?\-?\.+\-[xo>]?\s* return 'LINK';
\s*[xo<]?\-\-\s* return 'START_LINK';
\s*[xo<]?\=\=\s* return 'START_LINK';
\s*[xo<]?\-\.\s* return 'START_LINK';
"(-" return '(-';
"-)" return '-)';
"([" return 'STADIUMSTART';
@@ -401,11 +367,11 @@ link: linkStatement arrowText
| linkStatement
{$$ = $1;}
| START_LINK text LINK
{var inf = yy.destructLink($3, $1); $$ = {"type":inf.type,"stroke":inf.stroke,"text":$2};}
{var inf = yy.destructLink($3, $1); $$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length,"text":$2};}
;
linkStatement: LINK
{var inf = yy.destructLink($1);$$ = {"type":inf.type,"stroke":inf.stroke};}
{var inf = yy.destructLink($1);$$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length};}
;
arrowText: