Merge branch 'develop' into sidv/memoize

* develop: (22 commits)
  fix: Tsconfig
  ci: lint .jison files for any console.log()
  refactor: remove `console.log` in c4Diagram.jison
  style: forbid using `console` in mermaid src code
  Add tests for other boundary properties
  Add first test for Boundary
  Test all different types of systems
  Introduce shape list in test
  Add tests for C4 System
  Make test grouping more explicit
  Copy tests from Person to PersonExt
  Add test for link to Person_Ext
  Add question on Person_Ext
  Add test for structure of Person_Ext
  Add test for alias
  Add test for label
  Add test for description
  Add test for $tags
  Add test for $link
  Add test for $sprite
  ...
This commit is contained in:
Sidharth Vinod 2022-09-09 16:02:37 +05:30
commit 1c6328cc1b
No known key found for this signature in database
GPG Key ID: FB5CCD378D3907CD
12 changed files with 600 additions and 154 deletions

View File

@ -22,6 +22,7 @@
],
"plugins": ["@typescript-eslint", "html", "jest", "jsdoc", "json"],
"rules": {
"no-console": "error",
"no-prototype-builtins": "off",
"no-unused-vars": "off",
"jsdoc/check-indentation": "off",
@ -45,6 +46,12 @@
"no-undef": "off",
"jsdoc/require-jsdoc": "off"
}
},
{
"files": ["./cypress/**", "./demos/**"],
"rules": {
"no-console": "off"
}
}
]
}

View File

@ -40,3 +40,18 @@ jobs:
- name: Verify Docs
run: yarn docs:verify
- name: Check no `console.log()` in .jison files
# ESLint can't parse .jison files directly
# In the future, it might be worth making a `eslint-plugin-jison`, so
# that this will be built into the `yarn lint` command.
run: |
shopt -s globstar
mkdir -p tmp/
for jison_file in src/**/*.jison; do
outfile="tmp/$(basename -- "$jison_file" .jison)-jison.js"
echo "Converting $jison_file to $outfile"
# default module-type (CJS) always adds a console.log()
yarn jison "$jison_file" --outfile "$outfile" --module-type "amd"
done
yarn eslint --no-eslintrc --rule no-console:error --parser "@babel/eslint-parser" "./tmp/*-jison.js"

View File

@ -0,0 +1,110 @@
import c4Db from '../c4Db';
import c4 from './c4Diagram.jison';
import { setConfig } from '../../../config';
setConfig({
securityLevel: 'strict',
});
describe.each(['Boundary'])('parsing a C4 %s', function (macroName) {
beforeEach(function () {
c4.parser.yy = c4Db;
c4.parser.yy.clear();
});
it('should parse a C4 diagram with one Boundary correctly', function () {
c4.parser.parse(`C4Context
title System Context diagram for Internet Banking System
${macroName}(b1, "BankBoundary") {
System(SystemAA, "Internet Banking System")
}`);
const yy = c4.parser.yy;
const boundaries = yy.getBoundarys();
expect(boundaries.length).toBe(2);
const boundary = boundaries[1];
expect(boundary).toEqual({
alias: 'b1',
label: {
text: 'BankBoundary',
},
// TODO: Why are link, and tags undefined instead of not appearing at all?
// Compare to Person where they don't show up.
link: undefined,
tags: undefined,
parentBoundary: 'global',
type: {
// TODO: Why is this `system` instead of `boundary`?
text: 'system',
},
wrap: false,
});
});
it('should parse the alias', function () {
c4.parser.parse(`C4Context
${macroName}(b1, "BankBoundary") {
System(SystemAA, "Internet Banking System")
}`);
expect(c4.parser.yy.getBoundarys()[1]).toMatchObject({
alias: 'b1',
});
});
it('should parse the label', function () {
c4.parser.parse(`C4Context
${macroName}(b1, "BankBoundary") {
System(SystemAA, "Internet Banking System")
}`);
expect(c4.parser.yy.getBoundarys()[1]).toMatchObject({
label: {
text: 'BankBoundary',
},
});
});
it('should parse the type', function () {
c4.parser.parse(`C4Context
${macroName}(b1, "", "company") {
System(SystemAA, "Internet Banking System")
}`);
expect(c4.parser.yy.getBoundarys()[1]).toMatchObject({
type: { text: 'company' },
});
});
it('should parse a link', function () {
c4.parser.parse(`C4Context
${macroName}(b1, $link="https://github.com/mermaidjs") {
System(SystemAA, "Internet Banking System")
}`);
expect(c4.parser.yy.getBoundarys()[1]).toMatchObject({
label: {
text: {
link: 'https://github.com/mermaidjs',
},
},
});
});
it('should parse tags', function () {
c4.parser.parse(`C4Context
${macroName}(b1, $tags="tag1,tag2") {
System(SystemAA, "Internet Banking System")
}`);
expect(c4.parser.yy.getBoundarys()[1]).toMatchObject({
label: {
text: {
tags: 'tag1,tag2',
},
},
});
});
});

View File

@ -115,80 +115,80 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
"C4Dynamic" return 'C4_DYNAMIC';
"C4Deployment" return 'C4_DEPLOYMENT';
"Person_Ext" { this.begin("person_ext"); console.log('begin person_ext'); return 'PERSON_EXT';}
"Person" { this.begin("person"); console.log('begin person'); return 'PERSON';}
"SystemQueue_Ext" { this.begin("system_ext_queue"); console.log('begin system_ext_queue'); return 'SYSTEM_EXT_QUEUE';}
"SystemDb_Ext" { this.begin("system_ext_db"); console.log('begin system_ext_db'); return 'SYSTEM_EXT_DB';}
"System_Ext" { this.begin("system_ext"); console.log('begin system_ext'); return 'SYSTEM_EXT';}
"SystemQueue" { this.begin("system_queue"); console.log('begin system_queue'); return 'SYSTEM_QUEUE';}
"SystemDb" { this.begin("system_db"); console.log('begin system_db'); return 'SYSTEM_DB';}
"System" { this.begin("system"); console.log('begin system'); return 'SYSTEM';}
"Person_Ext" { this.begin("person_ext"); return 'PERSON_EXT';}
"Person" { this.begin("person"); return 'PERSON';}
"SystemQueue_Ext" { this.begin("system_ext_queue"); return 'SYSTEM_EXT_QUEUE';}
"SystemDb_Ext" { this.begin("system_ext_db"); return 'SYSTEM_EXT_DB';}
"System_Ext" { this.begin("system_ext"); return 'SYSTEM_EXT';}
"SystemQueue" { this.begin("system_queue"); return 'SYSTEM_QUEUE';}
"SystemDb" { this.begin("system_db"); return 'SYSTEM_DB';}
"System" { this.begin("system"); return 'SYSTEM';}
"Boundary" { this.begin("boundary"); console.log('begin boundary'); return 'BOUNDARY';}
"Enterprise_Boundary" { this.begin("enterprise_boundary"); console.log('begin enterprise_boundary'); return 'ENTERPRISE_BOUNDARY';}
"System_Boundary" { this.begin("system_boundary"); console.log('begin system_boundary'); return 'SYSTEM_BOUNDARY';}
"Boundary" { this.begin("boundary"); return 'BOUNDARY';}
"Enterprise_Boundary" { this.begin("enterprise_boundary"); return 'ENTERPRISE_BOUNDARY';}
"System_Boundary" { this.begin("system_boundary"); return 'SYSTEM_BOUNDARY';}
"ContainerQueue_Ext" { this.begin("container_ext_queue"); console.log('begin container_ext_queue'); return 'CONTAINER_EXT_QUEUE';}
"ContainerDb_Ext" { this.begin("container_ext_db"); console.log('begin container_ext_db'); return 'CONTAINER_EXT_DB';}
"Container_Ext" { this.begin("container_ext"); console.log('begin container_ext'); return 'CONTAINER_EXT';}
"ContainerQueue" { this.begin("container_queue"); console.log('begin container_queue'); return 'CONTAINER_QUEUE';}
"ContainerDb" { this.begin("container_db"); console.log('begin container_db'); return 'CONTAINER_DB';}
"Container" { this.begin("container"); console.log('begin container'); return 'CONTAINER';}
"ContainerQueue_Ext" { this.begin("container_ext_queue"); return 'CONTAINER_EXT_QUEUE';}
"ContainerDb_Ext" { this.begin("container_ext_db"); return 'CONTAINER_EXT_DB';}
"Container_Ext" { this.begin("container_ext"); return 'CONTAINER_EXT';}
"ContainerQueue" { this.begin("container_queue"); return 'CONTAINER_QUEUE';}
"ContainerDb" { this.begin("container_db"); return 'CONTAINER_DB';}
"Container" { this.begin("container"); return 'CONTAINER';}
"Container_Boundary" { this.begin("container_boundary"); console.log('begin container_boundary'); return 'CONTAINER_BOUNDARY';}
"Container_Boundary" { this.begin("container_boundary"); return 'CONTAINER_BOUNDARY';}
"ComponentQueue_Ext" { this.begin("component_ext_queue"); console.log('begin component_ext_queue'); return 'COMPONENT_EXT_QUEUE';}
"ComponentDb_Ext" { this.begin("component_ext_db"); console.log('begin component_ext_db'); return 'COMPONENT_EXT_DB';}
"Component_Ext" { this.begin("component_ext"); console.log('begin component_ext'); return 'COMPONENT_EXT';}
"ComponentQueue" { this.begin("component_queue"); console.log('begin component_queue'); return 'COMPONENT_QUEUE';}
"ComponentDb" { this.begin("component_db"); console.log('begin component_db'); return 'COMPONENT_DB';}
"Component" { this.begin("component"); console.log('begin component'); return 'COMPONENT';}
"ComponentQueue_Ext" { this.begin("component_ext_queue"); return 'COMPONENT_EXT_QUEUE';}
"ComponentDb_Ext" { this.begin("component_ext_db"); return 'COMPONENT_EXT_DB';}
"Component_Ext" { this.begin("component_ext"); return 'COMPONENT_EXT';}
"ComponentQueue" { this.begin("component_queue"); return 'COMPONENT_QUEUE';}
"ComponentDb" { this.begin("component_db"); return 'COMPONENT_DB';}
"Component" { this.begin("component"); return 'COMPONENT';}
"Deployment_Node" { this.begin("node"); console.log('begin node'); return 'NODE';}
"Node" { this.begin("node"); console.log('begin node'); return 'NODE';}
"Node_L" { this.begin("node_l"); console.log('begin node_l'); return 'NODE_L';}
"Node_R" { this.begin("node_r"); console.log('begin node_r'); return 'NODE_R';}
"Deployment_Node" { this.begin("node"); return 'NODE';}
"Node" { this.begin("node"); return 'NODE';}
"Node_L" { this.begin("node_l"); return 'NODE_L';}
"Node_R" { this.begin("node_r"); return 'NODE_R';}
"Rel" { this.begin("rel"); console.log('begin rel'); return 'REL';}
"BiRel" { this.begin("birel"); console.log('begin birel'); return 'BIREL';}
"Rel_Up" { this.begin("rel_u"); console.log('begin rel_u'); return 'REL_U';}
"Rel_U" { this.begin("rel_u"); console.log('begin rel_u'); return 'REL_U';}
"Rel_Down" { this.begin("rel_d"); console.log('begin rel_d'); return 'REL_D';}
"Rel_D" { this.begin("rel_d"); console.log('begin rel_d'); return 'REL_D';}
"Rel_Left" { this.begin("rel_l"); console.log('begin rel_l'); return 'REL_L';}
"Rel_L" { this.begin("rel_l"); console.log('begin rel_l'); return 'REL_L';}
"Rel_Right" { this.begin("rel_r"); console.log('begin rel_r'); return 'REL_R';}
"Rel_R" { this.begin("rel_r"); console.log('begin rel_r'); return 'REL_R';}
"Rel_Back" { this.begin("rel_b"); console.log('begin rel_b'); return 'REL_B';}
"RelIndex" { this.begin("rel_index"); console.log('begin rel_index'); return 'REL_INDEX';}
"Rel" { this.begin("rel"); return 'REL';}
"BiRel" { this.begin("birel"); return 'BIREL';}
"Rel_Up" { this.begin("rel_u"); return 'REL_U';}
"Rel_U" { this.begin("rel_u"); return 'REL_U';}
"Rel_Down" { this.begin("rel_d"); return 'REL_D';}
"Rel_D" { this.begin("rel_d"); return 'REL_D';}
"Rel_Left" { this.begin("rel_l"); return 'REL_L';}
"Rel_L" { this.begin("rel_l"); return 'REL_L';}
"Rel_Right" { this.begin("rel_r"); return 'REL_R';}
"Rel_R" { this.begin("rel_r"); return 'REL_R';}
"Rel_Back" { this.begin("rel_b"); return 'REL_B';}
"RelIndex" { this.begin("rel_index"); return 'REL_INDEX';}
"UpdateElementStyle" { this.begin("update_el_style"); console.log('begin update_el_style'); return 'UPDATE_EL_STYLE';}
"UpdateRelStyle" { this.begin("update_rel_style"); console.log('begin update_rel_style'); return 'UPDATE_REL_STYLE';}
"UpdateLayoutConfig" { this.begin("update_layout_config"); console.log('begin update_layout_config'); return 'UPDATE_LAYOUT_CONFIG';}
"UpdateElementStyle" { this.begin("update_el_style"); return 'UPDATE_EL_STYLE';}
"UpdateRelStyle" { this.begin("update_rel_style"); return 'UPDATE_REL_STYLE';}
"UpdateLayoutConfig" { this.begin("update_layout_config"); return 'UPDATE_LAYOUT_CONFIG';}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,update_el_style,update_rel_style,update_layout_config><<EOF>> return "EOF_IN_STRUCT";
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,update_el_style,update_rel_style,update_layout_config>[(][ ]*[,] { console.log('begin attribute with ATTRIBUTE_EMPTY'); this.begin("attribute"); return "ATTRIBUTE_EMPTY";}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,update_el_style,update_rel_style,update_layout_config>[(] { console.log('begin attribute'); this.begin("attribute"); }
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,update_el_style,update_rel_style,update_layout_config,attribute>[)] { console.log('STOP attribute'); this.popState();console.log('STOP diagram'); this.popState();}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,update_el_style,update_rel_style,update_layout_config>[(][ ]*[,] { this.begin("attribute"); return "ATTRIBUTE_EMPTY";}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,update_el_style,update_rel_style,update_layout_config>[(] { this.begin("attribute"); }
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,update_el_style,update_rel_style,update_layout_config,attribute>[)] { this.popState();this.popState();}
<attribute>",," { console.log(',,'); return 'ATTRIBUTE_EMPTY';}
<attribute>"," { console.log(','); }
<attribute>[ ]*["]["] { console.log('ATTRIBUTE_EMPTY'); return 'ATTRIBUTE_EMPTY';}
<attribute>[ ]*["] { console.log('begin string'); this.begin("string");}
<string>["] { console.log('STOP string'); this.popState(); }
<string>[^"]* { console.log('STR'); return "STR";}
<attribute>",," { return 'ATTRIBUTE_EMPTY';}
<attribute>"," { }
<attribute>[ ]*["]["] { return 'ATTRIBUTE_EMPTY';}
<attribute>[ ]*["] { this.begin("string");}
<string>["] { this.popState(); }
<string>[^"]* { return "STR";}
<attribute>[ ]*[\$] { console.log('begin string_kv'); this.begin("string_kv");}
<string_kv>[^=]* { console.log('STR_KEY'); this.begin("string_kv_key"); return "STR_KEY";}
<string_kv_key>[=][ ]*["] { console.log('begin string_kv_value'); this.popState(); this.begin("string_kv_value"); }
<string_kv_value>[^"]+ { console.log('STR_VALUE'); return "STR_VALUE";}
<string_kv_value>["] { console.log('STOP string_kv_value'); this.popState(); this.popState(); }
<attribute>[ ]*[\$] { this.begin("string_kv");}
<string_kv>[^=]* { this.begin("string_kv_key"); return "STR_KEY";}
<string_kv_key>[=][ ]*["] { this.popState(); this.begin("string_kv_value"); }
<string_kv_value>[^"]+ { return "STR_VALUE";}
<string_kv_value>["] { this.popState(); this.popState(); }
<attribute>[^,]+ { console.log('not STR'); return "STR";}
<attribute>[^,]+ { return "STR";}
'{' { /* this.begin("lbrace"); */ console.log('begin boundary block'); return "LBRACE";}
'}' { /* this.popState(); */ console.log('STOP boundary block'); return "RBRACE";}
'{' { /* this.begin("lbrace"); */ return "LBRACE";}
'}' { /* this.popState(); */ return "RBRACE";}
[\s]+ return 'SPACE';
[\n\r]+ return 'EOL';
@ -231,7 +231,7 @@ directive
;
openDirective
: open_directive { console.log("open_directive: ", $1); yy.parseDirective('%%{', 'open_directive'); }
: open_directive { yy.parseDirective('%%{', 'open_directive'); }
;
typeDirective
@ -239,11 +239,11 @@ typeDirective
;
argDirective
: arg_directive { $1 = $1.trim().replace(/'/g, '"'); console.log("arg_directive: ", $1); yy.parseDirective($1, 'arg_directive'); }
: arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); }
;
closeDirective
: close_directive { console.log("close_directive: ", $1); yy.parseDirective('}%%', 'close_directive', 'c4Context'); }
: close_directive { yy.parseDirective('}%%', 'close_directive', 'c4Context'); }
;
graphConfig
@ -285,13 +285,13 @@ boundaryStartStatement
;
boundaryStart
: ENTERPRISE_BOUNDARY attributes {console.log($1,JSON.stringify($2)); $2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| SYSTEM_BOUNDARY attributes {console.log($1,JSON.stringify($2)); $2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| BOUNDARY attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| CONTAINER_BOUNDARY attributes {console.log($1,JSON.stringify($2)); $2.splice(2, 0, 'CONTAINER'); yy.addContainerBoundary(...$2); $$=$2;}
| NODE attributes {console.log($1,JSON.stringify($2)); yy.addDeploymentNode('node', ...$2); $$=$2;}
| NODE_L attributes {console.log($1,JSON.stringify($2)); yy.addDeploymentNode('nodeL', ...$2); $$=$2;}
| NODE_R attributes {console.log($1,JSON.stringify($2)); yy.addDeploymentNode('nodeR', ...$2); $$=$2;}
: ENTERPRISE_BOUNDARY attributes {$2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| SYSTEM_BOUNDARY attributes {$2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| BOUNDARY attributes {yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| CONTAINER_BOUNDARY attributes {$2.splice(2, 0, 'CONTAINER'); yy.addContainerBoundary(...$2); $$=$2;}
| NODE attributes {yy.addDeploymentNode('node', ...$2); $$=$2;}
| NODE_L attributes {yy.addDeploymentNode('nodeL', ...$2); $$=$2;}
| NODE_R attributes {yy.addDeploymentNode('nodeR', ...$2); $$=$2;}
;
boundaryStopStatement
@ -305,48 +305,48 @@ diagramStatements
;
diagramStatement
: PERSON attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('person', ...$2); $$=$2;}
| PERSON_EXT attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('external_person', ...$2); $$=$2;}
| SYSTEM attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('system', ...$2); $$=$2;}
| SYSTEM_DB attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('system_db', ...$2); $$=$2;}
| SYSTEM_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('system_queue', ...$2); $$=$2;}
| SYSTEM_EXT attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('external_system', ...$2); $$=$2;}
| SYSTEM_EXT_DB attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('external_system_db', ...$2); $$=$2;}
| SYSTEM_EXT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('external_system_queue', ...$2); $$=$2;}
| CONTAINER attributes {console.log($1,JSON.stringify($2)); yy.addContainer('container', ...$2); $$=$2;}
| CONTAINER_DB attributes {console.log($1,JSON.stringify($2)); yy.addContainer('container_db', ...$2); $$=$2;}
| CONTAINER_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addContainer('container_queue', ...$2); $$=$2;}
| CONTAINER_EXT attributes {console.log($1,JSON.stringify($2)); yy.addContainer('external_container', ...$2); $$=$2;}
| CONTAINER_EXT_DB attributes {console.log($1,JSON.stringify($2)); yy.addContainer('external_container_db', ...$2); $$=$2;}
| CONTAINER_EXT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addContainer('external_container_queue', ...$2); $$=$2;}
| COMPONENT attributes {console.log($1,JSON.stringify($2)); yy.addComponent('component', ...$2); $$=$2;}
| COMPONENT_DB attributes {console.log($1,JSON.stringify($2)); yy.addComponent('component_db', ...$2); $$=$2;}
| COMPONENT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addComponent('component_queue', ...$2); $$=$2;}
| COMPONENT_EXT attributes {console.log($1,JSON.stringify($2)); yy.addComponent('external_component', ...$2); $$=$2;}
| COMPONENT_EXT_DB attributes {console.log($1,JSON.stringify($2)); yy.addComponent('external_component_db', ...$2); $$=$2;}
| COMPONENT_EXT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addComponent('external_component_queue', ...$2); $$=$2;}
: PERSON attributes {yy.addPersonOrSystem('person', ...$2); $$=$2;}
| PERSON_EXT attributes {yy.addPersonOrSystem('external_person', ...$2); $$=$2;}
| SYSTEM attributes {yy.addPersonOrSystem('system', ...$2); $$=$2;}
| SYSTEM_DB attributes {yy.addPersonOrSystem('system_db', ...$2); $$=$2;}
| SYSTEM_QUEUE attributes {yy.addPersonOrSystem('system_queue', ...$2); $$=$2;}
| SYSTEM_EXT attributes {yy.addPersonOrSystem('external_system', ...$2); $$=$2;}
| SYSTEM_EXT_DB attributes {yy.addPersonOrSystem('external_system_db', ...$2); $$=$2;}
| SYSTEM_EXT_QUEUE attributes {yy.addPersonOrSystem('external_system_queue', ...$2); $$=$2;}
| CONTAINER attributes {yy.addContainer('container', ...$2); $$=$2;}
| CONTAINER_DB attributes {yy.addContainer('container_db', ...$2); $$=$2;}
| CONTAINER_QUEUE attributes {yy.addContainer('container_queue', ...$2); $$=$2;}
| CONTAINER_EXT attributes {yy.addContainer('external_container', ...$2); $$=$2;}
| CONTAINER_EXT_DB attributes {yy.addContainer('external_container_db', ...$2); $$=$2;}
| CONTAINER_EXT_QUEUE attributes {yy.addContainer('external_container_queue', ...$2); $$=$2;}
| COMPONENT attributes {yy.addComponent('component', ...$2); $$=$2;}
| COMPONENT_DB attributes {yy.addComponent('component_db', ...$2); $$=$2;}
| COMPONENT_QUEUE attributes {yy.addComponent('component_queue', ...$2); $$=$2;}
| COMPONENT_EXT attributes {yy.addComponent('external_component', ...$2); $$=$2;}
| COMPONENT_EXT_DB attributes {yy.addComponent('external_component_db', ...$2); $$=$2;}
| COMPONENT_EXT_QUEUE attributes {yy.addComponent('external_component_queue', ...$2); $$=$2;}
| boundaryStatement
| REL attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel', ...$2); $$=$2;}
| BIREL attributes {console.log($1,JSON.stringify($2)); yy.addRel('birel', ...$2); $$=$2;}
| REL_U attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_u', ...$2); $$=$2;}
| REL_D attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_d', ...$2); $$=$2;}
| REL_L attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_l', ...$2); $$=$2;}
| REL_R attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_r', ...$2); $$=$2;}
| REL_B attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_b', ...$2); $$=$2;}
| REL_INDEX attributes {console.log($1,JSON.stringify($2)); $2.splice(0, 1); yy.addRel('rel', ...$2); $$=$2;}
| UPDATE_EL_STYLE attributes {console.log($1,JSON.stringify($2)); yy.updateElStyle('update_el_style', ...$2); $$=$2;}
| UPDATE_REL_STYLE attributes {console.log($1,JSON.stringify($2)); yy.updateRelStyle('update_rel_style', ...$2); $$=$2;}
| UPDATE_LAYOUT_CONFIG attributes {console.log($1,JSON.stringify($2)); yy.updateLayoutConfig('update_layout_config', ...$2); $$=$2;}
| REL attributes {yy.addRel('rel', ...$2); $$=$2;}
| BIREL attributes {yy.addRel('birel', ...$2); $$=$2;}
| REL_U attributes {yy.addRel('rel_u', ...$2); $$=$2;}
| REL_D attributes {yy.addRel('rel_d', ...$2); $$=$2;}
| REL_L attributes {yy.addRel('rel_l', ...$2); $$=$2;}
| REL_R attributes {yy.addRel('rel_r', ...$2); $$=$2;}
| REL_B attributes {yy.addRel('rel_b', ...$2); $$=$2;}
| REL_INDEX attributes {$2.splice(0, 1); yy.addRel('rel', ...$2); $$=$2;}
| UPDATE_EL_STYLE attributes {yy.updateElStyle('update_el_style', ...$2); $$=$2;}
| UPDATE_REL_STYLE attributes {yy.updateRelStyle('update_rel_style', ...$2); $$=$2;}
| UPDATE_LAYOUT_CONFIG attributes {yy.updateLayoutConfig('update_layout_config', ...$2); $$=$2;}
;
attributes
: attribute { console.log('PUSH ATTRIBUTE: ', $1); $$ = [$1]; }
| attribute attributes { console.log('PUSH ATTRIBUTE: ', $1); $2.unshift($1); $$=$2;}
: attribute { $$ = [$1]; }
| attribute attributes { $2.unshift($1); $$=$2;}
;
attribute
: STR { $$ = $1.trim(); }
| STR_KEY STR_VALUE { console.log('kv: ', $1, $2); let kv={}; kv[$1.trim()]=$2.trim(); $$=kv; }
| STR_KEY STR_VALUE { let kv={}; kv[$1.trim()]=$2.trim(); $$=kv; }
| ATTRIBUTE { $$ = $1.trim(); }
| ATTRIBUTE_EMPTY { $$ = ""; }
;

View File

@ -1,49 +1,20 @@
import flowDb from '../c4Db';
import flow from './c4Diagram.jison';
import c4Db from '../c4Db';
import c4 from './c4Diagram.jison';
import { setConfig } from '../../../config';
setConfig({
securityLevel: 'strict',
});
describe('parsing a flow chart', function () {
describe('parsing a C4 diagram', function () {
beforeEach(function () {
flow.parser.yy = flowDb;
flow.parser.yy.clear();
});
it('should parse a C4 diagram with one Person correctly', function () {
flow.parser.parse(`C4Context
title System Context diagram for Internet Banking System
Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")`);
const yy = flow.parser.yy;
expect(yy.getC4Type()).toBe('C4Context');
expect(yy.getTitle()).toBe('System Context diagram for Internet Banking System');
const shapes = yy.getC4ShapeArray();
expect(shapes.length).toBe(1);
const onlyShape = shapes[0];
expect(onlyShape).toEqual({
alias: 'customerA',
descr: {
text: 'A customer of the bank, with personal bank accounts.',
},
label: {
text: 'Banking Customer A',
},
parentBoundary: 'global',
typeC4Shape: {
text: 'person',
},
wrap: false,
});
c4.parser.yy = c4Db;
c4.parser.yy.clear();
});
it('should handle a trailing whitespaces after statements', function () {
const whitespace = ' ';
const rendered = flow.parser.parse(`C4Context${whitespace}
const rendered = c4.parser.parse(`C4Context${whitespace}
title System Context diagram for Internet Banking System${whitespace}
Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")${whitespace}`);
@ -51,11 +22,11 @@ Person(customerA, "Banking Customer A", "A customer of the bank, with personal b
});
it('should handle parameter names that are keywords', function () {
flow.parser.parse(`C4Context
c4.parser.parse(`C4Context
title title
Person(Person, "Person", "Person")`);
const yy = flow.parser.yy;
const yy = c4.parser.yy;
expect(yy.getTitle()).toBe('title');
const shapes = yy.getC4ShapeArray();
@ -68,10 +39,10 @@ Person(Person, "Person", "Person")`);
});
it('should allow default in the parameters', function () {
flow.parser.parse(`C4Context
c4.parser.parse(`C4Context
Person(default, "default", "default")`);
const yy = flow.parser.yy;
const yy = c4.parser.yy;
const shapes = yy.getC4ShapeArray();
expect(shapes.length).toBe(1);

View File

@ -0,0 +1,111 @@
import c4Db from '../c4Db';
import c4 from './c4Diagram.jison';
import { setConfig } from '../../../config';
setConfig({
securityLevel: 'strict',
});
describe('parsing a C4 Person', function () {
beforeEach(function () {
c4.parser.yy = c4Db;
c4.parser.yy.clear();
});
it('should parse a C4 diagram with one Person correctly', function () {
c4.parser.parse(`C4Context
title System Context diagram for Internet Banking System
Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")`);
const yy = c4.parser.yy;
const shapes = yy.getC4ShapeArray();
expect(shapes.length).toBe(1);
const onlyShape = shapes[0];
expect(onlyShape).toEqual({
alias: 'customerA',
descr: {
text: 'A customer of the bank, with personal bank accounts.',
},
label: {
text: 'Banking Customer A',
},
parentBoundary: 'global',
typeC4Shape: {
text: 'person',
},
wrap: false,
});
});
it('should parse the alias', function () {
c4.parser.parse(`C4Context
Person(customerA, "Banking Customer A")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
alias: 'customerA',
});
});
it('should parse the label', function () {
c4.parser.parse(`C4Context
Person(customerA, "Banking Customer A")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: 'Banking Customer A',
},
});
});
it('should parse the description', function () {
c4.parser.parse(`C4Context
Person(customerA, "", "A customer of the bank, with personal bank accounts.")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
descr: {
text: 'A customer of the bank, with personal bank accounts.',
},
});
});
it('should parse a sprite', function () {
c4.parser.parse(`C4Context
Person(customerA, $sprite="users")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: {
sprite: 'users',
},
},
});
});
it('should parse a link', function () {
c4.parser.parse(`C4Context
Person(customerA, $link="https://github.com/mermaidjs")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: {
link: 'https://github.com/mermaidjs',
},
},
});
});
it('should parse tags', function () {
c4.parser.parse(`C4Context
Person(customerA, $tags="tag1,tag2")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: {
tags: 'tag1,tag2',
},
},
});
});
});

View File

@ -0,0 +1,116 @@
import c4Db from '../c4Db';
import c4 from './c4Diagram.jison';
import { setConfig } from '../../../config';
setConfig({
securityLevel: 'strict',
});
describe('parsing a C4 Person_Ext', function () {
beforeEach(function () {
c4.parser.yy = c4Db;
c4.parser.yy.clear();
});
it('should parse a C4 diagram with one Person_Ext correctly', function () {
c4.parser.parse(`C4Context
title System Context diagram for Internet Banking System
Person_Ext(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")`);
const yy = c4.parser.yy;
const shapes = yy.getC4ShapeArray();
expect(shapes.length).toBe(1);
const onlyShape = shapes[0];
expect(onlyShape).toEqual({
alias: 'customerA',
descr: {
text: 'A customer of the bank, with personal bank accounts.',
},
label: {
text: 'Banking Customer A',
},
// TODO: Why are link, sprite, and tags undefined instead of not appearing at all?
// Compare to Person where they don't show up.
link: undefined,
sprite: undefined,
tags: undefined,
parentBoundary: 'global',
typeC4Shape: {
text: 'external_person',
},
wrap: false,
});
});
it('should parse the alias', function () {
c4.parser.parse(`C4Context
Person_Ext(customerA, "Banking Customer A")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
alias: 'customerA',
});
});
it('should parse the label', function () {
c4.parser.parse(`C4Context
Person_Ext(customerA, "Banking Customer A")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: 'Banking Customer A',
},
});
});
it('should parse the description', function () {
c4.parser.parse(`C4Context
Person_Ext(customerA, "", "A customer of the bank, with personal bank accounts.")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
descr: {
text: 'A customer of the bank, with personal bank accounts.',
},
});
});
it('should parse a sprite', function () {
c4.parser.parse(`C4Context
Person_Ext(customerA, $sprite="users")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: {
sprite: 'users',
},
},
});
});
it('should parse a link', function () {
c4.parser.parse(`C4Context
Person_Ext(customerA, $link="https://github.com/mermaidjs")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: {
link: 'https://github.com/mermaidjs',
},
},
});
});
it('should parse tags', function () {
c4.parser.parse(`C4Context
Person_Ext(customerA, $tags="tag1,tag2")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: {
tags: 'tag1,tag2',
},
},
});
});
});

View File

@ -0,0 +1,123 @@
import c4Db from '../c4Db';
import c4 from './c4Diagram.jison';
import { setConfig } from '../../../config';
setConfig({
securityLevel: 'strict',
});
describe.each([
['System', 'system'],
['SystemDb', 'system_db'],
['SystemQueue', 'system_queue'],
['System_Ext', 'external_system'],
['SystemDb_Ext', 'external_system_db'],
['SystemQueue_Ext', 'external_system_queue'],
])('parsing a C4 %s', function (macroName, elementName) {
beforeEach(function () {
c4.parser.yy = c4Db;
c4.parser.yy.clear();
});
it('should parse a C4 diagram with one System correctly', function () {
c4.parser.parse(`C4Context
title System Context diagram for Internet Banking System
${macroName}(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.")`);
const yy = c4.parser.yy;
const shapes = yy.getC4ShapeArray();
expect(shapes.length).toBe(1);
const onlyShape = shapes[0];
expect(onlyShape).toEqual({
alias: 'SystemAA',
descr: {
text: 'Allows customers to view information about their bank accounts, and make payments.',
},
label: {
text: 'Internet Banking System',
},
// TODO: Why are link, sprite, and tags undefined instead of not appearing at all?
// Compare to Person where they don't show up.
link: undefined,
sprite: undefined,
tags: undefined,
parentBoundary: 'global',
typeC4Shape: {
text: elementName,
},
wrap: false,
});
});
it('should parse the alias', function () {
c4.parser.parse(`C4Context
${macroName}(SystemAA, "Internet Banking System")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
alias: 'SystemAA',
});
});
it('should parse the label', function () {
c4.parser.parse(`C4Context
${macroName}(SystemAA, "Internet Banking System")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: 'Internet Banking System',
},
});
});
it('should parse the description', function () {
c4.parser.parse(`C4Context
${macroName}(SystemAA, "", "Allows customers to view information about their bank accounts, and make payments.")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
descr: {
text: 'Allows customers to view information about their bank accounts, and make payments.',
},
});
});
it('should parse a sprite', function () {
c4.parser.parse(`C4Context
${macroName}(SystemAA, $sprite="users")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: {
sprite: 'users',
},
},
});
});
it('should parse a link', function () {
c4.parser.parse(`C4Context
${macroName}(SystemAA, $link="https://github.com/mermaidjs")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: {
link: 'https://github.com/mermaidjs',
},
},
});
});
it('should parse tags', function () {
c4.parser.parse(`C4Context
${macroName}(SystemAA, $tags="tag1,tag2")`);
expect(c4.parser.yy.getC4ShapeArray()[0]).toMatchObject({
label: {
text: {
tags: 'tag1,tag2',
},
},
});
});
});

View File

@ -550,8 +550,6 @@ describe('when parsing a gitGraph', function () {
testBranch3Merge,
] = Object.values(commits);
console.log(Object.keys(commits));
expect(mainCommit.branch).toBe('main');
expect(mainCommit.parents).toStrictEqual([]);

View File

@ -49,7 +49,6 @@ export const draw = (text, id, version, diagObj) => {
svg.attr('width', 400);
// svg.attr('viewBox', '0 0 300 150');
} catch (e) {
console.error(e);
log.error('Error while rendering info diagram');
log.error(e.message);
}

View File

@ -30,6 +30,7 @@ import { isDetailedError } from './utils';
* ```
*
* Renders the mermaid diagrams
*
* @param config
* @param nodes
* @param callback
@ -158,13 +159,7 @@ if (typeof document !== 'undefined') {
/*!
* Wait for document loaded before starting the execution
*/
window.addEventListener(
'load',
function () {
contentLoaded();
},
false
);
window.addEventListener('load', contentLoaded, false);
}
/**

View File

@ -13,7 +13,8 @@
/* Language and Environment */
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"lib": [
"ES2021"
"ES2021",
"DOM"
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */