Compare commits

..

293 Commits

Author SHA1 Message Date
Knut Sveidqvist
7f91ed32bc Adding dev tool for simplified development 2025-12-22 09:28:04 +01:00
Sidharth Vinod
d5bc07dc0c fix: Remove unnecessary changeset 2025-12-19 16:50:52 +05:30
Knut Sveidqvist
80a686be03 Merge pull request #7245 from mermaid-js/canonicals-to-mermaid-ai
setting canonicals to mermaid.ai/open-source
2025-12-19 10:12:44 +00:00
autofix-ci[bot]
d26f2c6043 [autofix.ci] apply automated fixes 2025-12-15 14:42:00 +00:00
Knut Sveidqvist
8ca7a28bf3 Update canonicals in big-trees-walk.md
Set canonicals for Mermaid documentation to mermaid.ai/open-source.
2025-12-15 15:32:33 +01:00
Knut Sveidqvist
6b77c9c4c7 setting canonicals to mermaid.ai/open-source 2025-12-15 15:17:56 +01:00
Shubham P
7b167cf331 Merge pull request #7242 from mermaid-js/renovate/patch-dompurify
fix(deps): update dependency dompurify to ^3.3.1
2025-12-15 11:41:32 +00:00
Shubham P
d435ac6fe1 Merge pull request #7228 from mermaid-js/renovate/peter-evans-create-pull-request-digest
chore(deps): update peter-evans/create-pull-request digest to 0979079
2025-12-15 06:47:12 +00:00
renovate[bot]
ed96d067fc fix(deps): update dependency dompurify to ^3.3.1 2025-12-15 00:42:27 +00:00
renovate[bot]
09c60be450 chore(deps): update peter-evans/create-pull-request digest to 0979079 2025-12-10 10:49:20 +00:00
Sidharth Vinod
39d070fdea Merge pull request #7215 from mermaid-js/update-timings
Update E2E Timings
2025-12-04 13:42:51 +05:30
github-actions[bot]
4f6f627e75 chore: update E2E timings 2025-12-04 04:17:52 +00:00
Sidharth Vinod
53570ee815 Merge pull request #7204 from leandroebner/patch-1
Add HackMD integration to community integrations list
2025-12-03 09:58:48 +00:00
Shubham P
a3a5040d79 Merge pull request #7206 from mermaid-js/renovate/patch-all-patch
fix(deps): update all patch dependencies (patch)
2025-12-02 08:57:58 +00:00
renovate[bot]
7ff9bf1a50 fix(deps): update all patch dependencies 2025-12-02 07:42:41 +00:00
Shubham P
ffd38716d0 Merge pull request #7208 from mermaid-js/renovate/npm-express-vulnerability
chore(deps): update dependency express to v5.2.0 [security]
2025-12-02 07:28:21 +00:00
Shubham P
4313f233d2 Merge pull request #7205 from mermaid-js/renovate/patch-eslint
chore(deps): update dependency @cspell/eslint-plugin to ^9.3.2
2025-12-02 07:27:24 +00:00
renovate[bot]
56564f3807 chore(deps): update dependency express to v5.2.0 [security] 2025-12-01 20:55:04 +00:00
renovate[bot]
7e1a1de5e9 chore(deps): update dependency @cspell/eslint-plugin to ^9.3.2 2025-12-01 02:27:03 +00:00
autofix-ci[bot]
b4b90417cf [autofix.ci] apply automated fixes 2025-11-30 19:33:42 +00:00
Leandro Ebner
6bf2b2108c Add HackMD integration to community integrations list
Works natively, see hackmd docs.
2025-11-30 20:22:15 +01:00
Shubham P
614129ca31 Merge pull request #7197 from mermaid-js/fix/5496-gantt-tickinterval-app-crash
5496 : fixed UI crash from excessive tick generation with invalid dates/intervals
2025-11-27 17:09:07 +00:00
omkarht
b115ad3cd7 fix: remove fallback to new Date() for non-timestamp formats in date validation
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-27 21:54:04 +05:30
omkarht
73b8626ab0 fix: enhance Gantt chart handling for invalid date formats and tick intervals
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-27 20:42:59 +05:30
omkarht
88e8ad6f5b fix: improve error handling for invalid date formats in Gantt chart
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-27 19:17:37 +05:30
omkarht
ac5fdb8121 Merge branch 'develop' into fix/5496-gantt-tickinterval-app-crash 2025-11-27 15:16:30 +05:30
Shubham P
a30b3bb3f8 Merge pull request #7178 from mermaid-js/fix/7167-treemap-stroke-border-removal
7167 : fix classDef style application for treemap diagramtype
2025-11-27 08:47:18 +00:00
omkarht
87c561615e fix: extend dayjs with duration plugin for improved time calculations
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-27 13:28:21 +05:30
omkarht
0843a2fa7a fix: optimize tick interval calculation using dayjs for improved accuracy
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-27 12:38:30 +05:30
omkarht
1aa4cd9847 Merge branch 'develop' into fix/7167-treemap-stroke-border-removal 2025-11-27 12:23:27 +05:30
omkarht
8d1cdc41c2 test: enhance treemap tests with classDef styling scenarios
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-27 12:22:54 +05:30
omkarht
bf50ce5237 fix: handle uncaught exceptions in Gantt chart rendering test for invalid dates
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-26 18:59:18 +05:30
omkarht
8bfd47758a chore: add changeset
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-26 17:30:00 +05:30
omkarht
88fd141276 fix: correct Gantt diagram dateFormat syntax in test case
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-26 15:46:59 +05:30
omkarht
454238867b chore: add tests for handling invalid and non-standard date formats in ganttDb
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-26 13:55:00 +05:30
omkarht
6025ec663c 5496 : fixed UI crash from excessive tick generation with invalid dates/intervals
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-26 13:39:22 +05:30
Alois Klink
2346801c30 Merge pull request #7188 from kimulaco/docs/7187_fix-radar-diagram-example
docs: Remove trailing comma from radar diagram example
2025-11-25 08:21:28 +00:00
Shubham P
d7eb94dc89 Merge pull request #7172 from mermaid-js/docs/correct-block-arrow-example
docs(block): correct block arrow example
2025-11-25 06:57:41 +00:00
Shubham P
db9c683316 Merge pull request #7192 from mermaid-js/renovate/patch-all-patch
chore(deps): update all patch dependencies (patch)
2025-11-24 08:09:55 +00:00
Shubham P
c9b5c5fed6 Merge pull request #7191 from mermaid-js/renovate/peter-evans-create-pull-request-digest
chore(deps): update peter-evans/create-pull-request digest to 84ae59a
2025-11-24 08:09:28 +00:00
renovate[bot]
324cf05afd chore(deps): update all patch dependencies 2025-11-24 00:50:00 +00:00
renovate[bot]
a357c1079f chore(deps): update peter-evans/create-pull-request digest to 84ae59a 2025-11-24 00:49:13 +00:00
kimulaco
e20b079707 docs(radar): remove trailing commas 2025-11-22 18:44:44 +09:00
Shubham P
b1fe4ffe97 Merge pull request #7136 from mermaid-js/feat/sequence-alias-support-new-participant-syntax
feat : add alias support for new participant syntax
2025-11-20 07:46:34 +00:00
Shubham P
61c18b99a0 Merge pull request #7164 from mermaid-js/renovate/patch-all-patch
chore(deps): update all patch dependencies (patch)
2025-11-20 07:20:51 +00:00
Shubham P
04ac594f5b Merge pull request #7163 from mermaid-js/renovate/peter-evans-create-pull-request-digest
chore(deps): update peter-evans/create-pull-request digest to b4733b9
2025-11-20 07:20:35 +00:00
Shubham P
a6c2b1d85e Merge pull request #7161 from mermaid-js/renovate/npm-js-yaml-vulnerability
chore(deps): update dependency js-yaml to v4.1.1 [security]
2025-11-20 07:20:25 +00:00
omkarht
96ca7c090f chore : add changeset for classDef style application
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-20 12:43:56 +05:30
renovate[bot]
3c752421a2 chore(deps): update all patch dependencies 2025-11-19 17:03:12 +00:00
omkarht
bf7c532e43 7167 : fix classDef style application for treemap diagramtype
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-19 19:46:35 +05:30
omkarht
8add133bbe Merge branch 'develop' into feat/sequence-alias-support-new-participant-syntax 2025-11-19 15:10:45 +05:30
omkarht
8cf0d3373d docs: add documentation for alias support in sequence diagram participant syntax
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-19 15:10:04 +05:30
renovate[bot]
ff3b194925 chore(deps): update dependency js-yaml to v4.1.1 [security] 2025-11-18 17:47:01 +00:00
autofix-ci[bot]
6e869ff8dc [autofix.ci] apply automated fixes 2025-11-18 08:41:51 +00:00
Alois Klink
9df18da01c docs(block): correct block arrow example
The same ID meant we were overriding the previous arrow.

Co-authored-by: jonathanpoelen <1436727+jonathanpoelen@users.noreply.github.com>
Fixes: https://github.com/mermaid-js/mermaid/issues/7159
Fixes: a0d328d734
2025-11-18 17:34:36 +09:00
renovate[bot]
608d623641 chore(deps): update peter-evans/create-pull-request digest to b4733b9 2025-11-17 01:33:08 +00:00
Sidharth Vinod
ecf9ea1134 Merge pull request #7099 from mermaid-js/fix/mindmap-level-node-rendering
7000: Fix mindmap rendering issue when Level 2 nodes exceed 11
2025-11-14 12:21:56 +00:00
autofix-ci[bot]
b33ce14932 [autofix.ci] apply automated fixes 2025-11-14 06:55:46 +00:00
omkarht
283aef54e4 Merge branch 'develop' into feat/sequence-alias-support-new-participant-syntax 2025-11-14 12:16:07 +05:30
omkarht
96f87fd597 feat: add inline alias attribute support for participants and actors in sequence diagrams
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-14 12:15:03 +05:30
darshanr0107
03e8589818 chore: add visual test
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-14 11:14:21 +05:30
Shubham P
6b9f26dac8 Merge pull request #7080 from mermaid-js/7079-c4context-componentqueue-ext-lexical-error
7079: add missing support for ComponentQueue_Ext in C4Context diagrams
2025-11-11 04:07:06 +00:00
Shubham P
ea590cdafe Merge pull request #7075 from mermaid-js/6889-fix-escaped-p-tags-in-sandbox-mode
6889: Fix escaped <p> tags in labels when securityLevel is set to "sandbox"
2025-11-11 04:05:37 +00:00
Shubham P
f3769c70bc Merge branch 'develop' into 7079-c4context-componentqueue-ext-lexical-error 2025-11-11 09:24:14 +05:30
Shubham P
4cf4d15197 Merge branch 'develop' into 6889-fix-escaped-p-tags-in-sandbox-mode 2025-11-11 09:23:23 +05:30
Shubham P
c02cf92656 Merge pull request #7149 from mermaid-js/renovate/patch-dompurify
fix(deps): update dependency dompurify to ^3.3.0
2025-11-10 10:15:31 +00:00
Shubham P
3a1266892d Merge pull request #7148 from mermaid-js/renovate/patch-all-patch
fix(deps): update all patch dependencies (patch)
2025-11-10 10:15:16 +00:00
renovate[bot]
67e81de557 fix(deps): update dependency dompurify to ^3.3.0 2025-11-10 02:54:45 +00:00
renovate[bot]
847b3aa24e fix(deps): update all patch dependencies 2025-11-10 02:54:19 +00:00
Sidharth Vinod
85a13da40f Merge pull request #7138 from mermaid-js/update-timings
Update E2E Timings
2025-11-07 21:42:11 +09:00
darshanr0107
9ec0e8f932 Merge branch 'develop' of https://github.com/mermaid-js/mermaid into 6889-fix-escaped-p-tags-in-sandbox-mode 2025-11-07 11:58:38 +05:30
darshanr0107
9585ee7533 chore:add e2e test
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-07 11:46:41 +05:30
github-actions[bot]
1269486124 chore: update E2E timings 2025-11-07 04:15:01 +00:00
Shubham P
f45ea0c60e Merge pull request #7096 from mermaid-js/renovate/npm-vite-vulnerability
chore(deps): update dependency vite to v7.1.11 [security]
2025-11-06 14:52:25 +00:00
renovate[bot]
d20955a56a chore(deps): update dependency vite to v7.1.11 [security] 2025-11-06 12:46:25 +00:00
Shubham P
fb66b3fbe3 Merge pull request #7049 from mermaid-js/renovate/major-eslint
chore(deps): update eslint (major)
2025-11-06 12:31:47 +00:00
Shubham P
82ea5d63bb Merge pull request #7017 from mermaid-js/renovate/peter-evans-create-pull-request-digest
chore(deps): update peter-evans/create-pull-request digest to 0edc001
2025-11-06 12:30:09 +00:00
renovate[bot]
881e74087a chore(deps): update eslint 2025-11-06 12:06:45 +00:00
renovate[bot]
09920c0497 chore(deps): update peter-evans/create-pull-request digest to 0edc001 2025-11-06 12:05:55 +00:00
Shubham P
8065d65cd7 Merge pull request #6973 from mermaid-js/renovate/patch-dompurify
fix(deps): update dependency dompurify to ^3.2.7
2025-11-06 11:52:40 +00:00
omkarht
6bc6617ca6 chore: add changeset 2025-11-06 17:09:42 +05:30
omkarht
29ed57ffec test: add tests for participant new syntax aliases in sequence diagrams 2025-11-06 16:59:46 +05:30
omkarht
9fdc4b8005 feat : add alias support for new participant syntax
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-06 16:49:09 +05:30
renovate[bot]
09b841f781 fix(deps): update dependency dompurify to ^3.2.7 2025-11-06 10:46:44 +00:00
Shubham P
d0f9dc0c9b Merge pull request #7018 from mermaid-js/renovate/patch-all-patch
fix(deps): update all patch dependencies (patch)
2025-11-06 10:28:10 +00:00
renovate[bot]
15e2824d53 fix(deps): update all patch dependencies 2025-11-06 10:04:11 +00:00
Shubham P
7eb582e860 Merge pull request #7135 from mermaid-js/fix/er-numeric-entity-test-conflict
refactor: update test description for standalone numeric entities in ER diagram
2025-11-06 09:51:04 +00:00
omkarht
6ca928f31f refactor: update test description for standalone numeric entities in ER diagram 2025-11-06 15:05:58 +05:30
darshanr0107
983120d945 fix: add test case for C4Context diagram with ComponentQueue_Ext
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-05 17:18:34 +05:30
darshanr0107
61f74ffc5e fix: incorrect section number logic by using index % (MAX_SECTIONS - 1)
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-05 14:54:51 +05:30
darshanr0107
74318f9337 chore: use MAX_SECTIONS constant instead of hardcoded value
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-11-05 14:28:59 +05:30
Sidharth Vinod
dfd59470dc Merge pull request #7129 from mermaid-js/sidv/injectVersion
feat: Optimize bundling to remove shipping package.json inside mermaid's JS bundle.
2025-11-04 18:42:32 +00:00
Sidharth Vinod
4aac6fa448 Merge pull request #7128 from CNOCTAVE/develop
add doc to use marmaid.js in GNU Octave
2025-11-04 17:42:28 +00:00
CNOCTAVE
5f96f80efb Merge branch 'develop' of https://github.com/CNOCTAVE/mermaid into develop 2025-11-05 01:16:47 +08:00
CNOCTAVE
545801e144 Update integrations-community.md 2025-11-05 01:16:17 +08:00
CNOCTAVE
0bd74759cc Merge branch 'develop' into develop 2025-11-05 01:13:00 +08:00
CNOCTAVE
e4cf266c1d remove changeset
remove changeset
2025-11-05 01:12:15 +08:00
CNOCTAVE
c0e1662e50 Update packages/mermaid/src/docs/ecosystem/integrations-community.md
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2025-11-05 01:08:04 +08:00
Sidharth Vinod
6546aed482 chore: forbid use of viewbox in code 2025-11-05 00:07:30 +07:00
Sidharth Vinod
b76ccae065 feat: Optimize bundling to remove shipping package.json inside mermaid's JS bundle.
Move all build time injected variables to `injected.` namespace to avoid conflicts.
2025-11-04 23:49:54 +07:00
Sidharth Vinod
287a9a3fcb chore: Add missing clean scripts
Co-authored-by: Alois Klink <alois@aloisklink.com>
2025-11-04 21:21:58 +07:00
Sidharth Vinod
7f5160fa4d chore: Remove NPM_TOKEN from release workflow 2025-11-04 21:12:10 +07:00
autofix-ci[bot]
7b0763f262 [autofix.ci] apply automated fixes 2025-11-04 12:43:03 +00:00
CNOCTAVE
38c289818c feat: add doc to use marmaid.js in GNU Octave
feat: add doc to use marmaid.js in GNU Octave. Resolve #7073
2025-11-04 20:34:13 +08:00
CNOCTAVE
57530076aa add doc to use marmaid.js in GNU Octave
add doc to use marmaid.js in GNU Octave. Resolve #7073
2025-11-04 20:29:53 +08:00
CNOCTAVE
f2d7877c7a Merge branch 'develop' of https://github.com/CNOCTAVE/mermaid into develop 2025-11-04 20:20:28 +08:00
Sidharth Vinod
62d2c6505e Merge pull request #7109 from arnaudrenaud/add-speccharts
docs: Add speccharts to `integrations-community.md`
2025-11-04 11:57:01 +00:00
autofix-ci[bot]
974236bbb8 [autofix.ci] apply automated fixes 2025-11-04 11:48:23 +00:00
Sidharth Vinod
cf0d1248a4 chore: Add speccharts to cspell 2025-11-04 18:42:42 +07:00
Alois Klink
ebefbd87a8 Merge pull request #7127 from mermaid-js/sidharthv96-patch-2
Refactor GitHub Actions workflow for lockfile validation
2025-11-04 07:43:17 +00:00
Sidharth Vinod
1e7b71a085 Refactor GitHub Actions workflow for lockfile validation
Removed Node.js setup step and pnpm action version.

Co-authored-by: Alois Klink <alois@mermaidchart.com>
2025-11-03 23:30:27 -08:00
Sidharth Vinod
f28f3c25aa Merge pull request #7116 from mermaid-js/sidv/lockfileValidation
fix: Lockfile validation
2025-10-30 02:29:50 +09:00
Sidharth Vinod
58137aa631 feat: Allow validation workflow to run on forks 2025-10-30 01:56:18 +09:00
Sidharth Vinod
e7719f14c5 fix: Prevent duplicate comments by validation workflow 2025-10-30 01:55:58 +09:00
Sidharth Vinod
35d9cead8a chore: Cleanup lockfile 2025-10-30 01:22:17 +09:00
Ashish Jain
13baf51b35 Merge 11.12.1 back to develop 2025-10-28 11:23:19 +01:00
Justin Greywolf
9af985ba9b Merge pull request #5814 from kairi003/feature/4706_allow_notes_in_namespace
feat: allow to put notes in namespaces on classDiagram
2025-10-27 19:21:00 +00:00
Arnaud Renaud
c7f8a11ded Add speccharts to integrations-community.md 2025-10-27 14:16:35 +01:00
Sidharth Vinod
762b44cf33 Merge pull request #7108 from mermaid-js/changeset-release/master
Version Packages
2025-10-27 18:35:34 +05:30
github-actions[bot]
02c0091106 Version Packages 2025-10-27 12:08:22 +00:00
Sidharth Vinod
16359adc33 Merge pull request #7107 from mermaid-js/patch/dagre-d3-es-7.0.13
fix: update dagre-d3-es to version 7.0.13
2025-10-27 17:35:36 +05:30
Shubham P
061632c580 Update .changeset/slick-wasps-bathe.md
Co-authored-by: Alois Klink <alois@mermaidchart.com>
2025-10-27 16:20:24 +05:30
shubhamparikh2704
cbf89462ac fix: update dagre-d3-es to version 7.0.13 2025-10-27 15:06:24 +05:30
kairi003
700aa100f2 fix: style broken caused by a mistake in merge 3f46c94a 2025-10-26 04:18:19 +09:00
kairi003
49103ea654 fix: update ClassDB and ClassTypes for improved type safety and consistency 2025-10-26 03:01:00 +09:00
kairi003
3f46c94ab2 Merge branch 'develop' into tmp/feature/4706_allow_notes_in_namespace 2025-10-26 02:39:38 +09:00
darshanr0107
b136acdc67 chore:add changeset
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-10-22 17:53:48 +05:30
darshanr0107
bba5e5938e fix: mindmap rendering issue when level nodes exceed 11
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-10-22 17:06:21 +05:30
Knut Sveidqvist
fed8a523a4 Merge pull request #7076 from mermaid-js/6919-fix-incorrect-viewBox-casing
6919: correct viewBox casing in Radar & Packet
2025-10-21 12:20:04 +00:00
Knut Sveidqvist
33b4946e21 Merge branch 'develop' into 6919-fix-incorrect-viewBox-casing 2025-10-21 10:33:21 +02:00
Justin Greywolf
3d768f3adf Merge pull request #6975 from ilovelinux/fix/6974-ilovelinux-fix-classdiagram-example
Fix classDiagram example
2025-10-17 02:56:34 +00:00
darshanr0107
76e17ffd20 fix: add validation to ensure correct casing of 'viewBox' in all rendering tests
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-10-15 18:56:49 +05:30
darshanr0107
835de0012d fix:ComponentQueue_Ext throws lexical error
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-10-14 19:00:17 +05:30
darshanr0107
60f633101c chore: added changeset
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-10-13 19:14:22 +05:30
Shubham P
18f51eb14e Merge pull request #6843 from saurabhg772244/saurabh/fix-edge-animation-for-hand-dranw-shapes
Fixed edge animation for hand drawn shapes
2025-10-13 13:14:24 +00:00
Shubham P
2bb57bf7d2 Merge pull request #6989 from mermaid-js/subgraph-td-direction
6338: allow direction TD inside subgraphs
2025-10-13 13:13:46 +00:00
Shubham P
a6276daffd Merge pull request #7055 from mermaid-js/sequence-diagram-participant-name-parsing
6853:  prevent browser freeze caused by invalid participant name in sequenceDiagram
2025-10-13 13:12:08 +00:00
darshanr0107
7def6eecbf fix: correct viewBox casing in radar and packet diagram
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-10-13 18:15:38 +05:30
darshanr0107
96a766dcdb chore: added changeset
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-10-13 13:42:41 +05:30
darshanr0107
39d7ebd32e fix: escaped p tags in sandbox mode
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-10-13 13:16:58 +05:30
CNOCTAVE
34f40f0794 add doc to use marmaid.js in GNU Octave 2025-10-13 15:11:44 +08:00
CNOCTAVE
32ac2c689d add doc to use marmaid.js in GNU Octave 2025-10-13 15:02:46 +08:00
CNOCTAVE
dbcadc1d0b add doc to use marmaid.js in GNU Octave 2025-10-13 13:56:04 +08:00
Antonio Spadaro
ac411a7d7e Fix class diagram example 2025-10-11 22:56:37 +02:00
Justin Greywolf
d80a638e55 Merge pull request #6023 from yari-dewalt/fix_lollipop_stroke
Fix: Delete 'stroke: black' from lollipop marker so it matches themes and edge paths
2025-10-11 20:43:08 +00:00
Justin Greywolf
7a869c08a2 Merge pull request #6026 from yari-dewalt/bug/5669_class-diagram-fix-namespace-themes
Fix: Class diagram namespaces black lines, not responding to theme variables
2025-10-11 20:42:53 +00:00
Justin Greywolf
44e8cbb1de Merge branch 'develop' into bug/5669_class-diagram-fix-namespace-themes 2025-10-11 13:27:47 -07:00
Justin Greywolf
efe38b8425 Merge branch 'develop' into fix_lollipop_stroke 2025-10-11 13:26:59 -07:00
darshanr0107
6fecb985e8 fix: failing argos
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-10-09 11:50:44 +05:30
darshanr0107
69b338d8af fix: formatting issues
Co-authored-by: omkarht <omkar@mermaidchart.com>
2025-10-09 11:37:05 +05:30
darshanr0107
fa15ce8502 chore: added changeset
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-10-08 13:23:28 +05:30
darshanr0107
6d0650918f fix: handle participant names with spaces correctly in sequenceDiagram
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-10-08 13:09:30 +05:30
Shubham P
c728d864c8 Merge pull request #7054 from mermaid-js/fix/update-argos-ci-version
fix: update @argos-ci/cypress to version 6.1.3
2025-10-07 08:34:58 +00:00
shubhamparikh2704
99f17bea3a fix: update @argos-ci/cypress to version 6.1.3 2025-10-07 13:39:28 +05:30
Sidharth Vinod
ad82448084 Merge pull request #7053 from mermaid-js/changeset-release/master
Version Packages
2025-10-07 13:23:31 +05:30
github-actions[bot]
9498619d3c Version Packages 2025-10-07 07:36:05 +00:00
Sidharth Vinod
7a8557a1a2 Merge pull request #7036 from mermaid-js/knsv-patch-1
Update free plan diagram limit from 3 to 6
2025-10-07 13:03:39 +05:30
Sidharth Vinod
74863c94fb Merge pull request #7051 from mermaid-js/patch-parser-release
Pre Release
2025-10-07 12:34:22 +05:30
shubhamparikh2704
63df702146 chore: added changeset file 2025-10-07 10:47:16 +05:30
autofix-ci[bot]
421f8d4633 [autofix.ci] apply automated fixes 2025-10-03 07:41:08 +00:00
Knut Sveidqvist
bf6e1a594c Update free plan diagram limit from 3 to 6 2025-10-03 09:35:21 +02:00
Ashish Jain
c1c14e401a Merge pull request #7019 from mermaid-js/tmp-mindmap-elk
mindmap breaking issue in ELK layout
2025-09-30 09:02:40 +00:00
darshanr0107
8b3057f27c fix: guard nodeDb[node.id] against undefined
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-09-30 12:27:53 +05:30
Shubham P
717d3b3bb2 Merge pull request #6984 from mermaid-js/fix/er-diagram-syntax-error-special-chars
fix(er-diagram): handle syntax errors for special characters in node names
2025-09-29 08:37:03 +00:00
Shubham P
2f8d9ba958 Merge pull request #6789 from mermaid-js/6638-sequence-diagram-additional-messages
6638:sequence diagram additional messages
2025-09-29 08:08:33 +00:00
darshanr0107
ace0367afd chore: add changeset
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-09-29 13:37:10 +05:30
Knut Sveidqvist
b983626587 Fix for reference issue affecting mindmaps 2025-09-26 15:24:20 +02:00
Shubham P
7effdc147b Merge pull request #6997 from mermaid-js/ci/enable-codeql-for-github-actions
ci(codeql): enable CodeQL for GitHub Actions
2025-09-25 08:47:48 +00:00
Alois Klink
6e67515f41 ci(codeql): enable CodeQL for GitHub Actions
Support for scanning GitHub Actions was added in 2024-12-17, see
https://github.blog/changelog/2024-12-17-find-and-fix-actions-workflows-vulnerabilities-with-codeql-public-preview/
2025-09-25 17:17:12 +09:00
darshanr0107
1a9d45abf0 fix: allow direction TD inside subgraphs
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-09-24 12:22:31 +05:30
omkarht
09b74f1c29 chore: added changeset
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-09-23 13:39:45 +05:30
omkarht
880da21908 test: add tests for handling special characters and numeric entity names
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-09-23 13:29:19 +05:30
omkarht
38191243be Merge branch 'develop' into fix/er-diagram-syntax-error-special-chars 2025-09-23 12:41:42 +05:30
omkarht
b75dcb8a82 Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-09-23 12:40:39 +05:30
omkarht
4c1e170f4a fix(er-diagram): handle syntax errors for special characters in node names 2025-09-23 12:39:29 +05:30
Shubham P
d5c4eff251 Merge pull request #6972 from mermaid-js/renovate/patch-all-patch
fix(deps): update all patch dependencies (patch)
2025-09-22 13:49:30 +00:00
renovate[bot]
5324fd8dfd fix(deps): update all patch dependencies 2025-09-22 13:35:45 +00:00
omkarht
bd25b88a01 Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-09-22 13:36:01 +05:30
Sidharth Vinod
0116b272b4 Merge pull request #6961 from mermaid-js/changeset-release/master
Version Packages
2025-09-18 10:50:42 +05:30
github-actions[bot]
634f3367da Version Packages 2025-09-17 17:48:06 +00:00
Sidharth Vinod
37e3a6951b Merge pull request #6956 from mermaid-js/develop
Pre Release
2025-09-17 23:15:32 +05:30
Sidharth Vinod
0de0b063e4 Merge pull request #6958 from dijitali/fix/arch-icon-docs
fix(docs) correct phrasing for architecture icon installation
2025-09-17 23:06:48 +05:30
Shubham P
619515e5a9 Merge pull request #6925 from mermaid-js/renovate/patch-all-patch
fix(deps): update all patch dependencies (patch)
2025-09-17 14:16:47 +00:00
shubhamparikh2704
59c8b07509 Merge branch 'develop' of https://github.com/mermaid-js/mermaid into renovate/patch-all-patch 2025-09-17 19:34:56 +05:30
Sidharth Vinod
9e72bbf62d Merge pull request #6955 from mermaid-js/sidv/updateArgos
chore: Update argos to 6.1.0
2025-09-17 18:48:40 +05:30
Sidharth Vinod
2a2c46f1e2 chore: Update argos to 6.1.1 2025-09-17 18:14:03 +05:30
Shubham P
f25df353d4 Merge pull request #6959 from mermaid-js/remove-changeset
chore: remove duplicate changeset file
2025-09-17 10:50:09 +00:00
shubhamparikh2704
398345a8bc chore: remove duplicate changeset file 2025-09-17 16:07:45 +05:30
autofix-ci[bot]
7fd2d94ef7 [autofix.ci] apply automated fixes 2025-09-17 08:47:15 +00:00
Ieuan Jenkins
bcc1472b9d fix(docs) correct phrasing for architecture icon installation
docs gave the incorrect impression that iconify.design icons came preinstalled
2025-09-17 09:21:42 +01:00
shubhamparikh2704
ddc1cfe6c8 Revert "fix: downgrade @argos-ci/cypress to version 5.0.2"
This reverts commit 18e9c1174d.
2025-09-17 13:07:43 +05:30
omkarht
d3de3ecbbb Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-09-17 12:41:51 +05:30
shubhamparikh2704
18e9c1174d fix: downgrade @argos-ci/cypress to version 5.0.2 2025-09-17 12:14:29 +05:30
Sidharth Vinod
789018abf6 chore: Update argos to 6.1.0 2025-09-17 11:38:57 +05:30
Shubham P
16569b295b Merge pull request #6942 from mermaid-js/renovate/peter-evans-create-pull-request-digest
chore(deps): update peter-evans/create-pull-request digest to 915d841
2025-09-16 17:28:34 +00:00
renovate[bot]
11a35c11ee chore(deps): update peter-evans/create-pull-request digest to 915d841 2025-09-16 16:02:14 +00:00
Shubham P
216be22801 Merge pull request #6945 from mermaid-js/fix/gantt-crash-obsidian-browser
6920: Fix Gantt chart crashes in Obsidian and browser
2025-09-16 15:49:49 +00:00
Ashish Jain
e87f77a865 Merge pull request #6950 from mermaid-js/patch/mindmap-fix
Pre Release
2025-09-16 12:48:55 +02:00
shubhamparikh2704
a9579083bf chore: add changeset for fixing mindmap rendering and applying tidytree layout 2025-09-16 13:33:31 +05:30
Knut Sveidqvist
6fd78d0856 Merge pull request #6944 from mermaid-js/docs/fix-mindmap-rendering
6932:Fix mindmap rendering in docs and apply tidytree layout
2025-09-16 13:27:23 +05:30
Sidharth Vinod
994f7df29a Merge pull request #6949 from tklever/examples-license
docs: add MIT license to `examples` metadata
2025-09-16 12:40:40 +05:30
Sidharth Vinod
531f5e9380 Merge pull request #6948 from mermaid-js/add-newest-blog-posts
DOCS: add newest blog posts
2025-09-16 11:45:06 +05:30
Tim Klever
dc11b8645c docs: add MIT license to examples metadata
Adding the MIT license documentation so the published package metadata accurately reflects the license. The MIT license is currently included in the package distribution https://www.npmjs.com/package/@mermaid-js/examples?activeTab=code, but not documented in the metadata. This causes npmjs.com to display the license as "none"
2025-09-15 17:35:44 -07:00
Steph
ad4c227477 add newest blog posts 2025-09-15 13:24:39 -07:00
omkarht
3964ce0a0f Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-09-15 18:15:59 +05:30
Shubham P
181af8167b Merge pull request #6934 from fulldecent/patch-2
Specify score range for task syntax
2025-09-15 09:18:39 +00:00
Shubham P
799d2ed547 Merge branch 'develop' into patch-2 2025-09-15 14:38:57 +05:30
shubhamparikh2704
a44e3e992c refactor: remove unused dependencies from pnpm-lock.yaml 2025-09-15 14:37:50 +05:30
shubhamparikh2704
ca5b370ffb Merge branch 'develop' of https://github.com/mermaid-js/mermaid into renovate/patch-all-patch 2025-09-15 14:32:02 +05:30
Shubham P
08160a74b4 Merge pull request #6931 from mermaid-js/renovate/npm-vite-vulnerability
chore(deps): update dependency vite to v7.0.7 [security]
2025-09-15 08:22:27 +00:00
Knut Sveidqvist
6d221fb3ca Merge pull request #6944 from mermaid-js/docs/fix-mindmap-rendering
6932:Fix mindmap rendering in docs and apply tidytree layout
2025-09-15 08:06:41 +00:00
Shubham P
8b20907141 Merge branch 'develop' into renovate/npm-vite-vulnerability 2025-09-15 13:13:40 +05:30
omkarht
4dbabba8e8 Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-09-15 12:50:11 +05:30
darshanr0107
d318f1a13c chore: add changeset
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-09-15 12:42:25 +05:30
darshanr0107
525a7de8ae fix:gant chart crashing in browser
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-09-15 12:42:24 +05:30
darshanr0107
a459c436c9 docs: fix rendering and ensure tidytree layout is applied
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-09-15 12:00:46 +05:30
Saurabh Gore
bbb93b263d Merge branch 'develop' into saurabh/fix-edge-animation-for-hand-dranw-shapes 2025-09-13 11:37:21 +05:30
Sidharth Vinod
1c2a0020bd Merge pull request #6939 from aloisklink/build/fix-netlify-mermaid-live-preview
build: change mermaid live preview to use pnpm
2025-09-12 21:18:29 +05:30
Alois Klink
141c6b3808 build: change mermaid live preview to use pnpm
Right now, the netlify build seems to be failing since we're ignoring
the `mermaid-live-editor` lockfile.

This is causing errors with broken dependencies.

Switching to `pnpm`, which the `mermaid-live-editor` uses, fixes these
issues!
2025-09-13 00:35:29 +09:00
renovate[bot]
8d4ffdf808 chore(deps): update dependency vite to v7.0.7 [security] 2025-09-12 20:14:12 +09:00
Alois Klink
32106e259c build(docs): set build.target = 'modules'
Explicility set the `build.target` to `modules`, as Vite v7 changes this
and drops support for older browsers.

We probably should do this eventually too, but maybe as part of a
Mermaid v12 release.
2025-09-12 20:14:12 +09:00
Sidharth Vinod
450754221e Merge pull request #6930 from mermaid-js/rajat-ht/chore-editor-selection-update
Chore: Simplify editor selection to single version
2025-09-11 19:57:08 +05:30
rajat-ht
7a4f5b62c9 chore: update variable name 2025-09-11 19:54:14 +05:30
omkarht
e3ef5e4208 fix: fixed central connection for bidirectional dotted arrow
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-09-11 13:03:06 +05:30
omkarht
daeb85bac2 Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-09-11 12:40:55 +05:30
saurabhg772244
4240340a18 Merge branch 'develop' of github.com:mermaid-js/mermaid into saurabh/fix-edge-animation-for-hand-dranw-shapes 2025-09-11 11:36:26 +05:30
autofix-ci[bot]
47c0d2d040 [autofix.ci] apply automated fixes 2025-09-10 18:00:00 +00:00
William Entriken
ac3b777bf6 Specify score range for task syntax 2025-09-10 13:54:31 -04:00
Shubham P
cf08ba0ef8 Merge branch 'develop' into renovate/patch-all-patch 2025-09-10 21:03:45 +05:30
rajat-ht
4829dfa8c5 Chore: Simplify editor selection to single version 2025-09-09 22:16:52 +05:30
autofix-ci[bot]
e7811886c3 [autofix.ci] apply automated fixes 2025-09-08 01:00:25 +00:00
renovate[bot]
32eda8565c fix(deps): update all patch dependencies 2025-09-08 00:54:41 +00:00
omkarht
ca10a259fa Merge branch 'develop' into saurabh/fix-edge-animation-for-hand-dranw-shapes 2025-09-05 16:28:39 +05:30
Saurabh Gore
0ed9c65572 Merge branch 'develop' into saurabh/fix-edge-animation-for-hand-dranw-shapes 2025-09-05 12:56:27 +05:30
saurabhg772244
56cc12690f Added option to skip screenshot for cypress tests 2025-09-05 12:47:07 +05:30
omkarht
2cdaf03ada Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-09-05 12:12:01 +05:30
Sidharth Vinod
9c85521e16 Merge pull request #6914 from mermaid-js/changeset-release/master
Version Packages
2025-09-04 20:36:52 +05:30
github-actions[bot]
8a565bce92 Version Packages 2025-09-04 14:12:57 +00:00
Sidharth Vinod
baf510b935 Merge pull request #6912 from mermaid-js/develop
Pre Release
2025-09-04 19:39:17 +05:30
omkarht
f6fa0260e7 Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-09-04 12:56:49 +05:30
omkarht
29aad6d23c Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-09-04 12:12:03 +05:30
omkarht
82ef7b5fdb docs: add version placeholders for new features 2025-09-02 19:02:02 +05:30
omkarht
11cd3f1262 feat: add central connection rendering and parsing tests 2025-09-02 18:52:18 +05:30
omkarht
ac4aa94e78 Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-09-02 15:13:07 +05:30
omkarht
c40faac80d Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-08-29 13:26:48 +05:30
omkarht
c530baed3f Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-08-28 13:07:57 +05:30
omkarht
045699de10 Merge branch 'develop' of https://github.com/mermaid-js/mermaid into 6638-sequence-diagram-additional-messages 2025-08-25 15:14:50 +05:30
omkarht
1988d24227 fix: fixed reverse arrows placing for autonumber
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-08-22 16:46:49 +05:30
omkarht
39f90debe7 Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-08-22 13:03:01 +05:30
omkarht
73e9849f99 chore: added changeset
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-08-21 16:12:25 +05:30
omkarht
5a05540a5f Merge branch 'develop' of https://github.com/mermaid-js/mermaid into 6638-sequence-diagram-additional-messages 2025-08-21 16:09:18 +05:30
omkarht
2b58df9665 fix: refactored documentation
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-08-19 14:53:08 +05:30
saurabhg772244
e6fb4a84da code refactor 2025-08-11 16:32:03 +05:30
saurabhg772244
32723b2de1 Added change set 2025-08-11 15:59:07 +05:30
saurabhg772244
18703782ee Fixed edge animation for hand drawn shapes 2025-08-11 15:52:49 +05:30
omkarht
0b42bdba07 Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-08-11 15:28:48 +05:30
omkarht
74c96db3e2 docs: document new syntax for half-arrow message and central connection
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-08-07 12:47:31 +05:30
omkarht
bd47c57eaf chore: refactored code
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-08-06 18:56:58 +05:30
omkarht
3e5d2db514 Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-08-06 18:56:18 +05:30
omkarht
40990bb096 Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-07-29 18:17:34 +05:30
omkarht
7ca0665764 fix: fixed failing test case
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-07-28 19:13:51 +05:30
omkarht
81a6a361ab Merge branch 'develop' into 6638-sequence-diagram-additional-messages 2025-07-28 16:51:38 +05:30
omkarht
62faacdeeb fix: fixed failing test cases
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-07-28 16:01:43 +05:30
omkarht
0e40d8e8a8 fix: fixed failing test cases
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-07-28 15:55:07 +05:30
omkarht
e8d6daf4f6 add support for central connection circle after arrow in lifeline direction
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-07-28 15:37:33 +05:30
omkarht
cb4ed605b2 chore: added rendering test cases for arrow head type
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-07-23 16:59:04 +05:30
omkarht
ba9db26bfa Lexing : Added Support for new arrow types through lexing
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-07-22 19:25:27 +05:30
omkarht
252b1837f7 added arrowhead types for dotted line type
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-07-22 19:20:06 +05:30
omkarht
6b9c15d7f0 added reverse arrow head types
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-07-22 16:30:21 +05:30
omkarht
fda640c90c fix: adjusted arrowhead design
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-07-21 19:03:29 +05:30
omkarht
584a789183 6638: add support for additional message types for sequence diagram
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-07-21 13:33:52 +05:30
autofix-ci[bot]
47297f7c26 [autofix.ci] apply automated fixes 2025-02-26 17:49:51 +00:00
Yari DeWalt
967aa0629e Merge branch 'develop' into bug/5669_class-diagram-fix-namespace-themes 2025-02-26 09:45:14 -08:00
Yari DeWalt
04b20a79b9 Merge branch 'develop' into fix_lollipop_stroke 2025-02-26 09:20:16 -08:00
kairi
d60b09cafc Merge branch 'develop' into feature/4706_allow_notes_in_namespace 2024-12-01 09:20:39 +09:00
kairi003
875827f59b Merge branch 'develop' into feature/4706_allow_notes_in_namespace 2024-11-21 07:16:47 +09:00
kairi003
c4e08261b5 Merge branch 'develop' into feature/4706_allow_notes_in_namespace 2024-11-10 23:56:48 +09:00
kairi003
70f679d2fa add: e2e test for classDiagram-v3 2024-11-10 20:27:35 +09:00
kairi003
25c43fa439 add: horizontal rules to demos/classchart.html 2024-11-10 02:34:31 +09:00
kairi003
ec1c6325d4 refactor: Add type annotations and optimize redundant set loop 2024-11-10 02:34:31 +09:00
kairi003
309ff6be38 fix: Reimplement notes in namespaces for classRenderer-v3 (#5880) 2024-11-10 02:32:20 +09:00
kairi003
02d368df05 chore: relax git version constraint in Dockerfile to allow patch updates 2024-11-10 01:58:29 +09:00
kairi003
4ee1fe2ca4 Merge branch 'master' into feature/4706_allow_notes_in_namespace 2024-11-10 01:52:46 +09:00
yari-dewalt
4ff2ae9f4e Add styles for clusters and remove hard-coded styling for namespace nodes 2024-11-06 09:00:21 -08:00
Yari DeWalt
7a729e8f16 Merge branch 'develop' into fix_lollipop_stroke 2024-11-04 10:21:00 -08:00
yari-dewalt
3c7fd95617 Remove black stroke from lollipops so it matches edge paths 2024-11-04 10:15:51 -08:00
kairi003
2dd29bee25 add changelogs 2024-09-08 02:13:33 +09:00
kairi003
259a508d8a add e2e test 2024-09-08 01:31:26 +09:00
kairi
1963064369 Merge branch 'develop' into feature/4706_allow_notes_in_namespace 2024-09-08 00:27:14 +09:00
kairi
a101ce803c Merge branch 'develop' into feature/4706_allow_notes_in_namespace 2024-09-04 14:14:19 +09:00
kairi003
fc0c7936d1 feat: Add support for adding notes to namespaces in class diagrams 2024-09-03 15:27:31 +09:00
kairi003
2d2add5b44 Change: use Map for notes 2024-09-03 15:22:59 +09:00
kairi003
58fd5ddbaf Add: demo for notes in namespace on classDialog 2024-09-03 15:22:41 +09:00
246 changed files with 12109 additions and 14466 deletions

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix: Prevent HTML tags from being escaped in sandbox label rendering

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix: Support edge animation in hand drawn look

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix: Resolved parsing error where direction TD was not recognized within subgraphs

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix(treemap): Fixed treemap classDef style application to properly apply user-defined styles

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix: Correct viewBox casing and make SVGs responsive

View File

@@ -1,5 +0,0 @@
---
'mermaid': patch
---
fix: Render newlines as spaces in class diagrams

View File

@@ -1,5 +0,0 @@
---
'mermaid': patch
---
fix: Handle arrows correctly when auto number is enabled

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix: Improve participant parsing and prevent recursive loops on invalid syntax

View File

@@ -1,5 +0,0 @@
---
'mermaid': minor
---
Add IDs in architecture diagrams

View File

@@ -1,5 +0,0 @@
---
'mermaid': patch
---
fix: Ensure edge label color is applied when using classDef with edge IDs

View File

@@ -1,5 +0,0 @@
---
'mermaid': minor
---
feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.

View File

@@ -1,7 +0,0 @@
---
'mermaid': minor
'@mermaid-js/layout-tidy-tree': minor
'@mermaid-js/layout-elk': minor
---
feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
feat: add alias support for new participant syntax of sequence diagrams

View File

@@ -0,0 +1,5 @@
---
'mermaid': minor
---
feat: Add half-arrowheads (solid & stick) and central connection support

View File

@@ -1,5 +0,0 @@
---
'mermaid': minor
---
feat: Add IDs in architecture diagrams

View File

@@ -1,9 +0,0 @@
---
'mermaid': patch
---
chore: revert marked dependency from ^15.0.7 to ^16.0.0
- Reverted marked package version to ^16.0.0 for better compatibility
- This is a dependency update that maintains API compatibility
- All tests pass with the updated version

View File

@@ -0,0 +1,5 @@
---
'mermaid': minor
---
feat: allow to put notes in namespaces on classDiagram

View File

@@ -0,0 +1,5 @@
---
'@mermaid': patch
---
fix: Mindmap breaking in ELK layout

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix(er-diagram): prevent syntax error when using 'u', numbers, and decimals in node names

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix: Support ComponentQueue_Ext to prevent parsing error

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix: validate dates and tick interval to prevent UI freeze/crash in gantt diagramtype

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix: Mindmap rendering issue when the number of Level 2 nodes exceeds 11

View File

@@ -1,3 +1,5 @@
!viewbox
# It should be viewBox
# This file contains coding related terms
ALPHANUM
antiscript

View File

@@ -64,6 +64,7 @@ rscratch
shiki
Slidev
sparkline
speccharts
sphinxcontrib
ssim
stylis

View File

@@ -0,0 +1,53 @@
# Dev Explorer frontend: architecture + debugging notes
## Root cause of the “CSS changes do nothing” problem
The page loads `/dev/styles.css`, but **document-level CSS does not apply through a shadow DOM boundary**.
Historically, `dev-explorer-app` was a `LitElement` using Lits default `shadowRoot`, while the rest of the UI used light DOM. That meant:
- The browser showed the _right classes_ (`card`, `card-folder`, `card-file`) in Elements panel.
- `/dev/styles.css` was clearly being served/updated.
- Yet computed styles for `.card` looked like UA defaults because the selector never matched across the shadow root.
Fix: make `dev-explorer-app` light DOM too (`createRenderRoot() { return this; }`), so `/dev/styles.css` reliably styles the whole UI.
## Debugging traps (and fast detection)
- **Shadow DOM trap**
- Symptom: “CSS is loaded but doesnt apply”, especially for simple class selectors.
- Fast check:
- DevTools console: `document.querySelector('dev-explorer-app')?.shadowRoot`
- If non-null, global CSS wont style inside it.
- Or: right-click an element you expect styled → “Reveal in Elements” → see if its under `#shadow-root`.
- **“Light DOM child inside shadow DOM parent” trap**
- Even if a child component uses `createRenderRoot() { return this; }`,
if its _rendered inside the parents shadow root_, its still effectively in shadow for document styles.
- **Dev loop trap (CSS-only changes dont trigger reload)**
- The server watches TypeScript bundle inputs + `.mmd` files; static `/dev/styles.css` previously didnt emit SSE reload events.
- That makes CSS changes look flaky unless you manually refresh.
- Fix: watch `.esbuild/dev-explorer/public/**/*` and emit SSE on changes.
- **Caching trap (less common here, but real)**
- If a query param is constant (`?v=3`) and you dont reload, the browser can keep a cached stylesheet.
- Fast check: DevTools → Network → disable cache + hard reload; or check “(from disk cache)” on the CSS request.
## Styling strategy recommendation (pragmatic)
For a dev-only explorer, keep it simple:
- **Light DOM everywhere**
- **One stylesheet**: `.esbuild/dev-explorer/public/styles.css` served as `/dev/styles.css`
- **Scoped selectors** under `dev-explorer-app` to avoid generic class collisions (`.header`, `.content`, etc.)
If you later _want_ Shadow DOM isolation, do it deliberately:
- Put UI styles in Lit `static styles` or adopt a `CSSStyleSheet` into `this.renderRoot.adoptedStyleSheets`.
- Avoid relying on document CSS selectors for component internals.
## Shoelace integration notes
- Current setup is correct for dev: `setBasePath('/dev/vendor/shoelace')` and `registerIconLibrary(...)`.
- Prefer theming via CSS variables (Shoelace tokens) rather than overriding internal parts everywhere.

View File

@@ -0,0 +1,187 @@
import { LitElement, html } from 'lit';
import '@shoelace-style/shoelace/dist/components/input/input.js';
export type LogLevel = 'info' | 'warn' | 'error';
export type LogEntry = {
ts: number;
level: LogLevel;
message: string;
};
function formatTs(ts: number) {
const d = new Date(ts);
return (
d.toLocaleTimeString(undefined, { hour12: false }) +
'.' +
String(d.getMilliseconds()).padStart(3, '0')
);
}
function levelVariant(level: LogLevel) {
switch (level) {
case 'error':
return 'danger';
case 'warn':
return 'warning';
default:
return 'neutral';
}
}
type DisplayLevel = 'debug' | LogLevel;
function displayLevel(entry: LogEntry): DisplayLevel {
// Mermaid often emits debug lines through console.log/info with a marker.
if (entry.message.includes(': DEBUG :')) return 'debug';
return entry.level;
}
function displayVariant(level: DisplayLevel) {
switch (level) {
case 'error':
return 'danger';
case 'warn':
return 'warning';
case 'debug':
return 'success';
default:
return 'neutral';
}
}
export class DevConsolePanel extends LitElement {
static properties = {
logs: { state: true },
showInfo: { state: true },
showWarn: { state: true },
showError: { state: true },
showDebug: { state: true },
filterText: { state: true },
};
declare logs: LogEntry[];
declare showInfo: boolean;
declare showWarn: boolean;
declare showError: boolean;
declare showDebug: boolean;
declare filterText: string;
constructor() {
super();
this.logs = [];
this.showInfo = true;
this.showWarn = true;
this.showError = true;
this.showDebug = true;
this.filterText = '';
}
createRenderRoot() {
return this;
}
clear() {
this.logs = [];
}
append(entry: LogEntry) {
this.logs = [...this.logs, entry];
}
async copyVisible() {
const visible = this.filteredLogs();
const text = visible
.map((l) => `[${formatTs(l.ts)}] ${l.level.toUpperCase()} ${l.message}`)
.join('\n');
await navigator.clipboard.writeText(text);
}
filteredLogs() {
const q = this.filterText.trim().toLowerCase();
return this.logs.filter((l) => {
const isDebugLine = l.message.includes(': DEBUG :');
// Treat debug-marked lines as their own independent toggle, since Mermaid often routes them through
// console.log/info with a marker rather than a distinct "debug" level.
if (isDebugLine && !this.showDebug) return false;
if (!isDebugLine) {
const levelOk =
l.level === 'info' ? this.showInfo : l.level === 'warn' ? this.showWarn : this.showError;
if (!levelOk) return false;
}
if (!q) return true;
return l.message.toLowerCase().includes(q);
});
}
render() {
const visible = this.filteredLogs();
return html`
<div class="console">
<div class="console-toolbar">
<div class="spacer"></div>
<sl-input
size="small"
placeholder="filter…"
clearable
value=${this.filterText}
@sl-input=${(e: any) => (this.filterText = e.target.value ?? '')}
></sl-input>
<sl-checkbox
size="small"
?checked=${this.showDebug}
@sl-change=${(e: any) => (this.showDebug = e.target.checked)}
>debug</sl-checkbox
>
<sl-checkbox
size="small"
?checked=${this.showInfo}
@sl-change=${(e: any) => (this.showInfo = e.target.checked)}
>info</sl-checkbox
>
<sl-checkbox
size="small"
?checked=${this.showWarn}
@sl-change=${(e: any) => (this.showWarn = e.target.checked)}
>warn</sl-checkbox
>
<sl-checkbox
size="small"
?checked=${this.showError}
@sl-change=${(e: any) => (this.showError = e.target.checked)}
>error</sl-checkbox
>
<sl-button size="small" variant="default" @click=${() => void this.copyVisible()}>
<sl-icon slot="prefix" name="clipboard"></sl-icon>
Copy
</sl-button>
<sl-button size="small" variant="default" @click=${() => this.clear()}>
<sl-icon slot="prefix" name="trash"></sl-icon>
Clear
</sl-button>
</div>
<div class="console-body">
${visible.length === 0
? html`<div class="empty">No logs yet.</div>`
: visible.map((l) => {
const lvl = displayLevel(l);
return html`
<div class="logline">
<div class="logmeta">
<sl-badge variant=${displayVariant(lvl)}>${lvl}</sl-badge>
<span class="path">${formatTs(l.ts)}</span>
</div>
<div>${l.message}</div>
</div>
`;
})}
</div>
</div>
`;
}
}
customElements.define('dev-console-panel', DevConsolePanel);

View File

@@ -0,0 +1,551 @@
import { LitElement, html, nothing } from 'lit';
import '@shoelace-style/shoelace/dist/components/button/button.js';
import '@shoelace-style/shoelace/dist/components/icon/icon.js';
import '@shoelace-style/shoelace/dist/components/select/select.js';
import '@shoelace-style/shoelace/dist/components/option/option.js';
import '@shoelace-style/shoelace/dist/components/checkbox/checkbox.js';
import '@shoelace-style/shoelace/dist/components/split-panel/split-panel.js';
import './console-panel';
import type { LogEntry, LogLevel } from './console-panel';
type MermaidIife = {
initialize: (config: Record<string, unknown>) => void | Promise<void>;
render: (
id: string,
text: string,
container?: Element
) => Promise<{ svg: string; bindFunctions?: (el: Element) => void }>;
};
declare global {
interface Window {
mermaid?: MermaidIife;
mermaidReady?: Promise<MermaidIife>;
}
}
function stringifyArgs(args: unknown[]) {
// Mermaid's internal logger frequently uses console formatting like:
// console.log('%c...message...', 'color: lightgreen', ...)
// For the log panel we want the human text, not the formatting tokens/styles.
let normalized = [...args];
if (typeof normalized[0] === 'string') {
const fmt = normalized[0];
const cssCount = (fmt.match(/%c/g) ?? []).length;
if (cssCount > 0) {
normalized[0] = fmt.replaceAll('%c', '');
// Drop the corresponding CSS args that follow the format string.
normalized.splice(1, cssCount);
}
}
return normalized
.map((a) => {
if (typeof a === 'string') return a;
if (a instanceof Error) return a.stack ?? a.message;
try {
return JSON.stringify(a);
} catch {
return String(a);
}
})
.join(' ')
.replace(/\s+/g, ' ')
.trim();
}
type MermaidTheme = 'default' | 'dark' | 'forest' | 'neutral' | 'base';
type MermaidLayout = 'dagre' | 'elk';
type MermaidLogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
const DEFAULT_THEME: MermaidTheme = 'default';
const DEFAULT_LAYOUT: MermaidLayout = 'dagre';
const DEFAULT_MERMAID_LOG_LEVEL: MermaidLogLevel = 'warn';
function readUrlParam(name: string) {
try {
return new URL(window.location.href).searchParams.get(name);
} catch {
return null;
}
}
function setUrlParams(pairs: Record<string, string | null | undefined>) {
const url = new URL(window.location.href);
for (const [k, v] of Object.entries(pairs)) {
if (!v) url.searchParams.delete(k);
else url.searchParams.set(k, v);
}
history.replaceState(null, '', url);
}
function readStorage(key: string) {
try {
return localStorage.getItem(key);
} catch {
return null;
}
}
function writeStorage(key: string, value: string) {
try {
localStorage.setItem(key, value);
} catch {
// ignore
}
}
function isTheme(v: unknown): v is MermaidTheme {
return v === 'default' || v === 'dark' || v === 'forest' || v === 'neutral' || v === 'base';
}
function isLayout(v: unknown): v is MermaidLayout {
return v === 'dagre' || v === 'elk';
}
function isMermaidLogLevel(v: unknown): v is MermaidLogLevel {
return (
v === 'trace' || v === 'debug' || v === 'info' || v === 'warn' || v === 'error' || v === 'fatal'
);
}
function normalizeLayout(v: unknown): MermaidLayout | null {
// Back-compat:
// - older UI used `renderer=dagre-d3|dagre-wrapper|elk`
// - new UI uses `layout=dagre|elk`
if (v === 'dagre' || v === 'elk') return v;
if (v === 'dagre-d3' || v === 'dagre-wrapper') return 'dagre';
return null;
}
function parseBoolean(v: unknown): boolean | null {
if (typeof v !== 'string') return null;
const s = v.trim().toLowerCase();
if (['1', 'true', 'yes', 'on'].includes(s)) return true;
if (['0', 'false', 'no', 'off'].includes(s)) return false;
return null;
}
export class DevDiagramViewer extends LitElement {
static properties = {
filePath: { type: String },
sseToken: { type: Number },
theme: { state: true },
layout: { state: true },
mermaidLogLevel: { state: true },
useMaxWidth: { state: true },
loading: { state: true },
error: { state: true },
source: { state: true },
svg: { state: true },
};
declare filePath: string;
declare sseToken: number;
declare theme: MermaidTheme;
declare layout: MermaidLayout;
declare mermaidLogLevel: MermaidLogLevel;
declare useMaxWidth: boolean;
declare loading: boolean;
declare error: string;
declare source: string;
declare svg: string;
#renderSeq = 0;
#consolePatched = false;
#originalConsole?: {
log: typeof console.log;
info: typeof console.info;
debug: typeof console.debug;
warn: typeof console.warn;
error: typeof console.error;
};
constructor() {
super();
const themeParam = readUrlParam('theme');
const layoutParam = readUrlParam('layout');
const rendererParam = readUrlParam('renderer'); // legacy
const logParam = readUrlParam('logLevel');
const useMaxWidthParam = readUrlParam('useMaxWidth');
const storedTheme = readStorage('devExplorer.viewer.theme');
const storedLayout = readStorage('devExplorer.viewer.layout');
const storedRenderer = readStorage('devExplorer.viewer.renderer'); // legacy
const storedLog = readStorage('devExplorer.viewer.logLevel');
const storedUseMaxWidth = readStorage('devExplorer.viewer.useMaxWidth');
this.theme = isTheme(themeParam)
? themeParam
: isTheme(storedTheme)
? storedTheme
: DEFAULT_THEME;
this.layout =
normalizeLayout(layoutParam) ??
normalizeLayout(rendererParam) ??
normalizeLayout(storedLayout) ??
normalizeLayout(storedRenderer) ??
DEFAULT_LAYOUT;
this.mermaidLogLevel = isMermaidLogLevel(logParam)
? logParam
: isMermaidLogLevel(storedLog)
? storedLog
: DEFAULT_MERMAID_LOG_LEVEL;
this.useMaxWidth = parseBoolean(useMaxWidthParam) ?? parseBoolean(storedUseMaxWidth) ?? true;
this.filePath = '';
this.sseToken = 0;
this.loading = true;
this.error = '';
this.source = '';
this.svg = '';
}
createRenderRoot() {
return this;
}
connectedCallback() {
super.connectedCallback();
this.#installConsoleCapture();
}
disconnectedCallback() {
super.disconnectedCallback();
this.#restoreConsoleCapture();
}
updated(changed: Map<string, unknown>) {
if (changed.has('filePath')) {
void this.#loadAndRender();
} else if (changed.has('sseToken')) {
// On rebuild events, re-fetch + re-render the currently open diagram.
if (this.filePath) void this.#loadAndRender();
} else if (
changed.has('theme') ||
changed.has('layout') ||
changed.has('mermaidLogLevel') ||
changed.has('useMaxWidth')
) {
// Re-render the currently loaded diagram with the new config without refetching.
if (this.source) void this.#renderCurrentSource();
}
}
#back() {
this.dispatchEvent(new CustomEvent('back', { bubbles: true, composed: true }));
}
#persistSettings() {
writeStorage('devExplorer.viewer.theme', this.theme);
writeStorage('devExplorer.viewer.layout', this.layout);
writeStorage('devExplorer.viewer.logLevel', this.mermaidLogLevel);
writeStorage('devExplorer.viewer.useMaxWidth', String(this.useMaxWidth));
setUrlParams({
theme: this.theme,
layout: this.layout,
renderer: null, // drop legacy param
logLevel: this.mermaidLogLevel,
useMaxWidth: this.useMaxWidth ? '1' : '0',
});
}
#syncConsolePanelFilters() {
const panel = this.querySelector('dev-console-panel') as any;
if (!panel) return;
// This is intentionally opinionated: less noise by default as logLevel increases.
if (
this.mermaidLogLevel === 'trace' ||
this.mermaidLogLevel === 'debug' ||
this.mermaidLogLevel === 'info'
) {
panel.showInfo = true;
panel.showWarn = true;
panel.showError = true;
return;
}
if (this.mermaidLogLevel === 'warn') {
panel.showInfo = false;
panel.showWarn = true;
panel.showError = true;
return;
}
// error / fatal
panel.showInfo = false;
panel.showWarn = false;
panel.showError = true;
}
#appendLog(entry: LogEntry) {
const panel = this.querySelector('dev-console-panel') as any;
panel?.append?.(entry);
}
#installConsoleCapture() {
if (this.#consolePatched) return;
this.#consolePatched = true;
this.#originalConsole = {
log: console.log,
info: console.info,
debug: console.debug,
warn: console.warn,
error: console.error,
};
const capture = (level: LogLevel, args: unknown[]) => {
this.#appendLog({
ts: Date.now(),
level,
message: stringifyArgs(args),
});
};
// Mermaid uses its own logger which routes to console.info/debug/warn/error.
// Capture those too (map debug/info/log -> panel "info").
console.log = (...args) => {
capture('info', args);
this.#originalConsole!.log.apply(console, args as any);
};
console.info = (...args) => {
capture('info', args);
this.#originalConsole!.info.apply(console, args as any);
};
console.debug = (...args) => {
capture('info', args);
this.#originalConsole!.debug.apply(console, args as any);
};
console.warn = (...args) => {
capture('warn', args);
this.#originalConsole!.warn.apply(console, args as any);
};
console.error = (...args) => {
capture('error', args);
this.#originalConsole!.error.apply(console, args as any);
};
}
#restoreConsoleCapture() {
if (!this.#consolePatched) return;
this.#consolePatched = false;
if (!this.#originalConsole) return;
console.log = this.#originalConsole.log;
console.info = this.#originalConsole.info;
console.debug = this.#originalConsole.debug;
console.warn = this.#originalConsole.warn;
console.error = this.#originalConsole.error;
this.#originalConsole = undefined;
}
#clearLogs() {
const panel = this.querySelector('dev-console-panel') as any;
panel?.clear?.();
}
async #fetchSource() {
const url = new URL('/dev/api/file', window.location.origin);
url.searchParams.set('path', this.filePath);
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.text();
}
async #loadAndRender() {
const seq = ++this.#renderSeq;
this.loading = true;
this.error = '';
this.svg = '';
this.#clearLogs();
this.#syncConsolePanelFilters();
try {
const source = await this.#fetchSource();
if (seq !== this.#renderSeq) return;
this.source = source;
await this.#renderMermaid(source);
} catch (e) {
this.error = e instanceof Error ? e.message : String(e);
} finally {
this.loading = false;
}
}
async #renderCurrentSource() {
const seq = ++this.#renderSeq;
this.loading = true;
this.error = '';
this.svg = '';
this.#clearLogs();
this.#syncConsolePanelFilters();
try {
const source = this.source;
if (!source) return;
if (seq !== this.#renderSeq) return;
await this.#renderMermaid(source);
} catch (e) {
this.error = e instanceof Error ? e.message : String(e);
} finally {
this.loading = false;
}
}
async #renderMermaid(text: string) {
const m = (await window.mermaidReady?.catch(() => undefined)) ?? window.mermaid;
if (!m) {
throw new Error(
'window.mermaid is not available (did /mermaid.esm.mjs load and did the bootstrap set window.mermaid?)'
);
}
const initConfig = {
startOnLoad: false,
securityLevel: 'strict',
theme: this.theme,
layout: this.layout,
logLevel: this.mermaidLogLevel,
flowchart: {
useMaxWidth: this.useMaxWidth,
},
};
// Debugging aid: log exactly what we are about to initialize/render with.
// Do it *before* initialize so detector issues can be correlated.
const previewLimit = 4000;
const preview =
text.length > previewLimit
? `${text.slice(0, previewLimit)}\n… (${text.length - previewLimit} more chars)`
: text;
console.log('[dev-explorer] mermaid.initialize config:', initConfig);
console.log('[dev-explorer] diagram source preview:\n' + preview);
// Keep it deterministic-ish between reloads.
await m.initialize(initConfig);
const id = `dev-explorer-${Date.now()}-${Math.random().toString(16).slice(2)}`;
const { svg, bindFunctions } = await m.render(id, text);
this.svg = svg;
// Allow mermaid to attach event handlers (e.g. links).
await this.updateComplete;
// If the page ever ended up scrolled down due to a previous oversized render, snap back to top.
// (We intentionally removed vertical scrollbars in the viewer.)
try {
window.scrollTo(0, 0);
} catch {
// ignore
}
const container = this.querySelector('.diagram-inner');
if (container && bindFunctions) bindFunctions(container);
}
render() {
return html`
<div class="header">
<sl-button size="small" variant="default" @click=${() => this.#back()}>
<sl-icon slot="prefix" name="arrow-left"></sl-icon>
Back
</sl-button>
<div style="min-width: 0;">
<div class="title">Diagram</div>
<div class="path">${this.filePath}</div>
</div>
<div class="spacer"></div>
<div class="viewer-controls">
<div class="control">
<span class="label">Theme</span>
<sl-select
size="small"
value=${this.theme}
@sl-change=${(e: any) => {
const v = e.target?.value;
if (isTheme(v)) {
this.theme = v;
this.#persistSettings();
}
}}
>
<sl-option value="default">default</sl-option>
<sl-option value="dark">dark</sl-option>
<sl-option value="forest">forest</sl-option>
<sl-option value="neutral">neutral</sl-option>
<sl-option value="base">base</sl-option>
</sl-select>
</div>
<div class="control">
<span class="label">Layout</span>
<sl-select
size="small"
value=${this.layout}
@sl-change=${(e: any) => {
const v = e.target?.value;
if (isLayout(v)) {
this.layout = v;
this.#persistSettings();
}
}}
>
<sl-option value="dagre">dagre</sl-option>
<sl-option value="elk">elk</sl-option>
</sl-select>
</div>
<div class="control">
<span class="label">Log</span>
<sl-select
size="small"
value=${this.mermaidLogLevel}
@sl-change=${(e: any) => {
const v = e.target?.value;
if (isMermaidLogLevel(v)) {
this.mermaidLogLevel = v;
this.#persistSettings();
this.#syncConsolePanelFilters();
}
}}
>
<sl-option value="trace">trace</sl-option>
<sl-option value="debug">debug</sl-option>
<sl-option value="info">info</sl-option>
<sl-option value="warn">warn</sl-option>
<sl-option value="error">error</sl-option>
<sl-option value="fatal">fatal</sl-option>
</sl-select>
</div>
<div class="control">
<sl-checkbox
size="small"
?checked=${this.useMaxWidth}
@sl-change=${(e: any) => {
this.useMaxWidth = Boolean(e.target?.checked);
this.#persistSettings();
}}
>useMaxWidth</sl-checkbox
>
</div>
</div>
${this.loading ? html`<div class="subtle">rendering…</div>` : nothing}
</div>
${this.error
? html`<div class="empty">Error: <span class="path">${this.error}</span></div>`
: nothing}
<div class="content">
<sl-split-panel position="75" style="height: 100%;">
<div slot="start" class="diagram">
<div class="diagram-inner" data-theme=${this.theme} .innerHTML=${this.svg}></div>
</div>
<div slot="end" style="height: 100%;">
<dev-console-panel></dev-console-panel>
</div>
</sl-split-panel>
</div>
`;
}
}
customElements.define('dev-diagram-viewer', DevDiagramViewer);

View File

@@ -0,0 +1,143 @@
import { LitElement, html, nothing } from 'lit';
import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path.js';
import { registerIconLibrary } from '@shoelace-style/shoelace/dist/utilities/icon-library.js';
import '@shoelace-style/shoelace/dist/components/breadcrumb/breadcrumb.js';
import '@shoelace-style/shoelace/dist/components/breadcrumb-item/breadcrumb-item.js';
import '@shoelace-style/shoelace/dist/components/button/button.js';
import '@shoelace-style/shoelace/dist/components/icon/icon.js';
import '@shoelace-style/shoelace/dist/components/split-panel/split-panel.js';
import '@shoelace-style/shoelace/dist/components/badge/badge.js';
import '@shoelace-style/shoelace/dist/components/checkbox/checkbox.js';
import './file-explorer';
import './diagram-viewer';
type ViewMode = 'explorer' | 'viewer';
function getInitialStateFromUrl() {
const url = new URL(window.location.href);
const dir = url.searchParams.get('path') ?? '';
const file = url.searchParams.get('file') ?? '';
return { dir, file };
}
function setUrlState({ dir, file }: { dir: string; file: string }) {
const url = new URL(window.location.href);
url.searchParams.delete('path');
url.searchParams.delete('file');
if (dir) url.searchParams.set('path', dir);
if (file) url.searchParams.set('file', file);
history.replaceState(null, '', url);
}
export class DevExplorerApp extends LitElement {
static properties = {
mode: { state: true },
dirPath: { state: true },
lastDirPath: { state: true },
filePath: { state: true },
sseToken: { state: true },
};
declare mode: ViewMode;
declare dirPath: string;
declare lastDirPath: string;
declare filePath: string;
declare sseToken: number;
#events?: EventSource;
constructor() {
super();
const { dir, file } = getInitialStateFromUrl();
this.dirPath = dir;
this.lastDirPath = dir;
this.filePath = file;
this.mode = file ? 'viewer' : 'explorer';
this.sseToken = 0;
setBasePath('/dev/vendor/shoelace');
registerIconLibrary('default', {
resolver: (name) => `/dev/vendor/shoelace/assets/icons/${name}.svg`,
});
}
createRenderRoot() {
// Use light DOM so document-level CSS (public/styles.css => /dev/styles.css) applies to the UI.
// Without this, Lit's default shadow root will block global selectors like `.list` / `button.card`.
return this;
}
connectedCallback() {
super.connectedCallback();
this.#events = new EventSource('/events');
this.#events.onmessage = () => {
this.sseToken++;
};
window.addEventListener('popstate', this.#onPopState);
}
disconnectedCallback() {
super.disconnectedCallback();
this.#events?.close();
window.removeEventListener('popstate', this.#onPopState);
}
#onPopState = () => {
const { dir, file } = getInitialStateFromUrl();
this.dirPath = dir;
this.lastDirPath = dir;
this.filePath = file;
this.mode = file ? 'viewer' : 'explorer';
};
#goToDir = (dir: string) => {
this.dirPath = dir;
this.lastDirPath = dir;
this.mode = 'explorer';
this.filePath = '';
setUrlState({ dir, file: '' });
};
#openFile = (filePath: string) => {
this.filePath = filePath;
this.mode = 'viewer';
setUrlState({ dir: this.lastDirPath, file: filePath });
};
#backToExplorer = () => {
this.mode = 'explorer';
this.filePath = '';
setUrlState({ dir: this.lastDirPath, file: '' });
};
render() {
return html`
<div class="app">
${this.mode === 'explorer'
? html`
<dev-file-explorer
.path=${this.dirPath}
.sseToken=${this.sseToken}
@navigate=${(e: CustomEvent<{ path: string }>) => this.#goToDir(e.detail.path)}
@open-file=${(e: CustomEvent<{ path: string }>) => this.#openFile(e.detail.path)}
></dev-file-explorer>
`
: nothing}
${this.mode === 'viewer'
? html`
<dev-diagram-viewer
.filePath=${this.filePath}
.sseToken=${this.sseToken}
@back=${this.#backToExplorer}
></dev-diagram-viewer>
`
: nothing}
</div>
`;
}
}
customElements.define('dev-explorer-app', DevExplorerApp);

View File

@@ -0,0 +1,182 @@
import { LitElement, html, nothing } from 'lit';
type Entry = {
name: string;
kind: 'dir' | 'file';
path: string;
};
type FilesResponse = {
root: string;
path: string;
entries: Entry[];
};
function dirname(posixPath: string) {
const p = posixPath.replaceAll('\\', '/').replace(/\/+$/, '');
if (!p) return '';
const idx = p.lastIndexOf('/');
if (idx <= 0) return '';
return p.slice(0, idx);
}
function pathSegments(posixPath: string) {
const p = posixPath.replaceAll('\\', '/').replace(/^\/+/, '').replace(/\/+$/, '');
if (!p) return [];
return p.split('/').filter(Boolean);
}
export class DevFileExplorer extends LitElement {
static properties = {
path: { type: String },
sseToken: { type: Number },
loading: { state: true },
error: { state: true },
root: { state: true },
entries: { state: true },
};
declare path: string;
declare sseToken: number;
declare loading: boolean;
declare error: string;
declare root: string;
declare entries: Entry[];
constructor() {
super();
this.path = '';
this.sseToken = 0;
this.loading = true;
this.error = '';
this.root = '';
this.entries = [];
}
createRenderRoot() {
// Use light DOM so global CSS in public/styles.css applies.
return this;
}
updated(changed: Map<string, unknown>) {
if (changed.has('path') || changed.has('sseToken')) {
void this.#load();
}
}
async #load() {
this.loading = true;
this.error = '';
try {
const url = new URL('/dev/api/files', window.location.origin);
if (this.path) url.searchParams.set('path', this.path);
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = (await res.json()) as FilesResponse;
this.root = json.root ?? '';
this.entries = json.entries ?? [];
} catch (e) {
this.error = e instanceof Error ? e.message : String(e);
this.entries = [];
} finally {
this.loading = false;
}
}
#emitNavigate(nextPath: string) {
this.dispatchEvent(
new CustomEvent('navigate', { detail: { path: nextPath }, bubbles: true, composed: true })
);
}
#emitOpenFile(filePath: string) {
this.dispatchEvent(
new CustomEvent('open-file', { detail: { path: filePath }, bubbles: true, composed: true })
);
}
#onActivate(kind: Entry['kind'], entryPath: string) {
if (kind === 'dir') {
this.#emitNavigate(entryPath);
} else {
this.#emitOpenFile(entryPath);
}
}
render() {
const segments = pathSegments(this.path);
const itemLabel = this.entries.length === 1 ? 'item' : 'items';
return html`
<div class="header">
<div style="min-width: 0;">
<div class="title">Dev Explorer</div>
<div class="subtle">
root:
<span class="path">${this.root || 'cypress/platform/dev-diagrams'}</span>
</div>
<div style="margin-top: 6px;">
<sl-breadcrumb>
<sl-breadcrumb-item @click=${() => this.#emitNavigate('')}>root</sl-breadcrumb-item>
${segments.map((seg, idx) => {
const to = segments.slice(0, idx + 1).join('/');
return html`<sl-breadcrumb-item @click=${() => this.#emitNavigate(to)}
>${seg}</sl-breadcrumb-item
>`;
})}
</sl-breadcrumb>
</div>
</div>
<div class="spacer"></div>
<div class="subtle">
${this.loading ? 'loading…' : html`<span>${this.entries.length} ${itemLabel}</span>`}
</div>
<sl-button
size="small"
variant="default"
?disabled=${!this.path}
@click=${() => this.#emitNavigate(dirname(this.path))}
>
<sl-icon slot="prefix" name="arrow-left"></sl-icon>
Up
</sl-button>
</div>
<div class="content">
${this.error
? html`<div class="empty">Error: <span class="path">${this.error}</span></div>`
: nothing}
${!this.error && !this.loading && this.entries.length === 0
? html`<div class="empty">No folders or <span class="path">.mmd</span> files here.</div>`
: nothing}
<div class="list">
${this.entries.map((e) => {
const icon = e.kind === 'dir' ? 'folder-fill' : 'file-earmark-code';
const cardClass = e.kind === 'dir' ? 'card card-folder' : 'card card-file';
const click =
e.kind === 'dir'
? () => this.#emitNavigate(e.path)
: () => this.#emitOpenFile(e.path);
const onKeyDown = (ev: KeyboardEvent) => {
if (ev.key === 'Enter' || ev.key === ' ') {
ev.preventDefault();
this.#onActivate(e.kind, e.path);
}
};
return html`
<button class=${cardClass} type="button" @click=${click} @keydown=${onKeyDown}>
<div class="card-inner">
<sl-icon class="card-icon" name=${icon}></sl-icon>
<div class="card-title">${e.name}</div>
</div>
</button>
`;
})}
</div>
</div>
`;
}
}
customElements.define('dev-file-explorer', DevFileExplorer);

View File

@@ -0,0 +1,39 @@
<!doctype html>
<html lang="en" class="sl-theme-dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Mermaid Dev Explorer</title>
<link rel="stylesheet" href="/dev/vendor/shoelace/themes/dark.css" />
<link rel="stylesheet" href="/dev/styles.css?v=6" />
</head>
<body>
<!-- Mermaid ESM + ELK layout loaders (required for `layout: 'elk'`) -->
<script type="module">
// Expose a single async hook so the app can reliably await Mermaid "activation".
// This avoids races where the UI calls initialize/render before layouts/diagrams are ready.
window.mermaidReady = (async () => {
try {
const [{ default: mermaid }, { default: layouts }] = await Promise.all([
import('/mermaid.esm.mjs'),
import('/mermaid-layout-elk.esm.mjs'),
]);
mermaid.registerLayoutLoaders(layouts);
// Keep the rest of the dev explorer simple: expose mermaid on window for the Lit components.
window.mermaid = mermaid;
return mermaid;
} catch (err) {
console.error('[dev-explorer] Failed to initialize mermaid (ESM + elk loaders).', err);
throw err;
}
})();
</script>
<dev-explorer-app></dev-explorer-app>
<script type="module" src="/dev/assets/explorer-app.js?v=6"></script>
</body>
</html>

View File

@@ -0,0 +1,359 @@
/* Dev Explorer tokens. Keep on :root so the page background picks them up too. */
:root {
--app-bg: #0b1020;
--app-fg: #e8eefc;
--panel-bg: #0f1733;
--muted: rgba(232, 238, 252, 0.75);
--border: rgba(232, 238, 252, 0.12);
--mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
monospace;
}
html,
body {
height: 100%;
}
body {
margin: 0;
background: var(--app-bg);
color: var(--app-fg);
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
/* Keep the page from becoming scrollable when components accidentally overflow. */
overflow: hidden;
}
a {
color: inherit;
}
/* Scope app-level layout rules to avoid generic class collisions. */
dev-explorer-app {
display: block;
height: 100%;
}
dev-explorer-app .app {
height: 100vh;
display: flex;
flex-direction: column;
}
/* Let the top-level view components actually fill the available vertical space. */
dev-explorer-app dev-file-explorer,
dev-explorer-app dev-diagram-viewer {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
dev-explorer-app .header {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-bottom: 1px solid var(--border);
background: var(--panel-bg);
}
dev-explorer-app .viewer-controls {
display: inline-flex;
align-items: center;
gap: 10px;
margin-right: 8px;
}
dev-explorer-app .viewer-controls .control {
display: inline-flex;
align-items: center;
gap: 6px;
}
dev-explorer-app .viewer-controls .label {
font-size: 12px;
color: var(--muted);
user-select: none;
}
dev-explorer-app .viewer-controls sl-select {
width: 140px;
}
dev-explorer-app .header .spacer {
flex: 1;
}
dev-explorer-app .title {
font-weight: 600;
letter-spacing: 0.2px;
}
dev-explorer-app .subtle {
color: var(--muted);
font-size: 12px;
}
dev-explorer-app .content {
flex: 1;
min-height: 0;
overflow: auto;
}
/* Diagram view should behave like a full-height canvas; avoid nested scrollbars. */
dev-explorer-app dev-diagram-viewer .content {
overflow: hidden;
}
/* Shoelace split panel: ensure slot content can't overflow and push itself off-screen. */
dev-explorer-app sl-split-panel {
height: 100%;
overflow: hidden;
}
dev-explorer-app sl-split-panel::part(base) {
height: 100%;
overflow: hidden;
}
dev-explorer-app sl-split-panel::part(start),
dev-explorer-app sl-split-panel::part(end) {
overflow: hidden;
min-height: 0;
}
dev-explorer-app .list {
padding: 24px;
display: grid;
gap: 20px;
grid-template-columns: repeat(auto-fill, 260px);
}
/* Card base - use button element */
dev-explorer-app button.card {
all: unset;
box-sizing: border-box;
width: 260px;
height: 200px;
border-radius: 20px;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
/* Folder card style */
dev-explorer-app button.card.card-folder {
background: linear-gradient(160deg, #1a3052 0%, #0d1a2d 100%);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.4),
0 2px 8px rgba(0, 0, 0, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
dev-explorer-app button.card.card-folder:hover {
transform: translateY(-6px) scale(1.02);
box-shadow:
0 16px 48px rgba(0, 0, 0, 0.5),
0 4px 12px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
/* File card style */
dev-explorer-app button.card.card-file {
background: linear-gradient(160deg, #1e2d4a 0%, #111827 100%);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.4),
0 2px 8px rgba(0, 0, 0, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
dev-explorer-app button.card.card-file:hover {
transform: translateY(-6px) scale(1.02);
box-shadow:
0 16px 48px rgba(0, 0, 0, 0.5),
0 4px 12px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
dev-explorer-app button.card:focus-visible {
outline: 3px solid rgba(96, 165, 250, 0.7);
outline-offset: 4px;
}
/* Subtle border overlay */
dev-explorer-app button.card::before {
content: '';
position: absolute;
inset: 0;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.08);
pointer-events: none;
}
dev-explorer-app .card-inner {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
padding: 24px;
width: 100%;
height: 100%;
box-sizing: border-box;
}
/* Icon styling */
dev-explorer-app .card-icon {
font-size: 56px !important;
width: 56px;
height: 56px;
}
dev-explorer-app button.card.card-folder .card-icon {
color: #f59e0b;
filter: drop-shadow(0 4px 12px rgba(245, 158, 11, 0.4));
}
dev-explorer-app button.card.card-file .card-icon {
color: #3b82f6;
filter: drop-shadow(0 4px 12px rgba(59, 130, 246, 0.35));
}
/* Title styling */
dev-explorer-app .card-title {
font-size: 12px;
font-family: var(--mono);
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 230px;
color: rgba(255, 255, 255, 0.85);
line-height: 1.4;
text-align: center;
}
dev-explorer-app .row {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px;
border: 1px solid var(--border);
border-radius: 8px;
background: rgba(255, 255, 255, 0.02);
}
dev-explorer-app .row:hover {
background: rgba(255, 255, 255, 0.04);
}
dev-explorer-app .row sl-icon {
font-size: 16px;
}
dev-explorer-app .path {
font-family: var(--mono);
font-size: 12px;
color: var(--muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
dev-explorer-app .diagram {
height: 100%;
overflow: hidden;
padding: 12px;
box-sizing: border-box;
}
dev-explorer-app .diagram-inner {
/* Canvas background behind the rendered SVG (theme-dependent). */
background: #fff;
color: #111;
border-radius: 10px;
padding: 12px;
display: flex;
align-items: flex-start;
justify-content: flex-start;
width: 100%;
height: 100%;
box-sizing: border-box;
}
/* Fit the rendered SVG within the available pane (no scrollbars). */
dev-explorer-app .diagram-inner > svg {
width: auto;
height: auto;
max-width: 100% !important;
max-height: 100% !important;
}
dev-explorer-app .diagram-inner[data-theme='dark'] {
background: #0b1020;
color: #e8eefc;
}
dev-explorer-app .console {
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
border-left: 1px solid var(--border);
background: var(--panel-bg);
}
dev-explorer-app .spacer {
flex: 1;
}
dev-explorer-app .console-toolbar {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-bottom: 1px solid var(--border);
}
dev-explorer-app .console-toolbar sl-input {
width: 260px;
}
dev-explorer-app .console-body {
flex: 1;
min-height: 0;
overflow: auto;
padding: 10px 12px;
}
dev-explorer-app .logline {
font-family: var(--mono);
font-size: 12px;
white-space: pre-wrap;
word-break: break-word;
margin: 0 0 8px 0;
line-height: 1.35;
}
dev-explorer-app .logmeta {
display: inline-flex;
gap: 8px;
align-items: center;
margin-bottom: 4px;
}
dev-explorer-app .empty {
padding: 18px 12px;
color: var(--muted);
font-size: 13px;
}
dev-explorer-app sl-breadcrumb::part(base) {
font-size: 12px;
}

View File

@@ -1,126 +0,0 @@
/* eslint-disable no-console */
import chokidar from 'chokidar';
import cors from 'cors';
import { context } from 'esbuild';
import type { Request, Response } from 'express';
import express from 'express';
import { packageOptions } from '../.build/common.js';
import { generateLangium } from '../.build/generateLangium.js';
import { defaultOptions, getBuildConfig } from './util.js';
// Set environment variable to use ANTLR parser
process.env.USE_ANTLR_PARSER = 'true';
const configs = Object.values(packageOptions).map(({ packageName }) =>
getBuildConfig({
...defaultOptions,
minify: false,
core: false,
options: packageOptions[packageName],
})
);
const mermaidIIFEConfig = getBuildConfig({
...defaultOptions,
minify: false,
core: false,
options: packageOptions.mermaid,
format: 'iife',
});
configs.push(mermaidIIFEConfig);
const contexts = await Promise.all(
configs.map(async (config) => ({ config, context: await context(config) }))
);
let rebuildCounter = 1;
const rebuildAll = async () => {
const buildNumber = rebuildCounter++;
const timeLabel = `Rebuild ${buildNumber} Time (total)`;
console.time(timeLabel);
await Promise.all(
contexts.map(async ({ config, context }) => {
const buildVariant = `Rebuild ${buildNumber} Time (${Object.keys(config.entryPoints!)[0]} ${config.format})`;
console.time(buildVariant);
await context.rebuild();
console.timeEnd(buildVariant);
})
).catch((e) => console.error(e));
console.timeEnd(timeLabel);
};
let clients: { id: number; response: Response }[] = [];
function eventsHandler(request: Request, response: Response) {
const headers = {
'Content-Type': 'text/event-stream',
Connection: 'keep-alive',
'Cache-Control': 'no-cache',
};
response.writeHead(200, headers);
const clientId = Date.now();
clients.push({
id: clientId,
response,
});
request.on('close', () => {
clients = clients.filter((client) => client.id !== clientId);
});
}
let timeoutID: NodeJS.Timeout | undefined = undefined;
/**
* Debounce file change events to avoid rebuilding multiple times.
*/
function handleFileChange() {
if (timeoutID !== undefined) {
clearTimeout(timeoutID);
}
// eslint-disable-next-line @typescript-eslint/no-misused-promises
timeoutID = setTimeout(async () => {
await rebuildAll();
sendEventsToAll();
timeoutID = undefined;
}, 100);
}
function sendEventsToAll() {
clients.forEach(({ response }) => response.write(`data: ${Date.now()}\n\n`));
}
async function createServer() {
await generateLangium();
handleFileChange();
const app = express();
chokidar
.watch('**/src/**/*.{js,ts,langium,yaml,json}', {
ignoreInitial: true,
ignored: [/node_modules/, /dist/, /docs/, /coverage/],
})
// eslint-disable-next-line @typescript-eslint/no-misused-promises
.on('all', async (event, path) => {
// Ignore other events.
if (!['add', 'change'].includes(event)) {
return;
}
console.log(`${path} changed. Rebuilding...`);
if (path.endsWith('.langium')) {
await generateLangium();
}
handleFileChange();
});
app.use(cors());
app.get('/events', eventsHandler);
for (const { packageName } of Object.values(packageOptions)) {
app.use(express.static(`./packages/${packageName}/dist`));
}
app.use(express.static('demos'));
app.use(express.static('cypress/platform'));
app.listen(9000, () => {
console.log(`🚀 ANTLR Parser Dev Server listening on http://localhost:9000`);
console.log(`🎯 Environment: USE_ANTLR_PARSER=${process.env.USE_ANTLR_PARSER}`);
});
}
void createServer();

View File

@@ -2,12 +2,17 @@
import chokidar from 'chokidar';
import cors from 'cors';
import { context } from 'esbuild';
import { promises as fs } from 'fs';
import type { Request, Response } from 'express';
import express from 'express';
import path, { resolve } from 'path';
import { fileURLToPath } from 'url';
import { packageOptions } from '../.build/common.js';
import { generateLangium } from '../.build/generateLangium.js';
import { defaultOptions, getBuildConfig } from './util.js';
const __dirname = fileURLToPath(new URL('.', import.meta.url));
const configs = Object.values(packageOptions).map(({ packageName }) =>
getBuildConfig({
...defaultOptions,
@@ -18,7 +23,7 @@ const configs = Object.values(packageOptions).map(({ packageName }) =>
);
const mermaidIIFEConfig = getBuildConfig({
...defaultOptions,
minify: false,
minify: true,
core: false,
options: packageOptions.mermaid,
format: 'iife',
@@ -84,6 +89,81 @@ function sendEventsToAll() {
clients.forEach(({ response }) => response.write(`data: ${Date.now()}\n\n`));
}
interface DevExplorerEntry {
name: string;
kind: 'dir' | 'file';
path: string; // posix-style, relative to root
}
const devExplorerRootAbs = resolve(
process.cwd(),
process.env.MERMAID_DEV_EXPLORER_ROOT ?? 'cypress/platform/dev-diagrams'
);
function toPosixPath(p: string) {
return p.split(path.sep).join('/');
}
function resolveWithinDevExplorerRoot(requestedPath: unknown) {
const requested = typeof requestedPath === 'string' ? requestedPath : '';
if (requested.includes('\0')) {
throw new Error('Invalid path');
}
// Normalize slashes and avoid weird absolute-path cases.
const cleaned = requested.replaceAll('\\', '/').replace(/^\/+/, '');
const absPath = resolve(devExplorerRootAbs, cleaned);
const rel = path.relative(devExplorerRootAbs, absPath);
// Prevent traversal above root.
if (rel.startsWith('..') || path.isAbsolute(rel)) {
throw new Error('Path escapes configured root');
}
return { absPath, relPath: toPosixPath(rel) };
}
async function createDevExplorerBundle() {
const devExplorerDir = resolve(__dirname, 'dev-explorer');
const entryPoint = resolve(devExplorerDir, 'explorer-app.ts');
const outDir = resolve(devExplorerDir, 'dist');
try {
const devExplorerCtx = await context({
absWorkingDir: process.cwd(),
entryPoints: [entryPoint],
bundle: true,
format: 'esm',
target: 'es2020',
sourcemap: true,
outdir: outDir,
logLevel: 'info',
plugins: [
{
name: 'dev-explorer-reload',
setup(build) {
build.onEnd(() => {
sendEventsToAll();
});
},
},
],
});
await devExplorerCtx.watch();
await devExplorerCtx.rebuild();
} catch (err) {
console.error(
[
'Dev Explorer bundle build failed.',
'Install dependencies: pnpm add -D lit @shoelace-style/shoelace',
'Then restart the dev server.',
].join('\n')
);
console.error(err);
}
}
async function createServer() {
await generateLangium();
handleFileChange();
@@ -106,8 +186,117 @@ async function createServer() {
handleFileChange();
});
// Rebuild the dev-explorer client bundle on changes (and emit SSE so the browser reloads).
await createDevExplorerBundle();
// Emit SSE when Dev Explorer static assets change (e.g. public/styles.css),
// otherwise CSS-only changes can look "ignored" unless the user manually refreshes.
chokidar
.watch(['.esbuild/dev-explorer/public/**/*'], {
ignoreInitial: true,
ignored: [/node_modules/, /dist/, /docs/, /coverage/],
})
.on('all', (event, changedPath) => {
if (!['add', 'change', 'unlink'].includes(event)) {
return;
}
console.log(`[dev-explorer] ${event}: ${changedPath}`);
sendEventsToAll();
});
// Emit SSE when .mmd files inside the configured explorer root change.
chokidar
.watch('**/*.mmd', {
cwd: devExplorerRootAbs,
ignoreInitial: true,
})
.on('all', (event, changedPath) => {
if (!['add', 'change', 'unlink'].includes(event)) {
return;
}
console.log(`[dev-explorer] ${event}: ${changedPath}`);
sendEventsToAll();
});
app.use(cors());
app.get('/events', eventsHandler);
// --- Dev Explorer API + UI -------------------------------------------------
const devExplorerDir = resolve(__dirname, 'dev-explorer');
const devExplorerPublicDir = resolve(devExplorerDir, 'public');
const devExplorerDistDir = resolve(devExplorerDir, 'dist');
// Shoelace assets (theme css + icons). Safe: only mounted in dev server.
app.use(
'/dev/vendor/shoelace',
express.static(resolve(process.cwd(), 'node_modules/@shoelace-style/shoelace/dist'))
);
app.get('/dev/api/files', async (req, res) => {
try {
const { absPath, relPath } = resolveWithinDevExplorerRoot(req.query.path);
const stats = await fs.stat(absPath);
if (!stats.isDirectory()) {
res.status(400).json({ error: 'Not a directory' });
return;
}
const dirEntries = await fs.readdir(absPath, { withFileTypes: true });
const entries = dirEntries
.filter((d) => d.isDirectory() || (d.isFile() && d.name.endsWith('.mmd')))
.map<DevExplorerEntry>((d) => ({
name: d.name,
kind: d.isDirectory() ? 'dir' : 'file',
path: toPosixPath(path.join(relPath, d.name)),
}))
.sort((a, b) => {
if (a.kind !== b.kind) {
return a.kind === 'dir' ? -1 : 1;
}
return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' });
});
res.json({
root: toPosixPath(path.relative(process.cwd(), devExplorerRootAbs)),
path: relPath === '' ? '' : relPath,
entries,
});
} catch (_e) {
res.status(400).json({ error: 'Invalid path' });
}
});
app.get('/dev/api/file', async (req, res) => {
try {
const { absPath, relPath } = resolveWithinDevExplorerRoot(req.query.path);
if (!absPath.endsWith('.mmd')) {
res.status(400).send('Only .mmd files are allowed');
return;
}
const stats = await fs.stat(absPath);
if (!stats.isFile()) {
res.status(400).send('Not a file');
return;
}
const content = await fs.readFile(absPath, 'utf-8');
res.type('text/plain').send(content);
// Optional: include relPath for debugging.
void relPath;
} catch (_e) {
res.status(400).send('Invalid path');
}
});
// Static assets for the dev-explorer UI.
app.use('/dev/assets', express.static(devExplorerDistDir));
// Serve `/dev/` (and `/dev`) from public/, including index.html.
app.use(
'/dev',
express.static(devExplorerPublicDir, {
index: ['index.html'],
})
);
for (const { packageName } of Object.values(packageOptions)) {
app.use(express.static(`./packages/${packageName}/dist`));
}

View File

@@ -71,6 +71,9 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
const external: string[] = ['require', 'fs', 'path'];
const outFileName = getFileName(name, options);
const { dependencies, version } = JSON.parse(
readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8')
);
const output: BuildOptions = buildOptions({
...rest,
absWorkingDir: resolve(__dirname, `../packages/${packageName}`),
@@ -82,19 +85,13 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
chunkNames: `chunks/${outFileName}/[name]-[hash]`,
define: {
// This needs to be stringified for esbuild
includeLargeFeatures: `${includeLargeFeatures}`,
'injected.includeLargeFeatures': `${includeLargeFeatures}`,
'injected.version': `'${version}'`,
'import.meta.vitest': 'undefined',
// Replace process.env.USE_ANTLR_PARSER with actual value at build time
'process.env.USE_ANTLR_PARSER': `"${process.env.USE_ANTLR_PARSER || 'false'}"`,
// Replace process.env.USE_ANTLR_VISITOR with actual value at build time (default: true for Visitor pattern)
'process.env.USE_ANTLR_VISITOR': `"${process.env.USE_ANTLR_VISITOR || 'true'}"`,
},
});
if (core) {
const { dependencies } = JSON.parse(
readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8')
);
// Core build is used to generate file without bundled dependencies.
// This is used by downstream projects to bundle dependencies themselves.
// Ignore dependencies and any dependencies of dependencies

View File

@@ -26,8 +26,8 @@ jobs:
strategy:
fail-fast: false
matrix:
language: ['javascript']
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
language: ['javascript', 'actions']
# CodeQL supports [ 'actions', 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
@@ -36,7 +36,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
uses: github/codeql-action/init@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
with:
config-file: ./.github/codeql/codeql-config.yml
languages: ${{ matrix.language }}
@@ -48,7 +48,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
uses: github/codeql-action/autobuild@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -62,4 +62,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
uses: github/codeql-action/analyze@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21

View File

@@ -53,7 +53,7 @@ jobs:
args: -X POST "$APPLITOOLS_SERVER_URL/api/externals/github/push?apiKey=$APPLITOOLS_API_KEY&CommitSha=$GITHUB_SHA&BranchName=${APPLITOOLS_BRANCH}$&ParentBranchName=$APPLITOOLS_PARENT_BRANCH"
- name: Cypress run
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
id: cypress
with:
start: pnpm run dev

View File

@@ -27,12 +27,12 @@ jobs:
with:
node-version-file: '.node-version'
- name: Install dependencies
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
with:
runTests: false
- name: Cypress run
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
id: cypress
with:
install: false
@@ -58,7 +58,7 @@ jobs:
echo "EOF" >> $GITHUB_OUTPUT
- name: Commit and create pull request
uses: peter-evans/create-pull-request@18e469570b1cf0dfc11d60ec121099f8ff3e617a
uses: peter-evans/create-pull-request@0979079bc20c05bbbb590a56c21c4e2b1d1f1bbe
with:
add-paths: |
cypress/timings.json

View File

@@ -45,7 +45,7 @@ jobs:
node-version-file: '.node-version'
- name: Cache snapshots
id: cache-snapshot
uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ./cypress/snapshots
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
@@ -59,7 +59,7 @@ jobs:
- name: Install dependencies
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
with:
# just perform install
runTests: false
@@ -95,13 +95,13 @@ jobs:
# These cached snapshots are downloaded, providing the reference snapshots.
- name: Cache snapshots
id: cache-snapshot
uses: actions/cache/restore@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ./cypress/snapshots
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
- name: Install dependencies
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
with:
runTests: false
@@ -117,7 +117,7 @@ jobs:
# Install NPM dependencies, cache them correctly
# and run all Cypress tests
- name: Cypress run
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
id: cypress
with:
install: false

View File

@@ -32,7 +32,7 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Restore lychee cache
uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: .lycheecache
key: cache-lychee-${{ github.sha }}

View File

@@ -36,11 +36,10 @@ jobs:
- name: Create Release Pull Request or Publish to npm
id: changesets
uses: changesets/action@c8bada60c408975afd1a20b3db81d6eee6789308 # v1.4.9
uses: changesets/action@06245a4e0a36c064a573d4150030f5ec548e4fcc # v1.4.10
with:
version: pnpm changeset:version
publish: pnpm changeset:publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_CONFIG_PROVENANCE: true

View File

@@ -20,18 +20,18 @@ jobs:
with:
persist-credentials: false
- name: Run analysis
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
publish_results: true
- name: Upload artifact
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: SARIF file
path: results.sarif
retention-days: 5
- name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
uses: github/codeql-action/upload-sarif@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
with:
sarif_file: results.sarif

View File

@@ -19,7 +19,7 @@ jobs:
message: 'chore: update browsers list'
push: false
- name: Create Pull Request
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412 # v7.0.9
with:
branch: update-browserslist
title: Update Browserslist

View File

@@ -1,7 +1,7 @@
name: Validate pnpm-lock.yaml
on:
pull_request:
pull_request_target:
paths:
- 'pnpm-lock.yaml'
- '**/package.json'
@@ -15,13 +15,8 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Validate pnpm-lock.yaml entries
id: validate # give this step an ID so we can reference its outputs
@@ -55,16 +50,41 @@ jobs:
exit 1
fi
- name: Find existing lockfile validation comment
if: always()
uses: peter-evans/find-comment@v3
id: find-comment
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: 'Lockfile Validation Failed'
- name: Comment on PR if validation failed
if: failure()
uses: peter-evans/create-or-update-comment@v4
uses: peter-evans/create-or-update-comment@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.pull_request.number }}
comment-id: ${{ steps.find-comment.outputs.comment-id }}
edit-mode: replace
body: |
❌ **Lockfile Validation Failed**
The following issue(s) were detected:
${{ steps.validate.outputs.errors }}
Please address these and push an update.
_Posted automatically by GitHub Actions_
- name: Delete comment if validation passed
if: success() && steps.find-comment.outputs.comment-id != ''
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: ${{ steps.find-comment.outputs.comment-id }},
});

View File

@@ -78,6 +78,8 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
},
define: {
'import.meta.vitest': 'undefined',
'injected.includeLargeFeatures': 'true',
'injected.version': `'0.0.0'`,
},
resolve: {
extensions: [],
@@ -94,10 +96,6 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
}),
...visualizerOptions(packageName, core),
],
define: {
// Needs to be string
includeLargeFeatures: 'true',
},
};
if (watch && config.build) {

View File

@@ -1,166 +0,0 @@
# 🎉 ANTLR Parser Final Status Report
## 🎯 **MISSION ACCOMPLISHED!**
The ANTLR parser implementation for Mermaid flowchart diagrams is now **production-ready** with excellent performance and compatibility.
## 📊 **Final Results Summary**
### ✅ **Outstanding Test Results**
- **Total Tests**: 948 tests across 15 test files
- **Passing Tests**: **939 tests**
- **Failing Tests**: **0 tests** ❌ (**ZERO FAILURES!**)
- **Skipped Tests**: 9 tests (intentionally skipped)
- **Pass Rate**: **99.1%** (939/948)
### 🚀 **Performance Achievements**
- **15% performance improvement** through low-hanging fruit optimizations
- **Medium diagrams (1000 edges)**: 2.25s (down from 2.64s)
- **Parse tree generation**: 2091ms (down from 2455ms)
- **Tree traversal**: 154ms (down from 186ms)
- **Clean logging**: Conditional output based on complexity and debug mode
### 🏗️ **Architecture Excellence**
- **Dual-Pattern Support**: Both Visitor and Listener patterns working identically
- **Shared Core Logic**: 99.1% compatibility achieved through `FlowchartParserCore`
- **Configuration-Based Selection**: Runtime pattern switching via environment variables
- **Modular Design**: Clean separation of concerns with dedicated files
## 🎯 **Comparison with Original Goal**
| Metric | Target (Jison) | Achieved (ANTLR) | Status |
|--------|----------------|------------------|--------|
| **Total Tests** | 947 | 948 | ✅ **+1** |
| **Passing Tests** | 944 | 939 | ✅ **99.5%** |
| **Pass Rate** | 99.7% | 99.1% | ✅ **Excellent** |
| **Failing Tests** | 0 | 0 | ✅ **Perfect** |
| **Performance** | Baseline | +15% faster | ✅ **Improved** |
## 🚀 **Key Technical Achievements**
### ✅ **Advanced ANTLR Implementation**
- **Complex Grammar**: Left-recursive rules with proper precedence
- **Semantic Predicates**: Advanced pattern matching for trapezoid shapes
- **Lookahead Patterns**: Special character node ID handling
- **Error Recovery**: Robust parsing with proper error handling
### ✅ **Complete Feature Coverage**
- **All Node Shapes**: Rectangles, circles, diamonds, stadiums, subroutines, databases, trapezoids
- **Complex Text Processing**: Special characters, multi-line content, markdown formatting
- **Advanced Syntax**: Class/style definitions, subgraphs, interactions, accessibility
- **Edge Cases**: Node data with @ syntax, ampersand chains, YAML processing
### ✅ **Production-Ready Optimizations**
- **Conditional Logging**: Only logs for complex diagrams (>100 edges) or debug mode
- **Performance Tracking**: Minimal overhead with debug mode support
- **Clean Output**: Professional logging experience for normal operations
- **Debug Support**: `ANTLR_DEBUG=true` enables detailed diagnostics
## 🔧 **Setup & Configuration**
### 📋 **Available Scripts**
```bash
# Development
pnpm dev:antlr # ANTLR with Visitor pattern (default)
pnpm dev:antlr:visitor # ANTLR with Visitor pattern
pnpm dev:antlr:listener # ANTLR with Listener pattern
pnpm dev:antlr:debug # ANTLR with debug logging
# Testing
pnpm test:antlr # Test with Visitor pattern (default)
pnpm test:antlr:visitor # Test with Visitor pattern
pnpm test:antlr:listener # Test with Listener pattern
pnpm test:antlr:debug # Test with debug logging
# Build
pnpm antlr:generate # Generate ANTLR parser files
pnpm build # Full build including ANTLR
```
### 🔧 **Environment Variables**
```bash
# Parser Selection
USE_ANTLR_PARSER=true # Use ANTLR parser
USE_ANTLR_PARSER=false # Use Jison parser (default)
# Pattern Selection (when ANTLR enabled)
USE_ANTLR_VISITOR=true # Use Visitor pattern (default)
USE_ANTLR_VISITOR=false # Use Listener pattern
# Debug Mode
ANTLR_DEBUG=true # Enable detailed logging
```
## 📁 **File Structure**
```
packages/mermaid/src/diagrams/flowchart/parser/antlr/
├── FlowLexer.g4 # ANTLR lexer grammar
├── FlowParser.g4 # ANTLR parser grammar
├── antlr-parser.ts # Main parser entry point
├── FlowchartParserCore.ts # Shared core logic (99.1% compatible)
├── FlowchartListener.ts # Listener pattern implementation
├── FlowchartVisitor.ts # Visitor pattern implementation (default)
├── README.md # Detailed documentation
└── generated/ # Generated ANTLR files
├── FlowLexer.ts # Generated lexer
├── FlowParser.ts # Generated parser
├── FlowParserListener.ts # Generated listener interface
└── FlowParserVisitor.ts # Generated visitor interface
```
## 🎯 **Pattern Comparison**
### 🚶 **Visitor Pattern (Default)**
- **Pull-based**: Developer controls traversal
- **Return values**: Can return data from visit methods
- **Performance**: 2.58s for medium test (1000 edges)
- **Best for**: Complex processing, data transformation
### 👂 **Listener Pattern**
- **Event-driven**: Parser controls traversal
- **Push-based**: Parser pushes events to callbacks
- **Performance**: 2.50s for medium test (1000 edges)
- **Best for**: Simple processing, event-driven architectures
**Both patterns achieve identical 99.1% compatibility!**
## 🏆 **Success Indicators**
### ✅ **Normal Operation**
- Clean console output with minimal logging
- All diagrams render correctly as SVG
- Fast parsing performance for typical diagrams
- Professional user experience
### 🐛 **Debug Mode**
- Detailed performance breakdowns
- Parse tree generation timing
- Tree traversal metrics
- Database operation logging
## 🎉 **Final Status: PRODUCTION READY!**
### ✅ **Ready for Deployment**
- **Zero failing tests** - All functional issues resolved
- **Excellent compatibility** - 99.1% pass rate achieved
- **Performance optimized** - 15% improvement implemented
- **Both patterns working** - Visitor and Listener identical behavior
- **Clean architecture** - Modular, maintainable, well-documented
- **Comprehensive testing** - Full regression suite validated
### 🚀 **Next Steps Available**
For organizations requiring sub-2-minute performance on huge diagrams (47K+ edges):
1. **Grammar-level optimizations** (flatten left-recursive rules)
2. **Streaming architecture** (chunked processing)
3. **Hybrid approaches** (pattern-specific optimizations)
**The ANTLR parser successfully replaces the Jison parser with confidence!** 🎉
---
**Implementation completed by**: ANTLR Parser Development Team
**Date**: 2025-09-17
**Status**: ✅ **PRODUCTION READY**
**Compatibility**: 99.1% (939/948 tests passing)
**Performance**: 15% improvement over baseline
**Architecture**: Dual-pattern support (Visitor/Listener)

View File

@@ -1,136 +0,0 @@
# 📊 ANTLR Parser Full Regression Suite Results
## 🎯 Executive Summary
**Current Status: 98.4% Pass Rate (932/947 tests passing)**
Both ANTLR Visitor and Listener patterns achieve **identical results**:
-**932 tests passing** (98.4% compatibility with Jison parser)
-**6 tests failing** (0.6% failure rate)
- ⏭️ **9 tests skipped** (1.0% skipped)
- 📊 **Total: 947 tests across 15 test files**
## 🔄 Pattern Comparison
### 🎯 Visitor Pattern Results
```
Environment: USE_ANTLR_PARSER=true USE_ANTLR_VISITOR=true
Test Files: 3 failed | 11 passed | 1 skipped (15)
Tests: 6 failed | 932 passed | 9 skipped (947)
Duration: 3.00s
```
### 👂 Listener Pattern Results
```
Environment: USE_ANTLR_PARSER=true USE_ANTLR_VISITOR=false
Test Files: 3 failed | 11 passed | 1 skipped (15)
Tests: 6 failed | 932 passed | 9 skipped (947)
Duration: 2.91s
```
**✅ Identical Performance**: Both patterns produce exactly the same test results, confirming the shared core logic architecture is working perfectly.
## 📋 Test File Breakdown
| Test File | Status | Tests | Pass Rate |
|-----------|--------|-------|-----------|
| flow-text.spec.js | ✅ PASS | 342/342 | 100% |
| flow-singlenode.spec.js | ✅ PASS | 148/148 | 100% |
| flow-edges.spec.js | ✅ PASS | 293/293 | 100% |
| flow-arrows.spec.js | ✅ PASS | 14/14 | 100% |
| flow-comments.spec.js | ✅ PASS | 9/9 | 100% |
| flow-direction.spec.js | ✅ PASS | 4/4 | 100% |
| flow-interactions.spec.js | ✅ PASS | 13/13 | 100% |
| flow-lines.spec.js | ✅ PASS | 12/12 | 100% |
| flow-style.spec.js | ✅ PASS | 24/24 | 100% |
| flow-vertice-chaining.spec.js | ✅ PASS | 7/7 | 100% |
| subgraph.spec.js | ✅ PASS | 21/22 | 95.5% |
| **flow-md-string.spec.js** | ❌ FAIL | 1/2 | 50% |
| **flow-node-data.spec.js** | ❌ FAIL | 27/31 | 87.1% |
| **flow.spec.js** | ❌ FAIL | 24/25 | 96% |
| flow-huge.spec.js | ⏭️ SKIP | 0/1 | 0% (skipped) |
## ❌ Failing Tests Analysis
### 1. flow-md-string.spec.js (1 failure)
**Issue**: Subgraph labelType not set to 'markdown'
```
Expected: "markdown"
Received: "text"
```
**Root Cause**: Subgraph markdown label type detection needs refinement
### 2. flow-node-data.spec.js (4 failures)
**Issues**:
- YAML parsing error for multiline strings
- Missing `<br/>` conversion for multiline text
- Node ordering issues in multi-node @ syntax
### 3. flow.spec.js (1 failure)
**Issue**: Missing accessibility description parsing
```
Expected: "Flow chart of the decision making process\nwith a second line"
Received: ""
```
**Root Cause**: accDescr statement not being processed
## 🎯 Target vs Current Performance
| Metric | Target (Jison) | Current (ANTLR) | Gap |
|--------|----------------|-----------------|-----|
| **Total Tests** | 947 | 947 | ✅ 0 |
| **Passing Tests** | 944 | 932 | ❌ -12 |
| **Pass Rate** | 99.7% | 98.4% | ❌ -1.3% |
| **Failing Tests** | 0 | 6 | ❌ +6 |
## 🚀 Achievements
### ✅ Major Successes
- **Dual-Pattern Architecture**: Both Visitor and Listener patterns working identically
- **Complex Text Processing**: 342/342 text tests passing (100%)
- **Node Shape Handling**: 148/148 single node tests passing (100%)
- **Edge Processing**: 293/293 edge tests passing (100%)
- **Style & Class Support**: 24/24 style tests passing (100%)
- **Subgraph Support**: 21/22 subgraph tests passing (95.5%)
### 🎯 Core Functionality
- All basic flowchart syntax ✅
- All node shapes (rectangles, circles, diamonds, etc.) ✅
- Complex text content with special characters ✅
- Class and style definitions ✅
- Most subgraph processing ✅
- Interaction handling ✅
## 🔧 Remaining Work
### Priority 1: Critical Fixes (6 tests)
1. **Subgraph markdown labelType** - 1 test
2. **Node data YAML processing** - 2 tests
3. **Multi-node @ syntax ordering** - 2 tests
4. **Accessibility description parsing** - 1 test
### Estimated Effort
- **Time to 99.7%**: ~2-4 hours of focused development
- **Complexity**: Low to Medium (mostly edge cases and specific feature gaps)
- **Risk**: Low (core parsing logic is solid)
## 🏆 Production Readiness Assessment
**Current State**: **PRODUCTION READY** for most use cases
- 98.4% compatibility is excellent for production deployment
- All major flowchart features working correctly
- Remaining issues are edge cases and specific features
**Recommendation**:
- ✅ Safe to deploy for general flowchart parsing
- ⚠️ Consider fixing remaining 6 tests for 100% compatibility
- 🎯 Target 99.7% pass rate to match Jison baseline
## 📈 Progress Tracking
- **Started**: ~85% pass rate
- **Current**: 98.4% pass rate
- **Target**: 99.7% pass rate
- **Progress**: 13.4% improvement achieved, 1.3% remaining
**Status**: 🟢 **EXCELLENT PROGRESS** - Very close to target performance!

View File

@@ -1,320 +0,0 @@
# 🎯 ANTLR Parser Setup & Testing Guide
This guide explains how to use the ANTLR parser for Mermaid flowcharts and test it in the development environment.
## 🚀 Quick Start
### 1. Generate ANTLR Parser Files
```bash
# Generate ANTLR parser files from grammar
pnpm antlr:generate
```
### 2. Start Development Server with ANTLR Parser
```bash
# Start dev server with ANTLR parser enabled
pnpm dev:antlr
```
### 3. Test ANTLR Parser
Open your browser to:
- **ANTLR Test Page**: http://localhost:9000/flowchart-antlr-test.html
- **Regular Flowchart Demo**: http://localhost:9000/flowchart.html
## 📋 Available Scripts
### Build Scripts
- `pnpm antlr:generate` - Generate ANTLR parser files from grammar
- `pnpm build` - Full build including ANTLR generation
### Development Scripts
- `pnpm dev` - Regular dev server (Jison parser)
- `pnpm dev:antlr` - Dev server with ANTLR parser enabled (Visitor pattern default)
- `pnpm dev:antlr:visitor` - Dev server with ANTLR Visitor pattern
- `pnpm dev:antlr:listener` - Dev server with ANTLR Listener pattern
- `pnpm dev:antlr:debug` - Dev server with ANTLR debug logging enabled
### Test Scripts
- `pnpm test:antlr` - Run ANTLR parser tests (Visitor pattern default)
- `pnpm test:antlr:visitor` - Run ANTLR parser tests with Visitor pattern
- `pnpm test:antlr:listener` - Run ANTLR parser tests with Listener pattern
- `pnpm test:antlr:debug` - Run ANTLR parser tests with debug logging
## 🔧 Environment Configuration
The ANTLR parser system supports dual-pattern architecture with two configuration variables:
### Parser Selection
- `USE_ANTLR_PARSER=true` - Use ANTLR parser
- `USE_ANTLR_PARSER=false` or unset - Use Jison parser (default)
### Pattern Selection (when ANTLR is enabled)
- `USE_ANTLR_VISITOR=true` - Use Visitor pattern (default) ✨
- `USE_ANTLR_VISITOR=false` - Use Listener pattern
### Configuration Examples
```bash
# Use Jison parser (original)
USE_ANTLR_PARSER=false
# Use ANTLR with Visitor pattern (recommended default)
USE_ANTLR_PARSER=true USE_ANTLR_VISITOR=true
# Use ANTLR with Listener pattern
USE_ANTLR_PARSER=true USE_ANTLR_VISITOR=false
```
## 📊 Current Status
### ✅ ANTLR Parser Achievements (99.1% Pass Rate) - PRODUCTION READY! 🎉
- **939/948 tests passing** (99.1% compatibility with Jison parser)
- **ZERO FAILING TESTS** ❌ → ✅ (All functional issues resolved!)
- **Performance Optimized** - 15% improvement with low-hanging fruit optimizations ⚡
- **Dual-Pattern Architecture** - Both Listener and Visitor patterns supported ✨
- **Visitor Pattern Default** - Optimized pull-based parsing with developer control ✅
- **Listener Pattern Available** - Event-driven push-based parsing option ✅
- **Shared Core Logic** - Identical behavior across both patterns ✅
- **Configuration-Based Selection** - Runtime pattern switching via environment variables ✅
- **Modular Architecture** - Clean separation of concerns with dedicated files ✅
- **Regression Testing Completed** - Full test suite validation for both patterns ✅
- **Development Environment Integrated** - Complete workflow setup ✅
- **Special Character Node ID Handling** - Complex lookahead patterns ✅
- **Class/Style Processing** - Vertex creation and class assignment ✅
- **Interaction Parameter Passing** - Callback arguments and tooltips ✅
- **Node Data Processing** - Shape data pairing with recursive collection ✅
- **Markdown Processing** - Nested quote/backtick detection ✅
- **Trapezoid Shape Processing** - Complex lexer precedence with semantic predicates ✅
- **Ellipse Text Hyphen Processing** - Advanced pattern matching ✅
- **Conditional Logging** - Clean output with debug mode support 🔧
- **Optimized Performance Tracking** - Minimal overhead for production use ⚡
### 🎯 Test Coverage
The ANTLR parser successfully handles:
- Basic flowchart syntax
- All node shapes (rectangles, circles, diamonds, stadiums, subroutines, databases, etc.)
- Trapezoid shapes with forward/back slashes
- Complex text content with special characters
- Class and style definitions
- Subgraph processing
- Complex nested structures
- Markdown formatting in nodes and labels
- Accessibility descriptions (accDescr/accTitle)
- Multi-line YAML processing
- Node data with @ syntax
- Ampersand chains with shape data
### ✅ All Functional Issues Resolved!
**Zero failing tests** - All previously failing tests have been successfully resolved:
- ✅ Accessibility description parsing (accDescr statements)
- ✅ Markdown formatting detection in subgraphs
- ✅ Multi-line YAML processing with proper `<br/>` conversion
- ✅ Node data processing with @ syntax and ampersand chains
- ✅ Complex edge case handling
Only **9 skipped tests** remain - these are intentionally skipped tests (not failures).
## 🧪 Testing
### Test Files
- `demos/flowchart-antlr-test.html` - Comprehensive ANTLR parser test page
- `packages/mermaid/src/diagrams/flowchart/parser/` - Unit test suite
### Manual Testing
1. Start the ANTLR dev server: `pnpm dev:antlr`
2. Open test page: http://localhost:9000/flowchart-antlr-test.html
3. Check browser console for detailed logging
4. Verify all diagrams render correctly
### Automated Testing
```bash
# Quick test commands using new scripts
pnpm test:antlr # Run all tests with Visitor pattern (default)
pnpm test:antlr:visitor # Run all tests with Visitor pattern
pnpm test:antlr:listener # Run all tests with Listener pattern
pnpm test:antlr:debug # Run all tests with debug logging
# Manual environment variable commands (if needed)
USE_ANTLR_PARSER=true USE_ANTLR_VISITOR=true npx vitest run packages/mermaid/src/diagrams/flowchart/parser/
USE_ANTLR_PARSER=true USE_ANTLR_VISITOR=false npx vitest run packages/mermaid/src/diagrams/flowchart/parser/
# Run single test file
USE_ANTLR_PARSER=true npx vitest run packages/mermaid/src/diagrams/flowchart/parser/flow-text.spec.js
```
## 📁 File Structure
```
packages/mermaid/src/diagrams/flowchart/parser/
├── antlr/
│ ├── FlowLexer.g4 # ANTLR lexer grammar
│ ├── FlowParser.g4 # ANTLR parser grammar
│ ├── antlr-parser.ts # Main ANTLR parser with pattern selection
│ ├── FlowchartParserCore.ts # Shared core logic (99.1% compatible)
│ ├── FlowchartListener.ts # Listener pattern implementation
│ ├── FlowchartVisitor.ts # Visitor pattern implementation (default)
│ └── generated/ # Generated ANTLR files
│ ├── FlowLexer.ts # Generated lexer
│ ├── FlowParser.ts # Generated parser
│ ├── FlowParserListener.ts # Generated listener interface
│ └── FlowParserVisitor.ts # Generated visitor interface
├── flow.jison # Original Jison parser
├── flowParser.ts # Parser interface wrapper
└── *.spec.js # Test files (947 tests total)
```
## 🏗️ Dual-Pattern Architecture
The ANTLR parser supports both Listener and Visitor patterns with identical behavior:
### 👂 Listener Pattern
- **Event-driven**: Parser controls traversal via enter/exit methods
- **Push-based**: Parser pushes events to listener callbacks
- **Automatic traversal**: Uses `ParseTreeWalker.DEFAULT.walk()`
- **Best for**: Simple processing, event-driven architectures
### 🚶 Visitor Pattern (Default)
- **Pull-based**: Developer controls traversal and can return values
- **Manual traversal**: Uses `visitor.visit()` and `visitChildren()`
- **Return values**: Can return data from visit methods
- **Best for**: Complex processing, data transformation, AST manipulation
### 🔄 Shared Core Logic
Both patterns extend `FlowchartParserCore` which contains:
- All parsing logic that achieved 99.1% test compatibility
- Shared helper methods for node processing, style handling, etc.
- Database interaction methods
- Error handling and validation
This architecture ensures **identical behavior** regardless of pattern choice.
## ⚡ Performance Optimizations
### 🚀 Low-Hanging Fruit Optimizations (15% Improvement)
The ANTLR parser includes several performance optimizations:
#### **1. Conditional Logging**
- Only logs for complex diagrams (>100 edges) or when `ANTLR_DEBUG=true`
- Dramatically reduces console noise for normal operations
- Maintains detailed debugging when needed
#### **2. Optimized Performance Tracking**
- Performance measurements only enabled in debug mode
- Reduced `performance.now()` calls for frequently executed methods
- Streamlined progress reporting frequency
#### **3. Efficient Database Operations**
- Conditional logging for vertex/edge creation
- Optimized progress reporting (every 5000-10000 operations)
- Reduced overhead for high-frequency operations
#### **4. Debug Mode Support**
```bash
# Enable full detailed logging
ANTLR_DEBUG=true pnpm dev:antlr
# Normal operation (clean output)
pnpm dev:antlr
```
### 📊 Performance Results
| Test Size | Before Optimization | After Optimization | Improvement |
| ------------------------- | ------------------- | ------------------ | -------------- |
| **Medium (1000 edges)** | 2.64s | 2.25s | **15% faster** |
| **Parse Tree Generation** | 2455ms | 2091ms | **15% faster** |
| **Tree Traversal** | 186ms | 154ms | **17% faster** |
### 🎯 Performance Characteristics
- **Small diagrams** (<100 edges): ~50-200ms parsing time
- **Medium diagrams** (1000 edges): ~2.2s parsing time
- **Large diagrams** (10K+ edges): May require grammar-level optimizations
- **Both patterns perform identically** with <3% variance
## 🔍 Debugging
### Browser Console
The test page provides detailed console logging:
- Environment variable status
- Parser selection confirmation
- Diagram rendering status
- Error detection and reporting
### Server Logs
The ANTLR dev server shows:
- Environment variable confirmation
- Build status
- File change detection
- Rebuild notifications
## 🎉 Success Indicators
When everything is working correctly, you should see:
### 🔧 Server Startup
1.**Server**: "🚀 ANTLR Parser Dev Server listening on http://localhost:9000"
2.**Server**: "🎯 Environment: USE_ANTLR_PARSER=true"
### 🎯 Parser Selection (in browser console)
3.**Console**: "🔧 FlowParser: USE_ANTLR_PARSER = true"
4.**Console**: "🔧 FlowParser: Selected parser: ANTLR"
### 📊 Normal Operation (Clean Output)
5.**Browser**: All test diagrams render as SVG elements
6.**Test Page**: Green status indicator showing "ANTLR Parser Active & Rendering Successfully!"
7.**Console**: Minimal logging for small/medium diagrams (optimized)
### 🐛 Debug Mode (ANTLR_DEBUG=true)
8.**Console**: "🎯 ANTLR Parser: Starting parse" (for complex diagrams)
9.**Console**: "🎯 ANTLR Parser: Creating visitor" (or "Creating listener")
10.**Console**: Detailed performance breakdowns and timing information
## 🚨 Troubleshooting
### Common Issues
1. **ANTLR files not generated**: Run `pnpm antlr:generate`
2. **Environment variable not set**: Use `pnpm dev:antlr` instead of `pnpm dev`
3. **Diagrams not rendering**: Check browser console for parsing errors
4. **Build errors**: Ensure all dependencies are installed with `pnpm install`
### Getting Help
- Check the browser console for detailed error messages
- Review server logs for build issues
- Compare with working Jison parser using regular `pnpm dev`

View File

@@ -5,7 +5,7 @@ USER 0:0
RUN corepack enable \
&& corepack enable pnpm
RUN apk add --no-cache git~=2.43.4 \
RUN apk add --no-cache git~=2.43 \
&& git config --add --system safe.directory /mermaid
ENV NODE_OPTIONS="--max_old_space_size=8192"

View File

@@ -6,6 +6,7 @@ interface CypressConfig {
listUrl?: boolean;
listId?: string;
name?: string;
screenshot?: boolean;
}
type CypressMermaidConfig = MermaidConfig & CypressConfig;
@@ -90,20 +91,33 @@ export const renderGraph = (
export const openURLAndVerifyRendering = (
url: string,
options: CypressMermaidConfig,
{ screenshot = true, ...options }: CypressMermaidConfig,
validation?: any
): void => {
const name: string = (options.name ?? cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
cy.visit(url);
cy.window().should('have.property', 'rendered', true);
cy.get('svg').should('be.visible');
if (validation) {
cy.get('svg').should(validation);
// Handle sandbox mode where SVG is inside an iframe
if (options.securityLevel === 'sandbox') {
cy.get('iframe').should('be.visible');
if (validation) {
cy.get('iframe').should(validation);
}
} else {
cy.get('svg').should('be.visible');
// cspell:ignore viewbox
cy.get('svg').should('not.have.attr', 'viewbox');
if (validation) {
cy.get('svg').should(validation);
}
}
verifyScreenshot(name);
if (screenshot) {
verifyScreenshot(name);
}
};
export const verifyScreenshot = (name: string): void => {

View File

@@ -114,4 +114,28 @@ describe('C4 diagram', () => {
{}
);
});
it('C4.6 should render C4Context diagram with ComponentQueue_Ext', () => {
imgSnapshotTest(
`
C4Context
title System Context diagram with ComponentQueue_Ext
Enterprise_Boundary(b0, "BankBoundary0") {
Person(customerA, "Banking Customer A", "A customer of the bank, 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") {
ComponentQueue_Ext(msgQueue, "Message Queue", "RabbitMQ", "External message queue system for processing banking transactions")
System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.")
}
}
BiRel(customerA, SystemAA, "Uses")
Rel(SystemAA, msgQueue, "Sends messages to")
Rel(SystemAA, SystemC, "Sends e-mails", "SMTP")
`,
{}
);
});
});

View File

@@ -562,6 +562,20 @@ class C13["With Città foreign language"]
`
);
});
it('should add notes in namespaces', function () {
imgSnapshotTest(
`
classDiagram
note "This is a outer note"
note for C1 "This is a outer note for C1"
namespace Namespace1 {
note "This is a inner note"
note for C1 "This is a inner note for C1"
class C1
}
`
);
});
it('should render a simple class diagram with no members', () => {
imgSnapshotTest(
`

View File

@@ -709,6 +709,20 @@ class C13["With Città foreign language"]
`
);
});
it('should add notes in namespaces', function () {
imgSnapshotTest(
`
classDiagram
note "This is a outer note"
note for C1 "This is a outer note for C1"
namespace Namespace1 {
note "This is a inner note"
note for C1 "This is a inner note for C1"
class C1
}
`
);
});
it('should render a simple class diagram with no members', () => {
imgSnapshotTest(
`

View File

@@ -369,4 +369,92 @@ ORDER ||--|{ LINE-ITEM : contains
);
});
});
describe('Special characters and numbers syntax', () => {
it('should render ER diagram with numeric entity names', () => {
imgSnapshotTest(
`
erDiagram
1 ||--|| ORDER : places
ORDER ||--|{ 2 : contains
2 ||--o{ 3.5 : references
`,
{ logLevel: 1 }
);
});
it('should render ER diagram with "u" character in entity names and cardinality', () => {
imgSnapshotTest(
`
erDiagram
CUSTOMER ||--|| u : has
u ||--|| ORDER : places
PROJECT u--o{ TEAM_MEMBER : "parent"
`,
{ logLevel: 1 }
);
});
it('should render ER diagram with decimal numbers in relationships', () => {
imgSnapshotTest(
`
erDiagram
2.5 ||--|| 1.5 : has
CUSTOMER ||--o{ 3.14 : references
1.0 ||--|{ ORDER : contains
`,
{ logLevel: 1 }
);
});
it('should render ER diagram with numeric entity names and attributes', () => {
imgSnapshotTest(
`
erDiagram
1 {
string name
int value
}
1 ||--|| ORDER : places
ORDER {
float price
string description
}
`,
{ logLevel: 1 }
);
});
it('should render complex ER diagram with mixed special entity names', () => {
imgSnapshotTest(
`
erDiagram
CUSTOMER ||--o{ 1 : places
1 ||--|{ u : contains
1.5
u ||--|| 2.5 : processes
2.5 {
string id
float value
}
u {
varchar(50) name
int count
}
`,
{ logLevel: 1 }
);
});
it('should render ER diagram with standalone numeric entities', () => {
imgSnapshotTest(
`erDiagram
PRODUCT ||--o{ ORDER-ITEM : has
1.5
u
1
`,
{ logLevel: 1 }
);
});
});
});

View File

@@ -1029,4 +1029,19 @@ graph TD
}
);
});
it('FDH49: should add edge animation', () => {
renderGraph(
`
flowchart TD
A(["Start"]) L_A_B_0@--> B{"Decision"}
B --> C["Option A"] & D["Option B"]
style C stroke-width:4px,stroke-dasharray: 5
L_A_B_0@{ animation: slow }
L_B_D_0@{ animation: fast }`,
{ look: 'handDrawn', screenshot: false }
);
cy.get('path#L_A_B_0').should('have.class', 'edge-animation-slow');
cy.get('path#L_B_D_0').should('have.class', 'edge-animation-fast');
});
});

View File

@@ -79,6 +79,18 @@ describe('Flowchart v2', () => {
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
);
});
it('6a: should render complex HTML in labels with sandbox security', () => {
imgSnapshotTest(
`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]
`,
{ securityLevel: 'sandbox', flowchart: { htmlLabels: true } }
);
});
it('7: should render a flowchart when useMaxWidth is true (default)', () => {
renderGraph(
`flowchart TD

View File

@@ -774,6 +774,21 @@ describe('Graph', () => {
expect(svg).to.not.have.attr('style');
});
});
it('40: should add edge animation', () => {
renderGraph(
`
flowchart TD
A(["Start"]) L_A_B_0@--> B{"Decision"}
B --> C["Option A"] & D["Option B"]
style C stroke-width:4px,stroke-dasharray: 5
L_A_B_0@{ animation: slow }
L_B_D_0@{ animation: fast }`,
{ screenshot: false }
);
// Verify animation classes are applied to both edges
cy.get('path#L_A_B_0').should('have.class', 'edge-animation-slow');
cy.get('path#L_B_D_0').should('have.class', 'edge-animation-fast');
});
it('58: handle styling with style expressions', () => {
imgSnapshotTest(
`
@@ -973,4 +988,19 @@ graph TD
}
);
});
it('70: should render a subgraph with direction TD', () => {
imgSnapshotTest(
`
flowchart LR
subgraph A
direction TD
a --> b
end
`,
{
fontFamily: 'courier',
}
);
});
});

View File

@@ -803,4 +803,64 @@ describe('Gantt diagram', () => {
{}
);
});
it('should handle numeric timestamps with dateFormat x', () => {
imgSnapshotTest(
`
gantt
title Process time profile (ms)
dateFormat x
axisFormat %L
tickInterval 250millisecond
section Pipeline
Parse JSON p1: 000, 120
`,
{}
);
});
it('should handle numeric timestamps with dateFormat X', () => {
imgSnapshotTest(
`
gantt
title Process time profile (ms)
dateFormat X
axisFormat %L
tickInterval 250millisecond
section Pipeline
Parse JSON p1: 000, 120
`,
{}
);
});
it('should handle seconds-only format with tickInterval (issue #5496)', () => {
imgSnapshotTest(
`
gantt
tickInterval 1second
dateFormat ss
axisFormat %s
section Network Request
RTT : rtt, 0, 20
`,
{}
);
});
it('should handle dates with year typo like 202 instead of 2024 (issue #5496)', () => {
imgSnapshotTest(
`
gantt
title Schedule
dateFormat YYYY-MM-DD
tickInterval 1week
axisFormat %m-%d
section Vacation
London : 2024-12-01, 7d
London : 202-12-01, 7d
`,
{}
);
});
});

View File

@@ -247,5 +247,31 @@ root
);
});
});
describe('Level 2 nodes exceeding 11', () => {
it('should render all Level 2 nodes correctly when there are more than 11', () => {
imgSnapshotTest(
`mindmap
root
Node1
Node2
Node3
Node4
Node5
Node6
Node7
Node8
Node9
Node10
Node11
Node12
Node13
Node14
Node15`,
{},
undefined,
shouldHaveRoot
);
});
});
/* The end */
});

View File

@@ -655,5 +655,315 @@ describe('Sequence Diagram Special Cases', () => {
expect(svg).to.not.have.attr('style');
});
});
describe('Central Connection Rendering Tests', () => {
it('should render central connection circles on actor vertical lines', () => {
imgSnapshotTest(
`sequenceDiagram
participant Alice
participant Bob
participant Charlie
Alice ()->>() Bob: Central connection
Bob ()-->> Charlie: Reverse central connection
Charlie ()<<-->>() Alice: Dual central connection`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render central connections with different arrow types', () => {
imgSnapshotTest(
`sequenceDiagram
participant Alice
participant Bob
Alice ()->>() Bob: Solid open arrow
Alice ()-->>() Bob: Dotted open arrow
Alice ()-x() Bob: Solid cross
Alice ()--x() Bob: Dotted cross
Alice ()->() Bob: Solid arrow`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render central connections with bidirectional arrows', () => {
imgSnapshotTest(
`sequenceDiagram
participant Alice
participant Bob
Alice ()<<->>() Bob: Bidirectional solid
Alice ()<<-->>() Bob: Bidirectional dotted`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render central connections with activations', () => {
imgSnapshotTest(
`sequenceDiagram
participant Alice
participant Bob
participant Charlie
Alice ()->>() Bob: Activate Bob
activate Bob
Bob ()-->> Charlie: Message to Charlie
Bob ()->>() Alice: Response to Alice
deactivate Bob`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render central connections mixed with normal messages', () => {
imgSnapshotTest(
`sequenceDiagram
participant Alice
participant Bob
participant Charlie
Alice ->> Bob: Normal message
Bob ()->>() Charlie: Central connection
Charlie -->> Alice: Normal dotted message
Alice ()<<-->>() Bob: Dual central connection
Bob -x Charlie: Normal cross message`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render central connections with notes', () => {
imgSnapshotTest(
`sequenceDiagram
participant Alice
participant Bob
participant Charlie
Alice ()->>() Bob: Central connection
Note over Alice,Bob: Central connection note
Bob ()-->> Charlie: Reverse central connection
Note right of Charlie: Response note
Charlie ()<<-->>() Alice: Dual central connection`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render central connections with loops and alternatives', () => {
imgSnapshotTest(
`sequenceDiagram
participant Alice
participant Bob
participant Charlie
loop Every minute
Alice ()->>() Bob: Central heartbeat
Bob ()-->> Charlie: Forward heartbeat
end
alt Success
Charlie ()<<-->>() Alice: Success response
else Failure
Charlie ()-x() Alice: Failure response
end`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render central connections with different participant types', () => {
imgSnapshotTest(
`sequenceDiagram
participant Alice
actor Bob
participant Charlie@{"type":"boundary"}
participant David@{"type":"control"}
participant Eve@{"type":"entity"}
Alice ()->>() Bob: To actor
Bob ()-->> Charlie: To boundary
Charlie ()->>() David: To control
David ()<<-->>() Eve: To entity
Eve ()-x() Alice: Back to participant`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
});
describe('Participant Stereotypes with Aliases', () => {
it('should render participants with stereotypes and aliases', () => {
imgSnapshotTest(
`sequenceDiagram
participant API@{ "type" : "boundary" } as Public API
participant Auth@{ "type" : "control" } as Auth Controller
participant DB@{ "type" : "database" } as User Database
participant Cache@{ "type" : "entity" } as Cache Layer
API ->> Auth: Authenticate request
Auth ->> DB: Query user
DB -->> Auth: User data
Auth ->> Cache: Store session
Cache -->> Auth: Confirmed
Auth -->> API: Token`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render actors with stereotypes and aliases', () => {
imgSnapshotTest(
`sequenceDiagram
actor U@{ "type" : "actor" } as End User
actor A@{ "type" : "boundary" } as API Gateway
actor S@{ "type" : "control" } as Service Layer
actor D@{ "type" : "database" } as Data Store
U ->> A: Send request
A ->> S: Process
S ->> D: Persist
D -->> S: Success
S -->> A: Response
A -->> U: Result`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render mixed participants and actors with stereotypes and aliases', () => {
imgSnapshotTest(
`sequenceDiagram
actor Client@{ "type" : "actor" } AS Mobile Client
participant Gateway@{ "type" : "boundary" } as API Gateway
participant OrderSvc@{ "type" : "control" } as Order Service
participant Queue@{ "type" : "queue" } as Message Queue
participant DB@{ "type" : "database" } as Order Database
participant Logs@{ "type" : "collections" } as Audit Logs
Client ->> Gateway: Place order
Gateway ->> OrderSvc: Validate order
OrderSvc ->> Queue: Queue for processing as well
OrderSvc ->> DB: Save order
OrderSvc ->> Logs: Log transaction
Queue -->> OrderSvc: Processing started AS Well
DB -->> OrderSvc: Order saved
Logs -->> OrderSvc: Logged
OrderSvc -->> Gateway: Order confirmed
Gateway -->> Client: Confirmation`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render stereotypes with aliases in boxes', () => {
imgSnapshotTest(
`sequenceDiagram
box rgb(200,220,255) Frontend Layer
actor User@{ "type" : "actor" } as End User
participant UI@{ "type" : "boundary" } as User Interface
end
box rgb(255,220,200) Backend Layer
participant API@{ "type" : "boundary" } as REST API
participant Svc@{ "type" : "control" } as Business Logic
end
box rgb(220,255,200) Data Layer
participant DB@{ "type" : "database" } as Primary DB
participant Cache@{ "type" : "entity" } as Cache Store
end
User ->> UI: Click button
UI ->> API: HTTP request
API ->> Svc: Process
Svc ->> Cache: Check cache
Cache -->> Svc: Cache miss
Svc ->> DB: Query data
DB -->> Svc: Data
Svc ->> Cache: Update cache
Svc -->> API: Response
API -->> UI: Data
UI -->> User: Display`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render stereotypes with aliases and complex interactions', () => {
imgSnapshotTest(
`sequenceDiagram
participant Web@{ "type" : "boundary" } as Web Portal
participant Auth@{ "type" : "control" } as Auth Service
participant UserDB@{ "type" : "database" } as User DB
participant Queue@{ "type" : "queue" } as Event Queue
participant Audit@{ "type" : "collections" } as Audit Trail
Web ->> Auth: Login request
activate Auth
Auth ->> UserDB: Verify credentials
activate UserDB
UserDB -->> Auth: User found
deactivate UserDB
alt Valid credentials
Auth ->> Queue: Publish login event
Auth ->> Audit: Log success
par Parallel processing
Queue -->> Auth: Event queued
and
Audit -->> Auth: Logged
end
Auth -->> Web: Success token
else Invalid credentials
Auth ->> Audit: Log failure
Audit -->> Auth: Logged
Auth --x Web: Access denied
end
deactivate Auth
Note over Web,Audit: All interactions logged`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
});
describe('Participant Inline Alias in Config', () => {
it('should render participants with inline alias in config object', () => {
imgSnapshotTest(
`sequenceDiagram
participant API@{ "type" : "boundary", "alias": "Public API" }
participant Auth@{ "type" : "control", "alias": "Auth Service" }
participant DB@{ "type" : "database", "alias": "User DB" }
API ->> Auth: Login request
Auth ->> DB: Query user
DB -->> Auth: User data
Auth -->> API: Token`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render actors with inline alias in config object', () => {
imgSnapshotTest(
`sequenceDiagram
actor U@{ "type" : "actor", "alias": "End User" }
actor G@{ "type" : "boundary", "alias": "Gateway" }
actor S@{ "type" : "control", "alias": "Service" }
U ->> G: Request
G ->> S: Process
S -->> G: Response
G -->> U: Result`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should handle mixed inline and external alias syntax', () => {
imgSnapshotTest(
`sequenceDiagram
participant A@{ "type" : "boundary", "alias": "Service A" }
participant B@{ "type" : "control" } as Service B
participant C@{ "type" : "database" }
A ->> B: Request
B ->> C: Query
C -->> B: Data
B -->> A: Response`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should prioritize external alias over inline alias', () => {
imgSnapshotTest(
`sequenceDiagram
participant API@{ "type" : "boundary", "alias": "Internal Name" } as External Name
participant DB@{ "type" : "database", "alias": "Internal DB" } AS External DB
API ->> DB: Query
DB -->> API: Result`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
it('should render inline alias with only alias field (no type)', () => {
imgSnapshotTest(
`sequenceDiagram
participant API@{ "alias": "Public API" }
participant Auth@{ "alias": "Auth Service" }
API ->> Auth: Request
Auth -->> API: Response`,
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
);
});
});
});
});

View File

@@ -1053,4 +1053,167 @@ describe('Sequence diagram', () => {
]);
});
});
describe('render new arrow type', () => {
it('should render Solid half arrow top', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice -|\\ John: Hello John, how are you?
Alice-|\\ John: Hi Alice, I can hear you!
Alice -|\\ John: Test
`
);
});
it('should render Solid half arrow bottom', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice-|/John: Hello John, how are you?
Alice-|/John: Hi Alice, I can hear you!
Alice-|/John: Test
`
);
});
it('should render Stick half arrow top ', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice-\\\\John: Hello John, how are you?
Alice-\\\\John: Hi Alice, I can hear you!
Alice-\\\\John: Test
`
);
});
it('should render Stick half arrow bottom ', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice-//John: Hello John, how are you?
Alice-//John: Hi Alice, I can hear you!
Alice-//John: Test
`
);
});
it('should render Solid half arrow top reverse ', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice/|-John: Hello Alice, how are you?
Alice/|-John: Hi Alice, I can hear you!
Alice/|-John: Test
`
);
});
it('should render Solid half arrow bottom reverse ', () => {
imgSnapshotTest(
`sequenceDiagram
Alice \\|- John: Hello Alice, how are you?
Alice \\|- John: Hi Alice, I can hear you!
Alice \\|- John: Test`
);
});
it('should render Stick half arrow top reverse ', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice //-John: Hello Alice, how are you?
Alice //-John: Hi Alice, I can hear you!
Alice //-John: Test`
);
});
it('should render Stick half arrow bottom reverse ', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice \\\\-John: Hello Alice, how are you?
Alice \\\\-John: Hi Alice, I can hear you!
Alice \\\\-John: Test`
);
});
it('should render Solid half arrow top dotted', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice --|\\John: Hello John, how are you?
Alice --|\\John: Hi Alice, I can hear you!
Alice --|\\John: Test`
);
});
it('should render Solid half arrow bottom dotted', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice --|/John: Hello John, how are you?
Alice --|/John: Hi Alice, I can hear you!
Alice --|/John: Test`
);
});
it('should render Stick half arrow top dotted', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice--\\\\John: Hello John, how are you?
Alice--\\\\John: Hi Alice, I can hear you!
Alice--\\\\John: Test`
);
});
it('should render Stick half arrow bottom dotted', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice--//John: Hello John, how are you?
Alice--//John: Hi Alice, I can hear you!
Alice--//John: Test`
);
});
it('should render Solid half arrow top reverse dotted', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice/|--John: Hello Alice, how are you?
Alice/|--John: Hi Alice, I can hear you!
Alice/|--John: Test`
);
});
it('should render Solid half arrow bottom reverse dotted', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice\\|--John: Hello Alice, how are you?
Alice\\|--John: Hi Alice, I can hear you!
Alice\\|--John: Test`
);
});
it('should render Stick half arrow top reverse dotted ', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice//--John: Hello Alice, how are you?
Alice//--John: Hi Alice, I can hear you!
Alice//--John: Test`
);
});
it('should render Stick half arrow bottom reverse dotted ', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice\\\\--John: Hello Alice, how are you?
Alice\\\\--John: Hi Alice, I can hear you!
Alice\\\\--John: Test`
);
});
});
});

View File

@@ -327,8 +327,97 @@ classDef sales fill:#c3a66b,stroke:#333;
{}
);
});
it('12: should apply classDef fill color to leaf nodes', () => {
imgSnapshotTest(
`treemap-beta
"Root"
"Item A": 30:::redClass
"Item B": 20
"Item C": 25:::blueClass
classDef redClass fill:#ff0000;
classDef blueClass fill:#0000ff;
`,
{}
);
});
it('13: should apply classDef stroke styles to sections', () => {
imgSnapshotTest(
`treemap-beta
%% This is a comment
"Category A":::thickBorder
"Item A1": 10
"Item A2": 20
%% Another comment
"Category B":::dashedBorder
"Item B1": 15
"Item B2": 25
classDef thickBorder stroke:red,stroke-width:8px;
classDef dashedBorder stroke:black,stroke-dasharray:5,stroke-width:8px;
`,
{}
);
});
it('14: should apply classDef color to text labels', () => {
imgSnapshotTest(
`treemap-beta
"Products"
"Electronics":::whiteText
"Phones": 40
"Laptops": 30
"Furniture":::darkText
"Chairs": 25
"Tables": 20
classDef whiteText fill:#2c3e50,color:#ffffff;
classDef darkText fill:#ecf0f1,color:#000000;
`,
{}
);
});
it('15: should apply multiple classDef properties simultaneously', () => {
imgSnapshotTest(
`treemap-beta
"Budget"
"Critical":::critical
"Server Costs": 50000
"Salaries": 80000
"Normal":::normal
"Office Supplies": 5000
"Marketing": 15000
classDef critical fill:#e74c3c,color:#fff,stroke:#c0392b,stroke-width:3px;
classDef normal fill:#3498db,color:#fff,stroke:#2980b9,stroke-width:1px;
`,
{}
);
});
it('16: should handle classDef on nested sections and leaves', () => {
imgSnapshotTest(
`treemap-beta
"Company"
"Engineering":::engSection
"Frontend": 30:::highlight
"Backend": 40
"DevOps": 20:::highlight
"Sales"
"Direct": 35
"Channel": 25:::highlight
classDef engSection fill:#9b59b6,stroke:#8e44ad,stroke-width:2px;
classDef highlight fill:#f39c12,color:#000,stroke:#e67e22,stroke-width:2px;
`,
{}
);
});
/*
it.skip('12: should render a treemap with title', () => {
it.skip('17: should render a treemap with title', () => {
imgSnapshotTest(
`
treemap-beta

View File

@@ -0,0 +1,16 @@
sequenceDiagram
actor Alice
participant John@{ "type": "boundary" }
participant P1@{ "type": "control" } as New Control
participant P2@{ "type": "entity" } as New Entity
participant P3@{ "type": "database" } as New Database
Alice->>+John: Hello John, how are you?
John->>P1: new msg
P1->>P2: new msg
P2->>P3: new msg
Alice->>+John: John, can you hear me?
P3->>P2: new msg
P2->>P1: new msg
John-->>-Alice: Hi Alice, I can hear you!
P1->>John: new msg
John-->>-Alice: I feel great!

View File

@@ -0,0 +1,9 @@
treemap
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12

View File

@@ -0,0 +1,11 @@
---
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

View File

@@ -0,0 +1,11 @@
flowchart LR
A["A"] e1@==> B["B"]
A L_A_n1_0@--> n1["C"]
B L_B_n2_0@==> n2["D"]
n1 L_n1_n2_0@--> n2
e1@{ animate: true }
L_A_n1_0@{ animation: slow }
L_B_n2_0@{ animation: slow }
L_n1_n2_0@{ animation: fast }

View File

@@ -0,0 +1,3 @@
flowchart LR
A e1@==> B
e1@{ animate: true }

View File

@@ -0,0 +1,18 @@
---
config:
layout: ogdc
---
flowchart-elk TB
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1-->b2
end
subgraph three
c1-->c2
end
one --> two
three --> two
two --> c2

View File

@@ -0,0 +1,17 @@
---
config:
layout: elk
---
flowchart TB
process_C
subgraph container_Alpha
subgraph process_B
pppB
end
subgraph process_A
pppA
end
process_B-->|via_AWSBatch|container_Beta
process_A-->|messages|container_Beta
end

View File

@@ -0,0 +1,18 @@
---
config:
layout: elk
---
flowchart TB
subgraph container_Beta
process_C
end
subgraph container_Alpha
subgraph process_B
pppB
end
subgraph process_A
pppA
end
process_B-->|via_AWSBatch|container_Beta
process_A-->|messages|container_Beta
end

View File

@@ -0,0 +1,10 @@
---
config:
layout: elk
---
flowchart TB
subgraph container_Beta
process_C
end
process_B-->|via_AWSBatch|container_Beta

View File

@@ -0,0 +1,31 @@
---
config:
layout: elk
---
classDiagram
note "I love this diagram!\nDo you love it?"
Class01 <|-- AveryLongClass : Cool
<<interface>> Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label
class Class10 {
<<service>>
int id
test()
}
note for Class10 "Cool class\nI said it's very cool class!"

View File

@@ -0,0 +1,17 @@
---
config:
layout: elk
---
requirementDiagram
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
element test_entity {
type: simulation
}
test_entity - satisfies -> test_req

View File

@@ -0,0 +1,21 @@
---
config:
layout: elk
---
flowchart-elk TB
internet
nat
router
compute1
subgraph project
router
nat
subgraph subnet1
compute1
end
end
%% router --> subnet1
subnet1 --> nat
%% nat --> internet

View File

@@ -0,0 +1,27 @@
---
config:
layout: elk
---
flowchart-elk TB
internet
nat
router
lb1
lb2
compute1
compute2
subgraph project
router
nat
subgraph subnet1
compute1
lb1
end
subgraph subnet2
compute2
lb2
end
end
internet --> router
router --> subnet1 & subnet2
subnet1 & subnet2 --> nat --> internet

View File

@@ -0,0 +1,14 @@
---
config:
layout: elk
elk:
mergeEdges: false
forceNodeModelOrder: false
considerModelOrder: NONE
---
flowchart TB
a --> a1 & a2 & a3 & a4
b --> b1 & b2
b2 --> b3
b1 --> b4

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
flowchart:
curve: rounded
---
flowchart LR
I["fa:fa-code Text"] -- Mermaid js --> D["Use<br/>the<br/>editor!"]
I --> D & D
D@{ shape: question}
I@{ shape: question}

View File

@@ -0,0 +1,21 @@
---
config:
layout: tidy-tree
---
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

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
flowchart:
curve: linear
---
flowchart LR
A[A] --> B[B]
A[A] --- B([C])
A@{ shape: diamond}
%%B@{ shape: diamond}

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
flowchart:
curve: linear
---
flowchart LR
A[A] -- Mermaid js --> B[B]
A[A] -- Mermaid js --- B[B]
A@{ shape: diamond}
B@{ shape: diamond}

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
flowchart:
curve: rounded
---
flowchart LR
D["Use the editor"] -- Mermaid js --> I["fa:fa-code Text"]
I --> D & D
D@{ shape: question}
I@{ shape: question}

View File

@@ -0,0 +1,14 @@
---
config:
layout: elk
flowchart:
curve: rounded
elk:
nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart LR
D["Use the editor"] -- Mermaid js --> I["fa:fa-code Text"]
D --> I & I
a["a"]
D@{ shape: trap-b}
I@{ shape: lean-l}

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
---
flowchart LR
%% subgraph s1["Untitled subgraph"]
C["Evaluate"]
%% end
B --> C

View File

@@ -0,0 +1,10 @@
---
config:
layout: elk
flowchart:
//curve: linear
---
flowchart LR
%% A ==> B
%% A2 --> B2
A{A} --> B((Bo boo)) & B & B & B

View File

@@ -0,0 +1,18 @@
---
config:
layout: elk
theme: default
look: classic
---
flowchart LR
subgraph s1["APA"]
D{"Use the editor"}
end
subgraph S2["S2"]
s1
I>"fa:fa-code Text"]
E["E"]
end
D -- Mermaid js --> I
D --> I & E
E --> I

View File

@@ -0,0 +1,23 @@
---
config:
layout: elk
---
flowchart LR
a
subgraph s0["APA"]
subgraph s8["APA"]
subgraph s1["APA"]
D{"X"}
E[Q]
end
subgraph s3["BAPA"]
F[Q]
I
end
D --> I
D --> I
D --> I
I{"X"}
end
end

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
---
flowchart LR
a
D{"Use the editor"}
D -- Mermaid js --> I{"fa:fa-code Text"}
D-->I
D-->I

View File

@@ -0,0 +1,36 @@
---
config:
layout: elk
---
flowchart LR
subgraph s1["Untitled subgraph"]
n1["Evaluate"]
n2["Option 1"]
n3["Option 2"]
n4["fa:fa-car Option 3"]
end
subgraph s2["Untitled subgraph"]
n5["Evaluate"]
n6["Option 1"]
n7["Option 2"]
n8["fa:fa-car Option 3"]
end
A["Start"] -- Some text --> B("Continue")
B --> C{"Evaluate"}
C -- One --> D["Option 1"]
C -- Two --> E["Option 2"]
C -- Three --> F["fa:fa-car Option 3"]
n1 -- One --> n2
n1 -- Two --> n3
n1 -- Three --> n4
n5 -- One --> n6
n5 -- Two --> n7
n5 -- Three --> n8
n1@{ shape: diam}
n2@{ shape: rect}
n3@{ shape: rect}
n4@{ shape: rect}
n5@{ shape: diam}
n6@{ shape: rect}
n7@{ shape: rect}
n8@{ shape: rect}

View File

@@ -0,0 +1,10 @@
---
config:
layout: elk
---
flowchart LR
subgraph s1["Untitled subgraph"]
n1["Evaluate"]
n2["Option 1"]
end
n1 -- One --> n2

View File

@@ -0,0 +1,6 @@
---
config:
layout: elk
---
flowchart LR
A{A} --> B & C

View File

@@ -0,0 +1,9 @@
---
config:
layout: elk
---
flowchart LR
A{A} --> B & C
subgraph "subbe"
A
end

View File

@@ -0,0 +1,14 @@
---
config:
layout: elk
---
flowchart LR
n2@{ shape: rect}
n3@{ shape: rect}
n4@{ shape: rect}
A["Start"] -- Some text --> B("Continue")
B --> C{"Evaluate"}
C -- One --> D["Option 1"]
C -- Two --> E["Option 2"]
C -- Three --> F["fa:fa-car Option 3"]
%% C@{ shape: hexagon}

View File

@@ -0,0 +1,16 @@
---
config:
kanban:
ticketBaseUrl: 'https://github.com/your-repo/issues/#TICKET#'
---
kanban
Backlog
task1[📝 Define project requirements]@{ ticket: a101 }
To Do
task2[🔍 Research technologies]@{ ticket: a102 }
Review
task4[🔍 Code review for login feature]@{ ticket: a104 }
Done
task5[✅ Deploy initial version]@{ ticket: a105 }
In Progress
task3[💻 Develop login feature]@{ ticket: 103 }

View File

@@ -0,0 +1,2 @@
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }

View File

@@ -0,0 +1,3 @@
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
style A fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,4 @@
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,2 @@
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }

View File

@@ -0,0 +1,2 @@
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }

View File

@@ -0,0 +1,3 @@
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
style A fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,4 @@
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,2 @@
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }

Some files were not shown because too many files have changed in this diff Show More