diff --git a/packages/mermaid/src/diagrams/block/blockDB.ts b/packages/mermaid/src/diagrams/block/blockDB.ts index 2ef204430..9717bc348 100644 --- a/packages/mermaid/src/diagrams/block/blockDB.ts +++ b/packages/mermaid/src/diagrams/block/blockDB.ts @@ -18,48 +18,46 @@ import { log } from '../../logger.js'; // export type TBlockColumnsDefaultValue = 'H'; // Do we support something else, like 'auto' | 0? // Initialize the node database for simple lookups -let nodeDatabase: Record = {}; -const blockDatabase: Record = {}; +let blockDatabase: Record = {}; + +const populateBlockDatabase = (blockList: Block[], parent: Block): void => { + for (const block of blockList) { + if (block.type === 'column-setting') { + const columns = block.columns || -1; + parent.columns = columns; + } else { + if (!block.label) { + block.label = block.id; + } + blockDatabase[block.id] = block; + + if (block.children) { + populateBlockDatabase(block.children, block); + } + } + } +}; // Function to get a node by its id type IGetNodeById = (id: string) => Block | undefined; -export const getNodeById = (id: string): Block | undefined => { - console.log(id, nodeDatabase); +export const getBlockById = (id: string): Block | undefined => { return blockDatabase[id]; }; // TODO: Convert to generic TreeNode type? Convert to class? -let rootBlock = { id: 'root', children: [] as Block[], columns: -1 }; let blocks: Block[] = []; const links: Link[] = []; -// let rootBlock = { id: 'root', children: [], columns: -1 } as Block; -let currentBlock = rootBlock; +let rootBlock = { id: 'root', type: 'composite', children: [], columns: -1 } as Block; const clear = (): void => { log.info('Clear called'); - // rootBlocks = []; - blocks = [] as Block[]; commonClear(); - rootBlock = { id: 'root', children: [], columns: -1 }; - currentBlock = rootBlock; - nodeDatabase = {}; - blockDatabase[rootBlock.id] = rootBlock; + rootBlock = { id: 'root', type: 'composite', children: [], columns: -1 } as Block; + blockDatabase = { root: rootBlock }; + blocks = [] as Block[]; }; -// type IAddBlock = (block: Block) => Block; -// const addBlock: IAddBlock = (block: Block, parent?: Block): Block => { -// log.info('addBlock', block, parent); -// if (parent) { -// parent.children ??= []; -// parent.children.push(block); -// } else { -// rootBlock.children.push(block); -// } -// blocks.push(block); -// return block; -// }; - type ITypeStr2Type = (typeStr: string) => BlockType; export function typeStr2Type(typeStr: string) { // TODO: add all types @@ -74,6 +72,7 @@ export function typeStr2Type(typeStr: string) { } let cnt = 0; +type IGenerateId = () => string; export const generateId = () => { cnt++; return 'id-' + Math.random().toString(36).substr(2, 12) + '-' + cnt; @@ -96,13 +95,15 @@ export const addBlock = (_id: string, _label?: string, type?: BlockType) => { blockDatabase[node.id] = node; // currentBlock.children ??= []; // currentBlock.children.push(node); - // console.log('currentBlock', currentBlock.children, nodeDatabase); - console.log('addNode called:', id, label, type, node); + // log.info('currentBlock', currentBlock.children, nodeDatabase); + log.info('addNode called:', id, label, type, node); return node; }; type ISetHierarchy = (block: Block[]) => void; const setHierarchy = (block: Block[]): void => { + populateBlockDatabase(block, rootBlock); + log.info('blockdb', JSON.stringify(blockDatabase, null, 2)); blocks = block; }; @@ -115,7 +116,6 @@ const addLink: IAddLink = (link: Link): 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 => { @@ -149,8 +149,8 @@ const getColumns = (blockid: string): number => { type IGetBlocks = () => Block[]; const getBlocks: IGetBlocks = () => { - // console.log('Block in test', rootBlock.children || []); - console.log('Block in test', blocks, blocks[0].id); + // log.info('Block in test', rootBlock.children || []); + log.info('Block in test', blocks, blocks[0].id); return blocks || []; }; @@ -172,7 +172,8 @@ export interface BlockDB extends DiagramDB { getColumns: IGetColumns; typeStr2Type: ITypeStr2Type; setHierarchy: ISetHierarchy; - getNodeById: IGetNodeById; + getBlockById: IGetNodeById; + generateId: IGenerateId; } const db: BlockDB = { @@ -184,7 +185,7 @@ const db: BlockDB = { getBlocks, getLinks, setHierarchy, - getNodeById, + getBlockById, // getAccTitle, // setAccTitle, // getAccDescription, @@ -194,6 +195,7 @@ const db: BlockDB = { setColumns, getColumns, clear, + generateId, }; export default db; diff --git a/packages/mermaid/src/diagrams/block/blockTypes.ts b/packages/mermaid/src/diagrams/block/blockTypes.ts index 4afbe4351..a695b4ec7 100644 --- a/packages/mermaid/src/diagrams/block/blockTypes.ts +++ b/packages/mermaid/src/diagrams/block/blockTypes.ts @@ -22,7 +22,8 @@ export type BlockType = | 'cylinder' | 'group' | 'doublecircle' - | 'composite'; + | 'composite' + | 'column-setting'; export interface Block { id: string; diff --git a/packages/mermaid/src/diagrams/block/parser/block.jison b/packages/mermaid/src/diagrams/block/parser/block.jison index 309dbfdea..829ccd300 100644 --- a/packages/mermaid/src/diagrams/block/parser/block.jison +++ b/packages/mermaid/src/diagrams/block/parser/block.jison @@ -138,7 +138,7 @@ seperator ; start: BLOCK_DIAGRAM_KEY document EOF - {console.log('This is the hierarchy ', JSON.stringify($2, null, 2)); yy.setHierarchy($2); } + {yy.getLogger().info('This is the hierarchy ', JSON.stringify($2, null, 2)); yy.setHierarchy($2); } ; @@ -180,16 +180,16 @@ statement ; nodeStatement - : nodeStatement link node { yy.getLogger().info('Rule: nodeStatement (nodeStatement link node) '); yy.addBlock($1.id); $$ = {id: $1.id}; } - | node { yy.getLogger().info('Rule: nodeStatement (node) ', $1); yy.addBlock($1.id, $1.label, yy.typeStr2Type($1)); $$ = {id: $1.id}; } + : nodeStatement link node { yy.getLogger().info('Rule: nodeStatement (nodeStatement link node) '); $$ = {id: $1.id}; } + | node { yy.getLogger().info('Rule: nodeStatement (node) ', $1); $$ = {id: $1.id, label: $1.label, type: yy.typeStr2Type($1)}; } ; columnsStatement - : COLUMNS { yy.getLogger().info("COLUMNS: ", $1);yy.setColumns($1); } + : COLUMNS { yy.getLogger().info("COLUMNS: ", $1); $$ = {type: 'column-setting', columns: $1 === 'auto'?-1:parseInt($1) } } ; blockStatement - : block document end { console.log('Rule: blockStatement : ', $1, $2, $3); const block = yy.addBlock(undefined, undefined, 'composite'); $$ = { id: block.id, children: $2 }; } + : block document end { yy.getLogger().info('Rule: blockStatement : ', $1, $2, $3); const id = yy.generateId(); $$ = { id, type:'composite', label:id, children: $2 }; } ; diff --git a/packages/mermaid/src/diagrams/block/parser/block.spec.ts b/packages/mermaid/src/diagrams/block/parser/block.spec.ts index 584a817b5..eea9bb65b 100644 --- a/packages/mermaid/src/diagrams/block/parser/block.spec.ts +++ b/packages/mermaid/src/diagrams/block/parser/block.spec.ts @@ -21,7 +21,7 @@ describe('Block diagram', function () { block.parse(str); const blocks = db.getBlocks(); expect(blocks.length).toBe(1); - expect(blocks[0].ID).toBe('id'); + expect(blocks[0].id).toBe('id'); expect(blocks[0].label).toBe('id'); }); it('a node with a square shape and a label', async () => { @@ -32,7 +32,7 @@ describe('Block diagram', function () { block.parse(str); const blocks = db.getBlocks(); expect(blocks.length).toBe(1); - expect(blocks[0].ID).toBe('id'); + expect(blocks[0].id).toBe('id'); expect(blocks[0].label).toBe('A label'); expect(blocks[0].type).toBe('square'); }); @@ -45,10 +45,10 @@ describe('Block diagram', function () { block.parse(str); const blocks = db.getBlocks(); expect(blocks.length).toBe(2); - expect(blocks[0].ID).toBe('id1'); + expect(blocks[0].id).toBe('id1'); expect(blocks[0].label).toBe('id1'); expect(blocks[0].type).toBe('square'); - expect(blocks[1].ID).toBe('id2'); + expect(blocks[1].id).toBe('id2'); expect(blocks[1].label).toBe('id2'); expect(blocks[1].type).toBe('square'); }); @@ -62,13 +62,13 @@ describe('Block diagram', function () { block.parse(str); const blocks = db.getBlocks(); expect(blocks.length).toBe(3); - expect(blocks[0].ID).toBe('id1'); + expect(blocks[0].id).toBe('id1'); expect(blocks[0].label).toBe('id1'); expect(blocks[0].type).toBe('square'); - expect(blocks[1].ID).toBe('id2'); + expect(blocks[1].id).toBe('id2'); expect(blocks[1].label).toBe('id2'); expect(blocks[1].type).toBe('square'); - expect(blocks[2].ID).toBe('id3'); + expect(blocks[2].id).toBe('id3'); expect(blocks[2].label).toBe('id3'); expect(blocks[2].type).toBe('square'); }); @@ -81,10 +81,10 @@ describe('Block diagram', function () { block.parse(str); const blocks = db.getBlocks(); expect(blocks.length).toBe(2); - expect(blocks[0].ID).toBe('id'); + expect(blocks[0].id).toBe('id'); expect(blocks[0].label).toBe('A label'); expect(blocks[0].type).toBe('square'); - expect(blocks[1].ID).toBe('id2'); + expect(blocks[1].id).toBe('id2'); expect(blocks[1].label).toBe('id2'); expect(blocks[1].type).toBe('square'); }); @@ -152,24 +152,32 @@ describe('Block diagram', function () { it('compound blocks 2', async () => { const str = `block-beta block - aBlock["Block"] - bBlock["Block"] + aBlock["ABlock"] + bBlock["BBlock"] end `; block.parse(str); const blocks = db.getBlocks(); - console.log('blocks', blocks); expect(blocks.length).toBe(1); + expect(blocks[0].children.length).toBe(2); - expect(blocks[0].id).toBe('id'); - expect(blocks[0].label).toBe('A label'); - expect(blocks[0].type).toBe('square'); - // expect(blocks[1].ID).toBe('id2'); - // expect(blocks[1].label).toBe('id2'); - // expect(blocks[1].type).toBe('square'); + expect(blocks[0].id).not.toBe(undefined); + expect(blocks[0].label).toBe(blocks[0].id); + expect(blocks[0].type).toBe('composite'); + + const aBlock = blocks[0].children[0]; + + expect(aBlock.id).not.toBe(aBlock); + expect(aBlock.label).toBe('ABlock'); + expect(aBlock.type).toBe('square'); + + const bBlock = blocks[0].children[1]; + expect(bBlock.id).not.toBe(bBlock); + expect(bBlock.label).toBe('BBlock'); + expect(bBlock.type).toBe('square'); }); - it.only('compound blocks', async () => { + it('compound blocks of compound blocks', async () => { const str = `block-beta block aBlock["ABlock"] @@ -182,29 +190,30 @@ describe('Block diagram', function () { block.parse(str); const blocks = db.getBlocks(); - const aBlockPos = blocks[0].children[0]; - const bBlockPos = blocks[0].children[1].children[0]; + const aBlock = blocks[0].children[0]; + const secondComposite = blocks[0].children[1]; + const bBlock = blocks[0].children[1].children[0]; - const root = db.getNodeById(blocks[0].id); - expect(blocks.length).toBe(1); - expect(blocks[0].id).not.toBe(undefined); - expect(root?.label).toBe(blocks[0].id); expect(blocks[0].children.length).toBe(2); - expect(root?.type).toBe('composite'); + expect(blocks[0].id).not.toBe(undefined); + expect(blocks[0].label).toBe(blocks[0].id); + expect(blocks[0].type).toBe('composite'); - const aBlock = db.getNodeById(aBlockPos.id); - console.log('aBlock', aBlock); - expect(aBlock?.label).toBe('ABlock'); - expect(aBlock?.type).toBe('square'); + expect(secondComposite.children.length).toBe(1); + expect(secondComposite.id).not.toBe(undefined); + expect(secondComposite.label).toBe(secondComposite.id); + expect(secondComposite.type).toBe('composite'); - const bBlock = db.getNodeById(bBlockPos.id); + expect(aBlock.id).not.toBe(aBlock); + expect(aBlock.label).toBe('ABlock'); + expect(aBlock.type).toBe('square'); - expect(bBlock.id).toBe('bBlock'); + expect(bBlock.id).not.toBe(bBlock); expect(bBlock.label).toBe('BBlock'); expect(bBlock.type).toBe('square'); }); - it.skip('compound blocks with title', async () => { - const str = `block + it('compound blocks with title', async () => { + const str = `block-beta block compoundBlock["Compound block"] columns 1 block2["Block 1"]