diff --git a/.build/jsonSchema.ts b/.build/jsonSchema.ts
index c1ff5f481de..7715a96c434 100644
--- a/.build/jsonSchema.ts
+++ b/.build/jsonSchema.ts
@@ -27,6 +27,7 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
'sankey',
'block',
'packet',
+ 'treeView',
'architecture',
'radar',
'venn',
diff --git a/.changeset/weak-tools-pay.md b/.changeset/weak-tools-pay.md
new file mode 100644
index 00000000000..60776a1bb73
--- /dev/null
+++ b/.changeset/weak-tools-pay.md
@@ -0,0 +1,7 @@
+---
+'@mermaid-js/examples': minor
+'mermaid': minor
+'@mermaid-js/parser': minor
+---
+
+add new TreeView diagram
diff --git a/cypress/integration/rendering/treeView.spec.ts b/cypress/integration/rendering/treeView.spec.ts
new file mode 100644
index 00000000000..837f7d2521f
--- /dev/null
+++ b/cypress/integration/rendering/treeView.spec.ts
@@ -0,0 +1,75 @@
+import { imgSnapshotTest } from '../../helpers/util';
+
+describe('TreeView Diagram', () => {
+ it('should render a simple treeView diagram', () => {
+ imgSnapshotTest(
+ `treeView-beta
+ "file1.ts"`
+ );
+ });
+
+ it('should render a complex treeView diagram', () => {
+ imgSnapshotTest(
+ `treeView-beta
+ "root"
+ "folder1"
+ "file1.js"
+ "file2.ts"
+ "folder2"
+ "file3.spec.ts"
+ "folder3"
+ "file4.ts"
+ "file5.ts"
+ "folder4"
+ "file6.ts"
+ "file7.ts"`
+ );
+ });
+
+ it('should render a complex treeView diagram with multiple roots', () => {
+ imgSnapshotTest(
+ `treeView-beta
+ "folder1"
+ "file1.js"
+ "file2.ts"
+ "folder2"
+ "file3.spec.ts"
+ "folder3"
+ "file4.ts"
+ "file5.ts"
+ "folder4"
+ "file6.ts"
+ "file7.ts"`
+ );
+ });
+
+ it('should render a treeView diagram with custom config', () => {
+ imgSnapshotTest(
+ `
+---
+config:
+ treeView:
+ rowIndent: 80
+ lineThickness: 3
+ themeVariables:
+ treeView:
+ labelFontSize: '20px'
+ labelColor: '#FF0000'
+ lineColor: '#00FF00'
+---
+treeView-beta
+ "folder1"
+ "file1.js"
+ "file2.ts"
+ "folder2"
+ "file3.spec.ts"
+ "folder3"
+ "file4.ts"
+ "file5.ts"
+ "folder4"
+ "file6.ts"
+ "file7.ts"
+ `
+ );
+ });
+});
diff --git a/demos/index.html b/demos/index.html
index c5a062cd94b..9a74804e579 100644
--- a/demos/index.html
+++ b/demos/index.html
@@ -1,105 +1,108 @@
-
-
-
-
-
- Mermaid Quick Test Page
-
-
-
-
-
- Mermaid quick test and demo pages
-
- Some of these pages have duplicates; some are slow to load because they have so many graphs.
-
- You can test custom code in the development page.
-
- If you'd like to clean up one of the pages, please feel free to
- submit a pull request (PR).
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
-
+
+
+
+
+
+ Mermaid Quick Test Page
+
+
+
+
+
+ Mermaid quick test and demo pages
+
+ Some of these pages have duplicates; some are slow to load because they have so many graphs.
+
+ You can test custom code in the development page.
+
+ If you'd like to clean up one of the pages, please feel free to
+ submit a pull request (PR).
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
diff --git a/demos/treeView.html b/demos/treeView.html
new file mode 100644
index 00000000000..174830fa102
--- /dev/null
+++ b/demos/treeView.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+ Mermaid TreeView Diagram Demo
+
+
+
+
+ TreeView Diagram Demo
+
+ Basic TreeView Example
+
+ treeView-beta
+ "docs"
+ "build"
+ "make.bat"
+ "Makefile"
+ "out"
+ "source"
+ "build"
+ "static"
+ "_templates"
+ "div. Files"
+
+
+ TreeView Config Example
+
+ ---
+ config:
+ treeView:
+ rowIndent: 80
+ lineThickness: 3
+ themeVariables:
+ treeView:
+ labelFontSize: '20px'
+ labelColor: '#FF0000'
+ lineColor: '#00FF00'
+ ---
+ treeView-beta
+ "packages"
+ "mermaid"
+ "src"
+ "parser"
+
+
+
+
+
diff --git a/docs/config/setup/defaultConfig/variables/configKeys.md b/docs/config/setup/defaultConfig/variables/configKeys.md
index 2e7258bb854..056ef6cbd2f 100644
--- a/docs/config/setup/defaultConfig/variables/configKeys.md
+++ b/docs/config/setup/defaultConfig/variables/configKeys.md
@@ -12,4 +12,4 @@
> `const` **configKeys**: `Set`<`string`>
-Defined in: [packages/mermaid/src/defaultConfig.ts:298](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L298)
+Defined in: [packages/mermaid/src/defaultConfig.ts:302](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L302)
diff --git a/docs/config/setup/mermaid/interfaces/MermaidConfig.md b/docs/config/setup/mermaid/interfaces/MermaidConfig.md
index 8d1fea23e59..dd84eaea0d0 100644
--- a/docs/config/setup/mermaid/interfaces/MermaidConfig.md
+++ b/docs/config/setup/mermaid/interfaces/MermaidConfig.md
@@ -105,7 +105,7 @@ You can set this attribute to base the seed on a static string.
> `optional` **dompurifyConfig**: `Config`
-Defined in: [packages/mermaid/src/config.type.ts:222](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L222)
+Defined in: [packages/mermaid/src/config.type.ts:223](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L223)
---
@@ -179,7 +179,7 @@ See
> `optional` **fontSize**: `number`
-Defined in: [packages/mermaid/src/config.type.ts:224](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L224)
+Defined in: [packages/mermaid/src/config.type.ts:225](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L225)
---
@@ -305,7 +305,7 @@ Defines which main look to use for the diagram.
> `optional` **markdownAutoWrap**: `boolean`
-Defined in: [packages/mermaid/src/config.type.ts:225](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L225)
+Defined in: [packages/mermaid/src/config.type.ts:226](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L226)
---
@@ -365,7 +365,7 @@ Defined in: [packages/mermaid/src/config.type.ts:208](https://github.com/mermaid
> `optional` **radar**: `RadarDiagramConfig`
-Defined in: [packages/mermaid/src/config.type.ts:220](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L220)
+Defined in: [packages/mermaid/src/config.type.ts:221](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L221)
---
@@ -437,7 +437,7 @@ Defined in: [packages/mermaid/src/config.type.ts:205](https://github.com/mermaid
> `optional` **suppressErrorRendering**: `boolean`
-Defined in: [packages/mermaid/src/config.type.ts:231](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L231)
+Defined in: [packages/mermaid/src/config.type.ts:232](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L232)
Suppresses inserting 'Syntax error' diagram in the DOM.
This is useful when you want to control how to handle syntax errors in your application.
@@ -479,11 +479,19 @@ Defined in: [packages/mermaid/src/config.type.ts:203](https://github.com/mermaid
---
+### treeView?
+
+> `optional` **treeView**: `TreeViewDiagramConfig`
+
+Defined in: [packages/mermaid/src/config.type.ts:220](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L220)
+
+---
+
### venn?
> `optional` **venn**: `VennDiagramConfig`
-Defined in: [packages/mermaid/src/config.type.ts:221](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L221)
+Defined in: [packages/mermaid/src/config.type.ts:222](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L222)
---
@@ -491,7 +499,7 @@ Defined in: [packages/mermaid/src/config.type.ts:221](https://github.com/mermaid
> `optional` **wrap**: `boolean`
-Defined in: [packages/mermaid/src/config.type.ts:223](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L223)
+Defined in: [packages/mermaid/src/config.type.ts:224](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L224)
---
diff --git a/docs/syntax/treeView.md b/docs/syntax/treeView.md
new file mode 100644
index 00000000000..4f4b1ee91cd
--- /dev/null
+++ b/docs/syntax/treeView.md
@@ -0,0 +1,97 @@
+> **Warning**
+>
+> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
+>
+> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/treeView.md](../../packages/mermaid/src/docs/syntax/treeView.md).
+
+# TreeView Diagram (v\+)
+
+## Introduction
+
+A TreeView diagram is used to represent hierarchical data in the form of a directory-like structure.
+
+## Syntax
+
+The structure of the tree depends only on indentation.
+
+```
+treeView-beta
+ ""
+ ""
+ ""
+ ""
+ ""
+```
+
+## Examples
+
+```mermaid-example
+treeView-beta
+ "packages"
+ "mermaid"
+ "src"
+ "parser"
+```
+
+```mermaid
+treeView-beta
+ "packages"
+ "mermaid"
+ "src"
+ "parser"
+```
+
+```mermaid-example
+---
+config:
+ treeView:
+ rowIndent: 80
+ lineThickness: 3
+ themeVariables:
+ treeView:
+ labelFontSize: '20px'
+ labelColor: '#FF0000'
+ lineColor: '#00FF00'
+---
+treeView-beta
+ "packages"
+ "mermaid"
+ "src"
+ "parser"
+```
+
+```mermaid
+---
+config:
+ treeView:
+ rowIndent: 80
+ lineThickness: 3
+ themeVariables:
+ treeView:
+ labelFontSize: '20px'
+ labelColor: '#FF0000'
+ lineColor: '#00FF00'
+---
+treeView-beta
+ "packages"
+ "mermaid"
+ "src"
+ "parser"
+```
+
+## Config Variables
+
+| Property | Description | Default Value |
+| ------------- | ------------------------- | ------------- |
+| rowIndent | Indentation for each row | 10 |
+| paddingX | Horizontal padding of row | 5 |
+| paddingY | Vertical padding of row | 5 |
+| lineThickness | Thickness of the line | 1 |
+
+### Theme Variables
+
+| Property | Description | Default Value |
+| ------------- | ---------------------- | ------------- |
+| labelFontSize | Font size of the label | '16px' |
+| labelColor | Color of the label | 'black' |
+| lineColor | Color of the line | 'black' |
diff --git a/packages/examples/src/examples/tree-view.ts b/packages/examples/src/examples/tree-view.ts
new file mode 100644
index 00000000000..009b24348ec
--- /dev/null
+++ b/packages/examples/src/examples/tree-view.ts
@@ -0,0 +1,24 @@
+import type { DiagramMetadata } from '../types.js';
+
+export default {
+ id: 'treeView',
+ name: 'TreeView',
+ description: 'Visualize hierarchical data as a tree structure',
+ examples: [
+ {
+ title: 'Basic TreeView',
+ isDefault: true,
+ code: `treeView-beta
+ "docs"
+ "build"
+ "make.bat"
+ "Makefile"
+ "out"
+ "source"
+ "build"
+ "static"
+ "_templates"
+ "div. Files"`,
+ },
+ ],
+} satisfies DiagramMetadata;
diff --git a/packages/examples/src/index.ts b/packages/examples/src/index.ts
index 720d2d6da3b..09421075afb 100644
--- a/packages/examples/src/index.ts
+++ b/packages/examples/src/index.ts
@@ -23,6 +23,7 @@ import packetDiagram from './examples/packet.js';
import blockDiagram from './examples/block.js';
import treemapDiagram from './examples/treemap.js';
import vennDiagram from './examples/venn.js';
+import treeViewDiagram from './examples/tree-view.js';
export const diagramData: DiagramMetadata[] = [
flowChart,
@@ -49,4 +50,5 @@ export const diagramData: DiagramMetadata[] = [
blockDiagram,
treemapDiagram,
vennDiagram,
+ treeViewDiagram,
];
diff --git a/packages/mermaid/src/config.type.ts b/packages/mermaid/src/config.type.ts
index f2600160682..25759f9b80d 100644
--- a/packages/mermaid/src/config.type.ts
+++ b/packages/mermaid/src/config.type.ts
@@ -217,6 +217,7 @@ export interface MermaidConfig {
sankey?: SankeyDiagramConfig;
packet?: PacketDiagramConfig;
block?: BlockDiagramConfig;
+ treeView?: TreeViewDiagramConfig;
radar?: RadarDiagramConfig;
venn?: VennDiagramConfig;
dompurifyConfig?: DOMPurifyConfiguration;
@@ -1613,6 +1614,30 @@ export interface PacketDiagramConfig extends BaseDiagramConfig {
export interface BlockDiagramConfig extends BaseDiagramConfig {
padding?: number;
}
+/**
+ * The object containing configurations specific for treeView diagrams.
+ *
+ * This interface was referenced by `MermaidConfig`'s JSON-Schema
+ * via the `definition` "TreeViewDiagramConfig".
+ */
+export interface TreeViewDiagramConfig extends BaseDiagramConfig {
+ /**
+ * Horizontal distance between rows differing by one level
+ */
+ rowIndent?: number;
+ /**
+ * Horizontal padding of label
+ */
+ paddingX?: number;
+ /**
+ * Vertical padding of label
+ */
+ paddingY?: number;
+ /**
+ * Thickness of the line
+ */
+ lineThickness?: number;
+}
/**
* The object containing configurations specific for radar diagrams.
*
diff --git a/packages/mermaid/src/defaultConfig.ts b/packages/mermaid/src/defaultConfig.ts
index 49731b311ab..659081921e3 100644
--- a/packages/mermaid/src/defaultConfig.ts
+++ b/packages/mermaid/src/defaultConfig.ts
@@ -261,6 +261,10 @@ const config: RequiredDeep = {
packet: {
...defaultConfigJson.packet,
},
+ treeView: {
+ ...defaultConfigJson.treeView,
+ useWidth: undefined,
+ },
radar: {
...defaultConfigJson.radar,
},
diff --git a/packages/mermaid/src/diagram-api/diagram-orchestration.ts b/packages/mermaid/src/diagram-api/diagram-orchestration.ts
index e365a6227ce..88f71a07e9e 100644
--- a/packages/mermaid/src/diagram-api/diagram-orchestration.ts
+++ b/packages/mermaid/src/diagram-api/diagram-orchestration.ts
@@ -24,6 +24,7 @@ import sankey from '../diagrams/sankey/sankeyDetector.js';
import { packet } from '../diagrams/packet/detector.js';
import { radar } from '../diagrams/radar/detector.js';
import block from '../diagrams/block/blockDetector.js';
+import treeView from '../diagrams/treeView/detector.js';
import architecture from '../diagrams/architecture/architectureDetector.js';
import { ishikawa } from '../diagrams/ishikawa/ishikawaDetector.js';
import venn from '../diagrams/venn/vennDetector.js';
@@ -102,6 +103,7 @@ export const addDiagrams = () => {
packet,
xychart,
block,
+ treeView,
radar,
ishikawa,
treemap,
diff --git a/packages/mermaid/src/diagrams/treeView/db.ts b/packages/mermaid/src/diagrams/treeView/db.ts
new file mode 100644
index 00000000000..db18b948c5d
--- /dev/null
+++ b/packages/mermaid/src/diagrams/treeView/db.ts
@@ -0,0 +1,79 @@
+import type { TreeViewDiagramConfig } from '../../config.type.js';
+import type { TreeViewDB, Node } from './types.js';
+import { getConfig as getCommonConfig } from '../../config.js';
+import DEFAULT_CONFIG from '../../defaultConfig.js';
+import {
+ clear as commonClear,
+ getAccDescription,
+ getAccTitle,
+ getDiagramTitle,
+ setAccDescription,
+ setAccTitle,
+ setDiagramTitle,
+} from '../common/commonDb.js';
+import { cleanAndMerge } from '../../utils.js';
+import { ImperativeState } from '../../utils/imperativeState.js';
+
+interface TreeViewState {
+ cnt: number;
+ stack: Node[];
+}
+
+const state = new ImperativeState(() => ({
+ cnt: 1,
+ stack: [
+ {
+ id: 0,
+ level: -1,
+ name: '/',
+ children: [],
+ },
+ ],
+}));
+
+const clear = () => {
+ state.reset();
+ commonClear();
+};
+
+const getRoot = () => {
+ return state.records.stack[0];
+};
+
+const getCount = () => state.records.cnt;
+
+const defaultConfig: Required = DEFAULT_CONFIG.treeView;
+
+const getConfig = (): Required => {
+ return cleanAndMerge(defaultConfig, getCommonConfig().treeView);
+};
+
+const addNode = (level: number, name: string) => {
+ while (level <= state.records.stack[state.records.stack.length - 1].level) {
+ state.records.stack.pop();
+ }
+ const node = {
+ id: state.records.cnt++,
+ level,
+ name,
+ children: [],
+ };
+ state.records.stack[state.records.stack.length - 1].children.push(node);
+ state.records.stack.push(node);
+};
+
+const db: TreeViewDB = {
+ clear,
+ addNode,
+ getRoot,
+ getCount,
+ getConfig,
+ getAccTitle,
+ getAccDescription,
+ getDiagramTitle,
+ setAccDescription,
+ setAccTitle,
+ setDiagramTitle,
+};
+
+export default db;
diff --git a/packages/mermaid/src/diagrams/treeView/detector.ts b/packages/mermaid/src/diagrams/treeView/detector.ts
new file mode 100644
index 00000000000..ef4d84e44ed
--- /dev/null
+++ b/packages/mermaid/src/diagrams/treeView/detector.ts
@@ -0,0 +1,21 @@
+import type { DiagramDetector, DiagramLoader } from '../../diagram-api/types.js';
+import type { ExternalDiagramDefinition } from '../../diagram-api/types.js';
+
+const id = 'treeView';
+
+const detector: DiagramDetector = (txt) => {
+ return /^\s*treeView-beta/.test(txt);
+};
+
+const loader: DiagramLoader = async () => {
+ const { diagram } = await import('./diagram.js');
+ return { id, diagram };
+};
+
+const plugin: ExternalDiagramDefinition = {
+ id,
+ detector,
+ loader,
+};
+
+export default plugin;
diff --git a/packages/mermaid/src/diagrams/treeView/diagram.ts b/packages/mermaid/src/diagrams/treeView/diagram.ts
new file mode 100644
index 00000000000..19d432d9684
--- /dev/null
+++ b/packages/mermaid/src/diagrams/treeView/diagram.ts
@@ -0,0 +1,12 @@
+import type { DiagramDefinition } from '../../diagram-api/types.js';
+import { parser } from './parser.js';
+import db from './db.js';
+import renderer from './renderer.js';
+import styles from './styles.js';
+
+export const diagram: DiagramDefinition = {
+ db,
+ renderer,
+ parser,
+ styles,
+};
diff --git a/packages/mermaid/src/diagrams/treeView/parser.ts b/packages/mermaid/src/diagrams/treeView/parser.ts
new file mode 100644
index 00000000000..70c63c220b0
--- /dev/null
+++ b/packages/mermaid/src/diagrams/treeView/parser.ts
@@ -0,0 +1,18 @@
+import type { ParserDefinition } from '../../diagram-api/types.js';
+import { log } from '../../logger.js';
+import { populateCommonDb } from '../common/populateCommonDb.js';
+import db from './db.js';
+import { parse, type TreeView } from '@mermaid-js/parser';
+
+const populate = (ast: TreeView) => {
+ populateCommonDb(ast, db);
+ ast.nodes.map((node) => db.addNode(node.indent ? parseInt(node.indent) : 0, node.name));
+};
+
+export const parser: ParserDefinition = {
+ parse: async (input: string): Promise => {
+ const ast = await parse('treeView', input);
+ log.debug(ast);
+ populate(ast);
+ },
+};
diff --git a/packages/mermaid/src/diagrams/treeView/renderer.ts b/packages/mermaid/src/diagrams/treeView/renderer.ts
new file mode 100644
index 00000000000..150f765b763
--- /dev/null
+++ b/packages/mermaid/src/diagrams/treeView/renderer.ts
@@ -0,0 +1,126 @@
+import type { DiagramRenderer, DrawDefinition } from '../../diagram-api/types.js';
+import { log } from '../../logger.js';
+import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
+import type { D3SVGElement, TreeViewDB } from './types.js';
+import { configureSvgSize } from '../../setupGraphViewbox.js';
+import type { TreeViewDiagramConfig } from '../../config.type.js';
+import type { Node } from './types.js';
+
+const positionLabel = (
+ x: number,
+ y: number,
+ node: Node,
+ domElem: D3SVGElement,
+ config: Required
+) => {
+ const label = domElem
+ .append('text')
+ .text(node.name)
+ .attr('dominant-baseline', 'middle')
+ .attr('class', 'treeView-node-label');
+ const { height: labelHeight, width: labelWidth } = label.node()!.getBBox();
+ const height = labelHeight + config.paddingY * 2;
+ const width = labelWidth + config.paddingX * 2;
+ label.attr('x', x + config.paddingX);
+ label.attr('y', y + height / 2);
+ node.BBox = {
+ x,
+ y,
+ width,
+ height,
+ };
+};
+
+const positionLine = (
+ domElem: D3SVGElement,
+ x1: number,
+ y1: number,
+ x2: number,
+ y2: number,
+ lineThickness: number
+) => {
+ return domElem
+ .append('line')
+ .attr('x1', x1)
+ .attr('y1', y1)
+ .attr('x2', x2)
+ .attr('y2', y2)
+ .attr('stroke-width', lineThickness)
+ .attr('class', 'treeView-node-line');
+};
+
+const drawTree = (
+ elem: D3SVGElement,
+ root: Node,
+ config: Required
+) => {
+ let totalHeight = 0;
+ let totalWidth = 0;
+ const drawNode = (
+ elem: D3SVGElement,
+ node: Node,
+ config: Required,
+ depth: number
+ ) => {
+ const indent = depth * (config.rowIndent + config.paddingX);
+ positionLabel(indent, totalHeight, node, elem, config);
+ const { height, width } = node.BBox!;
+ positionLine(
+ elem,
+ indent - config.rowIndent,
+ totalHeight + height / 2,
+ indent,
+ totalHeight + height / 2,
+ config.lineThickness
+ );
+
+ totalWidth = Math.max(totalWidth, indent + width);
+ totalHeight += height;
+ };
+
+ const processNode = (node: Node, depth = 0) => {
+ drawNode(elem, node, config, depth);
+ node.children.forEach((child) => {
+ processNode(child, depth + 1);
+ });
+ const { x, y, height } = node.BBox!;
+ if (node.children.length) {
+ const { y: endY, height: endHeight } = node.children[node.children.length - 1].BBox!;
+ positionLine(
+ elem,
+ x + config.paddingX,
+ y + height,
+ x + config.paddingX,
+ endY + endHeight / 2 + config.lineThickness / 2,
+ config.lineThickness
+ );
+ }
+ };
+
+ processNode(root);
+ return { totalHeight, totalWidth };
+};
+
+const draw: DrawDefinition = (text, id, _ver, diagObj) => {
+ log.debug('Rendering treeView diagram\n' + text);
+
+ const db = diagObj.db as TreeViewDB;
+ const root = db.getRoot();
+ const config = db.getConfig();
+
+ const svg = selectSvgElement(id);
+ const treeElem = svg.append('g');
+ treeElem.attr('class', 'tree-view');
+
+ const { totalHeight, totalWidth } = drawTree(treeElem, root, config);
+ /* -${config.lineThickness/2} is required for a line with x coordinate = 0
+ as there is overflow to the left due to the line being centered */
+ svg.attr('viewBox', `-${config.lineThickness / 2} 0 ${totalWidth} ${totalHeight}`);
+ configureSvgSize(svg, totalHeight, totalWidth, config.useMaxWidth);
+};
+
+const renderer: DiagramRenderer = {
+ draw,
+};
+
+export default renderer;
diff --git a/packages/mermaid/src/diagrams/treeView/styles.ts b/packages/mermaid/src/diagrams/treeView/styles.ts
new file mode 100644
index 00000000000..691e127acee
--- /dev/null
+++ b/packages/mermaid/src/diagrams/treeView/styles.ts
@@ -0,0 +1,31 @@
+import type { DiagramStylesProvider } from '../../diagram-api/types.js';
+import { cleanAndMerge } from '../../utils.js';
+import type { TreeViewDiagramStyles } from './types.js';
+
+const defaultTreeViewDiagramStyles: Required = {
+ labelFontSize: '16px',
+ labelColor: 'black',
+ lineColor: 'black',
+};
+
+const styles: DiagramStylesProvider = ({
+ treeView,
+}: {
+ treeView?: TreeViewDiagramStyles;
+}): string => {
+ const { labelFontSize, labelColor, lineColor } = cleanAndMerge(
+ defaultTreeViewDiagramStyles,
+ treeView
+ );
+ return `
+ .treeView-node-label {
+ font-size: ${labelFontSize};
+ fill: ${labelColor};
+ }
+ .treeView-node-line {
+ stroke: ${lineColor};
+ }
+ `;
+};
+
+export default styles;
diff --git a/packages/mermaid/src/diagrams/treeView/types.ts b/packages/mermaid/src/diagrams/treeView/types.ts
new file mode 100644
index 00000000000..43a7f4e6da3
--- /dev/null
+++ b/packages/mermaid/src/diagrams/treeView/types.ts
@@ -0,0 +1,32 @@
+import type { TreeViewDiagramConfig } from '../../config.type.js';
+import type { DiagramDBBase } from '../../diagram-api/types.js';
+import type { Selection } from 'd3-selection';
+
+interface BBox {
+ x: number;
+ y: number;
+ width: number;
+ height: number;
+}
+
+export interface Node {
+ id: number;
+ level: number;
+ name: string;
+ BBox?: BBox;
+ children: Node[];
+}
+
+export interface TreeViewDB extends DiagramDBBase {
+ addNode: (level: number, name: string) => void;
+ getRoot: () => Node;
+ getCount: () => number;
+}
+
+export interface TreeViewDiagramStyles {
+ labelColor?: string;
+ labelFontSize?: string;
+ lineColor?: string;
+}
+
+export type D3SVGElement = Selection;
diff --git a/packages/mermaid/src/docs/.vitepress/config.ts b/packages/mermaid/src/docs/.vitepress/config.ts
index 4bab6795b88..b74b326a105 100644
--- a/packages/mermaid/src/docs/.vitepress/config.ts
+++ b/packages/mermaid/src/docs/.vitepress/config.ts
@@ -191,6 +191,7 @@ function sidebarSyntax() {
{ text: 'Treemap 🔥', link: '/syntax/treemap' },
{ text: 'Venn 🔥', link: '/syntax/venn' },
{ text: 'Ishikawa 🔥', link: '/syntax/ishikawa' },
+ { text: 'TreeView 🔥', link: '/syntax/treeView' },
{ text: 'Other Examples', link: '/syntax/examples' },
],
},
diff --git a/packages/mermaid/src/docs/syntax/treeView.md b/packages/mermaid/src/docs/syntax/treeView.md
new file mode 100644
index 00000000000..19cad4e9288
--- /dev/null
+++ b/packages/mermaid/src/docs/syntax/treeView.md
@@ -0,0 +1,64 @@
+# TreeView Diagram (v+)
+
+## Introduction
+
+A TreeView diagram is used to represent hierarchical data in the form of a directory-like structure.
+
+## Syntax
+
+The structure of the tree depends only on indentation.
+
+```
+treeView-beta
+ ""
+ ""
+ ""
+ ""
+ ""
+```
+
+## Examples
+
+```mermaid-example
+treeView-beta
+ "packages"
+ "mermaid"
+ "src"
+ "parser"
+```
+
+```mermaid-example
+---
+config:
+ treeView:
+ rowIndent: 80
+ lineThickness: 3
+ themeVariables:
+ treeView:
+ labelFontSize: '20px'
+ labelColor: '#FF0000'
+ lineColor: '#00FF00'
+---
+treeView-beta
+ "packages"
+ "mermaid"
+ "src"
+ "parser"
+```
+
+## Config Variables
+
+| Property | Description | Default Value |
+| ------------- | ------------------------- | ------------- |
+| rowIndent | Indentation for each row | 10 |
+| paddingX | Horizontal padding of row | 5 |
+| paddingY | Vertical padding of row | 5 |
+| lineThickness | Thickness of the line | 1 |
+
+### Theme Variables
+
+| Property | Description | Default Value |
+| ------------- | ---------------------- | ------------- |
+| labelFontSize | Font size of the label | '16px' |
+| labelColor | Color of the label | 'black' |
+| lineColor | Color of the line | 'black' |
diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts
index db7ef07254e..47ae1ad18de 100644
--- a/packages/mermaid/src/mermaidAPI.spec.ts
+++ b/packages/mermaid/src/mermaidAPI.spec.ts
@@ -763,6 +763,7 @@ graph TD;A--x|text including URL space|B;`)
{ textDiagramType: 'requirementDiagram', expectedType: 'requirement' },
{ textDiagramType: 'sequenceDiagram', expectedType: 'sequence' },
{ textDiagramType: 'stateDiagram-v2', expectedType: 'stateDiagram' },
+ { textDiagramType: 'treeView-beta', expectedType: 'treeView' },
{ textDiagramType: 'radar-beta', expectedType: 'radar' },
{ textDiagramType: 'architecture-beta', expectedType: 'architecture' },
];
@@ -776,7 +777,7 @@ graph TD;A--x|text including URL space|B;`)
describe(`${testedDiagram.textDiagramType}`, () => {
const diagramType = testedDiagram.textDiagramType;
const content = testedDiagram.content || '';
- const diagramText = `${diagramType}\n accTitle: ${a11yTitle}\n accDescr: ${a11yDescr}\n ${content}`;
+ const diagramText = `${diagramType}\n accTitle: ${a11yTitle}\n accDescr: ${a11yDescr}\n${content}`;
const expectedDiagramType = testedDiagram.expectedType;
jsdomIt(
diff --git a/packages/mermaid/src/rendering-util/multi-diagram-id-uniqueness.spec.ts b/packages/mermaid/src/rendering-util/multi-diagram-id-uniqueness.spec.ts
index 026e223e56f..05e01a1e905 100644
--- a/packages/mermaid/src/rendering-util/multi-diagram-id-uniqueness.spec.ts
+++ b/packages/mermaid/src/rendering-util/multi-diagram-id-uniqueness.spec.ts
@@ -105,6 +105,12 @@ radar-beta
"Section 2"
"Leaf 2.1": 20`,
+ treeView: `treeView-beta
+"packages"
+ "mermaid"
+ "src"
+ "parser"`,
+
ishikawa: `ishikawa-beta
Root Cause
Category A
diff --git a/packages/mermaid/src/schemas/config.schema.yaml b/packages/mermaid/src/schemas/config.schema.yaml
index 7a0f07a500c..eb53c34b694 100644
--- a/packages/mermaid/src/schemas/config.schema.yaml
+++ b/packages/mermaid/src/schemas/config.schema.yaml
@@ -54,6 +54,7 @@ required:
- sankey
- packet
- block
+ - treeView
- look
- venn
properties:
@@ -315,6 +316,8 @@ properties:
$ref: '#/$defs/PacketDiagramConfig'
block:
$ref: '#/$defs/BlockDiagramConfig'
+ treeView:
+ $ref: '#/$defs/TreeViewDiagramConfig'
radar:
$ref: '#/$defs/RadarDiagramConfig'
venn:
@@ -2312,6 +2315,34 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file)
minimum: 0
default: 8
+ TreeViewDiagramConfig:
+ title: TreeView Diagram Config
+ allOf: [{ $ref: '#/$defs/BaseDiagramConfig' }]
+ description: The object containing configurations specific for treeView diagrams.
+ type: object
+ unevaluatedProperties: false
+ properties:
+ rowIndent:
+ description: Horizontal distance between rows differing by one level
+ type: number
+ minimum: 0
+ default: 10
+ paddingX:
+ description: Horizontal padding of label
+ type: number
+ minimum: 0
+ default: 5
+ paddingY:
+ description: Vertical padding of label
+ type: number
+ minimum: 0
+ default: 5
+ lineThickness:
+ description: Thickness of the line
+ type: number
+ minimum: 0
+ default: 1
+
RadarDiagramConfig:
title: Radar Diagram Config
allOf: [{ $ref: '#/$defs/BaseDiagramConfig' }]
diff --git a/packages/mermaid/src/styles.spec.ts b/packages/mermaid/src/styles.spec.ts
index fc38d7c4d55..5525c3e4e96 100644
--- a/packages/mermaid/src/styles.spec.ts
+++ b/packages/mermaid/src/styles.spec.ts
@@ -29,6 +29,7 @@ import timeline from './diagrams/timeline/styles.js';
import mindmap from './diagrams/mindmap/styles.js';
import packet from './diagrams/packet/styles.js';
import block from './diagrams/block/styles.js';
+import treeView from './diagrams/treeView/styles.js';
import radar from './diagrams/radar/styles.js';
import venn from './diagrams/venn/styles.js';
import themes from './themes/index.js';
@@ -101,6 +102,7 @@ describe('styles', () => {
block,
timeline,
packet,
+ treeView,
radar,
venn,
})) {
diff --git a/packages/parser/langium-config.json b/packages/parser/langium-config.json
index 85c722a02c0..391dc225400 100644
--- a/packages/parser/langium-config.json
+++ b/packages/parser/langium-config.json
@@ -16,6 +16,11 @@
"grammar": "src/language/pie/pie.langium",
"fileExtensions": [".mmd", ".mermaid"]
},
+ {
+ "id": "treeView",
+ "grammar": "src/language/treeView/treeView.langium",
+ "fileExtensions": [".mmd", ".mermaid"]
+ },
{
"id": "architecture",
"grammar": "src/language/architecture/architecture.langium",
diff --git a/packages/parser/src/language/index.ts b/packages/parser/src/language/index.ts
index 5920a7010fa..b3a768b0b6a 100644
--- a/packages/parser/src/language/index.ts
+++ b/packages/parser/src/language/index.ts
@@ -13,6 +13,8 @@ export {
Commit,
Merge,
Statement,
+ TreeView,
+ TreeNode,
isInfo,
isPacket,
isPacketBlock,
@@ -35,6 +37,7 @@ export {
GitGraphGrammarGeneratedModule as GitGraphGeneratedModule,
RadarGrammarGeneratedModule as RadarGeneratedModule,
TreemapGrammarGeneratedModule as TreemapGeneratedModule,
+ TreeViewGrammarGeneratedModule as TreeViewGeneratedModule,
} from './generated/module.js';
export * from './gitGraph/index.js';
@@ -42,6 +45,7 @@ export * from './common/index.js';
export * from './info/index.js';
export * from './packet/index.js';
export * from './pie/index.js';
+export * from './treeView/index.js';
export * from './architecture/index.js';
export * from './radar/index.js';
export * from './treemap/index.js';
diff --git a/packages/parser/src/language/treeView/index.ts b/packages/parser/src/language/treeView/index.ts
new file mode 100644
index 00000000000..fd3c604b084
--- /dev/null
+++ b/packages/parser/src/language/treeView/index.ts
@@ -0,0 +1 @@
+export * from './module.js';
diff --git a/packages/parser/src/language/treeView/module.ts b/packages/parser/src/language/treeView/module.ts
new file mode 100644
index 00000000000..13f7079b8ea
--- /dev/null
+++ b/packages/parser/src/language/treeView/module.ts
@@ -0,0 +1,80 @@
+import type {
+ DefaultSharedCoreModuleContext,
+ LangiumCoreServices,
+ LangiumSharedCoreServices,
+ Module,
+ PartialLangiumCoreServices,
+} from 'langium';
+import {
+ EmptyFileSystem,
+ createDefaultCoreModule,
+ createDefaultSharedCoreModule,
+ inject,
+} from 'langium';
+
+import { TreeViewValueConverter } from './valueConverter.js';
+import {
+ MermaidGeneratedSharedModule,
+ TreeViewGrammarGeneratedModule as TreeViewGeneratedModule,
+} from '../generated/module.js';
+import { TreeViewTokenBuilder } from './tokenBuilder.js';
+
+/**
+ * Declaration of `TreeView` services.
+ */
+interface TreeViewAddedServices {
+ parser: {
+ TokenBuilder: TreeViewTokenBuilder;
+ ValueConverter: TreeViewValueConverter;
+ };
+}
+
+/**
+ * Union of Langium default services and `TreeView` services.
+ */
+export type TreeViewServices = LangiumCoreServices & TreeViewAddedServices;
+
+/**
+ * Dependency injection module that overrides Langium default services and
+ * contributes the declared `TreeView` services.
+ */
+export const TreeViewModule: Module<
+ TreeViewServices,
+ PartialLangiumCoreServices & TreeViewAddedServices
+> = {
+ parser: {
+ TokenBuilder: () => new TreeViewTokenBuilder(),
+ ValueConverter: () => new TreeViewValueConverter(),
+ },
+};
+
+/**
+ * Create the full set of services required by Langium.
+ *
+ * First inject the shared services by merging two modules:
+ * - Langium default shared services
+ * - Services generated by langium-cli
+ *
+ * Then inject the language-specific services by merging three modules:
+ * - Langium default language-specific services
+ * - Services generated by langium-cli
+ * - Services specified in this file
+ * @param context - Optional module context with the LSP connection
+ * @returns An object wrapping the shared services and the language-specific services
+ */
+export function createTreeViewServices(context: DefaultSharedCoreModuleContext = EmptyFileSystem): {
+ shared: LangiumSharedCoreServices;
+ TreeView: TreeViewServices;
+} {
+ const shared: LangiumSharedCoreServices = inject(
+ createDefaultSharedCoreModule(context),
+ MermaidGeneratedSharedModule
+ );
+ const TreeView: TreeViewServices = inject(
+ createDefaultCoreModule({ shared }),
+ TreeViewGeneratedModule,
+ TreeViewModule
+ );
+ shared.ServiceRegistry.register(TreeView);
+ return { shared, TreeView };
+}
diff --git a/packages/parser/src/language/treeView/tokenBuilder.ts b/packages/parser/src/language/treeView/tokenBuilder.ts
new file mode 100644
index 00000000000..5aacc5f903f
--- /dev/null
+++ b/packages/parser/src/language/treeView/tokenBuilder.ts
@@ -0,0 +1,7 @@
+import { AbstractMermaidTokenBuilder } from '../common/index.js';
+
+export class TreeViewTokenBuilder extends AbstractMermaidTokenBuilder {
+ public constructor() {
+ super(['treeView-beta']);
+ }
+}
diff --git a/packages/parser/src/language/treeView/treeView.langium b/packages/parser/src/language/treeView/treeView.langium
new file mode 100644
index 00000000000..51443090fed
--- /dev/null
+++ b/packages/parser/src/language/treeView/treeView.langium
@@ -0,0 +1,45 @@
+/**
+ * TreeView grammar for Langium
+ * Converted from treemap grammar
+ *
+ * The ML_COMMENT and NL hidden terminals handle whitespace, comments, and newlines
+ * before the treemap keyword, allowing for empty lines and comments before the
+ * treeView declaration.
+ */
+grammar TreeViewGrammar
+
+terminal ACC_DESCR: /[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/;
+terminal ACC_TITLE: /[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/;
+terminal TITLE: /[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/;
+
+interface TreeView {
+ nodes: TreeNode[]
+ title?: string
+ accTitle?: string
+ accDescr?: string
+}
+
+entry TreeView returns TreeView:
+ "treeView-beta"
+ TitleAndAccessibilities?
+ nodes+=TreeNode*
+ ;
+
+fragment TitleAndAccessibilities:
+ ((accDescr=ACC_DESCR | accTitle=ACC_TITLE | title=TITLE))+
+;
+
+// This should be processed before whitespace is ignored
+terminal INDENTATION: /[ \t]{1,}/; // One or more spaces/tabs for indentation
+
+hidden terminal WS: /[ \t]+/; // One or more spaces or tabs for hidden whitespace
+hidden terminal ML_COMMENT: /\%\%[^\n]*/;
+hidden terminal NL: /\r?\n/;
+
+TreeNode:
+ // actually contains the indent, but is converted to a length value by valueConverter
+ indent=INDENTATION?
+ name=STRING2
+;
+
+terminal STRING2: /"[^"]*"|'[^']*'/;
diff --git a/packages/parser/src/language/treeView/valueConverter.ts b/packages/parser/src/language/treeView/valueConverter.ts
new file mode 100644
index 00000000000..31fae101f6b
--- /dev/null
+++ b/packages/parser/src/language/treeView/valueConverter.ts
@@ -0,0 +1,18 @@
+import type { CstNode, GrammarAST, ValueType } from 'langium';
+import { AbstractMermaidValueConverter } from '../common/index.js';
+
+export class TreeViewValueConverter extends AbstractMermaidValueConverter {
+ protected runCustomConverter(
+ rule: GrammarAST.AbstractRule,
+ input: string,
+ _cstNode: CstNode
+ ): ValueType | undefined {
+ if (rule.name === 'INDENTATION') {
+ return input?.length || 0;
+ } else if (rule.name === 'STRING2') {
+ // Remove quotes
+ return input.substring(1, input.length - 1);
+ }
+ return undefined;
+ }
+}
diff --git a/packages/parser/src/parse.ts b/packages/parser/src/parse.ts
index 27bf241ebd7..133a604fdef 100644
--- a/packages/parser/src/parse.ts
+++ b/packages/parser/src/parse.ts
@@ -1,8 +1,17 @@
import type { LangiumParser, ParseResult } from 'langium';
-import type { Info, Packet, Pie, Architecture, GitGraph, Radar, Treemap } from './index.js';
+import type {
+ Info,
+ Packet,
+ Pie,
+ Architecture,
+ GitGraph,
+ Radar,
+ Treemap,
+ TreeView,
+} from './index.js';
-export type DiagramAST = Info | Packet | Pie | Architecture | GitGraph | Radar;
+export type DiagramAST = Info | Packet | Pie | Architecture | GitGraph | Radar | TreeView;
const parsers: Record = {};
const initializers = {
@@ -21,6 +30,11 @@ const initializers = {
const parser = createPieServices().Pie.parser.LangiumParser;
parsers.pie = parser;
},
+ treeView: async () => {
+ const { createTreeViewServices } = await import('./language/treeView/index.js');
+ const parser = createTreeViewServices().TreeView.parser.LangiumParser;
+ parsers.treeView = parser;
+ },
architecture: async () => {
const { createArchitectureServices } = await import('./language/architecture/index.js');
const parser = createArchitectureServices().Architecture.parser.LangiumParser;
@@ -46,6 +60,7 @@ const initializers = {
export async function parse(diagramType: 'info', text: string): Promise;
export async function parse(diagramType: 'packet', text: string): Promise;
export async function parse(diagramType: 'pie', text: string): Promise;
+export async function parse(diagramType: 'treeView', text: string): Promise;
export async function parse(diagramType: 'architecture', text: string): Promise;
export async function parse(diagramType: 'gitGraph', text: string): Promise;
export async function parse(diagramType: 'radar', text: string): Promise;
diff --git a/packages/parser/tests/test-util.ts b/packages/parser/tests/test-util.ts
index ee76271093e..d965814ed72 100644
--- a/packages/parser/tests/test-util.ts
+++ b/packages/parser/tests/test-util.ts
@@ -13,6 +13,8 @@ import type {
PacketServices,
GitGraph,
GitGraphServices,
+ TreeView,
+ TreeViewServices,
} from '../src/language/index.js';
import {
createArchitectureServices,
@@ -21,6 +23,7 @@ import {
createRadarServices,
createPacketServices,
createGitGraphServices,
+ createTreeViewServices,
} from '../src/language/index.js';
const consoleMock = vi.spyOn(console, 'log').mockImplementation(() => undefined);
@@ -105,3 +108,14 @@ export function createGitGraphTestServices() {
return { services: gitGraphServices, parse };
}
export const gitGraphParse = createGitGraphTestServices().parse;
+
+const treeViewServices: TreeViewServices = createTreeViewServices().TreeView;
+const treeViewParser: LangiumParser = treeViewServices.parser.LangiumParser;
+export function createTreeViewTestServices() {
+ const parse = (input: string) => {
+ return treeViewParser.parse(input);
+ };
+
+ return { services: treeViewServices, parse };
+}
+export const treeViewParse = createTreeViewTestServices().parse;
diff --git a/packages/parser/tests/treeView.test.ts b/packages/parser/tests/treeView.test.ts
new file mode 100644
index 00000000000..ce147e3f965
--- /dev/null
+++ b/packages/parser/tests/treeView.test.ts
@@ -0,0 +1,103 @@
+import { describe, expect, it } from 'vitest';
+import { expectNoErrorsOrAlternatives } from './test-util.js';
+import type { TreeView } from '../src/language/generated/ast.js';
+import type { LangiumParser } from 'langium';
+import { createTreeViewServices } from '../src/language/treeView/module.js';
+
+describe('TreeView Parser', () => {
+ const services = createTreeViewServices().TreeView;
+ const parser: LangiumParser = services.parser.LangiumParser;
+
+ const parse = (input: string) => {
+ return parser.parse(input);
+ };
+
+ describe('Basic Parsing', () => {
+ it('should parse empty treeView', () => {
+ const result = parse('treeView-beta');
+ expectNoErrorsOrAlternatives(result);
+ expect(result.value.$type).toBe('TreeView');
+ expect(result.value.nodes).toHaveLength(0);
+ });
+
+ it('should parse a treeView with only a root node', () => {
+ const result = parse('treeView-beta\n"Root"');
+ expectNoErrorsOrAlternatives(result);
+ expect(result.value.$type).toBe('TreeView');
+ expect(result.value.nodes).toHaveLength(1);
+ expect(result.value.nodes[0].name).toBe('Root');
+ expect(result.value.nodes[0].indent).toBe(undefined);
+ });
+
+ it('should parse a treeView with multiple words within a node', () => {
+ const result = parse('treeView-beta\n"Multi Word Root"');
+ expectNoErrorsOrAlternatives(result);
+ expect(result.value.$type).toBe('TreeView');
+ expect(result.value.nodes).toHaveLength(1);
+ expect(result.value.nodes[0].name).toBe('Multi Word Root');
+ expect(result.value.nodes[0].indent).toBe(undefined);
+ });
+
+ it('should parse a treeView with child nodes', () => {
+ const result = parse(`treeView-beta\n"Root"\n "Child1"\n "Child2"\n "Child3"`);
+ expectNoErrorsOrAlternatives(result);
+ expect(result.value.$type).toBe('TreeView');
+ expect(result.value.nodes).toHaveLength(4);
+
+ expect(result.value.nodes[0].name).toBe('Root');
+ expect(result.value.nodes[0].indent).toBe(undefined);
+
+ expect(result.value.nodes[1].name).toBe('Child1');
+ expect(result.value.nodes[1].indent).toBe(4);
+
+ expect(result.value.nodes[2].name).toBe('Child2');
+ expect(result.value.nodes[2].indent).toBe(4);
+
+ expect(result.value.nodes[3].name).toBe('Child3');
+ expect(result.value.nodes[3].indent).toBe(8);
+ });
+ });
+
+ describe('Title and Accessibilities', () => {
+ it('should parse a treeView with title', () => {
+ const result = parse('treeView-beta\ntitle My TreeView Diagram\n"Root"\n "Child"');
+ expectNoErrorsOrAlternatives(result);
+ expect(result.value.$type).toBe('TreeView');
+ expect(result.value.title).toBe('My TreeView Diagram');
+ expect(result.value.nodes).toHaveLength(2);
+ });
+
+ it('should parse a treeView with accTitle', () => {
+ const result = parse('treeView-beta\naccTitle: Accessible Title\n"Root"\n "Child"');
+ expectNoErrorsOrAlternatives(result);
+ expect(result.value.$type).toBe('TreeView');
+ expect(result.value.accTitle).toBe('Accessible Title');
+ expect(result.value.nodes).toHaveLength(2);
+ });
+
+ it('should parse a treeView with accDescr', () => {
+ const result = parse(
+ 'treeView-beta\naccDescr: This is an accessible description\n"Root"\n "Child"'
+ );
+ expectNoErrorsOrAlternatives(result);
+ expect(result.value.$type).toBe('TreeView');
+ expect(result.value.accDescr).toBe('This is an accessible description');
+ expect(result.value.nodes).toHaveLength(2);
+ });
+
+ it('should parse a treeView with multiple accessibility attributes', () => {
+ const result = parse(`treeView-beta
+title My TreeView Diagram
+accTitle: Accessible Title
+accDescr: This is an accessible description
+"Root"
+ "Child"`);
+ expectNoErrorsOrAlternatives(result);
+ expect(result.value.$type).toBe('TreeView');
+ expect(result.value.title).toBe('My TreeView Diagram');
+ expect(result.value.accTitle).toBe('Accessible Title');
+ expect(result.value.accDescr).toBe('This is an accessible description');
+ expect(result.value.nodes).toHaveLength(2);
+ });
+ });
+});