Compare commits

...

226 Commits

Author SHA1 Message Date
Sidharth Vinod
158f9925ce Merge pull request #5760 from mermaid-js/changeset-release/master
Version Packages
2024-08-24 12:33:37 +05:30
github-actions[bot]
dab8f08a9e Version Packages 2024-08-24 07:03:01 +00:00
Sidharth Vinod
313fefe704 Merge pull request #5759 from mermaid-js/develop
Release v11.0.1
2024-08-24 12:31:04 +05:30
Sidharth Vinod
17c0af1cf6 chore: Update flowchart widths 2024-08-24 12:18:19 +05:30
Sidharth Vinod
1bb09cc9a8 Merge branch 'master' into develop
* master:
  Correct casing for hand drawn
  Updates to information about the new syntax
  Updating syntax reference with code showing how to select layout and look.
  [autofix.ci] apply automated fixes
  Version Packages (#5749)
  Bump mermaid minor
  Revert mermaid version
  add latest blog posts
  Version Packages (#5748)
  Test changeset (#5746)
  Version Packages
  Release parser, v0.1.0, test changeset
2024-08-24 11:55:07 +05:30
Sidharth Vinod
1e35341136 Merge pull request #5758 from mermaid-js/sidv/fixTypes
fix: layout-elk types
2024-08-24 11:53:47 +05:30
Sidharth Vinod
501a55d8f2 chore: Add changeset 2024-08-24 11:51:33 +05:30
Sidharth Vinod
ca57235e05 fix: Type export for layout-elk 2024-08-24 11:51:00 +05:30
Knut Sveidqvist
a4e1479759 Correct casing for hand drawn 2024-08-23 17:49:52 +02:00
Knut Sveidqvist
e499f700ce Updates to information about the new syntax 2024-08-23 17:41:24 +02:00
Knut Sveidqvist
d559fcc90b Updating syntax reference with code showing how to select layout and look. 2024-08-23 17:35:44 +02:00
Sidharth Vinod
35b98f2b89 Merge pull request #5750 from mermaid-js/add-blog-posts
DOCS: add latest blog posts
2024-08-23 20:40:16 +05:30
autofix-ci[bot]
e391966de8 [autofix.ci] apply automated fixes 2024-08-23 15:08:07 +00:00
github-actions[bot]
4d10e3f258 Version Packages (#5749)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-08-23 20:33:20 +05:30
Sidharth Vinod
bf05d8781e Bump mermaid minor 2024-08-23 20:30:02 +05:30
Sidharth Vinod
2efe741924 Revert mermaid version 2024-08-23 20:29:33 +05:30
Steph
f04fa4d565 add latest blog posts 2024-08-23 07:58:53 -07:00
github-actions[bot]
5bbf3678c5 Version Packages (#5748)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-08-23 20:22:20 +05:30
Sidharth Vinod
83926c9707 Test changeset (#5746) 2024-08-23 20:18:23 +05:30
Sidharth Vinod
49cb8d8388 Merge pull request #5745 from mermaid-js/changeset-release/master
Version Packages
2024-08-23 19:29:09 +05:30
github-actions[bot]
eb3ed2a5e4 Version Packages 2024-08-23 13:56:03 +00:00
Sidharth Vinod
28f9181dd4 Merge pull request #5744 from mermaid-js/sidv/release-Parser
Release parser, v0.1.0, test changeset
2024-08-23 19:23:19 +05:30
Sidharth Vinod
5013484924 Release parser, v0.1.0, test changeset 2024-08-23 19:21:40 +05:30
Sidharth Vinod
a10f46932f Merge pull request #5664 from Austin-Fulbright/feature/4401_creating_langium_parser_gitGraph
Feature/4401 creating langium parser git graph
2024-08-23 19:11:51 +05:30
Sidharth Vinod
5deaef456e chore: add changeset 2024-08-23 19:11:04 +05:30
Sidharth Vinod
a87f77339e Merge branch 'develop' into pr/Austin-Fulbright/5664
* develop: (34 commits)
  Mermaid version v11.0.0
  Run release drafter in release branch
  [autofix.ci] apply automated fixes
  Updating syntax reference with code showing how to select layout and look.
  Fix for selecting the correct diagramPadding for flowcharts
  Fix for turned arrow heads and missing edge sections
  Basic fix for handdrawn subgraph styling
  Fix for text alignment issue
  #5237 Fix for weird line intersection
  Fix config
  docs: Update release version
  docs: Update release version
  chore: Revert version changes
  chore: Revert version changes
  Remove release drafter
  Add changeset to PR template
  Remove changesets
  Update changelog format
  verify Docs version before publish
  chore: Remove prePublishOnly
  ...
2024-08-23 19:08:46 +05:30
Knut Sveidqvist
078038b080 Merge branch 'master' into develop 2024-08-23 15:33:01 +02:00
Sidharth Vinod
ea9a06160c Merge pull request #5733 from mermaid-js/sidv/changesets
Add changesets
2024-08-23 18:29:26 +05:30
Sidharth Vinod
6c89763ef9 Merge branch 'develop' into feature/4401_creating_langium_parser_gitGraph 2024-08-23 17:40:08 +05:30
Knut Sveidqvist
2cfdd1620a Mermaid version v11.0.0 2024-08-23 14:07:47 +02:00
Knut Sveidqvist
b9f4faa916 Merge branch 'release/11.0.0' 2024-08-23 14:05:39 +02:00
Sidharth Vinod
21c636c4c6 Run release drafter in release branch 2024-08-23 16:23:45 +05:30
autofix-ci[bot]
dd57030732 [autofix.ci] apply automated fixes 2024-08-23 10:13:11 +00:00
Knut Sveidqvist
efba4c18d1 Updating syntax reference with code showing how to select layout and look. 2024-08-23 12:08:09 +02:00
Knut Sveidqvist
48fd76e076 Fix for selecting the correct diagramPadding for flowcharts 2024-08-23 10:35:14 +02:00
Knut Sveidqvist
fdf376f9c8 Merge branch 'release/11.0.0' of github.com:mermaid-js/mermaid into release/11.0.0 2024-08-23 09:42:27 +02:00
Knut Sveidqvist
46b7ee87dd Fix for turned arrow heads and missing edge sections 2024-08-23 09:42:02 +02:00
Sidharth Vinod
14a94c0c51 Merge branch 'develop' into release/11.0.0
* develop:
  Update ComboStrap link
2024-08-23 12:08:56 +05:30
Sidharth Vinod
24490f7789 Update ComboStrap link 2024-08-23 12:07:41 +05:30
Knut Sveidqvist
09afb077f0 Basic fix for handdrawn subgraph styling 2024-08-23 08:24:36 +02:00
Ashish Jain
99ee235e75 Fix for text alignment issue 2024-08-22 17:52:48 +02:00
Sidharth Vinod
029a444d32 Merge branch 'develop' into release/11.0.0
* develop:
  chore: Update lockfile
  chore: Fix peer dependencies
2024-08-22 20:17:01 +05:30
Sidharth Vinod
8c4c92a861 Merge pull request #5737 from mermaid-js/sidv/fixPeerDependency
chore: Fix peer dependencies
2024-08-22 20:16:04 +05:30
Knut Sveidqvist
19d46fc823 #5237 Fix for weird line intersection 2024-08-22 16:29:23 +02:00
Sidharth Vinod
ae2dc70385 chore: Update lockfile 2024-08-22 19:45:49 +05:30
Sidharth Vinod
0ad44c12fe chore: Fix peer dependencies 2024-08-22 19:41:19 +05:30
Sidharth Vinod
ad12fa7fff Fix config 2024-08-22 19:35:10 +05:30
Sidharth Vinod
53bff117aa Merge branch 'develop' into release/11.0.0
* develop:
  update link to mermaid chart playground
  fix promo bar links
  Fix text color
  Add animated transitions
  feat: Update promo bar links
  update badge on mermaid chart page
  remove product hunt badge
  chore: Revert pnpm changes
  add most recent blog posts
  update product hunt badges
  chore: Update docs
  Add Slidev to the list of integrations
  add announcement bar to docs and minor styling update
  update product hunt badge on mermaid chart page
  add product hunt badge to homepage
  fix linting issue
  add blog post confluence plugin
2024-08-22 16:58:55 +05:30
Sidharth Vinod
2fe5e678bf Merge branch 'master' into develop
* master:
  update link to mermaid chart playground
  fix promo bar links
  Fix text color
  Add animated transitions
  feat: Update promo bar links
  update badge on mermaid chart page
  remove product hunt badge
  chore: Revert pnpm changes
  add most recent blog posts
  update product hunt badges
  chore: Update docs
  Add Slidev to the list of integrations
  add announcement bar to docs and minor styling update
  update product hunt badge on mermaid chart page
  add product hunt badge to homepage
  fix linting issue
  add blog post confluence plugin
2024-08-22 16:58:19 +05:30
Sidharth Vinod
4665b6bf15 docs: Update release version 2024-08-22 16:54:40 +05:30
Sidharth Vinod
a9d317f997 docs: Update release version 2024-08-22 16:52:02 +05:30
Sidharth Vinod
9c032648c1 Merge branch 'develop' into sidv/changesets 2024-08-22 16:48:58 +05:30
Sidharth Vinod
0e68788de4 Merge branch 'release/11.0.0' of https://github.com/mermaid-js/mermaid into release/11.0.0
* 'release/11.0.0' of https://github.com/mermaid-js/mermaid:
  #5237 Proper setting of the handdrawn seed in the visual tests
2024-08-22 16:48:03 +05:30
Knut Sveidqvist
44037c0c9d Merge branch 'release/11.0.0' of github.com:mermaid-js/mermaid into release/11.0.0 2024-08-22 13:13:33 +02:00
Knut Sveidqvist
95e47d283e #5237 Proper setting of the handdrawn seed in the visual tests 2024-08-22 13:13:09 +02:00
Sidharth Vinod
9dcda25355 Merge branch 'develop' into sidv/changesets
* develop:
  Fix docs
2024-08-22 16:20:03 +05:30
Sidharth Vinod
225115ad07 Fix docs 2024-08-22 16:19:49 +05:30
Sidharth Vinod
0c316d9dc2 chore: Revert version changes 2024-08-22 16:18:59 +05:30
Sidharth Vinod
5ed5274256 chore: Revert version changes 2024-08-22 16:18:39 +05:30
Sidharth Vinod
283ec73ed9 Remove release drafter 2024-08-22 16:17:17 +05:30
Sidharth Vinod
eac8459041 Add changeset to PR template 2024-08-22 16:17:07 +05:30
Sidharth Vinod
598de7019a Remove changesets 2024-08-22 16:11:31 +05:30
Sidharth Vinod
cc545f4433 Update changelog format 2024-08-22 15:57:56 +05:30
Sidharth Vinod
61632f2d7f verify Docs version before publish 2024-08-22 15:47:00 +05:30
Sidharth Vinod
3d9a24dd28 chore: Remove prePublishOnly 2024-08-22 15:46:04 +05:30
Sidharth Vinod
c4b92069ba chore: Copy readme before publish 2024-08-22 15:45:20 +05:30
Sidharth Vinod
c892a89536 Mark @mermaid-js/mermaid-example-diagram as private 2024-08-22 15:37:20 +05:30
Sidharth Vinod
89c782c094 Merge branch 'sidv/changesets' of https://github.com/mermaid-js/mermaid into sidv/changesets
* 'sidv/changesets' of https://github.com/mermaid-js/mermaid:
  [autofix.ci] apply automated fixes
2024-08-22 15:29:24 +05:30
Sidharth Vinod
7debe2fc59 Split changesets 2024-08-22 15:27:30 +05:30
autofix-ci[bot]
fc44d1fcdd [autofix.ci] apply automated fixes 2024-08-22 09:56:56 +00:00
Sidharth Vinod
6e7a24e200 Update version and publish scripts 2024-08-22 15:21:48 +05:30
Sidharth Vinod
8815e447ad Merge branch 'develop' into sidv/changesets
* develop:
  Revert pnpm-lock changes
  chore: Fix build issue
  Removing the redundant element in the render function
2024-08-22 15:10:04 +05:30
Sidharth Vinod
c3ca401888 Merge branch 'sidv/changesets' of https://github.com/mermaid-js/mermaid into sidv/changesets
* 'sidv/changesets' of https://github.com/mermaid-js/mermaid:
  [autofix.ci] apply automated fixes
2024-08-22 15:09:41 +05:30
Sidharth Vinod
4da479388d Revert pnpm-lock changes 2024-08-22 15:05:18 +05:30
Sidharth Vinod
0a0546e241 chore: Fix build issue 2024-08-22 15:00:53 +05:30
Sidharth Vinod
c61159b63f Update release command 2024-08-22 14:37:17 +05:30
autofix-ci[bot]
7a1c25bb3b [autofix.ci] apply automated fixes 2024-08-22 08:57:34 +00:00
Sidharth Vinod
d0ea3dd82b chore: Update release command 2024-08-22 14:27:34 +05:30
Sidharth Vinod
36444ab242 Update access 2024-08-22 14:22:33 +05:30
Sidharth Vinod
0cf639cb1b Merge branch 'develop' into sidv/changesets
* develop:
  [autofix.ci] apply automated fixes
  fix: Type of render
  chore: Rename Group to SVGGroup
  [autofix.ci] apply automated fixes
  feat: Inject internal helpers into render function
  chore: Move render function to bottom
  chore: ts-ignore errors
  [autofix.ci] apply automated fixes
  chore: Cleanup layoutelk
2024-08-22 14:21:33 +05:30
Sidharth Vinod
90364a020b docs: Add changeset 2024-08-22 14:19:44 +05:30
Sidharth Vinod
6e4b349c3a chore: Ignore packages in changeset 2024-08-22 14:11:54 +05:30
Sidharth Vinod
03d6531a7d chore: Revert package versions to match master 2024-08-22 14:10:25 +05:30
Sidharth Vinod
dd5866a4cb chore: Add changeset workflow 2024-08-22 14:10:08 +05:30
Knut Sveidqvist
47ac57be69 Removing the redundant element in the render function 2024-08-22 10:11:13 +02:00
Austin-Fulbright
52f5d95c81 Merge branch 'develop' into feature/4401_creating_langium_parser_gitGraph 2024-08-21 12:33:18 -04:00
Knut Sveidqvist
f1c066b68e Merge branch 'develop' into release/11.0.0 2024-08-21 16:26:14 +02:00
Sidharth Vinod
3eaf8b7177 feat: Add changesets 2024-08-21 19:54:59 +05:30
Knut Sveidqvist
0b9554c675 Merge pull request #5730 from mermaid-js/sidv/cleanupLayoutElk
chore: Cleanup layoutelk
2024-08-21 16:24:31 +02:00
Knut Sveidqvist
9134e1c837 #5237 Clean and fix for issue with edges to the diamond shape 2024-08-21 16:11:59 +02:00
Knut Sveidqvist
10c25348f3 #5237 Removing unused code 2024-08-21 14:42:44 +02:00
autofix-ci[bot]
8ffd198d8b [autofix.ci] apply automated fixes 2024-08-21 12:16:35 +00:00
Sidharth Vinod
7c81096bbc Merge branch 'sidv/cleanupLayoutElk' of https://github.com/mermaid-js/mermaid into sidv/cleanupLayoutElk
* 'sidv/cleanupLayoutElk' of https://github.com/mermaid-js/mermaid:
  [autofix.ci] apply automated fixes
2024-08-21 17:41:26 +05:30
Sidharth Vinod
3593fa63db fix: Type of render
Make optional parameter an object
2024-08-21 17:41:11 +05:30
Sidharth Vinod
037ba2fa9c chore: Rename Group to SVGGroup 2024-08-21 17:39:01 +05:30
autofix-ci[bot]
4d7b1e8eaf [autofix.ci] apply automated fixes 2024-08-21 11:57:36 +00:00
Sidharth Vinod
f6e1515f66 feat: Inject internal helpers into render function 2024-08-21 17:22:21 +05:30
Sidharth Vinod
c5be9fd882 chore: Move render function to bottom 2024-08-21 17:12:59 +05:30
Sidharth Vinod
01b5935a4e chore: ts-ignore errors 2024-08-21 17:12:03 +05:30
Sidharth Vinod
c1cd39bd65 Merge branch 'develop' into sidv/cleanupLayoutElk
* develop:
2024-08-21 17:10:51 +05:30
Sidharth Vinod
b2db7eb6bf Merge branch 'elk-migration' into sidv/cleanupLayoutElk
* elk-migration:
  chore: Use spaces
  docs: Add Readme
  chore: Use default export
  [autofix.ci] apply automated fixes
2024-08-21 17:10:17 +05:30
Knut Sveidqvist
f4097dfd82 Merge pull request #5729 from mermaid-js/elk-migration
Support flowchart-elk to use layout: elk
2024-08-21 13:10:26 +02:00
Sidharth Vinod
797877bcbf chore: Use spaces 2024-08-21 16:23:56 +05:30
Sidharth Vinod
db8a0028a6 docs: Add Readme 2024-08-21 16:22:10 +05:30
Sidharth Vinod
50a535125e chore: Use default export 2024-08-21 15:29:08 +05:30
autofix-ci[bot]
ed07a9e896 [autofix.ci] apply automated fixes 2024-08-21 09:12:02 +00:00
autofix-ci[bot]
43ffb00996 [autofix.ci] apply automated fixes 2024-08-21 09:10:09 +00:00
Sidharth Vinod
04e205bcb4 Merge branch 'elk-migration' into sidv/cleanupLayoutElk
* elk-migration:
  chore: Update pnpm and lockfile
2024-08-21 14:36:15 +05:30
Sidharth Vinod
58aa4c467f Merge branch 'develop' into elk-migration
* develop:
  chore: Update pnpm and lockfile
2024-08-21 14:34:55 +05:30
Sidharth Vinod
0cc7eb7638 Merge pull request #5728 from mermaid-js/sidv/updatePNPM
chore: Update pnpm and lockfile
2024-08-21 14:34:32 +05:30
Sidharth Vinod
4e126e174b chore: Cleanup layoutelk 2024-08-21 14:17:06 +05:30
Sidharth Vinod
44875691db chore: Remove mermaid-flowchart-elk 2024-08-21 13:37:58 +05:30
Sidharth Vinod
c140e1a658 chore: Update pnpm and lockfile 2024-08-21 13:33:32 +05:30
Sidharth Vinod
77118ad40c feat: Use dagre as fallback if elk layout is not present
Warn users that we are using the fallback
2024-08-21 13:30:02 +05:30
Sidharth Vinod
bc3fe33428 feat: Set config.layout=elk when using flowchart-elk 2024-08-21 13:29:09 +05:30
Sidharth Vinod
754fa24104 chore: Remove redundant flowDiagram-v2 2024-08-21 13:28:11 +05:30
Sidharth Vinod
69b3a9d3a2 feat: Support fallback layouts in renderer 2024-08-21 13:27:23 +05:30
Austin Fulbright
24ba5b73da added gitgraph in imperative state 2024-08-20 14:53:01 -04:00
Austin-Fulbright
8ef30a2642 Merge branch 'develop' into feature/4401_creating_langium_parser_gitGraph 2024-08-20 14:34:50 -04:00
Sidharth Vinod
8fdeb6d9d3 Merge branch 'develop' of https://github.com/mermaid-js/mermaid into develop
* 'develop' of https://github.com/mermaid-js/mermaid:
  #5726 Refactor paragraph margin in mermaid styles
  #5726 Setting the default margin
  [autofix.ci] apply automated fixes
  fix: Create a copy of config passed in initialize, so that theme variables are not leaked to the object
  refactor!(sankey): default to `useMaxWidth` true
  refactor!(git): default to `useMaxWidth` true
  [autofix.ci] apply automated fixes
  [autofix.ci] apply automated fixes
  chore: Simplify dataFetcher helper functions
  chore: Simplify dataFetcher helper functions
2024-08-20 20:45:04 +05:30
Sidharth Vinod
21efbbdbe8 chore: Skip running autofix.ci on renovate branches 2024-08-20 20:45:00 +05:30
Sidharth Vinod
1956d3d63c Merge pull request #5670 from mermaid-js/sidv/5237_review
5237 Review Updates
2024-08-20 18:15:37 +05:30
Knut Sveidqvist
25efa4e63f Merge pull request #5727 from mermaid-js/5726_doctype
Aligning doctype so that mermaid renders in the same way with or without it
2024-08-20 14:45:14 +02:00
Knut Sveidqvist
6df6f5ab2c Merge pull request #5725 from mermaid-js/sidv/copyInitOptions
fix: Create a copy of config passed in initialize, so that theme variables are not leaked to the object
2024-08-20 14:45:00 +02:00
Knut Sveidqvist
c5dfa4213d Merge pull request #5724 from aloisklink/fix/default-sankey-useMaxWidth-to-true
refactor!(sankey): default to `useMaxWidth` true
2024-08-20 14:44:38 +02:00
Knut Sveidqvist
a48d970410 Merge pull request #5723 from aloisklink/fix/default-gitGraph-useMaxWidth-to-true
refactor!(git): default to `useMaxWidth` true
2024-08-20 14:44:19 +02:00
Knut Sveidqvist
1168db6830 #5726 Refactor paragraph margin in mermaid styles 2024-08-20 14:28:17 +02:00
Knut Sveidqvist
f76cab1ba3 #5726 Setting the default margin 2024-08-20 14:13:46 +02:00
autofix-ci[bot]
78fbf36c6e [autofix.ci] apply automated fixes 2024-08-20 11:32:49 +00:00
Sidharth Vinod
3ee19337ca fix: Create a copy of config passed in initialize, so that theme variables are not leaked to the object 2024-08-20 16:57:11 +05:30
Austin Fulbright
3ac242978d fixed merge 2024-08-20 07:04:05 -04:00
Austin Fulbright
94ee076aad fixed config for user configs 2024-08-20 06:46:33 -04:00
Austin Fulbright
7a7b41557d implemented transfer objects from parser to db 2024-08-20 06:37:49 -04:00
Austin Fulbright
d9d9cc9ddc added objects to be transfered from parser to db 2024-08-20 06:06:19 -04:00
Austin-Fulbright
4ec0dcfe1f Merge branch 'develop' into feature/4401_creating_langium_parser_gitGraph 2024-08-20 06:03:37 -04:00
Alois Klink
d82958d73d refactor!(sankey): default to useMaxWidth true
All other diagrams default to `useMaxWidth` `true`.

BREAKING CHANGE: Change the default value of `useMaxWidth` for sankey
                 diagrams to `true`.
2024-08-20 18:53:40 +09:00
Alois Klink
6b5286eff8 refactor!(git): default to useMaxWidth true
All other diagrams (with the exception of Sankey) default to `true`.

BREAKING CHANGE: Change the default value of `useMaxWidth` for gitgraphs
                 to `true`.
2024-08-20 18:53:22 +09:00
Sidharth Vinod
04c29e2a96 Merge pull request #5335 from FutzMonitor/4175Issue-allowSemicolons
Allow Semicolons in Timeline Titles, Sections, Periods, and Events
2024-08-20 09:07:17 +00:00
Sidharth Vinod
4e7d65062a Revert #5305
As it doesn't fix the issue in all cases.
2024-08-20 14:29:42 +05:30
Sidharth Vinod
262bf4e2b0 chore: Simplify unit test 2024-08-20 14:25:52 +05:30
Sidharth Vinod
f63eb45e7d Merge branch 'develop' into pr/FutzMonitor/5335
* develop: (485 commits)
  [autofix.ci] apply automated fixes
  add MonsterWriter to list of community integrations
  fix: Making insertCluster async
  Ignore codeql warning
  Removed the un-necessary test
  Fixed broken test
  [autofix.ci] apply automated fixes
  Fixed lint issue
  #5237 Fix for text alignment for handdrawn text using svg labels
  #5237 Fix for subroutine positioning
  Updated handDrawn cypress test
  adding handDrawn cypress test
  #5237 Async fix for clusters
  sequence diagram NaN values issue
  review comment fixes
  #5237 Replace generic object with Map
  #5237 Removing old flowchart renderer
  #5237 Fixes from comments
  Adding elk test
  chore(deps): update eslint
  ...
2024-08-20 14:17:55 +05:30
autofix-ci[bot]
4e40f29f33 [autofix.ci] apply automated fixes 2024-08-20 07:12:51 +00:00
Sidharth Vinod
0faeeb6411 Merge branch 'develop' into sidv/5237_review 2024-08-20 12:37:36 +05:30
Austin Fulbright
b93691be0e fixed small error 2024-08-20 01:00:13 -04:00
Austin Fulbright
66e53df04b added most suggested changes 2024-08-20 00:30:01 -04:00
Austin Fulbright
53798beb96 fixed gitgraphconfig problem 2024-08-15 16:10:20 -04:00
Austin Fulbright
299e559aa5 added config as global 2024-08-14 10:51:45 -04:00
autofix-ci[bot]
3539a35578 [autofix.ci] apply automated fixes 2024-08-13 21:56:26 +00:00
Austin-Fulbright
d50150cbfa Merge branch 'mermaid-js:develop' into feature/4401_creating_langium_parser_gitGraph 2024-08-13 17:51:21 -04:00
Austin-Fulbright
73aae9e86e Merge branch 'develop' into feature/4401_creating_langium_parser_gitGraph 2024-08-12 09:13:42 -04:00
Austin Fulbright
d73a090875 fixed BT with parallel commits and added more unit tests 2024-08-10 23:33:23 -04:00
Austin Fulbright
aba306b685 fixed highlight color 2024-08-10 12:32:25 -04:00
Austin Fulbright
c49a1bf60c fixed custom type REVERSE for merge, fixed branch spacing for TB 2024-08-10 12:28:24 -04:00
Austin Fulbright
d684e0d924 added more unit tests to gitGraphParser.ts and gitGraphRenderer.ts 2024-08-10 11:22:22 -04:00
Austin Fulbright
269284c6d7 added parser unit tests and organized config in gitGraphAst.ts 2024-08-10 10:37:24 -04:00
Austin Fulbright
62950c31a4 finished gitGraphRenderer.ts 2024-08-10 07:46:10 -04:00
Austin-Fulbright
e0d0cdcf1f Merge branch 'mermaid-js:develop' into feature/4401_creating_langium_parser_gitGraph 2024-08-10 06:15:10 -04:00
Austin Fulbright
a93b8324ad made draw commit more readable, included more helper functions and interfaces, added in-source test suite to renderer 2024-08-10 06:08:57 -04:00
Sidharth Vinod
59aaa310dd Merge pull request #5704 from mermaid-js/fix-promo-bar-links
DOCS: fix promo bar links
2024-08-09 10:22:02 +05:30
steph
f4ce428d66 update link to mermaid chart playground 2024-08-08 21:49:01 -07:00
steph
5aecd127bd fix promo bar links 2024-08-08 21:42:00 -07:00
Austin Fulbright
2218929416 fixed types in gitGraphTypes 2024-08-08 19:49:09 -04:00
Austin Fulbright
00603e7bac fix ts-ignore errors refactored large functions to use helpers 2024-08-08 18:47:34 -04:00
Sidharth Vinod
1990786c2c Merge pull request #5697 from mermaid-js/sidv/updatePromo
Update Promo Links
2024-08-07 13:13:58 +05:30
Sidharth Vinod
980c97a44c Fix text color 2024-08-07 12:24:03 +05:30
Sidharth Vinod
42177a3098 Add animated transitions 2024-08-07 12:10:35 +05:30
Sidharth Vinod
657e38f6e0 feat: Update promo bar links 2024-08-07 11:35:12 +05:30
Austin Fulbright
8fe0ed1d03 added parser test and combined the two gitGraph tests 2024-08-06 19:26:13 -04:00
Austin Fulbright
38e048b94e fixed hash error loc & line properties 2024-08-05 14:08:42 -04:00
Austin Fulbright
2a38d46fd9 fixed the rest of the concerns, refactored portions of the gitGraphParser test to handle async actions 2024-08-05 13:53:51 -04:00
Austin-Fulbright
9ed38ccf3a Merge branch 'mermaid-js:develop' into feature/4401_creating_langium_parser_gitGraph 2024-08-05 11:07:32 -04:00
Sidharth Vinod
e8ddae4882 Merge pull request #5679 from mermaid-js/product-hunt-updates
DOCS: Product Hunt updates
2024-08-03 15:32:01 +05:30
Steph
c0d6d89330 update badge on mermaid chart page 2024-07-30 12:30:46 -07:00
Steph
1cdc73d270 remove product hunt badge 2024-07-29 00:25:23 -07:00
autofix-ci[bot]
6b336cbe77 [autofix.ci] apply automated fixes 2024-07-27 13:16:26 +00:00
Sidharth Vinod
cdca63dcfe chore: Simplify dataFetcher helper functions 2024-07-27 15:18:09 +05:30
Sidharth Vinod
b79191e39c chore: Simplify dataFetcher helper functions 2024-07-27 15:14:52 +05:30
Austin-Fulbright
f30085c47e Update packages/mermaid/src/diagrams/git/gitGraphAst.ts
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-07-27 04:06:43 -04:00
Austin-Fulbright
ef25160b8e Update packages/mermaid/src/diagrams/git/gitGraphAst.ts
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-07-27 04:06:09 -04:00
Austin-Fulbright
6c1e5aae92 Delete packages/mermaid/src/diagrams/git/parser/gitGraph.jison 2024-07-27 04:05:34 -04:00
Austin-Fulbright
a0207f9195 Update packages/mermaid/src/diagrams/git/gitGraphAst.ts
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-07-27 04:04:23 -04:00
Austin-Fulbright
346efdd384 Update packages/mermaid/src/diagrams/git/gitGraphAst.ts
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-07-27 04:04:16 -04:00
Austin-Fulbright
6e5e5f9c61 Update packages/mermaid/src/diagrams/git/gitGraphAst.ts
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-07-27 04:03:25 -04:00
Austin-Fulbright
871f0478c6 Update packages/parser/src/language/gitGraph/module.ts
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-07-27 04:03:19 -04:00
Austin-Fulbright
5dfc94e6f5 Update packages/mermaid/src/diagrams/git/gitGraphParser.ts
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-07-27 04:03:14 -04:00
Austin-Fulbright
ec2d9c9a08 Update packages/mermaid/src/diagrams/git/gitGraphParser.ts
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-07-27 04:03:08 -04:00
Austin-Fulbright
281064f714 Update packages/mermaid/src/diagrams/git/gitGraphAst.ts
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-07-27 04:03:02 -04:00
Austin-Fulbright
62757c529f Update packages/mermaid/src/diagrams/git/gitGraphAst.ts
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-07-27 04:02:56 -04:00
Austin-Fulbright
e57fee1f37 Update packages/mermaid/src/diagrams/git/gitGraphAst.ts
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-07-27 04:02:49 -04:00
Austin Fulbright
0d4c3e5f72 added unit tests for gitGraph parser 2024-07-27 03:51:28 -04:00
Austin Fulbright
275dbe9b2e fixed all rendering differences 2024-07-27 02:02:12 -04:00
Austin-Fulbright
9f6a7b79ac allows for custom merge type 2024-07-27 00:49:07 -04:00
Austin Fulbright
3168084cf5 fixed rendering 2024-07-27 00:03:59 -04:00
Austin Fulbright
887e5803d8 fixed some features and added propper default direction 2024-07-26 23:28:07 -04:00
Austin Fulbright
a386bd0b74 fixed tags for gitGraph 2024-07-26 22:55:40 -04:00
Austin Fulbright
1af90946bc fixed options e2e test 2024-07-25 06:22:37 -04:00
Austin Fulbright
d0eadebb99 added parser 2024-07-25 05:25:19 -04:00
Austin Fulbright
1a95d48852 added Imperative state 2024-07-24 13:53:00 -04:00
Austin Fulbright
0b67cffdfa fixed cherrypicking tests 2024-07-24 10:37:21 -04:00
Austin Fulbright
d2e2017907 fixed undefined for type errors 2024-07-24 09:48:46 -04:00
Austin Fulbright
5460bc0a0c fixed checkout branch with no commits 2024-07-24 07:13:10 -04:00
Austin-Fulbright
ebd4da95cd Merge branch 'mermaid-js:develop' into feature/4401_creating_langium_parser_gitGraph 2024-07-24 05:37:54 -04:00
Sidharth Vinod
4694ec08d3 Merge pull request #5663 from mermaid-js/add-blog-posts
DOCS: Add blog posts
2024-07-24 11:03:58 +05:30
Sidharth Vinod
e26dbfe11a chore: Revert pnpm changes 2024-07-24 11:03:40 +05:30
Sidharth Vinod
0d6552e63d Merge pull request #5662 from mermaid-js/update-product-hunt-content
DOCS: Update product hunt badges
2024-07-24 10:45:31 +05:30
Steph
e683b8886a add most recent blog posts 2024-07-23 16:57:03 -07:00
Steph
765e0cd35c update product hunt badges 2024-07-23 16:46:42 -07:00
Austin Fulbright
6f7c291512 Added gitGraphAst as typescript added gitGraphTypes and gitGraphParser 2024-07-22 04:10:36 -04:00
Austin Fulbright
1d0e98dd62 Added the langium module for gitGraph 2024-07-21 19:50:59 -04:00
Sidharth Vinod
515d880f0a Merge pull request #5629 from KermanX/patch-1
Add Slidev to the list of integrations
2024-07-09 10:44:34 +05:30
Sidharth Vinod
60a30a3beb chore: Update docs 2024-07-09 10:43:27 +05:30
_Kerman
e95e915d2b Add Slidev to the list of integrations 2024-07-09 10:40:49 +05:30
Sidharth Vinod
99552b3389 Merge pull request #5602 from mermaid-js/add-product-hunt-badge
DOCS: Product Hunt
2024-06-27 11:23:10 +05:30
steph
7391b05c43 add announcement bar to docs and minor styling update 2024-06-26 22:23:42 -07:00
steph
0691c722c3 update product hunt badge on mermaid chart page 2024-06-26 22:21:49 -07:00
steph
534a10edea add product hunt badge to homepage 2024-06-26 21:24:27 -07:00
Justin Greywolf
af5e69327b Merge pull request #5536 from mermaid-js/add-blog-post-confluence-plugin
DOCS: Add blog post - Official Mermaid Chart for Confluence app
2024-05-22 21:27:03 -07:00
Steph
20b03189df fix linting issue 2024-05-22 13:45:58 -07:00
Steph
3d44eb0f42 add blog post confluence plugin 2024-05-22 13:40:49 -07:00
Christian
c239b6e311 Merge branch 'develop' into 4175Issue-allowSemicolons 2024-03-30 15:14:12 -04:00
futzmonitor
cf88f0609d Changes to timeline.spec.js
1. Re-organized the new TL-6 test to not use a for-loop with a switch case.
2. Imported the commonDb module to ensure titles are be tested.
3. Use indices to retrieve elements that need to be tested.
2024-03-19 10:02:51 -04:00
futzmonitor
e433b953f6 Merge branch 'develop' into 4175Issue-allowSemicolons 2024-03-18 10:28:56 -04:00
futzmonitor
fab6987601 Merge branch 'develop' into 4175Issue-allowSemicolons 2024-02-27 09:36:04 -05:00
futzmonitor
9e3ebf1648 Run the pnpm lint:fix command to fix linting problems 2024-02-27 09:33:11 -05:00
futzmonitor
f13beabdd0 Merge branch 'develop' into 4175Issue-allowSemicolons 2024-02-26 21:07:30 -05:00
futzmonitor
1169cb9e85 Changes to timeline.jison
1. Removed the semicolon from the regex for titles, sections, periods, and events.
Changes to timeline.spec.js
1. Added a test for the changes made in the timeline parser
2024-02-26 20:59:40 -05:00
125 changed files with 6409 additions and 5730 deletions

8
.changeset/README.md Normal file
View File

@@ -0,0 +1,8 @@
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

12
.changeset/config.json Normal file
View File

@@ -0,0 +1,12 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": ["@changesets/changelog-github", { "repo": "mermaid-js/mermaid" }],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"bumpVersionsWithWorkspaceProtocolOnly": true,
"ignore": ["@mermaid-js/docs", "@mermaid-js/webpack-test", "@mermaid-js/mermaid-example-diagram"]
}

View File

@@ -120,6 +120,8 @@ SUBROUTINEEND
SUBROUTINESTART
Subschemas
substr
SVGG
SVGSVG
TAGEND
TAGSTART
techn

View File

@@ -58,6 +58,7 @@ rehype
roughjs
rscratch
shiki
Slidev
sparkline
sphinxcontrib
ssim

View File

@@ -15,4 +15,4 @@ Make sure you
- [ ] :book: have read the [contribution guidelines](https://mermaid.js.org/community/contributing.html)
- [ ] :computer: have added necessary unit/e2e tests.
- [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://mermaid.js.org/community/contributing.html#update-documentation) is used for all new features.
- [ ] :bookmark: targeted `develop` branch
- [ ] :butterfly: If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running `pnpm changeset` and following the prompts. Changesets that add features should be `minor` and those that fix bugs should be `patch`. Please prefix changeset messages with `feat:`, `fix:`, or `chore:`.

View File

@@ -1,36 +0,0 @@
name-template: '$NEXT_PATCH_VERSION'
tag-template: '$NEXT_PATCH_VERSION'
categories:
- title: '🚨 **Breaking Changes**'
labels:
- 'Breaking Change'
- title: '🚀 Features'
labels:
- 'Type: Enhancement'
- 'feature' # deprecated, new PRs shouldn't have this
- title: '🐛 Bug Fixes'
labels:
- 'Type: Bug / Error'
- 'fix' # deprecated, new PRs shouldn't have this
- title: '🧰 Maintenance'
labels:
- 'Type: Other'
- 'chore' # deprecated, new PRs shouldn't have this
- title: '⚡️ Performance'
labels:
- 'Type: Performance'
- title: '📚 Documentation'
labels:
- 'Area: Documentation'
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
sort-by: title
sort-direction: ascending
exclude-labels:
- 'Skip changelog'
no-changes-template: 'This release contains minor changes and bugfixes.'
template: |
# Release Notes
$CHANGES
🎉 **Thanks to all contributors helping with this release!** 🎉

View File

@@ -2,6 +2,8 @@ name: autofix.ci # needed to securely identify the workflow
on:
pull_request:
branches-ignore:
- 'renovate/**'
permissions:
contents: read

View File

@@ -1,23 +0,0 @@
name: Draft Release
on:
push:
branches:
- master
permissions:
contents: read
jobs:
draft-release:
runs-on: ubuntu-latest
permissions:
contents: write # write permission is required to create a GitHub release
pull-requests: read # required to read PR titles/labels
steps:
- name: Draft Release
uses: release-drafter/release-drafter@v6
with:
disable-autolabeler: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

37
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Release
on:
push:
branches:
- master
concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v3
- uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version-file: '.node-version'
- name: Install Packages
run: pnpm install --frozen-lockfile
- name: Create Release Pull Request or Publish to npm
id: changesets
uses: changesets/action@v1
with:
version: pnpm changeset:version
publish: pnpm changeset:publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -12,7 +12,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -30,7 +30,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: true },
fontFamily: 'courier',
}
@@ -47,7 +47,7 @@ describe('Flowchart HandDrawn', () => {
C -->|Two| E[iPhone]
C -->|Three| F[Car]
`,
{ look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
);
});
@@ -62,7 +62,7 @@ describe('Flowchart HandDrawn', () => {
C -->|Two| E[\\iPhone\\]
C -->|Three| F[Car]
`,
{ look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
);
});
@@ -78,7 +78,7 @@ describe('Flowchart HandDrawn', () => {
classDef processHead fill:#888888,color:white,font-weight:bold,stroke-width:3px,stroke:#001f3f
class 1A,1B,D,E processHead
`,
{ look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
);
});
@@ -107,7 +107,7 @@ describe('Flowchart HandDrawn', () => {
35(SAM.CommonFA.PopulationFME)-->39(SAM.CommonFA.ChargeDetails)
36(SAM.CommonFA.PremetricCost)-->39(SAM.CommonFA.ChargeDetails)
`,
{ look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
);
});
@@ -178,7 +178,7 @@ describe('Flowchart HandDrawn', () => {
9a072290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002
9a072290_1ec3_e711_8c5a_005056ad0002-->71082290_1ec3_e711_8c5a_005056ad0002
`,
{ look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
);
});
@@ -187,7 +187,7 @@ describe('Flowchart HandDrawn', () => {
`
graph TB;subgraph "number as labels";1;end;
`,
{ look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
);
});
@@ -199,7 +199,7 @@ describe('Flowchart HandDrawn', () => {
a1-->a2
end
`,
{ look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
);
});
@@ -211,7 +211,7 @@ describe('Flowchart HandDrawn', () => {
a1-->a2
end
`,
{ look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
);
});
@@ -246,7 +246,7 @@ describe('Flowchart HandDrawn', () => {
style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred
style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue
`,
{ look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
);
});
@@ -348,7 +348,7 @@ describe('Flowchart HandDrawn', () => {
sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A;
sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4FC27B48-A6F9-460A-A675-021F5854FE22;
`,
{ look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
);
});
@@ -364,7 +364,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
listUrl: false,
listId: 'color styling',
fontFamily: 'courier',
@@ -390,7 +390,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
listUrl: false,
listId: 'color styling',
fontFamily: 'courier',
@@ -411,7 +411,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -435,7 +435,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -457,7 +457,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -471,7 +471,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -485,7 +485,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -500,7 +500,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -527,7 +527,7 @@ describe('Flowchart HandDrawn', () => {
class A someclass;`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -544,7 +544,7 @@ describe('Flowchart HandDrawn', () => {
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
`,
{ look: 'handDrawn', handDrawnSeed: 0, flowchart: { nodeSpacing: 50 }, fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { nodeSpacing: 50 }, fontFamily: 'courier' }
);
});
@@ -560,7 +560,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { rankSpacing: '100' },
fontFamily: 'courier',
}
@@ -578,7 +578,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -603,7 +603,7 @@ describe('Flowchart HandDrawn', () => {
click E "notes://do-your-thing/id" "other protocol test"
click F "javascript:alert('test')" "script test"
`,
{ look: 'handDrawn', handDrawnSeed: 0, securityLevel: 'loose', fontFamily: 'courier' }
{ look: 'handDrawn', handDrawnSeed: 1, securityLevel: 'loose', fontFamily: 'courier' }
);
});
@@ -623,7 +623,7 @@ describe('Flowchart HandDrawn', () => {
click B "index.html#link-clicked" "link test"
click D testClick "click test"
`,
{ look: 'handDrawn', handDrawnSeed: 0, flowchart: { htmlLabels: true } }
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { htmlLabels: true } }
);
});
@@ -645,7 +645,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -664,7 +664,7 @@ describe('Flowchart HandDrawn', () => {
class A myClass1
class D myClass2
`,
{ look: 'handDrawn', handDrawnSeed: 0, flowchart: { htmlLabels: true } }
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { htmlLabels: true } }
);
});
@@ -682,7 +682,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -711,7 +711,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -728,7 +728,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -752,7 +752,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: false },
fontFamily: 'courier',
}
@@ -769,7 +769,7 @@ describe('Flowchart HandDrawn', () => {
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
`,
{ look: 'handDrawn', handDrawnSeed: 0, flowchart: { diagramPadding: 0 } }
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { diagramPadding: 0 } }
);
});
@@ -778,7 +778,7 @@ describe('Flowchart HandDrawn', () => {
`graph TD
A[Christmas]
`,
{ look: 'handDrawn', handDrawnSeed: 0 }
{ look: 'handDrawn', handDrawnSeed: 1 }
);
});
@@ -796,7 +796,7 @@ describe('Flowchart HandDrawn', () => {
C -----> E4
C ======> E5
`,
{ look: 'handDrawn', handDrawnSeed: 0 }
{ look: 'handDrawn', handDrawnSeed: 1 }
);
});
it('FDH36: should render escaped without html labels', () => {
@@ -804,7 +804,7 @@ describe('Flowchart HandDrawn', () => {
`graph TD
a["<strong>Haiya</strong>"]-->b
`,
{ look: 'handDrawn', handDrawnSeed: 0, htmlLabels: false, flowchart: { htmlLabels: false } }
{ look: 'handDrawn', handDrawnSeed: 1, htmlLabels: false, flowchart: { htmlLabels: false } }
);
});
it('FDH37: should render non-escaped with html labels', () => {
@@ -814,7 +814,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
htmlLabels: true,
flowchart: { htmlLabels: true },
securityLevel: 'loose',
@@ -830,7 +830,7 @@ describe('Flowchart HandDrawn', () => {
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
`,
{ look: 'handDrawn', handDrawnSeed: 0, flowchart: { useMaxWidth: true } }
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { useMaxWidth: true } }
);
cy.get('svg').should((svg) => {
expect(svg).to.have.attr('width', '100%');
@@ -853,7 +853,7 @@ describe('Flowchart HandDrawn', () => {
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
`,
{ look: 'handDrawn', handDrawnSeed: 0, flowchart: { useMaxWidth: false } }
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { useMaxWidth: false } }
);
cy.get('svg').should((svg) => {
// const height = parseFloat(svg.attr('height'));
@@ -874,7 +874,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
htmlLabels: true,
flowchart: { htmlLabels: true },
securityLevel: 'loose',
@@ -904,7 +904,7 @@ describe('Flowchart HandDrawn', () => {
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
htmlLabels: true,
flowchart: { htmlLabels: true },
securityLevel: 'loose',
@@ -919,7 +919,7 @@ graph TD
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
htmlLabels: true,
flowchart: { htmlLabels: true },
securityLevel: 'loose',
@@ -937,7 +937,7 @@ graph TD
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
htmlLabels: true,
flowchart: { htmlLabels: true },
securityLevel: 'loose',
@@ -977,7 +977,7 @@ graph TD
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
htmlLabels: true,
flowchart: { htmlLabels: true },
securityLevel: 'loose',
@@ -999,7 +999,7 @@ graph TD
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
htmlLabels: true,
flowchart: { htmlLabels: true },
securityLevel: 'loose',
@@ -1016,7 +1016,7 @@ graph TD
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
htmlLabels: true,
flowchart: { htmlLabels: true },
securityLevel: 'loose',
@@ -1027,12 +1027,12 @@ graph TD
imgSnapshotTest(
`
graph TD
classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff
classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff
hello --> default
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
htmlLabels: true,
flowchart: { htmlLabels: true },
securityLevel: 'loose',
@@ -1051,7 +1051,7 @@ graph TD
`,
{
look: 'handDrawn',
handDrawnSeed: 0,
handDrawnSeed: 1,
flowchart: { htmlLabels: true },
securityLevel: 'loose',
}

View File

@@ -99,7 +99,7 @@ describe('Flowchart v2', () => {
const style = svg.attr('style');
expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
expect(maxWidthValue).to.be.within(446 * 0.95 - 1, 446 * 1.05);
expect(maxWidthValue).to.be.within(417 * 0.95, 417 * 1.05);
});
});
it('8: should render a flowchart when useMaxWidth is false', () => {
@@ -118,7 +118,7 @@ describe('Flowchart v2', () => {
const width = parseFloat(svg.attr('width'));
// use within because the absolute value can be slightly different depending on the environment ±5%
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
expect(width).to.be.within(446 * 0.95 - 1, 446 * 1.05);
expect(width).to.be.within(417 * 0.95, 417 * 1.05);
expect(svg).to.not.have.attr('style');
});
});

View File

@@ -822,7 +822,7 @@ flowchart LR
<script type="module">
import mermaid from './mermaid.esm.mjs';
import { layouts } from './mermaid-layout-elk.esm.mjs';
import layouts from './mermaid-layout-elk.esm.mjs';
mermaid.registerLayoutLoaders(layouts);
mermaid.parseError = function (err, hash) {};

View File

@@ -147,7 +147,7 @@ flowchart LR
<script type="module">
import mermaid from './mermaid.esm.mjs';
import { layouts } from './mermaid-layout-elk.esm.mjs';
import layouts from './mermaid-layout-elk.esm.mjs';
mermaid.registerLayoutLoaders(layouts);
mermaid.parseError = function (err, hash) {};

View File

@@ -84,16 +84,25 @@
<div class="flex">
<pre id="diagram" class="mermaid">
---
config:
look: handDrawn
flowchart:
htmlLabels: false
title: hello2
config:
look: handDrawn
layout: elk
elk:
nodePlacementStrategy: BRANDES_KOEPF
---
flowchart
A[I am a long text, where do I go??? handdrawn - false]
flowchart LR
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]
</pre
>
<pre id="diagram" class="mermaid">
<pre id="diagram" class="mermaid2">
---
config:
look: handdrawn
@@ -106,7 +115,7 @@ flowchart
>
</div>
<div class="flex">
<pre id="diagram" class="mermaid">
<pre id="diagram" class="mermaid2">
---
config:
flowchart:
@@ -116,7 +125,7 @@ flowchart
A[I am a long text, where do I go??? classic - false]
</pre
>
<pre id="diagram" class="mermaid">
<pre id="diagram" class="mermaid2">
---
config:
flowchart:
@@ -159,8 +168,8 @@ flowchart LR
<script type="module">
import mermaid from './mermaid.esm.mjs';
// import { layouts } from './mermaid-layout-elk.esm.mjs';
// mermaid.registerLayoutLoaders(layouts);
import layouts from './mermaid-layout-elk.esm.mjs';
mermaid.registerLayoutLoaders(layouts);
mermaid.parseError = function (err, hash) {
console.error('Mermaid error: ', err);
};

View File

@@ -1222,7 +1222,7 @@ direction LR
<script type="module">
import mermaid from './mermaid.esm.mjs';
import { layouts } from './mermaid-layout-elk.esm.mjs';
import layouts from './mermaid-layout-elk.esm.mjs';
mermaid.registerLayoutLoaders(layouts);
mermaid.parseError = function (err, hash) {
@@ -1268,4 +1268,4 @@ direction LR
</script>
</body>
</html>
</html>

View File

@@ -1,7 +1,7 @@
import mermaid from './mermaid.esm.mjs';
import { layouts } from './mermaid-layout-elk.esm.mjs';
import externalExample from './mermaid-example-diagram.esm.mjs';
import layouts from './mermaid-layout-elk.esm.mjs';
import zenUml from './mermaid-zenuml.esm.mjs';
import mermaid from './mermaid.esm.mjs';
function b64ToUtf8(str) {
return decodeURIComponent(escape(window.atob(str)));

View File

@@ -16,7 +16,7 @@
#### Defined in
[packages/mermaid/src/rendering-util/render.ts:9](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L9)
[packages/mermaid/src/rendering-util/render.ts:24](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L24)
---
@@ -26,7 +26,7 @@
#### Defined in
[packages/mermaid/src/rendering-util/render.ts:8](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L8)
[packages/mermaid/src/rendering-util/render.ts:23](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L23)
---
@@ -36,4 +36,4 @@
#### Defined in
[packages/mermaid/src/rendering-util/render.ts:7](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L7)
[packages/mermaid/src/rendering-util/render.ts:22](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L22)

View File

@@ -28,7 +28,7 @@ page.
#### Defined in
[packages/mermaid/src/mermaid.ts:432](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L432)
[packages/mermaid/src/mermaid.ts:435](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L435)
---
@@ -59,7 +59,7 @@ A graph definition key
#### Defined in
[packages/mermaid/src/mermaid.ts:434](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L434)
[packages/mermaid/src/mermaid.ts:437](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L437)
---
@@ -89,7 +89,7 @@ Use [initialize](mermaid.Mermaid.md#initialize) and [run](mermaid.Mermaid.md#run
#### Defined in
[packages/mermaid/src/mermaid.ts:427](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L427)
[packages/mermaid/src/mermaid.ts:430](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L430)
---
@@ -116,56 +116,13 @@ This function should be called before the run function.
#### Defined in
[packages/mermaid/src/mermaid.ts:431](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L431)
---
### internalHelpers
**internalHelpers**: `Object`
Internal helpers for mermaid
**`Deprecated`**
- This should not be used by external packages, as the definitions will change without notice.
#### Type declaration
| Name | Type |
| :--------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `common` | { `evaluate`: (`val?`: `string` \| `boolean`) => `boolean` ; `getMax`: (...`values`: `number`\[]) => `number` ; `getMin`: (...`values`: `number`\[]) => `number` ; `getRows`: (`s?`: `string`) => `string`\[] ; `getUrl`: (`useAbsolute`: `boolean`) => `string` ; `hasBreaks`: (`text`: `string`) => `boolean` ; `lineBreakRegex`: `RegExp` ; `removeScript`: (`txt`: `string`) => `string` ; `sanitizeText`: (`text`: `string`, `config`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => `string` ; `sanitizeTextOrArray`: (`a`: `string` \| `string`\[] \| `string`\[]\[], `config`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => `string` \| `string`\[] ; `splitBreaks`: (`text`: `string`) => `string`\[] } |
| `common.evaluate` | (`val?`: `string` \| `boolean`) => `boolean` |
| `common.getMax` | (...`values`: `number`\[]) => `number` |
| `common.getMin` | (...`values`: `number`\[]) => `number` |
| `common.getRows` | (`s?`: `string`) => `string`\[] |
| `common.getUrl` | (`useAbsolute`: `boolean`) => `string` |
| `common.hasBreaks` | (`text`: `string`) => `boolean` |
| `common.lineBreakRegex` | `RegExp` |
| `common.removeScript` | (`txt`: `string`) => `string` |
| `common.sanitizeText` | (`text`: `string`, `config`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => `string` |
| `common.sanitizeTextOrArray` | (`a`: `string` \| `string`\[] \| `string`\[]\[], `config`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => `string` \| `string`\[] |
| `common.splitBreaks` | (`text`: `string`) => `string`\[] |
| `getConfig` | () => [`MermaidConfig`](mermaid.MermaidConfig.md) |
| `insertCluster` | (`elem`: `any`, `node`: `any`) => `Promise`<`any`> |
| `insertEdge` | (`elem`: `any`, `edge`: `any`, `clusterDb`: `any`, `diagramType`: `any`, `startNode`: `any`, `endNode`: `any`, `id`: `any`) => { `originalPath`: `any` ; `updatedPath`: `any` } |
| `insertEdgeLabel` | (`elem`: `any`, `edge`: `any`) => `Promise`<`any`> |
| `insertMarkers` | (`elem`: `any`, `markerArray`: `any`, `type`: `any`, `id`: `any`) => `void` |
| `insertNode` | (`elem`: `any`, `node`: `any`, `dir`: `any`) => `Promise`<`any`> |
| `interpolateToCurve` | (`interpolate`: `undefined` \| `string`, `defaultCurve`: `CurveFactory`) => `CurveFactory` |
| `labelHelper` | (`parent`: `any`, `node`: `any`, `_classes`: `any`) => `Promise`<{ `bbox`: `any` ; `halfPadding`: `number` ; `label`: `any` = labelEl; `shapeSvg`: `any` }> |
| `log` | `Record`<`LogLevel`, (...`data`: `any`\[]) => `void`(`message?`: `any`, ...`optionalParams`: `any`\[]) => `void`> |
| `positionEdgeLabel` | (`edge`: `any`, `paths`: `any`) => `void` |
#### Defined in
[packages/mermaid/src/mermaid.ts:439](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L439)
[packages/mermaid/src/mermaid.ts:434](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L434)
---
### mermaidAPI
**mermaidAPI**: `Readonly`<{ `defaultConfig`: [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.defaultConfig; `getConfig`: () => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.getConfig; `getDiagramFromText`: (`text`: `string`, `metadata`: `Pick`<`DiagramMetadata`, `"title"`>) => `Promise`<`Diagram`> ; `getSiteConfig`: () => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => `void` ; `parse`: (`text`: `string`, `parseOptions`: [`ParseOptions`](mermaid.ParseOptions.md) & { `suppressErrors`: `true` }) => `Promise`<[`ParseResult`](mermaid.ParseResult.md) | `false`>(`text`: `string`, `parseOptions?`: [`ParseOptions`](mermaid.ParseOptions.md)) => `Promise`<[`ParseResult`](mermaid.ParseResult.md)> ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](mermaid.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.setConfig; `updateSiteConfig`: (`conf`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.updateSiteConfig }>
**mermaidAPI**: `Readonly`<{ `defaultConfig`: [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.defaultConfig; `getConfig`: () => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.getConfig; `getDiagramFromText`: (`text`: `string`, `metadata`: `Pick`<`DiagramMetadata`, `"title"`>) => `Promise`<`Diagram`> ; `getSiteConfig`: () => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`userOptions`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => `void` ; `parse`: (`text`: `string`, `parseOptions`: [`ParseOptions`](mermaid.ParseOptions.md) & { `suppressErrors`: `true` }) => `Promise`<[`ParseResult`](mermaid.ParseResult.md) | `false`>(`text`: `string`, `parseOptions?`: [`ParseOptions`](mermaid.ParseOptions.md)) => `Promise`<[`ParseResult`](mermaid.ParseResult.md)> ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](mermaid.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.setConfig; `updateSiteConfig`: (`conf`: [`MermaidConfig`](mermaid.MermaidConfig.md)) => [`MermaidConfig`](mermaid.MermaidConfig.md) = configApi.updateSiteConfig }>
**`Deprecated`**
@@ -173,7 +130,7 @@ Use [parse](mermaid.Mermaid.md#parse) and [render](mermaid.Mermaid.md#render) in
#### Defined in
[packages/mermaid/src/mermaid.ts:421](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L421)
[packages/mermaid/src/mermaid.ts:424](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L424)
---
@@ -223,7 +180,7 @@ Error if the diagram is invalid and parseOptions.suppressErrors is false or not
#### Defined in
[packages/mermaid/src/mermaid.ts:422](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L422)
[packages/mermaid/src/mermaid.ts:425](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L425)
---
@@ -233,7 +190,7 @@ Error if the diagram is invalid and parseOptions.suppressErrors is false or not
#### Defined in
[packages/mermaid/src/mermaid.ts:416](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L416)
[packages/mermaid/src/mermaid.ts:419](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L419)
---
@@ -261,7 +218,7 @@ Used to register external diagram types.
#### Defined in
[packages/mermaid/src/mermaid.ts:430](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L430)
[packages/mermaid/src/mermaid.ts:433](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L433)
---
@@ -285,7 +242,7 @@ Used to register external diagram types.
#### Defined in
[packages/mermaid/src/mermaid.ts:429](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L429)
[packages/mermaid/src/mermaid.ts:432](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L432)
---
@@ -311,7 +268,7 @@ Used to register external diagram types.
#### Defined in
[packages/mermaid/src/mermaid.ts:423](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L423)
[packages/mermaid/src/mermaid.ts:426](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L426)
---
@@ -359,7 +316,7 @@ Renders the mermaid diagrams
#### Defined in
[packages/mermaid/src/mermaid.ts:428](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L428)
[packages/mermaid/src/mermaid.ts:431](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L431)
---
@@ -394,7 +351,7 @@ to it (eg. dart interop wrapper). (Initially there is no parseError member of me
#### Defined in
[packages/mermaid/src/mermaid.ts:433](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L433)
[packages/mermaid/src/mermaid.ts:436](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L436)
---
@@ -404,4 +361,4 @@ to it (eg. dart interop wrapper). (Initially there is no parseError member of me
#### Defined in
[packages/mermaid/src/mermaid.ts:415](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L415)
[packages/mermaid/src/mermaid.ts:418](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L418)

View File

@@ -0,0 +1,19 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/setup/interfaces/mermaid.RenderOptions.md](../../../../packages/mermaid/src/docs/config/setup/interfaces/mermaid.RenderOptions.md).
# Interface: RenderOptions
[mermaid](../modules/mermaid.md).RenderOptions
## Properties
### algorithm
`Optional` **algorithm**: `string`
#### Defined in
[packages/mermaid/src/rendering-util/render.ts:8](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L8)

View File

@@ -18,7 +18,7 @@ The nodes to render. If this is set, `querySelector` will be ignored.
#### Defined in
[packages/mermaid/src/mermaid.ts:45](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L45)
[packages/mermaid/src/mermaid.ts:48](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L48)
---
@@ -44,7 +44,7 @@ A callback to call after each diagram is rendered.
#### Defined in
[packages/mermaid/src/mermaid.ts:49](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L49)
[packages/mermaid/src/mermaid.ts:52](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L52)
---
@@ -56,7 +56,7 @@ The query selector to use when finding elements to render. Default: `".mermaid"`
#### Defined in
[packages/mermaid/src/mermaid.ts:41](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L41)
[packages/mermaid/src/mermaid.ts:44](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L44)
---
@@ -68,4 +68,4 @@ If `true`, errors will be logged to the console, but not thrown. Default: `false
#### Defined in
[packages/mermaid/src/mermaid.ts:53](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L53)
[packages/mermaid/src/mermaid.ts:56](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L56)

View File

@@ -14,7 +14,7 @@
#### Defined in
[packages/mermaid/src/defaultConfig.ts:279](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L279)
[packages/mermaid/src/defaultConfig.ts:266](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L266)
---

View File

@@ -20,11 +20,22 @@
- [MermaidConfig](../interfaces/mermaid.MermaidConfig.md)
- [ParseOptions](../interfaces/mermaid.ParseOptions.md)
- [ParseResult](../interfaces/mermaid.ParseResult.md)
- [RenderOptions](../interfaces/mermaid.RenderOptions.md)
- [RenderResult](../interfaces/mermaid.RenderResult.md)
- [RunOptions](../interfaces/mermaid.RunOptions.md)
## Type Aliases
### InternalHelpers
Ƭ **InternalHelpers**: typeof `internalHelpers`
#### Defined in
[packages/mermaid/src/internals.ts:33](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/internals.ts#L33)
---
### ParseErrorFunction
Ƭ **ParseErrorFunction**: (`err`: `string` | [`DetailedError`](../interfaces/mermaid.DetailedError.md) | `unknown`, `hash?`: `any`) => `void`
@@ -48,6 +59,26 @@
[packages/mermaid/src/Diagram.ts:10](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/Diagram.ts#L10)
---
### SVG
Ƭ **SVG**: `d3.Selection`<`SVGSVGElement`, `unknown`, `Element` | `null`, `unknown`>
#### Defined in
[packages/mermaid/src/diagram-api/types.ts:130](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L130)
---
### SVGGroup
Ƭ **SVGGroup**: `d3.Selection`<`SVGGElement`, `unknown`, `Element` | `null`, `unknown`>
#### Defined in
[packages/mermaid/src/diagram-api/types.ts:132](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L132)
## Variables
### default
@@ -56,4 +87,4 @@
#### Defined in
[packages/mermaid/src/mermaid.ts:442](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L442)
[packages/mermaid/src/mermaid.ts:440](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaid.ts#L440)

View File

@@ -59,6 +59,7 @@ To add an integration to this list, see the [Integrations - create page](./integ
- [MonsterWriter](https://www.monsterwriter.com/) ✅
- [Joplin](https://joplinapp.org) ✅
- [LiveBook](https://livebook.dev) ✅
- [Slidev](https://sli.dev) ✅
- [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) ✅
- [Mermaid Flow Visual Editor](https://www.mermaidflow.app) ✅
- [Mermerd](https://github.com/KarnerTh/mermerd)
@@ -134,7 +135,7 @@ Communication tools and platforms
### Wikis
- [DokuWiki](https://dokuwiki.org)
- [ComboStrap](https://combostrap.com/mermaid)
- [ComboStrap](https://combostrap.com/utility/create-diagram-with-mermaid-vh3ab9yj)
- [Mermaid Plugin](https://www.dokuwiki.org/plugin:mermaid)
- [Foswiki](https://foswiki.org)
- [Mermaid Plugin](https://foswiki.org/Extensions/MermaidPlugin)

View File

@@ -12,7 +12,7 @@ Try the Ultimate AI, Mermaid, and Visual Diagramming Suite by creating an accoun
<br />
<a href="https://www.producthunt.com/posts/mermaid-chart?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-mermaid&#0045;chart" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=416671&theme=light" alt="Mermaid&#0032;Chart - A&#0032;smarter&#0032;way&#0032;to&#0032;create&#0032;diagrams | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<a href="https://www.producthunt.com/products/mermaid-chart?utm_source=badge-follow&utm_medium=badge&utm_souce=badge-mermaid&#0045;chart" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/follow.svg?product_id=552855&theme=light" alt="Mermaid&#0032;Chart - A&#0032;smarter&#0032;way&#0032;to&#0032;create&#0032;diagrams | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
## About

View File

@@ -83,3 +83,139 @@ Allows for the limited reconfiguration of a diagram just before it is rendered.
### [Theme Manipulation](../config/theming.md)
An application of using Directives to change [Themes](../config/theming.md). `Theme` is a value within Mermaid's configuration that dictates the color scheme for diagrams.
### Layout and look
We've restructured how Mermaid renders diagrams, enabling new features like selecting layout and look. **Currently, this is supported for flowcharts and state diagrams**, with plans to extend support to all diagram types.
### Selecting Diagram Looks
Mermaid offers a variety of styles or “looks” for your diagrams, allowing you to tailor the visual appearance to match your specific needs or preferences. Whether you prefer a hand-drawn or classic style, you can easily customize your diagrams.
**Available Looks:**
```
• Hand-Drawn Look: For a more personal, creative touch, the hand-drawn look brings a sketch-like quality to your diagrams. This style is perfect for informal settings or when you want to add a bit of personality to your diagrams.
• Classic Look: If you prefer the traditional Mermaid style, the classic look maintains the original appearance that many users are familiar with. Its great for consistency across projects or when you want to keep the familiar aesthetic.
```
**How to Select a Look:**
You can select a look by adding the look parameter in the metadata section of your Mermaid diagram code. Heres an example:
```mermaid-example
---
config:
look: handDrawn
theme: neutral
---
flowchart LR
A[Start] --> B{Decision}
B -->|Yes| C[Continue]
B -->|No| D[Stop]
```
```mermaid
---
config:
look: handDrawn
theme: neutral
---
flowchart LR
A[Start] --> B{Decision}
B -->|Yes| C[Continue]
B -->|No| D[Stop]
```
#### Selecting Layout Algorithms
In addition to customizing the look of your diagrams, Mermaid Chart now allows you to choose different layout algorithms to better organize and present your diagrams, especially when dealing with more complex structures. The layout algorithm dictates how nodes and edges are arranged on the page.
#### Supported Layout Algorithms:
```
• Dagre (default): This is the classic layout algorithm that has been used in Mermaid for a long time. It provides a good balance of simplicity and visual clarity, making it ideal for most diagrams.
• ELK: For those who need more sophisticated layout capabilities, especially when working with large or intricate diagrams, the ELK (Eclipse Layout Kernel) layout offers advanced options. It provides a more optimized arrangement, potentially reducing overlapping and improving readability. This is not included out the box but needs to be added when integrating mermaid for sites/applications that want to have elk support.
```
#### How to Select a Layout Algorithm:
You can specify the layout algorithm directly in the metadata section of your Mermaid diagram code. Heres an example:
```mermaid-example
---
config:
layout: elk
look: handDrawn
theme: dark
---
flowchart TB
A[Start] --> B{Decision}
B -->|Yes| C[Continue]
B -->|No| D[Stop]
```
```mermaid
---
config:
layout: elk
look: handDrawn
theme: dark
---
flowchart TB
A[Start] --> B{Decision}
B -->|Yes| C[Continue]
B -->|No| D[Stop]
```
In this example, the `layout: elk` line configures the diagram to use the ELK layout algorithm, along with the hand drawn look and forest theme.
#### Customizing ELK Layout:
When using the ELK layout, you can further refine the diagrams configuration, such as how nodes are placed and whether parallel edges should be combined:
- To combine parallel edges, use mergeEdges: true | false.
- To configure node placement, use nodePlacementStrategy with the following options:
- SIMPLE
- NETWORK_SIMPLEX
- LINEAR_SEGMENTS
- BRANDES_KOEPF (default)
**Example configuration:**
```
---
config:
layout: elk
elk:
mergeEdges: true
nodePlacementStrategy: LINEAR_SEGMENTS
---
flowchart LR
A[Start] --> B{Choose Path}
B -->|Option 1| C[Path 1]
B -->|Option 2| D[Path 2]
#### Using Dagre Layout with Classic Look:
```
Another example:
```
---
config:
layout: dagre
look: classic
theme: default
---
flowchart LR
A[Start] --> B{Choose Path}
B -->|Option 1| C[Path 1]
B -->|Option 2| D[Path 2]
```
These options give you the flexibility to create diagrams that not only look great but are also arranged to best suit your datas structure and flow.
When integrating Mermaid, you can include look and layout configuration with the initialize call. This is also where you add the loading of elk.

View File

@@ -6,6 +6,48 @@
# Blog
## [Mermaid v11 is out!](https://www.mermaidchart.com/blog/posts/mermaid-v11/)
23 August 2024 · 2 mins
Mermaid v11 introduces advanced layout options, new diagram types, and enhanced customization features, thanks to the incredible contributions from our community.
## [Mermaid Innovation - Introducing New Looks for Mermaid Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-innovation-introducing-new-looks-for-mermaid-diagrams/)
6 August 2024 ·3 mins
Discover the fresh new and unique Neo and Hand-Drawn looks for Mermaid Diagrams, while still offering the classic look you love.
## [The Mermaid Chart Plugin for Jira: A How-To User Guide](https://www.mermaidchart.com/blog/posts/the-mermaid-chart-plugin-for-jira-a-how-to-user-guide/)
31 July 2024 · 5 mins
The Mermaid Chart plugin for Jira has arrived!
## [Mermaid AI Is Here to Change the Game For Diagram Creation](https://www.mermaidchart.com/blog/posts/mermaid-ai-is-here-to-change-the-game-for-diagram-creation/)
22 July 2024 · 5 mins
The Mermaid AI chat interface
## [How to Make a Sequence Diagram with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-sequence-diagram-in-mermaid-chart-step-by-step-guide/)
8 July 2024 · 6 mins
Sequence diagrams are important for communicating complex systems in a clear and concise manner.
## [How to Use the New “Comments” Feature in Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-use-the-new-comments-feature-in-mermaid-chart/)
2 July 2024 · 3 mins
How to Use the New Comments Feature in Mermaid Chart
## [How to Use the official Mermaid Chart for Confluence app](https://www.mermaidchart.com/blog/posts/how-to-use-the-official-mermaid-chart-for-confluence-app/)
21 May 2024 · 4 mins
It doesnt matter if youre a data enthusiast, software engineer, or visual storyteller; our Confluence app can allow you to embed Mermaid Chart diagrams — and dynamically edit them — within your Confluence pages.
## [How to Choose the Right Documentation Software](https://www.mermaidchart.com/blog/posts/how-to-choose-the-right-documentation-software/)
7 May 2024 · 5 mins

View File

@@ -172,7 +172,7 @@ The `title` is an _optional_ string to be displayed at the top of the Gantt char
The `excludes` is an _optional_ attribute that accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays".
These date will be marked on the graph, and be excluded from the duration calculation of tasks. Meaning that if there are excluded dates during a task interval, the number of 'skipped' days will be added to the end of the task to ensure the duration is as specified in the code.
#### Weekend (v\<MERMAID_RELEASE_VERSION>+)
#### Weekend (v\11.0.0+)
When excluding weekends, it is possible to configure the weekends to be either Friday and Saturday or Saturday and Sunday. By default weekends are Saturday and Sunday.
To define the weekend start day, there is an _optional_ attribute `weekend` that can be added in a new line followed by either `friday` or `saturday`.

View File

@@ -918,7 +918,7 @@ Usage example:
commit
```
### Bottom to Top (`BT:`) (v\<MERMAID_RELEASE_VERSION>+)
### Bottom to Top (`BT:`) (v11.0.0+)
In `BT` (**Bottom-to-Top**) orientation, the commits run from bottom to top of the graph and branches are arranged side-by-side.

View File

@@ -4,7 +4,7 @@
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/packet.md](../../packages/mermaid/src/docs/syntax/packet.md).
# Packet Diagram (v\<MERMAID_RELEASE_VERSION>+)
# Packet Diagram (v11.0.0+)
## Introduction

View File

@@ -208,18 +208,18 @@ Messages can be of two displayed either solid or with a dotted line.
There are ten types of arrows currently supported:
| Type | Description |
| -------- | ------------------------------------------------------------------------ |
| `->` | Solid line without arrow |
| `-->` | Dotted line without arrow |
| `->>` | Solid line with arrowhead |
| `-->>` | Dotted line with arrowhead |
| `<<->>` | Solid line with bidirectional arrowheads (v\<MERMAID_RELEASE_VERSION>+) |
| `<<-->>` | Dotted line with bidirectional arrowheads (v\<MERMAID_RELEASE_VERSION>+) |
| `-x` | Solid line with a cross at the end |
| `--x` | Dotted line with a cross at the end. |
| `-)` | Solid line with an open arrow at the end (async) |
| `--)` | Dotted line with a open arrow at the end (async) |
| Type | Description |
| -------- | ---------------------------------------------------- |
| `->` | Solid line without arrow |
| `-->` | Dotted line without arrow |
| `->>` | Solid line with arrowhead |
| `-->>` | Dotted line with arrowhead |
| `<<->>` | Solid line with bidirectional arrowheads (v11.0.0+) |
| `<<-->>` | Dotted line with bidirectional arrowheads (v11.0.0+) |
| `-x` | Solid line with a cross at the end |
| `--x` | Dotted line with a cross at the end. |
| `-)` | Solid line with an open arrow at the end (async) |
| `--)` | Dotted line with a open arrow at the end (async) |
## Activations

View File

@@ -4,7 +4,7 @@
"version": "10.2.4",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module",
"packageManager": "pnpm@9.4.0+sha512.f549b8a52c9d2b8536762f99c0722205efc5af913e77835dbccc3b0b0b2ca9e7dc8022b78062c17291c48e88749c70ce88eb5a74f1fa8c4bf5e18bb46c8bd83a",
"packageManager": "pnpm@9.7.1+sha512.faf344af2d6ca65c4c5c8c2224ea77a81a5e8859cbc4e06b1511ddce2f0151512431dd19e6aff31f2c6a8f5f2aced9bd2273e1fed7dd4de1868984059d2c4247",
"keywords": [
"diagram",
"markdown",
@@ -24,7 +24,9 @@
"dev": "tsx .esbuild/server.ts",
"dev:vite": "tsx .vite/server.ts",
"dev:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm dev:vite",
"release": "pnpm build",
"copy-readme": "cpy './README.*' ./packages/mermaid/ --cwd=.",
"changeset:version": "changeset version && pnpm build && pnpm --filter mermaid run docs:release-version && pnpm --filter mermaid run docs:build && git add --all",
"changeset:publish": "pnpm copy-readme && changeset publish",
"lint": "eslint --quiet --stats --cache --cache-strategy content . && pnpm lint:jison && prettier --cache --check .",
"lint:fix": "eslint --cache --cache-strategy content --fix . && prettier --write . && tsx scripts/fixCSpell.ts",
"lint:jison": "tsx ./scripts/jison/lint.mts",
@@ -40,7 +42,6 @@
"test": "pnpm lint && vitest run",
"test:watch": "vitest --watch",
"test:coverage": "vitest --coverage",
"prepublishOnly": "pnpm build && pnpm test",
"prepare": "husky install && pnpm build",
"pre-commit": "lint-staged"
},
@@ -63,6 +64,8 @@
"devDependencies": {
"@applitools/eyes-cypress": "^3.44.4",
"@argos-ci/cypress": "^2.1.0",
"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.27.7",
"@cspell/eslint-plugin": "^8.8.4",
"@cypress/code-coverage": "^3.12.30",
"@eslint/js": "^9.4.0",
@@ -82,6 +85,7 @@
"chokidar": "^3.6.0",
"concurrently": "^8.2.2",
"cors": "^2.8.5",
"cpy-cli": "^5.0.0",
"cross-env": "^7.0.3",
"cspell": "^8.6.0",
"cypress": "^13.11.0",

View File

@@ -1,6 +1,7 @@
{
"name": "@mermaid-js/mermaid-example-diagram",
"version": "9.3.0",
"private": true,
"description": "Example of external diagram module for MermaidJS.",
"module": "dist/mermaid-example-diagram.core.mjs",
"types": "dist/detector.d.ts",
@@ -18,9 +19,7 @@
"example",
"mermaid"
],
"scripts": {
"prepublishOnly": "pnpm -w run build"
},
"scripts": {},
"repository": {
"type": "git",
"url": "https://github.com/mermaid-js/mermaid"

View File

@@ -1,45 +0,0 @@
{
"name": "@mermaid-js/flowchart-elk",
"version": "1.0.0-rc.1",
"description": "Flowchart plugin for mermaid with ELK layout",
"module": "dist/mermaid-flowchart-elk.core.mjs",
"types": "dist/packages/mermaid-flowchart-elk/src/detector.d.ts",
"type": "module",
"exports": {
".": {
"import": "./dist/mermaid-flowchart-elk.core.mjs",
"types": "./dist/packages/mermaid-flowchart-elk/src/detector.d.ts"
},
"./*": "./*"
},
"keywords": [
"diagram",
"markdown",
"flowchart",
"elk",
"mermaid"
],
"scripts": {
"prepublishOnly": "pnpm -w run build"
},
"repository": {
"type": "git",
"url": "https://github.com/mermaid-js/mermaid"
},
"author": "Knut Sveidqvist",
"license": "MIT",
"dependencies": {
"d3": "^7.9.0",
"dagre-d3-es": "7.0.10",
"elkjs": "^0.9.2",
"khroma": "^2.1.0"
},
"devDependencies": {
"concurrently": "^8.2.2",
"mermaid": "workspace:^",
"rimraf": "^5.0.5"
},
"files": [
"dist"
]
}

View File

@@ -1,75 +0,0 @@
import plugin from './detector.js';
import { describe, it } from 'vitest';
const { detector } = plugin;
describe('flowchart-elk detector', () => {
it('should fail for dagre-d3', () => {
expect(
detector('flowchart', {
flowchart: {
defaultRenderer: 'dagre-d3',
},
})
).toBe(false);
});
it('should fail for dagre-wrapper', () => {
expect(
detector('flowchart', {
flowchart: {
defaultRenderer: 'dagre-wrapper',
},
})
).toBe(false);
});
it('should succeed for elk', () => {
expect(
detector('flowchart', {
flowchart: {
defaultRenderer: 'elk',
},
})
).toBe(true);
expect(
detector('graph', {
flowchart: {
defaultRenderer: 'elk',
},
})
).toBe(true);
});
// The error from the issue was reproduced with mindmap, so this is just an example
// what matters is the keyword somewhere inside graph definition
it('should check only the beginning of the line in search of keywords', () => {
expect(
detector('mindmap ["Descendant node in flowchart"]', {
flowchart: {
defaultRenderer: 'elk',
},
})
).toBe(false);
expect(
detector('mindmap ["Descendant node in graph"]', {
flowchart: {
defaultRenderer: 'elk',
},
})
).toBe(false);
});
it('should detect flowchart-elk', () => {
expect(detector('flowchart-elk')).toBe(true);
});
it('should not detect class with defaultRenderer set to elk', () => {
expect(
detector('class', {
flowchart: {
defaultRenderer: 'elk',
},
})
).toBe(false);
});
});

View File

@@ -1,32 +0,0 @@
import type {
ExternalDiagramDefinition,
DiagramDetector,
DiagramLoader,
} from '../../mermaid/src/diagram-api/types.js';
const id = 'flowchart-elk';
const detector: DiagramDetector = (txt, config): boolean => {
if (
// If diagram explicitly states flowchart-elk
/^\s*flowchart-elk/.test(txt) ||
// If a flowchart/graph diagram has their default renderer set to elk
(/^\s*(flowchart|graph)/.test(txt) && config?.flowchart?.defaultRenderer === 'elk')
) {
return true;
}
return false;
};
const loader: DiagramLoader = async () => {
const { diagram } = await import('./diagram-definition.js');
return { id, diagram };
};
const plugin: ExternalDiagramDefinition = {
id,
detector,
loader,
};
export default plugin;

View File

@@ -1,12 +0,0 @@
// @ts-ignore: JISON typing missing
import parser from '../../mermaid/src/diagrams/flowchart/parser/flow.jison';
import db from '../../mermaid/src/diagrams/flowchart/flowDb.js';
import styles from '../../mermaid/src/diagrams/flowchart/styles.js';
import renderer from './flowRenderer-elk.js';
export const diagram = {
db,
renderer,
parser,
styles,
};

View File

@@ -1,888 +0,0 @@
import { select, line, curveLinear } from 'd3';
import { insertNode } from '../../mermaid/src/dagre-wrapper/nodes.js';
import insertMarkers from '../../mermaid/src/dagre-wrapper/markers.js';
import { insertEdgeLabel } from '../../mermaid/src/dagre-wrapper/edges.js';
import { findCommonAncestor } from './render-utils.js';
import { labelHelper } from '../../mermaid/src/dagre-wrapper/shapes/util.js';
import { getConfig } from '../../mermaid/src/config.js';
import { log } from '../../mermaid/src/logger.js';
import utils from '../../mermaid/src/utils.js';
import { setupGraphViewbox } from '../../mermaid/src/setupGraphViewbox.js';
import common from '../../mermaid/src/diagrams/common/common.js';
import { interpolateToCurve, getStylesFromArray } from '../../mermaid/src/utils.js';
import ELK from 'elkjs/lib/elk.bundled.js';
import { getLineFunctionsWithOffset } from '../../mermaid/src/utils/lineWithOffset.js';
import { addEdgeMarkers } from '../../mermaid/src/dagre-wrapper/edgeMarker.js';
const elk = new ELK();
let portPos = {};
const conf = {};
export const setConf = function (cnf) {
const keys = Object.keys(cnf);
for (const key of keys) {
conf[key] = cnf[key];
}
};
let nodeDb = {};
// /**
// * Function that adds the vertices found during parsing to the graph to be rendered.
// *
// * @param vert Object containing the vertices.
// * @param g The graph that is to be drawn.
// * @param svgId
// * @param root
// * @param doc
// * @param diagObj
// */
export const addVertices = async function (vert, svgId, root, doc, diagObj, parentLookupDb, graph) {
const svg = root.select(`[id="${svgId}"]`);
const nodes = svg.insert('g').attr('class', 'nodes');
const keys = [...vert.keys()];
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
await Promise.all(
keys.map(async function (id) {
const vertex = vert.get(id);
/**
* Variable for storing the classes for the vertex
*
* @type {string}
*/
let classStr = 'default';
if (vertex.classes.length > 0) {
classStr = vertex.classes.join(' ');
}
classStr = classStr + ' flowchart-label';
const styles = getStylesFromArray(vertex.styles);
// Use vertex id as text in the box if no text is provided by the graph definition
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id;
// We create a SVG label, either by delegating to addHtmlLabel or manually
const labelData = { width: 0, height: 0 };
const ports = [
{
id: vertex.id + '-west',
layoutOptions: {
'port.side': 'WEST',
},
},
{
id: vertex.id + '-east',
layoutOptions: {
'port.side': 'EAST',
},
},
{
id: vertex.id + '-south',
layoutOptions: {
'port.side': 'SOUTH',
},
},
{
id: vertex.id + '-north',
layoutOptions: {
'port.side': 'NORTH',
},
},
];
let radius = 0;
let _shape = '';
let layoutOptions = {};
// Set the shape based parameters
switch (vertex.type) {
case 'round':
radius = 5;
_shape = 'rect';
break;
case 'square':
_shape = 'rect';
break;
case 'diamond':
_shape = 'question';
layoutOptions = {
portConstraints: 'FIXED_SIDE',
};
break;
case 'hexagon':
_shape = 'hexagon';
break;
case 'odd':
_shape = 'rect_left_inv_arrow';
break;
case 'lean_right':
_shape = 'lean_right';
break;
case 'lean_left':
_shape = 'lean_left';
break;
case 'trapezoid':
_shape = 'trapezoid';
break;
case 'inv_trapezoid':
_shape = 'inv_trapezoid';
break;
case 'odd_right':
_shape = 'rect_left_inv_arrow';
break;
case 'circle':
_shape = 'circle';
break;
case 'ellipse':
_shape = 'ellipse';
break;
case 'stadium':
_shape = 'stadium';
break;
case 'subroutine':
_shape = 'subroutine';
break;
case 'cylinder':
_shape = 'cylinder';
break;
case 'group':
_shape = 'rect';
break;
case 'doublecircle':
_shape = 'doublecircle';
break;
default:
_shape = 'rect';
}
// Add the node
const node = {
labelStyle: styles.labelStyle,
shape: _shape,
labelText: vertexText,
labelType: vertex.labelType,
rx: radius,
ry: radius,
class: classStr,
style: styles.style,
id: vertex.id,
link: vertex.link,
linkTarget: vertex.linkTarget,
tooltip: diagObj.db.getTooltip(vertex.id) || '',
domId: diagObj.db.lookUpDomId(vertex.id),
haveCallback: vertex.haveCallback,
width: vertex.type === 'group' ? 500 : undefined,
dir: vertex.dir,
type: vertex.type,
props: vertex.props,
padding: getConfig().flowchart.padding,
};
let boundingBox;
let nodeEl;
// Add the element to the DOM
if (node.type !== 'group') {
nodeEl = await insertNode(nodes, node, vertex.dir);
boundingBox = nodeEl.node().getBBox();
} else {
const { shapeSvg, bbox } = await labelHelper(nodes, node, undefined, true);
labelData.width = bbox.width;
labelData.wrappingWidth = getConfig().flowchart.wrappingWidth;
labelData.height = bbox.height;
labelData.labelNode = shapeSvg.node();
node.labelData = labelData;
}
// const { shapeSvg, bbox } = await labelHelper(svg, node, undefined, true);
const data = {
id: vertex.id,
ports: vertex.type === 'diamond' ? ports : [],
// labelStyle: styles.labelStyle,
// shape: _shape,
layoutOptions,
labelText: vertexText,
labelData,
// labels: [{ text: vertexText }],
// rx: radius,
// ry: radius,
// class: classStr,
// style: styles.style,
// link: vertex.link,
// linkTarget: vertex.linkTarget,
// tooltip: diagObj.db.getTooltip(vertex.id) || '',
domId: diagObj.db.lookUpDomId(vertex.id),
// haveCallback: vertex.haveCallback,
width: boundingBox?.width,
height: boundingBox?.height,
// dir: vertex.dir,
type: vertex.type,
// props: vertex.props,
// padding: getConfig().flowchart.padding,
// boundingBox,
el: nodeEl,
parent: parentLookupDb.parentById[vertex.id],
};
// if (!Object.keys(parentLookupDb.childrenById).includes(vertex.id)) {
// graph.children.push({
// ...data,
// });
// }
nodeDb[node.id] = data;
// log.trace('setNode', {
// labelStyle: styles.labelStyle,
// shape: _shape,
// labelText: vertexText,
// rx: radius,
// ry: radius,
// class: classStr,
// style: styles.style,
// id: vertex.id,
// domId: diagObj.db.lookUpDomId(vertex.id),
// width: vertex.type === 'group' ? 500 : undefined,
// type: vertex.type,
// dir: vertex.dir,
// props: vertex.props,
// padding: getConfig().flowchart.padding,
// parent: parentLookupDb.parentById[vertex.id],
// });
})
);
return graph;
};
const getNextPosition = (position, edgeDirection, graphDirection) => {
const portPos = {
TB: {
in: {
north: 'north',
},
out: {
south: 'west',
west: 'east',
east: 'south',
},
},
LR: {
in: {
west: 'west',
},
out: {
east: 'south',
south: 'north',
north: 'east',
},
},
RL: {
in: {
east: 'east',
},
out: {
west: 'north',
north: 'south',
south: 'west',
},
},
BT: {
in: {
south: 'south',
},
out: {
north: 'east',
east: 'west',
west: 'north',
},
},
};
portPos.TD = portPos.TB;
return portPos[graphDirection][edgeDirection][position];
// return 'south';
};
const getNextPort = (node, edgeDirection, graphDirection) => {
log.info('getNextPort', { node, edgeDirection, graphDirection });
if (!portPos[node]) {
switch (graphDirection) {
case 'TB':
case 'TD':
portPos[node] = {
inPosition: 'north',
outPosition: 'south',
};
break;
case 'BT':
portPos[node] = {
inPosition: 'south',
outPosition: 'north',
};
break;
case 'RL':
portPos[node] = {
inPosition: 'east',
outPosition: 'west',
};
break;
case 'LR':
portPos[node] = {
inPosition: 'west',
outPosition: 'east',
};
break;
}
}
const result = edgeDirection === 'in' ? portPos[node].inPosition : portPos[node].outPosition;
if (edgeDirection === 'in') {
portPos[node].inPosition = getNextPosition(
portPos[node].inPosition,
edgeDirection,
graphDirection
);
} else {
portPos[node].outPosition = getNextPosition(
portPos[node].outPosition,
edgeDirection,
graphDirection
);
}
return result;
};
const getEdgeStartEndPoint = (edge, dir) => {
let source = edge.start;
let target = edge.end;
// Save the original source and target
const sourceId = source;
const targetId = target;
const startNode = nodeDb[source];
const endNode = nodeDb[target];
if (!startNode || !endNode) {
return { source, target };
}
if (startNode.type === 'diamond') {
source = `${source}-${getNextPort(source, 'out', dir)}`;
}
if (endNode.type === 'diamond') {
target = `${target}-${getNextPort(target, 'in', dir)}`;
}
// Add the edge to the graph
return { source, target, sourceId, targetId };
};
/**
* Add edges to graph based on parsed graph definition
*
* @param {object} edges The edges to add to the graph
* @param {object} g The graph object
* @param cy
* @param diagObj
* @param graph
* @param svg
*/
export const addEdges = function (edges, diagObj, graph, svg) {
log.info('abc78 edges = ', edges);
const labelsEl = svg.insert('g').attr('class', 'edgeLabels');
let linkIdCnt = {};
let dir = diagObj.db.getDirection();
let defaultStyle;
let defaultLabelStyle;
if (edges.defaultStyle !== undefined) {
const defaultStyles = getStylesFromArray(edges.defaultStyle);
defaultStyle = defaultStyles.style;
defaultLabelStyle = defaultStyles.labelStyle;
}
edges.forEach(function (edge) {
// Identify Link
const linkIdBase = 'L-' + edge.start + '-' + edge.end;
// count the links from+to the same node to give unique id
if (linkIdCnt[linkIdBase] === undefined) {
linkIdCnt[linkIdBase] = 0;
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
} else {
linkIdCnt[linkIdBase]++;
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
}
let linkId = linkIdBase + '-' + linkIdCnt[linkIdBase];
log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);
const linkNameStart = 'LS-' + edge.start;
const linkNameEnd = 'LE-' + edge.end;
const edgeData = { style: '', labelStyle: '' };
edgeData.minlen = edge.length || 1;
//edgeData.id = 'id' + cnt;
// Set link type for rendering
if (edge.type === 'arrow_open') {
edgeData.arrowhead = 'none';
} else {
edgeData.arrowhead = 'normal';
}
// Check of arrow types, placed here in order not to break old rendering
edgeData.arrowTypeStart = 'arrow_open';
edgeData.arrowTypeEnd = 'arrow_open';
/* eslint-disable no-fallthrough */
switch (edge.type) {
case 'double_arrow_cross':
edgeData.arrowTypeStart = 'arrow_cross';
case 'arrow_cross':
edgeData.arrowTypeEnd = 'arrow_cross';
break;
case 'double_arrow_point':
edgeData.arrowTypeStart = 'arrow_point';
case 'arrow_point':
edgeData.arrowTypeEnd = 'arrow_point';
break;
case 'double_arrow_circle':
edgeData.arrowTypeStart = 'arrow_circle';
case 'arrow_circle':
edgeData.arrowTypeEnd = 'arrow_circle';
break;
}
let style = '';
let labelStyle = '';
switch (edge.stroke) {
case 'normal':
style = 'fill:none;';
if (defaultStyle !== undefined) {
style = defaultStyle;
}
if (defaultLabelStyle !== undefined) {
labelStyle = defaultLabelStyle;
}
edgeData.thickness = 'normal';
edgeData.pattern = 'solid';
break;
case 'dotted':
edgeData.thickness = 'normal';
edgeData.pattern = 'dotted';
edgeData.style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
break;
case 'thick':
edgeData.thickness = 'thick';
edgeData.pattern = 'solid';
edgeData.style = 'stroke-width: 3.5px;fill:none;';
break;
}
if (edge.style !== undefined) {
const styles = getStylesFromArray(edge.style);
style = styles.style;
labelStyle = styles.labelStyle;
}
edgeData.style = edgeData.style += style;
edgeData.labelStyle = edgeData.labelStyle += labelStyle;
if (edge.interpolate !== undefined) {
edgeData.curve = interpolateToCurve(edge.interpolate, curveLinear);
} else if (edges.defaultInterpolate !== undefined) {
edgeData.curve = interpolateToCurve(edges.defaultInterpolate, curveLinear);
} else {
edgeData.curve = interpolateToCurve(conf.curve, curveLinear);
}
if (edge.text === undefined) {
if (edge.style !== undefined) {
edgeData.arrowheadStyle = 'fill: #333';
}
} else {
edgeData.arrowheadStyle = 'fill: #333';
edgeData.labelpos = 'c';
}
edgeData.labelType = edge.labelType;
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
if (edge.style === undefined) {
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;';
}
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
edgeData.id = linkId;
edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd;
const labelEl = insertEdgeLabel(labelsEl, edgeData);
// calculate start and end points of the edge, note that the source and target
// can be modified for shapes that have ports
const { source, target, sourceId, targetId } = getEdgeStartEndPoint(edge, dir);
log.debug('abc78 source and target', source, target);
// Add the edge to the graph
graph.edges.push({
id: 'e' + edge.start + edge.end,
sources: [source],
targets: [target],
sourceId,
targetId,
labelEl: labelEl,
labels: [
{
width: edgeData.width,
height: edgeData.height,
orgWidth: edgeData.width,
orgHeight: edgeData.height,
text: edgeData.label,
layoutOptions: {
'edgeLabels.inline': 'true',
'edgeLabels.placement': 'CENTER',
},
},
],
edgeData,
});
});
return graph;
};
// TODO: break out and share with dagre wrapper. The current code in dagre wrapper also adds
// adds the line to the graph, but we don't need that here. This is why we can't use the dagre
// wrapper directly for this
/**
* Add the markers to the edge depending on the type of arrow is
* @param svgPath
* @param edgeData
* @param diagramType
* @param arrowMarkerAbsolute
* @param id
*/
const addMarkersToEdge = function (svgPath, edgeData, diagramType, arrowMarkerAbsolute, id) {
let url = '';
// Check configuration for absolute path
if (arrowMarkerAbsolute) {
url =
window.location.protocol +
'//' +
window.location.host +
window.location.pathname +
window.location.search;
url = url.replace(/\(/g, '\\(');
url = url.replace(/\)/g, '\\)');
}
// look in edge data and decide which marker to use
addEdgeMarkers(svgPath, edgeData, url, id, diagramType);
};
/**
* Returns the all the styles from classDef statements in the graph definition.
*
* @param text
* @param diagObj
* @returns {Map<string, import('../../mermaid/src/diagram-api/types.js').DiagramStyleClassDef>} ClassDef styles
*/
export const getClasses = function (text, diagObj) {
log.info('Extracting classes');
return diagObj.db.getClasses();
};
const addSubGraphs = function (db) {
const parentLookupDb = { parentById: {}, childrenById: {} };
const subgraphs = db.getSubGraphs();
log.info('Subgraphs - ', subgraphs);
subgraphs.forEach(function (subgraph) {
subgraph.nodes.forEach(function (node) {
parentLookupDb.parentById[node] = subgraph.id;
if (parentLookupDb.childrenById[subgraph.id] === undefined) {
parentLookupDb.childrenById[subgraph.id] = [];
}
parentLookupDb.childrenById[subgraph.id].push(node);
});
});
subgraphs.forEach(function (subgraph) {
const data = { id: subgraph.id };
if (parentLookupDb.parentById[subgraph.id] !== undefined) {
data.parent = parentLookupDb.parentById[subgraph.id];
}
});
return parentLookupDb;
};
const calcOffset = function (src, dest, parentLookupDb) {
const ancestor = findCommonAncestor(src, dest, parentLookupDb);
if (ancestor === undefined || ancestor === 'root') {
return { x: 0, y: 0 };
}
const ancestorOffset = nodeDb[ancestor].offset;
return { x: ancestorOffset.posX, y: ancestorOffset.posY };
};
const insertEdge = function (edgesEl, edge, edgeData, diagObj, parentLookupDb, id) {
const offset = calcOffset(edge.sourceId, edge.targetId, parentLookupDb);
const src = edge.sections[0].startPoint;
const dest = edge.sections[0].endPoint;
const segments = edge.sections[0].bendPoints ? edge.sections[0].bendPoints : [];
const segPoints = segments.map((segment) => [segment.x + offset.x, segment.y + offset.y]);
const points = [
[src.x + offset.x, src.y + offset.y],
...segPoints,
[dest.x + offset.x, dest.y + offset.y],
];
const { x, y } = getLineFunctionsWithOffset(edge.edgeData);
const curve = line().x(x).y(y).curve(curveLinear);
const edgePath = edgesEl
.insert('path')
.attr('d', curve(points))
.attr('class', 'path ' + edgeData.classes)
.attr('fill', 'none');
Object.entries(edgeData).forEach(([key, value]) => {
if (key !== 'classes') {
edgePath.attr(key, value);
}
});
const edgeG = edgesEl.insert('g').attr('class', 'edgeLabel');
const edgeWithLabel = select(edgeG.node().appendChild(edge.labelEl));
const box = edgeWithLabel.node().firstChild.getBoundingClientRect();
edgeWithLabel.attr('width', box.width);
edgeWithLabel.attr('height', box.height);
edgeG.attr(
'transform',
`translate(${edge.labels[0].x + offset.x}, ${edge.labels[0].y + offset.y})`
);
addMarkersToEdge(edgePath, edgeData, diagObj.type, diagObj.arrowMarkerAbsolute, id);
};
/**
* Recursive function that iterates over an array of nodes and inserts the children of each node.
* It also recursively populates the inserts the children of the children and so on.
* @param nodeArray
* @param parentLookupDb
*/
const insertChildren = (nodeArray, parentLookupDb) => {
nodeArray.forEach((node) => {
// Check if we have reached the end of the tree
if (!node.children) {
node.children = [];
}
// Check if the node has children
const childIds = parentLookupDb.childrenById[node.id];
// If the node has children, add them to the node
if (childIds) {
childIds.forEach((childId) => {
node.children.push(nodeDb[childId]);
});
}
// Recursive call
insertChildren(node.children, parentLookupDb);
});
};
/**
* Draws a flowchart in the tag with id: id based on the graph definition in text.
*
* @param text
* @param id
*/
export const draw = async function (text, id, _version, diagObj) {
const { securityLevel, flowchart: conf } = getConfig();
nodeDb = {};
portPos = {};
const renderEl = select('body').append('div').attr('style', 'height:400px').attr('id', 'cy');
let graph = {
id: 'root',
layoutOptions: {
'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
'elk.layered.spacing.edgeNodeBetweenLayers': conf?.nodeSpacing ? `${conf.nodeSpacing}` : '30',
// 'elk.layered.mergeEdges': 'true',
'elk.direction': 'DOWN',
// 'elk.ports.sameLayerEdges': true,
// 'nodePlacement.strategy': 'SIMPLE',
},
children: [],
edges: [],
};
log.info('Drawing flowchart using v3 renderer', elk);
// Set the direction,
// Fetch the default direction, use TD if none was found
let dir = diagObj.db.getDirection();
switch (dir) {
case 'BT':
graph.layoutOptions['elk.direction'] = 'UP';
break;
case 'TB':
graph.layoutOptions['elk.direction'] = 'DOWN';
break;
case 'LR':
graph.layoutOptions['elk.direction'] = 'RIGHT';
break;
case 'RL':
graph.layoutOptions['elk.direction'] = 'LEFT';
break;
}
// Find the root dom node to ne used in rendering
// Handle root and document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
}
const root =
securityLevel === 'sandbox'
? select(sandboxElement.nodes()[0].contentDocument.body)
: select('body');
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
const svg = root.select(`[id="${id}"]`);
// Define the supported markers for the diagram
const markers = ['point', 'circle', 'cross'];
// Add the marker definitions to the svg as marker tags
insertMarkers(svg, markers, diagObj.type, id);
// Fetch the vertices/nodes and edges/links from the parsed graph definition
const vert = diagObj.db.getVertices();
// Setup nodes from the subgraphs with type group, these will be used
// as nodes with children in the subgraph
let subG;
const subGraphs = diagObj.db.getSubGraphs();
log.info('Subgraphs - ', subGraphs);
for (let i = subGraphs.length - 1; i >= 0; i--) {
subG = subGraphs[i];
diagObj.db.addVertex(
subG.id,
{ text: subG.title, type: subG.labelType },
'group',
undefined,
subG.classes,
subG.dir
);
}
// debugger;
// Add an element in the svg to be used to hold the subgraphs container
// elements
const subGraphsEl = svg.insert('g').attr('class', 'subgraphs');
// Create the lookup db for the subgraphs and their children to used when creating
// the tree structured graph
const parentLookupDb = addSubGraphs(diagObj.db);
// Add the nodes to the graph, this will entail creating the actual nodes
// in order to get the size of the node. You can't get the size of a node
// that is not in the dom so we need to add it to the dom, get the size
// we will position the nodes when we get the layout from elkjs
graph = await addVertices(vert, id, root, doc, diagObj, parentLookupDb, graph);
// Time for the edges, we start with adding an element in the node to hold the edges
const edgesEl = svg.insert('g').attr('class', 'edges edgePath');
// Fetch the edges form the parsed graph definition
const edges = diagObj.db.getEdges();
// Add the edges to the graph, this will entail creating the actual edges
graph = addEdges(edges, diagObj, graph, svg);
// Iterate through all nodes and add the top level nodes to the graph
const nodes = Object.keys(nodeDb);
nodes.forEach((nodeId) => {
const node = nodeDb[nodeId];
if (!node.parent) {
graph.children.push(node);
}
// Subgraph
if (parentLookupDb.childrenById[nodeId] !== undefined) {
node.labels = [
{
text: node.labelText,
layoutOptions: {
'nodeLabels.placement': '[H_CENTER, V_TOP, INSIDE]',
},
width: node.labelData.width,
height: node.labelData.height,
// width: 100,
// height: 100,
},
];
delete node.x;
delete node.y;
delete node.width;
delete node.height;
}
});
insertChildren(graph.children, parentLookupDb);
log.info('after layout', JSON.stringify(graph, null, 2));
const g = await elk.layout(graph);
drawNodes(0, 0, g.children, svg, subGraphsEl, diagObj, 0);
utils.insertTitle(svg, 'flowchartTitleText', conf.titleTopMargin, diagObj.db.getDiagramTitle());
log.info('after layout', g);
g.edges?.map((edge) => {
insertEdge(edgesEl, edge, edge.edgeData, diagObj, parentLookupDb, id);
});
setupGraphViewbox({}, svg, conf.diagramPadding, conf.useMaxWidth);
// Remove element after layout
renderEl.remove();
};
const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, diagObj, depth) => {
nodeArray.forEach(function (node) {
if (node) {
nodeDb[node.id].offset = {
posX: node.x + relX,
posY: node.y + relY,
x: relX,
y: relY,
depth,
width: node.width,
height: node.height,
};
if (node.type === 'group') {
const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph');
subgraphEl
.insert('rect')
.attr('class', 'subgraph subgraph-lvl-' + (depth % 5) + ' node')
.attr('x', node.x + relX)
.attr('y', node.y + relY)
.attr('width', node.width)
.attr('height', node.height);
const label = subgraphEl.insert('g').attr('class', 'label');
const labelCentering = getConfig().flowchart.htmlLabels ? node.labelData.width / 2 : 0;
label.attr(
'transform',
`translate(${node.labels[0].x + relX + node.x + labelCentering}, ${
node.labels[0].y + relY + node.y + 3
})`
);
label.node().appendChild(node.labelData.labelNode);
log.info('Id (UGH)= ', node.type, node.labels);
} else {
log.info('Id (UGH)= ', node.id);
node.el.attr(
'transform',
`translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})`
);
}
}
});
nodeArray.forEach(function (node) {
if (node && node.type === 'group') {
drawNodes(relX + node.x, relY + node.y, node.children, svg, subgraphsEl, diagObj, depth + 1);
}
});
};
export default {
getClasses,
draw,
};

View File

@@ -1,41 +0,0 @@
import type { TreeData } from './render-utils.js';
import { findCommonAncestor } from './render-utils.js';
describe('when rendering a flowchart using elk ', () => {
let lookupDb: TreeData;
beforeEach(() => {
lookupDb = {
parentById: {
B4: 'inner',
B5: 'inner',
C4: 'inner2',
C5: 'inner2',
B2: 'Ugge',
B3: 'Ugge',
inner: 'Ugge',
inner2: 'Ugge',
B6: 'outer',
},
childrenById: {
inner: ['B4', 'B5'],
inner2: ['C4', 'C5'],
Ugge: ['B2', 'B3', 'inner', 'inner2'],
outer: ['B6'],
},
};
});
it('to find parent of siblings in a subgraph', () => {
expect(findCommonAncestor('B4', 'B5', lookupDb)).toBe('inner');
});
it('to find an uncle', () => {
expect(findCommonAncestor('B4', 'B2', lookupDb)).toBe('Ugge');
});
it('to find a cousin', () => {
expect(findCommonAncestor('B4', 'C4', lookupDb)).toBe('Ugge');
});
it('to find a grandparent', () => {
expect(findCommonAncestor('B4', 'B6', lookupDb)).toBe('root');
});
it('to find ancestor of siblings in the root', () => {
expect(findCommonAncestor('B1', 'outer', lookupDb)).toBe('root');
});
});

View File

@@ -1,25 +0,0 @@
export interface TreeData {
parentById: Record<string, string>;
childrenById: Record<string, string[]>;
}
export const findCommonAncestor = (id1: string, id2: string, treeData: TreeData) => {
const { parentById } = treeData;
const visited = new Set();
let currentId = id1;
while (currentId) {
visited.add(currentId);
if (currentId === id2) {
return currentId;
}
currentId = parentById[currentId];
}
currentId = id2;
while (currentId) {
if (visited.has(currentId)) {
return currentId;
}
currentId = parentById[currentId];
}
return 'root';
};

View File

@@ -1,143 +0,0 @@
/** Returns the styles given options */
export interface FlowChartStyleOptions {
arrowheadColor: string;
border2: string;
clusterBkg: string;
clusterBorder: string;
edgeLabelBackground: string;
fontFamily: string;
lineColor: string;
mainBkg: string;
nodeBorder: string;
nodeTextColor: string;
tertiaryColor: string;
textColor: string;
titleColor: string;
[key: string]: string;
}
const genSections = (options: FlowChartStyleOptions) => {
let sections = '';
for (let i = 0; i < 5; i++) {
sections += `
.subgraph-lvl-${i} {
fill: ${options[`surface${i}`]};
stroke: ${options[`surfacePeer${i}`]};
}
`;
}
return sections;
};
const getStyles = (options: FlowChartStyleOptions) =>
`.label {
font-family: ${options.fontFamily};
color: ${options.nodeTextColor || options.textColor};
}
.cluster-label text {
fill: ${options.titleColor};
}
.cluster-label span {
color: ${options.titleColor};
}
.label text,span {
fill: ${options.nodeTextColor || options.textColor};
color: ${options.nodeTextColor || options.textColor};
}
.node rect,
.node circle,
.node ellipse,
.node polygon,
.node path {
fill: ${options.mainBkg};
stroke: ${options.nodeBorder};
stroke-width: 1px;
}
.node .label {
text-align: center;
}
.node.clickable {
cursor: pointer;
}
.arrowheadPath {
fill: ${options.arrowheadColor};
}
.edgePath .path {
stroke: ${options.lineColor};
stroke-width: 2.0px;
}
.flowchart-link {
stroke: ${options.lineColor};
fill: none;
}
.edgeLabel {
background-color: ${options.edgeLabelBackground};
rect {
opacity: 0.85;
background-color: ${options.edgeLabelBackground};
fill: ${options.edgeLabelBackground};
}
text-align: center;
}
.cluster rect {
fill: ${options.clusterBkg};
stroke: ${options.clusterBorder};
stroke-width: 1px;
}
.cluster text {
fill: ${options.titleColor};
}
.cluster span {
color: ${options.titleColor};
}
/* .cluster div {
color: ${options.titleColor};
} */
div.mermaidTooltip {
position: absolute;
text-align: center;
max-width: 200px;
padding: 2px;
font-family: ${options.fontFamily};
font-size: 12px;
background: ${options.tertiaryColor};
border: 1px solid ${options.border2};
border-radius: 2px;
pointer-events: none;
z-index: 100;
}
.flowchartTitleText {
text-anchor: middle;
font-size: 18px;
fill: ${options.textColor};
}
.subgraph {
stroke-width:2;
rx:3;
}
// .subgraph-lvl-1 {
// fill:#ccc;
// // stroke:black;
// }
.flowchart-label text {
text-anchor: middle;
}
${genSections(options)}
`;
export default getStyles;

View File

@@ -1,10 +0,0 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "../..",
"outDir": "./dist",
"types": ["vitest/importMeta", "vitest/globals"]
},
"include": ["./src/**/*.ts"],
"typeRoots": ["./src/types"]
}

View File

@@ -0,0 +1,10 @@
# @mermaid-js/layout-elk
## 0.1.1
### Patch Changes
- [#5758](https://github.com/mermaid-js/mermaid/pull/5758) [`501a55d`](https://github.com/mermaid-js/mermaid/commit/501a55d8f225901ba345c498dec4298490a0196e) Thanks [@sidharthv96](https://github.com/sidharthv96)! - fix: Types path
- Updated dependencies [[`5deaef4`](https://github.com/mermaid-js/mermaid/commit/5deaef456e74d796866431c26f69360e4e74dbff)]:
- mermaid@11.0.2

View File

@@ -0,0 +1,72 @@
# @mermaid-js/layout-elk
This package provides a layout engine for Mermaid based on the [ELK](https://www.eclipse.org/elk/) layout engine.
> [!NOTE]
> The ELK Layout engine will not be available in all providers that support mermaid by default.
> The websites will have to install the `@mermaid-js/layout-elk` package to use the ELK layout engine.
## Usage
```
flowchart-elk TD
A --> B
A --> C
```
```
---
config:
layout: elk
---
flowchart TD
A --> B
A --> C
```
```
---
config:
layout: elk.stress
---
flowchart TD
A --> B
A --> C
```
### With bundlers
```sh
npm install @mermaid-js/layout-elk
```
```ts
import mermaid from 'mermaid';
import elkLayouts from '@mermaid-js/layout-elk';
mermaid.registerLayoutLoaders(elkLayouts);
```
### With CDN
```html
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
import elkLayouts from 'https://cdn.jsdelivr.net/npm/@mermaid-js/layout-elk@11/dist/mermaid-layout-elk.esm.min.mjs';
mermaid.registerLayoutLoaders(elkLayouts);
</script>
```
## Supported layouts
- `elk`: The default layout, which is `elk.layered`.
- `elk.layered`: Layered layout
- `elk.stress`: Stress layout
- `elk.force`: Force layout
- `elk.mrtree`: Multi-root tree layout
- `elk.sporeOverlap`: Spore overlap layout
<!-- TODO: Add images for these layouts, as GitHub doesn't support natively -->

View File

@@ -1,14 +1,14 @@
{
"name": "@mermaid-js/layout-elk",
"version": "0.0.1",
"version": "0.1.1",
"description": "ELK layout engine for mermaid",
"module": "dist/mermaid-layout-elk.core.mjs",
"types": "dist/packages/mermaid-layout-elk/src/index.d.ts",
"types": "dist/layout.d.ts",
"type": "module",
"exports": {
".": {
"import": "./dist/mermaid-layout-elk.core.mjs",
"types": "./dist/packages/mermaid-layout-elk/src/index.d.ts"
"types": "./dist/layout.d.ts"
},
"./*": "./*"
},
@@ -18,9 +18,7 @@
"elk",
"mermaid"
],
"scripts": {
"prepublishOnly": "pnpm -w run build"
},
"scripts": {},
"repository": {
"type": "git",
"url": "https://github.com/mermaid-js/mermaid"
@@ -31,11 +29,15 @@
],
"license": "MIT",
"dependencies": {
"elkjs": "^0.9.3",
"d3": "^7.9.0"
"d3": "^7.9.0",
"elkjs": "^0.9.3"
},
"devDependencies": {
"@types/d3": "^7.4.3",
"mermaid": "workspace:^"
},
"peerDependencies": {
"mermaid": "workspace:^"
"mermaid": "^11.0.0"
},
"files": [
"dist"

View File

@@ -3,7 +3,7 @@ import type { LayoutLoaderDefinition } from 'mermaid';
const loader = async () => await import(`./render.js`);
const algos = ['elk.stress', 'elk.force', 'elk.mrtree', 'elk.sporeOverlap'];
export const layouts: LayoutLoaderDefinition[] = [
const layouts: LayoutLoaderDefinition[] = [
{
name: 'elk',
loader,
@@ -15,3 +15,5 @@ export const layouts: LayoutLoaderDefinition[] = [
algorithm: algo,
})),
];
export default layouts;

File diff suppressed because it is too large Load Diff

View File

@@ -19,8 +19,7 @@
"mermaid"
],
"scripts": {
"clean": "rimraf dist",
"prepublishOnly": "pnpm -w run build"
"clean": "rimraf dist"
},
"repository": {
"type": "git",
@@ -40,7 +39,7 @@
"mermaid": "workspace:^"
},
"peerDependencies": {
"mermaid": "workspace:>=10.0.0"
"mermaid": "^10 || ^11"
},
"files": [
"dist"

View File

@@ -0,0 +1,32 @@
# mermaid
## 11.0.2
### Patch Changes
- [#5664](https://github.com/mermaid-js/mermaid/pull/5664) [`5deaef4`](https://github.com/mermaid-js/mermaid/commit/5deaef456e74d796866431c26f69360e4e74dbff) Thanks [@Austin-Fulbright](https://github.com/Austin-Fulbright)! - chore: Migrate git graph to langium, use typescript for internals
- Updated dependencies [[`5deaef4`](https://github.com/mermaid-js/mermaid/commit/5deaef456e74d796866431c26f69360e4e74dbff)]:
- @mermaid-js/parser@0.2.0
## 11.0.1
### Patch Changes
- [#2](https://github.com/calvinvette/mermaid/pull/2) [`bf05d87`](https://github.com/mermaid-js/mermaid/commit/bf05d8781edacb580fdb053da167e968b7570117) Thanks [@calvinvette](https://github.com/calvinvette)! - test changeset
## 11.0.2
### Patch Changes
- Updated dependencies [[`83926c9`](https://github.com/mermaid-js/mermaid/commit/83926c9707b09c34e300888186250191ee8ae30a)]:
- @mermaid-js/parser@0.1.1
## 11.0.1
### Patch Changes
- [#5744](https://github.com/mermaid-js/mermaid/pull/5744) [`5013484`](https://github.com/mermaid-js/mermaid/commit/50134849246141ec400e33e08c12c10539b84de9) Thanks [@sidharthv96](https://github.com/sidharthv96)! - Release parser, test changesets
- Updated dependencies [[`5013484`](https://github.com/mermaid-js/mermaid/commit/50134849246141ec400e33e08c12c10539b84de9)]:
- @mermaid-js/parser@0.1.0

View File

@@ -1,6 +1,6 @@
{
"name": "mermaid",
"version": "11.0.0-alpha.7",
"version": "11.0.2",
"description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
"type": "module",
"module": "./dist/mermaid.core.mjs",
@@ -48,8 +48,7 @@
"types:build-config": "tsx scripts/create-types-from-json-schema.mts",
"types:verify-config": "tsx scripts/create-types-from-json-schema.mts --verify",
"checkCircle": "npx madge --circular ./src",
"release": "pnpm build",
"prepublishOnly": "cpy '../../README.*' ./ --cwd=. && pnpm docs:release-version && pnpm -w run build"
"prepublishOnly": "pnpm docs:verify-version"
},
"repository": {
"type": "git",
@@ -106,7 +105,6 @@
"ajv": "^8.12.0",
"chokidar": "^3.6.0",
"concurrently": "^8.2.2",
"cpy-cli": "^5.0.0",
"csstree-validator": "^3.0.0",
"globby": "^14.0.1",
"jison": "^0.4.18",

View File

@@ -248,19 +248,6 @@ const config: RequiredDeep<MermaidConfig> = {
...defaultConfigJson.requirement,
useWidth: undefined,
},
gitGraph: {
...defaultConfigJson.gitGraph,
// TODO: This is a temporary override for `gitGraph`, since every other
// diagram does have `useMaxWidth`, but instead sets it to `true`.
// Should we set this to `true` instead?
useMaxWidth: false,
},
sankey: {
...defaultConfigJson.sankey,
// this is false, unlike every other diagram (other than gitGraph)
// TODO: can we make this default to `true` instead?
useMaxWidth: false,
},
packet: {
...defaultConfigJson.packet,
},

View File

@@ -129,6 +129,6 @@ export type HTML = d3.Selection<HTMLIFrameElement, unknown, Element | null, unkn
export type SVG = d3.Selection<SVGSVGElement, unknown, Element | null, unknown>;
export type Group = d3.Selection<SVGGElement, unknown, Element | null, unknown>;
export type SVGGroup = d3.Selection<SVGGElement, unknown, Element | null, unknown>;
export type DiagramStylesProvider = (options?: any) => string;

View File

@@ -1,5 +1,6 @@
import { sanitizeUrl } from '@braintree/sanitize-url';
import type { Group, SVG } from '../../diagram-api/types.js';
import type { SVG, SVGGroup } from '../../diagram-api/types.js';
import { lineBreakRegex } from './common.js';
import type {
Bound,
D3ImageElement,
@@ -11,9 +12,8 @@ import type {
TextData,
TextObject,
} from './commonTypes.js';
import { lineBreakRegex } from './common.js';
export const drawRect = (element: SVG | Group, rectData: RectData): D3RectElement => {
export const drawRect = (element: SVG | SVGGroup, rectData: RectData): D3RectElement => {
const rectElement: D3RectElement = element.append('rect');
rectElement.attr('x', rectData.x);
rectElement.attr('y', rectData.y);
@@ -50,7 +50,7 @@ export const drawRect = (element: SVG | Group, rectData: RectData): D3RectElemen
* @param element - Diagram (reference for bounds)
* @param bounds - Shape of the rectangle
*/
export const drawBackgroundRect = (element: SVG | Group, bounds: Bound): void => {
export const drawBackgroundRect = (element: SVG | SVGGroup, bounds: Bound): void => {
const rectData: RectData = {
x: bounds.startx,
y: bounds.starty,
@@ -64,7 +64,7 @@ export const drawBackgroundRect = (element: SVG | Group, bounds: Bound): void =>
rectElement.lower();
};
export const drawText = (element: SVG | Group, textData: TextData): D3TextElement => {
export const drawText = (element: SVG | SVGGroup, textData: TextData): D3TextElement => {
const nText: string = textData.text.replace(lineBreakRegex, ' ');
const textElem: D3TextElement = element.append('text');
@@ -84,7 +84,7 @@ export const drawText = (element: SVG | Group, textData: TextData): D3TextElemen
return textElem;
};
export const drawImage = (elem: SVG | Group, x: number, y: number, link: string): void => {
export const drawImage = (elem: SVG | SVGGroup, x: number, y: number, link: string): void => {
const imageElement: D3ImageElement = elem.append('image');
imageElement.attr('x', x);
imageElement.attr('y', y);
@@ -93,7 +93,7 @@ export const drawImage = (elem: SVG | Group, x: number, y: number, link: string)
};
export const drawEmbeddedImage = (
element: SVG | Group,
element: SVG | SVGGroup,
x: number,
y: number,
link: string

View File

@@ -1,5 +1,5 @@
import type { SVG, SVGGroup } from '../../diagram-api/types.js';
import { log } from '../../logger.js';
import type { Group, SVG } from '../../diagram-api/types.js';
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
@@ -13,7 +13,7 @@ import { configureSvgSize } from '../../setupGraphViewbox.js';
export const draw = (_text: string, id: string, version: string) => {
log.debug('rendering svg for syntax error\n');
const svg: SVG = selectSvgElement(id);
const g: Group = svg.append('g');
const g: SVGGroup = svg.append('g');
svg.attr('viewBox', '0 0 2412 512');
configureSvgSize(svg, 100, 512, true);

View File

@@ -1,34 +1,26 @@
import type {
ExternalDiagramDefinition,
DiagramDetector,
DiagramLoader,
ExternalDiagramDefinition,
} from '../../../diagram-api/types.js';
import { log } from '../../../logger.js';
const id = 'flowchart-elk';
const detector: DiagramDetector = (txt, config): boolean => {
const detector: DiagramDetector = (txt, config = {}): boolean => {
if (
// If diagram explicitly states flowchart-elk
/^\s*flowchart-elk/.test(txt) ||
// If a flowchart/graph diagram has their default renderer set to elk
(/^\s*flowchart|graph/.test(txt) && config?.flowchart?.defaultRenderer === 'elk')
) {
// This will log at the end, hopefully.
setTimeout(
() =>
log.warn(
'flowchart-elk was moved to an external package in Mermaid v11. Please refer [release notes](link) for more details. This diagram will be rendered using `dagre` layout as a fallback.'
),
500
);
config.layout = 'elk';
return true;
}
return false;
};
const loader: DiagramLoader = async () => {
const { diagram } = await import('../flowDiagram-v2.js');
const { diagram } = await import('../flowDiagram.js');
return { id, diagram };
};

View File

@@ -1,5 +1,8 @@
import type { DiagramDetector, DiagramLoader } from '../../diagram-api/types.js';
import type { ExternalDiagramDefinition } from '../../diagram-api/types.js';
import type {
DiagramDetector,
DiagramLoader,
ExternalDiagramDefinition,
} from '../../diagram-api/types.js';
const id = 'flowchart-v2';
@@ -19,7 +22,7 @@ const detector: DiagramDetector = (txt, config) => {
};
const loader: DiagramLoader = async () => {
const { diagram } = await import('./flowDiagram-v2.js');
const { diagram } = await import('./flowDiagram.js');
return { id, diagram };
};

View File

@@ -1,23 +0,0 @@
// @ts-ignore: JISON doesn't support types
import flowParser from './parser/flow.jison';
import flowDb from './flowDb.js';
import renderer from './flowRenderer-v3-unified.js';
import flowStyles from './styles.js';
import type { MermaidConfig } from '../../config.type.js';
import { setConfig } from '../../diagram-api/diagramAPI.js';
export const diagram = {
parser: flowParser,
db: flowDb,
renderer,
styles: flowStyles,
init: (cnf: MermaidConfig) => {
if (!cnf.flowchart) {
cnf.flowchart = {};
}
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } });
flowDb.clear();
flowDb.setGen('gen-2');
},
};

View File

@@ -1,10 +1,10 @@
// @ts-ignore: JISON doesn't support types
import flowParser from './parser/flow.jison';
import flowDb from './flowDb.js';
import renderer from './flowRenderer-v3-unified.js';
import flowStyles from './styles.js';
import type { MermaidConfig } from '../../config.type.js';
import { setConfig } from '../../diagram-api/diagramAPI.js';
import flowDb from './flowDb.js';
import renderer from './flowRenderer-v3-unified.js';
// @ts-ignore: JISON doesn't support types
import flowParser from './parser/flow.jison';
import flowStyles from './styles.js';
export const diagram = {
parser: flowParser,
@@ -15,6 +15,9 @@ export const diagram = {
if (!cnf.flowchart) {
cnf.flowchart = {};
}
if (cnf.layout) {
setConfig({ layout: cnf.layout });
}
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } });
flowDb.clear();

View File

@@ -2,8 +2,8 @@ import { select } from 'd3';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
import { log } from '../../logger.js';
import { getDiagramElements } from '../../rendering-util/insertElementsForSize.js';
import { render } from '../../rendering-util/render.js';
import { getDiagramElement } from '../../rendering-util/insertElementsForSize.js';
import { getRegisteredLayoutAlgorithm, render } from '../../rendering-util/render.js';
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
import type { LayoutData } from '../../rendering-util/types.js';
import utils from '../../utils.js';
@@ -35,12 +35,17 @@ export const draw = async function (text: string, id: string, _version: string,
log.debug('Before getData: ');
const data4Layout = diag.db.getData() as LayoutData;
log.debug('Data: ', data4Layout);
// Create the root SVG - the element is the div containing the SVG element
const { element, svg } = getDiagramElements(id, securityLevel);
// Create the root SVG
const svg = getDiagramElement(id, securityLevel);
const direction = getDirection();
data4Layout.type = diag.type;
data4Layout.layoutAlgorithm = layout;
data4Layout.layoutAlgorithm = getRegisteredLayoutAlgorithm(layout);
if (data4Layout.layoutAlgorithm === 'dagre' && layout === 'elk') {
log.warn(
'flowchart-elk was moved to an external package in Mermaid v11. Please refer [release notes](https://github.com/mermaid-js/mermaid/releases/tag/v11.0.0) for more details. This diagram will be rendered using `dagre` layout as a fallback.'
);
}
data4Layout.direction = direction;
data4Layout.nodeSpacing = conf?.nodeSpacing || 50;
data4Layout.rankSpacing = conf?.rankSpacing || 50;
@@ -48,8 +53,8 @@ export const draw = async function (text: string, id: string, _version: string,
data4Layout.diagramId = id;
log.debug('REF1:', data4Layout);
await render(data4Layout, svg, element);
const padding = data4Layout.config.flowchart?.padding ?? 8;
await render(data4Layout, svg);
const padding = data4Layout.config.flowchart?.diagramPadding ?? 8;
utils.insertTitle(
svg,
'flowchartTitleText',

File diff suppressed because it is too large Load Diff

View File

@@ -1,535 +0,0 @@
import { log } from '../../logger.js';
import { random } from '../../utils.js';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import common from '../common/common.js';
import {
setAccTitle,
getAccTitle,
getAccDescription,
setAccDescription,
clear as commonClear,
setDiagramTitle,
getDiagramTitle,
} from '../common/commonDb.js';
let { mainBranchName, mainBranchOrder } = getConfig().gitGraph;
let commits = new Map();
let head = null;
let branchesConfig = new Map();
branchesConfig.set(mainBranchName, { name: mainBranchName, order: mainBranchOrder });
let branches = new Map();
branches.set(mainBranchName, head);
let curBranch = mainBranchName;
let direction = 'LR';
let seq = 0;
/**
*
*/
function getId() {
return random({ length: 7 });
}
// /**
// * @param currentCommit
// * @param otherCommit
// */
// function isFastForwardable(currentCommit, otherCommit) {
// log.debug('Entering isFastForwardable:', currentCommit.id, otherCommit.id);
// let cnt = 0;
// while (currentCommit.seq <= otherCommit.seq && currentCommit !== otherCommit && cnt < 1000) {
// cnt++;
// // only if other branch has more commits
// if (otherCommit.parent == null) break;
// if (Array.isArray(otherCommit.parent)) {
// log.debug('In merge commit:', otherCommit.parent);
// return (
// isFastForwardable(currentCommit, commits.get(otherCommit.parent[0])) ||
// isFastForwardable(currentCommit, commits.get(otherCommit.parent[1]))
// );
// } else {
// otherCommit = commits.get(otherCommit.parent);
// }
// }
// log.debug(currentCommit.id, otherCommit.id);
// return currentCommit.id === otherCommit.id;
// }
/**
* @param currentCommit
* @param otherCommit
*/
// function isReachableFrom(currentCommit, otherCommit) {
// const currentSeq = currentCommit.seq;
// const otherSeq = otherCommit.seq;
// if (currentSeq > otherSeq) return isFastForwardable(otherCommit, currentCommit);
// return false;
// }
/**
* @param list
* @param fn
*/
function uniqBy(list, fn) {
const recordMap = Object.create(null);
return list.reduce((out, item) => {
const key = fn(item);
if (!recordMap[key]) {
recordMap[key] = true;
out.push(item);
}
return out;
}, []);
}
export const setDirection = function (dir) {
direction = dir;
};
let options = {};
export const setOptions = function (rawOptString) {
log.debug('options str', rawOptString);
rawOptString = rawOptString?.trim();
rawOptString = rawOptString || '{}';
try {
options = JSON.parse(rawOptString);
} catch (e) {
log.error('error while parsing gitGraph options', e.message);
}
};
export const getOptions = function () {
return options;
};
export const commit = function (msg, id, type, tags) {
log.debug('Entering commit:', msg, id, type, tags);
const config = getConfig();
id = common.sanitizeText(id, config);
msg = common.sanitizeText(msg, config);
tags = tags?.map((tag) => common.sanitizeText(tag, config));
const commit = {
id: id ? id : seq + '-' + getId(),
message: msg,
seq: seq++,
type: type ? type : commitType.NORMAL,
tags: tags ?? [],
parents: head == null ? [] : [head.id],
branch: curBranch,
};
head = commit;
commits.set(commit.id, commit);
branches.set(curBranch, commit.id);
log.debug('in pushCommit ' + commit.id);
};
export const branch = function (name, order) {
name = common.sanitizeText(name, getConfig());
if (!branches.has(name)) {
branches.set(name, head != null ? head.id : null);
branchesConfig.set(name, { name, order: order ? parseInt(order, 10) : null });
checkout(name);
log.debug('in createBranch');
} else {
let error = new Error(
'Trying to create an existing branch. (Help: Either use a new name if you want create a new branch or try using "checkout ' +
name +
'")'
);
error.hash = {
text: 'branch ' + name,
token: 'branch ' + name,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['"checkout ' + name + '"'],
};
throw error;
}
};
export const merge = function (otherBranch, custom_id, override_type, custom_tags) {
const config = getConfig();
otherBranch = common.sanitizeText(otherBranch, config);
custom_id = common.sanitizeText(custom_id, config);
const currentCommit = commits.get(branches.get(curBranch));
const otherCommit = commits.get(branches.get(otherBranch));
if (curBranch === otherBranch) {
let error = new Error('Incorrect usage of "merge". Cannot merge a branch to itself');
error.hash = {
text: 'merge ' + otherBranch,
token: 'merge ' + otherBranch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['branch abc'],
};
throw error;
} else if (currentCommit === undefined || !currentCommit) {
let error = new Error(
'Incorrect usage of "merge". Current branch (' + curBranch + ')has no commits'
);
error.hash = {
text: 'merge ' + otherBranch,
token: 'merge ' + otherBranch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['commit'],
};
throw error;
} else if (!branches.has(otherBranch)) {
let error = new Error(
'Incorrect usage of "merge". Branch to be merged (' + otherBranch + ') does not exist'
);
error.hash = {
text: 'merge ' + otherBranch,
token: 'merge ' + otherBranch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['branch ' + otherBranch],
};
throw error;
} else if (otherCommit === undefined || !otherCommit) {
let error = new Error(
'Incorrect usage of "merge". Branch to be merged (' + otherBranch + ') has no commits'
);
error.hash = {
text: 'merge ' + otherBranch,
token: 'merge ' + otherBranch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['"commit"'],
};
throw error;
} else if (currentCommit === otherCommit) {
let error = new Error('Incorrect usage of "merge". Both branches have same head');
error.hash = {
text: 'merge ' + otherBranch,
token: 'merge ' + otherBranch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['branch abc'],
};
throw error;
} else if (custom_id && commits.has(custom_id)) {
let error = new Error(
'Incorrect usage of "merge". Commit with id:' +
custom_id +
' already exists, use different custom Id'
);
error.hash = {
text: 'merge ' + otherBranch + custom_id + override_type + custom_tags?.join(','),
token: 'merge ' + otherBranch + custom_id + override_type + custom_tags?.join(','),
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: [
`merge ${otherBranch} ${custom_id}_UNIQUE ${override_type} ${custom_tags?.join(',')}`,
],
};
throw error;
}
// if (isReachableFrom(currentCommit, otherCommit)) {
// log.debug('Already merged');
// return;
// }
// if (isFastForwardable(currentCommit, otherCommit)) {
// branches.set(curBranch, branches.get(otherBranch));
// head = commits.get(branches.get(curBranch));
// } else {
// create merge commit
const commit = {
id: custom_id ? custom_id : seq + '-' + getId(),
message: 'merged branch ' + otherBranch + ' into ' + curBranch,
seq: seq++,
parents: [head == null ? null : head.id, branches.get(otherBranch)],
branch: curBranch,
type: commitType.MERGE,
customType: override_type,
customId: custom_id ? true : false,
tags: custom_tags ? custom_tags : [],
};
head = commit;
commits.set(commit.id, commit);
branches.set(curBranch, commit.id);
// }
log.debug(branches);
log.debug('in mergeBranch');
};
export const cherryPick = function (sourceId, targetId, tags, parentCommitId) {
log.debug('Entering cherryPick:', sourceId, targetId, tags);
const config = getConfig();
sourceId = common.sanitizeText(sourceId, config);
targetId = common.sanitizeText(targetId, config);
tags = tags?.map((tag) => common.sanitizeText(tag, config));
parentCommitId = common.sanitizeText(parentCommitId, config);
if (!sourceId || !commits.has(sourceId)) {
let error = new Error(
'Incorrect usage of "cherryPick". Source commit id should exist and provided'
);
error.hash = {
text: 'cherryPick ' + sourceId + ' ' + targetId,
token: 'cherryPick ' + sourceId + ' ' + targetId,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['cherry-pick abc'],
};
throw error;
}
let sourceCommit = commits.get(sourceId);
let sourceCommitBranch = sourceCommit.branch;
if (
parentCommitId &&
!(Array.isArray(sourceCommit.parents) && sourceCommit.parents.includes(parentCommitId))
) {
let error = new Error(
'Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit.'
);
throw error;
}
if (sourceCommit.type === commitType.MERGE && !parentCommitId) {
let error = new Error(
'Incorrect usage of cherry-pick: If the source commit is a merge commit, an immediate parent commit must be specified.'
);
throw error;
}
if (!targetId || !commits.has(targetId)) {
// cherry-pick source commit to current branch
if (sourceCommitBranch === curBranch) {
let error = new Error(
'Incorrect usage of "cherryPick". Source commit is already on current branch'
);
error.hash = {
text: 'cherryPick ' + sourceId + ' ' + targetId,
token: 'cherryPick ' + sourceId + ' ' + targetId,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['cherry-pick abc'],
};
throw error;
}
const currentCommit = commits.get(branches.get(curBranch));
if (currentCommit === undefined || !currentCommit) {
let error = new Error(
'Incorrect usage of "cherry-pick". Current branch (' + curBranch + ')has no commits'
);
error.hash = {
text: 'cherryPick ' + sourceId + ' ' + targetId,
token: 'cherryPick ' + sourceId + ' ' + targetId,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['cherry-pick abc'],
};
throw error;
}
const commit = {
id: seq + '-' + getId(),
message: 'cherry-picked ' + sourceCommit + ' into ' + curBranch,
seq: seq++,
parents: [head == null ? null : head.id, sourceCommit.id],
branch: curBranch,
type: commitType.CHERRY_PICK,
tags: tags
? tags.filter(Boolean)
: [
`cherry-pick:${sourceCommit.id}${
sourceCommit.type === commitType.MERGE ? `|parent:${parentCommitId}` : ''
}`,
],
};
head = commit;
commits.set(commit.id, commit);
branches.set(curBranch, commit.id);
log.debug(branches);
log.debug('in cherryPick');
}
};
export const checkout = function (branch) {
branch = common.sanitizeText(branch, getConfig());
if (!branches.has(branch)) {
let error = new Error(
'Trying to checkout branch which is not yet created. (Help try using "branch ' + branch + '")'
);
error.hash = {
text: 'checkout ' + branch,
token: 'checkout ' + branch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['"branch ' + branch + '"'],
};
throw error;
} else {
curBranch = branch;
const id = branches.get(curBranch);
head = commits.get(id);
}
};
// export const reset = function (commitRef) {
// log.debug('in reset', commitRef);
// const ref = commitRef.split(':')[0];
// let parentCount = parseInt(commitRef.split(':')[1]);
// let commit = ref === 'HEAD' ? head : commits.get(branches.get(ref));
// log.debug(commit, parentCount);
// while (parentCount > 0) {
// commit = commits.get(commit.parent);
// parentCount--;
// if (!commit) {
// const err = 'Critical error - unique parent commit not found during reset';
// log.error(err);
// throw err;
// }
// }
// head = commit;
// branches[curBranch] = commit.id;
// };
/**
* @param arr
* @param key
* @param newVal
*/
function upsert(arr, key, newVal) {
const index = arr.indexOf(key);
if (index === -1) {
arr.push(newVal);
} else {
arr.splice(index, 1, newVal);
}
}
/** @param commitArr */
function prettyPrintCommitHistory(commitArr) {
const commit = commitArr.reduce((out, commit) => {
if (out.seq > commit.seq) {
return out;
}
return commit;
}, commitArr[0]);
let line = '';
commitArr.forEach(function (c) {
if (c === commit) {
line += '\t*';
} else {
line += '\t|';
}
});
const label = [line, commit.id, commit.seq];
for (let branch in branches) {
if (branches.get(branch) === commit.id) {
label.push(branch);
}
}
log.debug(label.join(' '));
if (commit.parents && commit.parents.length == 2) {
const newCommit = commits.get(commit.parents[0]);
upsert(commitArr, commit, newCommit);
commitArr.push(commits.get(commit.parents[1]));
} else if (commit.parents.length == 0) {
return;
} else {
const nextCommit = commits.get(commit.parents);
upsert(commitArr, commit, nextCommit);
}
commitArr = uniqBy(commitArr, (c) => c.id);
prettyPrintCommitHistory(commitArr);
}
export const prettyPrint = function () {
log.debug(commits);
const node = getCommitsArray()[0];
prettyPrintCommitHistory([node]);
};
export const clear = function () {
commits = new Map();
head = null;
const { mainBranchName, mainBranchOrder } = getConfig().gitGraph;
branches = new Map();
branches.set(mainBranchName, null);
branchesConfig = new Map();
branchesConfig.set(mainBranchName, { name: mainBranchName, order: mainBranchOrder });
curBranch = mainBranchName;
seq = 0;
commonClear();
};
export const getBranchesAsObjArray = function () {
const branchesArray = [...branchesConfig.values()]
.map((branchConfig, i) => {
if (branchConfig.order !== null) {
return branchConfig;
}
return {
...branchConfig,
order: parseFloat(`0.${i}`, 10),
};
})
.sort((a, b) => a.order - b.order)
.map(({ name }) => ({ name }));
return branchesArray;
};
export const getBranches = function () {
return branches;
};
export const getCommits = function () {
return commits;
};
export const getCommitsArray = function () {
const commitArr = [...commits.values()];
commitArr.forEach(function (o) {
log.debug(o.id);
});
commitArr.sort((a, b) => a.seq - b.seq);
return commitArr;
};
export const getCurrentBranch = function () {
return curBranch;
};
export const getDirection = function () {
return direction;
};
export const getHead = function () {
return head;
};
export const commitType = {
NORMAL: 0,
REVERSE: 1,
HIGHLIGHT: 2,
MERGE: 3,
CHERRY_PICK: 4,
};
export default {
getConfig: () => getConfig().gitGraph,
setDirection,
setOptions,
getOptions,
commit,
branch,
merge,
cherryPick,
checkout,
//reset,
prettyPrint,
clear,
getBranchesAsObjArray,
getBranches,
getCommits,
getCommitsArray,
getCurrentBranch,
getDirection,
getHead,
setAccTitle,
getAccTitle,
getAccDescription,
setAccDescription,
setDiagramTitle,
getDiagramTitle,
commitType,
};

View File

@@ -0,0 +1,522 @@
import { log } from '../../logger.js';
import { cleanAndMerge, random } from '../../utils.js';
import { getConfig as commonGetConfig } from '../../config.js';
import common from '../common/common.js';
import {
setAccTitle,
getAccTitle,
getAccDescription,
setAccDescription,
clear as commonClear,
setDiagramTitle,
getDiagramTitle,
} from '../common/commonDb.js';
import type {
DiagramOrientation,
Commit,
GitGraphDB,
CommitDB,
MergeDB,
BranchDB,
CherryPickDB,
} from './gitGraphTypes.js';
import { commitType } from './gitGraphTypes.js';
import { ImperativeState } from '../../utils/imperativeState.js';
import DEFAULT_CONFIG from '../../defaultConfig.js';
import type { GitGraphDiagramConfig } from '../../config.type.js';
interface GitGraphState {
commits: Map<string, Commit>;
head: Commit | null;
branchConfig: Map<string, { name: string; order: number | undefined }>;
branches: Map<string, string | null>;
currBranch: string;
direction: DiagramOrientation;
seq: number;
options: any;
}
const DEFAULT_GITGRAPH_CONFIG: Required<GitGraphDiagramConfig> = DEFAULT_CONFIG.gitGraph;
const getConfig = (): Required<GitGraphDiagramConfig> => {
const config = cleanAndMerge({
...DEFAULT_GITGRAPH_CONFIG,
...commonGetConfig().gitGraph,
});
return config;
};
const state = new ImperativeState<GitGraphState>(() => {
const config = getConfig();
const mainBranchName = config.mainBranchName;
const mainBranchOrder = config.mainBranchOrder;
return {
mainBranchName,
commits: new Map(),
head: null,
branchConfig: new Map([[mainBranchName, { name: mainBranchName, order: mainBranchOrder }]]),
branches: new Map([[mainBranchName, null]]),
currBranch: mainBranchName,
direction: 'LR',
seq: 0,
options: {},
};
});
function getID() {
return random({ length: 7 });
}
/**
* @param list - list of items
* @param fn - function to get the key
*/
function uniqBy(list: any[], fn: (item: any) => any) {
const recordMap = Object.create(null);
return list.reduce((out, item) => {
const key = fn(item);
if (!recordMap[key]) {
recordMap[key] = true;
out.push(item);
}
return out;
}, []);
}
export const setDirection = function (dir: DiagramOrientation) {
state.records.direction = dir;
};
export const setOptions = function (rawOptString: string) {
log.debug('options str', rawOptString);
rawOptString = rawOptString?.trim();
rawOptString = rawOptString || '{}';
try {
state.records.options = JSON.parse(rawOptString);
} catch (e: any) {
log.error('error while parsing gitGraph options', e.message);
}
};
export const getOptions = function () {
return state.records.options;
};
export const commit = function (commitDB: CommitDB) {
let msg = commitDB.msg;
let id = commitDB.id;
const type = commitDB.type;
let tags = commitDB.tags;
log.info('commit', msg, id, type, tags);
log.debug('Entering commit:', msg, id, type, tags);
const config = getConfig();
id = common.sanitizeText(id, config);
msg = common.sanitizeText(msg, config);
tags = tags?.map((tag) => common.sanitizeText(tag, config));
const newCommit: Commit = {
id: id ? id : state.records.seq + '-' + getID(),
message: msg,
seq: state.records.seq++,
type: type ?? commitType.NORMAL,
tags: tags ?? [],
parents: state.records.head == null ? [] : [state.records.head.id],
branch: state.records.currBranch,
};
state.records.head = newCommit;
log.info('main branch', config.mainBranchName);
state.records.commits.set(newCommit.id, newCommit);
state.records.branches.set(state.records.currBranch, newCommit.id);
log.debug('in pushCommit ' + newCommit.id);
};
export const branch = function (branchDB: BranchDB) {
let name = branchDB.name;
const order = branchDB.order;
name = common.sanitizeText(name, getConfig());
if (state.records.branches.has(name)) {
throw new Error(
`Trying to create an existing branch. (Help: Either use a new name if you want create a new branch or try using "checkout ${name}")`
);
}
state.records.branches.set(name, state.records.head != null ? state.records.head.id : null);
state.records.branchConfig.set(name, { name, order });
checkout(name);
log.debug('in createBranch');
};
export const merge = (mergeDB: MergeDB): void => {
let otherBranch = mergeDB.branch;
let customId = mergeDB.id;
const overrideType = mergeDB.type;
const customTags = mergeDB.tags;
const config = getConfig();
otherBranch = common.sanitizeText(otherBranch, config);
if (customId) {
customId = common.sanitizeText(customId, config);
}
const currentBranchCheck = state.records.branches.get(state.records.currBranch);
const otherBranchCheck = state.records.branches.get(otherBranch);
const currentCommit = currentBranchCheck
? state.records.commits.get(currentBranchCheck)
: undefined;
const otherCommit: Commit | undefined = otherBranchCheck
? state.records.commits.get(otherBranchCheck)
: undefined;
if (currentCommit && otherCommit && currentCommit.branch === otherBranch) {
throw new Error(`Cannot merge branch '${otherBranch}' into itself.`);
}
if (state.records.currBranch === otherBranch) {
const error: any = new Error('Incorrect usage of "merge". Cannot merge a branch to itself');
error.hash = {
text: `merge ${otherBranch}`,
token: `merge ${otherBranch}`,
expected: ['branch abc'],
};
throw error;
}
if (currentCommit === undefined || !currentCommit) {
const error: any = new Error(
`Incorrect usage of "merge". Current branch (${state.records.currBranch})has no commits`
);
error.hash = {
text: `merge ${otherBranch}`,
token: `merge ${otherBranch}`,
expected: ['commit'],
};
throw error;
}
if (!state.records.branches.has(otherBranch)) {
const error: any = new Error(
'Incorrect usage of "merge". Branch to be merged (' + otherBranch + ') does not exist'
);
error.hash = {
text: `merge ${otherBranch}`,
token: `merge ${otherBranch}`,
expected: [`branch ${otherBranch}`],
};
throw error;
}
if (otherCommit === undefined || !otherCommit) {
const error: any = new Error(
'Incorrect usage of "merge". Branch to be merged (' + otherBranch + ') has no commits'
);
error.hash = {
text: `merge ${otherBranch}`,
token: `merge ${otherBranch}`,
expected: ['"commit"'],
};
throw error;
}
if (currentCommit === otherCommit) {
const error: any = new Error('Incorrect usage of "merge". Both branches have same head');
error.hash = {
text: `merge ${otherBranch}`,
token: `merge ${otherBranch}`,
expected: ['branch abc'],
};
throw error;
}
if (customId && state.records.commits.has(customId)) {
const error: any = new Error(
'Incorrect usage of "merge". Commit with id:' +
customId +
' already exists, use different custom Id'
);
error.hash = {
text: `merge ${otherBranch} ${customId} ${overrideType} ${customTags?.join(' ')}`,
token: `merge ${otherBranch} ${customId} ${overrideType} ${customTags?.join(' ')}`,
expected: [
`merge ${otherBranch} ${customId}_UNIQUE ${overrideType} ${customTags?.join(' ')}`,
],
};
throw error;
}
const verifiedBranch: string = otherBranchCheck ? otherBranchCheck : ''; //figure out a cleaner way to do this
const commit = {
id: customId || `${state.records.seq}-${getID()}`,
message: `merged branch ${otherBranch} into ${state.records.currBranch}`,
seq: state.records.seq++,
parents: state.records.head == null ? [] : [state.records.head.id, verifiedBranch],
branch: state.records.currBranch,
type: commitType.MERGE,
customType: overrideType,
customId: customId ? true : false,
tags: customTags ?? [],
} satisfies Commit;
state.records.head = commit;
state.records.commits.set(commit.id, commit);
state.records.branches.set(state.records.currBranch, commit.id);
log.debug(state.records.branches);
log.debug('in mergeBranch');
};
export const cherryPick = function (cherryPickDB: CherryPickDB) {
let sourceId = cherryPickDB.id;
let targetId = cherryPickDB.targetId;
let tags = cherryPickDB.tags;
let parentCommitId = cherryPickDB.parent;
log.debug('Entering cherryPick:', sourceId, targetId, tags);
const config = getConfig();
sourceId = common.sanitizeText(sourceId, config);
targetId = common.sanitizeText(targetId, config);
tags = tags?.map((tag) => common.sanitizeText(tag, config));
parentCommitId = common.sanitizeText(parentCommitId, config);
if (!sourceId || !state.records.commits.has(sourceId)) {
const error: any = new Error(
'Incorrect usage of "cherryPick". Source commit id should exist and provided'
);
error.hash = {
text: `cherryPick ${sourceId} ${targetId}`,
token: `cherryPick ${sourceId} ${targetId}`,
expected: ['cherry-pick abc'],
};
throw error;
}
const sourceCommit = state.records.commits.get(sourceId);
if (sourceCommit === undefined || !sourceCommit) {
throw new Error('Incorrect usage of "cherryPick". Source commit id should exist and provided');
}
if (
parentCommitId &&
!(Array.isArray(sourceCommit.parents) && sourceCommit.parents.includes(parentCommitId))
) {
const error = new Error(
'Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit.'
);
throw error;
}
const sourceCommitBranch = sourceCommit.branch;
if (sourceCommit.type === commitType.MERGE && !parentCommitId) {
const error = new Error(
'Incorrect usage of cherry-pick: If the source commit is a merge commit, an immediate parent commit must be specified.'
);
throw error;
}
if (!targetId || !state.records.commits.has(targetId)) {
// cherry-pick source commit to current branch
if (sourceCommitBranch === state.records.currBranch) {
const error: any = new Error(
'Incorrect usage of "cherryPick". Source commit is already on current branch'
);
error.hash = {
text: `cherryPick ${sourceId} ${targetId}`,
token: `cherryPick ${sourceId} ${targetId}`,
expected: ['cherry-pick abc'],
};
throw error;
}
const currentCommitId = state.records.branches.get(state.records.currBranch);
if (currentCommitId === undefined || !currentCommitId) {
const error: any = new Error(
`Incorrect usage of "cherry-pick". Current branch (${state.records.currBranch})has no commits`
);
error.hash = {
text: `cherryPick ${sourceId} ${targetId}`,
token: `cherryPick ${sourceId} ${targetId}`,
expected: ['cherry-pick abc'],
};
throw error;
}
const currentCommit = state.records.commits.get(currentCommitId);
if (currentCommit === undefined || !currentCommit) {
const error: any = new Error(
`Incorrect usage of "cherry-pick". Current branch (${state.records.currBranch})has no commits`
);
error.hash = {
text: `cherryPick ${sourceId} ${targetId}`,
token: `cherryPick ${sourceId} ${targetId}`,
expected: ['cherry-pick abc'],
};
throw error;
}
const commit = {
id: state.records.seq + '-' + getID(),
message: `cherry-picked ${sourceCommit?.message} into ${state.records.currBranch}`,
seq: state.records.seq++,
parents: state.records.head == null ? [] : [state.records.head.id, sourceCommit.id],
branch: state.records.currBranch,
type: commitType.CHERRY_PICK,
tags: tags
? tags.filter(Boolean)
: [
`cherry-pick:${sourceCommit.id}${
sourceCommit.type === commitType.MERGE ? `|parent:${parentCommitId}` : ''
}`,
],
};
state.records.head = commit;
state.records.commits.set(commit.id, commit);
state.records.branches.set(state.records.currBranch, commit.id);
log.debug(state.records.branches);
log.debug('in cherryPick');
}
};
export const checkout = function (branch: string) {
branch = common.sanitizeText(branch, getConfig());
if (!state.records.branches.has(branch)) {
const error: any = new Error(
`Trying to checkout branch which is not yet created. (Help try using "branch ${branch}")`
);
error.hash = {
text: `checkout ${branch}`,
token: `checkout ${branch}`,
expected: [`branch ${branch}`],
};
throw error;
} else {
state.records.currBranch = branch;
const id = state.records.branches.get(state.records.currBranch);
if (id === undefined || !id) {
state.records.head = null;
} else {
state.records.head = state.records.commits.get(id) ?? null;
}
}
};
/**
* @param arr - array
* @param key - key
* @param newVal - new value
*/
function upsert(arr: any[], key: any, newVal: any) {
const index = arr.indexOf(key);
if (index === -1) {
arr.push(newVal);
} else {
arr.splice(index, 1, newVal);
}
}
function prettyPrintCommitHistory(commitArr: Commit[]) {
const commit = commitArr.reduce((out, commit) => {
if (out.seq > commit.seq) {
return out;
}
return commit;
}, commitArr[0]);
let line = '';
commitArr.forEach(function (c) {
if (c === commit) {
line += '\t*';
} else {
line += '\t|';
}
});
const label = [line, commit.id, commit.seq];
for (const branch in state.records.branches) {
if (state.records.branches.get(branch) === commit.id) {
label.push(branch);
}
}
log.debug(label.join(' '));
if (commit.parents && commit.parents.length == 2 && commit.parents[0] && commit.parents[1]) {
const newCommit = state.records.commits.get(commit.parents[0]);
upsert(commitArr, commit, newCommit);
if (commit.parents[1]) {
commitArr.push(state.records.commits.get(commit.parents[1])!);
}
} else if (commit.parents.length == 0) {
return;
} else {
if (commit.parents[0]) {
const newCommit = state.records.commits.get(commit.parents[0]);
upsert(commitArr, commit, newCommit);
}
}
commitArr = uniqBy(commitArr, (c) => c.id);
prettyPrintCommitHistory(commitArr);
}
export const prettyPrint = function () {
log.debug(state.records.commits);
const node = getCommitsArray()[0];
prettyPrintCommitHistory([node]);
};
export const clear = function () {
state.reset();
commonClear();
};
export const getBranchesAsObjArray = function () {
const branchesArray = [...state.records.branchConfig.values()]
.map((branchConfig, i) => {
if (branchConfig.order !== null && branchConfig.order !== undefined) {
return branchConfig;
}
return {
...branchConfig,
order: parseFloat(`0.${i}`),
};
})
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
.map(({ name }) => ({ name }));
return branchesArray;
};
export const getBranches = function () {
return state.records.branches;
};
export const getCommits = function () {
return state.records.commits;
};
export const getCommitsArray = function () {
const commitArr = [...state.records.commits.values()];
commitArr.forEach(function (o) {
log.debug(o.id);
});
commitArr.sort((a, b) => a.seq - b.seq);
return commitArr;
};
export const getCurrentBranch = function () {
return state.records.currBranch;
};
export const getDirection = function () {
return state.records.direction;
};
export const getHead = function () {
return state.records.head;
};
export const db: GitGraphDB = {
commitType,
getConfig,
setDirection,
setOptions,
getOptions,
commit,
branch,
merge,
cherryPick,
checkout,
//reset,
prettyPrint,
clear,
getBranchesAsObjArray,
getBranches,
getCommits,
getCommitsArray,
getCurrentBranch,
getDirection,
getHead,
setAccTitle,
getAccTitle,
getAccDescription,
setAccDescription,
setDiagramTitle,
getDiagramTitle,
};

View File

@@ -1,13 +1,13 @@
// @ts-ignore: JISON doesn't support types
import gitGraphParser from './parser/gitGraph.jison';
import gitGraphDb from './gitGraphAst.js';
import { parser } from './gitGraphParser.js';
import { db } from './gitGraphAst.js';
import gitGraphRenderer from './gitGraphRenderer.js';
import gitGraphStyles from './styles.js';
import type { DiagramDefinition } from '../../diagram-api/types.js';
export const diagram: DiagramDefinition = {
parser: gitGraphParser,
db: gitGraphDb,
parser,
db,
renderer: gitGraphRenderer,
styles: gitGraphStyles,
};

View File

@@ -1,272 +0,0 @@
import gitGraphAst from './gitGraphAst.js';
import { parser } from './parser/gitGraph.jison';
describe('when parsing a gitGraph', function () {
beforeEach(function () {
parser.yy = gitGraphAst;
parser.yy.clear();
});
it('should handle a gitGraph definition', function () {
const str = 'gitGraph:\n' + 'commit\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(parser.yy.getBranches().size).toBe(1);
});
it('should handle a gitGraph definition with empty options', function () {
const str = 'gitGraph:\n' + 'options\n' + ' end\n' + 'commit\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(parser.yy.getOptions()).toEqual({});
expect(commits.size).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(parser.yy.getBranches().size).toBe(1);
});
it('should handle a gitGraph definition with valid options', function () {
const str = 'gitGraph:\n' + 'options\n' + '{"key": "value"}\n' + 'end\n' + 'commit\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(parser.yy.getOptions().key).toBe('value');
expect(commits.size).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(parser.yy.getBranches().size).toBe(1);
});
it('should not fail on a gitGraph with malformed json', function () {
const str = 'gitGraph:\n' + 'options\n' + '{"key": "value"\n' + 'end\n' + 'commit\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(parser.yy.getBranches().size).toBe(1);
});
it('should handle set direction top to bottom', function () {
const str = 'gitGraph TB:\n' + 'commit\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('TB');
expect(parser.yy.getBranches().size).toBe(1);
});
it('should handle set direction bottom to top', function () {
const str = 'gitGraph BT:\n' + 'commit\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('BT');
expect(parser.yy.getBranches().size).toBe(1);
});
it('should checkout a branch', function () {
const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(0);
expect(parser.yy.getCurrentBranch()).toBe('new');
});
it('should switch a branch', function () {
const str = 'gitGraph:\n' + 'branch new\n' + 'switch new\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(0);
expect(parser.yy.getCurrentBranch()).toBe('new');
});
it('should add commits to checked out branch', function () {
const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n' + 'commit\n' + 'commit\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(2);
expect(parser.yy.getCurrentBranch()).toBe('new');
const branchCommit = parser.yy.getBranches().get('new');
expect(branchCommit).not.toBeNull();
expect(commits.get(branchCommit).parent).not.toBeNull();
});
it('should handle commit with args', function () {
const str = 'gitGraph:\n' + 'commit "a commit"\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(1);
const key = commits.keys().next().value;
expect(commits.get(key).message).toBe('a commit');
expect(parser.yy.getCurrentBranch()).toBe('main');
});
// Reset has been commented out in JISON
it.skip('should reset a branch', function () {
const str =
'gitGraph:\n' +
'commit\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
'commit\n' +
'reset main\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(3);
expect(parser.yy.getCurrentBranch()).toBe('newbranch');
expect(parser.yy.getBranches().get('newbranch')).toEqual(parser.yy.getBranches().get('main'));
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches().get('newbranch'));
});
it.skip('reset can take an argument', function () {
const str =
'gitGraph:\n' +
'commit\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
'commit\n' +
'reset main^\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(3);
expect(parser.yy.getCurrentBranch()).toBe('newbranch');
const main = commits.get(parser.yy.getBranches().get('main'));
expect(parser.yy.getHead().id).toEqual(main.parent);
});
it.skip('should handle fast forwardable merges', function () {
const str =
'gitGraph:\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
'commit\n' +
'commit\n' +
'checkout main\n' +
'merge newbranch\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(4);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getBranches().get('newbranch')).toEqual(parser.yy.getBranches().get('main'));
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches().get('newbranch'));
});
it('should handle cases when merge is a noop', function () {
const str =
'gitGraph:\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
'commit\n' +
'commit\n' +
'merge main\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(4);
expect(parser.yy.getCurrentBranch()).toBe('newbranch');
expect(parser.yy.getBranches().get('newbranch')).not.toEqual(
parser.yy.getBranches().get('main')
);
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches().get('newbranch'));
});
it('should handle merge with 2 parents', function () {
const str =
'gitGraph:\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
'commit\n' +
'commit\n' +
'checkout main\n' +
'commit\n' +
'merge newbranch\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(5);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getBranches().get('newbranch')).not.toEqual(
parser.yy.getBranches().get('main')
);
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches().get('main'));
});
it.skip('should handle ff merge when history walk has two parents (merge commit)', function () {
const str =
'gitGraph:\n' +
'commit\n' +
'branch newbranch\n' +
'checkout newbranch\n' +
'commit\n' +
'commit\n' +
'checkout main\n' +
'commit\n' +
'merge newbranch\n' +
'commit\n' +
'checkout newbranch\n' +
'merge main\n';
parser.parse(str);
const commits = parser.yy.getCommits();
expect(commits.size).toBe(7);
expect(parser.yy.getCurrentBranch()).toBe('newbranch');
expect(parser.yy.getBranches().get('newbranch')).toEqual(parser.yy.getBranches().get('main'));
expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches().get('main'));
parser.yy.prettyPrint();
});
it('should generate an array of known branches', function () {
const str =
'gitGraph:\n' +
'commit\n' +
'branch b1\n' +
'checkout b1\n' +
'commit\n' +
'commit\n' +
'branch b2\n';
parser.parse(str);
const branches = gitGraphAst.getBranchesAsObjArray();
expect(branches).toHaveLength(3);
expect(branches[0]).toHaveProperty('name', 'main');
expect(branches[1]).toHaveProperty('name', 'b1');
expect(branches[2]).toHaveProperty('name', 'b2');
});
});

View File

@@ -0,0 +1,243 @@
import type { GitGraph } from '@mermaid-js/parser';
import { parse } from '@mermaid-js/parser';
import type { ParserDefinition } from '../../diagram-api/types.js';
import { log } from '../../logger.js';
import { populateCommonDb } from '../common/populateCommonDb.js';
import { db } from './gitGraphAst.js';
import { commitType } from './gitGraphTypes.js';
import type {
CheckoutAst,
CherryPickingAst,
MergeAst,
CommitAst,
BranchAst,
GitGraphDBParseProvider,
CommitDB,
BranchDB,
MergeDB,
CherryPickDB,
} from './gitGraphTypes.js';
const populate = (ast: GitGraph, db: GitGraphDBParseProvider) => {
populateCommonDb(ast, db);
// @ts-ignore: this wont exist if the direction is not specified
if (ast.dir) {
// @ts-ignore: this wont exist if the direction is not specified
db.setDirection(ast.dir);
}
for (const statement of ast.statements) {
parseStatement(statement, db);
}
};
const parseStatement = (statement: any, db: GitGraphDBParseProvider) => {
const parsers: Record<string, (stmt: any) => void> = {
Commit: (stmt) => db.commit(parseCommit(stmt)),
Branch: (stmt) => db.branch(parseBranch(stmt)),
Merge: (stmt) => db.merge(parseMerge(stmt)),
Checkout: (stmt) => db.checkout(parseCheckout(stmt)),
CherryPicking: (stmt) => db.cherryPick(parseCherryPicking(stmt)),
};
const parser = parsers[statement.$type];
if (parser) {
parser(statement);
} else {
log.error(`Unknown statement type: ${statement.$type}`);
}
};
const parseCommit = (commit: CommitAst): CommitDB => {
const commitDB: CommitDB = {
id: commit.id,
msg: commit.message ?? '',
type: commit.type !== undefined ? commitType[commit.type] : commitType.NORMAL,
tags: commit.tags ?? undefined,
};
return commitDB;
};
const parseBranch = (branch: BranchAst): BranchDB => {
const branchDB: BranchDB = {
name: branch.name,
order: branch.order ?? 0,
};
return branchDB;
};
const parseMerge = (merge: MergeAst): MergeDB => {
const mergeDB: MergeDB = {
branch: merge.branch,
id: merge.id ?? '',
type: merge.type !== undefined ? commitType[merge.type] : undefined,
tags: merge.tags ?? undefined,
};
return mergeDB;
};
const parseCheckout = (checkout: CheckoutAst): string => {
const branch = checkout.branch;
return branch;
};
const parseCherryPicking = (cherryPicking: CherryPickingAst): CherryPickDB => {
const cherryPickDB: CherryPickDB = {
id: cherryPicking.id,
targetId: '',
tags: cherryPicking.tags?.length === 0 ? undefined : cherryPicking.tags,
parent: cherryPicking.parent,
};
return cherryPickDB;
};
export const parser: ParserDefinition = {
parse: async (input: string): Promise<void> => {
const ast: GitGraph = await parse('gitGraph', input);
log.debug(ast);
populate(ast, db);
},
};
if (import.meta.vitest) {
const { it, expect, describe } = import.meta.vitest;
const mockDB: GitGraphDBParseProvider = {
commitType: commitType,
setDirection: vi.fn(),
commit: vi.fn(),
branch: vi.fn(),
merge: vi.fn(),
cherryPick: vi.fn(),
checkout: vi.fn(),
};
describe('GitGraph Parser', () => {
it('should parse a commit statement', () => {
const commit = {
$type: 'Commit',
id: '1',
message: 'test',
tags: ['tag1', 'tag2'],
type: 'NORMAL',
};
parseStatement(commit, mockDB);
expect(mockDB.commit).toHaveBeenCalledWith({
id: '1',
msg: 'test',
tags: ['tag1', 'tag2'],
type: 0,
});
});
it('should parse a branch statement', () => {
const branch = {
$type: 'Branch',
name: 'newBranch',
order: 1,
};
parseStatement(branch, mockDB);
expect(mockDB.branch).toHaveBeenCalledWith({ name: 'newBranch', order: 1 });
});
it('should parse a checkout statement', () => {
const checkout = {
$type: 'Checkout',
branch: 'newBranch',
};
parseStatement(checkout, mockDB);
expect(mockDB.checkout).toHaveBeenCalledWith('newBranch');
});
it('should parse a merge statement', () => {
const merge = {
$type: 'Merge',
branch: 'newBranch',
id: '1',
tags: ['tag1', 'tag2'],
type: 'NORMAL',
};
parseStatement(merge, mockDB);
expect(mockDB.merge).toHaveBeenCalledWith({
branch: 'newBranch',
id: '1',
tags: ['tag1', 'tag2'],
type: 0,
});
});
it('should parse a cherry picking statement', () => {
const cherryPick = {
$type: 'CherryPicking',
id: '1',
tags: ['tag1', 'tag2'],
parent: '2',
};
parseStatement(cherryPick, mockDB);
expect(mockDB.cherryPick).toHaveBeenCalledWith({
id: '1',
targetId: '',
parent: '2',
tags: ['tag1', 'tag2'],
});
});
it('should parse a langium generated gitGraph ast', () => {
const dummy: GitGraph = {
$type: 'GitGraph',
statements: [],
};
const gitGraphAst: GitGraph = {
$type: 'GitGraph',
statements: [
{
$container: dummy,
$type: 'Commit',
id: '1',
message: 'test',
tags: ['tag1', 'tag2'],
type: 'NORMAL',
},
{
$container: dummy,
$type: 'Branch',
name: 'newBranch',
order: 1,
},
{
$container: dummy,
$type: 'Merge',
branch: 'newBranch',
id: '1',
tags: ['tag1', 'tag2'],
type: 'NORMAL',
},
{
$container: dummy,
$type: 'Checkout',
branch: 'newBranch',
},
{
$container: dummy,
$type: 'CherryPicking',
id: '1',
tags: ['tag1', 'tag2'],
parent: '2',
},
],
};
populate(gitGraphAst, mockDB);
expect(mockDB.commit).toHaveBeenCalledWith({
id: '1',
msg: 'test',
tags: ['tag1', 'tag2'],
type: 0,
});
expect(mockDB.branch).toHaveBeenCalledWith({ name: 'newBranch', order: 1 });
expect(mockDB.merge).toHaveBeenCalledWith({
branch: 'newBranch',
id: '1',
tags: ['tag1', 'tag2'],
type: 0,
});
expect(mockDB.checkout).toHaveBeenCalledWith('newBranch');
});
});
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,893 +0,0 @@
import { select } from 'd3';
import { getConfig, setupGraphViewbox } from '../../diagram-api/diagramAPI.js';
import { log } from '../../logger.js';
import utils from '../../utils.js';
/**
* @typedef {Map<string, { id: string, message: string, seq: number, type: number, tag: string, parents: string[], branch: string }>} CommitMap
*/
/** @type {CommitMap} */
let allCommitsDict = new Map();
const commitType = {
NORMAL: 0,
REVERSE: 1,
HIGHLIGHT: 2,
MERGE: 3,
CHERRY_PICK: 4,
};
const THEME_COLOR_LIMIT = 8;
let branchPos = {};
let commitPos = {};
let lanes = [];
let maxPos = 0;
let dir = 'LR';
let defaultPos = 30;
const clear = () => {
branchPos = new Map();
commitPos = new Map();
allCommitsDict = new Map();
maxPos = 0;
lanes = [];
dir = 'LR';
};
/**
* Draws a text, used for labels of the branches
*
* @param {string} txt The text
* @returns {SVGElement}
*/
const drawText = (txt) => {
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
let rows = [];
// Handling of new lines in the label
if (typeof txt === 'string') {
rows = txt.split(/\\n|\n|<br\s*\/?>/gi);
} else if (Array.isArray(txt)) {
rows = txt;
} else {
rows = [];
}
for (const row of rows) {
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', '0');
tspan.setAttribute('class', 'row');
tspan.textContent = row.trim();
svgLabel.appendChild(tspan);
}
/**
* @param svg
* @param selector
*/
return svgLabel;
};
/**
* Searches for the closest parent from the parents list passed as argument.
* The parents list comes from an individual commit. The closest parent is actually
* the one farther down the graph, since that means it is closer to its child.
*
* @param {string[]} parents
* @returns {string | undefined}
*/
const findClosestParent = (parents) => {
let closestParent = '';
let maxPosition = 0;
parents.forEach((parent) => {
const parentPosition =
dir === 'TB' || dir === 'BT' ? commitPos.get(parent).y : commitPos.get(parent).x;
if (parentPosition >= maxPosition) {
closestParent = parent;
maxPosition = parentPosition;
}
});
return closestParent || undefined;
};
/**
* Searches for the closest parent from the parents list passed as argument for Bottom-to-Top orientation.
* The parents list comes from an individual commit. The closest parent is actually
* the one farther down the graph, since that means it is closer to its child.
*
* @param {string[]} parents
* @returns {string | undefined}
*/
const findClosestParentBT = (parents) => {
let closestParent = '';
let maxPosition = Infinity;
parents.forEach((parent) => {
const parentPosition = commitPos.get(parent).y;
if (parentPosition <= maxPosition) {
closestParent = parent;
maxPosition = parentPosition;
}
});
return closestParent || undefined;
};
/**
* Sets the position of the commit elements when the orientation is set to BT-Parallel.
* This is needed to render the chart in Bottom-to-Top mode while keeping the parallel
* commits in the correct position. First, it finds the correct position of the root commit
* using the findClosestParent method. Then, it uses the findClosestParentBT to set the position
* of the remaining commits.
*
* @param {any} sortedKeys
* @param {CommitMap} commits
* @param {any} defaultPos
* @param {any} commitStep
* @param {any} layoutOffset
*/
const setParallelBTPos = (sortedKeys, commits, defaultPos, commitStep, layoutOffset) => {
let curPos = defaultPos;
let maxPosition = defaultPos;
let roots = [];
sortedKeys.forEach((key) => {
const commit = commits.get(key);
if (commit.parents.length) {
const closestParent = findClosestParent(commit.parents);
curPos = commitPos.get(closestParent).y + commitStep;
if (curPos >= maxPosition) {
maxPosition = curPos;
}
} else {
roots.push(commit);
}
const x = branchPos.get(commit.branch).pos;
const y = curPos + layoutOffset;
commitPos.set(commit.id, { x: x, y: y });
});
curPos = maxPosition;
roots.forEach((commit) => {
const posWithOffset = curPos + defaultPos;
const y = posWithOffset;
const x = branchPos.get(commit.branch).pos;
commitPos.set(commit.id, { x: x, y: y });
});
sortedKeys.forEach((key) => {
const commit = commits.get(key);
if (commit.parents.length) {
const closestParent = findClosestParentBT(commit.parents);
curPos = commitPos.get(closestParent).y - commitStep;
if (curPos <= maxPosition) {
maxPosition = curPos;
}
const x = branchPos.get(commit.branch).pos;
const y = curPos - layoutOffset;
commitPos.set(commit.id, { x: x, y: y });
}
});
};
/**
* Draws the commits with its symbol and labels. The function has two modes, one which only
* calculates the positions and one that does the actual drawing. This for a simple way getting the
* vertical layering correct in the graph.
*
* @param {any} svg
* @param {CommitMap} commits
* @param {any} modifyGraph
*/
const drawCommits = (svg, commits, modifyGraph) => {
const gitGraphConfig = getConfig().gitGraph;
const gBullets = svg.append('g').attr('class', 'commit-bullets');
const gLabels = svg.append('g').attr('class', 'commit-labels');
let pos = 0;
if (dir === 'TB' || dir === 'BT') {
pos = defaultPos;
}
const keys = [...commits.keys()];
const isParallelCommits = gitGraphConfig.parallelCommits;
const layoutOffset = 10;
const commitStep = 40;
let sortedKeys =
dir !== 'BT' || (dir === 'BT' && isParallelCommits)
? keys.sort((a, b) => {
return commits.get(a).seq - commits.get(b).seq;
})
: keys
.sort((a, b) => {
return commits.get(a).seq - commits.get(b).seq;
})
.reverse();
if (dir === 'BT' && isParallelCommits) {
setParallelBTPos(sortedKeys, commits, pos, commitStep, layoutOffset);
sortedKeys = sortedKeys.reverse();
}
sortedKeys.forEach((key) => {
const commit = commits.get(key);
if (isParallelCommits) {
if (commit.parents.length) {
const closestParent =
dir === 'BT' ? findClosestParentBT(commit.parents) : findClosestParent(commit.parents);
if (dir === 'TB') {
pos = commitPos.get(closestParent).y + commitStep;
} else if (dir === 'BT') {
pos = commitPos.get(key).y - commitStep;
} else {
pos = commitPos.get(closestParent).x + commitStep;
}
} else {
if (dir === 'TB') {
pos = defaultPos;
} else if (dir === 'BT') {
pos = commitPos.get(key).y - commitStep;
} else {
pos = 0;
}
}
}
const posWithOffset = dir === 'BT' && isParallelCommits ? pos : pos + layoutOffset;
const y = dir === 'TB' || dir === 'BT' ? posWithOffset : branchPos.get(commit.branch).pos;
const x = dir === 'TB' || dir === 'BT' ? branchPos.get(commit.branch).pos : posWithOffset;
// Don't draw the commits now but calculate the positioning which is used by the branch lines etc.
if (modifyGraph) {
let typeClass;
let commitSymbolType =
commit.customType !== undefined && commit.customType !== ''
? commit.customType
: commit.type;
switch (commitSymbolType) {
case commitType.NORMAL:
typeClass = 'commit-normal';
break;
case commitType.REVERSE:
typeClass = 'commit-reverse';
break;
case commitType.HIGHLIGHT:
typeClass = 'commit-highlight';
break;
case commitType.MERGE:
typeClass = 'commit-merge';
break;
case commitType.CHERRY_PICK:
typeClass = 'commit-cherry-pick';
break;
default:
typeClass = 'commit-normal';
}
if (commitSymbolType === commitType.HIGHLIGHT) {
const circle = gBullets.append('rect');
circle.attr('x', x - 10);
circle.attr('y', y - 10);
circle.attr('height', 20);
circle.attr('width', 20);
circle.attr(
'class',
`commit ${commit.id} commit-highlight${
branchPos.get(commit.branch).index % THEME_COLOR_LIMIT
} ${typeClass}-outer`
);
gBullets
.append('rect')
.attr('x', x - 6)
.attr('y', y - 6)
.attr('height', 12)
.attr('width', 12)
.attr(
'class',
`commit ${commit.id} commit${
branchPos.get(commit.branch).index % THEME_COLOR_LIMIT
} ${typeClass}-inner`
);
} else if (commitSymbolType === commitType.CHERRY_PICK) {
gBullets
.append('circle')
.attr('cx', x)
.attr('cy', y)
.attr('r', 10)
.attr('class', `commit ${commit.id} ${typeClass}`);
gBullets
.append('circle')
.attr('cx', x - 3)
.attr('cy', y + 2)
.attr('r', 2.75)
.attr('fill', '#fff')
.attr('class', `commit ${commit.id} ${typeClass}`);
gBullets
.append('circle')
.attr('cx', x + 3)
.attr('cy', y + 2)
.attr('r', 2.75)
.attr('fill', '#fff')
.attr('class', `commit ${commit.id} ${typeClass}`);
gBullets
.append('line')
.attr('x1', x + 3)
.attr('y1', y + 1)
.attr('x2', x)
.attr('y2', y - 5)
.attr('stroke', '#fff')
.attr('class', `commit ${commit.id} ${typeClass}`);
gBullets
.append('line')
.attr('x1', x - 3)
.attr('y1', y + 1)
.attr('x2', x)
.attr('y2', y - 5)
.attr('stroke', '#fff')
.attr('class', `commit ${commit.id} ${typeClass}`);
} else {
const circle = gBullets.append('circle');
circle.attr('cx', x);
circle.attr('cy', y);
circle.attr('r', commit.type === commitType.MERGE ? 9 : 10);
circle.attr(
'class',
`commit ${commit.id} commit${branchPos.get(commit.branch).index % THEME_COLOR_LIMIT}`
);
if (commitSymbolType === commitType.MERGE) {
const circle2 = gBullets.append('circle');
circle2.attr('cx', x);
circle2.attr('cy', y);
circle2.attr('r', 6);
circle2.attr(
'class',
`commit ${typeClass} ${commit.id} commit${
branchPos.get(commit.branch).index % THEME_COLOR_LIMIT
}`
);
}
if (commitSymbolType === commitType.REVERSE) {
const cross = gBullets.append('path');
cross
.attr('d', `M ${x - 5},${y - 5}L${x + 5},${y + 5}M${x - 5},${y + 5}L${x + 5},${y - 5}`)
.attr(
'class',
`commit ${typeClass} ${commit.id} commit${
branchPos.get(commit.branch).index % THEME_COLOR_LIMIT
}`
);
}
}
}
if (dir === 'TB' || dir === 'BT') {
commitPos.set(commit.id, { x: x, y: posWithOffset });
} else {
commitPos.set(commit.id, { x: posWithOffset, y: y });
}
// The first iteration over the commits are for positioning purposes, this
// is required for drawing the lines. The circles and labels is drawn after the labels
// placing them on top of the lines.
if (modifyGraph) {
const px = 4;
const py = 2;
// Draw the commit label
if (
commit.type !== commitType.CHERRY_PICK &&
((commit.customId && commit.type === commitType.MERGE) ||
commit.type !== commitType.MERGE) &&
gitGraphConfig.showCommitLabel
) {
const wrapper = gLabels.append('g');
const labelBkg = wrapper.insert('rect').attr('class', 'commit-label-bkg');
const text = wrapper
.append('text')
.attr('x', pos)
.attr('y', y + 25)
.attr('class', 'commit-label')
.text(commit.id);
let bbox = text.node().getBBox();
// Now we have the label, lets position the background
labelBkg
.attr('x', posWithOffset - bbox.width / 2 - py)
.attr('y', y + 13.5)
.attr('width', bbox.width + 2 * py)
.attr('height', bbox.height + 2 * py);
if (dir === 'TB' || dir === 'BT') {
labelBkg.attr('x', x - (bbox.width + 4 * px + 5)).attr('y', y - 12);
text.attr('x', x - (bbox.width + 4 * px)).attr('y', y + bbox.height - 12);
} else {
text.attr('x', posWithOffset - bbox.width / 2);
}
if (gitGraphConfig.rotateCommitLabel) {
if (dir === 'TB' || dir === 'BT') {
text.attr('transform', 'rotate(' + -45 + ', ' + x + ', ' + y + ')');
labelBkg.attr('transform', 'rotate(' + -45 + ', ' + x + ', ' + y + ')');
} else {
let r_x = -7.5 - ((bbox.width + 10) / 25) * 9.5;
let r_y = 10 + (bbox.width / 25) * 8.5;
wrapper.attr(
'transform',
'translate(' + r_x + ', ' + r_y + ') rotate(' + -45 + ', ' + pos + ', ' + y + ')'
);
}
}
}
if (commit.tags.length > 0) {
let yOffset = 0;
let maxTagBboxWidth = 0;
let maxTagBboxHeight = 0;
const tagElements = [];
for (const tagValue of commit.tags.reverse()) {
const rect = gLabels.insert('polygon');
const hole = gLabels.append('circle');
const tag = gLabels
.append('text')
// Note that we are delaying setting the x position until we know the width of the text
.attr('y', y - 16 - yOffset)
.attr('class', 'tag-label')
.text(tagValue);
let tagBbox = tag.node().getBBox();
maxTagBboxWidth = Math.max(maxTagBboxWidth, tagBbox.width);
maxTagBboxHeight = Math.max(maxTagBboxHeight, tagBbox.height);
// We don't use the max over here to center the text within the tags
tag.attr('x', posWithOffset - tagBbox.width / 2);
tagElements.push({
tag,
hole,
rect,
yOffset,
});
yOffset += 20;
}
for (const { tag, hole, rect, yOffset } of tagElements) {
const h2 = maxTagBboxHeight / 2;
const ly = y - 19.2 - yOffset;
rect.attr('class', 'tag-label-bkg').attr(
'points',
`
${pos - maxTagBboxWidth / 2 - px / 2},${ly + py}
${pos - maxTagBboxWidth / 2 - px / 2},${ly - py}
${posWithOffset - maxTagBboxWidth / 2 - px},${ly - h2 - py}
${posWithOffset + maxTagBboxWidth / 2 + px},${ly - h2 - py}
${posWithOffset + maxTagBboxWidth / 2 + px},${ly + h2 + py}
${posWithOffset - maxTagBboxWidth / 2 - px},${ly + h2 + py}`
);
hole
.attr('cy', ly)
.attr('cx', pos - maxTagBboxWidth / 2 + px / 2)
.attr('r', 1.5)
.attr('class', 'tag-hole');
if (dir === 'TB' || dir === 'BT') {
const yOrigin = pos + yOffset;
rect
.attr('class', 'tag-label-bkg')
.attr(
'points',
`
${x},${yOrigin + py}
${x},${yOrigin - py}
${x + layoutOffset},${yOrigin - h2 - py}
${x + layoutOffset + maxTagBboxWidth + px},${yOrigin - h2 - py}
${x + layoutOffset + maxTagBboxWidth + px},${yOrigin + h2 + py}
${x + layoutOffset},${yOrigin + h2 + py}`
)
.attr('transform', 'translate(12,12) rotate(45, ' + x + ',' + pos + ')');
hole
.attr('cx', x + px / 2)
.attr('cy', yOrigin)
.attr('transform', 'translate(12,12) rotate(45, ' + x + ',' + pos + ')');
tag
.attr('x', x + 5)
.attr('y', yOrigin + 3)
.attr('transform', 'translate(14,14) rotate(45, ' + x + ',' + pos + ')');
}
}
}
}
pos = dir === 'BT' && isParallelCommits ? pos + commitStep : pos + commitStep + layoutOffset;
if (pos > maxPos) {
maxPos = pos;
}
});
};
/**
* Detect if there are commits
* between commitA's x-position
* and commitB's x-position on the
* same branch as commitA, where
* commitA isn't main
*
* @param {any} commitA
* @param {any} commitB
* @param p1
* @param p2
* @param {CommitMap} allCommits
* @returns {boolean}
* If there are commits between
* commitA's x-position
* and commitB's x-position
* on the source branch, where
* source branch is not main
* return true
*/
const shouldRerouteArrow = (commitA, commitB, p1, p2, allCommits) => {
const commitBIsFurthest = dir === 'TB' || dir === 'BT' ? p1.x < p2.x : p1.y < p2.y;
const branchToGetCurve = commitBIsFurthest ? commitB.branch : commitA.branch;
const isOnBranchToGetCurve = (x) => x.branch === branchToGetCurve;
const isBetweenCommits = (x) => x.seq > commitA.seq && x.seq < commitB.seq;
return [...allCommits.values()].some((commitX) => {
return isBetweenCommits(commitX) && isOnBranchToGetCurve(commitX);
});
};
/**
* This function find a lane in the y-axis that is not overlapping with any other lanes. This is
* used for drawing the lines between commits.
*
* @param {any} y1
* @param {any} y2
* @param {any} depth
* @returns {number} Y value between y1 and y2
*/
const findLane = (y1, y2, depth = 0) => {
const candidate = y1 + Math.abs(y1 - y2) / 2;
if (depth > 5) {
return candidate;
}
let ok = lanes.every((lane) => Math.abs(lane - candidate) >= 10);
if (ok) {
lanes.push(candidate);
return candidate;
}
const diff = Math.abs(y1 - y2);
return findLane(y1, y2 - diff / 5, depth + 1);
};
/**
* Draw the lines between the commits. They were arrows initially.
*
* @param {any} svg
* @param {any} commitA
* @param {any} commitB
* @param {CommitMap} allCommits
*/
const drawArrow = (svg, commitA, commitB, allCommits) => {
const p1 = commitPos.get(commitA.id); // arrowStart
const p2 = commitPos.get(commitB.id); // arrowEnd
const arrowNeedsRerouting = shouldRerouteArrow(commitA, commitB, p1, p2, allCommits);
// log.debug('drawArrow', p1, p2, arrowNeedsRerouting, commitA.id, commitB.id);
// Lower-right quadrant logic; top-left is 0,0
let arc = '';
let arc2 = '';
let radius = 0;
let offset = 0;
let colorClassNum = branchPos.get(commitB.branch).index;
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
colorClassNum = branchPos.get(commitA.branch).index;
}
let lineDef;
if (arrowNeedsRerouting) {
arc = 'A 10 10, 0, 0, 0,';
arc2 = 'A 10 10, 0, 0, 1,';
radius = 10;
offset = 10;
const lineY = p1.y < p2.y ? findLane(p1.y, p2.y) : findLane(p2.y, p1.y);
const lineX = p1.x < p2.x ? findLane(p1.x, p2.x) : findLane(p2.x, p1.x);
if (dir === 'TB') {
if (p1.x < p2.x) {
// Source commit is on branch position left of destination commit
// so render arrow rightward with colour of destination branch
lineDef = `M ${p1.x} ${p1.y} L ${lineX - radius} ${p1.y} ${arc2} ${lineX} ${
p1.y + offset
} L ${lineX} ${p2.y - radius} ${arc} ${lineX + offset} ${p2.y} L ${p2.x} ${p2.y}`;
} else {
// Source commit is on branch position right of destination commit
// so render arrow leftward with colour of source branch
colorClassNum = branchPos.get(commitA.branch).index;
lineDef = `M ${p1.x} ${p1.y} L ${lineX + radius} ${p1.y} ${arc} ${lineX} ${
p1.y + offset
} L ${lineX} ${p2.y - radius} ${arc2} ${lineX - offset} ${p2.y} L ${p2.x} ${p2.y}`;
}
} else if (dir === 'BT') {
if (p1.x < p2.x) {
// Source commit is on branch position left of destination commit
// so render arrow rightward with colour of destination branch
lineDef = `M ${p1.x} ${p1.y} L ${lineX - radius} ${p1.y} ${arc} ${lineX} ${
p1.y - offset
} L ${lineX} ${p2.y + radius} ${arc2} ${lineX + offset} ${p2.y} L ${p2.x} ${p2.y}`;
} else {
// Source commit is on branch position right of destination commit
// so render arrow leftward with colour of source branch
colorClassNum = branchPos.get(commitA.branch).index;
lineDef = `M ${p1.x} ${p1.y} L ${lineX + radius} ${p1.y} ${arc2} ${lineX} ${
p1.y - offset
} L ${lineX} ${p2.y + radius} ${arc} ${lineX - offset} ${p2.y} L ${p2.x} ${p2.y}`;
}
} else {
if (p1.y < p2.y) {
// Source commit is on branch positioned above destination commit
// so render arrow downward with colour of destination branch
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY - radius} ${arc} ${
p1.x + offset
} ${lineY} L ${p2.x - radius} ${lineY} ${arc2} ${p2.x} ${lineY + offset} L ${p2.x} ${p2.y}`;
} else {
// Source commit is on branch positioned below destination commit
// so render arrow upward with colour of source branch
colorClassNum = branchPos.get(commitA.branch).index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY + radius} ${arc2} ${
p1.x + offset
} ${lineY} L ${p2.x - radius} ${lineY} ${arc} ${p2.x} ${lineY - offset} L ${p2.x} ${p2.y}`;
}
}
} else {
arc = 'A 20 20, 0, 0, 0,';
arc2 = 'A 20 20, 0, 0, 1,';
radius = 20;
offset = 20;
if (dir === 'TB') {
if (p1.x < p2.x) {
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${
p2.y
} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc2} ${p2.x} ${
p1.y + offset
} L ${p2.x} ${p2.y}`;
}
}
if (p1.x > p2.x) {
arc = 'A 20 20, 0, 0, 0,';
arc2 = 'A 20 20, 0, 0, 1,';
radius = 20;
offset = 20;
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc2} ${p1.x - offset} ${
p2.y
} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x + radius} ${p1.y} ${arc} ${p2.x} ${
p1.y + offset
} L ${p2.x} ${p2.y}`;
}
}
if (p1.x === p2.x) {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
}
} else if (dir === 'BT') {
if (p1.x < p2.x) {
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y + radius} ${arc2} ${p1.x + offset} ${
p2.y
} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${
p1.y - offset
} L ${p2.x} ${p2.y}`;
}
}
if (p1.x > p2.x) {
arc = 'A 20 20, 0, 0, 0,';
arc2 = 'A 20 20, 0, 0, 1,';
radius = 20;
offset = 20;
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y + radius} ${arc} ${p1.x - offset} ${
p2.y
} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${
p1.y - offset
} L ${p2.x} ${p2.y}`;
}
}
if (p1.x === p2.x) {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
}
} else {
if (p1.y < p2.y) {
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc2} ${p2.x} ${
p1.y + offset
} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${
p2.y
} L ${p2.x} ${p2.y}`;
}
}
if (p1.y > p2.y) {
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${
p1.y - offset
} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y + radius} ${arc2} ${p1.x + offset} ${
p2.y
} L ${p2.x} ${p2.y}`;
}
}
if (p1.y === p2.y) {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
}
}
}
svg
.append('path')
.attr('d', lineDef)
.attr('class', 'arrow arrow' + (colorClassNum % THEME_COLOR_LIMIT));
};
/**
* @param {*} svg
* @param {CommitMap} commits
*/
const drawArrows = (svg, commits) => {
const gArrows = svg.append('g').attr('class', 'commit-arrows');
[...commits.keys()].forEach((key) => {
const commit = commits.get(key);
if (commit.parents && commit.parents.length > 0) {
commit.parents.forEach((parent) => {
drawArrow(gArrows, commits.get(parent), commit, commits);
});
}
});
};
/**
* Adds the branches and the branches' labels to the svg.
*
* @param svg
* @param branches
*/
const drawBranches = (svg, branches) => {
const gitGraphConfig = getConfig().gitGraph;
const g = svg.append('g');
branches.forEach((branch, index) => {
const adjustIndexForTheme = index % THEME_COLOR_LIMIT;
const pos = branchPos.get(branch.name).pos;
const line = g.append('line');
line.attr('x1', 0);
line.attr('y1', pos);
line.attr('x2', maxPos);
line.attr('y2', pos);
line.attr('class', 'branch branch' + adjustIndexForTheme);
if (dir === 'TB') {
line.attr('y1', defaultPos);
line.attr('x1', pos);
line.attr('y2', maxPos);
line.attr('x2', pos);
} else if (dir === 'BT') {
line.attr('y1', maxPos);
line.attr('x1', pos);
line.attr('y2', defaultPos);
line.attr('x2', pos);
}
lanes.push(pos);
let name = branch.name;
// Create the actual text element
const labelElement = drawText(name);
// Create outer g, edgeLabel, this will be positioned after graph layout
const bkg = g.insert('rect');
const branchLabel = g.insert('g').attr('class', 'branchLabel');
// Create inner g, label, this will be positioned now for centering the text
const label = branchLabel.insert('g').attr('class', 'label branch-label' + adjustIndexForTheme);
label.node().appendChild(labelElement);
let bbox = labelElement.getBBox();
bkg
.attr('class', 'branchLabelBkg label' + adjustIndexForTheme)
.attr('rx', 4)
.attr('ry', 4)
.attr('x', -bbox.width - 4 - (gitGraphConfig.rotateCommitLabel === true ? 30 : 0))
.attr('y', -bbox.height / 2 + 8)
.attr('width', bbox.width + 18)
.attr('height', bbox.height + 4);
label.attr(
'transform',
'translate(' +
(-bbox.width - 14 - (gitGraphConfig.rotateCommitLabel === true ? 30 : 0)) +
', ' +
(pos - bbox.height / 2 - 1) +
')'
);
if (dir === 'TB') {
bkg.attr('x', pos - bbox.width / 2 - 10).attr('y', 0);
label.attr('transform', 'translate(' + (pos - bbox.width / 2 - 5) + ', ' + 0 + ')');
} else if (dir === 'BT') {
bkg.attr('x', pos - bbox.width / 2 - 10).attr('y', maxPos);
label.attr('transform', 'translate(' + (pos - bbox.width / 2 - 5) + ', ' + maxPos + ')');
} else {
bkg.attr('transform', 'translate(' + -19 + ', ' + (pos - bbox.height / 2) + ')');
}
});
};
/**
* @param txt
* @param id
* @param ver
* @param diagObj
*/
export const draw = function (txt, id, ver, diagObj) {
clear();
const conf = getConfig();
const gitGraphConfig = conf.gitGraph;
// try {
log.debug('in gitgraph renderer', txt + '\n', 'id:', id, ver);
allCommitsDict = diagObj.db.getCommits();
const branches = diagObj.db.getBranchesAsObjArray();
dir = diagObj.db.getDirection();
const diagram = select(`[id="${id}"]`);
// Position branches
let pos = 0;
branches.forEach((branch, index) => {
const labelElement = drawText(branch.name);
const g = diagram.append('g');
const branchLabel = g.insert('g').attr('class', 'branchLabel');
const label = branchLabel.insert('g').attr('class', 'label branch-label');
label.node().appendChild(labelElement);
let bbox = labelElement.getBBox();
branchPos.set(branch.name, { pos, index });
pos +=
50 +
(gitGraphConfig.rotateCommitLabel ? 40 : 0) +
(dir === 'TB' || dir === 'BT' ? bbox.width / 2 : 0);
label.remove();
branchLabel.remove();
g.remove();
});
drawCommits(diagram, allCommitsDict, false);
if (gitGraphConfig.showBranches) {
drawBranches(diagram, branches);
}
drawArrows(diagram, allCommitsDict);
drawCommits(diagram, allCommitsDict, true);
utils.insertTitle(
diagram,
'gitTitleText',
gitGraphConfig.titleTopMargin,
diagObj.db.getDiagramTitle()
);
// Setup the view box and size of the svg element
setupGraphViewbox(
undefined,
diagram,
gitGraphConfig.diagramPadding,
gitGraphConfig.useMaxWidth ?? conf.useMaxWidth
);
};
export default {
draw,
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,134 @@
import type { GitGraphDiagramConfig } from '../../config.type.js';
import type { DiagramDBBase } from '../../diagram-api/types.js';
export const commitType = {
NORMAL: 0,
REVERSE: 1,
HIGHLIGHT: 2,
MERGE: 3,
CHERRY_PICK: 4,
} as const;
export interface CommitDB {
msg: string;
id: string;
type: number;
tags?: string[];
}
export interface BranchDB {
name: string;
order: number;
}
export interface MergeDB {
branch: string;
id: string;
type?: number;
tags?: string[];
}
export interface CherryPickDB {
id: string;
targetId: string;
parent: string;
tags?: string[];
}
export interface Commit {
id: string;
message: string;
seq: number;
type: number;
tags: string[];
parents: string[];
branch: string;
customType?: number;
customId?: boolean;
}
export interface GitGraph {
statements: Statement[];
}
export type Statement = CommitAst | BranchAst | MergeAst | CheckoutAst | CherryPickingAst;
export interface CommitAst {
$type: 'Commit';
id: string;
message?: string;
tags?: string[];
type?: 'NORMAL' | 'REVERSE' | 'HIGHLIGHT';
}
export interface BranchAst {
$type: 'Branch';
name: string;
order?: number;
}
export interface MergeAst {
$type: 'Merge';
branch: string;
id?: string;
tags?: string[];
type?: 'NORMAL' | 'REVERSE' | 'HIGHLIGHT';
}
export interface CheckoutAst {
$type: 'Checkout';
branch: string;
}
export interface CherryPickingAst {
$type: 'CherryPicking';
id: string;
parent: string;
tags?: string[];
}
export interface GitGraphDB extends DiagramDBBase<GitGraphDiagramConfig> {
commitType: typeof commitType;
setDirection: (dir: DiagramOrientation) => void;
setOptions: (rawOptString: string) => void;
getOptions: () => any;
commit: (commitDB: CommitDB) => void;
branch: (branchDB: BranchDB) => void;
merge: (mergeDB: MergeDB) => void;
cherryPick: (cherryPickDB: CherryPickDB) => void;
checkout: (branch: string) => void;
prettyPrint: () => void;
clear: () => void;
getBranchesAsObjArray: () => { name: string }[];
getBranches: () => Map<string, string | null>;
getCommits: () => Map<string, Commit>;
getCommitsArray: () => Commit[];
getCurrentBranch: () => string;
getDirection: () => DiagramOrientation;
getHead: () => Commit | null;
}
export interface GitGraphDBParseProvider extends Partial<GitGraphDB> {
commitType: typeof commitType;
setDirection: (dir: DiagramOrientation) => void;
commit: (commitDB: CommitDB) => void;
branch: (branchDB: BranchDB) => void;
merge: (mergeDB: MergeDB) => void;
cherryPick: (cherryPickDB: CherryPickDB) => void;
checkout: (branch: string) => void;
}
export interface GitGraphDBRenderProvider extends Partial<GitGraphDB> {
prettyPrint: () => void;
clear: () => void;
getBranchesAsObjArray: () => { name: string }[];
getBranches: () => Map<string, string | null>;
getCommits: () => Map<string, Commit>;
getCommitsArray: () => Commit[];
getCurrentBranch: () => string;
getDirection: () => DiagramOrientation;
getHead: () => Commit | null;
getDiagramTitle: () => string;
}
export type DiagramOrientation = 'LR' | 'TB' | 'BT';

View File

@@ -1,248 +0,0 @@
/*
* Parse following
* gitGraph:
* commit
* commit
* branch
*/
%lex
%x string
%x options
%x acc_title
%x acc_descr
%x acc_descr_multiline
%options case-insensitive
%%
accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; }
<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; }
accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; }
<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; }
accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
<acc_descr_multiline>[\}] { this.popState(); }
<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value";
(\r?\n)+ /*{console.log('New line');return 'NL';}*/ return 'NL';
\#[^\n]* /* skip comments */
\%%[^\n]* /* skip comments */
"gitGraph" return 'GG';
commit(?=\s|$) return 'COMMIT';
"id:" return 'COMMIT_ID';
"type:" return 'COMMIT_TYPE';
"msg:" return 'COMMIT_MSG';
"NORMAL" return 'NORMAL';
"REVERSE" return 'REVERSE';
"HIGHLIGHT" return 'HIGHLIGHT';
"tag:" return 'COMMIT_TAG';
branch(?=\s|$) return 'BRANCH';
"order:" return 'ORDER';
merge(?=\s|$) return 'MERGE';
cherry\-pick(?=\s|$) return 'CHERRY_PICK';
"parent:" return 'PARENT_COMMIT'
// "reset" return 'RESET';
\b(checkout|switch)(?=\s|$) return 'CHECKOUT';
"LR" return 'DIR';
"TB" return 'DIR';
"BT" return 'DIR';
":" return ':';
"^" return 'CARET'
"options"\r?\n this.begin("options"); //
<options>[ \r\n\t]+"end" this.popState(); // not used anymore in the renderer, fixed for backward compatibility
<options>[\s\S]+(?=[ \r\n\t]+"end") return 'OPT'; //
["]["] return 'EMPTYSTR';
["] this.begin("string");
<string>["] this.popState();
<string>[^"]* return 'STR';
[0-9]+(?=\s|$) return 'NUM';
\w([-\./\w]*[-\w])? return 'ID'; // only a subset of https://git-scm.com/docs/git-check-ref-format
<<EOF>> return 'EOF';
\s+ /* skip all whitespace */ // lowest priority so we can use lookaheads in earlier regex
/lex
%left '^'
%start start
%% /* language grammar */
start
: eol start
| GG document EOF{ return $3; }
| GG ':' document EOF{ return $3; }
| GG DIR ':' document EOF {yy.setDirection($2); return $4;}
;
document
: /*empty*/
| options body { yy.setOptions($1); $$ = $2}
;
options
: options OPT {$1 +=$2; $$=$1}
| NL
;
body
: /*empty*/ {$$ = []}
| body line {$1.push($2); $$=$1;}
;
line
: statement eol {$$ =$1}
| NL
;
statement
: commitStatement
| mergeStatement
| cherryPickStatement
| acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); }
| acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); }
| acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); } | section {yy.addSection($1.substr(8));$$=$1.substr(8);}
| branchStatement
| CHECKOUT ref {yy.checkout($2)}
// | RESET reset_arg {yy.reset($2)}
;
branchStatement
: BRANCH ref {yy.branch($2)}
| BRANCH ref ORDER NUM {yy.branch($2, $4)}
;
cherryPickStatement
: CHERRY_PICK COMMIT_ID STR {yy.cherryPick($3, '', undefined)}
| CHERRY_PICK COMMIT_ID STR PARENT_COMMIT STR {yy.cherryPick($3, '', undefined,$5)}
| CHERRY_PICK COMMIT_ID STR commitTags {yy.cherryPick($3, '', $4)}
| CHERRY_PICK COMMIT_ID STR PARENT_COMMIT STR commitTags {yy.cherryPick($3, '', $6,$5)}
| CHERRY_PICK COMMIT_ID STR commitTags PARENT_COMMIT STR {yy.cherryPick($3, '', $4,$6)}
| CHERRY_PICK commitTags COMMIT_ID STR {yy.cherryPick($4, '', $2)}
| CHERRY_PICK commitTags COMMIT_ID STR PARENT_COMMIT STR {yy.cherryPick($4, '', $2,$6)}
;
mergeStatement
: MERGE ref {yy.merge($2,'','', undefined)}
| MERGE ref COMMIT_ID STR {yy.merge($2, $4,'', undefined)}
| MERGE ref COMMIT_TYPE commitType {yy.merge($2,'', $4, undefined)}
| MERGE ref commitTags {yy.merge($2, '','',$3)}
| MERGE ref commitTags COMMIT_ID STR {yy.merge($2, $5,'', $3)}
| MERGE ref commitTags COMMIT_TYPE commitType {yy.merge($2, '',$5, $3)}
| MERGE ref COMMIT_TYPE commitType commitTags {yy.merge($2, '',$4, $5)}
| MERGE ref COMMIT_ID STR COMMIT_TYPE commitType {yy.merge($2, $4, $6, undefined)}
| MERGE ref COMMIT_ID STR commitTags {yy.merge($2, $4, '', $5)}
| MERGE ref COMMIT_TYPE commitType COMMIT_ID STR {yy.merge($2, $6,$4, undefined)}
| MERGE ref COMMIT_ID STR COMMIT_TYPE commitType commitTags {yy.merge($2, $4, $6, $7)}
| MERGE ref COMMIT_TYPE commitType commitTags COMMIT_ID STR {yy.merge($2, $7, $4, $5)}
| MERGE ref COMMIT_ID STR commitTags COMMIT_TYPE commitType {yy.merge($2, $4, $7, $5)}
| MERGE ref COMMIT_TYPE commitType COMMIT_ID STR commitTags {yy.merge($2, $6, $4, $7)}
| MERGE ref commitTags COMMIT_TYPE commitType COMMIT_ID STR {yy.merge($2, $7, $5, $3)}
| MERGE ref commitTags COMMIT_ID STR COMMIT_TYPE commitType {yy.merge($2, $5, $7, $3)}
;
commitStatement
: COMMIT commit_arg {yy.commit($2)}
| COMMIT commitTags {yy.commit('','',yy.commitType.NORMAL,$2)}
| COMMIT COMMIT_TYPE commitType {yy.commit('','',$3, undefined)}
| COMMIT commitTags COMMIT_TYPE commitType {yy.commit('','',$4,$2)}
| COMMIT COMMIT_TYPE commitType commitTags {yy.commit('','',$3,$4)}
| COMMIT COMMIT_ID STR {yy.commit('',$3,yy.commitType.NORMAL, undefined)}
| COMMIT COMMIT_ID STR commitTags {yy.commit('',$3,yy.commitType.NORMAL,$4)}
| COMMIT commitTags COMMIT_ID STR {yy.commit('',$4,yy.commitType.NORMAL,$2)}
| COMMIT COMMIT_ID STR COMMIT_TYPE commitType {yy.commit('',$3,$5, undefined)}
| COMMIT COMMIT_TYPE commitType COMMIT_ID STR {yy.commit('',$5,$3, undefined)}
| COMMIT COMMIT_ID STR COMMIT_TYPE commitType commitTags {yy.commit('',$3,$5,$6)}
| COMMIT COMMIT_ID STR commitTags COMMIT_TYPE commitType {yy.commit('',$3,$6,$4)}
| COMMIT COMMIT_TYPE commitType COMMIT_ID STR commitTags {yy.commit('',$5,$3,$6)}
| COMMIT COMMIT_TYPE commitType commitTags COMMIT_ID STR {yy.commit('',$6,$3,$4)}
| COMMIT commitTags COMMIT_TYPE commitType COMMIT_ID STR {yy.commit('',$6,$4,$2)}
| COMMIT commitTags COMMIT_ID STR COMMIT_TYPE commitType {yy.commit('',$4,$6,$2)}
| COMMIT COMMIT_MSG STR {yy.commit($3,'',yy.commitType.NORMAL, undefined)}
| COMMIT commitTags COMMIT_MSG STR {yy.commit($4,'',yy.commitType.NORMAL,$2)}
| COMMIT COMMIT_MSG STR commitTags {yy.commit($3,'',yy.commitType.NORMAL,$4)}
| COMMIT COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($3,'',$5, undefined)}
| COMMIT COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($5,'',$3, undefined)}
| COMMIT COMMIT_ID STR COMMIT_MSG STR {yy.commit($5,$3,yy.commitType.NORMAL, undefined)}
| COMMIT COMMIT_MSG STR COMMIT_ID STR {yy.commit($3,$5,yy.commitType.NORMAL, undefined)}
| COMMIT COMMIT_MSG STR COMMIT_TYPE commitType commitTags {yy.commit($3,'',$5,$6)}
| COMMIT COMMIT_MSG STR commitTags COMMIT_TYPE commitType {yy.commit($3,'',$6,$4)}
| COMMIT COMMIT_TYPE commitType COMMIT_MSG STR commitTags {yy.commit($5,'',$3,$6)}
| COMMIT COMMIT_TYPE commitType commitTags COMMIT_MSG STR {yy.commit($6,'',$3,$4)}
| COMMIT commitTags COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($6,'',$4,$2)}
| COMMIT commitTags COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($4,'',$6,$2)}
| COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($3,$7,$5, undefined)}
| COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($3,$5,$7, undefined)}
| COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR {yy.commit($5,$7,$3, undefined)}
| COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR {yy.commit($7,$5,$3, undefined)}
| COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($7,$3,$5, undefined)}
| COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($5,$3,$7, undefined)}
| COMMIT COMMIT_MSG STR commitTags COMMIT_ID STR {yy.commit($3,$6,yy.commitType.NORMAL,$4)}
| COMMIT COMMIT_MSG STR COMMIT_ID STR commitTags {yy.commit($3,$5,yy.commitType.NORMAL,$6)}
| COMMIT commitTags COMMIT_MSG STR COMMIT_ID STR {yy.commit($4,$6,yy.commitType.NORMAL,$2)}
| COMMIT commitTags COMMIT_ID STR COMMIT_MSG STR {yy.commit($6,$4,yy.commitType.NORMAL,$2)}
| COMMIT COMMIT_ID STR commitTags COMMIT_MSG STR {yy.commit($6,$3,yy.commitType.NORMAL,$4)}
| COMMIT COMMIT_ID STR COMMIT_MSG STR commitTags {yy.commit($5,$3,yy.commitType.NORMAL,$6)}
| COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType commitTags {yy.commit($3,$5,$7,$8)}
| COMMIT COMMIT_MSG STR COMMIT_ID STR commitTags COMMIT_TYPE commitType {yy.commit($3,$5,$8,$6)}
| COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR commitTags {yy.commit($3,$7,$5,$8)}
| COMMIT COMMIT_MSG STR COMMIT_TYPE commitType commitTags COMMIT_ID STR {yy.commit($3,$8,$5,$6)}
| COMMIT COMMIT_MSG STR commitTags COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($3,$6,$8,$4)}
| COMMIT COMMIT_MSG STR commitTags COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($3,$8,$6,$4)}
| COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType commitTags {yy.commit($5,$3,$7,$8)}
| COMMIT COMMIT_ID STR COMMIT_MSG STR commitTags COMMIT_TYPE commitType {yy.commit($5,$3,$8,$6)}
| COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR commitTags {yy.commit($7,$3,$5,$8)}
| COMMIT COMMIT_ID STR COMMIT_TYPE commitType commitTags COMMIT_MSG STR {yy.commit($8,$3,$5,$6)}
| COMMIT COMMIT_ID STR commitTags COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($6,$3,$8,$4)}
| COMMIT COMMIT_ID STR commitTags COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($8,$3,$6,$4)}
| COMMIT commitTags COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($8,$4,$6,$2)}
| COMMIT commitTags COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($6,$4,$8,$2)}
| COMMIT commitTags COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR {yy.commit($8,$6,$4,$2)}
| COMMIT commitTags COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR {yy.commit($6,$8,$4,$2)}
| COMMIT commitTags COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($4,$6,$8,$2)}
| COMMIT commitTags COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($4,$8,$6,$2)}
| COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR commitTags {yy.commit($7,$5,$3,$8)}
| COMMIT COMMIT_TYPE commitType COMMIT_ID STR commitTags COMMIT_MSG STR {yy.commit($8,$5,$3,$6)}
| COMMIT COMMIT_TYPE commitType commitTags COMMIT_MSG STR COMMIT_ID STR {yy.commit($6,$8,$3,$4)}
| COMMIT COMMIT_TYPE commitType commitTags COMMIT_ID STR COMMIT_MSG STR {yy.commit($8,$6,$3,$4)}
| COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR commitTags {yy.commit($5,$7,$3,$8)}
| COMMIT COMMIT_TYPE commitType COMMIT_MSG STR commitTags COMMIT_ID STR {yy.commit($5,$8,$3,$6)}
;
commit_arg
: /* empty */ {$$ = ""}
| STR {$$=$1}
;
commitType
: NORMAL { $$=yy.commitType.NORMAL;}
| REVERSE { $$=yy.commitType.REVERSE;}
| HIGHLIGHT { $$=yy.commitType.HIGHLIGHT;}
;
commitTags
: COMMIT_TAG STR {$$=[$2]}
| COMMIT_TAG EMPTYSTR {$$=['']}
| commitTags COMMIT_TAG STR {$commitTags.push($3); $$=$commitTags;}
| commitTags COMMIT_TAG EMPTYSTR {$commitTags.push(''); $$=$commitTags;}
;
ref
: ID
| STR
;
eol
: NL
| ';'
| EOF
;
// reset_arg
// : 'HEAD' reset_parents{$$ = $1+ ":" + $2 }
// | ID reset_parents{$$ = $1+ ":" + yy.count; yy.count = 0}
// ;
// reset_parents
// : /* empty */ {yy.count = 0}
// | CARET reset_parents { yy.count += 1 }
// ;

View File

@@ -1,7 +1,7 @@
import type { DrawDefinition, SVG, SVGGroup } from '../../diagram-api/types.js';
import { log } from '../../logger.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
import type { DrawDefinition, Group, SVG } from '../../diagram-api/types.js';
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
/**
* Draws a an info picture in the tag with id: id based on the graph definition in text.
@@ -16,7 +16,7 @@ const draw: DrawDefinition = (text, id, version) => {
const svg: SVG = selectSvgElement(id);
configureSvgSize(svg, 100, 400, true);
const group: Group = svg.append('g');
const group: SVGGroup = svg.append('g');
group
.append('text')
.attr('x', 100)

View File

@@ -1,6 +1,6 @@
import type { Diagram } from '../../Diagram.js';
import type { PacketDiagramConfig } from '../../config.type.js';
import type { DiagramRenderer, DrawDefinition, Group, SVG } from '../../diagram-api/types.js';
import type { DiagramRenderer, DrawDefinition, SVG, SVGGroup } from '../../diagram-api/types.js';
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
import type { PacketDB, PacketWord } from './types.js';
@@ -39,7 +39,7 @@ const drawWord = (
rowNumber: number,
{ rowHeight, paddingX, paddingY, bitWidth, bitsPerRow, showBits }: Required<PacketDiagramConfig>
) => {
const group: Group = svg.append('g');
const group: SVGGroup = svg.append('g');
const wordY = rowNumber * (rowHeight + paddingY) + paddingY;
for (const block of word) {
const blockX = (block.start % bitsPerRow) * bitWidth + 1;

View File

@@ -1,13 +1,13 @@
import type d3 from 'd3';
import { scaleOrdinal, pie as d3pie, arc } from 'd3';
import { log } from '../../logger.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import { cleanAndMerge, parseFontSize } from '../../utils.js';
import type { DrawDefinition, Group, SVG } from '../../diagram-api/types.js';
import type { D3Section, PieDB, Sections } from './pieTypes.js';
import { arc, pie as d3pie, scaleOrdinal } from 'd3';
import type { MermaidConfig, PieDiagramConfig } from '../../config.type.js';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import type { DrawDefinition, SVG, SVGGroup } from '../../diagram-api/types.js';
import { log } from '../../logger.js';
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
import { cleanAndMerge, parseFontSize } from '../../utils.js';
import type { D3Section, PieDB, Sections } from './pieTypes.js';
const createPieArcs = (sections: Sections): d3.PieArcDatum<D3Section>[] => {
// Compute the position of each group on the pie:
@@ -46,7 +46,7 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => {
const height = 450;
const pieWidth: number = height;
const svg: SVG = selectSvgElement(id);
const group: Group = svg.append('g');
const group: SVGGroup = svg.append('g');
group.attr('transform', 'translate(' + pieWidth / 2 + ',' + height / 2 + ')');
const { themeVariables } = globalConfig;

View File

@@ -1,11 +1,11 @@
import { line, select } from 'd3';
import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import { log } from '../../logger.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
import common from '../common/common.js';
import markers from './requirementMarkers.js';
import { getConfig } from '../../diagram-api/diagramAPI.js';
let conf = {};
let relCnt = 0;
@@ -86,7 +86,7 @@ const newBodyNode = (parentNode, id, txts, yStart) => {
// );
let currentRow = 0;
const charLimit = 24;
const charLimit = 30;
let wrappedTxts = [];
txts.forEach((textStr) => {
let currentTextLen = textStr.length;

View File

@@ -166,43 +166,11 @@ function insertOrUpdateNode(nodes, nodeData, classes) {
* @returns {string}
*/
function getClassesFromDbInfo(dbInfoItem) {
if (dbInfoItem === undefined || dbInfoItem === null) {
return '';
} else {
if (dbInfoItem.classes) {
let classStr = '';
// for each class in classes, add it to the string as comma separated
for (let i = 0; i < dbInfoItem.classes.length; i++) {
//do not add comma for the last class
if (i === dbInfoItem.classes.length - 1) {
classStr += dbInfoItem.classes[i];
}
//add comma for all other classes
else {
classStr += dbInfoItem.classes[i] + ' ';
}
}
return classStr;
} else {
return '';
}
}
return dbInfoItem?.classes?.join(' ') ?? '';
}
/**
* Get classes from the db for the info item.
* If there aren't any or if dbInfoItem isn't defined, return an empty string.
* Else create 1 string from the list of classes found
*/
function getStylesFromDbInfo(dbInfoItem) {
if (dbInfoItem === undefined || dbInfoItem === null) {
return;
} else {
if (dbInfoItem.styles) {
return dbInfoItem.styles;
} else {
return [];
}
}
return dbInfoItem?.styles ?? [];
}
export const dataFetcher = (
@@ -224,10 +192,10 @@ export const dataFetcher = (
if (itemId !== 'root') {
let shape = SHAPE_STATE;
// The if === true / false can be removed if we can guarantee that the parsedItem.start is always a boolean
if (parsedItem.start === true) {
shape = SHAPE_START;
}
if (parsedItem.start === false) {
} else if (parsedItem.start === false) {
shape = SHAPE_END;
}
if (parsedItem.type !== DEFAULT_STATE_TYPE) {

View File

@@ -1,7 +1,7 @@
import { getConfig } from '../../diagram-api/diagramAPI.js';
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
import { log } from '../../logger.js';
import { getDiagramElements } from '../../rendering-util/insertElementsForSize.js';
import { getDiagramElement } from '../../rendering-util/insertElementsForSize.js';
import { render } from '../../rendering-util/render.js';
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
import type { LayoutData } from '../../rendering-util/types.js';
@@ -55,7 +55,7 @@ export const draw = async function (text: string, id: string, _version: string,
const data4Layout = diag.db.getData() as LayoutData;
// Create the root SVG - the element is the div containing the SVG element
const { element, svg } = getDiagramElements(id, securityLevel);
const svg = getDiagramElement(id, securityLevel);
data4Layout.type = diag.type;
data4Layout.layoutAlgorithm = layout;
@@ -67,10 +67,10 @@ export const draw = async function (text: string, id: string, _version: string,
data4Layout.markers = ['barb'];
data4Layout.diagramId = id;
// console.log('REF1:', data4Layout);
await render(data4Layout, svg, element);
await render(data4Layout, svg);
const padding = 8;
utils.insertTitle(
element,
svg,
'statediagramTitleText',
conf?.titleTopMargin ?? 25,
diag.db.getDiagramTitle()

View File

@@ -18,7 +18,7 @@
\#[^\n]* /* skip comments */
"timeline" return 'timeline';
"title"\s[^\n;]+ return 'title';
"title"\s[^\n]+ return 'title';
accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; }
<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; }
accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; }
@@ -26,11 +26,11 @@ accDescr\s*":"\s* { this.begin("ac
accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
<acc_descr_multiline>[\}] { this.popState(); }
<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value";
"section"\s[^:\n;]+ return 'section';
"section"\s[^:\n]+ return 'section';
// event starting with "==>" keyword
":"\s[^:\n;]+ return 'event';
[^#:\n;]+ return 'period';
":"\s[^:\n]+ return 'event';
[^#:\n]+ return 'period';
<<EOF>> return 'EOF';

View File

@@ -1,7 +1,7 @@
import { setLogLevel } from '../../diagram-api/diagramAPI.js';
import * as commonDb from '../common/commonDb.js';
import { parser as timeline } from './parser/timeline.jison';
import * as timelineDB from './timelineDb.js';
import * as commonDb from '../common/commonDb.js';
import { setLogLevel } from '../../diagram-api/diagramAPI.js';
describe('when parsing a timeline ', function () {
beforeEach(function () {
@@ -10,7 +10,7 @@ describe('when parsing a timeline ', function () {
setLogLevel('trace');
});
describe('Timeline', function () {
it('TL-1 should handle a simple section definition abc-123', function () {
it('should handle a simple section definition abc-123', function () {
let str = `timeline
section abc-123`;
@@ -18,7 +18,7 @@ describe('when parsing a timeline ', function () {
expect(timelineDB.getSections()).to.deep.equal(['abc-123']);
});
it('TL-2 should handle a simple section and only two tasks', function () {
it('should handle a simple section and only two tasks', function () {
let str = `timeline
section abc-123
task1
@@ -30,7 +30,7 @@ describe('when parsing a timeline ', function () {
});
});
it('TL-3 should handle a two section and two coressponding tasks', function () {
it('should handle a two section and two coressponding tasks', function () {
let str = `timeline
section abc-123
task1
@@ -51,7 +51,7 @@ describe('when parsing a timeline ', function () {
});
});
it('TL-4 should handle a section, and task and its events', function () {
it('should handle a section, and task and its events', function () {
let str = `timeline
section abc-123
task1: event1
@@ -75,7 +75,7 @@ describe('when parsing a timeline ', function () {
});
});
it('TL-5 should handle a section, and task and its multi line events', function () {
it('should handle a section, and task and its multi line events', function () {
let str = `timeline
section abc-123
task1: event1
@@ -100,7 +100,25 @@ describe('when parsing a timeline ', function () {
});
});
it('TL-6 should handle a title, section, task, and events with hashtags', function () {
it('should handle a title, section, task, and events with semicolons', function () {
let str = `timeline
title ;my;title;
section ;a;bc-123;
;ta;sk1;: ;ev;ent1; : ;ev;ent2; : ;ev;ent3;
`;
timeline.parse(str);
expect(commonDb.getDiagramTitle()).equal(';my;title;');
expect(timelineDB.getSections()).to.deep.equal([';a;bc-123;']);
expect(timelineDB.getTasks()[0].events).toMatchInlineSnapshot(`
[
";ev;ent1; ",
";ev;ent2; ",
";ev;ent3;",
]
`);
});
it('should handle a title, section, task, and events with hashtags', function () {
let str = `timeline
title #my#title#
section #a#bc-123#
@@ -110,9 +128,13 @@ describe('when parsing a timeline ', function () {
expect(commonDb.getDiagramTitle()).equal('#my#title#');
expect(timelineDB.getSections()).to.deep.equal(['#a#bc-123#']);
expect(timelineDB.getTasks()[0].task).equal('task1');
expect(timelineDB.getTasks()[0].events[0]).equal('#ev#ent1# ');
expect(timelineDB.getTasks()[0].events[1]).equal('#ev#ent2# ');
expect(timelineDB.getTasks()[0].events[2]).equal('#ev#ent3#');
expect(timelineDB.getTasks()[0].events).toMatchInlineSnapshot(`
[
"#ev#ent1# ",
"#ev#ent2# ",
"#ev#ent3#",
]
`);
});
});
});

View File

@@ -1,4 +1,4 @@
import type { Group } from '../../../../../diagram-api/types.js';
import type { SVGGroup } from '../../../../../diagram-api/types.js';
import type {
AxisDataType,
ChartComponent,
@@ -25,7 +25,7 @@ export function getAxis(
data: AxisDataType,
axisConfig: XYChartAxisConfig,
axisThemeConfig: XYChartAxisThemeConfig,
tmpSVGGroup: Group
tmpSVGGroup: SVGGroup
): Axis {
const textDimensionCalculator = new TextDimensionCalculatorWithFont(tmpSVGGroup);
if (isBandAxisData(data)) {

View File

@@ -1,13 +1,13 @@
import type { Group } from '../../../../diagram-api/types.js';
import type { SVGGroup } from '../../../../diagram-api/types.js';
import type {
BoundingRect,
ChartComponent,
Dimension,
DrawableElem,
Point,
XYChartConfig,
XYChartData,
XYChartThemeConfig,
XYChartConfig,
} from '../interfaces.js';
import type { TextDimensionCalculator } from '../textDimensionCalculator.js';
import { TextDimensionCalculatorWithFont } from '../textDimensionCalculator.js';
@@ -84,7 +84,7 @@ export function getChartTitleComponent(
chartConfig: XYChartConfig,
chartData: XYChartData,
chartThemeConfig: XYChartThemeConfig,
tmpSVGGroup: Group
tmpSVGGroup: SVGGroup
): ChartComponent {
const textDimensionCalculator = new TextDimensionCalculatorWithFont(tmpSVGGroup);
return new ChartTitle(textDimensionCalculator, chartConfig, chartData, chartThemeConfig);

View File

@@ -1,4 +1,4 @@
import type { Group } from '../../../diagram-api/types.js';
import type { SVGGroup } from '../../../diagram-api/types.js';
import type { DrawableElem, XYChartConfig, XYChartData, XYChartThemeConfig } from './interfaces.js';
import { Orchestrator } from './orchestrator.js';
@@ -7,7 +7,7 @@ export class XYChartBuilder {
config: XYChartConfig,
chartData: XYChartData,
chartThemeConfig: XYChartThemeConfig,
tmpSVGGroup: Group
tmpSVGGroup: SVGGroup
): DrawableElem[] {
const orchestrator = new Orchestrator(config, chartData, chartThemeConfig, tmpSVGGroup);
return orchestrator.getDrawableElement();

View File

@@ -1,3 +1,9 @@
import type { SVGGroup } from '../../../diagram-api/types.js';
import type { Axis } from './components/axis/index.js';
import { getAxis } from './components/axis/index.js';
import { getChartTitleComponent } from './components/chartTitle.js';
import type { Plot } from './components/plot/index.js';
import { getPlotComponent } from './components/plot/index.js';
import type {
ChartComponent,
DrawableElem,
@@ -6,12 +12,6 @@ import type {
XYChartThemeConfig,
} from './interfaces.js';
import { isBarPlot } from './interfaces.js';
import type { Axis } from './components/axis/index.js';
import { getAxis } from './components/axis/index.js';
import { getChartTitleComponent } from './components/chartTitle.js';
import type { Plot } from './components/plot/index.js';
import { getPlotComponent } from './components/plot/index.js';
import type { Group } from '../../../diagram-api/types.js';
export class Orchestrator {
private componentStore: {
@@ -24,7 +24,7 @@ export class Orchestrator {
private chartConfig: XYChartConfig,
private chartData: XYChartData,
chartThemeConfig: XYChartThemeConfig,
tmpSVGGroup: Group
tmpSVGGroup: SVGGroup
) {
this.componentStore = {
title: getChartTitleComponent(chartConfig, chartData, chartThemeConfig, tmpSVGGroup),

View File

@@ -1,13 +1,13 @@
import type { Dimension } from './interfaces.js';
import type { SVGGroup } from '../../../diagram-api/types.js';
import { computeDimensionOfText } from '../../../rendering-util/createText.js';
import type { Group } from '../../../diagram-api/types.js';
import type { Dimension } from './interfaces.js';
export interface TextDimensionCalculator {
getMaxDimension(texts: string[], fontSize: number): Dimension;
}
export class TextDimensionCalculatorWithFont implements TextDimensionCalculator {
constructor(private parentGroup: Group) {}
constructor(private parentGroup: SVGGroup) {}
getMaxDimension(texts: string[], fontSize: number): Dimension {
if (!this.parentGroup) {
return {

View File

@@ -1,3 +1,9 @@
import * as configApi from '../../config.js';
import defaultConfig from '../../defaultConfig.js';
import type { SVGGroup } from '../../diagram-api/types.js';
import { getThemeVariables } from '../../themes/theme-default.js';
import { cleanAndMerge } from '../../utils.js';
import { sanitizeText } from '../common/common.js';
import {
clear as commonClear,
getAccDescription,
@@ -7,11 +13,6 @@ import {
setAccTitle,
setDiagramTitle,
} from '../common/commonDb.js';
import * as configApi from '../../config.js';
import defaultConfig from '../../defaultConfig.js';
import { getThemeVariables } from '../../themes/theme-default.js';
import { cleanAndMerge } from '../../utils.js';
import { sanitizeText } from '../common/common.js';
import { XYChartBuilder } from './chartBuilder/index.js';
import type {
DrawableElem,
@@ -21,11 +22,10 @@ import type {
XYChartThemeConfig,
} from './chartBuilder/interfaces.js';
import { isBandAxisData, isLinearAxisData } from './chartBuilder/interfaces.js';
import type { Group } from '../../diagram-api/types.js';
let plotIndex = 0;
let tmpSVGGroup: Group;
let tmpSVGGroup: SVGGroup;
let xyChartConfig: XYChartConfig = getChartDefaultConfig();
let xyChartThemeConfig: XYChartThemeConfig = getChartDefaultThemeConfig();
@@ -75,7 +75,7 @@ function textSanitizer(text: string) {
return sanitizeText(text.trim(), config);
}
function setTmpSVGG(SVGG: Group) {
function setTmpSVGG(SVGG: SVGGroup) {
tmpSVGGroup = SVGG;
}
function setOrientation(orientation: string) {

View File

@@ -0,0 +1,14 @@
<template>
<div class="-mt-6 mb-8">
<a
href="https://www.producthunt.com/posts/mermaid-ai-2?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-mermaid&#0045;ai&#0045;2"
target="_blank"
><img
src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=465568&theme=light"
alt="Mermaid&#0032;AI - Maximize&#0032;your&#0032;diagramming&#0032;efficiency&#0032;with&#0032;Mermaid&#0032;AI | Product Hunt"
style="width: 250px; height: 54px"
width="250"
height="54"
/></a>
</div>
</template>

View File

@@ -1,26 +1,65 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
interface Taglines {
label: string;
url: string;
}
const taglines: Taglines[] = [
{
label: 'Use the Visual Editor in Mermaid Chart to design and build diagrams',
url: 'https://www.mermaidchart.com/play?utm_source=mermaid_live_editor&utm_medium=banner_ad&utm_campaign=visual_editor',
},
{
label: 'Diagram live with teammates in Mermaid Chart',
url: 'https://www.mermaidchart.com/play?utm_source=mermaid_live_editor&utm_medium=banner_ad&utm_campaign=teams',
},
{
label: 'Skip the rough draft with Mermaid AI in Mermaid Chart',
url: 'https://www.mermaidchart.com/play?utm_source=mermaid_live_editor&utm_medium=banner_ad&utm_campaign=mermaid_ai',
},
];
let index = ref(Math.floor(Math.random() * taglines.length));
onMounted(() => {
setInterval(() => {
index.value = (index.value + 1) % taglines.length;
}, 60_000);
});
</script>
<template>
<div
class="w-full top-bar bg-gradient-to-r from-[#bd34fe] to-[#ff3670] flex items-center text-center justify-center p-1 text-white"
>
<p class="flex-grow text-center tracking-wide text-text">
<a
href="https://www.mermaidchart.com/landing"
target="_blank"
class="unstyled flex-grow tracking-wide plausible-event-name=bannerClick"
>
<span class="text-primary-50 font-semibold">{{
[
'Try diagramming with ChatGPT at Mermaid Chart',
'Try Mermaids Visual Editor at Mermaid Chart',
'Enjoy live collaboration with teammates at Mermaid Chart',
][Math.floor(Math.random() * 3)]
}}</span>
<button
class="ml-4 rounded bg-[#111113] p-1 px-2 text-sm font-semibold tracking-wide text-white"
<div class="mb-4 w-full top-bar bg-gradient-to-r from-[#bd34fe] to-[#ff3670] flex p-1">
<p class="w-full tracking-wide fade-text">
<transition name="fade" mode="out-in">
<a
:key="index"
:href="taglines[index].url"
target="_blank"
class="unstyled flex justify-center items-center gap-4 text-white tracking-wide plausible-event-name=bannerClick"
>
Try it now
</button>
</a>
<span class="font-semibold">{{ taglines[index].label }}</span>
<button class="rounded bg-[#111113] p-1 px-2 text-sm font-semibold tracking-wide">
Try it now
</button>
</a>
</transition>
</p>
</div>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 1s;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.fade-enter-to,
.fade-leave-from {
opacity: 1;
}
</style>

View File

@@ -11,11 +11,11 @@ import HomePage from '../components/HomePage.vue';
import TopBar from '../components/TopBar.vue';
import { getRedirect } from './redirect.js';
// @ts-ignore Type not available
import { h } from 'vue';
import Theme from 'vitepress/theme';
import '../style/main.css';
import 'uno.css';
import type { EnhanceAppContext } from 'vitepress';
import Theme from 'vitepress/theme';
import { h } from 'vue';
import '../style/main.css';
export default {
...DefaultTheme,
@@ -24,6 +24,7 @@ export default {
// Keeping this as comment as it took a lot of time to figure out how to add a component to the top bar.
'home-hero-before': () => h(TopBar),
'home-features-after': () => h(HomePage),
'doc-before': () => h(TopBar),
});
},
enhanceApp({ app, router }: EnhanceAppContext) {

View File

@@ -54,6 +54,7 @@ To add an integration to this list, see the [Integrations - create page](./integ
- [MonsterWriter](https://www.monsterwriter.com/) ✅
- [Joplin](https://joplinapp.org) ✅
- [LiveBook](https://livebook.dev) ✅
- [Slidev](https://sli.dev) ✅
- [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) ✅
- [Mermaid Flow Visual Editor](https://www.mermaidflow.app) ✅
- [Mermerd](https://github.com/KarnerTh/mermerd)
@@ -129,7 +130,7 @@ Communication tools and platforms
### Wikis
- [DokuWiki](https://dokuwiki.org)
- [ComboStrap](https://combostrap.com/mermaid)
- [ComboStrap](https://combostrap.com/utility/create-diagram-with-mermaid-vh3ab9yj)
- [Mermaid Plugin](https://www.dokuwiki.org/plugin:mermaid)
- [Foswiki](https://foswiki.org)
- [Mermaid Plugin](https://foswiki.org/Extensions/MermaidPlugin)

View File

@@ -6,7 +6,7 @@ Try the Ultimate AI, Mermaid, and Visual Diagramming Suite by creating an accoun
<br />
<a href="https://www.producthunt.com/posts/mermaid-chart?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-mermaid&#0045;chart" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=416671&theme=light" alt="Mermaid&#0032;Chart - A&#0032;smarter&#0032;way&#0032;to&#0032;create&#0032;diagrams | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<a href="https://www.producthunt.com/products/mermaid-chart?utm_source=badge-follow&utm_medium=badge&utm_souce=badge-mermaid&#0045;chart" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/follow.svg?product_id=552855&theme=light" alt="Mermaid&#0032;Chart - A&#0032;smarter&#0032;way&#0032;to&#0032;create&#0032;diagrams | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
## About

View File

@@ -65,3 +65,110 @@ Allows for the limited reconfiguration of a diagram just before it is rendered.
### [Theme Manipulation](../config/theming.md)
An application of using Directives to change [Themes](../config/theming.md). `Theme` is a value within Mermaid's configuration that dictates the color scheme for diagrams.
### Layout and look
We've restructured how Mermaid renders diagrams, enabling new features like selecting layout and look. **Currently, this is supported for flowcharts and state diagrams**, with plans to extend support to all diagram types.
### Selecting Diagram Looks
Mermaid offers a variety of styles or “looks” for your diagrams, allowing you to tailor the visual appearance to match your specific needs or preferences. Whether you prefer a hand-drawn or classic style, you can easily customize your diagrams.
**Available Looks:**
• Hand-Drawn Look: For a more personal, creative touch, the hand-drawn look brings a sketch-like quality to your diagrams. This style is perfect for informal settings or when you want to add a bit of personality to your diagrams.
• Classic Look: If you prefer the traditional Mermaid style, the classic look maintains the original appearance that many users are familiar with. Its great for consistency across projects or when you want to keep the familiar aesthetic.
**How to Select a Look:**
You can select a look by adding the look parameter in the metadata section of your Mermaid diagram code. Heres an example:
```mermaid
---
config:
look: handDrawn
theme: neutral
---
flowchart LR
A[Start] --> B{Decision}
B -->|Yes| C[Continue]
B -->|No| D[Stop]
```
#### Selecting Layout Algorithms
In addition to customizing the look of your diagrams, Mermaid Chart now allows you to choose different layout algorithms to better organize and present your diagrams, especially when dealing with more complex structures. The layout algorithm dictates how nodes and edges are arranged on the page.
#### Supported Layout Algorithms:
• Dagre (default): This is the classic layout algorithm that has been used in Mermaid for a long time. It provides a good balance of simplicity and visual clarity, making it ideal for most diagrams.
• ELK: For those who need more sophisticated layout capabilities, especially when working with large or intricate diagrams, the ELK (Eclipse Layout Kernel) layout offers advanced options. It provides a more optimized arrangement, potentially reducing overlapping and improving readability. This is not included out the box but needs to be added when integrating mermaid for sites/applications that want to have elk support.
#### How to Select a Layout Algorithm:
You can specify the layout algorithm directly in the metadata section of your Mermaid diagram code. Heres an example:
```mermaid
---
config:
layout: elk
look: handDrawn
theme: dark
---
flowchart TB
A[Start] --> B{Decision}
B -->|Yes| C[Continue]
B -->|No| D[Stop]
```
In this example, the `layout: elk` line configures the diagram to use the ELK layout algorithm, along with the hand drawn look and forest theme.
#### Customizing ELK Layout:
When using the ELK layout, you can further refine the diagrams configuration, such as how nodes are placed and whether parallel edges should be combined:
- To combine parallel edges, use mergeEdges: true | false.
- To configure node placement, use nodePlacementStrategy with the following options:
- SIMPLE
- NETWORK_SIMPLEX
- LINEAR_SEGMENTS
- BRANDES_KOEPF (default)
**Example configuration:**
```
---
config:
layout: elk
elk:
mergeEdges: true
nodePlacementStrategy: LINEAR_SEGMENTS
---
flowchart LR
A[Start] --> B{Choose Path}
B -->|Option 1| C[Path 1]
B -->|Option 2| D[Path 2]
#### Using Dagre Layout with Classic Look:
```
Another example:
```
---
config:
layout: dagre
look: classic
theme: default
---
flowchart LR
A[Start] --> B{Choose Path}
B -->|Option 1| C[Path 1]
B -->|Option 2| D[Path 2]
```
These options give you the flexibility to create diagrams that not only look great but are also arranged to best suit your datas structure and flow.
When integrating Mermaid, you can include look and layout configuration with the initialize call. This is also where you add the loading of elk.

View File

@@ -1,5 +1,47 @@
# Blog
## [Mermaid v11 is out!](https://www.mermaidchart.com/blog/posts/mermaid-v11/)
23 August 2024 · 2 mins
Mermaid v11 introduces advanced layout options, new diagram types, and enhanced customization features, thanks to the incredible contributions from our community.
## [Mermaid Innovation - Introducing New Looks for Mermaid Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-innovation-introducing-new-looks-for-mermaid-diagrams/)
6 August 2024 ·3 mins
Discover the fresh new and unique Neo and Hand-Drawn looks for Mermaid Diagrams, while still offering the classic look you love.
## [The Mermaid Chart Plugin for Jira: A How-To User Guide](https://www.mermaidchart.com/blog/posts/the-mermaid-chart-plugin-for-jira-a-how-to-user-guide/)
31 July 2024 · 5 mins
The Mermaid Chart plugin for Jira has arrived!
## [Mermaid AI Is Here to Change the Game For Diagram Creation](https://www.mermaidchart.com/blog/posts/mermaid-ai-is-here-to-change-the-game-for-diagram-creation/)
22 July 2024 · 5 mins
The Mermaid AI chat interface
## [How to Make a Sequence Diagram with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-sequence-diagram-in-mermaid-chart-step-by-step-guide/)
8 July 2024 · 6 mins
Sequence diagrams are important for communicating complex systems in a clear and concise manner.
## [How to Use the New “Comments” Feature in Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-use-the-new-comments-feature-in-mermaid-chart/)
2 July 2024 · 3 mins
How to Use the New Comments Feature in Mermaid Chart
## [How to Use the official Mermaid Chart for Confluence app](https://www.mermaidchart.com/blog/posts/how-to-use-the-official-mermaid-chart-for-confluence-app/)
21 May 2024 · 4 mins
It doesnt matter if youre a data enthusiast, software engineer, or visual storyteller; our Confluence app can allow you to embed Mermaid Chart diagrams — and dynamically edit them — within your Confluence pages.
## [How to Choose the Right Documentation Software](https://www.mermaidchart.com/blog/posts/how-to-choose-the-right-documentation-software/)
7 May 2024 · 5 mins

View File

@@ -1,6 +1,7 @@
{
"name": "docs",
"name": "@mermaid-js/docs",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vitepress --port 3333 --open",

View File

@@ -114,7 +114,7 @@ The `title` is an _optional_ string to be displayed at the top of the Gantt char
The `excludes` is an _optional_ attribute that accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays".
These date will be marked on the graph, and be excluded from the duration calculation of tasks. Meaning that if there are excluded dates during a task interval, the number of 'skipped' days will be added to the end of the task to ensure the duration is as specified in the code.
#### Weekend (v\<MERMAID_RELEASE_VERSION>+)
#### Weekend (v\11.0.0+)
When excluding weekends, it is possible to configure the weekends to be either Friday and Saturday or Saturday and Sunday. By default weekends are Saturday and Sunday.
To define the weekend start day, there is an _optional_ attribute `weekend` that can be added in a new line followed by either `friday` or `saturday`.

View File

@@ -571,7 +571,7 @@ Usage example:
commit
```
### Bottom to Top (`BT:`) (v<MERMAID_RELEASE_VERSION>+)
### Bottom to Top (`BT:`) (v11.0.0+)
In `BT` (**Bottom-to-Top**) orientation, the commits run from bottom to top of the graph and branches are arranged side-by-side.

View File

@@ -1,4 +1,4 @@
# Packet Diagram (v<MERMAID_RELEASE_VERSION>+)
# Packet Diagram (v11.0.0+)
## Introduction

View File

@@ -143,18 +143,18 @@ Messages can be of two displayed either solid or with a dotted line.
There are ten types of arrows currently supported:
| Type | Description |
| -------- | ----------------------------------------------------------------------- |
| `->` | Solid line without arrow |
| `-->` | Dotted line without arrow |
| `->>` | Solid line with arrowhead |
| `-->>` | Dotted line with arrowhead |
| `<<->>` | Solid line with bidirectional arrowheads (v<MERMAID_RELEASE_VERSION>+) |
| `<<-->>` | Dotted line with bidirectional arrowheads (v<MERMAID_RELEASE_VERSION>+) |
| `-x` | Solid line with a cross at the end |
| `--x` | Dotted line with a cross at the end. |
| `-)` | Solid line with an open arrow at the end (async) |
| `--)` | Dotted line with a open arrow at the end (async) |
| Type | Description |
| -------- | ---------------------------------------------------- |
| `->` | Solid line without arrow |
| `-->` | Dotted line without arrow |
| `->>` | Solid line with arrowhead |
| `-->>` | Dotted line with arrowhead |
| `<<->>` | Solid line with bidirectional arrowheads (v11.0.0+) |
| `<<-->>` | Dotted line with bidirectional arrowheads (v11.0.0+) |
| `-x` | Solid line with a cross at the end |
| `--x` | Dotted line with a cross at the end. |
| `-)` | Solid line with an open arrow at the end (async) |
| `--)` | Dotted line with a open arrow at the end (async) |
## Activations

View File

@@ -29,3 +29,5 @@ export const internalHelpers = {
log,
positionEdgeLabel,
};
export type InternalHelpers = typeof internalHelpers;

View File

@@ -4,34 +4,37 @@
*/
import { dedent } from 'ts-dedent';
import type { MermaidConfig } from './config.type.js';
import { log } from './logger.js';
import utils from './utils.js';
import type { ParseOptions, ParseResult, RenderResult } from './types.js';
import { mermaidAPI } from './mermaidAPI.js';
import { registerLazyLoadedDiagrams, detectType } from './diagram-api/detectType.js';
import { loadRegisteredDiagrams } from './diagram-api/loadDiagram.js';
import type { ParseErrorFunction } from './Diagram.js';
import { isDetailedError } from './utils.js';
import type { DetailedError } from './utils.js';
import type { ExternalDiagramDefinition } from './diagram-api/types.js';
import type { UnknownDiagramError } from './errors.js';
import { detectType, registerLazyLoadedDiagrams } from './diagram-api/detectType.js';
import { addDiagrams } from './diagram-api/diagram-orchestration.js';
import { loadRegisteredDiagrams } from './diagram-api/loadDiagram.js';
import type { ExternalDiagramDefinition, SVG, SVGGroup } from './diagram-api/types.js';
import type { ParseErrorFunction } from './Diagram.js';
import type { UnknownDiagramError } from './errors.js';
import type { InternalHelpers } from './internals.js';
import { log } from './logger.js';
import { mermaidAPI } from './mermaidAPI.js';
import type { LayoutLoaderDefinition, RenderOptions } from './rendering-util/render.js';
import { registerLayoutLoaders } from './rendering-util/render.js';
import type { LayoutLoaderDefinition } from './rendering-util/render.js';
import { internalHelpers } from './internals.js';
import type { LayoutData } from './rendering-util/types.js';
import type { ParseOptions, ParseResult, RenderResult } from './types.js';
import type { DetailedError } from './utils.js';
import utils, { isDetailedError } from './utils.js';
export type {
MermaidConfig,
DetailedError,
ExternalDiagramDefinition,
InternalHelpers,
LayoutData,
LayoutLoaderDefinition,
MermaidConfig,
ParseErrorFunction,
RenderResult,
ParseOptions,
ParseResult,
RenderOptions,
RenderResult,
SVG,
SVGGroup,
UnknownDiagramError,
LayoutLoaderDefinition,
LayoutData,
};
export interface RunOptions {
@@ -432,11 +435,6 @@ export interface Mermaid {
contentLoaded: typeof contentLoaded;
setParseErrorHandler: typeof setParseErrorHandler;
detectType: typeof detectType;
/**
* Internal helpers for mermaid
* @deprecated - This should not be used by external packages, as the definitions will change without notice.
*/
internalHelpers: typeof internalHelpers;
}
const mermaid: Mermaid = {
@@ -453,7 +451,6 @@ const mermaid: Mermaid = {
contentLoaded,
setParseErrorHandler,
detectType,
internalHelpers,
};
export default mermaid;

View File

@@ -25,6 +25,7 @@ import { preprocessDiagram } from './preprocess.js';
import { decodeEntities } from './utils.js';
import { toBase64 } from './utils/base64.js';
import type { D3Element, ParseOptions, ParseResult, RenderResult } from './types.js';
import assignWithDepth from './assignWithDepth.js';
const MAX_TEXTLENGTH = 50_000;
const MAX_TEXTLENGTH_EXCEEDED_MSG =
@@ -473,9 +474,10 @@ const render = async function (
};
/**
* @param options - Initial Mermaid options
* @param userOptions - Initial Mermaid options
*/
function initialize(options: MermaidConfig = {}) {
function initialize(userOptions: MermaidConfig = {}) {
const options = assignWithDepth({}, userOptions);
// Handle legacy location of font-family configuration
if (options?.fontFamily && !options.themeVariables?.fontFamily) {
if (!options.themeVariables) {

View File

@@ -1,16 +1,16 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
// @ts-nocheck TODO: Fix types
import type { MermaidConfig } from '../config.type.js';
import type { Group } from '../diagram-api/types.js';
import { getConfig } from '$root/diagram-api/diagramAPI.js';
import common, { hasKatex, renderKatex } from '$root/diagrams/common/common.js';
import { select } from 'd3';
import type { MermaidConfig } from '../config.type.js';
import type { SVGGroup } from '../diagram-api/types.js';
import type { D3TSpanElement, D3TextElement } from '../diagrams/common/commonTypes.js';
import { log } from '../logger.js';
import { markdownToHTML, markdownToLines } from '../rendering-util/handle-markdown-text.js';
import { decodeEntities } from '../utils.js';
import { splitLineToFitWidth } from './splitText.js';
import type { MarkdownLine, MarkdownWord } from './types.js';
import common, { hasKatex, renderKatex } from '$root/diagrams/common/common.js';
import { getConfig } from '$root/diagram-api/diagramAPI.js';
function applyStyle(dom, styleFn) {
if (styleFn) {
@@ -36,6 +36,7 @@ async function addHtmlSpan(element, node, width, classes, addBackground = false)
div.style('white-space', 'nowrap');
div.style('line-height', '1.5');
div.style('max-width', width + 'px');
div.style('text-align', 'center');
div.attr('xmlns', 'http://www.w3.org/1999/xhtml');
if (addBackground) {
div.attr('class', 'labelBkg');
@@ -82,7 +83,7 @@ function computeWidthOfText(parentNode: any, lineHeight: number, line: MarkdownL
}
export function computeDimensionOfText(
parentNode: Group,
parentNode: SVGGroup,
lineHeight: number,
text: string
): DOMRect | undefined {

View File

@@ -1,7 +1,7 @@
import { select } from 'd3';
import { insertNode } from '../dagre-wrapper/nodes.js';
export const getDiagramElements = (id, securityLevel) => {
export const getDiagramElement = (id, securityLevel) => {
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
@@ -15,9 +15,7 @@ export const getDiagramElements = (id, securityLevel) => {
// Run the renderer. This is what draws the final graph.
// @ts-ignore todo: fix this
const element = root.select('#' + id + ' g');
return { svg, element };
return svg;
};
export function insertElementsForSize(el, data) {

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