Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug/4645 graph node containing keyword #4657

Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
b46c284
Add text state and tests
ibrahimWassouf Jul 20, 2023
3496f27
Re-implement markdown as its own text type
ibrahimWassouf Jul 20, 2023
5b987de
Put parser in stable state
ibrahimWassouf Jul 20, 2023
7adb1bc
Replace alphanum with NODE_STRING for most usecases
ibrahimWassouf Jul 21, 2023
69c91ae
Add unit test for edge case with lean_right/left vertices
ibrahimWassouf Jul 21, 2023
0d7cc74
Replace alphanum with idString where appropriate
ibrahimWassouf Jul 21, 2023
0a4e5f5
Slightly alter unit test node idString
ibrahimWassouf Jul 21, 2023
3fa3ed7
Remove grammar and unit test that expects HEX token
ibrahimWassouf Jul 21, 2023
8ff06e8
Correct expected error message in unit test
ibrahimWassouf Jul 21, 2023
0cc8f89
Add edgeText states
ibrahimWassouf Jul 21, 2023
20011c6
Add unit tests for edge text
ibrahimWassouf Jul 21, 2023
eea0ea5
Add unit tests for node id strings with keywords
ibrahimWassouf Jul 22, 2023
f48a9c8
Merge branch 'develop' into bug/4645_graph_node_containing_keyword
ibrahimWassouf Jul 22, 2023
3ab0e99
Remove href state and give call higher precedence
ibrahimWassouf Jul 22, 2023
fd88b42
Add unit test for vertex and edge having both strings and text
ibrahimWassouf Jul 22, 2023
4b9773a
Refactor token precedence that concern vertex text states
ibrahimWassouf Jul 24, 2023
fa8e027
Refactor directive grammar to use name instead of position in production
ibrahimWassouf Jul 24, 2023
087738d
Refactor statement grammars to use name values instead of positions i…
ibrahimWassouf Jul 24, 2023
474e0b9
Refactor vertex grammars to use name values instead of position in pr…
ibrahimWassouf Jul 24, 2023
45d9276
Change rest of grammar statements to use variable name instead of pos…
ibrahimWassouf Jul 25, 2023
4cfbd0d
Remove unused definitions
ibrahimWassouf Jul 25, 2023
651274b
Only allow quotes to wrap entire string
ibrahimWassouf Jul 25, 2023
47c1008
Add unit tests for all cases of TEXT and STR combinations
ibrahimWassouf Jul 25, 2023
20cd685
Allow escaped quotations in strings
ibrahimWassouf Jul 25, 2023
30a9b55
Correct classDef and class grammar
ibrahimWassouf Jul 25, 2023
fd461b7
Reimplement old alphaNumToken
ibrahimWassouf Jul 25, 2023
9655ba9
Merge branch 'develop' into bug/4645_graph_node_containing_keyword
ibrahimWassouf Jul 25, 2023
1dfb400
Merge branch 'develop' into bug/4645_graph_node_containing_keyword
ibrahimWassouf Jul 26, 2023
1df68f9
Remove class statement to show application of default class
ibrahimWassouf Jul 27, 2023
9eed2e2
Add imgSnapshotTest for escaped quotes
ibrahimWassouf Jul 27, 2023
d889742
Correct edge strings to have same configuration as vertex strings
ibrahimWassouf Jul 27, 2023
e25763d
Modified docs to mention escaping quotes with backslash
ibrahimWassouf Jul 29, 2023
f269f8c
Refactor unit tests for vertex shape
ibrahimWassouf Jul 30, 2023
bed05ce
Disallow any vertex shape start or end token in any text state
ibrahimWassouf Jul 30, 2023
844f9d9
Update and add new imgSnapshotTest
ibrahimWassouf Jul 30, 2023
ed4feae
Remove required space from TAGEND token regex
ibrahimWassouf Jul 30, 2023
b545681
Show escaped quotes in docs using old and new method
ibrahimWassouf Jul 30, 2023
834c67e
Remove escaped quotes with backslash feature
ibrahimWassouf Aug 1, 2023
ef4f228
Add unit tests for stange node names
ibrahimWassouf Aug 1, 2023
e3c5e6f
Modify HREF token regex to contain space
ibrahimWassouf Aug 1, 2023
7dc9857
Merge branch 'develop' into bug/4645_graph_node_containing_keyword
ibrahimWassouf Aug 1, 2023
daf43f8
Merge branch 'develop' into bug/4645_graph_node_containing_keyword
ibrahimWassouf Aug 1, 2023
dc57fcf
Remove replaceAll method in addLink
ibrahimWassouf Aug 1, 2023
199fdce
Add unit tests for node ids with special Chars
ibrahimWassouf Aug 3, 2023
971215e
Correct idStringToken definition to include all individual special to…
ibrahimWassouf Aug 3, 2023
ee6fa94
Refactor unit tests and remove repetition
ibrahimWassouf Aug 3, 2023
5a165e4
Revert to old docs concerning quotations marks in string
ibrahimWassouf Aug 3, 2023
aaf3336
Add underscore to unit test on special Chars
ibrahimWassouf Aug 3, 2023
850513f
Return Unicode Text to idStringToken definition
ibrahimWassouf Aug 3, 2023
c9db0ee
Add specialChars in textNoTagsToken, alphaNumToken
ibrahimWassouf Aug 4, 2023
34bf618
Merge branch 'develop' into bug/4645_graph_node_containing_keyword
ibrahimWassouf Aug 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions cypress/integration/rendering/flowchart.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -891,4 +891,20 @@ 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:#000,stroke:#000,stroke-width:4px,color:#fff
default --> default2
`,
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
);
});
it('67: allow escaping quotes with backslash', () => {
imgSnapshotTest(`
graph TD
a_node("This has an escaped \\" in it") -- "edge string can escape too \\"" --> b_node
`);
});
});
5 changes: 3 additions & 2 deletions docs/syntax/flowchart.md
Original file line number Diff line number Diff line change
Expand Up @@ -605,15 +605,16 @@ flowchart LR
### Entity codes to escape characters

It is possible to escape characters using the syntax exemplified here.
For quotation marks, you can escape them with a backslash.

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

```mermaid
flowchart LR
A["A double quote:#quot;"] -->B["A dec char:#9829;"]
A["A double quote:\""] -->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 'COLON', 'PIPE', 'TESTSTR', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'NODE_STRING', 'MINUS', got 'EOF'"
`);
await expect(getDiagramFromText('sequenceDiagram; A-->B')).rejects
.toThrowErrorMatchingInlineSnapshot(`
Expand Down
2 changes: 2 additions & 0 deletions packages/mermaid/src/diagrams/flowchart/flowDb.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export const addVertex = function (_id, textObj, type, style, classes, dir, prop
if (textObj !== undefined) {
config = configApi.getConfig();
txt = sanitizeText(textObj.text.trim());
txt = textObj.type === 'string' ? txt.replaceAll('\\"', '"') : txt;
vertices[id].labelType = textObj.type;
// strip quotes if string starts and ends with a quote
if (txt[0] === '"' && txt[txt.length - 1] === '"') {
Expand Down Expand Up @@ -149,6 +150,7 @@ export const addSingleLink = function (_start, _end, type) {
if (linkTextObj !== undefined) {
edge.text = sanitizeText(linkTextObj.text.trim());

edge.text = edge.text.replaceAll('\\"', '"');
nirname marked this conversation as resolved.
Show resolved Hide resolved
// strip quotes if string starts and ends with a quote
if (edge.text[0] === '"' && edge.text[edge.text.length - 1] === '"') {
edge.text = edge.text.substring(1, edge.text.length - 1);
Expand Down
127 changes: 127 additions & 0 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,28 @@ 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',
];

describe('[Edges] when parsing', () => {
beforeEach(function () {
flow.parser.yy = flowDb;
Expand Down Expand Up @@ -74,6 +96,23 @@ describe('[Edges] when parsing', () => {
expect(edges[0].length).toBe(1);
});

it.each(keywords)('should handle %s as text in double edged nodes', function (keyword) {
const res = flow.parser.parse(`graph TD;\nA x-- ${keyword} --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(`${keyword}`);
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;');

Expand Down Expand Up @@ -108,6 +147,23 @@ describe('[Edges] when parsing', () => {
expect(edges[0].length).toBe(1);
});

it.each(keywords)('should handle %s as text in thick double edged nodes', function (keyword) {
const res = flow.parser.parse(`graph TD;\nA x== ${keyword} ==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(`${keyword}`);
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;');

Expand Down Expand Up @@ -143,6 +199,23 @@ describe('[Edges] when parsing', () => {
});
});

it.each(keywords)('should handle %s as text in dotted double edged nodes', function (keyword) {
const res = flow.parser.parse(`graph TD;\nA x-. ${keyword} .-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(`${keyword}`);
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;');
Expand Down Expand Up @@ -178,6 +251,23 @@ describe('[Edges] when parsing', () => {
expect(edges[0].length).toBe(1);
});

it.each(keywords)('should handle double edged nodes with %s as text', function (keyword) {
const res = flow.parser.parse(`graph TD;\nA o-- ${keyword} --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(`${keyword}`);
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 o==o B;');

Expand Down Expand Up @@ -212,6 +302,23 @@ describe('[Edges] when parsing', () => {
expect(edges[0].length).toBe(1);
});

it.each(keywords)('should handle thick double edged nodes with %s as text', function (keyword) {
const res = flow.parser.parse(`graph TD;\nA o== ${keyword} ==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(`${keyword}`);
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 o-.-o B;');

Expand Down Expand Up @@ -245,6 +352,26 @@ describe('[Edges] when parsing', () => {
expect(edges[0].stroke).toBe('dotted');
expect(edges[0].length).toBe(1);
});

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

it('should handle multiple edges', function () {
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ setConfig({
securityLevel: 'strict',
});

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

describe('[Singlenodes] when parsing', () => {
beforeEach(function () {
flow.parser.yy = flowDb;
Expand Down Expand Up @@ -259,4 +280,30 @@ describe('[Singlenodes] when parsing', () => {
expect(edges.length).toBe(0);
expect(vert['i_d'].styles.length).toBe(0);
});

it.each(keywords)('should handle keywords between dashes "-"', function (keyword) {
const res = flow.parser.parse(`graph TD;a-${keyword}-node;`);
const vert = flow.parser.yy.getVertices();
expect(vert[`a-${keyword}-node`].text).toBe(`a-${keyword}-node`);
});

it.each(keywords)('should handle keywords between periods "."', function (keyword) {
const res = flow.parser.parse(`graph TD;a.${keyword}.node;`);
const vert = flow.parser.yy.getVertices();
expect(vert[`a.${keyword}.node`].text).toBe(`a.${keyword}.node`);
});

it.each(keywords)('should handle keywords between underscores "_"', function (keyword) {
const res = flow.parser.parse(`graph TD;a_${keyword}_node;`);
const vert = flow.parser.yy.getVertices();
expect(vert[`a_${keyword}_node`].text).toBe(`a_${keyword}_node`);
});

it.each(keywords)('should handle nodes ending in keywords', function (keyword) {
const res = flow.parser.parse(`graph TD;node_${keyword};node.${keyword};node-${keyword};`);
const vert = flow.parser.yy.getVertices();
expect(vert[`node_${keyword}`].text).toBe(`node_${keyword}`);
expect(vert[`node.${keyword}`].text).toBe(`node.${keyword}`);
expect(vert[`node-${keyword}`].text).toBe(`node-${keyword}`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,6 @@ describe('[Style] when parsing', () => {
expect(vert['Q'].styles[0]).toBe('background:#fff');
});

// log.debug(flow.parser.parse('graph TD;style Q background:#fff;'));
it('should handle styles for edges', function () {
const res = flow.parser.parse('graph TD;a-->b;\nstyle #0 stroke: #f66;');

const edges = flow.parser.yy.getEdges();

expect(edges.length).toBe(1);
});

it('should handle multiple styles for a vortex', function () {
const res = flow.parser.parse('graph TD;style R background:#fff,border:1px solid red;');

Expand Down
Loading
Loading