From 7198fe55a9312f12fdf810b9538585fe5f0d8d49 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Thu, 26 Oct 2023 22:01:44 +0200 Subject: [PATCH] Parsing of block arrows with directions, creating a dedicated new node for this. --- cypress/platform/knsv2.html | 29 +++++---- packages/mermaid/src/dagre-wrapper/nodes.js | 27 ++++++++ .../mermaid/src/diagrams/block/blockDB.ts | 2 + .../mermaid/src/diagrams/block/blockTypes.ts | 3 + .../src/diagrams/block/parser/block.jison | 61 +++++++++++-------- .../src/diagrams/block/renderHelpers.ts | 3 + 6 files changed, 84 insertions(+), 41 deletions(-) diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index 6d5c9846b..315c33b21 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -62,24 +62,23 @@ -
-block-beta
-  block
-    id3("Wider then")
-  end
-    
+block-beta
+      blockArrowId<["Label"]>(right, down)
+    
+
 block-beta
     columns 3
-    space:2
-    id1("Wider then")
-    space:9
-    space
-    id2{{"Wider then"}}
-    space
-    id3("Wider then")
-    space
-    space
+    space:3
+    ida idb idc
+    id1  id2
+      blockArrowId<["Label"]>(right)
+      blockArrowId2<["Label"]>(left)
+      blockArrowId3<["Label"]>(up)
+      blockArrowId4<["Label"]>(down)
+      blockArrowId5<["Label"]>(x)
+      blockArrowId6<["Label"]>(y)
+      blockArrowId6<["Label"]>(x, down)
     
 block-beta
diff --git a/packages/mermaid/src/dagre-wrapper/nodes.js b/packages/mermaid/src/dagre-wrapper/nodes.js
index 78bcfea99..41578f584 100644
--- a/packages/mermaid/src/dagre-wrapper/nodes.js
+++ b/packages/mermaid/src/dagre-wrapper/nodes.js
@@ -95,6 +95,32 @@ const hexagon = async (parent, node) => {
 
   return shapeSvg;
 };
+const block_arrow = async (parent, node) => {
+  const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
+
+  const f = 2;
+  const h = bbox.height + node.padding;
+  const m = h / f;
+  const w = bbox.width + 2 * m + node.padding;
+  const points = [
+    { x: m, y: 0 },
+    { x: w - m, y: 0 },
+    { x: w, y: -h / 2 },
+    { x: w - m, y: -h },
+    { x: m, y: -h },
+    { x: 0, y: -h / 2 },
+  ];
+
+  const hex = insertPolygonShape(shapeSvg, w, h, points);
+  hex.attr('style', node.style);
+  updateNodeBounds(node, hex);
+
+  node.intersect = function (point) {
+    return intersect.polygon(node, points, point);
+  };
+
+  return shapeSvg;
+};
 
 const rect_left_inv_arrow = async (parent, node) => {
   const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
@@ -1016,6 +1042,7 @@ const shapes = {
   doublecircle,
   stadium,
   hexagon,
+  block_arrow,
   rect_left_inv_arrow,
   lean_right,
   lean_left,
diff --git a/packages/mermaid/src/diagrams/block/blockDB.ts b/packages/mermaid/src/diagrams/block/blockDB.ts
index 6b787009d..a3ef97e24 100644
--- a/packages/mermaid/src/diagrams/block/blockDB.ts
+++ b/packages/mermaid/src/diagrams/block/blockDB.ts
@@ -99,6 +99,8 @@ export function typeStr2Type(typeStr: string) {
       return 'trapezoid';
     case '[\\/]':
       return 'inv_trapezoid';
+    case '<[]>':
+      return 'block_arrow';
     default:
       return 'square';
   }
diff --git a/packages/mermaid/src/diagrams/block/blockTypes.ts b/packages/mermaid/src/diagrams/block/blockTypes.ts
index f26d83fcc..001cd7bda 100644
--- a/packages/mermaid/src/diagrams/block/blockTypes.ts
+++ b/packages/mermaid/src/diagrams/block/blockTypes.ts
@@ -7,6 +7,8 @@ export interface BlockConfig extends BaseDiagramConfig {
 export type BlockType =
   | 'column-setting'
   | 'round'
+  | 'block_arrow'
+  | 'space'
   | 'square'
   | 'diamond'
   | 'hexagon'
@@ -40,6 +42,7 @@ export interface Block {
   node?: any;
   columns?: number; // | TBlockColumnsDefaultValue;
   classes?: string[];
+  directions?: string[];
 }
 
 export interface Link {
diff --git a/packages/mermaid/src/diagrams/block/parser/block.jison b/packages/mermaid/src/diagrams/block/parser/block.jison
index b2975b610..91d26faf3 100644
--- a/packages/mermaid/src/diagrams/block/parser/block.jison
+++ b/packages/mermaid/src/diagrams/block/parser/block.jison
@@ -16,6 +16,8 @@
 %x space
 %x md_string
 %x NODE
+%x BLOCK_ARROW
+%x ARROW_DIR
 
 
 // as per section 6.1 of RFC 2234 [2]
@@ -42,11 +44,10 @@ CRLF \u000D\u000A
 [^`"]+        { return "MD_STR";}
 [`]["]          { this.popState();}
 ["]                     this.pushState("string");
-["]             this.popState();
-[^"]*           return "STR";
+["]             { log.debug('LEX: POPPING STR:', yytext);this.popState();}
+[^"]*           { log.debug('LEX: STR ebd:', yytext); return "STR";}
 space[:]\d+            {  yytext = yytext.replace(/space\:/,'');yy.getLogger().info('SPACE NUM (LEX)', yytext); return 'SPACE_BLOCK'; }
 space                  { yytext = '1'; yy.getLogger().info('COLUMNS (LEX)', yytext); return 'SPACE_BLOCK'; }
-[^"]*           return "STR";
 "style"               return 'STYLE';
 "default"             return 'DEFAULT';
 "linkStyle"           return 'LINKSTYLE';
@@ -68,15 +69,15 @@ accDescr\s*"{"\s*                                { this.pushState("acc_descr_mul
 .*direction\s+LR[^\n]*                                      return 'direction_lr';
 
 // Start of nodes with shapes and description
-"-)"                   { yy.getLogger().info('Lex: -)'); this.pushState('NODE');return 'NODE_DSTART'; }
-"(-"                   { yy.getLogger().info('Lex: (-'); this.pushState('NODE');return 'NODE_DSTART'; }
-"))"                   { yy.getLogger().info('Lex: ))'); this.pushState('NODE');return 'NODE_DSTART';  }
-")"                    { yy.getLogger().info('Lex: )'); this.pushState('NODE');return 'NODE_DSTART';      }
-"(("                   { yy.getLogger().info('Lex: )'); this.pushState('NODE');return 'NODE_DSTART'; }
-"{{"                   { yy.getLogger().info('Lex: )'); this.pushState('NODE');return 'NODE_DSTART'; }
-"("                    { yy.getLogger().info('Lex: )'); this.pushState('NODE');return 'NODE_DSTART'; }
-"["                    { yy.getLogger().info('Lex: ['); this.pushState('NODE');return 'NODE_DSTART'; }
-"(["                   { yy.getLogger().info('Lex: )'); this.pushState('NODE');return 'NODE_DSTART'; }
+"-)"                   { yy.getLogger().info('Lexa: -)'); this.pushState('NODE');return 'NODE_DSTART'; }
+"(-"                   { yy.getLogger().info('Lexa: (-'); this.pushState('NODE');return 'NODE_DSTART'; }
+"))"                   { yy.getLogger().info('Lexa: ))'); this.pushState('NODE');return 'NODE_DSTART';  }
+")"                    { yy.getLogger().info('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART';      }
+"(("                   { yy.getLogger().info('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
+"{{"                   { yy.getLogger().info('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
+"("                    { yy.getLogger().info('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
+"["                    { yy.getLogger().info('Lexa: ['); this.pushState('NODE');return 'NODE_DSTART'; }
+"(["                   { yy.getLogger().info('Lexa: (['); this.pushState('NODE');return 'NODE_DSTART'; }
 "[["                   { this.pushState('NODE');return 'NODE_DSTART'; }
 "[|"                   { this.pushState('NODE');return 'NODE_DSTART'; }
 "[("                   { this.pushState('NODE');return 'NODE_DSTART'; }
@@ -85,19 +86,23 @@ accDescr\s*"{"\s*                                { this.pushState("acc_descr_mul
 "[/"                   { this.pushState('NODE');return 'NODE_DSTART'; }
 "[\\"                  { this.pushState('NODE');return 'NODE_DSTART'; }
 
+"<["                   { this.pushState('BLOCK_ARROW');log.debug('LEX ARR START');return 'BLOCK_ARROW_START'; }
 
-[^\(\[\n\-\)\{\}]+     { yy.getLogger().info('Lex: NODE_ID', yytext);return 'NODE_ID'; }
+[^\(\[\n\-\)\{\}\s\<]+     { yy.getLogger().info('Lex: NODE_ID', yytext);return 'NODE_ID'; }
 <>                { yy.getLogger().info('Lex: EOF', yytext);return 'EOF'; }
 
 // Handling of strings in node
+["][`]           { this.pushState("md_string");}
 ["][`]           { this.pushState("md_string");}
 [^`"]+      { return "NODE_DESCR";}
 [`]["]      { this.popState();}
 ["]              { yy.getLogger().info('Lex: Starting string');this.pushState("string");}
-[^"]+          { yy.getLogger().info('Lex: NODE_DESCR:', yytext); return "NODE_DESCR";}
-["]            {this.popState();}
+["]              { yy.getLogger().info('LEX ARR: Starting string');this.pushState("string");}
+[^"]+          { log.debug('LEX: NODE_DESCR:', yytext); return "NODE_DESCR";}
+["]            {log.debug('LEX POPPING');this.popState();}
 
 // Node end of shape
+\]\>             { this.popState();yy.getLogger().info('Lex: ]>'); return "NODE_DEND"; }
 [\)]\)           { this.popState();yy.getLogger().info('Lex: ))'); return "NODE_DEND"; }
 [\)]             { this.popState();yy.getLogger().info('Lex: )');  return "NODE_DEND"; }
 [\]]             { this.popState();yy.getLogger().info('Lex: ]'); return "NODE_DEND"; }
@@ -111,6 +116,15 @@ accDescr\s*"{"\s*                                { this.pushState("acc_descr_mul
 "/]"             { this.popState();yy.getLogger().info('Lex: /]'); return "NODE_DEND"; }
 ")]"             { this.popState();yy.getLogger().info('Lex: )]'); return "NODE_DEND"; }
 
+"]>"\s*"("       { log.debug('Lex: =>BAE');  this.pushState('ARROW_DIR');  }
+","?right\s*           { log.debug('Lex (right): dir:',yytext);return "DIR"; }
+","?left\s*            { log.debug('Lex (left):',yytext);return "DIR"; }
+","?x\s*               { log.debug('Lex (x):',yytext); return "DIR"; }
+","?y\s*               { log.debug('Lex (y):',yytext); return "DIR"; }
+","?up\s*              { log.debug('Lex (up):',yytext); return "DIR"; }
+","?\s*down\s*     { yytext = yytext.replace(/^,\s*/, ''); log.debug('Lex (down):',yytext); return "DIR"; }
+")"\s*             { yytext=']>';log.debug('Lex (ARROW_DIR end):',yytext);this.popState();this.popState();return "BLOCK_ARROW_END"; }
+
 // Edges
 \s*[xo<]?\-\-+[-xo>]\s*                 { yy.getLogger().info('Lex: LINK', '#'+yytext+'#'); return 'LINK'; }
 \s*[xo<]?\=\=+[=xo>]\s*                 { yy.getLogger().info('Lex: LINK', yytext); return 'LINK'; }
@@ -174,16 +188,6 @@ statement
   | SPACE_BLOCK
     { const num=parseInt($1); const spaceId = yy.generateId(); $$ = { id: spaceId, type:'space', label:'', width: num, children: [] }}
   | blockStatement
-//   SPACELIST node       { yy.getLogger().info('Node: ',$2.id);yy.addNode($1.length, $2.id, $2.descr, $2.type);  }
-// 	| SPACELIST ICON       { yy.getLogger().info('Icon: ',$2);yy.decorateNode({icon: $2}); }
-// 	| SPACELIST CLASS      { yy.decorateNode({class: $2}); }
-//   | SPACELINE { yy.getLogger().info('SPACELIST');}
-// 	|
-//    node					       { yy.getLogger().info('Node: ',$1.id);yy.addNode(0, $1.id, $1.descr, $1.type);  }
-// 	| ICON                 { yy.decorateNode({icon: $1}); }
-// 	| CLASS                { yy.decorateNode({class: $1}); }
-//   // | SPACELIST
-
 	;
 
 nodeStatement
@@ -200,7 +204,6 @@ blockStatement
   | block document end { yy.getLogger().info('Rule: blockStatement : ', $1, $2, $3); const id = yy.generateId(); $$ = { id, type:'composite', label:'', children: $2 }; }
   ;
 
-
 node
   : NODE_ID
   { yy.getLogger().info("Rule: node (NODE_ID seperator): ", $1); $$ = { id: $1 }; }
@@ -210,9 +213,15 @@ node
   // { yy.getLogger().info("Rule: node (nodeShapeNLabel seperator): ", $1, $2, $3); }
   ;
 
+dirList: DIR { yy.getLogger().info("Rule: dirList: ", $1); $$ = [$1]; }
+  | DIR dirList { yy.getLogger().info("Rule: dirList: ", $1, $2); $$ = [$1].concat($2); }
+  ;
+
 nodeShapeNLabel
   :   NODE_DSTART STR NODE_DEND
 	      { yy.getLogger().info("Rule: nodeShapeNLabel: ", $1, $2, $3); $$ = { typeStr: $1 + $3, label: $2 }; }
+	|    BLOCK_ARROW_START STR dirList BLOCK_ARROW_END
+    	      { yy.getLogger().info("Rule: BLOCK_ARROW nodeShapeNLabel: ", $1, $2, $3, $4); $$ = { typeStr: $1 + $4, label: $2, directions: $3}; }
   ;
 
 %%
diff --git a/packages/mermaid/src/diagrams/block/renderHelpers.ts b/packages/mermaid/src/diagrams/block/renderHelpers.ts
index 78cce974c..142de0c5c 100644
--- a/packages/mermaid/src/diagrams/block/renderHelpers.ts
+++ b/packages/mermaid/src/diagrams/block/renderHelpers.ts
@@ -50,6 +50,9 @@ function getNodeFromBlock(block: Block, db: BlockDB, positioned = false) {
     case 'hexagon':
       _shape = 'hexagon';
       break;
+    case 'block_arrow':
+      _shape = 'block_arrow';
+      break;
     case 'odd':
       _shape = 'rect_left_inv_arrow';
       break;