MermaidRenderer turns a rule or expression into Mermaid flowchart syntax.
This is useful for architecture documents, rule reviews, generated docs, or debugging complex expressions visually.
Import it from the optional rendering entry point:
import { DefaultMermaidTheme, MermaidRenderer } from '@samatawy/rules/render';
import { RuleParser, Workspace } from '@samatawy/rules';
import { DefaultMermaidTheme, MermaidRenderer } from '@samatawy/rules/render';
const space = new Workspace();
const parser = new RuleParser({ workspace: space });
const rule = parser.parse('IF total > 100 THEN discount = 0.1');
const renderer = new MermaidRenderer();
renderer.setStyles(DefaultMermaidTheme.styles());
const graph = renderer.render(rule);
If you render a rule, the output starts with a Mermaid flowchart declaration and includes IF, THEN, ELSE, or SET subgraphs where relevant.
If you render only an expression, the output starts with graph and focuses on the expression tree.
The renderer supports Mermaid's common directional layouts:
LR for left-to-rightRL for right-to-leftTD for top-downBT for bottom-upExample:
const renderer = new MermaidRenderer();
renderer.setLayout('TD');
renderer.setStyles(DefaultMermaidTheme.styles());
LR is the default.
Unlike the HTML renderer, Mermaid styling is always emitted as Mermaid classDef statements. That means setStyle() and setStyles() affect the rendered graph text directly.
Example customization:
const renderer = new MermaidRenderer();
renderer.setStyles(DefaultMermaidTheme.styles());
renderer.setStyle('variable', {
fill: 'darkgreen',
color: 'white',
stroke: 'lightgreen',
});
renderer.setStyle('block', {
fill: 'transparent',
stroke: 'slategray',
rx: '16',
ry: '16',
});
Supported Mermaid style properties are:
colorrxryfillstrokestroke-widthopacityfont-sizefont-weightfont-stylefont-familyDefaultMermaidTheme.styles() provides a ready-made theme for the built-in element types such as variables, literals, functions, operators, commands, and grouped blocks.
The expression price * quantity * (1 - discount) is parsed and rendered as a graph where operator nodes pull from their operand nodes:
import { ExpressionParser, Workspace } from '@samatawy/rules';
import { DefaultMermaidTheme, MermaidRenderer } from '@samatawy/rules/render';
const space = new Workspace();
const ep = new ExpressionParser({ workspace: space });
const expr = ep.parse('price * quantity * (1 - discount)');
const renderer = new MermaidRenderer();
renderer.setStyles(DefaultMermaidTheme.styles());
const graph = renderer.render(expr);
The resulting graph:
graph LR
classDef operator fill: transparent, color: cyan, rx: 12, ry: 12;
classDef literal fill: black, stroke: orange, color: orange;
classDef variable fill: darkgreen, color: lightgreen, stroke: lightgreen;
node1["×"]:::operator
node2["price"]:::variable
node3["×"]:::operator
node4["quantity"]:::variable
node5["−"]:::operator
node6[1]:::literal
node7["discount"]:::variable
node6 --> node5
node7 --> node5
node4 --> node3
node5 --> node3
node2 --> node1
node3 --> node1The rule IF order.total > 1000 THEN order.discount = 0.10 ELSE order.discount = 0.05 renders as a flowchart with IF, THEN, and ELSE subgraphs:
import { RuleParser, Workspace } from '@samatawy/rules';
import { DefaultMermaidTheme, MermaidRenderer } from '@samatawy/rules/render';
const space = new Workspace();
const rp = new RuleParser({ workspace: space });
const rule = rp.parse('IF order.total > 1000 THEN order.discount = 0.10 ELSE order.discount = 0.05');
const renderer = new MermaidRenderer();
renderer.setStyles(DefaultMermaidTheme.styles());
const graph = renderer.render(rule);
The resulting graph:
flowchart LR
classDef block fill: transparent, stroke: gray, rx: 24, ry: 24;
classDef operator fill: transparent, color: cyan, rx: 12, ry: 12;
classDef literal fill: black, stroke: orange, color: orange;
classDef variable fill: darkgreen, color: lightgreen, stroke: lightgreen;
subgraph IF["IF"]
direction LR
node1[">"]:::operator
node2["order.total"]:::variable
node3[1000]:::literal
node2 --> node1
node3 --> node1
end
style IF fill: transparent, stroke: gray, rx: 24, ry: 24;
subgraph THEN["THEN"]
direction LR
node4["order.discount"]:::variable
node5[0.1]:::literal
node5 --> node4
end
style THEN fill: transparent, stroke: gray, rx: 24, ry: 24;
IF -- true --> THEN
subgraph ELSE["ELSE"]
direction LR
node6["order.discount"]:::variable
node7[0.05]:::literal
node7 --> node6
end
style ELSE fill: transparent, stroke: gray, rx: 24, ry: 24;
IF -- false --> ELSEIF, THEN, ELSE, and SET sections become Mermaid subgraphs.The block style is applied to grouped rule sections and grouped expression containers such as ternaries and switches.
toJson(), a custom Mermaid theme can be swapped in without changing any parsing or evaluation logic.