From b9531d56c431ad3ef4e3181982dcb896ef57f7aa Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Tue, 8 Aug 2023 15:56:02 +0200 Subject: [PATCH] Adding support for compound blocks --- .../mermaid/src/diagrams/block/blockDB.ts | 51 ++++++++++++++++--- .../src/diagrams/block/parser/block.jison | 36 ++++++++----- .../src/diagrams/block/parser/block.spec.ts | 42 ++++++++++----- 3 files changed, 98 insertions(+), 31 deletions(-) diff --git a/packages/mermaid/src/diagrams/block/blockDB.ts b/packages/mermaid/src/diagrams/block/blockDB.ts index 35a2e209b..a0c97fc0f 100644 --- a/packages/mermaid/src/diagrams/block/blockDB.ts +++ b/packages/mermaid/src/diagrams/block/blockDB.ts @@ -18,7 +18,7 @@ import { // TODO: Convert to generic TreeNode type? Convert to class? export interface Block { - ID?: string; + ID: string; label?: string; parent?: Block; children?: Block[]; @@ -32,16 +32,21 @@ export interface Link { let rootBlocks: Block[] = []; let blocks: Block[] = []; -let links: Link[] = []; +const links: Link[] = []; +let rootBlock = { ID: 'root', children: [], columns: -1 } as Block; +let currentBlock: Block | undefined; const clear = (): void => { + rootBlocks = []; blocks = []; commonClear(); + rootBlock = { ID: 'root', children: [], columns: -1 }; + currentBlock = rootBlock; }; type IAddBlock = (block: Block) => Block; const addBlock: IAddBlock = (block: Block, parent?: Block): Block => { - if(parent) { + if (parent) { parent.children ??= []; parent.children.push(block); } else { @@ -57,14 +62,44 @@ const addLink: IAddLink = (link: Link): Link => { return link; }; +type ISetColumns = (columnsStr: string) => void; +const setColumns = (columnsStr: string): void => { + const columns = columnsStr === 'auto' ? -1 : parseInt(columnsStr); + currentBlock!.columns = columns; +}; + +const getBlock = (id: string, blocks: Block[]): Block | undefined => { + for (const block of blocks) { + if (block.ID === id) { + return block; + } + if (block.children) { + const foundBlock = getBlock(id, block.children); + if (foundBlock) { + return foundBlock; + } + } + } +}; + +type IGetColumns = (blockID: string) => number; +const getColumns = (blockID: string): number => { + const blocks = [rootBlock]; + const block = getBlock(blockID, blocks); + if (!block) { + return -1; + } + return block.columns || -1; +}; + type IGetBlocks = () => Block[]; -const getBlocks:IGetBlocks = () => blocks; +const getBlocks: IGetBlocks = () => blocks; type IGetLinks = () => Link[]; -const getLinks:IGetLinks = () => links; +const getLinks: IGetLinks = () => links; type IGetLogger = () => Console; -const getLogger:IGetLogger = () => console; +const getLogger: IGetLogger = () => console; export interface BlockDB extends DiagramDB { clear: () => void; @@ -74,6 +109,8 @@ export interface BlockDB extends DiagramDB { getLogger: IGetLogger; getBlocks: IGetBlocks; getLinks: IGetLinks; + setColumns: ISetColumns; + getColumns: IGetColumns; } const db: BlockDB = { @@ -89,6 +126,8 @@ const db: BlockDB = { // setAccDescription, // getDiagramTitle, // setDiagramTitle, + setColumns, + getColumns, clear, }; diff --git a/packages/mermaid/src/diagrams/block/parser/block.jison b/packages/mermaid/src/diagrams/block/parser/block.jison index 687085939..afd645d96 100644 --- a/packages/mermaid/src/diagrams/block/parser/block.jison +++ b/packages/mermaid/src/diagrams/block/parser/block.jison @@ -15,7 +15,6 @@ %x string %x md_string %x NODE -%options easy_keword_rules // as per section 6.1 of RFC 2234 [2] @@ -28,11 +27,15 @@ CRLF \u000D\u000A %% "block-beta" { return 'BLOCK_DIAGRAM_KEY'; } +"block"\s+ { yy.getLogger().info('Found space-block'); return 'block';} +"block"\n+ { yy.getLogger().info('Found nl-block'); return 'block';} // \s*\%\%.* { yy.getLogger().info('Found comment',yytext); } [\s]+ { yy.getLogger().info('.', yytext); /* skip all whitespace */ } [\n]+ {yy.getLogger().info('_', yytext); /* skip all whitespace */ } // [\n] return 'NL'; ({CRLF}|{LF}) { return 'NL' } +"columns"\s+"auto" { yytext=-1; return 'COLUMNS'; } +"columns"\s+[\d]+ { yytext = yytext.replace(/columns\s+/,''); yy.getLogger().info('COLUMNS (LEX)', yytext); return 'COLUMNS'; } ["][`] { this.pushState("md_string");} [^`"]+ { return "MD_STR";} [`]["] { this.popState();} @@ -114,6 +117,7 @@ accDescr\s*"{"\s* { this.pushState("acc_descr_mul /lex +%left '^' %start start %% // language grammar @@ -133,12 +137,8 @@ seperator {yy.getLogger().info('Rule: seperator (EOF) ');} ; -start: BLOCK_DIAGRAM_KEY document; +start: BLOCK_DIAGRAM_KEY document EOF; -blockDiagram - : blockDiagram document { return yy; } - | blockDiagram NL document { return yy; } - ; stop : NL {yy.getLogger().info('Stop NL ');} @@ -149,8 +149,8 @@ stop ; document - : document statement - | statement + : statement { yy.getLogger().info("Rule: statement: ", $1);} + | statement document { yy.getLogger().info("Rule: document statement: ", $1);} ; link @@ -162,6 +162,8 @@ link statement : nodeStatement + | columnsStatement + | 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}); } @@ -171,12 +173,22 @@ statement // | ICON { yy.decorateNode({icon: $1}); } // | CLASS { yy.decorateNode({class: $1}); } // // | SPACELIST - | EOF + ; -nodeStatement: nodeStatement link node { yy.getLogger().info('Rule: nodeStatement (nodeStatement link node) ');} - |node { yy.getLogger().info('Rule: nodeStatement (node) ');} - ; +nodeStatement + : nodeStatement link node { yy.getLogger().info('Rule: nodeStatement (nodeStatement link node) ');} + | node { yy.getLogger().info('Rule: nodeStatement (node) ', $1);} + ; + +columnsStatement + : COLUMNS { yy.getLogger().info("COLUMNS: ", $1);yy.setColumns($1); } + ; + +blockStatement + : block document end { yy.getLogger().info('Rule: blockStatement : ', $1); } + ; + node : NODE_ID diff --git a/packages/mermaid/src/diagrams/block/parser/block.spec.ts b/packages/mermaid/src/diagrams/block/parser/block.spec.ts index 2c575aeba..75cd76b82 100644 --- a/packages/mermaid/src/diagrams/block/parser/block.spec.ts +++ b/packages/mermaid/src/diagrams/block/parser/block.spec.ts @@ -55,19 +55,38 @@ describe('Block diagram', function () { block.parse(str); }); - it.skip('a diagram with column statements', async () => { + it('a diagram with column statements', async () => { const str = `block-beta - columns 1 + columns 2 block1["Block 1"] `; block.parse(str); + expect(db.getColumns('root')).toBe(2); + // Todo: DB check that the we have one block and that the root block has one column + }); + it('a diagram withput column statements', async () => { + const str = `block-beta + block1["Block 1"] + `; + + block.parse(str); + expect(db.getColumns('root')).toBe(-1); + // Todo: DB check that the we have one block and that the root block has one column + }); + it('a diagram with auto column statements', async () => { + const str = `block-beta + columns auto + block1["Block 1"] + `; + + block.parse(str); + expect(db.getColumns('root')).toBe(-1); // Todo: DB check that the we have one block and that the root block has one column }); - it.skip('blocks next to each other', async () => { + it('blocks next to each other', async () => { const str = `block-beta - block columns 2 block1["Block 1"] block2["Block 2"] @@ -78,9 +97,8 @@ describe('Block diagram', function () { // Todo: DB check that the we have two blocks and that the root block has two columns }); - it.skip('blocks on top of each other', async () => { + it('blocks on top of each other', async () => { const str = `block-beta - block columns 1 block1["Block 1"] block2["Block 2"] @@ -91,13 +109,11 @@ describe('Block diagram', function () { // Todo: DB check that the we have two blocks and that the root block has one column }); - it.skip('compound blocks', async () => { - const str = `block + it('compound blocks', async () => { + const str = `block-beta block - columns 2 - block2["Block 2"] - block3["Block 3"] - end %% End the compound block + aBlock["Block"] + end `; block.parse(str); @@ -121,7 +137,7 @@ describe('Block diagram', function () { columns 2 block2["Block 2"] block3["Block 3"] - end %% End the compound block + end `; block.parse(str);