mirror of
				https://github.com/mermaid-js/mermaid.git
				synced 2025-11-03 20:34:20 +01:00 
			
		
		
		
	Compare commits
	
		
			206 Commits
		
	
	
		
			mermaid@11
			...
			4ab98c2ec7
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					4ab98c2ec7 | ||
| 
						 | 
					aeb51e56e2 | ||
| 
						 | 
					ddcd8a5e73 | ||
| 
						 | 
					e464d080ef | ||
| 
						 | 
					1a9b94ca2d | ||
| 
						 | 
					e4b33a1d99 | ||
| 
						 | 
					e27a9da61d | ||
| 
						 | 
					03cf10003f | ||
| 
						 | 
					8e31fdb611 | ||
| 
						 | 
					5dd748148f | ||
| 
						 | 
					895f9d43ff | ||
| 
						 | 
					fb890a2be8 | ||
| 
						 | 
					5986189a52 | ||
| 
						 | 
					1988dfc956 | ||
| 
						 | 
					e48b0ba61d | ||
| 
						 | 
					1a4b8662cf | ||
| 
						 | 
					6083463c8e | ||
| 
						 | 
					1a14e331ea | ||
| 
						 | 
					ebb6680eba | ||
| 
						 | 
					6d1d46f88a | ||
| 
						 | 
					435790f931 | ||
| 
						 | 
					ffe9c1090e | ||
| 
						 | 
					a476e99d4c | ||
| 
						 | 
					0cc0b63e52 | ||
| 
						 | 
					694844050a | ||
| 
						 | 
					1be1620000 | ||
| 
						 | 
					c36cd05c45 | ||
| 
						 | 
					b7a591b8d3 | ||
| 
						 | 
					8bb29fc879 | ||
| 
						 | 
					e073c80019 | ||
| 
						 | 
					01aaef39b4 | ||
| 
						 | 
					3d640fc620 | ||
| 
						 | 
					724197c910 | ||
| 
						 | 
					6180c5f2ff | ||
| 
						 | 
					a9f7a94ae3 | ||
| 
						 | 
					3ffe9618ae | ||
| 
						 | 
					da539c1fa1 | ||
| 
						 | 
					5e8aa2dccf | ||
| 
						 | 
					ac04172cf8 | ||
| 
						 | 
					cf5b4b89a8 | ||
| 
						 | 
					1c269e0432 | ||
| 
						 | 
					999b836508 | ||
| 
						 | 
					326e4e3693 | ||
| 
						 | 
					9c92da487f | ||
| 
						 | 
					10752f1357 | ||
| 
						 | 
					1a80854242 | ||
| 
						 | 
					fc9c600a31 | ||
| 
						 | 
					da8ce0b93e | ||
| 
						 | 
					00a79353fc | ||
| 
						 | 
					1ceeca1ef1 | ||
| 
						 | 
					94890390ef | ||
| 
						 | 
					adfeb093cb | ||
| 
						 | 
					366d217928 | ||
| 
						 | 
					b94f1336ab | ||
| 
						 | 
					020c6d66e0 | ||
| 
						 | 
					cfc2551bdc | ||
| 
						 | 
					000308c8f5 | ||
| 
						 | 
					6039a8b930 | ||
| 
						 | 
					cd282f2245 | ||
| 
						 | 
					a27d90fe9c | ||
| 
						 | 
					64bf34b9ab | ||
| 
						 | 
					9faf2f9fb2 | ||
| 
						 | 
					f683b03645 | ||
| 
						 | 
					9cef40d164 | ||
| 
						 | 
					04612e078a | ||
| 
						 | 
					af585bdcc7 | ||
| 
						 | 
					37bfa2aa75 | ||
| 
						 | 
					54640ce476 | ||
| 
						 | 
					47b4c56b2b | ||
| 
						 | 
					6b1b0bf151 | ||
| 
						 | 
					7ba332ad4a | ||
| 
						 | 
					412d2a09d3 | ||
| 
						 | 
					7886fed8b2 | ||
| 
						 | 
					af3d5b6528 | ||
| 
						 | 
					404286a90d | ||
| 
						 | 
					827a9af790 | ||
| 
						 | 
					95733b6295 | ||
| 
						 | 
					8b86d617e7 | ||
| 
						 | 
					cc2112c7aa | ||
| 
						 | 
					767754f4fb | ||
| 
						 | 
					cff59c58b4 | ||
| 
						 | 
					ac976245ad | ||
| 
						 | 
					5b241bbb97 | ||
| 
						 | 
					7e5e47843b | ||
| 
						 | 
					9e2cd1a926 | ||
| 
						 | 
					abf2227faf | ||
| 
						 | 
					7db942b0e1 | ||
| 
						 | 
					70041c806f | ||
| 
						 | 
					77e2703f72 | ||
| 
						 | 
					771801b366 | ||
| 
						 | 
					a9a0a9b2de | ||
| 
						 | 
					1e5e835c41 | ||
| 
						 | 
					1f3f8da0f7 | ||
| 
						 | 
					b11f40e8ce | ||
| 
						 | 
					1fe045e638 | ||
| 
						 | 
					1c750ffc70 | ||
| 
						 | 
					b0ec93f29c | ||
| 
						 | 
					6b071c135a | ||
| 
						 | 
					42a3c3487f | ||
| 
						 | 
					d7b8ed2c5a | ||
| 
						 | 
					96c21c7e54 | ||
| 
						 | 
					e95e4d155a | ||
| 
						 | 
					688170558c | ||
| 
						 | 
					832f012e10 | ||
| 
						 | 
					2e2e8c4152 | ||
| 
						 | 
					6ff6e08c4b | ||
| 
						 | 
					d7f1f12549 | ||
| 
						 | 
					6e56869566 | ||
| 
						 | 
					d3e2be35be | ||
| 
						 | 
					852cb35f0a | ||
| 
						 | 
					260a045da0 | ||
| 
						 | 
					a28965064d | ||
| 
						 | 
					355eeeb9cc | ||
| 
						 | 
					5449d6a447 | ||
| 
						 | 
					34e91f8b65 | ||
| 
						 | 
					627ee1f34d | ||
| 
						 | 
					28840ebd84 | ||
| 
						 | 
					4145879003 | ||
| 
						 | 
					e097b480d5 | ||
| 
						 | 
					f76e27db70 | ||
| 
						 | 
					3e3ae08930 | ||
| 
						 | 
					966c112eb1 | ||
| 
						 | 
					55527e70c2 | ||
| 
						 | 
					447d1cf988 | ||
| 
						 | 
					003d1c7a70 | ||
| 
						 | 
					daf8d8d3be | ||
| 
						 | 
					d7a55b422b | ||
| 
						 | 
					12e3d31437 | ||
| 
						 | 
					ad024b01d6 | ||
| 
						 | 
					c12aea588c | ||
| 
						 | 
					9dfbf1166d | ||
| 
						 | 
					98bf9b4cb4 | ||
| 
						 | 
					e9ce8cf4da | ||
| 
						 | 
					d90634bf2b | ||
| 
						 | 
					90707e8062 | ||
| 
						 | 
					7e23f984e6 | ||
| 
						 | 
					b3a12237c0 | ||
| 
						 | 
					fad6676d18 | ||
| 
						 | 
					637680d4d9 | ||
| 
						 | 
					5f6f5110fd | ||
| 
						 | 
					af47269342 | ||
| 
						 | 
					d3c0893937 | ||
| 
						 | 
					75ef9bc681 | ||
| 
						 | 
					45edc91591 | ||
| 
						 | 
					f4edd19371 | ||
| 
						 | 
					b611a13e04 | ||
| 
						 | 
					7a38eb715d | ||
| 
						 | 
					2715ddb338 | ||
| 
						 | 
					ca2eca58c9 | ||
| 
						 | 
					b4fae2d096 | ||
| 
						 | 
					6dd9af0dd4 | ||
| 
						 | 
					3151241559 | ||
| 
						 | 
					dda9c9b46e | ||
| 
						 | 
					cdd1a70b67 | ||
| 
						 | 
					12c94a177b | ||
| 
						 | 
					d8bd4dea93 | ||
| 
						 | 
					6deb476182 | ||
| 
						 | 
					ed297ee235 | ||
| 
						 | 
					03c1201fcb | ||
| 
						 | 
					3ca317c5a0 | ||
| 
						 | 
					4d83263388 | ||
| 
						 | 
					254e5cbd51 | ||
| 
						 | 
					a58dd3c6ce | ||
| 
						 | 
					10b7bb568f | ||
| 
						 | 
					79ba50216a | ||
| 
						 | 
					71b04f93b0 | ||
| 
						 | 
					27185f62e4 | ||
| 
						 | 
					9655d07adf | ||
| 
						 | 
					939da082b2 | ||
| 
						 | 
					e70be4f155 | ||
| 
						 | 
					6621f6ddb2 | ||
| 
						 | 
					954f6cc8fc | ||
| 
						 | 
					19884294bc | ||
| 
						 | 
					e6b63fd70a | ||
| 
						 | 
					8a84ede164 | ||
| 
						 | 
					d79b7b2d97 | ||
| 
						 | 
					844f879f63 | ||
| 
						 | 
					cf789d2c91 | ||
| 
						 | 
					4936ef5c30 | ||
| 
						 | 
					f006718e56 | ||
| 
						 | 
					d720776918 | ||
| 
						 | 
					f43398dd44 | ||
| 
						 | 
					43ad451940 | ||
| 
						 | 
					94c099caa1 | ||
| 
						 | 
					3e6f680df2 | ||
| 
						 | 
					2e5d955e77 | ||
| 
						 | 
					7733faf6c4 | ||
| 
						 | 
					b053a88993 | ||
| 
						 | 
					7c77c46ede | ||
| 
						 | 
					da6937f474 | ||
| 
						 | 
					cbb496da79 | ||
| 
						 | 
					43e66a6089 | ||
| 
						 | 
					5acbd7e762 | ||
| 
						 | 
					febae345fc | ||
| 
						 | 
					28bdbbca1a | ||
| 
						 | 
					4b896fa22e | ||
| 
						 | 
					a25ee49edd | ||
| 
						 | 
					695b5b2fb2 | ||
| 
						 | 
					9b77af540b | ||
| 
						 | 
					7829138fb2 | ||
| 
						 | 
					7e7a4fc665 | ||
| 
						 | 
					34e6112fea | ||
| 
						 | 
					0c759d0075 | ||
| 
						 | 
					5b7c1aad9e | ||
| 
						 | 
					865c453547 | ||
| 
						 | 
					c0b14021b7 | 
@@ -33,4 +33,9 @@ export const packageOptions = {
 | 
			
		||||
    packageName: 'mermaid-layout-elk',
 | 
			
		||||
    file: 'layouts.ts',
 | 
			
		||||
  },
 | 
			
		||||
  examples: {
 | 
			
		||||
    name: 'mermaid-examples',
 | 
			
		||||
    packageName: 'examples',
 | 
			
		||||
    file: 'index.ts',
 | 
			
		||||
  },
 | 
			
		||||
} as const satisfies Record<string, PackageOptions>;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								.changeset/beige-peas-shave.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/beige-peas-shave.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
'@mermaid-js/mermaid-zenuml': patch
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
Fixed a critical bug that the ZenUML diagram is not rendered.
 | 
			
		||||
							
								
								
									
										5
									
								
								.changeset/large-mirrors-cheer.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/large-mirrors-cheer.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
'mermaid': patch
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
fix: Update casing of ID in requirement diagram
 | 
			
		||||
							
								
								
									
										5
									
								
								.changeset/lemon-masks-unite.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/lemon-masks-unite.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
'mermaid': minor
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
feat: Added support for per link curve styling in flowchart diagram using edge ids
 | 
			
		||||
							
								
								
									
										5
									
								
								.changeset/light-flowers-judge.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/light-flowers-judge.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
'mermaid': patch
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
fix: Make flowchart elk detector regex match less greedy
 | 
			
		||||
							
								
								
									
										8
									
								
								.changeset/lovely-queens-own.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.changeset/lovely-queens-own.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
---
 | 
			
		||||
'mermaid': patch
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
fix(block): overflowing blocks no longer affect later lines
 | 
			
		||||
 | 
			
		||||
This may change the layout of block diagrams that have overflowing lines
 | 
			
		||||
(i.e. block diagrams that use up more columns that the `columns` specifier).
 | 
			
		||||
							
								
								
									
										7
									
								
								.changeset/ninety-roses-turn.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.changeset/ninety-roses-turn.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
---
 | 
			
		||||
'mermaid': patch
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
fix: log warning for blocks exceeding column width
 | 
			
		||||
 | 
			
		||||
This update adds a validation check that logs a warning message when a block's width exceeds the defined column layout.
 | 
			
		||||
							
								
								
									
										5
									
								
								.changeset/silver-eyes-build.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/silver-eyes-build.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
'mermaid': patch
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
chore: migrate to class-based ArchitectureDB implementation
 | 
			
		||||
							
								
								
									
										5
									
								
								.changeset/smart-humans-cover.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/smart-humans-cover.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
'mermaid': patch
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
fix: Update flowchart direction TD's behavior to be the same as TB
 | 
			
		||||
							
								
								
									
										5
									
								
								.changeset/vast-buses-see.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/vast-buses-see.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
'mermaid': patch
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
chore: Update packet diagram to use new class-based database structure
 | 
			
		||||
							
								
								
									
										3
									
								
								.github/lychee.toml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/lychee.toml
									
									
									
									
										vendored
									
									
								
							@@ -52,6 +52,9 @@ exclude = [
 | 
			
		||||
# Swimm returns 404, even though the link is valid
 | 
			
		||||
"https://docs.swimm.io",
 | 
			
		||||
 | 
			
		||||
# Certificate Error
 | 
			
		||||
"https://noteshub.app",
 | 
			
		||||
 | 
			
		||||
# Timeout
 | 
			
		||||
"https://huehive.co",
 | 
			
		||||
"https://foswiki.org",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/autofix.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/autofix.yml
									
									
									
									
										vendored
									
									
								
							@@ -42,4 +42,4 @@ jobs:
 | 
			
		||||
        working-directory: ./packages/mermaid
 | 
			
		||||
        run: pnpm run docs:build
 | 
			
		||||
 | 
			
		||||
      - uses: autofix-ci/action@551dded8c6cc8a1054039c8bc0b8b48c51dfc6ef # main
 | 
			
		||||
      - uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27 # main
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/e2e-timings.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/e2e-timings.yml
									
									
									
									
										vendored
									
									
								
							@@ -58,7 +58,7 @@ jobs:
 | 
			
		||||
          echo "EOF" >> $GITHUB_OUTPUT
 | 
			
		||||
 | 
			
		||||
      - name: Commit and create pull request
 | 
			
		||||
        uses: peter-evans/create-pull-request@889dce9eaba7900ce30494f5e1ac7220b27e5c81
 | 
			
		||||
        uses: peter-evans/create-pull-request@07cbaebb4bfc9c5d7db426ea5a5f585df29dd0a0
 | 
			
		||||
        with:
 | 
			
		||||
          add-paths: |
 | 
			
		||||
            cypress/timings.json
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								.github/workflows/pr-labeler.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								.github/workflows/pr-labeler.yml
									
									
									
									
										vendored
									
									
								
							@@ -29,3 +29,29 @@ jobs:
 | 
			
		||||
          disable-releaser: true
 | 
			
		||||
        env:
 | 
			
		||||
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
 | 
			
		||||
      - name: Add "Sponsored by MermaidChart" label
 | 
			
		||||
        uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
 | 
			
		||||
        with:
 | 
			
		||||
          github-token: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
          script: |
 | 
			
		||||
            const prNumber = context.payload.pull_request.number;
 | 
			
		||||
            const { data: commits } = await github.rest.pulls.listCommits({
 | 
			
		||||
              owner: context.repo.owner,
 | 
			
		||||
              repo: context.repo.repo,
 | 
			
		||||
              pull_number: prNumber,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            const isSponsored = commits.every(
 | 
			
		||||
              (c) => c.commit.author.email?.endsWith('@mermaidchart.com')
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            if (isSponsored) {
 | 
			
		||||
              console.log('PR is sponsored. Adding label.');
 | 
			
		||||
              await github.rest.issues.addLabels({
 | 
			
		||||
                owner: context.repo.owner,
 | 
			
		||||
                repo: context.repo.repo,
 | 
			
		||||
                issue_number: prNumber,
 | 
			
		||||
                labels: ['Sponsored by MermaidChart'],
 | 
			
		||||
              });
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1005
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										1005
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1
									
								
								CHANGELOG.md
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								CHANGELOG.md
									
									
									
									
									
										Symbolic link
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
./packages/mermaid/CHANGELOG.md
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
import { MockedD3 } from '../packages/mermaid/src/tests/MockedD3.js';
 | 
			
		||||
 | 
			
		||||
export const select = function () {
 | 
			
		||||
  return new MockedD3();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const selectAll = function () {
 | 
			
		||||
  return new MockedD3();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const curveBasis = 'basis';
 | 
			
		||||
export const curveLinear = 'linear';
 | 
			
		||||
export const curveCardinal = 'cardinal';
 | 
			
		||||
@@ -26,7 +26,10 @@ export default eyesPlugin(
 | 
			
		||||
        config.env.useArgos = process.env.RUN_VISUAL_TEST === 'true';
 | 
			
		||||
 | 
			
		||||
        if (config.env.useArgos) {
 | 
			
		||||
          registerArgosTask(on, config);
 | 
			
		||||
          registerArgosTask(on, config, {
 | 
			
		||||
            // Enable upload to Argos only when it runs on CI.
 | 
			
		||||
            uploadToArgos: !!process.env.CI,
 | 
			
		||||
          });
 | 
			
		||||
        } else {
 | 
			
		||||
          addMatchImageSnapshotPlugin(on, config);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -384,4 +384,17 @@ describe('Block diagram', () => {
 | 
			
		||||
      {}
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('BL30: block should overflow if too wide for columns', () => {
 | 
			
		||||
    imgSnapshotTest(
 | 
			
		||||
      `block-beta
 | 
			
		||||
  columns 2
 | 
			
		||||
  fit:2
 | 
			
		||||
  overflow:3
 | 
			
		||||
  short:1
 | 
			
		||||
  also_overflow:2
 | 
			
		||||
`,
 | 
			
		||||
      {}
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -495,4 +495,21 @@ describe('Class diagram', () => {
 | 
			
		||||
      cy.get('a').should('have.attr', 'target', '_blank').should('have.attr', 'rel', 'noopener');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('Include char sequence "graph" in text (#6795)', () => {
 | 
			
		||||
    it('has a label with char sequence "graph"', () => {
 | 
			
		||||
      imgSnapshotTest(
 | 
			
		||||
        `
 | 
			
		||||
        classDiagram
 | 
			
		||||
          class Person {
 | 
			
		||||
            +String name
 | 
			
		||||
            -Int id
 | 
			
		||||
            #double age
 | 
			
		||||
            +Text demographicProfile
 | 
			
		||||
          }
 | 
			
		||||
        `,
 | 
			
		||||
        { flowchart: { defaultRenderer: 'elk' } }
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -354,4 +354,19 @@ ORDER ||--|{ LINE-ITEM : contains
 | 
			
		||||
      { logLevel: 1 }
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('Include char sequence "graph" in text (#6795)', () => {
 | 
			
		||||
    it('has a label with char sequence "graph"', () => {
 | 
			
		||||
      imgSnapshotTest(
 | 
			
		||||
        `
 | 
			
		||||
        erDiagram
 | 
			
		||||
          p[Photograph] {
 | 
			
		||||
            varchar(12) jobId
 | 
			
		||||
            date dateCreated
 | 
			
		||||
          }
 | 
			
		||||
        `,
 | 
			
		||||
        { flowchart: { defaultRenderer: 'elk' } }
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1113,4 +1113,24 @@ end
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('6617: Per Link Curve Styling using edge Ids', () => {
 | 
			
		||||
    imgSnapshotTest(
 | 
			
		||||
      `flowchart TD
 | 
			
		||||
      A e1@-->B e5@--> E
 | 
			
		||||
      E e7@--> D
 | 
			
		||||
      B e3@-->D
 | 
			
		||||
      A e2@-->C e4@-->D
 | 
			
		||||
      C e6@--> F
 | 
			
		||||
      F e8@--> D
 | 
			
		||||
      e1@{ curve: natural }
 | 
			
		||||
      e2@{ curve: stepAfter }
 | 
			
		||||
      e3@{ curve: monotoneY }
 | 
			
		||||
      e4@{ curve: bumpY }
 | 
			
		||||
      e5@{ curve: linear }
 | 
			
		||||
      e6@{ curve: catmullRom }
 | 
			
		||||
      e7@{ curve: cardinal }
 | 
			
		||||
      `
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -246,5 +246,22 @@ Word!\`]
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  describe('Include char sequence "graph" in text (#6795)', () => {
 | 
			
		||||
    it('has a label with char sequence "graph"', () => {
 | 
			
		||||
      imgSnapshotTest(
 | 
			
		||||
        `
 | 
			
		||||
        mindmap
 | 
			
		||||
          root
 | 
			
		||||
            Photograph
 | 
			
		||||
              Waterfall
 | 
			
		||||
              Landscape
 | 
			
		||||
            Geography
 | 
			
		||||
              Mountains
 | 
			
		||||
              Rocks
 | 
			
		||||
        `,
 | 
			
		||||
        { flowchart: { defaultRenderer: 'elk' } }
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  /* The end */
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import { imgSnapshotTest } from '../../helpers/util';
 | 
			
		||||
 | 
			
		||||
describe('packet structure', () => {
 | 
			
		||||
  it('should render a simple packet diagram', () => {
 | 
			
		||||
  it('should render a simple packet-beta diagram', () => {
 | 
			
		||||
    imgSnapshotTest(
 | 
			
		||||
      `packet-beta
 | 
			
		||||
  title Hello world
 | 
			
		||||
@@ -10,9 +10,18 @@ describe('packet structure', () => {
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should render a simple packet diagram', () => {
 | 
			
		||||
    imgSnapshotTest(
 | 
			
		||||
      `packet
 | 
			
		||||
  title Hello world
 | 
			
		||||
  0-10: "hello"
 | 
			
		||||
`
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should render a simple packet diagram without ranges', () => {
 | 
			
		||||
    imgSnapshotTest(
 | 
			
		||||
      `packet-beta
 | 
			
		||||
      `packet
 | 
			
		||||
  0: "h"
 | 
			
		||||
  1: "i"
 | 
			
		||||
`
 | 
			
		||||
@@ -21,7 +30,7 @@ describe('packet structure', () => {
 | 
			
		||||
 | 
			
		||||
  it('should render a complex packet diagram', () => {
 | 
			
		||||
    imgSnapshotTest(
 | 
			
		||||
      `packet-beta
 | 
			
		||||
      `packet
 | 
			
		||||
        0-15: "Source Port"
 | 
			
		||||
        16-31: "Destination Port"
 | 
			
		||||
        32-63: "Sequence Number"
 | 
			
		||||
@@ -52,7 +61,7 @@ describe('packet structure', () => {
 | 
			
		||||
        packet:
 | 
			
		||||
          showBits: false
 | 
			
		||||
      ---
 | 
			
		||||
      packet-beta
 | 
			
		||||
      packet
 | 
			
		||||
        0-15: "Source Port"
 | 
			
		||||
        16-31: "Destination Port"
 | 
			
		||||
        32-63: "Sequence Number"
 | 
			
		||||
 
 | 
			
		||||
@@ -2,219 +2,219 @@
 | 
			
		||||
  "durations": [
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/other/configuration.spec.js",
 | 
			
		||||
      "duration": 5659
 | 
			
		||||
      "duration": 5672
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/other/external-diagrams.spec.js",
 | 
			
		||||
      "duration": 2015
 | 
			
		||||
      "duration": 1990
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/other/ghsa.spec.js",
 | 
			
		||||
      "duration": 3195
 | 
			
		||||
      "duration": 3186
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/other/iife.spec.js",
 | 
			
		||||
      "duration": 1976
 | 
			
		||||
      "duration": 1948
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/other/interaction.spec.js",
 | 
			
		||||
      "duration": 11149
 | 
			
		||||
      "duration": 11938
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/other/rerender.spec.js",
 | 
			
		||||
      "duration": 1910
 | 
			
		||||
      "duration": 1932
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/other/xss.spec.js",
 | 
			
		||||
      "duration": 26998
 | 
			
		||||
      "duration": 27237
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/appli.spec.js",
 | 
			
		||||
      "duration": 3176
 | 
			
		||||
      "duration": 3170
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/architecture.spec.ts",
 | 
			
		||||
      "duration": 110
 | 
			
		||||
      "duration": 104
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/block.spec.js",
 | 
			
		||||
      "duration": 16265
 | 
			
		||||
      "duration": 17390
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/c4.spec.js",
 | 
			
		||||
      "duration": 5431
 | 
			
		||||
      "duration": 5296
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/classDiagram-elk-v3.spec.js",
 | 
			
		||||
      "duration": 38025
 | 
			
		||||
      "duration": 39004
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/classDiagram-handDrawn-v3.spec.js",
 | 
			
		||||
      "duration": 36179
 | 
			
		||||
      "duration": 37653
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/classDiagram-v2.spec.js",
 | 
			
		||||
      "duration": 22386
 | 
			
		||||
      "duration": 23278
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/classDiagram-v3.spec.js",
 | 
			
		||||
      "duration": 35378
 | 
			
		||||
      "duration": 36645
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/classDiagram.spec.js",
 | 
			
		||||
      "duration": 14967
 | 
			
		||||
      "duration": 15418
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/conf-and-directives.spec.js",
 | 
			
		||||
      "duration": 9140
 | 
			
		||||
      "duration": 9684
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/current.spec.js",
 | 
			
		||||
      "duration": 2652
 | 
			
		||||
      "duration": 2570
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/erDiagram-unified.spec.js",
 | 
			
		||||
      "duration": 82257
 | 
			
		||||
      "duration": 84687
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/erDiagram.spec.js",
 | 
			
		||||
      "duration": 14138
 | 
			
		||||
      "duration": 14819
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/errorDiagram.spec.js",
 | 
			
		||||
      "duration": 3718
 | 
			
		||||
      "duration": 3371
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/flowchart-elk.spec.js",
 | 
			
		||||
      "duration": 39683
 | 
			
		||||
      "duration": 39925
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/flowchart-handDrawn.spec.js",
 | 
			
		||||
      "duration": 28676
 | 
			
		||||
      "duration": 34694
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/flowchart-icon.spec.js",
 | 
			
		||||
      "duration": 7080
 | 
			
		||||
      "duration": 7137
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/flowchart-shape-alias.spec.ts",
 | 
			
		||||
      "duration": 23175
 | 
			
		||||
      "duration": 24740
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/flowchart-v2.spec.js",
 | 
			
		||||
      "duration": 40846
 | 
			
		||||
      "duration": 42077
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/flowchart.spec.js",
 | 
			
		||||
      "duration": 29743
 | 
			
		||||
      "duration": 30642
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/gantt.spec.js",
 | 
			
		||||
      "duration": 17352
 | 
			
		||||
      "duration": 18085
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/gitGraph.spec.js",
 | 
			
		||||
      "duration": 48514
 | 
			
		||||
      "duration": 50107
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/iconShape.spec.ts",
 | 
			
		||||
      "duration": 262422
 | 
			
		||||
      "duration": 276279
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/imageShape.spec.ts",
 | 
			
		||||
      "duration": 54513
 | 
			
		||||
      "duration": 56505
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/info.spec.ts",
 | 
			
		||||
      "duration": 3025
 | 
			
		||||
      "duration": 3036
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/journey.spec.js",
 | 
			
		||||
      "duration": 6994
 | 
			
		||||
      "duration": 6889
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/kanban.spec.ts",
 | 
			
		||||
      "duration": 7346
 | 
			
		||||
      "duration": 7353
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/katex.spec.js",
 | 
			
		||||
      "duration": 3642
 | 
			
		||||
      "duration": 3580
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/marker_unique_id.spec.js",
 | 
			
		||||
      "duration": 2464
 | 
			
		||||
      "duration": 2508
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/mindmap.spec.ts",
 | 
			
		||||
      "duration": 10882
 | 
			
		||||
      "duration": 10939
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/newShapes.spec.ts",
 | 
			
		||||
      "duration": 142092
 | 
			
		||||
      "duration": 149102
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/oldShapes.spec.ts",
 | 
			
		||||
      "duration": 109340
 | 
			
		||||
      "duration": 113987
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/packet.spec.ts",
 | 
			
		||||
      "duration": 4167
 | 
			
		||||
      "duration": 4060
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/pie.spec.ts",
 | 
			
		||||
      "duration": 5736
 | 
			
		||||
      "duration": 5715
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/quadrantChart.spec.js",
 | 
			
		||||
      "duration": 8628
 | 
			
		||||
      "duration": 8945
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/radar.spec.js",
 | 
			
		||||
      "duration": 5311
 | 
			
		||||
      "duration": 5337
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/requirement.spec.js",
 | 
			
		||||
      "duration": 2619
 | 
			
		||||
      "duration": 2643
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/requirementDiagram-unified.spec.js",
 | 
			
		||||
      "duration": 50640
 | 
			
		||||
      "duration": 52072
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/sankey.spec.ts",
 | 
			
		||||
      "duration": 6735
 | 
			
		||||
      "duration": 6692
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/sequencediagram.spec.js",
 | 
			
		||||
      "duration": 34777
 | 
			
		||||
      "duration": 35721
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/stateDiagram-v2.spec.js",
 | 
			
		||||
      "duration": 24440
 | 
			
		||||
      "duration": 26030
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/stateDiagram.spec.js",
 | 
			
		||||
      "duration": 15476
 | 
			
		||||
      "duration": 16333
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/theme.spec.js",
 | 
			
		||||
      "duration": 27932
 | 
			
		||||
      "duration": 29287
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/timeline.spec.ts",
 | 
			
		||||
      "duration": 8162
 | 
			
		||||
      "duration": 8491
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/treemap.spec.ts",
 | 
			
		||||
      "duration": 11763
 | 
			
		||||
      "duration": 12291
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/xyChart.spec.js",
 | 
			
		||||
      "duration": 19759
 | 
			
		||||
      "duration": 20651
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "spec": "cypress/integration/rendering/zenuml.spec.js",
 | 
			
		||||
      "duration": 3316
 | 
			
		||||
      "duration": 3218
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
    <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
 | 
			
		||||
    <link
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
 | 
			
		||||
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/font-awesome.min.css"
 | 
			
		||||
    />
 | 
			
		||||
    <link
 | 
			
		||||
      href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
 | 
			
		||||
    <div class="diagrams">
 | 
			
		||||
      <pre class="mermaid">
 | 
			
		||||
      packet-beta
 | 
			
		||||
      packet
 | 
			
		||||
        0-15: "Source Port"
 | 
			
		||||
        16-31: "Destination Port"
 | 
			
		||||
        32-63: "Sequence Number"
 | 
			
		||||
@@ -44,7 +44,7 @@
 | 
			
		||||
        packet:
 | 
			
		||||
          showBits: false
 | 
			
		||||
      ---
 | 
			
		||||
      packet-beta
 | 
			
		||||
      packet
 | 
			
		||||
        0-15: "Source Port"
 | 
			
		||||
        16-31: "Destination Port"
 | 
			
		||||
        32-63: "Sequence Number"
 | 
			
		||||
@@ -70,7 +70,7 @@
 | 
			
		||||
      config:
 | 
			
		||||
        theme: forest
 | 
			
		||||
      ---
 | 
			
		||||
      packet-beta
 | 
			
		||||
      packet
 | 
			
		||||
        title Forest theme
 | 
			
		||||
        0-15: "Source Port"
 | 
			
		||||
        16-31: "Destination Port"
 | 
			
		||||
@@ -97,7 +97,7 @@
 | 
			
		||||
      config:
 | 
			
		||||
        theme: dark
 | 
			
		||||
      ---
 | 
			
		||||
      packet-beta
 | 
			
		||||
      packet
 | 
			
		||||
        title Dark theme
 | 
			
		||||
        0-15: "Source Port"
 | 
			
		||||
        16-31: "Destination Port"
 | 
			
		||||
 
 | 
			
		||||
@@ -301,7 +301,7 @@ If you are adding a feature, you will definitely need to add tests. Depending on
 | 
			
		||||
 | 
			
		||||
Unit tests are tests that test a single function or module. They are the easiest to write and the fastest to run.
 | 
			
		||||
 | 
			
		||||
Unit tests are mandatory for all code except the renderers. (The renderers are tested with integration tests.)
 | 
			
		||||
Unit tests are mandatory for all code except the layout tests. (The layouts are tested with integration tests.)
 | 
			
		||||
 | 
			
		||||
We use [Vitest](https://vitest.dev) to run unit tests.
 | 
			
		||||
 | 
			
		||||
@@ -327,6 +327,30 @@ When using Docker prepend your command with `./run`:
 | 
			
		||||
./run pnpm test
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
##### Testing the DOM
 | 
			
		||||
 | 
			
		||||
One can use `jsdomIt` to test any part of Mermaid that interacts with the DOM, as long as it is not related to the layout.
 | 
			
		||||
 | 
			
		||||
The function `jsdomIt` ([developed in utils.ts](../../tests/util.ts)) overrides `it` from `vitest`, and creates a pseudo-browser environment that works almost like the real deal for the duration of the test. It uses JSDOM to create a DOM, and adds objects `window` and `document` to `global` to mock the browser environment.
 | 
			
		||||
 | 
			
		||||
> \[!NOTE]
 | 
			
		||||
> The layout cannot work in `jsdomIt` tests because JSDOM has no rendering engine, hence the pseudo-browser environment.
 | 
			
		||||
 | 
			
		||||
Example :
 | 
			
		||||
 | 
			
		||||
```typescript
 | 
			
		||||
import { ensureNodeFromSelector, jsdomIt } from './tests/util.js';
 | 
			
		||||
 | 
			
		||||
jsdomIt('should add element "thing" in the SVG', ({ svg }) => {
 | 
			
		||||
  // Code in this block runs in a pseudo-browser environment
 | 
			
		||||
  addThing(svg); // The svg item is the D3 selection of the SVG node
 | 
			
		||||
  const svgNode = ensureNodeFromSelector('svg'); // Retrieve the DOM node using the DOM API
 | 
			
		||||
  expect(svgNode.querySelector('thing')).not.toBeNull(); // Test the structure of the SVG
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
They can be used to test any method that interacts with the DOM, including for testing renderers. For renderers, additional integration testing is necessary to test the layout though.
 | 
			
		||||
 | 
			
		||||
#### Integration / End-to-End (E2E) Tests
 | 
			
		||||
 | 
			
		||||
These test the rendering and visual appearance of the diagrams.
 | 
			
		||||
 
 | 
			
		||||
@@ -111,3 +111,13 @@ const themes = {
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The actual options and values for the colors are defined in **src/theme/theme-\[xyz].js**. If you provide the options your diagram needs in the existing theme files then the theming will work smoothly without hiccups.
 | 
			
		||||
 | 
			
		||||
## Examples
 | 
			
		||||
 | 
			
		||||
The `@mermaid-js/examples` package contains a collection of examples that are used by tools like mermaid.live to help users get started with the new diagram.
 | 
			
		||||
 | 
			
		||||
You can duplicate an existing diagram example file, eg: `packages/examples/src/examples/flowchart.ts`, and modify it with details specific to your diagram.
 | 
			
		||||
 | 
			
		||||
Then you can import the example in the `packages/examples/src/index.ts` file and add it to the `examples` array.
 | 
			
		||||
 | 
			
		||||
Each diagram should have at least one example, and that should be marked as default. It is good to add more examples to showcase different features of the diagram.
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
 | 
			
		||||
# Interface: ExternalDiagramDefinition
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:99](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L99)
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:94](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L94)
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
 | 
			
		||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/diagram-api/types.ts:99](https://github.com/me
 | 
			
		||||
 | 
			
		||||
> **detector**: `DiagramDetector`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:101](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L101)
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:96](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L96)
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
@@ -26,7 +26,7 @@ Defined in: [packages/mermaid/src/diagram-api/types.ts:101](https://github.com/m
 | 
			
		||||
 | 
			
		||||
> **id**: `string`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:100](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L100)
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:95](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L95)
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
@@ -34,4 +34,4 @@ Defined in: [packages/mermaid/src/diagram-api/types.ts:100](https://github.com/m
 | 
			
		||||
 | 
			
		||||
> **loader**: `DiagramLoader`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:102](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L102)
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:97](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L97)
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
 | 
			
		||||
# Interface: Mermaid
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:418](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L418)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:429](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L429)
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
 | 
			
		||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/mermaid.ts:418](https://github.com/mermaid-js/
 | 
			
		||||
 | 
			
		||||
> **contentLoaded**: () => `void`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:436](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L436)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:447](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L447)
 | 
			
		||||
 | 
			
		||||
\##contentLoaded Callback function that is called when page is loaded. This functions fetches
 | 
			
		||||
configuration for mermaid rendering and calls init for rendering the mermaid diagrams on the
 | 
			
		||||
@@ -34,7 +34,7 @@ page.
 | 
			
		||||
 | 
			
		||||
> **detectType**: (`text`, `config`?) => `string`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:438](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L438)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:449](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L449)
 | 
			
		||||
 | 
			
		||||
Detects the type of the graph text.
 | 
			
		||||
 | 
			
		||||
@@ -86,11 +86,28 @@ A graph definition key
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
### getRegisteredDiagramsMetadata()
 | 
			
		||||
 | 
			
		||||
> **getRegisteredDiagramsMetadata**: () => `Pick`<[`ExternalDiagramDefinition`](ExternalDiagramDefinition.md), `"id"`>\[]
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:451](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L451)
 | 
			
		||||
 | 
			
		||||
Gets the metadata for all registered diagrams.
 | 
			
		||||
Currently only the id is returned.
 | 
			
		||||
 | 
			
		||||
#### Returns
 | 
			
		||||
 | 
			
		||||
`Pick`<[`ExternalDiagramDefinition`](ExternalDiagramDefinition.md), `"id"`>\[]
 | 
			
		||||
 | 
			
		||||
An array of objects with the id of the diagram.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
### ~~init()~~
 | 
			
		||||
 | 
			
		||||
> **init**: (`config`?, `nodes`?, `callback`?) => `Promise`<`void`>
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:431](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L431)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:442](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L442)
 | 
			
		||||
 | 
			
		||||
## init
 | 
			
		||||
 | 
			
		||||
@@ -138,7 +155,7 @@ Use [initialize](Mermaid.md#initialize) and [run](Mermaid.md#run) instead.
 | 
			
		||||
 | 
			
		||||
> **initialize**: (`config`) => `void`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:435](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L435)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:446](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L446)
 | 
			
		||||
 | 
			
		||||
Used to set configurations for mermaid.
 | 
			
		||||
This function should be called before the run function.
 | 
			
		||||
@@ -161,7 +178,7 @@ Configuration object for mermaid.
 | 
			
		||||
 | 
			
		||||
> **mermaidAPI**: `Readonly`<{ `defaultConfig`: [`MermaidConfig`](MermaidConfig.md); `getConfig`: () => [`MermaidConfig`](MermaidConfig.md); `getDiagramFromText`: (`text`, `metadata`) => `Promise`<`Diagram`>; `getSiteConfig`: () => [`MermaidConfig`](MermaidConfig.md); `globalReset`: () => `void`; `initialize`: (`userOptions`) => `void`; `parse`: (`text`, `parseOptions`) => `Promise`<`false` | [`ParseResult`](ParseResult.md)>(`text`, `parseOptions`?) => `Promise`<[`ParseResult`](ParseResult.md)>; `render`: (`id`, `text`, `svgContainingElement`?) => `Promise`<[`RenderResult`](RenderResult.md)>; `reset`: () => `void`; `setConfig`: (`conf`) => [`MermaidConfig`](MermaidConfig.md); `updateSiteConfig`: (`conf`) => [`MermaidConfig`](MermaidConfig.md); }>
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:425](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L425)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:436](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L436)
 | 
			
		||||
 | 
			
		||||
**`Internal`**
 | 
			
		||||
 | 
			
		||||
@@ -175,7 +192,7 @@ Use [parse](Mermaid.md#parse) and [render](Mermaid.md#render) instead. Please [o
 | 
			
		||||
 | 
			
		||||
> **parse**: (`text`, `parseOptions`) => `Promise`<`false` | [`ParseResult`](ParseResult.md)>(`text`, `parseOptions`?) => `Promise`<[`ParseResult`](ParseResult.md)>
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:426](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L426)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:437](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L437)
 | 
			
		||||
 | 
			
		||||
Parse the text and validate the syntax.
 | 
			
		||||
 | 
			
		||||
@@ -243,7 +260,7 @@ Error if the diagram is invalid and parseOptions.suppressErrors is false or not
 | 
			
		||||
 | 
			
		||||
> `optional` **parseError**: [`ParseErrorFunction`](../type-aliases/ParseErrorFunction.md)
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:420](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L420)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:431](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L431)
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
@@ -251,7 +268,7 @@ Defined in: [packages/mermaid/src/mermaid.ts:420](https://github.com/mermaid-js/
 | 
			
		||||
 | 
			
		||||
> **registerExternalDiagrams**: (`diagrams`, `opts`) => `Promise`<`void`>
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:434](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L434)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:445](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L445)
 | 
			
		||||
 | 
			
		||||
Used to register external diagram types.
 | 
			
		||||
 | 
			
		||||
@@ -281,7 +298,7 @@ If opts.lazyLoad is false, the diagrams will be loaded immediately.
 | 
			
		||||
 | 
			
		||||
> **registerIconPacks**: (`iconLoaders`) => `void`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:439](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L439)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:450](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L450)
 | 
			
		||||
 | 
			
		||||
#### Parameters
 | 
			
		||||
 | 
			
		||||
@@ -299,7 +316,7 @@ Defined in: [packages/mermaid/src/mermaid.ts:439](https://github.com/mermaid-js/
 | 
			
		||||
 | 
			
		||||
> **registerLayoutLoaders**: (`loaders`) => `void`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:433](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L433)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:444](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L444)
 | 
			
		||||
 | 
			
		||||
#### Parameters
 | 
			
		||||
 | 
			
		||||
@@ -317,7 +334,7 @@ Defined in: [packages/mermaid/src/mermaid.ts:433](https://github.com/mermaid-js/
 | 
			
		||||
 | 
			
		||||
> **render**: (`id`, `text`, `svgContainingElement`?) => `Promise`<[`RenderResult`](RenderResult.md)>
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:427](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L427)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:438](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L438)
 | 
			
		||||
 | 
			
		||||
#### Parameters
 | 
			
		||||
 | 
			
		||||
@@ -349,7 +366,7 @@ Deprecated for external use.
 | 
			
		||||
 | 
			
		||||
> **run**: (`options`) => `Promise`<`void`>
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:432](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L432)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:443](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L443)
 | 
			
		||||
 | 
			
		||||
## run
 | 
			
		||||
 | 
			
		||||
@@ -393,7 +410,7 @@ Optional runtime configs
 | 
			
		||||
 | 
			
		||||
> **setParseErrorHandler**: (`parseErrorHandler`) => `void`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:437](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L437)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:448](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L448)
 | 
			
		||||
 | 
			
		||||
## setParseErrorHandler Alternative to directly setting parseError using:
 | 
			
		||||
 | 
			
		||||
@@ -424,4 +441,4 @@ New parseError() callback.
 | 
			
		||||
 | 
			
		||||
> **startOnLoad**: `boolean`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:419](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L419)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:430](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L430)
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
 | 
			
		||||
# Interface: ParseOptions
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:59](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L59)
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:72](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L72)
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
 | 
			
		||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:59](https://github.com/mermaid-js/mer
 | 
			
		||||
 | 
			
		||||
> `optional` **suppressErrors**: `boolean`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:64](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L64)
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:77](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L77)
 | 
			
		||||
 | 
			
		||||
If `true`, parse will return `false` instead of throwing error when the diagram is invalid.
 | 
			
		||||
The `parseError` function will not be called.
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
 | 
			
		||||
# Interface: ParseResult
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:67](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L67)
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:80](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L80)
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
 | 
			
		||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:67](https://github.com/mermaid-js/mer
 | 
			
		||||
 | 
			
		||||
> **config**: [`MermaidConfig`](MermaidConfig.md)
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:75](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L75)
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:88](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L88)
 | 
			
		||||
 | 
			
		||||
The config passed as YAML frontmatter or directives
 | 
			
		||||
 | 
			
		||||
@@ -28,6 +28,6 @@ The config passed as YAML frontmatter or directives
 | 
			
		||||
 | 
			
		||||
> **diagramType**: `string`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:71](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L71)
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:84](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L84)
 | 
			
		||||
 | 
			
		||||
The diagram type, e.g. 'flowchart', 'sequence', etc.
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
 | 
			
		||||
# Interface: RenderResult
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:85](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L85)
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:98](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L98)
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
 | 
			
		||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:85](https://github.com/mermaid-js/mer
 | 
			
		||||
 | 
			
		||||
> `optional` **bindFunctions**: (`element`) => `void`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:103](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L103)
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:116](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L116)
 | 
			
		||||
 | 
			
		||||
Bind function to be called after the svg has been inserted into the DOM.
 | 
			
		||||
This is necessary for adding event listeners to the elements in the svg.
 | 
			
		||||
@@ -45,7 +45,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present.
 | 
			
		||||
 | 
			
		||||
> **diagramType**: `string`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:93](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L93)
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:106](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L106)
 | 
			
		||||
 | 
			
		||||
The diagram type, e.g. 'flowchart', 'sequence', etc.
 | 
			
		||||
 | 
			
		||||
@@ -55,6 +55,6 @@ The diagram type, e.g. 'flowchart', 'sequence', etc.
 | 
			
		||||
 | 
			
		||||
> **svg**: `string`
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:89](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L89)
 | 
			
		||||
Defined in: [packages/mermaid/src/types.ts:102](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L102)
 | 
			
		||||
 | 
			
		||||
The svg code for the rendered graph.
 | 
			
		||||
 
 | 
			
		||||
@@ -12,4 +12,4 @@
 | 
			
		||||
 | 
			
		||||
> **SVG**: `d3.Selection`<`SVGSVGElement`, `unknown`, `Element` | `null`, `unknown`>
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:130](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L130)
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:126](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L126)
 | 
			
		||||
 
 | 
			
		||||
@@ -12,4 +12,4 @@
 | 
			
		||||
 | 
			
		||||
> **SVGGroup**: `d3.Selection`<`SVGGElement`, `unknown`, `Element` | `null`, `unknown`>
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:132](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L132)
 | 
			
		||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:128](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L128)
 | 
			
		||||
 
 | 
			
		||||
@@ -12,4 +12,4 @@
 | 
			
		||||
 | 
			
		||||
> `const` **default**: [`Mermaid`](../interfaces/Mermaid.md)
 | 
			
		||||
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:442](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L442)
 | 
			
		||||
Defined in: [packages/mermaid/src/mermaid.ts:454](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L454)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										189
									
								
								docs/diagrams/flowchart-code-flow.mmd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								docs/diagrams/flowchart-code-flow.mmd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,189 @@
 | 
			
		||||
---
 | 
			
		||||
references:
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/flowchart/flowDiagram.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/flowchart/flowDb.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/flowchart/flowDetector.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/flowchart/styles.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/flowchart/types.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/flowchart/flowChartShapes.js"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/flowchart/parser/flowParser.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/flowchart/elk/detector.ts"
 | 
			
		||||
generationTime: 2025-07-23T10:31:53.266Z
 | 
			
		||||
---
 | 
			
		||||
flowchart TD
 | 
			
		||||
    %% Entry Points and Detection
 | 
			
		||||
    Input["User Input Text"] --> Detection{Detection Phase}
 | 
			
		||||
    
 | 
			
		||||
    Detection --> flowDetector["flowDetector.ts<br/>detector(txt, config)"]
 | 
			
		||||
    Detection --> flowDetectorV2["flowDetector-v2.ts<br/>detector(txt, config)"]
 | 
			
		||||
    Detection --> elkDetector["elk/detector.ts<br/>detector(txt, config)"]
 | 
			
		||||
    
 | 
			
		||||
    flowDetector --> |"Checks /^\s*graph/"| DetectLegacy{Legacy Flowchart?}
 | 
			
		||||
    flowDetectorV2 --> |"Checks /^\s*flowchart/"| DetectNew{New Flowchart?}
 | 
			
		||||
    elkDetector --> |"Checks /^\s*flowchart-elk/"| DetectElk{ELK Layout?}
 | 
			
		||||
    
 | 
			
		||||
    DetectLegacy --> |Yes| LoadDiagram
 | 
			
		||||
    DetectNew --> |Yes| LoadDiagram
 | 
			
		||||
    DetectElk --> |Yes| LoadDiagram
 | 
			
		||||
    
 | 
			
		||||
    %% Loading Phase
 | 
			
		||||
    LoadDiagram["loader() function"] --> flowDiagram["flowDiagram.ts<br/>diagram object"]
 | 
			
		||||
    
 | 
			
		||||
    flowDiagram --> DiagramStructure{Diagram Components}
 | 
			
		||||
    DiagramStructure --> Parser["parser: flowParser"]
 | 
			
		||||
    DiagramStructure --> Database["db: new FlowDB()"]
 | 
			
		||||
    DiagramStructure --> Renderer["renderer: flowRenderer-v3-unified"]
 | 
			
		||||
    DiagramStructure --> Styles["styles: flowStyles"]
 | 
			
		||||
    DiagramStructure --> Init["init: (cnf: MermaidConfig)"]
 | 
			
		||||
    
 | 
			
		||||
    %% Parser Phase
 | 
			
		||||
    Parser --> flowParser["parser/flowParser.ts<br/>newParser.parse(src)"]
 | 
			
		||||
    flowParser --> |"Preprocesses src"| RemoveWhitespace["Remove trailing whitespace<br/>src.replace(/}\s*\n/g, '}\n')"]
 | 
			
		||||
    RemoveWhitespace --> flowJison["parser/flow.jison<br/>flowJisonParser.parse(newSrc)"]
 | 
			
		||||
    
 | 
			
		||||
    flowJison --> ParseGraph["Parse Graph Structure"]
 | 
			
		||||
    ParseGraph --> ParseVertices["Parse Vertices"]
 | 
			
		||||
    ParseGraph --> ParseEdges["Parse Edges"]
 | 
			
		||||
    ParseGraph --> ParseSubgraphs["Parse Subgraphs"]
 | 
			
		||||
    ParseGraph --> ParseClasses["Parse Classes"]
 | 
			
		||||
    ParseGraph --> ParseStyles["Parse Styles"]
 | 
			
		||||
    
 | 
			
		||||
    %% Database Phase - FlowDB Class
 | 
			
		||||
    Database --> FlowDBClass["flowDb.ts<br/>FlowDB class"]
 | 
			
		||||
    
 | 
			
		||||
    FlowDBClass --> DBInit["constructor()<br/>- Initialize counters<br/>- Bind methods<br/>- Setup toolTips<br/>- Call clear()"]
 | 
			
		||||
    
 | 
			
		||||
    DBInit --> DBMethods{FlowDB Methods}
 | 
			
		||||
    
 | 
			
		||||
    DBMethods --> addVertex["addVertex(id, textObj, type, style,<br/>classes, dir, props, metadata)"]
 | 
			
		||||
    DBMethods --> addLink["addLink(_start[], _end[], linkData)"]
 | 
			
		||||
    DBMethods --> addSingleLink["addSingleLink(_start, _end, type, id)"]
 | 
			
		||||
    DBMethods --> setDirection["setDirection(dir)"]
 | 
			
		||||
    DBMethods --> addSubGraph["addSubGraph(nodes[], id, title)"]
 | 
			
		||||
    DBMethods --> addClass["addClass(id, style)"]
 | 
			
		||||
    DBMethods --> setClass["setClass(ids, className)"]
 | 
			
		||||
    DBMethods --> setTooltip["setTooltip(ids, tooltip)"]
 | 
			
		||||
    DBMethods --> setClickEvent["setClickEvent(id, functionName, args)"]
 | 
			
		||||
    DBMethods --> setClickFun["setClickFun(id, functionName, args)"]
 | 
			
		||||
    
 | 
			
		||||
    %% Vertex Processing
 | 
			
		||||
    addVertex --> VertexProcess{Vertex Processing}
 | 
			
		||||
    VertexProcess --> CreateVertex["Create FlowVertex object<br/>- id, labelType, domId<br/>- styles[], classes[]"]
 | 
			
		||||
    VertexProcess --> SanitizeText["sanitizeText(textObj.text)"]
 | 
			
		||||
    VertexProcess --> ParseMetadata["Parse YAML metadata<br/>yaml.load(yamlData)"]
 | 
			
		||||
    VertexProcess --> SetVertexProps["Set vertex properties<br/>- shape, label, icon, form<br/>- pos, img, constraint, w, h"]
 | 
			
		||||
    
 | 
			
		||||
    %% Edge Processing  
 | 
			
		||||
    addSingleLink --> EdgeProcess{Edge Processing}
 | 
			
		||||
    EdgeProcess --> CreateEdge["Create FlowEdge object<br/>- start, end, type, text<br/>- labelType, classes[]"]
 | 
			
		||||
    EdgeProcess --> ProcessLinkText["Process link text<br/>- sanitizeText()<br/>- strip quotes"]
 | 
			
		||||
    EdgeProcess --> SetEdgeProps["Set edge properties<br/>- type, stroke, length"]
 | 
			
		||||
    EdgeProcess --> GenerateEdgeId["Generate edge ID<br/>getEdgeId(start, end, counter)"]
 | 
			
		||||
    EdgeProcess --> ValidateEdgeLimit["Validate edge limit<br/>maxEdges check"]
 | 
			
		||||
    
 | 
			
		||||
    %% Data Collection
 | 
			
		||||
    DBMethods --> GetData["getData()"]
 | 
			
		||||
    GetData --> CollectNodes["Collect nodes[] from vertices"]
 | 
			
		||||
    GetData --> CollectEdges["Collect edges[] from edges"]
 | 
			
		||||
    GetData --> ProcessSubGraphs["Process subgraphs<br/>- parentDB Map<br/>- subGraphDB Map"]
 | 
			
		||||
    GetData --> AddNodeFromVertex["addNodeFromVertex()<br/>for each vertex"]
 | 
			
		||||
    GetData --> ProcessEdgeTypes["destructEdgeType()<br/>arrowTypeStart, arrowTypeEnd"]
 | 
			
		||||
    
 | 
			
		||||
    %% Node Creation
 | 
			
		||||
    AddNodeFromVertex --> NodeCreation{Node Creation}
 | 
			
		||||
    NodeCreation --> FindExistingNode["findNode(nodes, vertex.id)"]
 | 
			
		||||
    NodeCreation --> CreateBaseNode["Create base node<br/>- id, label, parentId<br/>- cssStyles, cssClasses<br/>- shape, domId, tooltip"]
 | 
			
		||||
    NodeCreation --> GetCompiledStyles["getCompiledStyles(classDefs)"]
 | 
			
		||||
    NodeCreation --> GetTypeFromVertex["getTypeFromVertex(vertex)"]
 | 
			
		||||
    
 | 
			
		||||
    %% Rendering Phase
 | 
			
		||||
    Renderer --> flowRendererV3["flowRenderer-v3-unified.ts<br/>draw(text, id, version, diag)"]
 | 
			
		||||
    
 | 
			
		||||
    flowRendererV3 --> RenderInit["Initialize rendering<br/>- getConfig()<br/>- handle securityLevel<br/>- getDiagramElement()"]
 | 
			
		||||
    
 | 
			
		||||
    RenderInit --> GetLayoutData["diag.db.getData()<br/>as LayoutData"]
 | 
			
		||||
    GetLayoutData --> SetupLayoutData["Setup layout data<br/>- type, layoutAlgorithm<br/>- direction, spacing<br/>- markers, diagramId"]
 | 
			
		||||
    
 | 
			
		||||
    SetupLayoutData --> CallRender["render(data4Layout, svg)"]
 | 
			
		||||
    CallRender --> SetupViewPort["setupViewPortForSVG(svg, padding)"]
 | 
			
		||||
    SetupViewPort --> ProcessLinks["Process vertex links<br/>- create anchor elements<br/>- handle click events"]
 | 
			
		||||
    
 | 
			
		||||
    %% Shape Rendering
 | 
			
		||||
    CallRender --> ShapeSystem["flowChartShapes.js<br/>Shape Functions"]
 | 
			
		||||
    
 | 
			
		||||
    ShapeSystem --> ShapeFunctions{Shape Functions}
 | 
			
		||||
    ShapeFunctions --> question["question(parent, bbox, node)"]
 | 
			
		||||
    ShapeFunctions --> hexagon["hexagon(parent, bbox, node)"]
 | 
			
		||||
    ShapeFunctions --> rect_left_inv_arrow["rect_left_inv_arrow(parent, bbox, node)"]
 | 
			
		||||
    ShapeFunctions --> lean_right["lean_right(parent, bbox, node)"]
 | 
			
		||||
    ShapeFunctions --> lean_left["lean_left(parent, bbox, node)"]
 | 
			
		||||
    
 | 
			
		||||
    ShapeFunctions --> insertPolygonShape["insertPolygonShape(parent, w, h, points)"]
 | 
			
		||||
    ShapeFunctions --> intersectPolygon["intersectPolygon(node, points, point)"]
 | 
			
		||||
    ShapeFunctions --> intersectRect["intersectRect(node, point)"]
 | 
			
		||||
    
 | 
			
		||||
    %% Styling System
 | 
			
		||||
    Styles --> stylesTS["styles.ts<br/>getStyles(options)"]
 | 
			
		||||
    stylesTS --> StyleOptions["FlowChartStyleOptions<br/>- arrowheadColor, border2<br/>- clusterBkg, mainBkg<br/>- fontFamily, textColor"]
 | 
			
		||||
    
 | 
			
		||||
    StyleOptions --> GenerateCSS["Generate CSS styles<br/>- .label, .cluster-label<br/>- .node, .edgePath<br/>- .flowchart-link, .edgeLabel"]
 | 
			
		||||
    GenerateCSS --> GetIconStyles["getIconStyles()"]
 | 
			
		||||
    
 | 
			
		||||
    %% Type System
 | 
			
		||||
    Parser --> TypeSystem["types.ts<br/>Type Definitions"]
 | 
			
		||||
    TypeSystem --> FlowVertex["FlowVertex interface"]
 | 
			
		||||
    TypeSystem --> FlowEdge["FlowEdge interface"]
 | 
			
		||||
    TypeSystem --> FlowClass["FlowClass interface"]
 | 
			
		||||
    TypeSystem --> FlowSubGraph["FlowSubGraph interface"]
 | 
			
		||||
    TypeSystem --> FlowVertexTypeParam["FlowVertexTypeParam<br/>Shape types"]
 | 
			
		||||
    
 | 
			
		||||
    %% Utility Functions
 | 
			
		||||
    DBMethods --> UtilityFunctions{Utility Functions}
 | 
			
		||||
    UtilityFunctions --> lookUpDomId["lookUpDomId(id)"]
 | 
			
		||||
    UtilityFunctions --> getClasses["getClasses()"]
 | 
			
		||||
    UtilityFunctions --> getDirection["getDirection()"]
 | 
			
		||||
    UtilityFunctions --> getVertices["getVertices()"]
 | 
			
		||||
    UtilityFunctions --> getEdges["getEdges()"]
 | 
			
		||||
    UtilityFunctions --> getSubGraphs["getSubGraphs()"]
 | 
			
		||||
    UtilityFunctions --> clear["clear()"]
 | 
			
		||||
    UtilityFunctions --> defaultConfig["defaultConfig()"]
 | 
			
		||||
    
 | 
			
		||||
    %% Event Handling
 | 
			
		||||
    ProcessLinks --> EventHandling{Event Handling}
 | 
			
		||||
    EventHandling --> setupToolTips["setupToolTips(element)"]
 | 
			
		||||
    EventHandling --> bindFunctions["bindFunctions(element)"]
 | 
			
		||||
    EventHandling --> runFunc["utils.runFunc(functionName, args)"]
 | 
			
		||||
    
 | 
			
		||||
    %% Common Database Functions
 | 
			
		||||
    DBMethods --> CommonDB["commonDb.js functions"]
 | 
			
		||||
    CommonDB --> setAccTitle["setAccTitle()"]
 | 
			
		||||
    CommonDB --> getAccTitle["getAccTitle()"]
 | 
			
		||||
    CommonDB --> setAccDescription["setAccDescription()"]
 | 
			
		||||
    CommonDB --> getAccDescription["getAccDescription()"]
 | 
			
		||||
    CommonDB --> setDiagramTitle["setDiagramTitle()"]
 | 
			
		||||
    CommonDB --> getDiagramTitle["getDiagramTitle()"]
 | 
			
		||||
    CommonDB --> commonClear["clear()"]
 | 
			
		||||
    
 | 
			
		||||
    %% Final Output
 | 
			
		||||
    ProcessLinks --> FinalSVG["Final SVG Output"]
 | 
			
		||||
    
 | 
			
		||||
    %% Layout Algorithm Selection
 | 
			
		||||
    SetupLayoutData --> LayoutAlgorithm{Layout Algorithm}
 | 
			
		||||
    LayoutAlgorithm --> Dagre["dagre<br/>(default)"]
 | 
			
		||||
    LayoutAlgorithm --> DagreWrapper["dagre-wrapper<br/>(v2 renderer)"]
 | 
			
		||||
    LayoutAlgorithm --> ELK["elk<br/>(external package)"]
 | 
			
		||||
    
 | 
			
		||||
    %% Testing Components
 | 
			
		||||
    FlowDBClass --> TestFiles["Test Files"]
 | 
			
		||||
    TestFiles --> flowDbSpec["flowDb.spec.ts"]
 | 
			
		||||
    TestFiles --> flowChartShapesSpec["flowChartShapes.spec.js"]
 | 
			
		||||
    TestFiles --> ParserTests["parser/*.spec.js files<br/>- flow-text.spec.js<br/>- flow-edges.spec.js<br/>- flow-style.spec.js<br/>- subgraph.spec.js"]
 | 
			
		||||
    
 | 
			
		||||
    %% Configuration
 | 
			
		||||
    Init --> ConfigSetup["Configuration Setup"]
 | 
			
		||||
    ConfigSetup --> FlowchartConfig["cnf.flowchart config"]
 | 
			
		||||
    ConfigSetup --> ArrowMarkers["arrowMarkerAbsolute"]
 | 
			
		||||
    ConfigSetup --> LayoutConfig["layout config"]
 | 
			
		||||
    ConfigSetup --> SetConfig["setConfig() calls"]
 | 
			
		||||
							
								
								
									
										307
									
								
								docs/diagrams/mermaid-api-sequence.mmd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										307
									
								
								docs/diagrams/mermaid-api-sequence.mmd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,307 @@
 | 
			
		||||
---
 | 
			
		||||
references:
 | 
			
		||||
  - "File: /packages/mermaid/src/mermaidAPI.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/mermaid.ts"
 | 
			
		||||
generationTime: 2025-01-28T16:30:00.000Z
 | 
			
		||||
---
 | 
			
		||||
sequenceDiagram
 | 
			
		||||
    participant User as User/Browser
 | 
			
		||||
    participant Mermaid as mermaid.ts
 | 
			
		||||
    participant Queue as executionQueue
 | 
			
		||||
    participant API as mermaidAPI.ts
 | 
			
		||||
    participant Config as configApi
 | 
			
		||||
    participant Preprocessor as preprocessDiagram
 | 
			
		||||
    participant DiagramAPI as diagram-api
 | 
			
		||||
    participant Diagram as Diagram.fromText
 | 
			
		||||
    participant Renderer as diagram.renderer
 | 
			
		||||
    participant Styles as Styling System
 | 
			
		||||
    participant DOM as DOM/SVG
 | 
			
		||||
 | 
			
		||||
    Note over User, DOM: Mermaid Complete API Flow
 | 
			
		||||
 | 
			
		||||
    %% Initialization Phase
 | 
			
		||||
    User->>+Mermaid: mermaid.initialize(config)
 | 
			
		||||
    Mermaid->>+API: mermaidAPI.initialize(config)
 | 
			
		||||
    
 | 
			
		||||
    API->>API: assignWithDepth({}, userOptions)
 | 
			
		||||
    API->>API: handle legacy fontFamily config
 | 
			
		||||
    API->>Config: saveConfigFromInitialize(options)
 | 
			
		||||
    
 | 
			
		||||
    alt Theme Configuration Available
 | 
			
		||||
        API->>API: check if theme in theme object
 | 
			
		||||
        API->>API: set themeVariables from theme
 | 
			
		||||
    else Default Theme
 | 
			
		||||
        API->>API: use default theme variables
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    API->>Config: setSiteConfig(options) or getSiteConfig()
 | 
			
		||||
    API->>API: setLogLevel(config.logLevel)
 | 
			
		||||
    API->>DiagramAPI: addDiagrams()
 | 
			
		||||
    
 | 
			
		||||
    API-->>-Mermaid: initialization complete
 | 
			
		||||
    Mermaid-->>-User: ready to render
 | 
			
		||||
 | 
			
		||||
    %% Content Loaded Event
 | 
			
		||||
    User->>DOM: document.load event
 | 
			
		||||
    DOM->>+Mermaid: contentLoaded()
 | 
			
		||||
    
 | 
			
		||||
    opt startOnLoad is true
 | 
			
		||||
        Mermaid->>Config: getConfig()
 | 
			
		||||
        Config-->>Mermaid: { startOnLoad: true }
 | 
			
		||||
        Mermaid->>Mermaid: run()
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    Mermaid-->>-DOM: event handling complete
 | 
			
		||||
 | 
			
		||||
    %% Main Run Function
 | 
			
		||||
    User->>+Mermaid: mermaid.run(options)
 | 
			
		||||
    
 | 
			
		||||
    Mermaid->>Mermaid: runThrowsErrors(options)
 | 
			
		||||
    Mermaid->>Config: getConfig()
 | 
			
		||||
    Config-->>Mermaid: configuration object
 | 
			
		||||
    
 | 
			
		||||
    alt nodes provided
 | 
			
		||||
        Mermaid->>Mermaid: use provided nodes
 | 
			
		||||
    else querySelector provided
 | 
			
		||||
        Mermaid->>DOM: document.querySelectorAll(querySelector)
 | 
			
		||||
        DOM-->>Mermaid: nodesToProcess
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    Mermaid->>Mermaid: new InitIDGenerator(deterministicIds, seed)
 | 
			
		||||
    
 | 
			
		||||
    loop For each diagram element
 | 
			
		||||
        Mermaid->>DOM: check element.getAttribute('data-processed')
 | 
			
		||||
        
 | 
			
		||||
        opt not processed
 | 
			
		||||
            Mermaid->>DOM: element.setAttribute('data-processed', 'true')
 | 
			
		||||
            Mermaid->>Mermaid: generate unique id
 | 
			
		||||
            Mermaid->>DOM: get element.innerHTML
 | 
			
		||||
            Mermaid->>Mermaid: entityDecode and clean text
 | 
			
		||||
            Mermaid->>Mermaid: detectInit(txt)
 | 
			
		||||
            
 | 
			
		||||
            Mermaid->>Queue: render(id, txt, element)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    Mermaid-->>-User: processing initiated
 | 
			
		||||
 | 
			
		||||
    %% Render Function (Queued)
 | 
			
		||||
    activate Queue
 | 
			
		||||
    Queue->>+API: mermaidAPI.render(id, text, container)
 | 
			
		||||
    
 | 
			
		||||
    API->>DiagramAPI: addDiagrams()
 | 
			
		||||
    API->>+Preprocessor: processAndSetConfigs(text)
 | 
			
		||||
    
 | 
			
		||||
    Preprocessor->>Preprocessor: preprocessDiagram(text)
 | 
			
		||||
    Preprocessor->>Config: reset()
 | 
			
		||||
    Preprocessor->>Config: addDirective(processed.config)
 | 
			
		||||
    Preprocessor-->>-API: { code, config }
 | 
			
		||||
    
 | 
			
		||||
    API->>Config: getConfig()
 | 
			
		||||
    Config-->>API: current configuration
 | 
			
		||||
    
 | 
			
		||||
    opt text length > maxTextSize
 | 
			
		||||
        API->>API: text = MAX_TEXTLENGTH_EXCEEDED_MSG
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    API->>API: setup id selectors and element IDs
 | 
			
		||||
    API->>API: determine security level (sandbox/loose)
 | 
			
		||||
 | 
			
		||||
    %% DOM Setup
 | 
			
		||||
    alt svgContainingElement provided
 | 
			
		||||
        alt isSandboxed
 | 
			
		||||
            API->>DOM: sandboxedIframe(select(svgContainingElement), iFrameID)
 | 
			
		||||
            API->>DOM: select iframe contentDocument body
 | 
			
		||||
        else
 | 
			
		||||
            API->>DOM: select(svgContainingElement)
 | 
			
		||||
        end
 | 
			
		||||
    else no container
 | 
			
		||||
        API->>API: removeExistingElements(document, id, divId, iFrameId)
 | 
			
		||||
        alt isSandboxed
 | 
			
		||||
            API->>DOM: sandboxedIframe(select('body'), iFrameID)
 | 
			
		||||
        else
 | 
			
		||||
            API->>DOM: select('body')
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    API->>DOM: appendDivSvgG(root, id, enclosingDivID, fontFamily, XMLNS_XLINK_STD)
 | 
			
		||||
 | 
			
		||||
    %% Diagram Creation
 | 
			
		||||
    API->>+Diagram: Diagram.fromText(text, { title: processed.title })
 | 
			
		||||
    
 | 
			
		||||
    Diagram->>DiagramAPI: detect diagram type
 | 
			
		||||
    Diagram->>DiagramAPI: load appropriate diagram
 | 
			
		||||
    Diagram-->>-API: diagram instance
 | 
			
		||||
    
 | 
			
		||||
    opt parsing error occurred
 | 
			
		||||
        API->>+Diagram: Diagram.fromText('error')
 | 
			
		||||
        Diagram-->>-API: error diagram
 | 
			
		||||
        API->>API: store parseEncounteredException
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    %% Style Generation
 | 
			
		||||
    API->>DOM: get svg element and firstChild
 | 
			
		||||
    API->>Renderer: diag.renderer.getClasses(text, diag)
 | 
			
		||||
    Renderer-->>API: diagramClassDefs
 | 
			
		||||
    
 | 
			
		||||
    API->>+Styles: createUserStyles(config, diagramType, diagramClassDefs, idSelector)
 | 
			
		||||
    
 | 
			
		||||
    Styles->>Styles: createCssStyles(config, classDefs)
 | 
			
		||||
    
 | 
			
		||||
    opt config.themeCSS defined
 | 
			
		||||
        Styles->>Styles: append themeCSS
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    opt fontFamily configured
 | 
			
		||||
        Styles->>Styles: add CSS variables for fonts
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    opt classDefs exist
 | 
			
		||||
        loop For each styleClassDef
 | 
			
		||||
            opt has styles
 | 
			
		||||
                Styles->>Styles: cssImportantStyles for each CSS element
 | 
			
		||||
            end
 | 
			
		||||
            opt has textStyles
 | 
			
		||||
                Styles->>Styles: cssImportantStyles for tspan elements
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    Styles->>Styles: getStyles(graphType, userCSSstyles, themeVariables)
 | 
			
		||||
    Styles->>Styles: serialize(compile(svgId{allStyles}), stringify)
 | 
			
		||||
    Styles-->>-API: compiled CSS rules
 | 
			
		||||
    
 | 
			
		||||
    API->>DOM: create style element
 | 
			
		||||
    API->>DOM: style.innerHTML = rules
 | 
			
		||||
    API->>DOM: svg.insertBefore(style, firstChild)
 | 
			
		||||
 | 
			
		||||
    %% Diagram Rendering
 | 
			
		||||
    API->>+Renderer: diag.renderer.draw(text, id, version, diag)
 | 
			
		||||
    
 | 
			
		||||
    Renderer->>Renderer: diagram-specific rendering logic
 | 
			
		||||
    Renderer->>DOM: create SVG elements
 | 
			
		||||
    Renderer->>DOM: apply positioning and styling
 | 
			
		||||
    Renderer-->>-API: rendered diagram
 | 
			
		||||
    
 | 
			
		||||
    opt rendering error
 | 
			
		||||
        alt suppressErrorRendering
 | 
			
		||||
            API->>API: removeTempElements()
 | 
			
		||||
            API->>Mermaid: throw error
 | 
			
		||||
        else
 | 
			
		||||
            API->>Renderer: errorRenderer.draw(text, id, version)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    %% Accessibility and Cleanup
 | 
			
		||||
    API->>DOM: select svg element
 | 
			
		||||
    API->>Diagram: diag.db.getAccTitle()
 | 
			
		||||
    API->>Diagram: diag.db.getAccDescription()
 | 
			
		||||
    API->>API: addA11yInfo(diagramType, svgNode, a11yTitle, a11yDescr)
 | 
			
		||||
    
 | 
			
		||||
    API->>DOM: set xmlns for foreignobject elements
 | 
			
		||||
    API->>DOM: get innerHTML from enclosing div
 | 
			
		||||
    
 | 
			
		||||
    API->>+API: cleanUpSvgCode(svgCode, isSandboxed, arrowMarkerAbsolute)
 | 
			
		||||
    
 | 
			
		||||
    opt not useArrowMarkerUrls and not sandboxed
 | 
			
		||||
        API->>API: replace marker-end URLs with anchors
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    API->>API: decodeEntities(svgCode)
 | 
			
		||||
    API->>API: replace <br> with <br/>
 | 
			
		||||
    API-->>-API: cleaned SVG code
 | 
			
		||||
    
 | 
			
		||||
    alt isSandboxed
 | 
			
		||||
        API->>+API: putIntoIFrame(svgCode, svgEl)
 | 
			
		||||
        API->>API: calculate iframe height
 | 
			
		||||
        API->>API: toBase64 encode SVG content
 | 
			
		||||
        API->>API: create iframe with sandbox attributes
 | 
			
		||||
        API-->>-API: iframe HTML
 | 
			
		||||
    else not loose security
 | 
			
		||||
        API->>API: DOMPurify.sanitize(svgCode, options)
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    API->>API: attachFunctions()
 | 
			
		||||
    API->>API: removeTempElements()
 | 
			
		||||
    
 | 
			
		||||
    opt parseEncounteredException
 | 
			
		||||
        API->>Mermaid: throw parseEncounteredException
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    API-->>-Queue: { diagramType, svg: svgCode, bindFunctions }
 | 
			
		||||
 | 
			
		||||
    %% Return to Web Integration
 | 
			
		||||
    activate Mermaid
 | 
			
		||||
    Queue-->>Mermaid: render result
 | 
			
		||||
    Mermaid->>DOM: element.innerHTML = svg
 | 
			
		||||
    
 | 
			
		||||
    opt postRenderCallback
 | 
			
		||||
        Mermaid->>User: postRenderCallback(id)
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    opt bindFunctions exist
 | 
			
		||||
        Mermaid->>DOM: bindFunctions(element)
 | 
			
		||||
    end
 | 
			
		||||
    deactivate Mermaid
 | 
			
		||||
 | 
			
		||||
    %% Parse Function Flow
 | 
			
		||||
    User->>+Mermaid: mermaid.parse(text, parseOptions)
 | 
			
		||||
    activate Queue
 | 
			
		||||
    
 | 
			
		||||
    Queue->>+API: mermaidAPI.parse(text, parseOptions)
 | 
			
		||||
    
 | 
			
		||||
    API->>DiagramAPI: addDiagrams()
 | 
			
		||||
    API->>Preprocessor: processAndSetConfigs(text)
 | 
			
		||||
    Preprocessor-->>API: { code, config }
 | 
			
		||||
    API->>Diagram: getDiagramFromText(code)
 | 
			
		||||
    Diagram-->>API: diagram instance
 | 
			
		||||
    API-->>-Queue: { diagramType: diagram.type, config }
 | 
			
		||||
    
 | 
			
		||||
    Queue-->>-Mermaid: parse result
 | 
			
		||||
    Mermaid-->>-User: ParseResult or false
 | 
			
		||||
 | 
			
		||||
    %% External Diagram Registration
 | 
			
		||||
    User->>+Mermaid: registerExternalDiagrams(diagrams, options)
 | 
			
		||||
    
 | 
			
		||||
    Mermaid->>DiagramAPI: addDiagrams()
 | 
			
		||||
    Mermaid->>DiagramAPI: registerLazyLoadedDiagrams(...diagrams)
 | 
			
		||||
    
 | 
			
		||||
    opt lazyLoad is false
 | 
			
		||||
        Mermaid->>DiagramAPI: loadRegisteredDiagrams()
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    Mermaid-->>-User: registration complete
 | 
			
		||||
 | 
			
		||||
    %% Error Handling
 | 
			
		||||
    Note over Mermaid, API: Error Handling Throughout
 | 
			
		||||
    alt Error occurs
 | 
			
		||||
        API->>Mermaid: throw error
 | 
			
		||||
        Mermaid->>+Mermaid: handleError(error, errors, parseError)
 | 
			
		||||
        
 | 
			
		||||
        Mermaid->>Mermaid: log.warn(error)
 | 
			
		||||
        
 | 
			
		||||
        alt isDetailedError
 | 
			
		||||
            Mermaid->>User: parseError(error.str, error.hash)
 | 
			
		||||
        else
 | 
			
		||||
            Mermaid->>User: parseError(error)
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
        opt not suppressErrors
 | 
			
		||||
            Mermaid->>User: throw error
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
        Mermaid-->>-User: error handled
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    %% Configuration Details
 | 
			
		||||
    Note over Config: Configuration Functions
 | 
			
		||||
    Note right of Config: Functions:<br/>- reset()<br/>- getConfig()<br/>- setConfig()<br/>- getSiteConfig()<br/>- updateSiteConfig()<br/>- saveConfigFromInitialize()
 | 
			
		||||
    
 | 
			
		||||
    Note over Styles: CSS Generation
 | 
			
		||||
    Note right of Styles: Features:<br/>- createCssStyles()<br/>- createUserStyles()<br/>- cssImportantStyles()<br/>- Theme integration<br/>- Class definitions
 | 
			
		||||
    
 | 
			
		||||
    Note over API: Security Levels
 | 
			
		||||
    Note right of API: Modes:<br/>- sandbox: iframe isolation<br/>- loose: minimal sanitization<br/>- default: DOMPurify sanitization
 | 
			
		||||
    
 | 
			
		||||
    Note over API: Helper Functions
 | 
			
		||||
    Note right of API: Utilities:<br/>- cleanUpSvgCode()<br/>- putIntoIFrame()<br/>- appendDivSvgG()<br/>- removeExistingElements() 
 | 
			
		||||
							
								
								
									
										180
									
								
								docs/diagrams/mindmap-implementation-sequence.mmd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								docs/diagrams/mindmap-implementation-sequence.mmd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,180 @@
 | 
			
		||||
---
 | 
			
		||||
references:
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/mindmap/mindmap-definition.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/mindmap/mindmapDb.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/mindmap/detector.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/mindmap/mindmapTypes.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/mindmap/mindmapRenderer.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/mindmap/styles.ts"
 | 
			
		||||
  - "File: /packages/mermaid/src/diagrams/mindmap/svgDraw.ts"
 | 
			
		||||
generationTime: 2025-01-28T16:00:00.000Z
 | 
			
		||||
---
 | 
			
		||||
sequenceDiagram
 | 
			
		||||
    participant User as User Input Text
 | 
			
		||||
    participant Detector as detector.ts
 | 
			
		||||
    participant Loader as DiagramLoader
 | 
			
		||||
    participant Definition as mindmap-definition.ts
 | 
			
		||||
    participant Parser as parser/mindmap.jison
 | 
			
		||||
    participant DB as MindmapDB
 | 
			
		||||
    participant Renderer as mindmapRenderer.ts
 | 
			
		||||
    participant Cytoscape as cytoscape.js
 | 
			
		||||
    participant SVGDraw as svgDraw.ts
 | 
			
		||||
    participant Styles as styles.ts
 | 
			
		||||
    participant Output as Final SVG
 | 
			
		||||
 | 
			
		||||
    Note over User, Output: Mindmap Implementation Flow
 | 
			
		||||
 | 
			
		||||
    %% Detection Phase
 | 
			
		||||
    User->>Detector: /^\s*mindmap/ text input
 | 
			
		||||
    activate Detector
 | 
			
		||||
    Detector->>Detector: detector(txt) validates pattern
 | 
			
		||||
    Detector->>Loader: loader() function called
 | 
			
		||||
    deactivate Detector
 | 
			
		||||
    
 | 
			
		||||
    activate Loader
 | 
			
		||||
    Loader->>Definition: import mindmap-definition.js
 | 
			
		||||
    deactivate Loader
 | 
			
		||||
 | 
			
		||||
    %% Core Structure Setup
 | 
			
		||||
    activate Definition
 | 
			
		||||
    Definition->>DB: get db() → new MindmapDB()
 | 
			
		||||
    Definition->>Renderer: setup renderer
 | 
			
		||||
    Definition->>Parser: setup parser
 | 
			
		||||
    Definition->>Styles: setup styles
 | 
			
		||||
    deactivate Definition
 | 
			
		||||
 | 
			
		||||
    %% Database Initialization
 | 
			
		||||
    activate DB
 | 
			
		||||
    Note over DB: MindmapDB Constructor
 | 
			
		||||
    DB->>DB: initialize nodes array
 | 
			
		||||
    DB->>DB: setup nodeType constants
 | 
			
		||||
    DB->>DB: bind methods
 | 
			
		||||
    DB->>DB: clear() state
 | 
			
		||||
    
 | 
			
		||||
    %% Parsing Phase
 | 
			
		||||
    activate Parser
 | 
			
		||||
    User->>Parser: mindmap syntax text
 | 
			
		||||
    
 | 
			
		||||
    loop For each node in hierarchy
 | 
			
		||||
        Parser->>DB: addNode(level, id, descr, type)
 | 
			
		||||
        activate DB
 | 
			
		||||
        DB->>DB: sanitizeText(id, descr)
 | 
			
		||||
        DB->>DB: getType(startStr, endStr)
 | 
			
		||||
        Note right of DB: Shape Detection:<br/>[ → RECT<br/>( → ROUNDED_RECT<br/>(( → CIRCLE<br/>)) → BANG<br/>{{ → HEXAGON
 | 
			
		||||
        DB->>DB: getParent(level)
 | 
			
		||||
        DB->>DB: create MindmapNode
 | 
			
		||||
        DB->>DB: add to hierarchy
 | 
			
		||||
        deactivate DB
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    opt Icon/Class Decoration
 | 
			
		||||
        Parser->>DB: decorateNode(decoration)
 | 
			
		||||
        DB->>DB: set icon/class properties
 | 
			
		||||
    end
 | 
			
		||||
    deactivate Parser
 | 
			
		||||
 | 
			
		||||
    %% Data Preparation
 | 
			
		||||
    Renderer->>DB: getData() for layout
 | 
			
		||||
    activate DB
 | 
			
		||||
    DB->>DB: collect all nodes
 | 
			
		||||
    DB->>DB: build parent-child relationships
 | 
			
		||||
    DB-->>Renderer: return node hierarchy
 | 
			
		||||
    deactivate DB
 | 
			
		||||
 | 
			
		||||
    %% Rendering Pipeline
 | 
			
		||||
    activate Renderer
 | 
			
		||||
    Note over Renderer: Rendering Phase
 | 
			
		||||
    
 | 
			
		||||
    Renderer->>Cytoscape: initialize cytoscape
 | 
			
		||||
    activate Cytoscape
 | 
			
		||||
    
 | 
			
		||||
    loop For each node in mindmap
 | 
			
		||||
        Renderer->>Cytoscape: addNodes(mindmap, cy, conf, level)
 | 
			
		||||
        Cytoscape->>Cytoscape: create node data
 | 
			
		||||
        Cytoscape->>Cytoscape: set position (x, y)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    loop For parent-child relationships
 | 
			
		||||
        Renderer->>Cytoscape: add edges
 | 
			
		||||
        Cytoscape->>Cytoscape: create edge data
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    Renderer->>Cytoscape: configure cose-bilkent layout
 | 
			
		||||
    Cytoscape->>Cytoscape: calculate optimal positions
 | 
			
		||||
    Cytoscape-->>Renderer: return positioned graph
 | 
			
		||||
    deactivate Cytoscape
 | 
			
		||||
 | 
			
		||||
    %% SVG Generation
 | 
			
		||||
    Renderer->>SVGDraw: drawNodes(db, svg, mindmap, section, conf)
 | 
			
		||||
    activate SVGDraw
 | 
			
		||||
    
 | 
			
		||||
    loop For each node recursively
 | 
			
		||||
        SVGDraw->>SVGDraw: select shape function
 | 
			
		||||
        
 | 
			
		||||
        alt Default Shape
 | 
			
		||||
            SVGDraw->>SVGDraw: defaultBkg() - rounded rectangle
 | 
			
		||||
        else Rectangle Shape
 | 
			
		||||
            SVGDraw->>SVGDraw: rectBkg() - sharp corners
 | 
			
		||||
        else Circle Shape
 | 
			
		||||
            SVGDraw->>SVGDraw: circleBkg() - perfect circle
 | 
			
		||||
        else Cloud Shape
 | 
			
		||||
            SVGDraw->>SVGDraw: cloudBkg() - organic curves
 | 
			
		||||
        else Bang Shape
 | 
			
		||||
            SVGDraw->>SVGDraw: bangBkg() - explosion style
 | 
			
		||||
        else Hexagon Shape
 | 
			
		||||
            SVGDraw->>SVGDraw: hexagonBkg() - six sides
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
        SVGDraw->>SVGDraw: create SVG elements
 | 
			
		||||
        SVGDraw->>SVGDraw: add text labels
 | 
			
		||||
        SVGDraw->>SVGDraw: position node
 | 
			
		||||
        
 | 
			
		||||
        opt Node has children
 | 
			
		||||
            SVGDraw->>SVGDraw: drawNodes() recursive call
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    deactivate SVGDraw
 | 
			
		||||
 | 
			
		||||
    %% Edge Rendering
 | 
			
		||||
    Renderer->>Renderer: drawEdges(edgesEl, cy)
 | 
			
		||||
    loop For each edge
 | 
			
		||||
        Renderer->>Renderer: extract edge bounds
 | 
			
		||||
        Renderer->>Renderer: draw SVG path
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    %% Styling Application
 | 
			
		||||
    Renderer->>Styles: getStyles(options)
 | 
			
		||||
    activate Styles
 | 
			
		||||
    
 | 
			
		||||
    Styles->>Styles: genSections(options)
 | 
			
		||||
    loop For THEME_COLOR_LIMIT sections
 | 
			
		||||
        Styles->>Styles: generate color scale
 | 
			
		||||
        Styles->>Styles: create CSS rules
 | 
			
		||||
        Note right of Styles: .section-X fills<br/>.edge-depth-X widths<br/>.node-icon-X colors
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    Styles->>Styles: apply theme integration
 | 
			
		||||
    Styles-->>Renderer: return compiled CSS
 | 
			
		||||
    deactivate Styles
 | 
			
		||||
 | 
			
		||||
    %% Final Assembly
 | 
			
		||||
    Renderer->>Output: selectSvgElement()
 | 
			
		||||
    Renderer->>Output: setupGraphViewbox()
 | 
			
		||||
    Renderer->>Output: apply styles
 | 
			
		||||
    Renderer->>Output: add interactive elements
 | 
			
		||||
    deactivate Renderer
 | 
			
		||||
 | 
			
		||||
    activate Output
 | 
			
		||||
    Note over Output: Final Mindmap Features
 | 
			
		||||
    Output->>Output: responsive layout
 | 
			
		||||
    Output->>Output: accessibility attributes
 | 
			
		||||
    Output->>Output: hover effects
 | 
			
		||||
    Output->>Output: click handling
 | 
			
		||||
    Output-->>User: rendered mindmap
 | 
			
		||||
    deactivate Output
 | 
			
		||||
 | 
			
		||||
    %% Configuration Details
 | 
			
		||||
    Note over DB, Styles: Configuration Options
 | 
			
		||||
    Note right of DB: Padding Calculations:<br/>Base padding from config<br/>RECT: ×2 padding<br/>ROUNDED_RECT: ×2 padding<br/>HEXAGON: ×2 padding
 | 
			
		||||
    Note right of Styles: Section Management:<br/>MAX_SECTIONS = 12<br/>Dynamic color generation<br/>Git theme integration
 | 
			
		||||
    Note right of Renderer: Layout Parameters:<br/>Cytoscape configuration<br/>coseBilkent settings<br/>Node spacing rules 
 | 
			
		||||
@@ -84,6 +84,7 @@ To add an integration to this list, see the [Integrations - create page](./integ
 | 
			
		||||
LLM integrations to create mermaid diagrams using AI from text descriptions.
 | 
			
		||||
 | 
			
		||||
- [HueHive - Create mermaid diagrams with text](https://huehive.co/tools/diagrams)
 | 
			
		||||
- [MCP Server Mermaid](https://github.com/hustcc/mcp-mermaid) - Generate mermaid diagram and chart with AI MCP dynamically.
 | 
			
		||||
 | 
			
		||||
### CRM/ERP
 | 
			
		||||
 | 
			
		||||
@@ -103,6 +104,7 @@ Blogging frameworks and platforms
 | 
			
		||||
  - [Mermaid](https://nextra.site/docs/guide/mermaid)
 | 
			
		||||
- [WordPress](https://wordpress.org)
 | 
			
		||||
  - [MerPRess](https://wordpress.org/plugins/merpress/)
 | 
			
		||||
  - [WP Documentation](https://wordpress.org/themes/wp-documentation/)
 | 
			
		||||
 | 
			
		||||
### CMS/ECM
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ Applications that support Mermaid files [SHOULD](https://datatracker.ietf.org/do
 | 
			
		||||
 | 
			
		||||
### MIME Type
 | 
			
		||||
 | 
			
		||||
The recommended [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml) for Mermaid media is `text/vnd.mermaid`.
 | 
			
		||||
 | 
			
		||||
Currently pending [IANA](https://www.iana.org/) recognition.
 | 
			
		||||
The recommended [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml) for Mermaid media is [`text/vnd.mermaid`](https://www.iana.org/assignments/media-types/application/vnd.mermaid).
 | 
			
		||||
 | 
			
		||||
## Showcase
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1795,15 +1795,54 @@ It is possible to style the type of curve used for lines between items, if the d
 | 
			
		||||
Available curve styles include `basis`, `bumpX`, `bumpY`, `cardinal`, `catmullRom`, `linear`, `monotoneX`, `monotoneY`,
 | 
			
		||||
`natural`, `step`, `stepAfter`, and `stepBefore`.
 | 
			
		||||
 | 
			
		||||
For a full list of available curves, including an explanation of custom curves, refer to
 | 
			
		||||
the [Shapes](https://d3js.org/d3-shape/curve) documentation in the [d3-shape](https://github.com/d3/d3-shape/) project.
 | 
			
		||||
 | 
			
		||||
Line styling can be achieved in two ways:
 | 
			
		||||
 | 
			
		||||
1. Change the curve style of all the lines
 | 
			
		||||
2. Change the curve style of a particular line
 | 
			
		||||
 | 
			
		||||
#### Diagram level curve style
 | 
			
		||||
 | 
			
		||||
In this example, a left-to-right graph uses the `stepBefore` curve style:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
%%{ init: { 'flowchart': { 'curve': 'stepBefore' } } }%%
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  flowchart:
 | 
			
		||||
    curve: stepBefore
 | 
			
		||||
---
 | 
			
		||||
graph LR
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For a full list of available curves, including an explanation of custom curves, refer to
 | 
			
		||||
the [Shapes](https://d3js.org/d3-shape/curve) documentation in the [d3-shape](https://github.com/d3/d3-shape/) project.
 | 
			
		||||
#### Edge level curve style using Edge IDs (v\<MERMAID_RELEASE_VERSION>+)
 | 
			
		||||
 | 
			
		||||
You can assign IDs to [edges](#attaching-an-id-to-edges). After assigning an ID you can modify the line style by modifying the edge's `curve` property using the following syntax:
 | 
			
		||||
 | 
			
		||||
```mermaid-example
 | 
			
		||||
flowchart LR
 | 
			
		||||
    A e1@==> B
 | 
			
		||||
    A e2@--> C
 | 
			
		||||
    e1@{ curve: linear }
 | 
			
		||||
    e2@{ curve: natural }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
flowchart LR
 | 
			
		||||
    A e1@==> B
 | 
			
		||||
    A e2@--> C
 | 
			
		||||
    e1@{ curve: linear }
 | 
			
		||||
    e2@{ curve: natural }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```info
 | 
			
		||||
Any edge curve style modified at the edge level overrides the diagram level style.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```info
 | 
			
		||||
If the same edge is modified multiple times the last modification will be rendered.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Styling a node
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ This diagram type is particularly useful for developers, network engineers, educ
 | 
			
		||||
## Syntax
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
packet-beta
 | 
			
		||||
packet
 | 
			
		||||
start: "Block name" %% Single-bit block
 | 
			
		||||
start-end: "Block name" %% Multi-bit blocks
 | 
			
		||||
... More Fields ...
 | 
			
		||||
@@ -28,7 +28,7 @@ start-end: "Block name" %% Multi-bit blocks
 | 
			
		||||
Using start and end bit counts can be difficult, especially when modifying a design. For this we add a bit count field, which starts from the end of the previous field automagically. Use `+<count>` to set the number of bits, thus:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
packet-beta
 | 
			
		||||
packet
 | 
			
		||||
+1: "Block name" %% Single-bit block
 | 
			
		||||
+8: "Block name" %% 8-bit block
 | 
			
		||||
9-15: "Manually set start and end, it's fine to mix and match"
 | 
			
		||||
@@ -41,7 +41,7 @@ packet-beta
 | 
			
		||||
---
 | 
			
		||||
title: "TCP Packet"
 | 
			
		||||
---
 | 
			
		||||
packet-beta
 | 
			
		||||
packet
 | 
			
		||||
0-15: "Source Port"
 | 
			
		||||
16-31: "Destination Port"
 | 
			
		||||
32-63: "Sequence Number"
 | 
			
		||||
@@ -65,7 +65,7 @@ packet-beta
 | 
			
		||||
---
 | 
			
		||||
title: "TCP Packet"
 | 
			
		||||
---
 | 
			
		||||
packet-beta
 | 
			
		||||
packet
 | 
			
		||||
0-15: "Source Port"
 | 
			
		||||
16-31: "Destination Port"
 | 
			
		||||
32-63: "Sequence Number"
 | 
			
		||||
@@ -86,7 +86,7 @@ packet-beta
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```mermaid-example
 | 
			
		||||
packet-beta
 | 
			
		||||
packet
 | 
			
		||||
title UDP Packet
 | 
			
		||||
+16: "Source Port"
 | 
			
		||||
+16: "Destination Port"
 | 
			
		||||
@@ -96,7 +96,7 @@ title UDP Packet
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
packet-beta
 | 
			
		||||
packet
 | 
			
		||||
title UDP Packet
 | 
			
		||||
+16: "Source Port"
 | 
			
		||||
+16: "Destination Port"
 | 
			
		||||
@@ -144,7 +144,7 @@ config:
 | 
			
		||||
    packet:
 | 
			
		||||
      startByteColor: red
 | 
			
		||||
---
 | 
			
		||||
packet-beta
 | 
			
		||||
packet
 | 
			
		||||
0-15: "Source Port"
 | 
			
		||||
16-31: "Destination Port"
 | 
			
		||||
32-63: "Sequence Number"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										35
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								package.json
									
									
									
									
									
								
							@@ -64,10 +64,10 @@
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@applitools/eyes-cypress": "^3.44.9",
 | 
			
		||||
    "@argos-ci/cypress": "^4.0.3",
 | 
			
		||||
    "@argos-ci/cypress": "^5.0.2",
 | 
			
		||||
    "@changesets/changelog-github": "^0.5.1",
 | 
			
		||||
    "@changesets/cli": "^2.27.12",
 | 
			
		||||
    "@cspell/eslint-plugin": "^8.19.3",
 | 
			
		||||
    "@cspell/eslint-plugin": "^8.19.4",
 | 
			
		||||
    "@cypress/code-coverage": "^3.12.49",
 | 
			
		||||
    "@eslint/js": "^9.26.0",
 | 
			
		||||
    "@rollup/plugin-typescript": "^12.1.2",
 | 
			
		||||
@@ -88,46 +88,46 @@
 | 
			
		||||
    "cors": "^2.8.5",
 | 
			
		||||
    "cpy-cli": "^5.0.0",
 | 
			
		||||
    "cross-env": "^7.0.3",
 | 
			
		||||
    "cspell": "^8.6.1",
 | 
			
		||||
    "cypress": "^14.0.3",
 | 
			
		||||
    "cspell": "^9.1.3",
 | 
			
		||||
    "cypress": "^14.5.1",
 | 
			
		||||
    "cypress-image-snapshot": "^4.0.1",
 | 
			
		||||
    "cypress-split": "^1.24.14",
 | 
			
		||||
    "esbuild": "^0.25.0",
 | 
			
		||||
    "eslint": "^9.26.0",
 | 
			
		||||
    "eslint-config-prettier": "^10.1.1",
 | 
			
		||||
    "eslint-config-prettier": "^10.1.8",
 | 
			
		||||
    "eslint-plugin-cypress": "^4.3.0",
 | 
			
		||||
    "eslint-plugin-html": "^8.1.2",
 | 
			
		||||
    "eslint-plugin-jest": "^28.11.0",
 | 
			
		||||
    "eslint-plugin-jsdoc": "^50.6.9",
 | 
			
		||||
    "eslint-plugin-html": "^8.1.3",
 | 
			
		||||
    "eslint-plugin-jest": "^28.14.0",
 | 
			
		||||
    "eslint-plugin-jsdoc": "^50.8.0",
 | 
			
		||||
    "eslint-plugin-json": "^4.0.1",
 | 
			
		||||
    "eslint-plugin-lodash": "^8.0.0",
 | 
			
		||||
    "eslint-plugin-markdown": "^5.1.0",
 | 
			
		||||
    "eslint-plugin-no-only-tests": "^3.3.0",
 | 
			
		||||
    "eslint-plugin-tsdoc": "^0.4.0",
 | 
			
		||||
    "eslint-plugin-unicorn": "^59.0.0",
 | 
			
		||||
    "eslint-plugin-unicorn": "^59.0.1",
 | 
			
		||||
    "express": "^5.1.0",
 | 
			
		||||
    "globals": "^16.0.0",
 | 
			
		||||
    "globby": "^14.0.2",
 | 
			
		||||
    "husky": "^9.1.7",
 | 
			
		||||
    "jest": "^29.7.0",
 | 
			
		||||
    "jest": "^30.0.4",
 | 
			
		||||
    "jison": "^0.4.18",
 | 
			
		||||
    "js-yaml": "^4.1.0",
 | 
			
		||||
    "jsdom": "^26.0.0",
 | 
			
		||||
    "jsdom": "^26.1.0",
 | 
			
		||||
    "langium-cli": "3.3.0",
 | 
			
		||||
    "lint-staged": "^15.2.11",
 | 
			
		||||
    "lint-staged": "^16.1.2",
 | 
			
		||||
    "markdown-table": "^3.0.4",
 | 
			
		||||
    "nyc": "^17.1.0",
 | 
			
		||||
    "path-browserify": "^1.0.1",
 | 
			
		||||
    "prettier": "^3.5.2",
 | 
			
		||||
    "prettier-plugin-jsdoc": "^1.3.2",
 | 
			
		||||
    "rimraf": "^6.0.1",
 | 
			
		||||
    "rollup-plugin-visualizer": "^5.14.0",
 | 
			
		||||
    "rollup-plugin-visualizer": "^6.0.3",
 | 
			
		||||
    "start-server-and-test": "^2.0.10",
 | 
			
		||||
    "tslib": "^2.8.1",
 | 
			
		||||
    "tsx": "^4.7.3",
 | 
			
		||||
    "typescript": "~5.7.3",
 | 
			
		||||
    "typescript-eslint": "^8.32.0",
 | 
			
		||||
    "vite": "^6.1.1",
 | 
			
		||||
    "typescript-eslint": "^8.38.0",
 | 
			
		||||
    "vite": "^7.0.3",
 | 
			
		||||
    "vite-plugin-istanbul": "^7.0.0",
 | 
			
		||||
    "vitest": "^3.0.6"
 | 
			
		||||
  },
 | 
			
		||||
@@ -139,8 +139,13 @@
 | 
			
		||||
      "roughjs": "patches/roughjs.patch"
 | 
			
		||||
    },
 | 
			
		||||
    "onlyBuiltDependencies": [
 | 
			
		||||
      "canvas",
 | 
			
		||||
      "cypress",
 | 
			
		||||
      "esbuild"
 | 
			
		||||
    ],
 | 
			
		||||
    "ignoredBuiltDependencies": [
 | 
			
		||||
      "sharp",
 | 
			
		||||
      "vue-demi"
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								packages/examples/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								packages/examples/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
# @mermaid-js/examples
 | 
			
		||||
 | 
			
		||||
## 1.0.0
 | 
			
		||||
 | 
			
		||||
### Minor Changes
 | 
			
		||||
 | 
			
		||||
- [#6453](https://github.com/mermaid-js/mermaid/pull/6453) [`4936ef5`](https://github.com/mermaid-js/mermaid/commit/4936ef5c306d2f892cca9a95a5deac4af6d4882b) Thanks [@sidharthv96](https://github.com/sidharthv96)! - feat: Add examples for diagrams in the `@mermaid-js/examples` package
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- [#6510](https://github.com/mermaid-js/mermaid/pull/6510) [`7a38eb7`](https://github.com/mermaid-js/mermaid/commit/7a38eb715d795cd5c66cb59357d64ec197b432e6) Thanks [@sidharthv96](https://github.com/sidharthv96)! - chore: Move packet diagram out of beta
 | 
			
		||||
 | 
			
		||||
- Updated dependencies [[`5acbd7e`](https://github.com/mermaid-js/mermaid/commit/5acbd7e762469d9d89a9c77faf6617ee13367f3a), [`d90634b`](https://github.com/mermaid-js/mermaid/commit/d90634bf2b09e586b055729e07e9a1a31b21827c), [`7a38eb7`](https://github.com/mermaid-js/mermaid/commit/7a38eb715d795cd5c66cb59357d64ec197b432e6), [`3e3ae08`](https://github.com/mermaid-js/mermaid/commit/3e3ae089305e1c7b9948b9e149eba6854fe7f2d6), [`d3e2be3`](https://github.com/mermaid-js/mermaid/commit/d3e2be35be066adeb7fd502b4a24c223c3b53947), [`637680d`](https://github.com/mermaid-js/mermaid/commit/637680d4d9e39b4f8cb6f05b4cb261e8f5693ac3)]:
 | 
			
		||||
  - mermaid@11.9.0
 | 
			
		||||
							
								
								
									
										41
									
								
								packages/examples/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								packages/examples/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
# @mermaid-js/examples
 | 
			
		||||
 | 
			
		||||
The `@mermaid-js/examples` package contains a collection of examples used by tools like [mermaid.live](https://mermaid.live) to help users get started with new diagrams.
 | 
			
		||||
 | 
			
		||||
You can duplicate an existing diagram example file, e.g., `packages/examples/src/examples/flowchart.ts`, and modify it with details specific to your diagram.
 | 
			
		||||
 | 
			
		||||
Then, import the example in the `packages/examples/src/index.ts` file and add it to the `examples` array.
 | 
			
		||||
 | 
			
		||||
Each diagram should have at least one example, which should be marked as the default. It's a good idea to add more examples to showcase different features of the diagram.
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
pnpm add @mermaid-js/examples
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
A sample usage of the package in mermaid.live, to get the default example for every diagram type:
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
import { diagramData } from '@mermaid-js/examples';
 | 
			
		||||
 | 
			
		||||
type DiagramDefinition = (typeof diagramData)[number];
 | 
			
		||||
 | 
			
		||||
const isValidDiagram = (diagram: DiagramDefinition): diagram is Required<DiagramDefinition> => {
 | 
			
		||||
  return Boolean(diagram.name && diagram.examples && diagram.examples.length > 0);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getSampleDiagrams = () => {
 | 
			
		||||
  const diagrams = diagramData
 | 
			
		||||
    .filter((d) => isValidDiagram(d))
 | 
			
		||||
    .map(({ examples, ...rest }) => ({
 | 
			
		||||
      ...rest,
 | 
			
		||||
      example: examples?.filter(({ isDefault }) => isDefault)[0],
 | 
			
		||||
    }));
 | 
			
		||||
  const examples: Record<string, string> = {};
 | 
			
		||||
  for (const diagram of diagrams) {
 | 
			
		||||
    examples[diagram.name.replace(/ (Diagram|Chart|Graph)/, '')] = diagram.example.code;
 | 
			
		||||
  }
 | 
			
		||||
  return examples;
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										36
									
								
								packages/examples/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								packages/examples/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@mermaid-js/examples",
 | 
			
		||||
  "version": "1.0.0",
 | 
			
		||||
  "description": "Mermaid examples package",
 | 
			
		||||
  "author": "Sidharth Vinod",
 | 
			
		||||
  "type": "module",
 | 
			
		||||
  "module": "./dist/mermaid-examples.core.mjs",
 | 
			
		||||
  "types": "./dist/mermaid.d.ts",
 | 
			
		||||
  "exports": {
 | 
			
		||||
    ".": {
 | 
			
		||||
      "types": "./dist/index.d.ts",
 | 
			
		||||
      "import": "./dist/mermaid-examples.core.mjs",
 | 
			
		||||
      "default": "./dist/mermaid-examples.core.mjs"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
    "dist"
 | 
			
		||||
  ],
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "https://github.com/mermaid-js/mermaid"
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "clean": "rimraf dist"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {},
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "mermaid": "workspace:*"
 | 
			
		||||
  },
 | 
			
		||||
  "peerDependencies": {
 | 
			
		||||
    "mermaid": "workspace:~"
 | 
			
		||||
  },
 | 
			
		||||
  "publishConfig": {
 | 
			
		||||
    "access": "public"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								packages/examples/src/example.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								packages/examples/src/example.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
import mermaid from 'mermaid';
 | 
			
		||||
import { diagramData } from './index.js';
 | 
			
		||||
 | 
			
		||||
describe('examples', () => {
 | 
			
		||||
  beforeAll(async () => {
 | 
			
		||||
    // To trigger the diagram registration
 | 
			
		||||
    await mermaid.registerExternalDiagrams([]);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should have examples for each diagrams', () => {
 | 
			
		||||
    const skippedDiagrams = [
 | 
			
		||||
      // These diagrams have no examples
 | 
			
		||||
      'error',
 | 
			
		||||
      'info',
 | 
			
		||||
      '---',
 | 
			
		||||
      // These diagrams have v2 versions, with examples
 | 
			
		||||
      'class',
 | 
			
		||||
      'graph',
 | 
			
		||||
      'flowchart-elk',
 | 
			
		||||
      'flowchart',
 | 
			
		||||
      'state',
 | 
			
		||||
    ];
 | 
			
		||||
    const diagrams = mermaid
 | 
			
		||||
      .getRegisteredDiagramsMetadata()
 | 
			
		||||
      .filter((d) => !skippedDiagrams.includes(d.id));
 | 
			
		||||
    expect(diagrams.length).toBeGreaterThan(0);
 | 
			
		||||
    for (const diagram of diagrams) {
 | 
			
		||||
      const data = diagramData.find((d) => d.id === diagram.id)!;
 | 
			
		||||
      expect(data, `Example for ${diagram.id} is not defined`).toBeDefined();
 | 
			
		||||
      expect(data.examples.length).toBeGreaterThan(0);
 | 
			
		||||
      expect(data.examples.filter((e) => e.isDefault).length).toBe(1);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										24
									
								
								packages/examples/src/examples/architecture.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								packages/examples/src/examples/architecture.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'architecture',
 | 
			
		||||
  name: 'Architecture Diagram',
 | 
			
		||||
  description: 'Visualize system architecture and components',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic System Architecture',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `architecture-beta
 | 
			
		||||
    group api(cloud)[API]
 | 
			
		||||
 | 
			
		||||
    service db(database)[Database] in api
 | 
			
		||||
    service disk1(disk)[Storage] in api
 | 
			
		||||
    service disk2(disk)[Storage] in api
 | 
			
		||||
    service server(server)[Server] in api
 | 
			
		||||
 | 
			
		||||
    db:L -- R:server
 | 
			
		||||
    disk1:T -- B:server
 | 
			
		||||
    disk2:T -- B:db`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										27
									
								
								packages/examples/src/examples/block.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								packages/examples/src/examples/block.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'block',
 | 
			
		||||
  name: 'Block Diagram',
 | 
			
		||||
  description: 'Create block-based visualizations with beta styling',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic Block Layout',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `block-beta
 | 
			
		||||
columns 1
 | 
			
		||||
  db(("DB"))
 | 
			
		||||
  blockArrowId6<["   "]>(down)
 | 
			
		||||
  block:ID
 | 
			
		||||
    A
 | 
			
		||||
    B["A wide one in the middle"]
 | 
			
		||||
    C
 | 
			
		||||
  end
 | 
			
		||||
  space
 | 
			
		||||
  D
 | 
			
		||||
  ID --> D
 | 
			
		||||
  C --> D
 | 
			
		||||
  style B fill:#969,stroke:#333,stroke-width:4px`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										47
									
								
								packages/examples/src/examples/c4.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								packages/examples/src/examples/c4.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'c4',
 | 
			
		||||
  name: 'C4 Diagram',
 | 
			
		||||
  description:
 | 
			
		||||
    'Visualize software architecture using the C4 model (Context, Container, Component, Code)',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Internet Banking System Context',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `C4Context
 | 
			
		||||
    title System Context diagram for Internet Banking System
 | 
			
		||||
    Enterprise_Boundary(b0, "BankBoundary0") {
 | 
			
		||||
        Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")
 | 
			
		||||
        Person(customerB, "Banking Customer B")
 | 
			
		||||
        Person_Ext(customerC, "Banking Customer C", "desc")
 | 
			
		||||
 | 
			
		||||
        Person(customerD, "Banking Customer D", "A customer of the bank, <br/> with personal bank accounts.")
 | 
			
		||||
 | 
			
		||||
        System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.")
 | 
			
		||||
 | 
			
		||||
        Enterprise_Boundary(b1, "BankBoundary") {
 | 
			
		||||
            SystemDb_Ext(SystemE, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
 | 
			
		||||
 | 
			
		||||
            System_Boundary(b2, "BankBoundary2") {
 | 
			
		||||
                System(SystemA, "Banking System A")
 | 
			
		||||
                System(SystemB, "Banking System B", "A system of the bank, with personal bank accounts. next line.")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.")
 | 
			
		||||
            SystemDb(SystemD, "Banking System D Database", "A system of the bank, with personal bank accounts.")
 | 
			
		||||
 | 
			
		||||
            Boundary(b3, "BankBoundary3", "boundary") {
 | 
			
		||||
                SystemQueue(SystemF, "Banking System F Queue", "A system of the bank.")
 | 
			
		||||
                SystemQueue_Ext(SystemG, "Banking System G Queue", "A system of the bank, with personal bank accounts.")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BiRel(customerA, SystemAA, "Uses")
 | 
			
		||||
    BiRel(SystemAA, SystemE, "Uses")
 | 
			
		||||
    Rel(SystemAA, SystemC, "Sends e-mails", "SMTP")
 | 
			
		||||
    Rel(SystemC, customerA, "Sends e-mails to")`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										34
									
								
								packages/examples/src/examples/class.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								packages/examples/src/examples/class.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'classDiagram',
 | 
			
		||||
  name: 'Class Diagram',
 | 
			
		||||
  description: 'Visualize class structures and relationships in object-oriented programming',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic Class Inheritance',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `classDiagram
 | 
			
		||||
    Animal <|-- Duck
 | 
			
		||||
    Animal <|-- Fish
 | 
			
		||||
    Animal <|-- Zebra
 | 
			
		||||
    Animal : +int age
 | 
			
		||||
    Animal : +String gender
 | 
			
		||||
    Animal: +isMammal()
 | 
			
		||||
    Animal: +mate()
 | 
			
		||||
    class Duck{
 | 
			
		||||
      +String beakColor
 | 
			
		||||
      +swim()
 | 
			
		||||
      +quack()
 | 
			
		||||
    }
 | 
			
		||||
    class Fish{
 | 
			
		||||
      -int sizeInFeet
 | 
			
		||||
      -canEat()
 | 
			
		||||
    }
 | 
			
		||||
    class Zebra{
 | 
			
		||||
      +bool is_wild
 | 
			
		||||
      +run()
 | 
			
		||||
    }`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										36
									
								
								packages/examples/src/examples/er.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								packages/examples/src/examples/er.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'er',
 | 
			
		||||
  name: 'Entity Relationship Diagram',
 | 
			
		||||
  description: 'Visualize database schemas and relationships between entities',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic ER Schema',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `erDiagram
 | 
			
		||||
    CUSTOMER ||--o{ ORDER : places
 | 
			
		||||
    ORDER ||--|{ ORDER_ITEM : contains
 | 
			
		||||
    PRODUCT ||--o{ ORDER_ITEM : includes
 | 
			
		||||
    CUSTOMER {
 | 
			
		||||
        string id
 | 
			
		||||
        string name
 | 
			
		||||
        string email
 | 
			
		||||
    }
 | 
			
		||||
    ORDER {
 | 
			
		||||
        string id
 | 
			
		||||
        date orderDate
 | 
			
		||||
        string status
 | 
			
		||||
    }
 | 
			
		||||
    PRODUCT {
 | 
			
		||||
        string id
 | 
			
		||||
        string name
 | 
			
		||||
        float price
 | 
			
		||||
    }
 | 
			
		||||
    ORDER_ITEM {
 | 
			
		||||
        int quantity
 | 
			
		||||
        float price
 | 
			
		||||
    }`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										19
									
								
								packages/examples/src/examples/flowchart.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								packages/examples/src/examples/flowchart.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'flowchart-v2',
 | 
			
		||||
  name: 'Flowchart',
 | 
			
		||||
  description: 'Visualize flowcharts and directed graphs',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic Flowchart',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `flowchart TD
 | 
			
		||||
    A[Christmas] -->|Get money| B(Go shopping)
 | 
			
		||||
    B --> C{Let me think}
 | 
			
		||||
    C -->|One| D[Laptop]
 | 
			
		||||
    C -->|Two| E[iPhone]
 | 
			
		||||
    C -->|Three| F[fa:fa-car Car]`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										22
									
								
								packages/examples/src/examples/gantt.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								packages/examples/src/examples/gantt.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'gantt',
 | 
			
		||||
  name: 'Gantt Chart',
 | 
			
		||||
  description: 'Visualize project schedules and timelines',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic Project Timeline',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `gantt
 | 
			
		||||
    title A Gantt Diagram
 | 
			
		||||
    dateFormat  YYYY-MM-DD
 | 
			
		||||
    section Section
 | 
			
		||||
    A task           :a1, 2014-01-01, 30d
 | 
			
		||||
    Another task     :after a1  , 20d
 | 
			
		||||
    section Another
 | 
			
		||||
    Task in sec      :2014-01-12  , 12d
 | 
			
		||||
    another task      : 24d`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										28
									
								
								packages/examples/src/examples/git.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								packages/examples/src/examples/git.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'gitGraph',
 | 
			
		||||
  name: 'Git Graph',
 | 
			
		||||
  description: 'Visualize Git repository history and branch relationships',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic Git Flow',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `gitGraph
 | 
			
		||||
    commit
 | 
			
		||||
    branch develop
 | 
			
		||||
    checkout develop
 | 
			
		||||
    commit
 | 
			
		||||
    commit
 | 
			
		||||
    checkout main
 | 
			
		||||
    merge develop
 | 
			
		||||
    commit
 | 
			
		||||
    branch feature
 | 
			
		||||
    checkout feature
 | 
			
		||||
    commit
 | 
			
		||||
    commit
 | 
			
		||||
    checkout main
 | 
			
		||||
    merge feature`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										37
									
								
								packages/examples/src/examples/kanban.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								packages/examples/src/examples/kanban.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'kanban',
 | 
			
		||||
  name: 'Kanban Diagram',
 | 
			
		||||
  description: 'Visualize work items in a Kanban board',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Kanban Diagram',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `---
 | 
			
		||||
config:
 | 
			
		||||
  kanban:
 | 
			
		||||
    ticketBaseUrl: 'https://github.com/mermaid-js/mermaid/issues/#TICKET#'
 | 
			
		||||
---
 | 
			
		||||
kanban
 | 
			
		||||
  Todo
 | 
			
		||||
    [Create Documentation]
 | 
			
		||||
    docs[Create Blog about the new diagram]
 | 
			
		||||
  [In progress]
 | 
			
		||||
    id6[Create renderer so that it works in all cases. We also add some extra text here for testing purposes. And some more just for the extra flare.]
 | 
			
		||||
  id9[Ready for deploy]
 | 
			
		||||
    id8[Design grammar]@{ assigned: 'knsv' }
 | 
			
		||||
  id10[Ready for test]
 | 
			
		||||
    id4[Create parsing tests]@{ ticket: 2038, assigned: 'K.Sveidqvist', priority: 'High' }
 | 
			
		||||
    id66[last item]@{ priority: 'Very Low', assigned: 'knsv' }
 | 
			
		||||
  id11[Done]
 | 
			
		||||
    id5[define getData]
 | 
			
		||||
    id2[Title of diagram is more than 100 chars when user duplicates diagram with 100 char]@{ ticket: 2036, priority: 'Very High'}
 | 
			
		||||
    id3[Update DB function]@{ ticket: 2037, assigned: knsv, priority: 'High' }
 | 
			
		||||
 | 
			
		||||
  id12[Can't reproduce]
 | 
			
		||||
    id3[Weird flickering in Firefox]
 | 
			
		||||
`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										32
									
								
								packages/examples/src/examples/mindmap.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								packages/examples/src/examples/mindmap.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'mindmap',
 | 
			
		||||
  name: 'Mindmap',
 | 
			
		||||
  description: 'Visualize ideas and concepts in a tree-like structure',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic Mindmap',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `mindmap
 | 
			
		||||
  root((mindmap))
 | 
			
		||||
    Origins
 | 
			
		||||
      Long history
 | 
			
		||||
      ::icon(fa fa-book)
 | 
			
		||||
      Popularisation
 | 
			
		||||
        British popular psychology author Tony Buzan
 | 
			
		||||
    Research
 | 
			
		||||
      On effectiveness<br/>and features
 | 
			
		||||
      On Automatic creation
 | 
			
		||||
        Uses
 | 
			
		||||
            Creative techniques
 | 
			
		||||
            Strategic planning
 | 
			
		||||
            Argument mapping
 | 
			
		||||
    Tools
 | 
			
		||||
      Pen and paper
 | 
			
		||||
      Mermaid`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
 | 
			
		||||
// cspell:ignore Buzan
 | 
			
		||||
							
								
								
									
										34
									
								
								packages/examples/src/examples/packet.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								packages/examples/src/examples/packet.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'packet',
 | 
			
		||||
  name: 'Packet Diagram',
 | 
			
		||||
  description: 'Visualize packet data and network traffic',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'TCP Packet',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `---
 | 
			
		||||
title: "TCP Packet"
 | 
			
		||||
---
 | 
			
		||||
packet
 | 
			
		||||
0-15: "Source Port"
 | 
			
		||||
16-31: "Destination Port"
 | 
			
		||||
32-63: "Sequence Number"
 | 
			
		||||
64-95: "Acknowledgment Number"
 | 
			
		||||
96-99: "Data Offset"
 | 
			
		||||
100-105: "Reserved"
 | 
			
		||||
106: "URG"
 | 
			
		||||
107: "ACK"
 | 
			
		||||
108: "PSH"
 | 
			
		||||
109: "RST"
 | 
			
		||||
110: "SYN"
 | 
			
		||||
111: "FIN"
 | 
			
		||||
112-127: "Window"
 | 
			
		||||
128-143: "Checksum"
 | 
			
		||||
144-159: "Urgent Pointer"
 | 
			
		||||
160-191: "(Options and Padding)"
 | 
			
		||||
192-255: "Data (variable length)"`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										17
									
								
								packages/examples/src/examples/pie.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								packages/examples/src/examples/pie.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'pie',
 | 
			
		||||
  name: 'Pie Chart',
 | 
			
		||||
  description: 'Visualize data as proportional segments of a circle',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic Pie Chart',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `pie title Pets adopted by volunteers
 | 
			
		||||
    "Dogs" : 386
 | 
			
		||||
    "Cats" : 85
 | 
			
		||||
    "Rats" : 15`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										27
									
								
								packages/examples/src/examples/quadrant-chart.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								packages/examples/src/examples/quadrant-chart.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'quadrantChart',
 | 
			
		||||
  name: 'Quadrant Chart',
 | 
			
		||||
  description: 'Visualize items in a 2x2 matrix based on two variables',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Product Positioning',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `quadrantChart
 | 
			
		||||
    title Reach and engagement of campaigns
 | 
			
		||||
    x-axis Low Reach --> High Reach
 | 
			
		||||
    y-axis Low Engagement --> High Engagement
 | 
			
		||||
    quadrant-1 We should expand
 | 
			
		||||
    quadrant-2 Need to promote
 | 
			
		||||
    quadrant-3 Re-evaluate
 | 
			
		||||
    quadrant-4 May be improved
 | 
			
		||||
    Campaign A: [0.3, 0.6]
 | 
			
		||||
    Campaign B: [0.45, 0.23]
 | 
			
		||||
    Campaign C: [0.57, 0.69]
 | 
			
		||||
    Campaign D: [0.78, 0.34]
 | 
			
		||||
    Campaign E: [0.40, 0.34]
 | 
			
		||||
    Campaign F: [0.35, 0.78]`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										25
									
								
								packages/examples/src/examples/radar.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								packages/examples/src/examples/radar.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'radar',
 | 
			
		||||
  name: 'Radar Diagram',
 | 
			
		||||
  description: 'Visualize data in a radial format',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Student Grades',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `---
 | 
			
		||||
title: "Grades"
 | 
			
		||||
---
 | 
			
		||||
radar-beta
 | 
			
		||||
  axis m["Math"], s["Science"], e["English"]
 | 
			
		||||
  axis h["History"], g["Geography"], a["Art"]
 | 
			
		||||
  curve a["Alice"]{85, 90, 80, 70, 75, 90}
 | 
			
		||||
  curve b["Bob"]{70, 75, 85, 80, 90, 85}
 | 
			
		||||
 | 
			
		||||
  max 100
 | 
			
		||||
  min 0
 | 
			
		||||
`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										27
									
								
								packages/examples/src/examples/requirement.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								packages/examples/src/examples/requirement.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'requirement',
 | 
			
		||||
  name: 'Requirement Diagram',
 | 
			
		||||
  description: 'Visualize system requirements and their relationships',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic Requirements',
 | 
			
		||||
      code: `requirementDiagram
 | 
			
		||||
 | 
			
		||||
    requirement test_req {
 | 
			
		||||
    id: 1
 | 
			
		||||
    text: the test text.
 | 
			
		||||
    risk: high
 | 
			
		||||
    verifymethod: test
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    element test_entity {
 | 
			
		||||
    type: simulation
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    test_entity - satisfies -> test_req`,
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										88
									
								
								packages/examples/src/examples/sankey.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								packages/examples/src/examples/sankey.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'sankey',
 | 
			
		||||
  name: 'Sankey Diagram',
 | 
			
		||||
  description: 'Visualize flow quantities between different stages or processes',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Energy Flow',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `---
 | 
			
		||||
config:
 | 
			
		||||
  sankey:
 | 
			
		||||
    showValues: false
 | 
			
		||||
---
 | 
			
		||||
sankey-beta
 | 
			
		||||
 | 
			
		||||
Agricultural 'waste',Bio-conversion,124.729
 | 
			
		||||
Bio-conversion,Liquid,0.597
 | 
			
		||||
Bio-conversion,Losses,26.862
 | 
			
		||||
Bio-conversion,Solid,280.322
 | 
			
		||||
Bio-conversion,Gas,81.144
 | 
			
		||||
Biofuel imports,Liquid,35
 | 
			
		||||
Biomass imports,Solid,35
 | 
			
		||||
Coal imports,Coal,11.606
 | 
			
		||||
Coal reserves,Coal,63.965
 | 
			
		||||
Coal,Solid,75.571
 | 
			
		||||
District heating,Industry,10.639
 | 
			
		||||
District heating,Heating and cooling - commercial,22.505
 | 
			
		||||
District heating,Heating and cooling - homes,46.184
 | 
			
		||||
Electricity grid,Over generation / exports,104.453
 | 
			
		||||
Electricity grid,Heating and cooling - homes,113.726
 | 
			
		||||
Electricity grid,H2 conversion,27.14
 | 
			
		||||
Electricity grid,Industry,342.165
 | 
			
		||||
Electricity grid,Road transport,37.797
 | 
			
		||||
Electricity grid,Agriculture,4.412
 | 
			
		||||
Electricity grid,Heating and cooling - commercial,40.858
 | 
			
		||||
Electricity grid,Losses,56.691
 | 
			
		||||
Electricity grid,Rail transport,7.863
 | 
			
		||||
Electricity grid,Lighting & appliances - commercial,90.008
 | 
			
		||||
Electricity grid,Lighting & appliances - homes,93.494
 | 
			
		||||
Gas imports,NGas,40.719
 | 
			
		||||
Gas reserves,NGas,82.233
 | 
			
		||||
Gas,Heating and cooling - commercial,0.129
 | 
			
		||||
Gas,Losses,1.401
 | 
			
		||||
Gas,Thermal generation,151.891
 | 
			
		||||
Gas,Agriculture,2.096
 | 
			
		||||
Gas,Industry,48.58
 | 
			
		||||
Geothermal,Electricity grid,7.013
 | 
			
		||||
H2 conversion,H2,20.897
 | 
			
		||||
H2 conversion,Losses,6.242
 | 
			
		||||
H2,Road transport,20.897
 | 
			
		||||
Hydro,Electricity grid,6.995
 | 
			
		||||
Liquid,Industry,121.066
 | 
			
		||||
Liquid,International shipping,128.69
 | 
			
		||||
Liquid,Road transport,135.835
 | 
			
		||||
Liquid,Domestic aviation,14.458
 | 
			
		||||
Liquid,International aviation,206.267
 | 
			
		||||
Liquid,Agriculture,3.64
 | 
			
		||||
Liquid,National navigation,33.218
 | 
			
		||||
Liquid,Rail transport,4.413
 | 
			
		||||
Marine algae,Bio-conversion,4.375
 | 
			
		||||
NGas,Gas,122.952
 | 
			
		||||
Nuclear,Thermal generation,839.978
 | 
			
		||||
Oil imports,Oil,504.287
 | 
			
		||||
Oil reserves,Oil,107.703
 | 
			
		||||
Oil,Liquid,611.99
 | 
			
		||||
Other waste,Solid,56.587
 | 
			
		||||
Other waste,Bio-conversion,77.81
 | 
			
		||||
Pumped heat,Heating and cooling - homes,193.026
 | 
			
		||||
Pumped heat,Heating and cooling - commercial,70.672
 | 
			
		||||
Solar PV,Electricity grid,59.901
 | 
			
		||||
Solar Thermal,Heating and cooling - homes,19.263
 | 
			
		||||
Solar,Solar Thermal,19.263
 | 
			
		||||
Solar,Solar PV,59.901
 | 
			
		||||
Solid,Agriculture,0.882
 | 
			
		||||
Solid,Thermal generation,400.12
 | 
			
		||||
Solid,Industry,46.477
 | 
			
		||||
Thermal generation,Electricity grid,525.531
 | 
			
		||||
Thermal generation,Losses,787.129
 | 
			
		||||
Thermal generation,District heating,79.329
 | 
			
		||||
Tidal,Electricity grid,9.452
 | 
			
		||||
UK land based bioenergy,Bio-conversion,182.01
 | 
			
		||||
Wave,Electricity grid,19.013
 | 
			
		||||
Wind,Electricity grid,289.366`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										18
									
								
								packages/examples/src/examples/sequence.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								packages/examples/src/examples/sequence.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'sequence',
 | 
			
		||||
  name: 'Sequence Diagram',
 | 
			
		||||
  description: 'Visualize interactions between objects over time',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic Sequence',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `sequenceDiagram
 | 
			
		||||
    Alice->>+John: Hello John, how are you?
 | 
			
		||||
    Alice->>+John: John, can you hear me?
 | 
			
		||||
    John-->>-Alice: Hi Alice, I can hear you!
 | 
			
		||||
    John-->>-Alice: I feel great!`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										20
									
								
								packages/examples/src/examples/state.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								packages/examples/src/examples/state.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'stateDiagram',
 | 
			
		||||
  name: 'State Diagram',
 | 
			
		||||
  description: 'Visualize the states and transitions of a system',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Basic State Diagram',
 | 
			
		||||
      code: `stateDiagram-v2
 | 
			
		||||
    [*] --> Still
 | 
			
		||||
    Still --> [*]
 | 
			
		||||
    Still --> Moving
 | 
			
		||||
    Moving --> Still
 | 
			
		||||
    Moving --> Crash
 | 
			
		||||
    Crash --> [*]`,
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										20
									
								
								packages/examples/src/examples/timeline.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								packages/examples/src/examples/timeline.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'timeline',
 | 
			
		||||
  name: 'Timeline Diagram',
 | 
			
		||||
  description: 'Visualize events and milestones in chronological order',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Project Timeline',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `timeline
 | 
			
		||||
    title History of Social Media Platform
 | 
			
		||||
    2002 : LinkedIn
 | 
			
		||||
    2004 : Facebook
 | 
			
		||||
         : Google
 | 
			
		||||
    2005 : YouTube
 | 
			
		||||
    2006 : Twitter`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										21
									
								
								packages/examples/src/examples/treemap.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								packages/examples/src/examples/treemap.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'treemap',
 | 
			
		||||
  name: 'Treemap',
 | 
			
		||||
  description: 'Visualize hierarchical data as nested rectangles',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Treemap',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `treemap-beta
 | 
			
		||||
"Section 1"
 | 
			
		||||
    "Leaf 1.1": 12
 | 
			
		||||
    "Section 1.2"
 | 
			
		||||
      "Leaf 1.2.1": 12
 | 
			
		||||
"Section 2"
 | 
			
		||||
    "Leaf 2.1": 20
 | 
			
		||||
    "Leaf 2.2": 25`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										22
									
								
								packages/examples/src/examples/user-journey.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								packages/examples/src/examples/user-journey.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'journey',
 | 
			
		||||
  name: 'User Journey Diagram',
 | 
			
		||||
  description: 'Visualize user interactions and experiences with a system',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'My Working Day',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `journey
 | 
			
		||||
    title My working day
 | 
			
		||||
    section Go to work
 | 
			
		||||
      Make tea: 5: Me
 | 
			
		||||
      Go upstairs: 3: Me
 | 
			
		||||
      Do work: 1: Me, Cat
 | 
			
		||||
    section Go home
 | 
			
		||||
      Go downstairs: 5: Me
 | 
			
		||||
      Sit down: 5: Me`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										19
									
								
								packages/examples/src/examples/xychart.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								packages/examples/src/examples/xychart.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import type { DiagramMetadata } from '../types.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  id: 'xychart',
 | 
			
		||||
  name: 'XY Chart',
 | 
			
		||||
  description: 'Create scatter plots and line charts with customizable axes',
 | 
			
		||||
  examples: [
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Sales Revenue',
 | 
			
		||||
      isDefault: true,
 | 
			
		||||
      code: `xychart-beta
 | 
			
		||||
    title "Sales Revenue"
 | 
			
		||||
    x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
 | 
			
		||||
    y-axis "Revenue (in $)" 4000 --> 11000
 | 
			
		||||
    bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
 | 
			
		||||
    line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]`,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
} satisfies DiagramMetadata;
 | 
			
		||||
							
								
								
									
										48
									
								
								packages/examples/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								packages/examples/src/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
import type { DiagramMetadata } from './types.js';
 | 
			
		||||
import flowChart from './examples/flowchart.js';
 | 
			
		||||
import c4 from './examples/c4.js';
 | 
			
		||||
import kanban from './examples/kanban.js';
 | 
			
		||||
import classDiagram from './examples/class.js';
 | 
			
		||||
import sequenceDiagram from './examples/sequence.js';
 | 
			
		||||
import pieDiagram from './examples/pie.js';
 | 
			
		||||
import userJourneyDiagram from './examples/user-journey.js';
 | 
			
		||||
import mindmapDiagram from './examples/mindmap.js';
 | 
			
		||||
import requirementDiagram from './examples/requirement.js';
 | 
			
		||||
import radarDiagram from './examples/radar.js';
 | 
			
		||||
import stateDiagram from './examples/state.js';
 | 
			
		||||
import erDiagram from './examples/er.js';
 | 
			
		||||
import gitDiagram from './examples/git.js';
 | 
			
		||||
import architectureDiagram from './examples/architecture.js';
 | 
			
		||||
import xychartDiagram from './examples/xychart.js';
 | 
			
		||||
import sankeyDiagram from './examples/sankey.js';
 | 
			
		||||
import ganttDiagram from './examples/gantt.js';
 | 
			
		||||
import timelineDiagram from './examples/timeline.js';
 | 
			
		||||
import quadrantChart from './examples/quadrant-chart.js';
 | 
			
		||||
import packetDiagram from './examples/packet.js';
 | 
			
		||||
import blockDiagram from './examples/block.js';
 | 
			
		||||
import treemapDiagram from './examples/treemap.js';
 | 
			
		||||
 | 
			
		||||
export const diagramData: DiagramMetadata[] = [
 | 
			
		||||
  flowChart,
 | 
			
		||||
  c4,
 | 
			
		||||
  kanban,
 | 
			
		||||
  classDiagram,
 | 
			
		||||
  sequenceDiagram,
 | 
			
		||||
  pieDiagram,
 | 
			
		||||
  userJourneyDiagram,
 | 
			
		||||
  mindmapDiagram,
 | 
			
		||||
  requirementDiagram,
 | 
			
		||||
  radarDiagram,
 | 
			
		||||
  stateDiagram,
 | 
			
		||||
  erDiagram,
 | 
			
		||||
  gitDiagram,
 | 
			
		||||
  architectureDiagram,
 | 
			
		||||
  xychartDiagram,
 | 
			
		||||
  sankeyDiagram,
 | 
			
		||||
  ganttDiagram,
 | 
			
		||||
  timelineDiagram,
 | 
			
		||||
  quadrantChart,
 | 
			
		||||
  packetDiagram,
 | 
			
		||||
  blockDiagram,
 | 
			
		||||
  treemapDiagram,
 | 
			
		||||
];
 | 
			
		||||
							
								
								
									
										12
									
								
								packages/examples/src/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								packages/examples/src/types.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
export interface Example {
 | 
			
		||||
  title: string;
 | 
			
		||||
  code: string;
 | 
			
		||||
  isDefault?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DiagramMetadata {
 | 
			
		||||
  id: string;
 | 
			
		||||
  name: string;
 | 
			
		||||
  description: string;
 | 
			
		||||
  examples: Example[];
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								packages/examples/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								packages/examples/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": "../../tsconfig.json",
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "outDir": "./dist",
 | 
			
		||||
    "rootDir": "./src",
 | 
			
		||||
    "module": "Node16",
 | 
			
		||||
    "moduleResolution": "Node16"
 | 
			
		||||
  },
 | 
			
		||||
  "include": ["src/**/*"],
 | 
			
		||||
  "exclude": ["node_modules", "dist"]
 | 
			
		||||
}
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
../mermaid/src/docs/syntax/zenuml.md
 | 
			
		||||
							
								
								
									
										384
									
								
								packages/mermaid-zenuml/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								packages/mermaid-zenuml/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,384 @@
 | 
			
		||||
# @mermaid-js/mermaid-zenuml
 | 
			
		||||
 | 
			
		||||
MermaidJS plugin for ZenUML integration - A powerful sequence diagram rendering engine.
 | 
			
		||||
 | 
			
		||||
> A Sequence diagram is an interaction diagram that shows how processes operate with one another and in what order.
 | 
			
		||||
 | 
			
		||||
Mermaid can render sequence diagrams with [ZenUML](https://zenuml.com). Note that ZenUML uses a different
 | 
			
		||||
syntax than the original Sequence Diagram in mermaid.
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    BookLibService.Borrow(id) {
 | 
			
		||||
      User = Session.GetUser()
 | 
			
		||||
      if(User.isActive) {
 | 
			
		||||
        try {
 | 
			
		||||
          BookRepository.Update(id, onLoan, User)
 | 
			
		||||
          receipt = new Receipt(id, dueDate)
 | 
			
		||||
        } catch (BookNotFoundException) {
 | 
			
		||||
          ErrorService.onException(BookNotFoundException)
 | 
			
		||||
        } finally {
 | 
			
		||||
          Connection.close()
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return receipt
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
### With bundlers
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
npm install @mermaid-js/mermaid-zenuml
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
import mermaid from 'mermaid';
 | 
			
		||||
import zenuml from '@mermaid-js/mermaid-zenuml';
 | 
			
		||||
 | 
			
		||||
await mermaid.registerExternalDiagrams([zenuml]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### With CDN
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<script type="module">
 | 
			
		||||
  import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
 | 
			
		||||
  import zenuml from 'https://cdn.jsdelivr.net/npm/@mermaid-js/mermaid-zenuml@0.2.0/dist/mermaid-zenuml.core.mjs';
 | 
			
		||||
  await mermaid.registerExternalDiagrams([zenuml]);
 | 
			
		||||
</script>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
> [!NOTE]  
 | 
			
		||||
> ZenUML uses experimental lazy loading & async rendering features which could change in the future.
 | 
			
		||||
 | 
			
		||||
## Basic Usage
 | 
			
		||||
 | 
			
		||||
Once the plugin is registered, you can create ZenUML diagrams using the `zenuml` syntax:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    Controller.Get(id) {
 | 
			
		||||
        Service.Get(id) {
 | 
			
		||||
            item = Repository.Get(id)
 | 
			
		||||
            if(item) {
 | 
			
		||||
                return item
 | 
			
		||||
            } else {
 | 
			
		||||
                return null
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return result
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## ZenUML Syntax Reference
 | 
			
		||||
 | 
			
		||||
### Participants
 | 
			
		||||
 | 
			
		||||
The participants can be defined implicitly as in the first example on this page. The participants or actors are
 | 
			
		||||
rendered in order of appearance in the diagram source text. Sometimes you might want to show the participants in a
 | 
			
		||||
different order than how they appear in the first message. It is possible to specify the actor's order of
 | 
			
		||||
appearance by doing the following:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    title Declare participant (optional)
 | 
			
		||||
    Bob
 | 
			
		||||
    Alice
 | 
			
		||||
    Alice->Bob: Hi Bob
 | 
			
		||||
    Bob->Alice: Hi Alice
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Annotators
 | 
			
		||||
 | 
			
		||||
If you specifically want to use symbols instead of just rectangles with text you can do so by using the annotator syntax to declare participants as per below.
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    title Annotators
 | 
			
		||||
    @Actor Alice
 | 
			
		||||
    @Database Bob
 | 
			
		||||
    Alice->Bob: Hi Bob
 | 
			
		||||
    Bob->Alice: Hi Alice
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Available annotators include:
 | 
			
		||||
 | 
			
		||||
- `@Actor` - Human figure
 | 
			
		||||
- `@Database` - Database symbol
 | 
			
		||||
- `@Boundary` - Boundary symbol
 | 
			
		||||
- `@Control` - Control symbol
 | 
			
		||||
- `@Entity` - Entity symbol
 | 
			
		||||
- `@Queue` - Queue symbol
 | 
			
		||||
 | 
			
		||||
### Aliases
 | 
			
		||||
 | 
			
		||||
The participants can have a convenient identifier and a descriptive label.
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    title Aliases
 | 
			
		||||
    A as Alice
 | 
			
		||||
    J as John
 | 
			
		||||
    A->J: Hello John, how are you?
 | 
			
		||||
    J->A: Great!
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Messages
 | 
			
		||||
 | 
			
		||||
Messages can be one of:
 | 
			
		||||
 | 
			
		||||
1. Sync message
 | 
			
		||||
2. Async message
 | 
			
		||||
3. Creation message
 | 
			
		||||
4. Reply message
 | 
			
		||||
 | 
			
		||||
### Sync message
 | 
			
		||||
 | 
			
		||||
You can think of a sync (blocking) method in a programming language.
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    title Sync message
 | 
			
		||||
    A.SyncMessage
 | 
			
		||||
    A.SyncMessage(with, parameters) {
 | 
			
		||||
      B.nestedSyncMessage()
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Async message
 | 
			
		||||
 | 
			
		||||
You can think of an async (non-blocking) method in a programming language. Fire an event and forget about it.
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    title Async message
 | 
			
		||||
    Alice->Bob: How are you?
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Creation message
 | 
			
		||||
 | 
			
		||||
We use `new` keyword to create an object.
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    new A1
 | 
			
		||||
    new A2(with, parameters)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Reply message
 | 
			
		||||
 | 
			
		||||
There are three ways to express a reply message:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    // 1. assign a variable from a sync message.
 | 
			
		||||
    a = A.SyncMessage()
 | 
			
		||||
 | 
			
		||||
    // 1.1. optionally give the variable a type
 | 
			
		||||
    SomeType a = A.SyncMessage()
 | 
			
		||||
 | 
			
		||||
    // 2. use return keyword
 | 
			
		||||
    A.SyncMessage() {
 | 
			
		||||
    return result
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 3. use @return or @reply annotator on an async message
 | 
			
		||||
    @return
 | 
			
		||||
    A->B: result
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The third way `@return` is rarely used, but it is useful when you want to return to one level up.
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    title Reply message
 | 
			
		||||
    Client->A.method() {
 | 
			
		||||
      B.method() {
 | 
			
		||||
        if(condition) {
 | 
			
		||||
          return x1
 | 
			
		||||
          // return early
 | 
			
		||||
          @return
 | 
			
		||||
          A->Client: x11
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return x2
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Advanced Features
 | 
			
		||||
 | 
			
		||||
### Nesting
 | 
			
		||||
 | 
			
		||||
Sync messages and Creation messages are naturally nestable with `{}`.
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    A.method() {
 | 
			
		||||
      B.nested_sync_method()
 | 
			
		||||
      B->C: nested async message
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Comments
 | 
			
		||||
 | 
			
		||||
It is possible to add comments to a sequence diagram with `// comment` syntax.
 | 
			
		||||
Comments will be rendered above the messages or fragments. Comments on other places
 | 
			
		||||
are ignored. Markdown is supported.
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    // a comment on a participant will not be rendered
 | 
			
		||||
    BookService
 | 
			
		||||
    // a comment on a message.
 | 
			
		||||
    // **Markdown** is supported.
 | 
			
		||||
    BookService.getBook()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Loops
 | 
			
		||||
 | 
			
		||||
It is possible to express loops in a ZenUML diagram. This is done by any of the
 | 
			
		||||
following notations:
 | 
			
		||||
 | 
			
		||||
1. while
 | 
			
		||||
2. for
 | 
			
		||||
3. forEach, foreach
 | 
			
		||||
4. loop
 | 
			
		||||
 | 
			
		||||
```zenuml
 | 
			
		||||
while(condition) {
 | 
			
		||||
    ...statements...
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    Alice->John: Hello John, how are you?
 | 
			
		||||
    while(true) {
 | 
			
		||||
      John->Alice: Great!
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Alt (Alternative paths)
 | 
			
		||||
 | 
			
		||||
It is possible to express alternative paths in a sequence diagram. This is done by the notation
 | 
			
		||||
 | 
			
		||||
```zenuml
 | 
			
		||||
if(condition1) {
 | 
			
		||||
    ...statements...
 | 
			
		||||
} else if(condition2) {
 | 
			
		||||
    ...statements...
 | 
			
		||||
} else {
 | 
			
		||||
    ...statements...
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    Alice->Bob: Hello Bob, how are you?
 | 
			
		||||
    if(is_sick) {
 | 
			
		||||
      Bob->Alice: Not so good :(
 | 
			
		||||
    } else {
 | 
			
		||||
      Bob->Alice: Feeling fresh like a daisy
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Opt (Optional)
 | 
			
		||||
 | 
			
		||||
It is possible to render an `opt` fragment. This is done by the notation
 | 
			
		||||
 | 
			
		||||
```zenuml
 | 
			
		||||
opt {
 | 
			
		||||
  ...statements...
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    Alice->Bob: Hello Bob, how are you?
 | 
			
		||||
    Bob->Alice: Not so good :(
 | 
			
		||||
    opt {
 | 
			
		||||
      Bob->Alice: Thanks for asking
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parallel
 | 
			
		||||
 | 
			
		||||
It is possible to show actions that are happening in parallel.
 | 
			
		||||
 | 
			
		||||
This is done by the notation
 | 
			
		||||
 | 
			
		||||
```zenuml
 | 
			
		||||
par {
 | 
			
		||||
  statement1
 | 
			
		||||
  statement2
 | 
			
		||||
  statement3
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    par {
 | 
			
		||||
        Alice->Bob: Hello guys!
 | 
			
		||||
        Alice->John: Hello guys!
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Try/Catch/Finally (Break)
 | 
			
		||||
 | 
			
		||||
It is possible to indicate a stop of the sequence within the flow (usually used to model exceptions).
 | 
			
		||||
 | 
			
		||||
This is done by the notation
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
try {
 | 
			
		||||
  ...statements...
 | 
			
		||||
} catch {
 | 
			
		||||
  ...statements...
 | 
			
		||||
} finally {
 | 
			
		||||
  ...statements...
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
zenuml
 | 
			
		||||
    try {
 | 
			
		||||
      Consumer->API: Book something
 | 
			
		||||
      API->BookingService: Start booking process
 | 
			
		||||
    } catch {
 | 
			
		||||
      API->Consumer: show failure
 | 
			
		||||
    } finally {
 | 
			
		||||
      API->BookingService: rollback status
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Contributing
 | 
			
		||||
 | 
			
		||||
This package is part of the [Mermaid](https://github.com/mermaid-js/mermaid) project. See the main repository for contributing guidelines.
 | 
			
		||||
 | 
			
		||||
## Contributors
 | 
			
		||||
 | 
			
		||||
- [Peng Xiao](https://github.com/MrCoder)
 | 
			
		||||
- [Sidharth Vinod](https://sidharth.dev)
 | 
			
		||||
- [Dong Cai](https://github.com/dontry)
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
MIT
 | 
			
		||||
 | 
			
		||||
## Links
 | 
			
		||||
 | 
			
		||||
- [ZenUML Official Website](https://zenuml.com)
 | 
			
		||||
- [Mermaid Documentation](https://mermaid.js.org)
 | 
			
		||||
- [GitHub Repository](https://github.com/mermaid-js/mermaid)
 | 
			
		||||
@@ -33,7 +33,7 @@
 | 
			
		||||
  ],
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@zenuml/core": "^3.31.1"
 | 
			
		||||
    "@zenuml/core": "^3.35.2"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "mermaid": "workspace:^"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								packages/mermaid-zenuml/src/zenuml.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								packages/mermaid-zenuml/src/zenuml.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
declare module '@zenuml/core' {
 | 
			
		||||
  interface RenderOptions {
 | 
			
		||||
    theme?: string;
 | 
			
		||||
    mode?: string;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  export default class ZenUml {
 | 
			
		||||
    constructor(container: Element);
 | 
			
		||||
    render(text: string, options?: RenderOptions): Promise<void>;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -53,7 +53,6 @@ export const draw = async function (text: string, id: string) {
 | 
			
		||||
 | 
			
		||||
  const { foreignObject, container, app } = createForeignObject(id);
 | 
			
		||||
  svgContainer.appendChild(foreignObject);
 | 
			
		||||
  // @ts-expect-error @zenuml/core@3.0.0 exports the wrong type for ZenUml
 | 
			
		||||
  const zenuml = new ZenUml(app);
 | 
			
		||||
  // default is a theme name. More themes to be added and will be configurable in the future
 | 
			
		||||
  await zenuml.render(text, { theme: 'default', mode: 'static' });
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "mermaid",
 | 
			
		||||
  "version": "11.8.1",
 | 
			
		||||
  "version": "11.9.0",
 | 
			
		||||
  "description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
 | 
			
		||||
  "type": "module",
 | 
			
		||||
  "module": "./dist/mermaid.core.mjs",
 | 
			
		||||
@@ -79,10 +79,10 @@
 | 
			
		||||
    "dagre-d3-es": "7.0.11",
 | 
			
		||||
    "dayjs": "^1.11.13",
 | 
			
		||||
    "dompurify": "^3.2.5",
 | 
			
		||||
    "katex": "^0.16.9",
 | 
			
		||||
    "katex": "^0.16.22",
 | 
			
		||||
    "khroma": "^2.1.0",
 | 
			
		||||
    "lodash-es": "^4.17.21",
 | 
			
		||||
    "marked": "^15.0.7",
 | 
			
		||||
    "marked": "^16.0.0",
 | 
			
		||||
    "roughjs": "^4.6.6",
 | 
			
		||||
    "stylis": "^4.3.6",
 | 
			
		||||
    "ts-dedent": "^2.2.0",
 | 
			
		||||
@@ -105,13 +105,14 @@
 | 
			
		||||
    "@types/stylis": "^4.2.7",
 | 
			
		||||
    "@types/uuid": "^10.0.0",
 | 
			
		||||
    "ajv": "^8.17.1",
 | 
			
		||||
    "canvas": "^3.1.0",
 | 
			
		||||
    "chokidar": "3.6.0",
 | 
			
		||||
    "concurrently": "^9.1.2",
 | 
			
		||||
    "csstree-validator": "^4.0.1",
 | 
			
		||||
    "globby": "^14.0.2",
 | 
			
		||||
    "jison": "^0.4.18",
 | 
			
		||||
    "js-base64": "^3.7.7",
 | 
			
		||||
    "jsdom": "^26.0.0",
 | 
			
		||||
    "jsdom": "^26.1.0",
 | 
			
		||||
    "json-schema-to-typescript": "^15.0.4",
 | 
			
		||||
    "micromatch": "^4.0.8",
 | 
			
		||||
    "path-browserify": "^1.0.1",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +1,25 @@
 | 
			
		||||
import { MockedD3 } from './tests/MockedD3.js';
 | 
			
		||||
import { setA11yDiagramInfo, addSVGa11yTitleDescription } from './accessibility.js';
 | 
			
		||||
import type { D3Element } from './types.js';
 | 
			
		||||
import { addSVGa11yTitleDescription, setA11yDiagramInfo } from './accessibility.js';
 | 
			
		||||
import { ensureNodeFromSelector, jsdomIt } from './tests/util.js';
 | 
			
		||||
import { expect } from 'vitest';
 | 
			
		||||
 | 
			
		||||
describe('accessibility', () => {
 | 
			
		||||
  const fauxSvgNode: MockedD3 = new MockedD3();
 | 
			
		||||
 | 
			
		||||
  describe('setA11yDiagramInfo', () => {
 | 
			
		||||
    it('should set svg element role to "graphics-document document"', () => {
 | 
			
		||||
      const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
 | 
			
		||||
      setA11yDiagramInfo(fauxSvgNode, 'flowchart');
 | 
			
		||||
      expect(svgAttrSpy).toHaveBeenCalledWith('role', 'graphics-document document');
 | 
			
		||||
    jsdomIt('should set svg element role to "graphics-document document"', ({ svg }) => {
 | 
			
		||||
      setA11yDiagramInfo(svg, 'flowchart');
 | 
			
		||||
      const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
      expect(svgNode.getAttribute('role')).toBe('graphics-document document');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should set aria-roledescription to the diagram type', () => {
 | 
			
		||||
      const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
 | 
			
		||||
      setA11yDiagramInfo(fauxSvgNode, 'flowchart');
 | 
			
		||||
      expect(svgAttrSpy).toHaveBeenCalledWith('aria-roledescription', 'flowchart');
 | 
			
		||||
    jsdomIt('should set aria-roledescription to the diagram type', ({ svg }) => {
 | 
			
		||||
      setA11yDiagramInfo(svg, 'flowchart');
 | 
			
		||||
      const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
      expect(svgNode.getAttribute('aria-roledescription')).toBe('flowchart');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should not set aria-roledescription if the diagram type is empty', () => {
 | 
			
		||||
      const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
 | 
			
		||||
      setA11yDiagramInfo(fauxSvgNode, '');
 | 
			
		||||
      expect(svgAttrSpy).toHaveBeenCalledTimes(1);
 | 
			
		||||
      expect(svgAttrSpy).toHaveBeenCalledWith('role', expect.anything()); // only called to set the role
 | 
			
		||||
    jsdomIt('should not set aria-roledescription if the diagram type is empty', ({ svg }) => {
 | 
			
		||||
      setA11yDiagramInfo(svg, '');
 | 
			
		||||
      const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
      expect(svgNode.getAttribute('aria-roledescription')).toBeNull();
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
@@ -39,115 +36,78 @@ describe('accessibility', () => {
 | 
			
		||||
        expect(noInsertAttrSpy).not.toHaveBeenCalled();
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // convenience functions to DRY up the spec
 | 
			
		||||
 | 
			
		||||
      function expectAriaLabelledByItTitleId(
 | 
			
		||||
        svgD3Node: D3Element,
 | 
			
		||||
        title: string | undefined,
 | 
			
		||||
        desc: string | undefined,
 | 
			
		||||
        givenId: string
 | 
			
		||||
      ): void {
 | 
			
		||||
        const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
 | 
			
		||||
        addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
 | 
			
		||||
        expect(svgAttrSpy).toHaveBeenCalledWith('aria-labelledby', `chart-title-${givenId}`);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      function expectAriaDescribedByItDescId(
 | 
			
		||||
        svgD3Node: D3Element,
 | 
			
		||||
        title: string | undefined,
 | 
			
		||||
        desc: string | undefined,
 | 
			
		||||
        givenId: string
 | 
			
		||||
      ): void {
 | 
			
		||||
        const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
 | 
			
		||||
        addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
 | 
			
		||||
        expect(svgAttrSpy).toHaveBeenCalledWith('aria-describedby', `chart-desc-${givenId}`);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      function a11yTitleTagInserted(
 | 
			
		||||
        svgD3Node: D3Element,
 | 
			
		||||
        title: string | undefined,
 | 
			
		||||
        desc: string | undefined,
 | 
			
		||||
        givenId: string,
 | 
			
		||||
        callNumber: number
 | 
			
		||||
      ): void {
 | 
			
		||||
        a11yTagInserted(svgD3Node, title, desc, givenId, callNumber, 'title', title);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      function a11yDescTagInserted(
 | 
			
		||||
        svgD3Node: D3Element,
 | 
			
		||||
        title: string | undefined,
 | 
			
		||||
        desc: string | undefined,
 | 
			
		||||
        givenId: string,
 | 
			
		||||
        callNumber: number
 | 
			
		||||
      ): void {
 | 
			
		||||
        a11yTagInserted(svgD3Node, title, desc, givenId, callNumber, 'desc', desc);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      function a11yTagInserted(
 | 
			
		||||
        _svgD3Node: D3Element,
 | 
			
		||||
        title: string | undefined,
 | 
			
		||||
        desc: string | undefined,
 | 
			
		||||
        givenId: string,
 | 
			
		||||
        callNumber: number,
 | 
			
		||||
        expectedPrefix: string,
 | 
			
		||||
        expectedText: string | undefined
 | 
			
		||||
      ): void {
 | 
			
		||||
        const fauxInsertedD3: MockedD3 = new MockedD3();
 | 
			
		||||
        const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxInsertedD3);
 | 
			
		||||
        const titleAttrSpy = vi.spyOn(fauxInsertedD3, 'attr').mockReturnValue(fauxInsertedD3);
 | 
			
		||||
        const titleTextSpy = vi.spyOn(fauxInsertedD3, 'text');
 | 
			
		||||
 | 
			
		||||
        addSVGa11yTitleDescription(fauxSvgNode, title, desc, givenId);
 | 
			
		||||
        expect(svginsertpy).toHaveBeenCalledWith(expectedPrefix, ':first-child');
 | 
			
		||||
        expect(titleAttrSpy).toHaveBeenCalledWith('id', `chart-${expectedPrefix}-${givenId}`);
 | 
			
		||||
        expect(titleTextSpy).toHaveBeenNthCalledWith(callNumber, expectedText);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      describe('with a11y title', () => {
 | 
			
		||||
        const a11yTitle = 'a11y title';
 | 
			
		||||
 | 
			
		||||
        describe('with a11y description', () => {
 | 
			
		||||
          const a11yDesc = 'a11y description';
 | 
			
		||||
 | 
			
		||||
          it('should set aria-labelledby to the title id inserted as a child', () => {
 | 
			
		||||
            expectAriaLabelledByItTitleId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
          jsdomIt('should set aria-labelledby to the title id inserted as a child', ({ svg }) => {
 | 
			
		||||
            addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
            expect(svgNode.getAttribute('aria-labelledby')).toBe(`chart-title-${givenId}`);
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          it('should set aria-describedby to the description id inserted as a child', () => {
 | 
			
		||||
            expectAriaDescribedByItDescId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
          });
 | 
			
		||||
          jsdomIt(
 | 
			
		||||
            'should set aria-describedby to the description id inserted as a child',
 | 
			
		||||
            ({ svg }) => {
 | 
			
		||||
              addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
              const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
              expect(svgNode.getAttribute('aria-describedby')).toBe(`chart-desc-${givenId}`);
 | 
			
		||||
            }
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
          it('should insert title tag as the first child with the text set to the accTitle given', () => {
 | 
			
		||||
            a11yTitleTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 2);
 | 
			
		||||
          });
 | 
			
		||||
          jsdomIt(
 | 
			
		||||
            'should insert title tag as the first child with the text set to the accTitle given',
 | 
			
		||||
            ({ svg }) => {
 | 
			
		||||
              addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
              const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
              const titleNode = ensureNodeFromSelector('title', svgNode);
 | 
			
		||||
              expect(titleNode?.innerHTML).toBe(a11yTitle);
 | 
			
		||||
            }
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
          it('should insert desc tag as the 2nd child with the text set to accDescription given', () => {
 | 
			
		||||
            a11yDescTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
 | 
			
		||||
          });
 | 
			
		||||
          jsdomIt(
 | 
			
		||||
            'should insert desc tag as the 2nd child with the text set to accDescription given',
 | 
			
		||||
            ({ svg }) => {
 | 
			
		||||
              addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
              const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
              const descNode = ensureNodeFromSelector('desc', svgNode);
 | 
			
		||||
              expect(descNode?.innerHTML).toBe(a11yDesc);
 | 
			
		||||
            }
 | 
			
		||||
          );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe(`without a11y description`, () => {
 | 
			
		||||
        describe(`without a11y description`, {}, () => {
 | 
			
		||||
          const a11yDesc = undefined;
 | 
			
		||||
 | 
			
		||||
          it('should set aria-labelledby to the title id inserted as a child', () => {
 | 
			
		||||
            expectAriaLabelledByItTitleId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
          jsdomIt('should set aria-labelledby to the title id inserted as a child', ({ svg }) => {
 | 
			
		||||
            addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
            expect(svgNode.getAttribute('aria-labelledby')).toBe(`chart-title-${givenId}`);
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          it('should not set aria-describedby', () => {
 | 
			
		||||
            const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
 | 
			
		||||
            addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-describedby', expect.anything());
 | 
			
		||||
          jsdomIt('should not set aria-describedby', ({ svg }) => {
 | 
			
		||||
            addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
            expect(svgNode.getAttribute('aria-describedby')).toBeNull();
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          it('should insert title tag as the first child with the text set to the accTitle given', () => {
 | 
			
		||||
            a11yTitleTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
 | 
			
		||||
          });
 | 
			
		||||
          jsdomIt(
 | 
			
		||||
            'should insert title tag as the first child with the text set to the accTitle given',
 | 
			
		||||
            ({ svg }) => {
 | 
			
		||||
              addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
              const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
              const titleNode = ensureNodeFromSelector('title', svgNode);
 | 
			
		||||
              expect(titleNode?.innerHTML).toBe(a11yTitle);
 | 
			
		||||
            }
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
          it('should not insert description tag', () => {
 | 
			
		||||
            const fauxTitle: MockedD3 = new MockedD3();
 | 
			
		||||
            const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
 | 
			
		||||
            addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            expect(svginsertpy).not.toHaveBeenCalledWith('desc', ':first-child');
 | 
			
		||||
          jsdomIt('should not insert description tag', ({ svg }) => {
 | 
			
		||||
            addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
            const descNode = svgNode.querySelector('desc');
 | 
			
		||||
            expect(descNode).toBeNull();
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
@@ -158,55 +118,66 @@ describe('accessibility', () => {
 | 
			
		||||
        describe('with a11y description', () => {
 | 
			
		||||
          const a11yDesc = 'a11y description';
 | 
			
		||||
 | 
			
		||||
          it('should not set aria-labelledby', () => {
 | 
			
		||||
            const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
 | 
			
		||||
            addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-labelledby', expect.anything());
 | 
			
		||||
          jsdomIt('should not set aria-labelledby', ({ svg }) => {
 | 
			
		||||
            addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
            expect(svgNode.getAttribute('aria-labelledby')).toBeNull();
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          it('should not insert title tag', () => {
 | 
			
		||||
            const fauxTitle: MockedD3 = new MockedD3();
 | 
			
		||||
            const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
 | 
			
		||||
            addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            expect(svginsertpy).not.toHaveBeenCalledWith('title', ':first-child');
 | 
			
		||||
          jsdomIt('should not insert title tag', ({ svg }) => {
 | 
			
		||||
            addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
            const titleNode = svgNode.querySelector('title');
 | 
			
		||||
            expect(titleNode).toBeNull();
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          it('should set aria-describedby to the description id inserted as a child', () => {
 | 
			
		||||
            expectAriaDescribedByItDescId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
          });
 | 
			
		||||
          jsdomIt(
 | 
			
		||||
            'should set aria-describedby to the description id inserted as a child',
 | 
			
		||||
            ({ svg }) => {
 | 
			
		||||
              addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
              const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
              expect(svgNode.getAttribute('aria-describedby')).toBe(`chart-desc-${givenId}`);
 | 
			
		||||
            }
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
          it('should insert desc tag as the 2nd child with the text set to accDescription given', () => {
 | 
			
		||||
            a11yDescTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
 | 
			
		||||
          });
 | 
			
		||||
          jsdomIt(
 | 
			
		||||
            'should insert desc tag as the 2nd child with the text set to accDescription given',
 | 
			
		||||
            ({ svg }) => {
 | 
			
		||||
              addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
              const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
              const descNode = ensureNodeFromSelector('desc', svgNode);
 | 
			
		||||
              expect(descNode?.innerHTML).toBe(a11yDesc);
 | 
			
		||||
            }
 | 
			
		||||
          );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe('without a11y description', () => {
 | 
			
		||||
          const a11yDesc = undefined;
 | 
			
		||||
 | 
			
		||||
          it('should not set aria-labelledby', () => {
 | 
			
		||||
            const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
 | 
			
		||||
            addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-labelledby', expect.anything());
 | 
			
		||||
          jsdomIt('should not set aria-labelledby', ({ svg }) => {
 | 
			
		||||
            addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
            expect(svgNode.getAttribute('aria-labelledby')).toBeNull();
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          it('should not set aria-describedby', () => {
 | 
			
		||||
            const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
 | 
			
		||||
            addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-describedby', expect.anything());
 | 
			
		||||
          jsdomIt('should not set aria-describedby', ({ svg }) => {
 | 
			
		||||
            addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
            expect(svgNode.getAttribute('aria-describedby')).toBeNull();
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          it('should not insert title tag', () => {
 | 
			
		||||
            const fauxTitle: MockedD3 = new MockedD3();
 | 
			
		||||
            const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
 | 
			
		||||
            addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            expect(svginsertpy).not.toHaveBeenCalledWith('title', ':first-child');
 | 
			
		||||
          jsdomIt('should not insert title tag', ({ svg }) => {
 | 
			
		||||
            addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
            const titleNode = svgNode.querySelector('title');
 | 
			
		||||
            expect(titleNode).toBeNull();
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          it('should not insert  description tag', () => {
 | 
			
		||||
            const fauxDesc: MockedD3 = new MockedD3();
 | 
			
		||||
            const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxDesc);
 | 
			
		||||
            addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            expect(svginsertpy).not.toHaveBeenCalledWith('desc', ':first-child');
 | 
			
		||||
          jsdomIt('should not insert  description tag', ({ svg }) => {
 | 
			
		||||
            addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
 | 
			
		||||
            const svgNode = ensureNodeFromSelector('svg');
 | 
			
		||||
            const descNode = svgNode.querySelector('desc');
 | 
			
		||||
            expect(descNode).toBeNull();
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
 
 | 
			
		||||
@@ -78,5 +78,41 @@ describe('diagram-orchestration', () => {
 | 
			
		||||
      flowchart: 1 "pie" pie: 2 "pie"`)
 | 
			
		||||
      ).toBe('pie');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should detect proper diagram when defaultRenderer is elk for flowchart', () => {
 | 
			
		||||
      expect(
 | 
			
		||||
        detectType('mindmap\n  root\n    Photograph\n      Waterfall', {
 | 
			
		||||
          flowchart: { defaultRenderer: 'elk' },
 | 
			
		||||
        })
 | 
			
		||||
      ).toBe('mindmap');
 | 
			
		||||
      expect(
 | 
			
		||||
        detectType(
 | 
			
		||||
          `
 | 
			
		||||
          classDiagram
 | 
			
		||||
            class Person {
 | 
			
		||||
              +String name
 | 
			
		||||
              -Int id
 | 
			
		||||
              #double age
 | 
			
		||||
              +Text demographicProfile
 | 
			
		||||
            }
 | 
			
		||||
          `,
 | 
			
		||||
          { flowchart: { defaultRenderer: 'elk' } }
 | 
			
		||||
        )
 | 
			
		||||
      ).toBe('class');
 | 
			
		||||
      expect(
 | 
			
		||||
        detectType(
 | 
			
		||||
          `
 | 
			
		||||
          erDiagram
 | 
			
		||||
            p[Photograph] {
 | 
			
		||||
              varchar(12) jobId
 | 
			
		||||
              date dateCreated
 | 
			
		||||
            }
 | 
			
		||||
          `,
 | 
			
		||||
          {
 | 
			
		||||
            flowchart: { defaultRenderer: 'elk' },
 | 
			
		||||
          }
 | 
			
		||||
        )
 | 
			
		||||
      ).toBe('er');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -7,20 +7,21 @@ export const loadRegisteredDiagrams = async () => {
 | 
			
		||||
  // Load all lazy loaded diagrams in parallel
 | 
			
		||||
  const results = await Promise.allSettled(
 | 
			
		||||
    Object.entries(detectors).map(async ([key, { detector, loader }]) => {
 | 
			
		||||
      if (loader) {
 | 
			
		||||
      if (!loader) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      try {
 | 
			
		||||
        getDiagram(key);
 | 
			
		||||
      } catch {
 | 
			
		||||
        try {
 | 
			
		||||
          getDiagram(key);
 | 
			
		||||
        } catch {
 | 
			
		||||
          try {
 | 
			
		||||
            // Register diagram if it is not already registered
 | 
			
		||||
            const { diagram, id } = await loader();
 | 
			
		||||
            registerDiagram(id, diagram, detector);
 | 
			
		||||
          } catch (err) {
 | 
			
		||||
            // Remove failed diagram from detectors
 | 
			
		||||
            log.error(`Failed to load external diagram with key ${key}. Removing from detectors.`);
 | 
			
		||||
            delete detectors[key];
 | 
			
		||||
            throw err;
 | 
			
		||||
          }
 | 
			
		||||
          // Register diagram if it is not already registered
 | 
			
		||||
          const { diagram, id } = await loader();
 | 
			
		||||
          registerDiagram(id, diagram, detector);
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
          // Remove failed diagram from detectors
 | 
			
		||||
          log.error(`Failed to load external diagram with key ${key}. Removing from detectors.`);
 | 
			
		||||
          delete detectors[key];
 | 
			
		||||
          throw err;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/* eslint-disable @typescript-eslint/no-explicit-any */
 | 
			
		||||
import type * as d3 from 'd3';
 | 
			
		||||
import type { SetRequired } from 'type-fest';
 | 
			
		||||
import type { SetOptional, SetRequired } from 'type-fest';
 | 
			
		||||
import type { Diagram } from '../Diagram.js';
 | 
			
		||||
import type { BaseDiagramConfig, MermaidConfig } from '../config.type.js';
 | 
			
		||||
 | 
			
		||||
@@ -91,17 +91,13 @@ export interface DiagramDefinition {
 | 
			
		||||
  ) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DetectorRecord {
 | 
			
		||||
  detector: DiagramDetector;
 | 
			
		||||
  loader?: DiagramLoader;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ExternalDiagramDefinition {
 | 
			
		||||
  id: string;
 | 
			
		||||
  detector: DiagramDetector;
 | 
			
		||||
  loader: DiagramLoader;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type DetectorRecord = SetOptional<Omit<ExternalDiagramDefinition, 'id'>, 'loader'>;
 | 
			
		||||
export type DiagramDetector = (text: string, config?: MermaidConfig) => boolean;
 | 
			
		||||
export type DiagramLoader = () => Promise<{ id: string; diagram: DiagramDefinition }>;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,12 @@
 | 
			
		||||
import { it, describe, expect } from 'vitest';
 | 
			
		||||
import { db } from './architectureDb.js';
 | 
			
		||||
import { parser } from './architectureParser.js';
 | 
			
		||||
 | 
			
		||||
const {
 | 
			
		||||
  clear,
 | 
			
		||||
  getDiagramTitle,
 | 
			
		||||
  getAccTitle,
 | 
			
		||||
  getAccDescription,
 | 
			
		||||
  getServices,
 | 
			
		||||
  getGroups,
 | 
			
		||||
  getEdges,
 | 
			
		||||
  getJunctions,
 | 
			
		||||
} = db;
 | 
			
		||||
 | 
			
		||||
import { ArchitectureDB } from './architectureDb.js';
 | 
			
		||||
describe('architecture diagrams', () => {
 | 
			
		||||
  let db: ArchitectureDB;
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    clear();
 | 
			
		||||
    db = new ArchitectureDB();
 | 
			
		||||
    // @ts-expect-error since type is set to undefined we will have error
 | 
			
		||||
    parser.parser?.yy = db;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('architecture diagram definitions', () => {
 | 
			
		||||
@@ -36,7 +27,7 @@ describe('architecture diagrams', () => {
 | 
			
		||||
    it('should handle title on the first line', async () => {
 | 
			
		||||
      const str = `architecture-beta title Simple Architecture Diagram`;
 | 
			
		||||
      await expect(parser.parse(str)).resolves.not.toThrow();
 | 
			
		||||
      expect(getDiagramTitle()).toBe('Simple Architecture Diagram');
 | 
			
		||||
      expect(db.getDiagramTitle()).toBe('Simple Architecture Diagram');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should handle title on another line', async () => {
 | 
			
		||||
@@ -44,7 +35,7 @@ describe('architecture diagrams', () => {
 | 
			
		||||
            title Simple Architecture Diagram
 | 
			
		||||
            `;
 | 
			
		||||
      await expect(parser.parse(str)).resolves.not.toThrow();
 | 
			
		||||
      expect(getDiagramTitle()).toBe('Simple Architecture Diagram');
 | 
			
		||||
      expect(db.getDiagramTitle()).toBe('Simple Architecture Diagram');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should handle accessibility title and description', async () => {
 | 
			
		||||
@@ -53,8 +44,8 @@ describe('architecture diagrams', () => {
 | 
			
		||||
            accDescr: Accessibility Description
 | 
			
		||||
            `;
 | 
			
		||||
      await expect(parser.parse(str)).resolves.not.toThrow();
 | 
			
		||||
      expect(getAccTitle()).toBe('Accessibility Title');
 | 
			
		||||
      expect(getAccDescription()).toBe('Accessibility Description');
 | 
			
		||||
      expect(db.getAccTitle()).toBe('Accessibility Title');
 | 
			
		||||
      expect(db.getAccDescription()).toBe('Accessibility Description');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should handle multiline accessibility description', async () => {
 | 
			
		||||
@@ -64,7 +55,7 @@ describe('architecture diagrams', () => {
 | 
			
		||||
            }
 | 
			
		||||
            `;
 | 
			
		||||
      await expect(parser.parse(str)).resolves.not.toThrow();
 | 
			
		||||
      expect(getAccDescription()).toBe('Accessibility Description');
 | 
			
		||||
      expect(db.getAccDescription()).toBe('Accessibility Description');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
import { getConfig as commonGetConfig } from '../../config.js';
 | 
			
		||||
import type { ArchitectureDiagramConfig } from '../../config.type.js';
 | 
			
		||||
import DEFAULT_CONFIG from '../../defaultConfig.js';
 | 
			
		||||
import { getConfig as commonGetConfig } from '../../config.js';
 | 
			
		||||
import type { DiagramDB } from '../../diagram-api/types.js';
 | 
			
		||||
import type { D3Element } from '../../types.js';
 | 
			
		||||
import { ImperativeState } from '../../utils/imperativeState.js';
 | 
			
		||||
import { cleanAndMerge } from '../../utils.js';
 | 
			
		||||
import {
 | 
			
		||||
  clear as commonClear,
 | 
			
		||||
  getAccDescription,
 | 
			
		||||
@@ -14,7 +15,6 @@ import {
 | 
			
		||||
} from '../common/commonDb.js';
 | 
			
		||||
import type {
 | 
			
		||||
  ArchitectureAlignment,
 | 
			
		||||
  ArchitectureDB,
 | 
			
		||||
  ArchitectureDirectionPair,
 | 
			
		||||
  ArchitectureDirectionPairMap,
 | 
			
		||||
  ArchitectureEdge,
 | 
			
		||||
@@ -33,330 +33,333 @@ import {
 | 
			
		||||
  isArchitectureService,
 | 
			
		||||
  shiftPositionByArchitectureDirectionPair,
 | 
			
		||||
} from './architectureTypes.js';
 | 
			
		||||
import { cleanAndMerge } from '../../utils.js';
 | 
			
		||||
 | 
			
		||||
const DEFAULT_ARCHITECTURE_CONFIG: Required<ArchitectureDiagramConfig> =
 | 
			
		||||
  DEFAULT_CONFIG.architecture;
 | 
			
		||||
export class ArchitectureDB implements DiagramDB {
 | 
			
		||||
  private nodes: Record<string, ArchitectureNode> = {};
 | 
			
		||||
  private groups: Record<string, ArchitectureGroup> = {};
 | 
			
		||||
  private edges: ArchitectureEdge[] = [];
 | 
			
		||||
  private registeredIds: Record<string, 'node' | 'group'> = {};
 | 
			
		||||
  private dataStructures?: ArchitectureState['dataStructures'];
 | 
			
		||||
  private elements: Record<string, D3Element> = {};
 | 
			
		||||
 | 
			
		||||
const state = new ImperativeState<ArchitectureState>(() => ({
 | 
			
		||||
  nodes: {},
 | 
			
		||||
  groups: {},
 | 
			
		||||
  edges: [],
 | 
			
		||||
  registeredIds: {},
 | 
			
		||||
  config: DEFAULT_ARCHITECTURE_CONFIG,
 | 
			
		||||
  dataStructures: undefined,
 | 
			
		||||
  elements: {},
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
const clear = (): void => {
 | 
			
		||||
  state.reset();
 | 
			
		||||
  commonClear();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const addService = function ({
 | 
			
		||||
  id,
 | 
			
		||||
  icon,
 | 
			
		||||
  in: parent,
 | 
			
		||||
  title,
 | 
			
		||||
  iconText,
 | 
			
		||||
}: Omit<ArchitectureService, 'edges'>) {
 | 
			
		||||
  if (state.records.registeredIds[id] !== undefined) {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      `The service id [${id}] is already in use by another ${state.records.registeredIds[id]}`
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  if (parent !== undefined) {
 | 
			
		||||
    if (id === parent) {
 | 
			
		||||
      throw new Error(`The service [${id}] cannot be placed within itself`);
 | 
			
		||||
    }
 | 
			
		||||
    if (state.records.registeredIds[parent] === undefined) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `The service [${id}]'s parent does not exist. Please make sure the parent is created before this service`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    if (state.records.registeredIds[parent] === 'node') {
 | 
			
		||||
      throw new Error(`The service [${id}]'s parent is not a group`);
 | 
			
		||||
    }
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  state.records.registeredIds[id] = 'node';
 | 
			
		||||
  public clear(): void {
 | 
			
		||||
    this.nodes = {};
 | 
			
		||||
    this.groups = {};
 | 
			
		||||
    this.edges = [];
 | 
			
		||||
    this.registeredIds = {};
 | 
			
		||||
    this.dataStructures = undefined;
 | 
			
		||||
    this.elements = {};
 | 
			
		||||
    commonClear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  state.records.nodes[id] = {
 | 
			
		||||
  public addService({
 | 
			
		||||
    id,
 | 
			
		||||
    type: 'service',
 | 
			
		||||
    icon,
 | 
			
		||||
    in: parent,
 | 
			
		||||
    title,
 | 
			
		||||
    iconText,
 | 
			
		||||
    title,
 | 
			
		||||
    edges: [],
 | 
			
		||||
    in: parent,
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getServices = (): ArchitectureService[] =>
 | 
			
		||||
  Object.values(state.records.nodes).filter<ArchitectureService>(isArchitectureService);
 | 
			
		||||
 | 
			
		||||
const addJunction = function ({ id, in: parent }: Omit<ArchitectureJunction, 'edges'>) {
 | 
			
		||||
  state.records.registeredIds[id] = 'node';
 | 
			
		||||
 | 
			
		||||
  state.records.nodes[id] = {
 | 
			
		||||
    id,
 | 
			
		||||
    type: 'junction',
 | 
			
		||||
    edges: [],
 | 
			
		||||
    in: parent,
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getJunctions = (): ArchitectureJunction[] =>
 | 
			
		||||
  Object.values(state.records.nodes).filter<ArchitectureJunction>(isArchitectureJunction);
 | 
			
		||||
 | 
			
		||||
const getNodes = (): ArchitectureNode[] => Object.values(state.records.nodes);
 | 
			
		||||
 | 
			
		||||
const getNode = (id: string): ArchitectureNode | null => state.records.nodes[id];
 | 
			
		||||
 | 
			
		||||
const addGroup = function ({ id, icon, in: parent, title }: ArchitectureGroup) {
 | 
			
		||||
  if (state.records.registeredIds[id] !== undefined) {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      `The group id [${id}] is already in use by another ${state.records.registeredIds[id]}`
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  if (parent !== undefined) {
 | 
			
		||||
    if (id === parent) {
 | 
			
		||||
      throw new Error(`The group [${id}] cannot be placed within itself`);
 | 
			
		||||
    }
 | 
			
		||||
    if (state.records.registeredIds[parent] === undefined) {
 | 
			
		||||
  }: Omit<ArchitectureService, 'edges'>): void {
 | 
			
		||||
    if (this.registeredIds[id] !== undefined) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `The group [${id}]'s parent does not exist. Please make sure the parent is created before this group`
 | 
			
		||||
        `The service id [${id}] is already in use by another ${this.registeredIds[id]}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    if (state.records.registeredIds[parent] === 'node') {
 | 
			
		||||
      throw new Error(`The group [${id}]'s parent is not a group`);
 | 
			
		||||
    if (parent !== undefined) {
 | 
			
		||||
      if (id === parent) {
 | 
			
		||||
        throw new Error(`The service [${id}] cannot be placed within itself`);
 | 
			
		||||
      }
 | 
			
		||||
      if (this.registeredIds[parent] === undefined) {
 | 
			
		||||
        throw new Error(
 | 
			
		||||
          `The service [${id}]'s parent does not exist. Please make sure the parent is created before this service`
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
      if (this.registeredIds[parent] === 'node') {
 | 
			
		||||
        throw new Error(`The service [${id}]'s parent is not a group`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.registeredIds[id] = 'node';
 | 
			
		||||
 | 
			
		||||
    this.nodes[id] = {
 | 
			
		||||
      id,
 | 
			
		||||
      type: 'service',
 | 
			
		||||
      icon,
 | 
			
		||||
      iconText,
 | 
			
		||||
      title,
 | 
			
		||||
      edges: [],
 | 
			
		||||
      in: parent,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  state.records.registeredIds[id] = 'group';
 | 
			
		||||
 | 
			
		||||
  state.records.groups[id] = {
 | 
			
		||||
    id,
 | 
			
		||||
    icon,
 | 
			
		||||
    title,
 | 
			
		||||
    in: parent,
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
const getGroups = (): ArchitectureGroup[] => {
 | 
			
		||||
  return Object.values(state.records.groups);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const addEdge = function ({
 | 
			
		||||
  lhsId,
 | 
			
		||||
  rhsId,
 | 
			
		||||
  lhsDir,
 | 
			
		||||
  rhsDir,
 | 
			
		||||
  lhsInto,
 | 
			
		||||
  rhsInto,
 | 
			
		||||
  lhsGroup,
 | 
			
		||||
  rhsGroup,
 | 
			
		||||
  title,
 | 
			
		||||
}: ArchitectureEdge<string>) {
 | 
			
		||||
  if (!isArchitectureDirection(lhsDir)) {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      `Invalid direction given for left hand side of edge ${lhsId}--${rhsId}. Expected (L,R,T,B) got ${lhsDir}`
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  if (!isArchitectureDirection(rhsDir)) {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      `Invalid direction given for right hand side of edge ${lhsId}--${rhsId}. Expected (L,R,T,B) got ${rhsDir}`
 | 
			
		||||
    );
 | 
			
		||||
  public getServices(): ArchitectureService[] {
 | 
			
		||||
    return Object.values(this.nodes).filter(isArchitectureService);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (state.records.nodes[lhsId] === undefined && state.records.groups[lhsId] === undefined) {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      `The left-hand id [${lhsId}] does not yet exist. Please create the service/group before declaring an edge to it.`
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  if (state.records.nodes[rhsId] === undefined && state.records.groups[lhsId] === undefined) {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      `The right-hand id [${rhsId}] does not yet exist. Please create the service/group before declaring an edge to it.`
 | 
			
		||||
    );
 | 
			
		||||
  public addJunction({ id, in: parent }: Omit<ArchitectureJunction, 'edges'>): void {
 | 
			
		||||
    this.registeredIds[id] = 'node';
 | 
			
		||||
 | 
			
		||||
    this.nodes[id] = {
 | 
			
		||||
      id,
 | 
			
		||||
      type: 'junction',
 | 
			
		||||
      edges: [],
 | 
			
		||||
      in: parent,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const lhsGroupId = state.records.nodes[lhsId].in;
 | 
			
		||||
  const rhsGroupId = state.records.nodes[rhsId].in;
 | 
			
		||||
  if (lhsGroup && lhsGroupId && rhsGroupId && lhsGroupId == rhsGroupId) {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      `The left-hand id [${lhsId}] is modified to traverse the group boundary, but the edge does not pass through two groups.`
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  if (rhsGroup && lhsGroupId && rhsGroupId && lhsGroupId == rhsGroupId) {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      `The right-hand id [${rhsId}] is modified to traverse the group boundary, but the edge does not pass through two groups.`
 | 
			
		||||
    );
 | 
			
		||||
  public getJunctions(): ArchitectureJunction[] {
 | 
			
		||||
    return Object.values(this.nodes).filter(isArchitectureJunction);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const edge = {
 | 
			
		||||
  public getNodes(): ArchitectureNode[] {
 | 
			
		||||
    return Object.values(this.nodes);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getNode(id: string): ArchitectureNode | null {
 | 
			
		||||
    return this.nodes[id] ?? null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public addGroup({ id, icon, in: parent, title }: ArchitectureGroup): void {
 | 
			
		||||
    if (this.registeredIds?.[id] !== undefined) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `The group id [${id}] is already in use by another ${this.registeredIds[id]}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    if (parent !== undefined) {
 | 
			
		||||
      if (id === parent) {
 | 
			
		||||
        throw new Error(`The group [${id}] cannot be placed within itself`);
 | 
			
		||||
      }
 | 
			
		||||
      if (this.registeredIds?.[parent] === undefined) {
 | 
			
		||||
        throw new Error(
 | 
			
		||||
          `The group [${id}]'s parent does not exist. Please make sure the parent is created before this group`
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
      if (this.registeredIds?.[parent] === 'node') {
 | 
			
		||||
        throw new Error(`The group [${id}]'s parent is not a group`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.registeredIds[id] = 'group';
 | 
			
		||||
 | 
			
		||||
    this.groups[id] = {
 | 
			
		||||
      id,
 | 
			
		||||
      icon,
 | 
			
		||||
      title,
 | 
			
		||||
      in: parent,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
  public getGroups(): ArchitectureGroup[] {
 | 
			
		||||
    return Object.values(this.groups);
 | 
			
		||||
  }
 | 
			
		||||
  public addEdge({
 | 
			
		||||
    lhsId,
 | 
			
		||||
    lhsDir,
 | 
			
		||||
    lhsInto,
 | 
			
		||||
    lhsGroup,
 | 
			
		||||
    rhsId,
 | 
			
		||||
    lhsDir,
 | 
			
		||||
    rhsDir,
 | 
			
		||||
    lhsInto,
 | 
			
		||||
    rhsInto,
 | 
			
		||||
    lhsGroup,
 | 
			
		||||
    rhsGroup,
 | 
			
		||||
    title,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  state.records.edges.push(edge);
 | 
			
		||||
  if (state.records.nodes[lhsId] && state.records.nodes[rhsId]) {
 | 
			
		||||
    state.records.nodes[lhsId].edges.push(state.records.edges[state.records.edges.length - 1]);
 | 
			
		||||
    state.records.nodes[rhsId].edges.push(state.records.edges[state.records.edges.length - 1]);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getEdges = (): ArchitectureEdge[] => state.records.edges;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the current diagram's adjacency list, spatial map, & group alignments.
 | 
			
		||||
 * If they have not been created, run the algorithms to generate them.
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
const getDataStructures = () => {
 | 
			
		||||
  if (state.records.dataStructures === undefined) {
 | 
			
		||||
    // Tracks how groups are aligned with one another. Generated while creating the adj list
 | 
			
		||||
    const groupAlignments: Record<
 | 
			
		||||
      string,
 | 
			
		||||
      Record<string, Exclude<ArchitectureAlignment, 'bend'>>
 | 
			
		||||
    > = {};
 | 
			
		||||
 | 
			
		||||
    // Create an adjacency list of the diagram to perform BFS on
 | 
			
		||||
    // Outer reduce applied on all services
 | 
			
		||||
    // Inner reduce applied on the edges for a service
 | 
			
		||||
    const adjList = Object.entries(state.records.nodes).reduce<
 | 
			
		||||
      Record<string, ArchitectureDirectionPairMap>
 | 
			
		||||
    >((prevOuter, [id, service]) => {
 | 
			
		||||
      prevOuter[id] = service.edges.reduce<ArchitectureDirectionPairMap>((prevInner, edge) => {
 | 
			
		||||
        // track the direction groups connect to one another
 | 
			
		||||
        const lhsGroupId = getNode(edge.lhsId)?.in;
 | 
			
		||||
        const rhsGroupId = getNode(edge.rhsId)?.in;
 | 
			
		||||
        if (lhsGroupId && rhsGroupId && lhsGroupId !== rhsGroupId) {
 | 
			
		||||
          const alignment = getArchitectureDirectionAlignment(edge.lhsDir, edge.rhsDir);
 | 
			
		||||
          if (alignment !== 'bend') {
 | 
			
		||||
            groupAlignments[lhsGroupId] ??= {};
 | 
			
		||||
            groupAlignments[lhsGroupId][rhsGroupId] = alignment;
 | 
			
		||||
            groupAlignments[rhsGroupId] ??= {};
 | 
			
		||||
            groupAlignments[rhsGroupId][lhsGroupId] = alignment;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (edge.lhsId === id) {
 | 
			
		||||
          // source is LHS
 | 
			
		||||
          const pair = getArchitectureDirectionPair(edge.lhsDir, edge.rhsDir);
 | 
			
		||||
          if (pair) {
 | 
			
		||||
            prevInner[pair] = edge.rhsId;
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          // source is RHS
 | 
			
		||||
          const pair = getArchitectureDirectionPair(edge.rhsDir, edge.lhsDir);
 | 
			
		||||
          if (pair) {
 | 
			
		||||
            prevInner[pair] = edge.lhsId;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return prevInner;
 | 
			
		||||
      }, {});
 | 
			
		||||
      return prevOuter;
 | 
			
		||||
    }, {});
 | 
			
		||||
 | 
			
		||||
    // Configuration for the initial pass of BFS
 | 
			
		||||
    const firstId = Object.keys(adjList)[0];
 | 
			
		||||
    const visited = { [firstId]: 1 };
 | 
			
		||||
    // If a key is present in this object, it has not been visited
 | 
			
		||||
    const notVisited = Object.keys(adjList).reduce(
 | 
			
		||||
      (prev, id) => (id === firstId ? prev : { ...prev, [id]: 1 }),
 | 
			
		||||
      {} as Record<string, number>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Perform BFS on the adjacency list
 | 
			
		||||
    const BFS = (startingId: string): ArchitectureSpatialMap => {
 | 
			
		||||
      const spatialMap = { [startingId]: [0, 0] };
 | 
			
		||||
      const queue = [startingId];
 | 
			
		||||
      while (queue.length > 0) {
 | 
			
		||||
        const id = queue.shift();
 | 
			
		||||
        if (id) {
 | 
			
		||||
          visited[id] = 1;
 | 
			
		||||
          delete notVisited[id];
 | 
			
		||||
          const adj = adjList[id];
 | 
			
		||||
          const [posX, posY] = spatialMap[id];
 | 
			
		||||
          Object.entries(adj).forEach(([dir, rhsId]) => {
 | 
			
		||||
            if (!visited[rhsId]) {
 | 
			
		||||
              spatialMap[rhsId] = shiftPositionByArchitectureDirectionPair(
 | 
			
		||||
                [posX, posY],
 | 
			
		||||
                dir as ArchitectureDirectionPair
 | 
			
		||||
              );
 | 
			
		||||
              queue.push(rhsId);
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return spatialMap;
 | 
			
		||||
    };
 | 
			
		||||
    const spatialMaps = [BFS(firstId)];
 | 
			
		||||
 | 
			
		||||
    // If our diagram is disconnected, keep adding additional spatial maps until all disconnected graphs have been found
 | 
			
		||||
    while (Object.keys(notVisited).length > 0) {
 | 
			
		||||
      spatialMaps.push(BFS(Object.keys(notVisited)[0]));
 | 
			
		||||
  }: ArchitectureEdge): void {
 | 
			
		||||
    if (!isArchitectureDirection(lhsDir)) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `Invalid direction given for left hand side of edge ${lhsId}--${rhsId}. Expected (L,R,T,B) got ${String(lhsDir)}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    state.records.dataStructures = {
 | 
			
		||||
      adjList,
 | 
			
		||||
      spatialMaps,
 | 
			
		||||
      groupAlignments,
 | 
			
		||||
    if (!isArchitectureDirection(rhsDir)) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `Invalid direction given for right hand side of edge ${lhsId}--${rhsId}. Expected (L,R,T,B) got ${String(rhsDir)}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.nodes[lhsId] === undefined && this.groups[lhsId] === undefined) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `The left-hand id [${lhsId}] does not yet exist. Please create the service/group before declaring an edge to it.`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    if (this.nodes[rhsId] === undefined && this.groups[rhsId] === undefined) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `The right-hand id [${rhsId}] does not yet exist. Please create the service/group before declaring an edge to it.`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const lhsGroupId = this.nodes[lhsId].in;
 | 
			
		||||
    const rhsGroupId = this.nodes[rhsId].in;
 | 
			
		||||
    if (lhsGroup && lhsGroupId && rhsGroupId && lhsGroupId == rhsGroupId) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `The left-hand id [${lhsId}] is modified to traverse the group boundary, but the edge does not pass through two groups.`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    if (rhsGroup && lhsGroupId && rhsGroupId && lhsGroupId == rhsGroupId) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `The right-hand id [${rhsId}] is modified to traverse the group boundary, but the edge does not pass through two groups.`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const edge = {
 | 
			
		||||
      lhsId,
 | 
			
		||||
      lhsDir,
 | 
			
		||||
      lhsInto,
 | 
			
		||||
      lhsGroup,
 | 
			
		||||
      rhsId,
 | 
			
		||||
      rhsDir,
 | 
			
		||||
      rhsInto,
 | 
			
		||||
      rhsGroup,
 | 
			
		||||
      title,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.edges.push(edge);
 | 
			
		||||
    if (this.nodes[lhsId] && this.nodes[rhsId]) {
 | 
			
		||||
      this.nodes[lhsId].edges.push(this.edges[this.edges.length - 1]);
 | 
			
		||||
      this.nodes[rhsId].edges.push(this.edges[this.edges.length - 1]);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return state.records.dataStructures;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const setElementForId = (id: string, element: D3Element) => {
 | 
			
		||||
  state.records.elements[id] = element;
 | 
			
		||||
};
 | 
			
		||||
const getElementById = (id: string) => state.records.elements[id];
 | 
			
		||||
  public getEdges(): ArchitectureEdge[] {
 | 
			
		||||
    return this.edges;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
const getConfig = (): Required<ArchitectureDiagramConfig> => {
 | 
			
		||||
  const config = cleanAndMerge({
 | 
			
		||||
    ...DEFAULT_ARCHITECTURE_CONFIG,
 | 
			
		||||
    ...commonGetConfig().architecture,
 | 
			
		||||
  });
 | 
			
		||||
  return config;
 | 
			
		||||
};
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the current diagram's adjacency list, spatial map, & group alignments.
 | 
			
		||||
   * If they have not been created, run the algorithms to generate them.
 | 
			
		||||
   * @returns
 | 
			
		||||
   */
 | 
			
		||||
  public getDataStructures() {
 | 
			
		||||
    if (this.dataStructures === undefined) {
 | 
			
		||||
      // Tracks how groups are aligned with one another. Generated while creating the adj list
 | 
			
		||||
      const groupAlignments: Record<
 | 
			
		||||
        string,
 | 
			
		||||
        Record<string, Exclude<ArchitectureAlignment, 'bend'>>
 | 
			
		||||
      > = {};
 | 
			
		||||
 | 
			
		||||
export const db: ArchitectureDB = {
 | 
			
		||||
  clear,
 | 
			
		||||
  setDiagramTitle,
 | 
			
		||||
  getDiagramTitle,
 | 
			
		||||
  setAccTitle,
 | 
			
		||||
  getAccTitle,
 | 
			
		||||
  setAccDescription,
 | 
			
		||||
  getAccDescription,
 | 
			
		||||
  getConfig,
 | 
			
		||||
      // Create an adjacency list of the diagram to perform BFS on
 | 
			
		||||
      // Outer reduce applied on all services
 | 
			
		||||
      // Inner reduce applied on the edges for a service
 | 
			
		||||
      const adjList = Object.entries(this.nodes).reduce<
 | 
			
		||||
        Record<string, ArchitectureDirectionPairMap>
 | 
			
		||||
      >((prevOuter, [id, service]) => {
 | 
			
		||||
        prevOuter[id] = service.edges.reduce<ArchitectureDirectionPairMap>((prevInner, edge) => {
 | 
			
		||||
          // track the direction groups connect to one another
 | 
			
		||||
          const lhsGroupId = this.getNode(edge.lhsId)?.in;
 | 
			
		||||
          const rhsGroupId = this.getNode(edge.rhsId)?.in;
 | 
			
		||||
          if (lhsGroupId && rhsGroupId && lhsGroupId !== rhsGroupId) {
 | 
			
		||||
            const alignment = getArchitectureDirectionAlignment(edge.lhsDir, edge.rhsDir);
 | 
			
		||||
            if (alignment !== 'bend') {
 | 
			
		||||
              groupAlignments[lhsGroupId] ??= {};
 | 
			
		||||
              groupAlignments[lhsGroupId][rhsGroupId] = alignment;
 | 
			
		||||
              groupAlignments[rhsGroupId] ??= {};
 | 
			
		||||
              groupAlignments[rhsGroupId][lhsGroupId] = alignment;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
  addService,
 | 
			
		||||
  getServices,
 | 
			
		||||
  addJunction,
 | 
			
		||||
  getJunctions,
 | 
			
		||||
  getNodes,
 | 
			
		||||
  getNode,
 | 
			
		||||
  addGroup,
 | 
			
		||||
  getGroups,
 | 
			
		||||
  addEdge,
 | 
			
		||||
  getEdges,
 | 
			
		||||
  setElementForId,
 | 
			
		||||
  getElementById,
 | 
			
		||||
  getDataStructures,
 | 
			
		||||
};
 | 
			
		||||
          if (edge.lhsId === id) {
 | 
			
		||||
            // source is LHS
 | 
			
		||||
            const pair = getArchitectureDirectionPair(edge.lhsDir, edge.rhsDir);
 | 
			
		||||
            if (pair) {
 | 
			
		||||
              prevInner[pair] = edge.rhsId;
 | 
			
		||||
            }
 | 
			
		||||
          } else {
 | 
			
		||||
            // source is RHS
 | 
			
		||||
            const pair = getArchitectureDirectionPair(edge.rhsDir, edge.lhsDir);
 | 
			
		||||
            if (pair) {
 | 
			
		||||
              prevInner[pair] = edge.lhsId;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          return prevInner;
 | 
			
		||||
        }, {});
 | 
			
		||||
        return prevOuter;
 | 
			
		||||
      }, {});
 | 
			
		||||
 | 
			
		||||
      // Configuration for the initial pass of BFS
 | 
			
		||||
      const firstId = Object.keys(adjList)[0];
 | 
			
		||||
      const visited = { [firstId]: 1 };
 | 
			
		||||
      // If a key is present in this object, it has not been visited
 | 
			
		||||
      const notVisited = Object.keys(adjList).reduce(
 | 
			
		||||
        (prev, id) => (id === firstId ? prev : { ...prev, [id]: 1 }),
 | 
			
		||||
        {} as Record<string, number>
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Perform BFS on the adjacency list
 | 
			
		||||
      const BFS = (startingId: string): ArchitectureSpatialMap => {
 | 
			
		||||
        const spatialMap = { [startingId]: [0, 0] };
 | 
			
		||||
        const queue = [startingId];
 | 
			
		||||
        while (queue.length > 0) {
 | 
			
		||||
          const id = queue.shift();
 | 
			
		||||
          if (id) {
 | 
			
		||||
            visited[id] = 1;
 | 
			
		||||
            delete notVisited[id];
 | 
			
		||||
            const adj = adjList[id];
 | 
			
		||||
            const [posX, posY] = spatialMap[id];
 | 
			
		||||
            Object.entries(adj).forEach(([dir, rhsId]) => {
 | 
			
		||||
              if (!visited[rhsId]) {
 | 
			
		||||
                spatialMap[rhsId] = shiftPositionByArchitectureDirectionPair(
 | 
			
		||||
                  [posX, posY],
 | 
			
		||||
                  dir as ArchitectureDirectionPair
 | 
			
		||||
                );
 | 
			
		||||
                queue.push(rhsId);
 | 
			
		||||
              }
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return spatialMap;
 | 
			
		||||
      };
 | 
			
		||||
      const spatialMaps = [BFS(firstId)];
 | 
			
		||||
 | 
			
		||||
      // If our diagram is disconnected, keep adding additional spatial maps until all disconnected graphs have been found
 | 
			
		||||
      while (Object.keys(notVisited).length > 0) {
 | 
			
		||||
        spatialMaps.push(BFS(Object.keys(notVisited)[0]));
 | 
			
		||||
      }
 | 
			
		||||
      this.dataStructures = {
 | 
			
		||||
        adjList,
 | 
			
		||||
        spatialMaps,
 | 
			
		||||
        groupAlignments,
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
    return this.dataStructures;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public setElementForId(id: string, element: D3Element): void {
 | 
			
		||||
    this.elements[id] = element;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getElementById(id: string): D3Element {
 | 
			
		||||
    return this.elements[id];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getConfig(): Required<ArchitectureDiagramConfig> {
 | 
			
		||||
    return cleanAndMerge({
 | 
			
		||||
      ...DEFAULT_ARCHITECTURE_CONFIG,
 | 
			
		||||
      ...commonGetConfig().architecture,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getConfigField<T extends keyof ArchitectureDiagramConfig>(
 | 
			
		||||
    field: T
 | 
			
		||||
  ): Required<ArchitectureDiagramConfig>[T] {
 | 
			
		||||
    return this.getConfig()[field];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public setAccTitle = setAccTitle;
 | 
			
		||||
  public getAccTitle = getAccTitle;
 | 
			
		||||
  public setDiagramTitle = setDiagramTitle;
 | 
			
		||||
  public getDiagramTitle = getDiagramTitle;
 | 
			
		||||
  public getAccDescription = getAccDescription;
 | 
			
		||||
  public setAccDescription = setAccDescription;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Typed wrapper for resolving an architecture diagram's config fields. Returns the default value if undefined
 | 
			
		||||
 * @param field - the config field to access
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
export function getConfigField<T extends keyof ArchitectureDiagramConfig>(
 | 
			
		||||
  field: T
 | 
			
		||||
): Required<ArchitectureDiagramConfig>[T] {
 | 
			
		||||
  return getConfig()[field];
 | 
			
		||||
}
 | 
			
		||||
// export function getConfigField<T extends keyof ArchitectureDiagramConfig>(
 | 
			
		||||
//   field: T
 | 
			
		||||
// ): Required<ArchitectureDiagramConfig>[T] {
 | 
			
		||||
//   return db.getConfig()[field];
 | 
			
		||||
// }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,14 @@
 | 
			
		||||
import type { DiagramDefinition } from '../../diagram-api/types.js';
 | 
			
		||||
import { parser } from './architectureParser.js';
 | 
			
		||||
import { db } from './architectureDb.js';
 | 
			
		||||
import { ArchitectureDB } from './architectureDb.js';
 | 
			
		||||
import styles from './architectureStyles.js';
 | 
			
		||||
import { renderer } from './architectureRenderer.js';
 | 
			
		||||
 | 
			
		||||
export const diagram: DiagramDefinition = {
 | 
			
		||||
  parser,
 | 
			
		||||
  db,
 | 
			
		||||
  get db() {
 | 
			
		||||
    return new ArchitectureDB();
 | 
			
		||||
  },
 | 
			
		||||
  renderer,
 | 
			
		||||
  styles,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,33 @@
 | 
			
		||||
import type { Architecture } from '@mermaid-js/parser';
 | 
			
		||||
import { parse } from '@mermaid-js/parser';
 | 
			
		||||
import { log } from '../../logger.js';
 | 
			
		||||
import type { ParserDefinition } from '../../diagram-api/types.js';
 | 
			
		||||
import { log } from '../../logger.js';
 | 
			
		||||
import { populateCommonDb } from '../common/populateCommonDb.js';
 | 
			
		||||
import type { ArchitectureDB } from './architectureTypes.js';
 | 
			
		||||
import { db } from './architectureDb.js';
 | 
			
		||||
import { ArchitectureDB } from './architectureDb.js';
 | 
			
		||||
 | 
			
		||||
const populateDb = (ast: Architecture, db: ArchitectureDB) => {
 | 
			
		||||
  populateCommonDb(ast, db);
 | 
			
		||||
  ast.groups.map(db.addGroup);
 | 
			
		||||
  ast.groups.map((group) => db.addGroup(group));
 | 
			
		||||
  ast.services.map((service) => db.addService({ ...service, type: 'service' }));
 | 
			
		||||
  ast.junctions.map((service) => db.addJunction({ ...service, type: 'junction' }));
 | 
			
		||||
  // @ts-ignore TODO our parser guarantees the type is L/R/T/B and not string. How to change to union type?
 | 
			
		||||
  ast.edges.map(db.addEdge);
 | 
			
		||||
  ast.edges.map((edge) => db.addEdge(edge));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const parser: ParserDefinition = {
 | 
			
		||||
  parser: {
 | 
			
		||||
    // @ts-expect-error - ArchitectureDB is not assignable to DiagramDB
 | 
			
		||||
    yy: undefined,
 | 
			
		||||
  },
 | 
			
		||||
  parse: async (input: string): Promise<void> => {
 | 
			
		||||
    const ast: Architecture = await parse('architecture', input);
 | 
			
		||||
    log.debug(ast);
 | 
			
		||||
    const db = parser.parser?.yy;
 | 
			
		||||
    if (!(db instanceof ArchitectureDB)) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        'parser.parser?.yy was not a ArchitectureDB. This is due to a bug within Mermaid, please report this issue at https://github.com/mermaid-js/mermaid/issues.'
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    populateDb(ast, db);
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
import { registerIconPacks } from '../../rendering-util/icons.js';
 | 
			
		||||
import type { Position } from 'cytoscape';
 | 
			
		||||
import cytoscape from 'cytoscape';
 | 
			
		||||
import type { FcoseLayoutOptions } from 'cytoscape-fcose';
 | 
			
		||||
@@ -7,9 +6,10 @@ import { select } from 'd3';
 | 
			
		||||
import type { DrawDefinition, SVG } from '../../diagram-api/types.js';
 | 
			
		||||
import type { Diagram } from '../../Diagram.js';
 | 
			
		||||
import { log } from '../../logger.js';
 | 
			
		||||
import { registerIconPacks } from '../../rendering-util/icons.js';
 | 
			
		||||
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
 | 
			
		||||
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
 | 
			
		||||
import { getConfigField } from './architectureDb.js';
 | 
			
		||||
import type { ArchitectureDB } from './architectureDb.js';
 | 
			
		||||
import { architectureIcons } from './architectureIcons.js';
 | 
			
		||||
import type {
 | 
			
		||||
  ArchitectureAlignment,
 | 
			
		||||
@@ -22,7 +22,6 @@ import type {
 | 
			
		||||
  NodeSingularData,
 | 
			
		||||
} from './architectureTypes.js';
 | 
			
		||||
import {
 | 
			
		||||
  type ArchitectureDB,
 | 
			
		||||
  type ArchitectureDirection,
 | 
			
		||||
  type ArchitectureEdge,
 | 
			
		||||
  type ArchitectureGroup,
 | 
			
		||||
@@ -44,7 +43,7 @@ registerIconPacks([
 | 
			
		||||
]);
 | 
			
		||||
cytoscape.use(fcose);
 | 
			
		||||
 | 
			
		||||
function addServices(services: ArchitectureService[], cy: cytoscape.Core) {
 | 
			
		||||
function addServices(services: ArchitectureService[], cy: cytoscape.Core, db: ArchitectureDB) {
 | 
			
		||||
  services.forEach((service) => {
 | 
			
		||||
    cy.add({
 | 
			
		||||
      group: 'nodes',
 | 
			
		||||
@@ -54,15 +53,15 @@ function addServices(services: ArchitectureService[], cy: cytoscape.Core) {
 | 
			
		||||
        icon: service.icon,
 | 
			
		||||
        label: service.title,
 | 
			
		||||
        parent: service.in,
 | 
			
		||||
        width: getConfigField('iconSize'),
 | 
			
		||||
        height: getConfigField('iconSize'),
 | 
			
		||||
        width: db.getConfigField('iconSize'),
 | 
			
		||||
        height: db.getConfigField('iconSize'),
 | 
			
		||||
      } as NodeSingularData,
 | 
			
		||||
      classes: 'node-service',
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function addJunctions(junctions: ArchitectureJunction[], cy: cytoscape.Core) {
 | 
			
		||||
function addJunctions(junctions: ArchitectureJunction[], cy: cytoscape.Core, db: ArchitectureDB) {
 | 
			
		||||
  junctions.forEach((junction) => {
 | 
			
		||||
    cy.add({
 | 
			
		||||
      group: 'nodes',
 | 
			
		||||
@@ -70,8 +69,8 @@ function addJunctions(junctions: ArchitectureJunction[], cy: cytoscape.Core) {
 | 
			
		||||
        type: 'junction',
 | 
			
		||||
        id: junction.id,
 | 
			
		||||
        parent: junction.in,
 | 
			
		||||
        width: getConfigField('iconSize'),
 | 
			
		||||
        height: getConfigField('iconSize'),
 | 
			
		||||
        width: db.getConfigField('iconSize'),
 | 
			
		||||
        height: db.getConfigField('iconSize'),
 | 
			
		||||
      } as NodeSingularData,
 | 
			
		||||
      classes: 'node-junction',
 | 
			
		||||
    });
 | 
			
		||||
@@ -257,7 +256,8 @@ function getAlignments(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getRelativeConstraints(
 | 
			
		||||
  spatialMaps: ArchitectureSpatialMap[]
 | 
			
		||||
  spatialMaps: ArchitectureSpatialMap[],
 | 
			
		||||
  db: ArchitectureDB
 | 
			
		||||
): fcose.FcoseRelativePlacementConstraint[] {
 | 
			
		||||
  const relativeConstraints: fcose.FcoseRelativePlacementConstraint[] = [];
 | 
			
		||||
  const posToStr = (pos: number[]) => `${pos[0]},${pos[1]}`;
 | 
			
		||||
@@ -296,7 +296,7 @@ function getRelativeConstraints(
 | 
			
		||||
                [ArchitectureDirectionName[
 | 
			
		||||
                  getOppositeArchitectureDirection(dir as ArchitectureDirection)
 | 
			
		||||
                ]]: currId,
 | 
			
		||||
                gap: 1.5 * getConfigField('iconSize'),
 | 
			
		||||
                gap: 1.5 * db.getConfigField('iconSize'),
 | 
			
		||||
              });
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
@@ -353,7 +353,7 @@ function layoutArchitecture(
 | 
			
		||||
          style: {
 | 
			
		||||
            'text-valign': 'bottom',
 | 
			
		||||
            'text-halign': 'center',
 | 
			
		||||
            'font-size': `${getConfigField('fontSize')}px`,
 | 
			
		||||
            'font-size': `${db.getConfigField('fontSize')}px`,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
@@ -375,23 +375,32 @@ function layoutArchitecture(
 | 
			
		||||
          selector: '.node-group',
 | 
			
		||||
          style: {
 | 
			
		||||
            // @ts-ignore Incorrect library types
 | 
			
		||||
            padding: `${getConfigField('padding')}px`,
 | 
			
		||||
            padding: `${db.getConfigField('padding')}px`,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
      layout: {
 | 
			
		||||
        name: 'grid',
 | 
			
		||||
        boundingBox: {
 | 
			
		||||
          x1: 0,
 | 
			
		||||
          x2: 100,
 | 
			
		||||
          y1: 0,
 | 
			
		||||
          y2: 100,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
    // Remove element after layout
 | 
			
		||||
    renderEl.remove();
 | 
			
		||||
 | 
			
		||||
    addGroups(groups, cy);
 | 
			
		||||
    addServices(services, cy);
 | 
			
		||||
    addJunctions(junctions, cy);
 | 
			
		||||
    addServices(services, cy, db);
 | 
			
		||||
    addJunctions(junctions, cy, db);
 | 
			
		||||
    addEdges(edges, cy);
 | 
			
		||||
    // Use the spatial map to create alignment arrays for fcose
 | 
			
		||||
    const alignmentConstraint = getAlignments(db, spatialMaps, groupAlignments);
 | 
			
		||||
 | 
			
		||||
    // Create the relative constraints for fcose by using an inverse of the spatial map and performing BFS on it
 | 
			
		||||
    const relativePlacementConstraint = getRelativeConstraints(spatialMaps);
 | 
			
		||||
    const relativePlacementConstraint = getRelativeConstraints(spatialMaps, db);
 | 
			
		||||
 | 
			
		||||
    const layout = cy.layout({
 | 
			
		||||
      name: 'fcose',
 | 
			
		||||
@@ -406,7 +415,9 @@ function layoutArchitecture(
 | 
			
		||||
        const { parent: parentA } = nodeData(nodeA);
 | 
			
		||||
        const { parent: parentB } = nodeData(nodeB);
 | 
			
		||||
        const elasticity =
 | 
			
		||||
          parentA === parentB ? 1.5 * getConfigField('iconSize') : 0.5 * getConfigField('iconSize');
 | 
			
		||||
          parentA === parentB
 | 
			
		||||
            ? 1.5 * db.getConfigField('iconSize')
 | 
			
		||||
            : 0.5 * db.getConfigField('iconSize');
 | 
			
		||||
        return elasticity;
 | 
			
		||||
      },
 | 
			
		||||
      edgeElasticity(edge: EdgeSingular) {
 | 
			
		||||
@@ -526,11 +537,11 @@ export const draw: DrawDefinition = async (text, id, _version, diagObj: Diagram)
 | 
			
		||||
 | 
			
		||||
  const cy = await layoutArchitecture(services, junctions, groups, edges, db, ds);
 | 
			
		||||
 | 
			
		||||
  await drawEdges(edgesElem, cy);
 | 
			
		||||
  await drawGroups(groupElem, cy);
 | 
			
		||||
  await drawEdges(edgesElem, cy, db);
 | 
			
		||||
  await drawGroups(groupElem, cy, db);
 | 
			
		||||
  positionNodes(db, cy);
 | 
			
		||||
 | 
			
		||||
  setupGraphViewbox(undefined, svg, getConfigField('padding'), getConfigField('useMaxWidth'));
 | 
			
		||||
  setupGraphViewbox(undefined, svg, db.getConfigField('padding'), db.getConfigField('useMaxWidth'));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const renderer = { draw };
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
import { getIconSVG } from '../../rendering-util/icons.js';
 | 
			
		||||
import type cytoscape from 'cytoscape';
 | 
			
		||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
 | 
			
		||||
import { createText } from '../../rendering-util/createText.js';
 | 
			
		||||
import { getIconSVG } from '../../rendering-util/icons.js';
 | 
			
		||||
import type { D3Element } from '../../types.js';
 | 
			
		||||
import { db, getConfigField } from './architectureDb.js';
 | 
			
		||||
import type { ArchitectureDB } from './architectureDb.js';
 | 
			
		||||
import { architectureIcons } from './architectureIcons.js';
 | 
			
		||||
import {
 | 
			
		||||
  ArchitectureDirectionArrow,
 | 
			
		||||
@@ -16,14 +16,17 @@ import {
 | 
			
		||||
  isArchitectureDirectionY,
 | 
			
		||||
  isArchitecturePairXY,
 | 
			
		||||
  nodeData,
 | 
			
		||||
  type ArchitectureDB,
 | 
			
		||||
  type ArchitectureJunction,
 | 
			
		||||
  type ArchitectureService,
 | 
			
		||||
} from './architectureTypes.js';
 | 
			
		||||
 | 
			
		||||
export const drawEdges = async function (edgesEl: D3Element, cy: cytoscape.Core) {
 | 
			
		||||
  const padding = getConfigField('padding');
 | 
			
		||||
  const iconSize = getConfigField('iconSize');
 | 
			
		||||
export const drawEdges = async function (
 | 
			
		||||
  edgesEl: D3Element,
 | 
			
		||||
  cy: cytoscape.Core,
 | 
			
		||||
  db: ArchitectureDB
 | 
			
		||||
) {
 | 
			
		||||
  const padding = db.getConfigField('padding');
 | 
			
		||||
  const iconSize = db.getConfigField('iconSize');
 | 
			
		||||
  const halfIconSize = iconSize / 2;
 | 
			
		||||
  const arrowSize = iconSize / 6;
 | 
			
		||||
  const halfArrowSize = arrowSize / 2;
 | 
			
		||||
@@ -183,13 +186,17 @@ export const drawEdges = async function (edgesEl: D3Element, cy: cytoscape.Core)
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const drawGroups = async function (groupsEl: D3Element, cy: cytoscape.Core) {
 | 
			
		||||
  const padding = getConfigField('padding');
 | 
			
		||||
export const drawGroups = async function (
 | 
			
		||||
  groupsEl: D3Element,
 | 
			
		||||
  cy: cytoscape.Core,
 | 
			
		||||
  db: ArchitectureDB
 | 
			
		||||
) {
 | 
			
		||||
  const padding = db.getConfigField('padding');
 | 
			
		||||
  const groupIconSize = padding * 0.75;
 | 
			
		||||
 | 
			
		||||
  const fontSize = getConfigField('fontSize');
 | 
			
		||||
  const fontSize = db.getConfigField('fontSize');
 | 
			
		||||
 | 
			
		||||
  const iconSize = getConfigField('iconSize');
 | 
			
		||||
  const iconSize = db.getConfigField('iconSize');
 | 
			
		||||
  const halfIconSize = iconSize / 2;
 | 
			
		||||
 | 
			
		||||
  await Promise.all(
 | 
			
		||||
@@ -266,7 +273,7 @@ export const drawServices = async function (
 | 
			
		||||
): Promise<number> {
 | 
			
		||||
  for (const service of services) {
 | 
			
		||||
    const serviceElem = elem.append('g');
 | 
			
		||||
    const iconSize = getConfigField('iconSize');
 | 
			
		||||
    const iconSize = db.getConfigField('iconSize');
 | 
			
		||||
 | 
			
		||||
    if (service.title) {
 | 
			
		||||
      const textElem = serviceElem.append('g');
 | 
			
		||||
@@ -350,7 +357,7 @@ export const drawJunctions = function (
 | 
			
		||||
) {
 | 
			
		||||
  junctions.forEach((junction) => {
 | 
			
		||||
    const junctionElem = elem.append('g');
 | 
			
		||||
    const iconSize = getConfigField('iconSize');
 | 
			
		||||
    const iconSize = db.getConfigField('iconSize');
 | 
			
		||||
 | 
			
		||||
    const bkgElem = junctionElem.append('g');
 | 
			
		||||
    bkgElem
 | 
			
		||||
 
 | 
			
		||||
@@ -92,7 +92,20 @@ export const setCssClass = function (itemIds: string, cssClassName: string) {
 | 
			
		||||
const populateBlockDatabase = (_blockList: Block[], parent: Block): void => {
 | 
			
		||||
  const blockList = _blockList.flat();
 | 
			
		||||
  const children = [];
 | 
			
		||||
  const columnSettingBlock = blockList.find((b) => b?.type === 'column-setting');
 | 
			
		||||
  const column = columnSettingBlock?.columns ?? -1;
 | 
			
		||||
  for (const block of blockList) {
 | 
			
		||||
    if (
 | 
			
		||||
      typeof column === 'number' &&
 | 
			
		||||
      column > 0 &&
 | 
			
		||||
      block.type !== 'column-setting' &&
 | 
			
		||||
      typeof block.widthInColumns === 'number' &&
 | 
			
		||||
      block.widthInColumns > column
 | 
			
		||||
    ) {
 | 
			
		||||
      log.warn(
 | 
			
		||||
        `Block ${block.id} width ${block.widthInColumns} exceeds configured column width ${column}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    if (block.label) {
 | 
			
		||||
      block.label = sanitizeText(block.label);
 | 
			
		||||
    }
 | 
			
		||||
@@ -287,7 +300,7 @@ const setBlock = (block: Block) => {
 | 
			
		||||
  blockDatabase.set(block.id, block);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getLogger = () => console;
 | 
			
		||||
const getLogger = () => log;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return all of the style classes
 | 
			
		||||
 
 | 
			
		||||
@@ -270,7 +270,12 @@ function layoutBlocks(block: Block, db: BlockDB) {
 | 
			
		||||
      if (child.children) {
 | 
			
		||||
        layoutBlocks(child, db);
 | 
			
		||||
      }
 | 
			
		||||
      columnPos += child?.widthInColumns ?? 1;
 | 
			
		||||
      let columnsFilled = child?.widthInColumns ?? 1;
 | 
			
		||||
      if (columns > 0) {
 | 
			
		||||
        // Make sure overflowing lines do not affect later lines
 | 
			
		||||
        columnsFilled = Math.min(columnsFilled, columns - (columnPos % columns));
 | 
			
		||||
      }
 | 
			
		||||
      columnPos += columnsFilled;
 | 
			
		||||
      log.debug('abc88 columnsPos', child, columnPos);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
// @ts-ignore: jison doesn't export types
 | 
			
		||||
import block from './block.jison';
 | 
			
		||||
import db from '../blockDB.js';
 | 
			
		||||
import { log } from '../../../logger.js';
 | 
			
		||||
 | 
			
		||||
describe('Block diagram', function () {
 | 
			
		||||
  describe('when parsing a block diagram graph it should handle > ', function () {
 | 
			
		||||
@@ -402,6 +403,25 @@ columns 1
 | 
			
		||||
      const B = blocks[0];
 | 
			
		||||
      expect(B.styles).toContain('fill:#f9F');
 | 
			
		||||
    });
 | 
			
		||||
    it('should log a warning when block width exceeds column width', () => {
 | 
			
		||||
      const str = `block-beta
 | 
			
		||||
  columns 1
 | 
			
		||||
  A:1
 | 
			
		||||
  B:2
 | 
			
		||||
  C:3
 | 
			
		||||
  D:4
 | 
			
		||||
  E:3
 | 
			
		||||
  F:2
 | 
			
		||||
  G:1`;
 | 
			
		||||
 | 
			
		||||
      const logWarnSpy = vi.spyOn(log, 'warn').mockImplementation(() => undefined);
 | 
			
		||||
 | 
			
		||||
      block.parse(str);
 | 
			
		||||
 | 
			
		||||
      expect(logWarnSpy).toHaveBeenCalledWith('Block B width 2 exceeds configured column width 1');
 | 
			
		||||
 | 
			
		||||
      logWarnSpy.mockRestore();
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('prototype properties', function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ const detector: DiagramDetector = (txt, config = {}): boolean => {
 | 
			
		||||
    // If diagram explicitly states flowchart-elk
 | 
			
		||||
    /^\s*flowchart-elk/.test(txt) ||
 | 
			
		||||
    // If a flowchart/graph diagram has their default renderer set to elk
 | 
			
		||||
    (/^\s*flowchart|graph/.test(txt) && config?.flowchart?.defaultRenderer === 'elk')
 | 
			
		||||
    (/^\s*(flowchart|graph)/.test(txt) && config?.flowchart?.defaultRenderer === 'elk')
 | 
			
		||||
  ) {
 | 
			
		||||
    config.layout = 'elk';
 | 
			
		||||
    return true;
 | 
			
		||||
 
 | 
			
		||||
@@ -125,4 +125,60 @@ describe('flow db getData', () => {
 | 
			
		||||
    const { edges } = flowDb.getData();
 | 
			
		||||
    expect(edges[0].curve).toBe('basis');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should support modifying interpolate using edge id syntax', () => {
 | 
			
		||||
    flowDb.addVertex('A', { text: 'A', type: 'text' }, undefined, [], [], '', {}, undefined);
 | 
			
		||||
    flowDb.addVertex('B', { text: 'B', type: 'text' }, undefined, [], [], '', {}, undefined);
 | 
			
		||||
    flowDb.addVertex('C', { text: 'C', type: 'text' }, undefined, [], [], '', {}, undefined);
 | 
			
		||||
    flowDb.addVertex('D', { text: 'D', type: 'text' }, undefined, [], [], '', {}, undefined);
 | 
			
		||||
    flowDb.addLink(['A'], ['B'], {});
 | 
			
		||||
    flowDb.addLink(['A'], ['C'], { id: 'e2' });
 | 
			
		||||
    flowDb.addLink(['B'], ['D'], { id: 'e3' });
 | 
			
		||||
    flowDb.addLink(['C'], ['D'], {});
 | 
			
		||||
    flowDb.updateLinkInterpolate(['default'], 'stepBefore');
 | 
			
		||||
    flowDb.updateLinkInterpolate([0], 'basis');
 | 
			
		||||
    flowDb.addVertex(
 | 
			
		||||
      'e2',
 | 
			
		||||
      { text: 'Shouldnt be used', type: 'text' },
 | 
			
		||||
      undefined,
 | 
			
		||||
      [],
 | 
			
		||||
      [],
 | 
			
		||||
      '',
 | 
			
		||||
      {},
 | 
			
		||||
      ' curve: monotoneX '
 | 
			
		||||
    );
 | 
			
		||||
    flowDb.addVertex(
 | 
			
		||||
      'e3',
 | 
			
		||||
      { text: 'Shouldnt be used', type: 'text' },
 | 
			
		||||
      undefined,
 | 
			
		||||
      [],
 | 
			
		||||
      [],
 | 
			
		||||
      '',
 | 
			
		||||
      {},
 | 
			
		||||
      ' curve: catmullRom '
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const { edges } = flowDb.getData();
 | 
			
		||||
    expect(edges[0].curve).toBe('basis');
 | 
			
		||||
    expect(edges[1].curve).toBe('monotoneX');
 | 
			
		||||
    expect(edges[2].curve).toBe('catmullRom');
 | 
			
		||||
    expect(edges[3].curve).toBe('stepBefore');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('flow db direction', () => {
 | 
			
		||||
  let flowDb: FlowDB;
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    flowDb = new FlowDB();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should set direction to TB when TD is set', () => {
 | 
			
		||||
    flowDb.setDirection('TD');
 | 
			
		||||
    expect(flowDb.getDirection()).toBe('TB');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should correctly set direction irrespective of leading spaces', () => {
 | 
			
		||||
    flowDb.setDirection(' TD');
 | 
			
		||||
    expect(flowDb.getDirection()).toBe('TB');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -139,6 +139,9 @@ export class FlowDB implements DiagramDB {
 | 
			
		||||
      if (edgeDoc?.animation !== undefined) {
 | 
			
		||||
        edge.animation = edgeDoc.animation;
 | 
			
		||||
      }
 | 
			
		||||
      if (edgeDoc?.curve !== undefined) {
 | 
			
		||||
        edge.interpolate = edgeDoc.curve;
 | 
			
		||||
      }
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -403,7 +406,8 @@ You have to call mermaid.initialize.`
 | 
			
		||||
   *
 | 
			
		||||
   */
 | 
			
		||||
  public setDirection(dir: string) {
 | 
			
		||||
    this.direction = dir;
 | 
			
		||||
    this.direction = dir.trim();
 | 
			
		||||
 | 
			
		||||
    if (/.*</.exec(this.direction)) {
 | 
			
		||||
      this.direction = 'RL';
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,59 @@ describe('[Lines] when parsing', () => {
 | 
			
		||||
    expect(edges[1].interpolate).toBe('cardinal');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle edge curve properties using edge ID', function () {
 | 
			
		||||
    const res = flow.parser.parse(
 | 
			
		||||
      'graph TD\n' +
 | 
			
		||||
        'A e1@-->B\n' +
 | 
			
		||||
        'A uniqueName@-->C\n' +
 | 
			
		||||
        'e1@{curve: basis}\n' +
 | 
			
		||||
        'uniqueName@{curve: cardinal}'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const vert = flow.parser.yy.getVertices();
 | 
			
		||||
    const edges = flow.parser.yy.getEdges();
 | 
			
		||||
 | 
			
		||||
    expect(edges[0].interpolate).toBe('basis');
 | 
			
		||||
    expect(edges[1].interpolate).toBe('cardinal');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle edge curve properties using edge ID but without overriding default', function () {
 | 
			
		||||
    const res = flow.parser.parse(
 | 
			
		||||
      'graph TD\n' +
 | 
			
		||||
        'A e1@-->B\n' +
 | 
			
		||||
        'A-->C\n' +
 | 
			
		||||
        'linkStyle default interpolate linear\n' +
 | 
			
		||||
        'e1@{curve: stepAfter}'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const vert = flow.parser.yy.getVertices();
 | 
			
		||||
    const edges = flow.parser.yy.getEdges();
 | 
			
		||||
 | 
			
		||||
    expect(edges[0].interpolate).toBe('stepAfter');
 | 
			
		||||
    expect(edges.defaultInterpolate).toBe('linear');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle edge curve properties using edge ID mixed with line interpolation', function () {
 | 
			
		||||
    const res = flow.parser.parse(
 | 
			
		||||
      'graph TD\n' +
 | 
			
		||||
        'A e1@-->B-->D\n' +
 | 
			
		||||
        'A-->C e4@-->D-->E\n' +
 | 
			
		||||
        'linkStyle default interpolate linear\n' +
 | 
			
		||||
        'linkStyle 1 interpolate basis\n' +
 | 
			
		||||
        'e1@{curve: monotoneX}\n' +
 | 
			
		||||
        'e4@{curve: stepBefore}'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const vert = flow.parser.yy.getVertices();
 | 
			
		||||
    const edges = flow.parser.yy.getEdges();
 | 
			
		||||
 | 
			
		||||
    expect(edges[0].interpolate).toBe('monotoneX');
 | 
			
		||||
    expect(edges[1].interpolate).toBe('basis');
 | 
			
		||||
    expect(edges.defaultInterpolate).toBe('linear');
 | 
			
		||||
    expect(edges[3].interpolate).toBe('stepBefore');
 | 
			
		||||
    expect(edges.defaultInterpolate).toBe('linear');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle line interpolation multi-numbered definitions', function () {
 | 
			
		||||
    const res = flow.parser.parse(
 | 
			
		||||
      'graph TD\n' + 'A-->B\n' + 'A-->C\n' + 'linkStyle 0,1 interpolate basis'
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,14 @@
 | 
			
		||||
// @ts-ignore: JISON doesn't support types
 | 
			
		||||
import parser from './parser/mindmap.jison';
 | 
			
		||||
import db from './mindmapDb.js';
 | 
			
		||||
import { MindmapDB } from './mindmapDb.js';
 | 
			
		||||
import renderer from './mindmapRenderer.js';
 | 
			
		||||
import styles from './styles.js';
 | 
			
		||||
import type { DiagramDefinition } from '../../diagram-api/types.js';
 | 
			
		||||
 | 
			
		||||
export const diagram: DiagramDefinition = {
 | 
			
		||||
  db,
 | 
			
		||||
  get db() {
 | 
			
		||||
    return new MindmapDB();
 | 
			
		||||
  },
 | 
			
		||||
  renderer,
 | 
			
		||||
  parser,
 | 
			
		||||
  styles,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
// @ts-expect-error No types available for JISON
 | 
			
		||||
import { parser as mindmap } from './parser/mindmap.jison';
 | 
			
		||||
import mindmapDB from './mindmapDb.js';
 | 
			
		||||
import { MindmapDB } from './mindmapDb.js';
 | 
			
		||||
// Todo fix utils functions for tests
 | 
			
		||||
import { setLogLevel } from '../../diagram-api/diagramAPI.js';
 | 
			
		||||
 | 
			
		||||
describe('when parsing a mindmap ', function () {
 | 
			
		||||
  beforeEach(function () {
 | 
			
		||||
    mindmap.yy = mindmapDB;
 | 
			
		||||
    mindmap.yy = new MindmapDB();
 | 
			
		||||
    mindmap.yy.clear();
 | 
			
		||||
    setLogLevel('trace');
 | 
			
		||||
  });
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user