diff --git a/.eslintrc.json b/.eslintrc.json index 4c702fcbc..e04bb050e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -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" + } } ] } diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 44e2f4cb1..e567aba89 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -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" diff --git a/src/diagrams/c4/parser/c4Boundary.spec.js b/src/diagrams/c4/parser/c4Boundary.spec.js new file mode 100644 index 000000000..c7130f557 --- /dev/null +++ b/src/diagrams/c4/parser/c4Boundary.spec.js @@ -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', + }, + }, + }); + }); +}); diff --git a/src/diagrams/c4/parser/c4Diagram.jison b/src/diagrams/c4/parser/c4Diagram.jison index 10783db53..03b851458 100644 --- a/src/diagrams/c4/parser/c4Diagram.jison +++ b/src/diagrams/c4/parser/c4Diagram.jison @@ -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';} <> return "EOF_IN_STRUCT"; -[(][ ]*[,] { console.log('begin attribute with ATTRIBUTE_EMPTY'); this.begin("attribute"); return "ATTRIBUTE_EMPTY";} -[(] { console.log('begin attribute'); this.begin("attribute"); } -[)] { console.log('STOP attribute'); this.popState();console.log('STOP diagram'); this.popState();} +[(][ ]*[,] { this.begin("attribute"); return "ATTRIBUTE_EMPTY";} +[(] { this.begin("attribute"); } +[)] { this.popState();this.popState();} -",," { console.log(',,'); return 'ATTRIBUTE_EMPTY';} -"," { console.log(','); } -[ ]*["]["] { console.log('ATTRIBUTE_EMPTY'); return 'ATTRIBUTE_EMPTY';} -[ ]*["] { console.log('begin string'); this.begin("string");} -["] { console.log('STOP string'); this.popState(); } -[^"]* { console.log('STR'); return "STR";} +",," { return 'ATTRIBUTE_EMPTY';} +"," { } +[ ]*["]["] { return 'ATTRIBUTE_EMPTY';} +[ ]*["] { this.begin("string");} +["] { this.popState(); } +[^"]* { return "STR";} -[ ]*[\$] { console.log('begin string_kv'); this.begin("string_kv");} -[^=]* { console.log('STR_KEY'); this.begin("string_kv_key"); return "STR_KEY";} -[=][ ]*["] { console.log('begin string_kv_value'); this.popState(); this.begin("string_kv_value"); } -[^"]+ { console.log('STR_VALUE'); return "STR_VALUE";} -["] { console.log('STOP string_kv_value'); this.popState(); this.popState(); } +[ ]*[\$] { this.begin("string_kv");} +[^=]* { this.begin("string_kv_key"); return "STR_KEY";} +[=][ ]*["] { this.popState(); this.begin("string_kv_value"); } +[^"]+ { return "STR_VALUE";} +["] { this.popState(); this.popState(); } -[^,]+ { console.log('not STR'); return "STR";} +[^,]+ { 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 { $$ = ""; } ; diff --git a/src/diagrams/c4/parser/flow.spec.js b/src/diagrams/c4/parser/c4Diagram.spec.js similarity index 50% rename from src/diagrams/c4/parser/flow.spec.js rename to src/diagrams/c4/parser/c4Diagram.spec.js index c01d99e40..b79934b84 100644 --- a/src/diagrams/c4/parser/flow.spec.js +++ b/src/diagrams/c4/parser/c4Diagram.spec.js @@ -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); diff --git a/src/diagrams/c4/parser/c4Person.spec.js b/src/diagrams/c4/parser/c4Person.spec.js new file mode 100644 index 000000000..b504c0384 --- /dev/null +++ b/src/diagrams/c4/parser/c4Person.spec.js @@ -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', + }, + }, + }); + }); +}); diff --git a/src/diagrams/c4/parser/c4PersonExt.spec.js b/src/diagrams/c4/parser/c4PersonExt.spec.js new file mode 100644 index 000000000..76547600a --- /dev/null +++ b/src/diagrams/c4/parser/c4PersonExt.spec.js @@ -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', + }, + }, + }); + }); +}); diff --git a/src/diagrams/c4/parser/c4System.spec.js b/src/diagrams/c4/parser/c4System.spec.js new file mode 100644 index 000000000..6d81c7379 --- /dev/null +++ b/src/diagrams/c4/parser/c4System.spec.js @@ -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', + }, + }, + }); + }); +}); diff --git a/src/diagrams/git/gitGraphParserV2.spec.js b/src/diagrams/git/gitGraphParserV2.spec.js index 9a33e288f..56a11a876 100644 --- a/src/diagrams/git/gitGraphParserV2.spec.js +++ b/src/diagrams/git/gitGraphParserV2.spec.js @@ -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([]); diff --git a/src/diagrams/info/infoRenderer.js b/src/diagrams/info/infoRenderer.js index 8976abb75..9e81b9ffb 100644 --- a/src/diagrams/info/infoRenderer.js +++ b/src/diagrams/info/infoRenderer.js @@ -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); } diff --git a/src/mermaid.ts b/src/mermaid.ts index d22ff1922..c93c6c94e 100644 --- a/src/mermaid.ts +++ b/src/mermaid.ts @@ -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); } /** diff --git a/tsconfig.json b/tsconfig.json index 8acf035d7..db76be75e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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. */