Skip to content

Commit

Permalink
Merge pull request #4657 from ibrahimWassouf/bug/4645_graph_node_cont…
Browse files Browse the repository at this point in the history
…aining_keyword

Bug/4645 graph node containing keyword
  • Loading branch information
nirname authored Aug 5, 2023
2 parents f8ebfee + 34bf618 commit e1379ee
Show file tree
Hide file tree
Showing 10 changed files with 605 additions and 447 deletions.
23 changes: 23 additions & 0 deletions cypress/integration/rendering/flowchart.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -891,4 +891,27 @@ graph TD
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
);
});
it('66: apply class called default on node called default', () => {
imgSnapshotTest(
`
graph TD
classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff
hello --> default
`,
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
);
});

it('67: should be able to style default node independently', () => {
imgSnapshotTest(
`
flowchart TD
classDef default fill:#a34
hello --> default
style default stroke:#000,stroke-width:4px
`,
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
);
});
});
4 changes: 2 additions & 2 deletions docs/syntax/flowchart.md
Original file line number Diff line number Diff line change
Expand Up @@ -608,12 +608,12 @@ It is possible to escape characters using the syntax exemplified here.

```mermaid-example
flowchart LR
A["A double quote:#quot;"] -->B["A dec char:#9829;"]
A["A double quote:#quot;"] --> B["A dec char:#9829;"]
```

```mermaid
flowchart LR
A["A double quote:#quot;"] -->B["A dec char:#9829;"]
A["A double quote:#quot;"] --> B["A dec char:#9829;"]
```

Numbers given are base 10, so `#` can be encoded as `#35;`. It is also supported to use HTML character names.
Expand Down
2 changes: 1 addition & 1 deletion packages/mermaid/src/diagram.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe('diagram detection', () => {
"Parse error on line 2:
graph TD; A-->
--------------^
Expecting 'AMP', 'ALPHA', 'COLON', 'PIPE', 'TESTSTR', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'MINUS', 'BRKT', 'DOT', 'PUNCTUATION', 'UNICODE_TEXT', 'PLUS', 'EQUALS', 'MULT', 'UNDERSCORE', got 'EOF'"
Expecting 'AMP', 'COLON', 'PIPE', 'TESTSTR', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'NODE_STRING', 'BRKT', 'MINUS', 'MULT', 'UNICODE_TEXT', got 'EOF'"
`);
await expect(getDiagramFromText('sequenceDiagram; A-->B')).rejects
.toThrowErrorMatchingInlineSnapshot(`
Expand Down
283 changes: 84 additions & 199 deletions packages/mermaid/src/diagrams/flowchart/parser/flow-edges.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,40 @@ setConfig({
securityLevel: 'strict',
});

const keywords = [
'graph',
'flowchart',
'flowchart-elk',
'style',
'default',
'linkStyle',
'interpolate',
'classDef',
'class',
'href',
'call',
'click',
'_self',
'_blank',
'_parent',
'_top',
'end',
'subgraph',
'kitty',
];

const doubleEndedEdges = [
{ edgeStart: 'x--', edgeEnd: '--x', stroke: 'normal', type: 'double_arrow_cross' },
{ edgeStart: 'x==', edgeEnd: '==x', stroke: 'thick', type: 'double_arrow_cross' },
{ edgeStart: 'x-.', edgeEnd: '.-x', stroke: 'dotted', type: 'double_arrow_cross' },
{ edgeStart: 'o--', edgeEnd: '--o', stroke: 'normal', type: 'double_arrow_circle' },
{ edgeStart: 'o==', edgeEnd: '==o', stroke: 'thick', type: 'double_arrow_circle' },
{ edgeStart: 'o-.', edgeEnd: '.-o', stroke: 'dotted', type: 'double_arrow_circle' },
{ edgeStart: '<--', edgeEnd: '-->', stroke: 'normal', type: 'double_arrow_point' },
{ edgeStart: '<==', edgeEnd: '==>', stroke: 'thick', type: 'double_arrow_point' },
{ edgeStart: '<-.', edgeEnd: '.->', stroke: 'dotted', type: 'double_arrow_point' },
];

describe('[Edges] when parsing', () => {
beforeEach(function () {
flow.parser.yy = flowDb;
Expand Down Expand Up @@ -39,211 +73,62 @@ describe('[Edges] when parsing', () => {
expect(edges[0].type).toBe('arrow_circle');
});

describe('cross', function () {
it('should handle double edged nodes and edges', function () {
const res = flow.parser.parse('graph TD;\nA x--x 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_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 () {
const res = flow.parser.parse('graph TD;\nA x-- text --x 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_cross');
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 () {
const res = flow.parser.parse('graph TD;\nA x==x 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_cross');
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 () {
const res = flow.parser.parse('graph TD;\nA x== text ==x 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_cross');
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 () {
const res = flow.parser.parse('graph TD;\nA x-.-x 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_cross');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(1);
});
describe('edges', function () {
doubleEndedEdges.forEach((edgeType) => {
it(`should handle ${edgeType.stroke} ${edgeType.type} with no text`, function () {
const res = flow.parser.parse(`graph TD;\nA ${edgeType.edgeStart}${edgeType.edgeEnd} B;`);

it('should handle double edged nodes with text on dotted arrows', function () {
const res = flow.parser.parse('graph TD;\nA x-. text .-x 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_cross');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(1);
});
});

describe('circle', function () {
it('should handle double edged nodes and edges', function () {
const res = flow.parser.parse('graph TD;\nA o--o 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_circle');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();

it('should handle double edged nodes with text', function () {
const res = flow.parser.parse('graph TD;\nA o-- text --o 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_circle');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('normal');
expect(edges[0].length).toBe(1);
});
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(`${edgeType.type}`);
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
});

it('should handle double edged nodes and edges on thick arrows', function () {
const res = flow.parser.parse('graph TD;\nA o==o 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_circle');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(1);
});
it(`should handle ${edgeType.stroke} ${edgeType.type} with text`, function () {
const res = flow.parser.parse(
`graph TD;\nA ${edgeType.edgeStart} text ${edgeType.edgeEnd} B;`
);

it('should handle double edged nodes with text on thick arrows', function () {
const res = flow.parser.parse('graph TD;\nA o== text ==o 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_circle');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('thick');
expect(edges[0].length).toBe(1);
});
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();

it('should handle double edged nodes and edges on dotted arrows', function () {
const res = flow.parser.parse('graph TD;\nA o-.-o 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_circle');
expect(edges[0].text).toBe('');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(1);
});
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(`${edgeType.type}`);
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
});

it('should handle double edged nodes with text on dotted arrows', function () {
const res = flow.parser.parse('graph TD;\nA o-. text .-o 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_circle');
expect(edges[0].text).toBe('text');
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(1);
it.each(keywords)(
`should handle ${edgeType.stroke} ${edgeType.type} with %s text`,
function (keyword) {
const res = flow.parser.parse(
`graph TD;\nA ${edgeType.edgeStart} ${keyword} ${edgeType.edgeEnd} 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(`${edgeType.type}`);
expect(edges[0].text).toBe(`${keyword}`);
expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
}
);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ A["\`The cat in **the** hat\`"]-- "\`The *bat* in the chat\`" -->B["The dog in t
expect(vert['A'].labelType).toBe('markdown');
expect(vert['B'].id).toBe('B');
expect(vert['B'].text).toBe('The dog in the hog');
expect(vert['B'].labelType).toBe('text');
expect(vert['B'].labelType).toBe('string');
expect(edges.length).toBe(2);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
Expand All @@ -35,7 +35,7 @@ A["\`The cat in **the** hat\`"]-- "\`The *bat* in the chat\`" -->B["The dog in t
expect(edges[1].end).toBe('C');
expect(edges[1].type).toBe('arrow_point');
expect(edges[1].text).toBe('The rat in the mat');
expect(edges[1].labelType).toBe('text');
expect(edges[1].labelType).toBe('string');
});
it('mardown formatting in subgraphs', function () {
const res = flow.parser.parse(`flowchart LR
Expand Down
Loading

0 comments on commit e1379ee

Please sign in to comment.