Merge branch 'develop' into refactor/unifyEdgeMarkers

This commit is contained in:
Sidharth Vinod 2023-11-16 11:00:33 +05:30 committed by GitHub
commit a47a9e400b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 805 additions and 137 deletions

View File

@ -1,4 +1,22 @@
'Type: Bug / Error': ['bug/*', fix/*] # yaml-language-server: $schema=https://raw.githubusercontent.com/release-drafter/release-drafter/master/schema.json
'Type: Enhancement': ['feature/*', 'feat/*'] autolabeler:
'Type: Other': ['other/*', 'chore/*', 'test/*', 'refactor/*'] - label: 'Type: Bug / Error'
'Area: Documentation': ['docs/*'] branch:
- '/bug\/.+/'
- '/fix\/.+/'
- label: 'Type: Enhancement'
branch:
- '/feature\/.+/'
- '/feat\/.+/'
- label: 'Type: Other'
branch:
- '/other\/.+/'
- '/chore\/.+/'
- '/test\/.+/'
- '/refactor\/.+/'
- label: 'Area: Documentation'
branch:
- '/docs\/.+/'
template: |
This field is unused, as we only use this config file for labeling PRs.

View File

@ -25,8 +25,6 @@ categories:
change-template: '- $TITLE (#$NUMBER) @$AUTHOR' change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
sort-by: title sort-by: title
sort-direction: ascending sort-direction: ascending
branches:
- develop
exclude-labels: exclude-labels:
- 'Skip changelog' - 'Skip changelog'
no-changes-template: 'This release contains minor changes and bugfixes.' no-changes-template: 'This release contains minor changes and bugfixes.'

View File

@ -16,12 +16,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18 node-version: 18

View File

@ -19,13 +19,13 @@ jobs:
matrix: matrix:
node-version: [18.x] node-version: [18.x]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}

View File

@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Check for difference in README.md and docs/README.md - name: Check for difference in README.md and docs/README.md
run: | run: |

View File

@ -15,7 +15,7 @@ jobs:
name: check tests name: check tests
if: github.repository_owner == 'mermaid-js' if: github.repository_owner == 'mermaid-js'
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: testomatio/check-tests@stable - uses: testomatio/check-tests@stable

View File

@ -29,7 +29,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL

View File

@ -1,6 +1,6 @@
# Dependency Review Action # Dependency Review Action
# #
# This Action will scan dependency manifest files that change as part of a Pull Reqest, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. # This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging.
# #
# Source repository: https://github.com/actions/dependency-review-action # Source repository: https://github.com/actions/dependency-review-action
# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
@ -15,6 +15,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 'Checkout Repository' - name: 'Checkout Repository'
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: 'Dependency Review' - name: 'Dependency Review'
uses: actions/dependency-review-action@v3 uses: actions/dependency-review-action@v3

View File

@ -30,13 +30,13 @@ jobs:
run: | run: |
echo "::error,title=Not using Applitols::APPLITOOLS_API_KEY is empty, disabling Applitools for this run." echo "::error,title=Not using Applitols::APPLITOOLS_API_KEY is empty, disabling Applitools for this run."
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}

View File

@ -17,13 +17,13 @@ jobs:
node-version: [18.x] node-version: [18.x]
containers: [1, 2, 3, 4] containers: [1, 2, 3, 4]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}

View File

@ -26,7 +26,7 @@ jobs:
# lychee only uses the GITHUB_TOKEN to avoid rate-limiting # lychee only uses the GITHUB_TOKEN to avoid rate-limiting
contents: read contents: read
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Restore lychee cache - name: Restore lychee cache
uses: actions/cache@v3 uses: actions/cache@v3

View File

@ -20,13 +20,13 @@ jobs:
matrix: matrix:
node-version: [18.x] node-version: [18.x]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}

View File

@ -1,23 +0,0 @@
name: Validate PR Labeler Configuration
on:
push:
paths:
- .github/workflows/pr-labeler-config-validator.yml
- .github/workflows/pr-labeler.yml
- .github/pr-labeler.yml
pull_request:
paths:
- .github/workflows/pr-labeler-config-validator.yml
- .github/workflows/pr-labeler.yml
- .github/pr-labeler.yml
jobs:
pr-labeler:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Validate Configuration
uses: Yash-Singh1/pr-labeler-config-validator@releases/v0.0.3
with:
configuration-path: .github/pr-labeler.yml

View File

@ -1,13 +1,31 @@
name: Apply labels to PR name: Apply labels to PR
on: on:
pull_request_target: pull_request_target:
types: [opened] # required for pr-labeler to support PRs from forks
# ===================== ⛔ ☢️ 🚫 ⚠️ Warning ⚠️ 🚫 ☢️ ⛔ =======================
# Be very careful what you put in this GitHub Action workflow file to avoid
# malicious PRs from getting access to the Mermaid-js repo.
#
# Please read the following first before reviewing/merging:
# - https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
# - https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
types: [opened, reopened, synchronize]
permissions:
contents: read
jobs: jobs:
pr-labeler: pr-labeler:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read # read permission is required to read config file
pull-requests: write # write permission is required to label PRs
steps: steps:
- name: Label PR - name: Label PR
uses: TimonVS/pr-labeler-action@v4 uses: release-drafter/release-drafter@v5
with:
config-name: pr-labeler.yml
disable-autolabeler: false
disable-releaser: true
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -23,12 +23,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18 node-version: 18

View File

@ -5,11 +5,19 @@ on:
branches: branches:
- develop - develop
permissions:
contents: read
jobs: jobs:
draft-release: draft-release:
runs-on: ubuntu-latest 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: steps:
- name: Draft Release - name: Draft Release
uses: toolmantim/release-drafter@v5 uses: release-drafter/release-drafter@v5
with:
disable-autolabeler: true
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -9,14 +9,14 @@ jobs:
publish-preview: publish-preview:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18.x node-version: 18.x

View File

@ -8,14 +8,14 @@ jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: fregante/setup-git-user@v2 - uses: fregante/setup-git-user@v2
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js v18 - name: Setup Node.js v18
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18.x node-version: 18.x

View File

@ -12,13 +12,13 @@ jobs:
matrix: matrix:
node-version: [18.x] node-version: [18.x]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}

View File

@ -8,7 +8,7 @@ jobs:
update-browser-list: update-browser-list:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- run: npx browserslist@latest --update-db - run: npx browserslist@latest --update-db
- name: Commit changes - name: Commit changes
uses: EndBug/add-and-commit@v9 uses: EndBug/add-and-commit@v9

View File

@ -44,6 +44,22 @@ Try Live Editor previews of future releases: <a href="https://develop.git.mermai
<a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a> <a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
## Table of content
<details>
<summary>Expand contents</summary>
- [About](#about)
- [Examples](#examples)
- [Release](#release)
- [Related projects](#related-projects)
- [Contributors](#contributors)
- [Security and safe diagrams](#security-and-safe-diagrams)
- [Reporting vulnerabilities](#reporting-vulnerabilities)
- [Appreciation](#appreciation)
</details>
## About ## About
<!-- <Main description> --> <!-- <Main description> -->

View File

@ -501,4 +501,16 @@ describe('Class diagram', () => {
B : -methods() B : -methods()
`); `);
}); });
it('should handle notes with anchor tag having target attribute', () => {
renderGraph(
`classDiagram
class test { }
note for test "<a href='https://mermaid.js.org/' target="_blank"><code>note about mermaid</code></a>"`
);
cy.get('svg').then((svg) => {
cy.get('a').should('have.attr', 'target', '_blank').should('have.attr', 'rel', 'noopener');
});
});
}); });

View File

@ -701,4 +701,114 @@ gitGraph TB:
{} {}
); );
}); });
it('34: should render a simple gitgraph with two branches from same commit', () => {
imgSnapshotTest(
`gitGraph
commit id:"1-abcdefg"
commit id:"2-abcdefg"
branch feature-001
commit id:"3-abcdefg"
commit id:"4-abcdefg"
checkout main
branch feature-002
commit id:"5-abcdefg"
checkout feature-001
merge feature-002
`,
{}
);
});
it('35: should render a simple gitgraph with two branches from same commit | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id:"1-abcdefg"
commit id:"2-abcdefg"
branch feature-001
commit id:"3-abcdefg"
commit id:"4-abcdefg"
checkout main
branch feature-002
commit id:"5-abcdefg"
checkout feature-001
merge feature-002
`,
{}
);
});
it('36: should render GitGraph with branch that is not used immediately', () => {
imgSnapshotTest(
`gitGraph LR:
commit id:"1-abcdefg"
branch x
checkout main
commit id:"2-abcdefg"
checkout x
commit id:"3-abcdefg"
checkout main
merge x
`,
{}
);
});
it('37: should render GitGraph with branch that is not used immediately | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id:"1-abcdefg"
branch x
checkout main
commit id:"2-abcdefg"
checkout x
commit id:"3-abcdefg"
checkout main
merge x
`,
{}
);
});
it('38: should render GitGraph with branch and sub-branch neither of which used immediately', () => {
imgSnapshotTest(
`gitGraph LR:
commit id:"1-abcdefg"
branch x
checkout main
commit id:"2-abcdefg"
checkout x
commit id:"3-abcdefg"
checkout main
merge x
checkout x
branch y
checkout x
commit id:"4-abcdefg"
checkout y
commit id:"5-abcdefg"
checkout x
merge y
`,
{}
);
});
it('39: should render GitGraph with branch and sub-branch neither of which used immediately | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id:"1-abcdefg"
branch x
checkout main
commit id:"2-abcdefg"
checkout x
commit id:"3-abcdefg"
checkout main
merge x
checkout x
branch y
checkout x
commit id:"4-abcdefg"
checkout y
commit id:"5-abcdefg"
checkout x
merge y
`,
{}
);
});
}); });

View File

@ -14,30 +14,364 @@
</head> </head>
<body> <body>
<h1>Git diagram demo</h1> <h1>Git graph demo</h1>
<h2>Simple "branch and merge" graph</h2>
<pre class="mermaid"> <pre class="mermaid">
--- ---
title: Simple Git diagram title: Simple "branch and merge" (left-to-right)
--- ---
gitGraph: gitGraph LR:
options
{
"nodeSpacing": 50,
"nodeRadius": 5
}
end
branch master
commit commit
branch newbranch branch newbranch
checkout newbranch checkout newbranch
commit commit
checkout main
merge newbranch
</pre>
<pre class="mermaid">
---
title: Simple "branch and merge" (top-to-bottom)
---
gitGraph TB:
commit commit
checkout master branch newbranch
checkout newbranch
commit commit
checkout main
merge newbranch
</pre>
<h2>Continuous development graph</h2>
<pre class="mermaid">
---
title: Continuous development (left-to-right)
---
gitGraph LR:
commit
branch develop
checkout develop
commit
checkout main
merge develop
checkout develop
commit
checkout main
merge develop
</pre>
<pre class="mermaid">
---
title: Continuous development (top-to-bottom)
---
gitGraph TB:
commit
branch develop
checkout develop
commit
checkout main
merge develop
checkout develop
commit
checkout main
merge develop
</pre>
<h2>Merge feature to advanced main graph</h2>
<pre class="mermaid">
---
title: Merge feature to advanced main (left-to-right)
---
gitGraph LR:
commit
branch newbranch
checkout newbranch
commit
checkout main
commit commit
merge newbranch merge newbranch
</pre> </pre>
<pre class="mermaid">
---
title: Merge feature to advanced main (top-to-bottom)
---
gitGraph TB:
commit
branch newbranch
checkout newbranch
commit
checkout main
commit
merge newbranch
</pre>
<h2>Two-way merges</h2>
<pre class="mermaid">
---
title: Two-way merges (left-to-right)
---
gitGraph LR:
commit
branch develop
checkout develop
commit
checkout main
merge develop
commit
checkout develop
merge main
commit
checkout main
merge develop
</pre>
<pre class="mermaid">
---
title: Two-way merges (top-to-bottom)
---
gitGraph TB:
commit
branch develop
checkout develop
commit
checkout main
merge develop
commit
checkout develop
merge main
commit
checkout main
merge develop
</pre>
<h2>Cherry-pick from branch graph</h2>
<pre class="mermaid">
---
title: Cherry-pick from branch (left-to-right)
---
gitGraph LR:
commit
branch newbranch
checkout newbranch
commit id: "Pick me"
checkout main
commit
checkout newbranch
commit
checkout main
cherry-pick id: "Pick me"
</pre>
<pre class="mermaid">
---
title: Cherry-pick from branch (top-to-bottom)
---
gitGraph TB:
commit
branch newbranch
checkout newbranch
commit id: "Pick me"
checkout main
commit
checkout newbranch
commit
checkout main
cherry-pick id: "Pick me"
</pre>
<h2>Cherry-pick from main graph</h2>
<pre class="mermaid">
---
title: Cherry-pick from main (left-to-right)
---
gitGraph LR:
commit
branch develop
commit
checkout main
commit id:"A"
checkout develop
commit
cherry-pick id: "A"
</pre>
<pre class="mermaid">
---
title: Cherry-pick from main (top-to-bottom)
---
gitGraph TB:
commit
branch develop
commit
checkout main
commit id:"A"
checkout develop
commit
cherry-pick id: "A"
</pre>
<h2>Cherry-pick then merge graph</h2>
<pre class="mermaid">
---
title: Cherry-pick then merge (left-to-right)
---
gitGraph LR:
commit
branch newbranch
checkout newbranch
commit id: "Pick me"
checkout main
commit
checkout newbranch
commit
checkout main
cherry-pick id: "Pick me"
merge newbranch
</pre>
<pre class="mermaid">
---
title: Cherry-pick then merge (top-to-bottom)
---
gitGraph TB:
commit
branch newbranch
checkout newbranch
commit id: "Pick me"
checkout main
commit
checkout newbranch
commit
checkout main
cherry-pick id: "Pick me"
merge newbranch
</pre>
<h2>Merge from main onto undeveloped branch graph</h2>
<pre class="mermaid">
---
title: Merge from main onto undeveloped branch (left-to-right)
---
gitGraph LR:
commit
branch develop
commit
checkout main
commit
checkout develop
merge main
</pre>
<pre class="mermaid">
---
title: Merge from main onto undeveloped branch (top-to-bottom)
---
gitGraph TB:
commit
branch develop
commit
checkout main
commit
checkout develop
merge main
</pre>
<h2>Merge from main onto developed branch graph</h2>
<pre class="mermaid">
---
title: Merge from main onto developed branch (left-to-right)
---
gitGraph LR:
commit
branch develop
commit
checkout main
commit
checkout develop
commit
merge main
</pre>
<pre class="mermaid">
---
title: Merge from main onto developed branch (top-to-bottom)
---
gitGraph TB:
commit
branch develop
commit
checkout main
commit
checkout develop
commit
merge main
</pre>
<h2>Two branches from same commit graph</h2>
<pre class="mermaid">
---
title: Two branches from same commit (left-to-right)
---
gitGraph LR:
commit
commit
branch feature-001
commit
commit
checkout main
branch feature-002
commit
checkout feature-001
merge feature-002
</pre>
<pre class="mermaid">
---
title: Two branches from same commit (top-to-bottom)
---
gitGraph TB:
commit
commit
branch feature-001
commit
commit
checkout main
branch feature-002
commit
checkout feature-001
merge feature-002
</pre>
<h2>Three branches and a cherry-pick from each graph</h2>
<pre class="mermaid">
---
title: Three branches and a cherry-pick from each (left-to-right)
---
gitGraph LR:
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
branch featureA
commit id:"FIX"
commit id: "FIX-2"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
cherry-pick id:"FIX"
checkout develop
commit id:"C"
merge featureA
</pre>
<pre class="mermaid">
---
title: Three branches and a cherry-pick from each (top-to-bottom)
---
gitGraph TB:
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
branch featureA
commit id:"FIX"
commit id: "FIX-2"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
cherry-pick id:"FIX"
checkout develop
commit id:"C"
merge featureA
</pre>
<script type="module"> <script type="module">
import mermaid from './mermaid.esm.mjs'; import mermaid from './mermaid.esm.mjs';
const ALLOWED_TAGS = [ const ALLOWED_TAGS = [

View File

@ -164,6 +164,13 @@
end end
</pre> </pre>
<pre class="mermaid">
sequenceDiagram
actor Alice
actor John
Alice-xJohn: Hello John, how are you?
John--xAlice: Great!
</pre>
<script type="module"> <script type="module">
import mermaid from './mermaid.esm.mjs'; import mermaid from './mermaid.esm.mjs';
mermaid.initialize({ mermaid.initialize({

View File

@ -10,9 +10,8 @@
## First search to see if someone has already asked (and hopefully been answered) or suggested the same thing. ## First search to see if someone has already asked (and hopefully been answered) or suggested the same thing.
- Search in Discussions - [Search in Discussions](https://github.com/orgs/mermaid-js/discussions)
- Search in open Issues - [Search in Issues (Open & Closed)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue)
- Search in closed Issues
If you find an open issue or discussion thread that is similar to your question but isn't answered, you can let us know that you are also interested in it. If you find an open issue or discussion thread that is similar to your question but isn't answered, you can let us know that you are also interested in it.
Use the GitHub reactions to add a thumbs-up to the issue or discussion thread. Use the GitHub reactions to add a thumbs-up to the issue or discussion thread.

View File

@ -10,8 +10,8 @@ When mermaid starts, configuration is extracted to determine a configuration to
- The default configuration - The default configuration
- Overrides at the site level are set by the initialize call, and will be applied to all diagrams in the site/app. The term for this is the **siteConfig**. - Overrides at the site level are set by the initialize call, and will be applied to all diagrams in the site/app. The term for this is the **siteConfig**.
- Frontmatter (v10.5.0+) - diagram authors can update select configuration parameters in the frontmatter of the diagram. These are applied to the render config. - Frontmatter (v10.5.0+) - diagram authors can update selected configuration parameters in the frontmatter of the diagram. These are applied to the render config.
- Directives (Deprecated by Frontmatter) - diagram authors can update select configuration parameters directly in the diagram code via directives. These are applied to the render config. - Directives (Deprecated by Frontmatter) - diagram authors can update selected configuration parameters directly in the diagram code via directives. These are applied to the render config.
**The render config** is configuration that is used when rendering by applying these configurations. **The render config** is configuration that is used when rendering by applying these configurations.

View File

@ -42,6 +42,12 @@ Below are a list of community plugins and integrations created with Mermaid.
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf) - [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
- [LiveBook](https://livebook.dev) ✅ - [LiveBook](https://livebook.dev) ✅
- [Atlassian Products](https://www.atlassian.com) - [Atlassian Products](https://www.atlassian.com)
- [Mermaid for Confluence](https://marketplace.atlassian.com/apps/1224722/mermaid-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Integration for Confluence](https://marketplace.atlassian.com/apps/1222792/mermaid-integration-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Diagrams for Confluence](https://marketplace.atlassian.com/apps/1226945/mermaid-diagrams-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Macro for Confluence](https://marketplace.atlassian.com/apps/1231150/mermaid-macro-for-confluence?hosting=cloud&tab=overview)
- [EliteSoft Mermaid Charts and Diagrams](https://marketplace.atlassian.com/apps/1227286/elitesoft-mermaid-charts-and-diagrams?hosting=cloud&tab=overview)
- [Mermaid for Jira Cloud - Draw UML diagrams easily](https://marketplace.atlassian.com/apps/1223053/mermaid-for-jira-cloud-draw-uml-diagrams-easily?hosting=cloud&tab=overview)
- [Mermaid Charts & Diagrams for Confluence](https://marketplace.atlassian.com/apps/1222572/) - [Mermaid Charts & Diagrams for Confluence](https://marketplace.atlassian.com/apps/1222572/)
- [Mermaid Charts & Diagrams for Jira](https://marketplace.atlassian.com/apps/1224537/) - [Mermaid Charts & Diagrams for Jira](https://marketplace.atlassian.com/apps/1224537/)
- [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview) - [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview)

View File

@ -340,7 +340,7 @@ To Deploy Mermaid:
</script> </script>
``` ```
**Doing so commands the mermaid parser to look for the `<div>` or `<pre>` tags with `class="mermaid"`. From these tags, mermaid tries read the diagram/chart definitions and render them into SVG charts.** **Doing so commands the mermaid parser to look for the `<div>` or `<pre>` tags with `class="mermaid"`. From these tags, mermaid tries to read the diagram/chart definitions and render them into SVG charts.**
**Examples can be found in** [Other examples](../syntax/examples.md) **Examples can be found in** [Other examples](../syntax/examples.md)

View File

@ -399,7 +399,7 @@ UpdateRelStyle(customerA, bankA, $offsetY="60")
title Component diagram for Internet Banking System - API Application title Component diagram for Internet Banking System - API Application
Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.") Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.")
Container(ma, "Mobile App", "Xamarin", "Provides a limited subset ot the internet banking functionality to customers via their mobile mobile device.") Container(ma, "Mobile App", "Xamarin", "Provides a limited subset to the internet banking functionality to customers via their mobile mobile device.")
ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.") ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.") System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
@ -439,7 +439,7 @@ UpdateRelStyle(customerA, bankA, $offsetY="60")
title Component diagram for Internet Banking System - API Application title Component diagram for Internet Banking System - API Application
Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.") Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.")
Container(ma, "Mobile App", "Xamarin", "Provides a limited subset ot the internet banking functionality to customers via their mobile mobile device.") Container(ma, "Mobile App", "Xamarin", "Provides a limited subset to the internet banking functionality to customers via their mobile mobile device.")
ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.") ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.") System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")

View File

@ -425,8 +425,6 @@ And `Link` can be one of:
A namespace groups classes. A namespace groups classes.
Code:
```mermaid-example ```mermaid-example
classDiagram classDiagram
namespace BaseShapes { namespace BaseShapes {

View File

@ -467,7 +467,7 @@ flowchart TB
A & B--> C & D A & B--> C & D
``` ```
If you describe the same diagram using the the basic syntax, it will take four lines. A If you describe the same diagram using the basic syntax, it will take four lines. A
word of warning, one could go overboard with this making the flowchart harder to read in word of warning, one could go overboard with this making the flowchart harder to read in
markdown form. The Swedish word `lagom` comes to mind. It means, not too much and not too little. markdown form. The Swedish word `lagom` comes to mind. It means, not too much and not too little.
This goes for expressive syntaxes as well. This goes for expressive syntaxes as well.

View File

@ -4,7 +4,7 @@
"version": "10.2.4", "version": "10.2.4",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", "description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module", "type": "module",
"packageManager": "pnpm@8.10.2", "packageManager": "pnpm@8.10.4",
"keywords": [ "keywords": [
"diagram", "diagram",
"markdown", "markdown",

View File

@ -231,7 +231,7 @@ export const addRelations = function (relations: ClassRelation[], g: graphlib.Gr
//Set relationship style and line type //Set relationship style and line type
classes: 'relation', classes: 'relation',
pattern: edge.relation.lineType == 1 ? 'dashed' : 'solid', pattern: edge.relation.lineType == 1 ? 'dashed' : 'solid',
id: 'id' + cnt, id: `id_${edge.id1}_${edge.id2}_${cnt}`,
// Set link type for rendering // Set link type for rendering
arrowhead: edge.type === 'arrow_open' ? 'none' : 'normal', arrowhead: edge.type === 'arrow_open' ? 'none' : 'normal',
//Set edge extra labels //Set edge extra labels

View File

@ -681,3 +681,82 @@ describe('given text representing a method, ', function () {
}); });
}); });
}); });
describe('given text representing an attribute', () => {
describe('when the attribute has no modifiers', () => {
it('should parse the display text correctly', () => {
const str = 'name String';
const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails();
expect(displayDetails.displayText).toBe('name String');
expect(displayDetails.cssStyle).toBe('');
});
});
describe('when the attribute has public "+" modifier', () => {
it('should parse the display text correctly', () => {
const str = '+name String';
const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails();
expect(displayDetails.displayText).toBe('+name String');
expect(displayDetails.cssStyle).toBe('');
});
});
describe('when the attribute has protected "#" modifier', () => {
it('should parse the display text correctly', () => {
const str = '#name String';
const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails();
expect(displayDetails.displayText).toBe('#name String');
expect(displayDetails.cssStyle).toBe('');
});
});
describe('when the attribute has private "-" modifier', () => {
it('should parse the display text correctly', () => {
const str = '-name String';
const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails();
expect(displayDetails.displayText).toBe('-name String');
expect(displayDetails.cssStyle).toBe('');
});
});
describe('when the attribute has internal "~" modifier', () => {
it('should parse the display text correctly', () => {
const str = '~name String';
const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails();
expect(displayDetails.displayText).toBe('~name String');
expect(displayDetails.cssStyle).toBe('');
});
});
describe('when the attribute has static "$" modifier', () => {
it('should parse the display text correctly and apply static css style', () => {
const str = 'name String$';
const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails();
expect(displayDetails.displayText).toBe('name String');
expect(displayDetails.cssStyle).toBe(staticCssStyle);
});
});
describe('when the attribute has abstract "*" modifier', () => {
it('should parse the display text correctly and apply abstract css style', () => {
const str = 'name String*';
const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails();
expect(displayDetails.displayText).toBe('name String');
expect(displayDetails.cssStyle).toBe(abstractCssStyle);
});
});
});

View File

@ -106,7 +106,7 @@ export class ClassMember {
this.visibility = firstChar as Visibility; this.visibility = firstChar as Visibility;
} }
if (lastChar.match(/[*?]/)) { if (lastChar.match(/[$*]/)) {
potentialClassifier = lastChar; potentialClassifier = lastChar;
} }

View File

@ -38,6 +38,20 @@ describe('when securityLevel is antiscript, all script must be removed', () => {
compareRemoveScript(`<img onerror="alert('hello');">`, `<img>`); compareRemoveScript(`<img onerror="alert('hello');">`, `<img>`);
}); });
it('should detect unsecured target attribute, if value is _blank then generate a secured link', () => {
compareRemoveScript(
`<a href="https://mermaid.js.org/" target="_blank">note about mermaid</a>`,
`<a href="https://mermaid.js.org/" target="_blank" rel="noopener">note about mermaid</a>`
);
});
it('should detect unsecured target attribute from links', () => {
compareRemoveScript(
`<a href="https://mermaid.js.org/" target="_self">note about mermaid</a>`,
`<a href="https://mermaid.js.org/" target="_self">note about mermaid</a>`
);
});
it('should detect iframes', () => { it('should detect iframes', () => {
compareRemoveScript( compareRemoveScript(
`<iframe src="http://abc.com/script1.js"></iframe> `<iframe src="http://abc.com/script1.js"></iframe>

View File

@ -25,7 +25,27 @@ export const getRows = (s?: string): string[] => {
* @returns The safer text * @returns The safer text
*/ */
export const removeScript = (txt: string): string => { export const removeScript = (txt: string): string => {
return DOMPurify.sanitize(txt); const TEMPORARY_ATTRIBUTE = 'data-temp-href-target';
DOMPurify.addHook('beforeSanitizeAttributes', (node: Element) => {
if (node.tagName === 'A' && node.hasAttribute('target')) {
node.setAttribute(TEMPORARY_ATTRIBUTE, node.getAttribute('target') || '');
}
});
const sanitizedText = DOMPurify.sanitize(txt);
DOMPurify.addHook('afterSanitizeAttributes', (node: Element) => {
if (node.tagName === 'A' && node.hasAttribute(TEMPORARY_ATTRIBUTE)) {
node.setAttribute('target', node.getAttribute(TEMPORARY_ATTRIBUTE) || '');
node.removeAttribute(TEMPORARY_ATTRIBUTE);
if (node.getAttribute('target') === '_blank') {
node.setAttribute('rel', 'noopener');
}
}
});
return sanitizedText;
}; };
const sanitizeMore = (text: string, config: MermaidConfig) => { const sanitizeMore = (text: string, config: MermaidConfig) => {

View File

@ -201,6 +201,13 @@ export const updateLinkInterpolate = function (positions, interp) {
*/ */
export const updateLink = function (positions, style) { export const updateLink = function (positions, style) {
positions.forEach(function (pos) { positions.forEach(function (pos) {
if (pos >= edges.length) {
throw new Error(
`The index ${pos} for linkStyle is out of bounds. Valid indices for linkStyle are between 0 and ${
edges.length - 1
}. (Help: Ensure that the index is within the range of existing edges.)`
);
}
if (pos === 'default') { if (pos === 'default') {
edges.defaultStyle = style; edges.defaultStyle = style;
} else { } else {
@ -425,7 +432,7 @@ const setupToolTips = function (element) {
tooltipElem tooltipElem
.text(el.attr('title')) .text(el.attr('title'))
.style('left', window.scrollX + rect.left + (rect.right - rect.left) / 2 + 'px') .style('left', window.scrollX + rect.left + (rect.right - rect.left) / 2 + 'px')
.style('top', window.scrollY + rect.top - 14 + document.body.scrollTop + 'px'); .style('top', window.scrollY + rect.bottom + 'px');
tooltipElem.html(tooltipElem.html().replace(/&lt;br\/&gt;/g, '<br/>')); tooltipElem.html(tooltipElem.html().replace(/&lt;br\/&gt;/g, '<br/>'));
el.classed('hover', true); el.classed('hover', true);
}) })

View File

@ -286,6 +286,30 @@ describe('[Style] when parsing', () => {
expect(edges[0].type).toBe('arrow_point'); expect(edges[0].type).toBe('arrow_point');
}); });
it('should handle style definitions within number of edges', function () {
expect(() =>
flow.parser
.parse(
`graph TD
A-->B
linkStyle 1 stroke-width:1px;`
)
.toThrow(
'The index 1 for linkStyle is out of bounds. Valid indices for linkStyle are between 0 and 0. (Help: Ensure that the index is within the range of existing edges.)'
)
);
});
it('should handle style definitions within number of edges', function () {
const res = flow.parser.parse(`graph TD
A-->B
linkStyle 0 stroke-width:1px;`);
const edges = flow.parser.yy.getEdges();
expect(edges[0].style[0]).toBe('stroke-width:1px');
});
it('should handle multi-numbered style definitions with more then 1 digit in a row', function () { it('should handle multi-numbered style definitions with more then 1 digit in a row', function () {
const res = flow.parser.parse( const res = flow.parser.parse(
'graph TD\n' + 'graph TD\n' +

View File

@ -338,26 +338,34 @@ const drawCommits = (svg, commits, modifyGraph) => {
}; };
/** /**
* Detect if there are other commits between commit1's x-position and commit2's x-position on the * Detect if there are commits
* same branch as commit2. * between commitA's x-position
* and commitB's x-position on the
* same branch as commitA, where
* commitA isn't main
* *
* @param {any} commit1 * @param {any} commitA
* @param {any} commit2 * @param {any} commitB
* @param branchToGetCurve
* @param p1
* @param p2
* @param allCommits * @param allCommits
* @returns {boolean} If there are commits between commit1's x-position and commit2's x-position * @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 hasOverlappingCommits = (commit1, commit2, allCommits) => { const shouldRerouteArrow = (commitA, commitB, p1, p2, allCommits) => {
// Find commits on the same branch as commit2 const commitBIsFurthest = dir === 'TB' ? p1.x < p2.x : p1.y < p2.y;
const keys = Object.keys(allCommits); const branchToGetCurve = commitBIsFurthest ? commitB.branch : commitA.branch;
const overlappingComits = keys.filter((key) => { const isOnBranchToGetCurve = (x) => x.branch === branchToGetCurve;
return ( const isBetweenCommits = (x) => x.seq > commitA.seq && x.seq < commitB.seq;
allCommits[key].branch === commit2.branch && return Object.values(allCommits).some((commitX) => {
allCommits[key].seq > commit1.seq && return isBetweenCommits(commitX) && isOnBranchToGetCurve(commitX);
allCommits[key].seq < commit2.seq
);
}); });
return overlappingComits.length > 0;
}; };
/** /**
@ -388,49 +396,61 @@ const findLane = (y1, y2, depth = 0) => {
* Draw the lines between the commits. They were arrows initially. * Draw the lines between the commits. They were arrows initially.
* *
* @param {any} svg * @param {any} svg
* @param {any} commit1 * @param {any} commitA
* @param {any} commit2 * @param {any} commitB
* @param {any} allCommits * @param {any} allCommits
*/ */
const drawArrow = (svg, commit1, commit2, allCommits) => { const drawArrow = (svg, commitA, commitB, allCommits) => {
const p1 = commitPos[commit1.id]; const p1 = commitPos[commitA.id]; // arrowStart
const p2 = commitPos[commit2.id]; const p2 = commitPos[commitB.id]; // arrowEnd
const overlappingCommits = hasOverlappingCommits(commit1, commit2, allCommits); const arrowNeedsRerouting = shouldRerouteArrow(commitA, commitB, p1, p2, allCommits);
// log.debug('drawArrow', p1, p2, overlappingCommits, commit1.id, commit2.id); // log.debug('drawArrow', p1, p2, arrowNeedsRerouting, commitA.id, commitB.id);
// Lower-right quadrant logic; top-left is 0,0
let arc = ''; let arc = '';
let arc2 = ''; let arc2 = '';
let radius = 0; let radius = 0;
let offset = 0; let offset = 0;
let colorClassNum = branchPos[commit2.branch].index; let colorClassNum = branchPos[commitB.branch].index;
let lineDef; let lineDef;
if (overlappingCommits) { if (arrowNeedsRerouting) {
arc = 'A 10 10, 0, 0, 0,'; arc = 'A 10 10, 0, 0, 0,';
arc2 = 'A 10 10, 0, 0, 1,'; arc2 = 'A 10 10, 0, 0, 1,';
radius = 10; radius = 10;
offset = 10; offset = 10;
// Figure out the color of the arrow,arrows going down take the color from the destination branch
colorClassNum = branchPos[commit2.branch].index;
const lineY = p1.y < p2.y ? findLane(p1.y, p2.y) : findLane(p2.y, p1.y); 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); const lineX = p1.x < p2.x ? findLane(p1.x, p2.x) : findLane(p2.x, p1.x);
if (dir === 'TB') { if (dir === 'TB') {
if (p1.x < p2.x) { if (p1.x < p2.x) {
// Source commit is on branch position left of destination commit
// so render arrow rightward with colour of destination branch
colorClassNum = branchPos[commitB.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${lineX - radius} ${p1.y} ${arc2} ${lineX} ${ lineDef = `M ${p1.x} ${p1.y} L ${lineX - radius} ${p1.y} ${arc2} ${lineX} ${
p1.y + offset p1.y + offset
} L ${lineX} ${p2.y - radius} ${arc} ${lineX + offset} ${p2.y} L ${p2.x} ${p2.y}`; } L ${lineX} ${p2.y - radius} ${arc} ${lineX + offset} ${p2.y} L ${p2.x} ${p2.y}`;
} else { } else {
// Source commit is on branch position right of destination commit
// so render arrow leftward with colour of source branch
colorClassNum = branchPos[commitA.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${lineX + radius} ${p1.y} ${arc} ${lineX} ${ lineDef = `M ${p1.x} ${p1.y} L ${lineX + radius} ${p1.y} ${arc} ${lineX} ${
p1.y + offset p1.y + offset
} L ${lineX} ${p2.y - radius} ${arc2} ${lineX - offset} ${p2.y} L ${p2.x} ${p2.y}`; } L ${lineX} ${p2.y - radius} ${arc2} ${lineX - offset} ${p2.y} L ${p2.x} ${p2.y}`;
} }
} else { } else {
if (p1.y < p2.y) { if (p1.y < p2.y) {
// Source commit is on branch positioned above destination commit
// so render arrow downward with colour of destination branch
colorClassNum = branchPos[commitB.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY - radius} ${arc} ${ lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY - radius} ${arc} ${
p1.x + offset p1.x + offset
} ${lineY} L ${p2.x - radius} ${lineY} ${arc2} ${p2.x} ${lineY + offset} L ${p2.x} ${p2.y}`; } ${lineY} L ${p2.x - radius} ${lineY} ${arc2} ${p2.x} ${lineY + offset} L ${p2.x} ${p2.y}`;
} else { } else {
// Source commit is on branch positioned below destination commit
// so render arrow upward with colour of source branch
colorClassNum = branchPos[commitA.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY + radius} ${arc2} ${ lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY + radius} ${arc2} ${
p1.x + offset p1.x + offset
} ${lineY} L ${p2.x - radius} ${lineY} ${arc} ${p2.x} ${lineY - offset} L ${p2.x} ${p2.y}`; } ${lineY} L ${p2.x - radius} ${lineY} ${arc} ${p2.x} ${lineY - offset} L ${p2.x} ${p2.y}`;
@ -445,7 +465,7 @@ const drawArrow = (svg, commit1, commit2, allCommits) => {
offset = 20; offset = 20;
// Figure out the color of the arrow,arrows going down take the color from the destination branch // Figure out the color of the arrow,arrows going down take the color from the destination branch
colorClassNum = branchPos[commit2.branch].index; colorClassNum = branchPos[commitB.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc2} ${p2.x} ${ lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc2} ${p2.x} ${
p1.y + offset p1.y + offset
@ -458,14 +478,14 @@ const drawArrow = (svg, commit1, commit2, allCommits) => {
offset = 20; offset = 20;
// Arrows going up take the color from the source branch // Arrows going up take the color from the source branch
colorClassNum = branchPos[commit1.branch].index; colorClassNum = branchPos[commitA.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc2} ${p1.x - offset} ${ lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc2} ${p1.x - offset} ${
p2.y p2.y
} L ${p2.x} ${p2.y}`; } L ${p2.x} ${p2.y}`;
} }
if (p1.x === p2.x) { if (p1.x === p2.x) {
colorClassNum = branchPos[commit1.branch].index; colorClassNum = branchPos[commitA.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x + radius} ${p1.y} ${arc} ${p1.x + offset} ${ lineDef = `M ${p1.x} ${p1.y} L ${p1.x + radius} ${p1.y} ${arc} ${p1.x + offset} ${
p2.y + radius p2.y + radius
} L ${p2.x} ${p2.y}`; } L ${p2.x} ${p2.y}`;
@ -475,10 +495,8 @@ const drawArrow = (svg, commit1, commit2, allCommits) => {
arc = 'A 20 20, 0, 0, 0,'; arc = 'A 20 20, 0, 0, 0,';
radius = 20; radius = 20;
offset = 20; offset = 20;
// Arrows going up take the color from the target branch
// Figure out the color of the arrow,arrows going down take the color from the destination branch colorClassNum = branchPos[commitB.branch].index;
colorClassNum = branchPos[commit2.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${p2.y} L ${ lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${p2.y} L ${
p2.x p2.x
} ${p2.y}`; } ${p2.y}`;
@ -487,16 +505,15 @@ const drawArrow = (svg, commit1, commit2, allCommits) => {
arc = 'A 20 20, 0, 0, 0,'; arc = 'A 20 20, 0, 0, 0,';
radius = 20; radius = 20;
offset = 20; offset = 20;
// Arrows going up take the color from the source branch // Arrows going up take the color from the source branch
colorClassNum = branchPos[commit1.branch].index; colorClassNum = branchPos[commitA.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${p1.y - offset} L ${ lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${p1.y - offset} L ${
p2.x p2.x
} ${p2.y}`; } ${p2.y}`;
} }
if (p1.y === p2.y) { if (p1.y === p2.y) {
colorClassNum = branchPos[commit1.branch].index; colorClassNum = branchPos[commitA.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${p2.y} L ${ lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${p2.y} L ${
p2.x p2.x
} ${p2.y}`; } ${p2.y}`;

View File

@ -829,6 +829,11 @@ export const draw = function (_text: string, id: string, _version: string, diagO
bounds.insert(activationData.startx, verticalPos - 10, activationData.stopx, verticalPos); bounds.insert(activationData.startx, verticalPos - 10, activationData.stopx, verticalPos);
} }
log.debug('createdActors', createdActors);
log.debug('destroyedActors', destroyedActors);
drawActors(diagram, actors, actorKeys, false);
// Draw the messages/signals // Draw the messages/signals
let sequenceIndex = 1; let sequenceIndex = 1;
let sequenceIndexStep = 1; let sequenceIndexStep = 1;
@ -1028,14 +1033,12 @@ export const draw = function (_text: string, id: string, _version: string, diagO
} }
}); });
log.debug('createdActors', createdActors);
log.debug('destroyedActors', destroyedActors);
drawActors(diagram, actors, actorKeys, false);
messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStartY, diagObj)); messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStartY, diagObj));
if (conf.mirrorActors) { if (conf.mirrorActors) {
drawActors(diagram, actors, actorKeys, true); drawActors(diagram, actors, actorKeys, true);
} }
backgrounds.forEach((e) => svgDraw.drawBackgroundRect(diagram, e)); backgrounds.forEach((e) => svgDraw.drawBackgroundRect(diagram, e));
fixLifeLineHeights(diagram, actors, actorKeys, conf); fixLifeLineHeights(diagram, actors, actorKeys, conf);

View File

@ -324,7 +324,7 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
const center = actor.x + actor.width / 2; const center = actor.x + actor.width / 2;
const centerY = actorY + 5; const centerY = actorY + 5;
const boxpluslineGroup = elem.append('g').lower(); const boxpluslineGroup = elem.append('g');
var g = boxpluslineGroup; var g = boxpluslineGroup;
if (!isFooter) { if (!isFooter) {

View File

@ -4,9 +4,8 @@
## First search to see if someone has already asked (and hopefully been answered) or suggested the same thing. ## First search to see if someone has already asked (and hopefully been answered) or suggested the same thing.
- Search in Discussions - [Search in Discussions](https://github.com/orgs/mermaid-js/discussions)
- Search in open Issues - [Search in Issues (Open & Closed)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue)
- Search in closed Issues
If you find an open issue or discussion thread that is similar to your question but isn't answered, you can let us know that you are also interested in it. If you find an open issue or discussion thread that is similar to your question but isn't answered, you can let us know that you are also interested in it.
Use the GitHub reactions to add a thumbs-up to the issue or discussion thread. Use the GitHub reactions to add a thumbs-up to the issue or discussion thread.

View File

@ -4,8 +4,8 @@ When mermaid starts, configuration is extracted to determine a configuration to
- The default configuration - The default configuration
- Overrides at the site level are set by the initialize call, and will be applied to all diagrams in the site/app. The term for this is the **siteConfig**. - Overrides at the site level are set by the initialize call, and will be applied to all diagrams in the site/app. The term for this is the **siteConfig**.
- Frontmatter (v10.5.0+) - diagram authors can update select configuration parameters in the frontmatter of the diagram. These are applied to the render config. - Frontmatter (v10.5.0+) - diagram authors can update selected configuration parameters in the frontmatter of the diagram. These are applied to the render config.
- Directives (Deprecated by Frontmatter) - diagram authors can update select configuration parameters directly in the diagram code via directives. These are applied to the render config. - Directives (Deprecated by Frontmatter) - diagram authors can update selected configuration parameters directly in the diagram code via directives. These are applied to the render config.
**The render config** is configuration that is used when rendering by applying these configurations. **The render config** is configuration that is used when rendering by applying these configurations.

View File

@ -40,6 +40,12 @@ Below are a list of community plugins and integrations created with Mermaid.
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf) - [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
- [LiveBook](https://livebook.dev) ✅ - [LiveBook](https://livebook.dev) ✅
- [Atlassian Products](https://www.atlassian.com) - [Atlassian Products](https://www.atlassian.com)
- [Mermaid for Confluence](https://marketplace.atlassian.com/apps/1224722/mermaid-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Integration for Confluence](https://marketplace.atlassian.com/apps/1222792/mermaid-integration-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Diagrams for Confluence](https://marketplace.atlassian.com/apps/1226945/mermaid-diagrams-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Macro for Confluence](https://marketplace.atlassian.com/apps/1231150/mermaid-macro-for-confluence?hosting=cloud&tab=overview)
- [EliteSoft Mermaid Charts and Diagrams](https://marketplace.atlassian.com/apps/1227286/elitesoft-mermaid-charts-and-diagrams?hosting=cloud&tab=overview)
- [Mermaid for Jira Cloud - Draw UML diagrams easily](https://marketplace.atlassian.com/apps/1223053/mermaid-for-jira-cloud-draw-uml-diagrams-easily?hosting=cloud&tab=overview)
- [Mermaid Charts & Diagrams for Confluence](https://marketplace.atlassian.com/apps/1222572/) - [Mermaid Charts & Diagrams for Confluence](https://marketplace.atlassian.com/apps/1222572/)
- [Mermaid Charts & Diagrams for Jira](https://marketplace.atlassian.com/apps/1224537/) - [Mermaid Charts & Diagrams for Jira](https://marketplace.atlassian.com/apps/1224537/)
- [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview) - [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview)

View File

@ -97,7 +97,7 @@ To Deploy Mermaid:
</script> </script>
``` ```
**Doing so commands the mermaid parser to look for the `<div>` or `<pre>` tags with `class="mermaid"`. From these tags, mermaid tries read the diagram/chart definitions and render them into SVG charts.** **Doing so commands the mermaid parser to look for the `<div>` or `<pre>` tags with `class="mermaid"`. From these tags, mermaid tries to read the diagram/chart definitions and render them into SVG charts.**
**Examples can be found in** [Other examples](../syntax/examples.md) **Examples can be found in** [Other examples](../syntax/examples.md)

View File

@ -257,7 +257,7 @@ UpdateRelStyle(customerA, bankA, $offsetY="60")
title Component diagram for Internet Banking System - API Application title Component diagram for Internet Banking System - API Application
Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.") Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.")
Container(ma, "Mobile App", "Xamarin", "Provides a limited subset ot the internet banking functionality to customers via their mobile mobile device.") Container(ma, "Mobile App", "Xamarin", "Provides a limited subset to the internet banking functionality to customers via their mobile mobile device.")
ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.") ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.") System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")

View File

@ -281,8 +281,6 @@ And `Link` can be one of:
A namespace groups classes. A namespace groups classes.
Code:
```mermaid-example ```mermaid-example
classDiagram classDiagram
namespace BaseShapes { namespace BaseShapes {

View File

@ -293,7 +293,7 @@ flowchart TB
A & B--> C & D A & B--> C & D
``` ```
If you describe the same diagram using the the basic syntax, it will take four lines. A If you describe the same diagram using the basic syntax, it will take four lines. A
word of warning, one could go overboard with this making the flowchart harder to read in word of warning, one could go overboard with this making the flowchart harder to read in
markdown form. The Swedish word `lagom` comes to mind. It means, not too much and not too little. markdown form. The Swedish word `lagom` comes to mind. It means, not too much and not too little.
This goes for expressive syntaxes as well. This goes for expressive syntaxes as well.