mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-20 15:59:51 +02:00
#3358 Adding db calls from node statements
This commit is contained in:
@@ -58,13 +58,8 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<pre id="diagram" class="mermaid">
|
<pre id="diagram" class="mermaid">
|
||||||
stateDiagram-v2
|
block-beta
|
||||||
[*] --> Still
|
id</pre
|
||||||
Still --> [*]
|
|
||||||
Still --> Moving
|
|
||||||
Moving --> Still
|
|
||||||
Moving --> Crash
|
|
||||||
Crash --> [*] </pre
|
|
||||||
>
|
>
|
||||||
<pre id="diagram" class="mermaid2">
|
<pre id="diagram" class="mermaid2">
|
||||||
flowchart RL
|
flowchart RL
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// import type { BlockDB } from './blockTypes.js';
|
// import type { BlockDB } from './blockTypes.js';
|
||||||
import type { DiagramDB } from '../../diagram-api/types.js';
|
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||||
import { BlockConfig } from './blockTypes.js';
|
import { BlockConfig, BlockType, Block, Link } from './blockTypes.js';
|
||||||
|
|
||||||
import * as configApi from '../../config.js';
|
import * as configApi from '../../config.js';
|
||||||
// import common from '../common/common.js';
|
// import common from '../common/common.js';
|
||||||
@@ -13,47 +13,78 @@ import {
|
|||||||
// getDiagramTitle,
|
// getDiagramTitle,
|
||||||
clear as commonClear,
|
clear as commonClear,
|
||||||
} from '../../commonDb.js';
|
} from '../../commonDb.js';
|
||||||
|
import { log } from '../../logger.js';
|
||||||
|
|
||||||
// export type TBlockColumnsDefaultValue = 'H'; // Do we support something else, like 'auto' | 0?
|
// export type TBlockColumnsDefaultValue = 'H'; // Do we support something else, like 'auto' | 0?
|
||||||
|
|
||||||
|
// Initialize the node database for simple lookups
|
||||||
|
let nodeDatabase: Record<string, Node> = {};
|
||||||
|
const blockDatabase: Record<string, Block> = {};
|
||||||
|
|
||||||
|
// Function to get a node by its ID
|
||||||
|
export const getNodeById = (id: string): Node | undefined => {
|
||||||
|
return nodeDatabase[id];
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: Convert to generic TreeNode type? Convert to class?
|
// TODO: Convert to generic TreeNode type? Convert to class?
|
||||||
export interface Block {
|
|
||||||
ID: string;
|
|
||||||
label?: string;
|
|
||||||
parent?: Block;
|
|
||||||
children?: Block[];
|
|
||||||
columns?: number; // | TBlockColumnsDefaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Link {
|
let rootBlock = { ID: 'root', children: [] as Block[], columns: -1 };
|
||||||
source: Block;
|
|
||||||
target: Block;
|
|
||||||
}
|
|
||||||
|
|
||||||
let rootBlocks: Block[] = [];
|
|
||||||
let blocks: Block[] = [];
|
let blocks: Block[] = [];
|
||||||
const links: Link[] = [];
|
const links: Link[] = [];
|
||||||
let rootBlock = { ID: 'root', children: [], columns: -1 } as Block;
|
// let rootBlock = { ID: 'root', children: [], columns: -1 } as Block;
|
||||||
let currentBlock: Block | undefined;
|
let currentBlock = rootBlock;
|
||||||
|
|
||||||
const clear = (): void => {
|
const clear = (): void => {
|
||||||
rootBlocks = [];
|
log.info('Clear called');
|
||||||
blocks = [];
|
// rootBlocks = [];
|
||||||
|
blocks = [] as Block[];
|
||||||
commonClear();
|
commonClear();
|
||||||
rootBlock = { ID: 'root', children: [], columns: -1 };
|
rootBlock = { ID: 'root', children: [], columns: -1 };
|
||||||
currentBlock = rootBlock;
|
currentBlock = rootBlock;
|
||||||
|
nodeDatabase = {};
|
||||||
|
blockDatabase[rootBlock.ID] = rootBlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IAddBlock = (block: Block) => Block;
|
// type IAddBlock = (block: Block) => Block;
|
||||||
const addBlock: IAddBlock = (block: Block, parent?: Block): Block => {
|
// const addBlock: IAddBlock = (block: Block, parent?: Block): Block => {
|
||||||
if (parent) {
|
// log.info('addBlock', block, parent);
|
||||||
parent.children ??= [];
|
// if (parent) {
|
||||||
parent.children.push(block);
|
// parent.children ??= [];
|
||||||
} else {
|
// parent.children.push(block);
|
||||||
rootBlocks.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
|
||||||
|
switch (typeStr) {
|
||||||
|
case '[]':
|
||||||
|
return 'square';
|
||||||
|
case '()':
|
||||||
|
return 'round';
|
||||||
|
default:
|
||||||
|
return 'square';
|
||||||
}
|
}
|
||||||
blocks.push(block);
|
}
|
||||||
return block;
|
|
||||||
|
type IAddBlock = (id: string, label: string, type: BlockType) => Block;
|
||||||
|
// Function to add a node to the database
|
||||||
|
export const addBlock = (id: string, _label?: string, type?: BlockType) => {
|
||||||
|
log.info('addNode called:', id, _label, type);
|
||||||
|
const label = _label || id;
|
||||||
|
const node: Block = {
|
||||||
|
ID: id,
|
||||||
|
label,
|
||||||
|
type: type || 'square',
|
||||||
|
};
|
||||||
|
blockDatabase[node.ID] = node;
|
||||||
|
currentBlock.children ??= [];
|
||||||
|
currentBlock.children.push(node);
|
||||||
|
return node;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IAddLink = (link: Link) => Link;
|
type IAddLink = (link: Link) => Link;
|
||||||
@@ -84,16 +115,21 @@ const getBlock = (id: string, blocks: Block[]): Block | undefined => {
|
|||||||
|
|
||||||
type IGetColumns = (blockID: string) => number;
|
type IGetColumns = (blockID: string) => number;
|
||||||
const getColumns = (blockID: string): number => {
|
const getColumns = (blockID: string): number => {
|
||||||
const blocks = [rootBlock];
|
const block = blockDatabase[blockID];
|
||||||
const block = getBlock(blockID, blocks);
|
|
||||||
if (!block) {
|
if (!block) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return block.columns || -1;
|
if (block.columns) {
|
||||||
|
return block.columns;
|
||||||
|
}
|
||||||
|
if (!block.children) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return block.children.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IGetBlocks = () => Block[];
|
type IGetBlocks = () => Block[];
|
||||||
const getBlocks: IGetBlocks = () => blocks;
|
const getBlocks: IGetBlocks = () => rootBlock.children || [];
|
||||||
|
|
||||||
type IGetLinks = () => Link[];
|
type IGetLinks = () => Link[];
|
||||||
const getLinks: IGetLinks = () => links;
|
const getLinks: IGetLinks = () => links;
|
||||||
@@ -111,12 +147,14 @@ export interface BlockDB extends DiagramDB {
|
|||||||
getLinks: IGetLinks;
|
getLinks: IGetLinks;
|
||||||
setColumns: ISetColumns;
|
setColumns: ISetColumns;
|
||||||
getColumns: IGetColumns;
|
getColumns: IGetColumns;
|
||||||
|
typeStr2Type: ITypeStr2Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
const db: BlockDB = {
|
const db: BlockDB = {
|
||||||
getConfig: () => configApi.getConfig().block,
|
getConfig: () => configApi.getConfig().block,
|
||||||
addBlock: addBlock,
|
addBlock: addBlock,
|
||||||
addLink: addLink,
|
addLink: addLink,
|
||||||
|
typeStr2Type: typeStr2Type,
|
||||||
getLogger, // TODO: remove
|
getLogger, // TODO: remove
|
||||||
getBlocks,
|
getBlocks,
|
||||||
getLinks,
|
getLinks,
|
||||||
|
@@ -3,3 +3,36 @@ import type { BaseDiagramConfig } from '../../config.type.js';
|
|||||||
export interface BlockConfig extends BaseDiagramConfig {
|
export interface BlockConfig extends BaseDiagramConfig {
|
||||||
padding?: number;
|
padding?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type BlockType =
|
||||||
|
| 'round'
|
||||||
|
| 'square'
|
||||||
|
| 'diamond'
|
||||||
|
| 'hexagon'
|
||||||
|
| 'odd'
|
||||||
|
| 'lean_right'
|
||||||
|
| 'lean_left'
|
||||||
|
| 'trapezoid'
|
||||||
|
| 'inv_trapezoid'
|
||||||
|
| 'odd_right'
|
||||||
|
| 'circle'
|
||||||
|
| 'ellipse'
|
||||||
|
| 'stadium'
|
||||||
|
| 'subroutine'
|
||||||
|
| 'cylinder'
|
||||||
|
| 'group'
|
||||||
|
| 'doublecircle';
|
||||||
|
|
||||||
|
export interface Block {
|
||||||
|
ID: string;
|
||||||
|
label?: string;
|
||||||
|
parent?: Block;
|
||||||
|
type?: BlockType;
|
||||||
|
children?: Block[];
|
||||||
|
columns?: number; // | TBlockColumnsDefaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Link {
|
||||||
|
source: Block;
|
||||||
|
target: Block;
|
||||||
|
}
|
||||||
|
@@ -64,7 +64,7 @@ accDescr\s*"{"\s* { this.pushState("acc_descr_mul
|
|||||||
|
|
||||||
// Start of nodes with shapes and description
|
// Start of nodes with shapes and description
|
||||||
"-)" { yy.getLogger().info('Lex: -)'); this.pushState('NODE');return 'NODE_D START'; }
|
"-)" { yy.getLogger().info('Lex: -)'); this.pushState('NODE');return 'NODE_D START'; }
|
||||||
"(-" { 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'; }
|
||||||
@@ -177,8 +177,8 @@ statement
|
|||||||
;
|
;
|
||||||
|
|
||||||
nodeStatement
|
nodeStatement
|
||||||
: nodeStatement link node { yy.getLogger().info('Rule: nodeStatement (nodeStatement link node) ');}
|
: nodeStatement link node { yy.getLogger().info('Rule: nodeStatement (nodeStatement link node) '); yy.addBlock($1.id);}
|
||||||
| node { yy.getLogger().info('Rule: nodeStatement (node) ', $1);}
|
| node { yy.getLogger().info('Rule: nodeStatement (node) ', $1); yy.addBlock($1.id, $1.label, yy.typeStr2Type($1)); }
|
||||||
;
|
;
|
||||||
|
|
||||||
columnsStatement
|
columnsStatement
|
||||||
@@ -192,16 +192,16 @@ blockStatement
|
|||||||
|
|
||||||
node
|
node
|
||||||
: NODE_ID
|
: NODE_ID
|
||||||
{ yy.getLogger().info("Rule: node (NODE_ID seperator): ", $1); }
|
{ yy.getLogger().info("Rule: node (NODE_ID seperator): ", $1); $$ = { id: $1 }; }
|
||||||
|NODE_ID nodeShapeNLabel
|
|NODE_ID nodeShapeNLabel
|
||||||
{ yy.getLogger().info("Rule: node (NODE_ID nodeShapeNLabel seperator): ", $1, $2); }
|
{ yy.getLogger().info("Rule: node (NODE_ID nodeShapeNLabel seperator): ", $1, $2); $$ = { id: $1, label: $2.label, typeStr: $2.typeStr };}
|
||||||
// |nodeShapeNLabel seperator
|
// |nodeShapeNLabel seperator
|
||||||
// { yy.getLogger().info("Rule: node (nodeShapeNLabel seperator): ", $1, $2, $3); }
|
// { yy.getLogger().info("Rule: node (nodeShapeNLabel seperator): ", $1, $2, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
nodeShapeNLabel
|
nodeShapeNLabel
|
||||||
: NODE_DSTART STR NODE_DEND
|
: NODE_DSTART STR NODE_DEND
|
||||||
{ yy.getLogger().info("Rule: nodeShapeNLabel: ", $1, $2, $3); $$ = { type: $1 + $3, descr: $2 }; }
|
{ yy.getLogger().info("Rule: nodeShapeNLabel: ", $1, $2, $3); $$ = { typeStr: $1 + $3, label: $2 }; }
|
||||||
;
|
;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
@@ -3,8 +3,7 @@ import block from './block.jison';
|
|||||||
import db from '../blockDB.js';
|
import db from '../blockDB.js';
|
||||||
import { cleanupComments } from '../../../diagram-api/comments.js';
|
import { cleanupComments } from '../../../diagram-api/comments.js';
|
||||||
import { prepareTextForParsing } from '../blockUtils.js';
|
import { prepareTextForParsing } from '../blockUtils.js';
|
||||||
import * as fs from 'fs';
|
import { setConfig } from '../../../config.js';
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
describe('Block diagram', function () {
|
describe('Block diagram', function () {
|
||||||
describe('when parsing an block diagram graph it should handle > ', function () {
|
describe('when parsing an block diagram graph it should handle > ', function () {
|
||||||
@@ -20,6 +19,22 @@ describe('Block diagram', function () {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
block.parse(str);
|
block.parse(str);
|
||||||
|
const blocks = db.getBlocks();
|
||||||
|
expect(blocks.length).toBe(1);
|
||||||
|
expect(blocks[0].ID).toBe('id');
|
||||||
|
expect(blocks[0].label).toBe('id');
|
||||||
|
});
|
||||||
|
it('a node with a square shape and a label', async () => {
|
||||||
|
const str = `block-beta
|
||||||
|
id["A label"]
|
||||||
|
`;
|
||||||
|
|
||||||
|
block.parse(str);
|
||||||
|
const blocks = db.getBlocks();
|
||||||
|
expect(blocks.length).toBe(1);
|
||||||
|
expect(blocks[0].ID).toBe('id');
|
||||||
|
expect(blocks[0].label).toBe('A label');
|
||||||
|
expect(blocks[0].type).toBe('square');
|
||||||
});
|
});
|
||||||
it('a diagram with multiple nodes', async () => {
|
it('a diagram with multiple nodes', async () => {
|
||||||
const str = `block-beta
|
const str = `block-beta
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import flowDb from '../flowDb.js';
|
import flowDb from '../flowDb.js';
|
||||||
import flow from './flow.jison';
|
import flow from './flow.jison';
|
||||||
import { setConfig } from '../../../config.js';
|
|
||||||
import { cleanupComments } from '../../../diagram-api/comments.js';
|
import { cleanupComments } from '../../../diagram-api/comments.js';
|
||||||
|
import { setConfig } from '../../../config.js';
|
||||||
|
|
||||||
setConfig({
|
setConfig({
|
||||||
securityLevel: 'strict',
|
securityLevel: 'strict',
|
||||||
|
Reference in New Issue
Block a user