diff --git a/.changeset/brave-memes-flash.md b/.changeset/brave-memes-flash.md
new file mode 100644
index 000000000..720cd7202
--- /dev/null
+++ b/.changeset/brave-memes-flash.md
@@ -0,0 +1,5 @@
+---
+'mermaid': patch
+---
+
+fix: Support edge animation in hand drawn look
diff --git a/.changeset/busy-mirrors-try.md b/.changeset/busy-mirrors-try.md
new file mode 100644
index 000000000..7e5d3b632
--- /dev/null
+++ b/.changeset/busy-mirrors-try.md
@@ -0,0 +1,5 @@
+---
+'mermaid': patch
+---
+
+fix: Resolved parsing error where direction TD was not recognized within subgraphs
diff --git a/.changeset/chilly-words-march.md b/.changeset/chilly-words-march.md
new file mode 100644
index 000000000..54c0b4ebf
--- /dev/null
+++ b/.changeset/chilly-words-march.md
@@ -0,0 +1,5 @@
+---
+'mermaid': patch
+---
+
+fix: Correct viewBox casing and make SVGs responsive
diff --git a/.changeset/clean-wolves-turn.md b/.changeset/clean-wolves-turn.md
deleted file mode 100644
index 7a44c1c16..000000000
--- a/.changeset/clean-wolves-turn.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'mermaid': patch
----
-
-fix: Render newlines as spaces in class diagrams
diff --git a/.changeset/crazy-loops-matter.md b/.changeset/crazy-loops-matter.md
deleted file mode 100644
index e6377a9e5..000000000
--- a/.changeset/crazy-loops-matter.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'mermaid': patch
----
-
-fix: Handle arrows correctly when auto number is enabled
diff --git a/.changeset/curly-apes-prove.md b/.changeset/curly-apes-prove.md
new file mode 100644
index 000000000..2acf3d1a3
--- /dev/null
+++ b/.changeset/curly-apes-prove.md
@@ -0,0 +1,5 @@
+---
+'mermaid': patch
+---
+
+fix: Improve participant parsing and prevent recursive loops on invalid syntax
diff --git a/.changeset/hungry-baths-glow.md b/.changeset/hungry-baths-glow.md
deleted file mode 100644
index b3084bcab..000000000
--- a/.changeset/hungry-baths-glow.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'mermaid': minor
----
-
-feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
diff --git a/.changeset/hungry-guests-drive.md b/.changeset/hungry-guests-drive.md
deleted file mode 100644
index 1b0e0a07b..000000000
--- a/.changeset/hungry-guests-drive.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-'mermaid': minor
-'@mermaid-js/layout-tidy-tree': minor
-'@mermaid-js/layout-elk': minor
----
-
-feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
diff --git a/.changeset/loud-results-melt.md b/.changeset/loud-results-melt.md
new file mode 100644
index 000000000..7005750c6
--- /dev/null
+++ b/.changeset/loud-results-melt.md
@@ -0,0 +1,5 @@
+---
+'mermaid': minor
+---
+
+feat: Add half-arrowheads (solid & stick) and central connection support
diff --git a/.changeset/revert-marked-dependency.md b/.changeset/revert-marked-dependency.md
deleted file mode 100644
index aded58871..000000000
--- a/.changeset/revert-marked-dependency.md
+++ /dev/null
@@ -1,9 +0,0 @@
----
-'mermaid': patch
----
-
-chore: revert marked dependency from ^15.0.7 to ^16.0.0
-
-- Reverted marked package version to ^16.0.0 for better compatibility
-- This is a dependency update that maintains API compatibility
-- All tests pass with the updated version
diff --git a/.changeset/short-seals-sort.md b/.changeset/short-seals-sort.md
new file mode 100644
index 000000000..db8309c7f
--- /dev/null
+++ b/.changeset/short-seals-sort.md
@@ -0,0 +1,5 @@
+---
+'mermaid': minor
+---
+
+feat: allow to put notes in namespaces on classDiagram
diff --git a/.changeset/slow-lemons-know.md b/.changeset/slow-lemons-know.md
new file mode 100644
index 000000000..49eb48543
--- /dev/null
+++ b/.changeset/slow-lemons-know.md
@@ -0,0 +1,5 @@
+---
+'@mermaid': patch
+---
+
+fix: Mindmap breaking in ELK layout
diff --git a/.changeset/sweet-games-build.md b/.changeset/sweet-games-build.md
new file mode 100644
index 000000000..a71e3de25
--- /dev/null
+++ b/.changeset/sweet-games-build.md
@@ -0,0 +1,5 @@
+---
+'mermaid': patch
+---
+
+fix(er-diagram): prevent syntax error when using 'u', numbers, and decimals in node names
diff --git a/.cspell/code-terms.txt b/.cspell/code-terms.txt
index 8b549f888..5f72ea221 100644
--- a/.cspell/code-terms.txt
+++ b/.cspell/code-terms.txt
@@ -1,3 +1,5 @@
+!viewbox
+# It should be viewBox
# This file contains coding related terms
ALPHANUM
antiscript
diff --git a/.cspell/libraries.txt b/.cspell/libraries.txt
index feee10fd1..4fceed5bb 100644
--- a/.cspell/libraries.txt
+++ b/.cspell/libraries.txt
@@ -64,6 +64,7 @@ rscratch
shiki
Slidev
sparkline
+speccharts
sphinxcontrib
ssim
stylis
diff --git a/.cspell/mermaid-terms.txt b/.cspell/mermaid-terms.txt
index 6900c15b0..45152a0ce 100644
--- a/.cspell/mermaid-terms.txt
+++ b/.cspell/mermaid-terms.txt
@@ -8,6 +8,7 @@ compositTitleSize
cose
curv
doublecircle
+elem
elems
gantt
gitgraph
diff --git a/.esbuild/util.ts b/.esbuild/util.ts
index 3a0ec6b41..a3e2ffe55 100644
--- a/.esbuild/util.ts
+++ b/.esbuild/util.ts
@@ -71,6 +71,9 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
const external: string[] = ['require', 'fs', 'path'];
const outFileName = getFileName(name, options);
+ const { dependencies, version } = JSON.parse(
+ readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8')
+ );
const output: BuildOptions = buildOptions({
...rest,
absWorkingDir: resolve(__dirname, `../packages/${packageName}`),
@@ -82,15 +85,13 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
chunkNames: `chunks/${outFileName}/[name]-[hash]`,
define: {
// This needs to be stringified for esbuild
- includeLargeFeatures: `${includeLargeFeatures}`,
+ 'injected.includeLargeFeatures': `${includeLargeFeatures}`,
+ 'injected.version': `'${version}'`,
'import.meta.vitest': 'undefined',
},
});
if (core) {
- const { dependencies } = JSON.parse(
- readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8')
- );
// Core build is used to generate file without bundled dependencies.
// This is used by downstream projects to bundle dependencies themselves.
// Ignore dependencies and any dependencies of dependencies
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index a6400a86a..64de2eb66 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -26,8 +26,8 @@ jobs:
strategy:
fail-fast: false
matrix:
- language: ['javascript']
- # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+ language: ['javascript', 'actions']
+ # CodeQL supports [ 'actions', 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
@@ -36,7 +36,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
+ uses: github/codeql-action/init@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
with:
config-file: ./.github/codeql/codeql-config.yml
languages: ${{ matrix.language }}
@@ -48,7 +48,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
+ uses: github/codeql-action/autobuild@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -62,4 +62,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
+ uses: github/codeql-action/analyze@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
diff --git a/.github/workflows/e2e-applitools.yml b/.github/workflows/e2e-applitools.yml
index 6aaa91eb8..853818425 100644
--- a/.github/workflows/e2e-applitools.yml
+++ b/.github/workflows/e2e-applitools.yml
@@ -53,7 +53,7 @@ jobs:
args: -X POST "$APPLITOOLS_SERVER_URL/api/externals/github/push?apiKey=$APPLITOOLS_API_KEY&CommitSha=$GITHUB_SHA&BranchName=${APPLITOOLS_BRANCH}$&ParentBranchName=$APPLITOOLS_PARENT_BRANCH"
- name: Cypress run
- uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
+ uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
id: cypress
with:
start: pnpm run dev
diff --git a/.github/workflows/e2e-timings.yml b/.github/workflows/e2e-timings.yml
index 21dbda293..21f6b4049 100644
--- a/.github/workflows/e2e-timings.yml
+++ b/.github/workflows/e2e-timings.yml
@@ -27,12 +27,12 @@ jobs:
with:
node-version-file: '.node-version'
- name: Install dependencies
- uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
+ uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
with:
runTests: false
- name: Cypress run
- uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
+ uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
id: cypress
with:
install: false
@@ -58,7 +58,7 @@ jobs:
echo "EOF" >> $GITHUB_OUTPUT
- name: Commit and create pull request
- uses: peter-evans/create-pull-request@18e469570b1cf0dfc11d60ec121099f8ff3e617a
+ uses: peter-evans/create-pull-request@0edc001d28a2959cd7a6b505629f1d82f0a6e67d
with:
add-paths: |
cypress/timings.json
diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index 56883b987..8fbf6d6f6 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -45,7 +45,7 @@ jobs:
node-version-file: '.node-version'
- name: Cache snapshots
id: cache-snapshot
- uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
+ uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ./cypress/snapshots
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
@@ -59,7 +59,7 @@ jobs:
- name: Install dependencies
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
- uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
+ uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
with:
# just perform install
runTests: false
@@ -95,13 +95,13 @@ jobs:
# These cached snapshots are downloaded, providing the reference snapshots.
- name: Cache snapshots
id: cache-snapshot
- uses: actions/cache/restore@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
+ uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ./cypress/snapshots
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
- name: Install dependencies
- uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
+ uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
with:
runTests: false
@@ -117,7 +117,7 @@ jobs:
# Install NPM dependencies, cache them correctly
# and run all Cypress tests
- name: Cypress run
- uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
+ uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
id: cypress
with:
install: false
diff --git a/.github/workflows/link-checker.yml b/.github/workflows/link-checker.yml
index f855ed23b..ce43c2ed7 100644
--- a/.github/workflows/link-checker.yml
+++ b/.github/workflows/link-checker.yml
@@ -32,7 +32,7 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Restore lychee cache
- uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
+ uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: .lycheecache
key: cache-lychee-${{ github.sha }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 649c40034..ece84ac20 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -36,11 +36,10 @@ jobs:
- name: Create Release Pull Request or Publish to npm
id: changesets
- uses: changesets/action@c8bada60c408975afd1a20b3db81d6eee6789308 # v1.4.9
+ uses: changesets/action@06245a4e0a36c064a573d4150030f5ec548e4fcc # v1.4.10
with:
version: pnpm changeset:version
publish: pnpm changeset:publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_CONFIG_PROVENANCE: true
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
index 4901b3781..3177ca15a 100644
--- a/.github/workflows/scorecard.yml
+++ b/.github/workflows/scorecard.yml
@@ -20,18 +20,18 @@ jobs:
with:
persist-credentials: false
- name: Run analysis
- uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
+ uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
publish_results: true
- name: Upload artifact
- uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: SARIF file
path: results.sarif
retention-days: 5
- name: Upload to code-scanning
- uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
+ uses: github/codeql-action/upload-sarif@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
with:
sarif_file: results.sarif
diff --git a/.github/workflows/update-browserlist.yml b/.github/workflows/update-browserlist.yml
index 94de12ad3..54ef39b11 100644
--- a/.github/workflows/update-browserlist.yml
+++ b/.github/workflows/update-browserlist.yml
@@ -19,7 +19,7 @@ jobs:
message: 'chore: update browsers list'
push: false
- name: Create Pull Request
- uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
+ uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
branch: update-browserslist
title: Update Browserslist
diff --git a/.github/workflows/validate-lockfile.yml b/.github/workflows/validate-lockfile.yml
index 59a6df96d..dcfb255b6 100644
--- a/.github/workflows/validate-lockfile.yml
+++ b/.github/workflows/validate-lockfile.yml
@@ -1,7 +1,7 @@
name: Validate pnpm-lock.yaml
on:
- pull_request:
+ pull_request_target:
paths:
- 'pnpm-lock.yaml'
- '**/package.json'
@@ -15,13 +15,8 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
-
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- node-version: 20
-
- - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
+ ref: ${{ github.event.pull_request.head.sha }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Validate pnpm-lock.yaml entries
id: validate # give this step an ID so we can reference its outputs
@@ -55,16 +50,41 @@ jobs:
exit 1
fi
+ - name: Find existing lockfile validation comment
+ if: always()
+ uses: peter-evans/find-comment@v3
+ id: find-comment
+ with:
+ issue-number: ${{ github.event.pull_request.number }}
+ comment-author: 'github-actions[bot]'
+ body-includes: 'Lockfile Validation Failed'
+
- name: Comment on PR if validation failed
if: failure()
- uses: peter-evans/create-or-update-comment@v4
+ uses: peter-evans/create-or-update-comment@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.pull_request.number }}
+ comment-id: ${{ steps.find-comment.outputs.comment-id }}
+ edit-mode: replace
body: |
+ ❌ **Lockfile Validation Failed**
+
The following issue(s) were detected:
${{ steps.validate.outputs.errors }}
Please address these and push an update.
_Posted automatically by GitHub Actions_
+
+ - name: Delete comment if validation passed
+ if: success() && steps.find-comment.outputs.comment-id != ''
+ uses: actions/github-script@v7
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ await github.rest.issues.deleteComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: ${{ steps.find-comment.outputs.comment-id }},
+ });
diff --git a/.vite/build.ts b/.vite/build.ts
index 480dd6b30..d59f0fac3 100644
--- a/.vite/build.ts
+++ b/.vite/build.ts
@@ -78,6 +78,8 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
},
define: {
'import.meta.vitest': 'undefined',
+ 'injected.includeLargeFeatures': 'true',
+ 'injected.version': `'0.0.0'`,
},
resolve: {
extensions: [],
@@ -94,10 +96,6 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
}),
...visualizerOptions(packageName, core),
],
- define: {
- // Needs to be string
- includeLargeFeatures: 'true',
- },
};
if (watch && config.build) {
diff --git a/Dockerfile b/Dockerfile
index 533604407..d7e6c8f84 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -5,7 +5,7 @@ USER 0:0
RUN corepack enable \
&& corepack enable pnpm
-RUN apk add --no-cache git~=2.43.4 \
+RUN apk add --no-cache git~=2.43 \
&& git config --add --system safe.directory /mermaid
ENV NODE_OPTIONS="--max_old_space_size=8192"
diff --git a/cypress/helpers/util.ts b/cypress/helpers/util.ts
index ab4bbef64..0332178f6 100644
--- a/cypress/helpers/util.ts
+++ b/cypress/helpers/util.ts
@@ -6,6 +6,7 @@ interface CypressConfig {
listUrl?: boolean;
listId?: string;
name?: string;
+ screenshot?: boolean;
}
type CypressMermaidConfig = MermaidConfig & CypressConfig;
@@ -90,7 +91,7 @@ export const renderGraph = (
export const openURLAndVerifyRendering = (
url: string,
- options: CypressMermaidConfig,
+ { screenshot = true, ...options }: CypressMermaidConfig,
validation?: any
): void => {
const name: string = (options.name ?? cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
@@ -98,12 +99,16 @@ export const openURLAndVerifyRendering = (
cy.visit(url);
cy.window().should('have.property', 'rendered', true);
cy.get('svg').should('be.visible');
+ // cspell:ignore viewbox
+ cy.get('svg').should('not.have.attr', 'viewbox');
if (validation) {
cy.get('svg').should(validation);
}
- verifyScreenshot(name);
+ if (screenshot) {
+ verifyScreenshot(name);
+ }
};
export const verifyScreenshot = (name: string): void => {
diff --git a/cypress/integration/other/configuration.spec.js b/cypress/integration/other/configuration.spec.js
index b48a197a4..a699e03a7 100644
--- a/cypress/integration/other/configuration.spec.js
+++ b/cypress/integration/other/configuration.spec.js
@@ -98,12 +98,12 @@ describe('Configuration', () => {
it('should handle arrowMarkerAbsolute set to true', () => {
renderGraph(
`flowchart TD
- A[Christmas] -->|Get money| B(Go shopping)
- B --> C{Let me think}
- C -->|One| D[Laptop]
- C -->|Two| E[iPhone]
- C -->|Three| F[fa:fa-car Car]
- `,
+ A[Christmas] -->|Get money| B(Go shopping)
+ B --> C{Let me think}
+ C -->|One| D[Laptop]
+ C -->|Two| E[iPhone]
+ C -->|Three| F[fa:fa-car Car]
+ `,
{
arrowMarkerAbsolute: true,
}
@@ -113,8 +113,7 @@ describe('Configuration', () => {
cy.get('path')
.first()
.should('have.attr', 'marker-end')
- .should('exist')
- .and('include', 'url(http\\:\\/\\/localhost');
+ .and('include', 'url(http://localhost');
});
});
it('should not taint the initial configuration when using multiple directives', () => {
diff --git a/cypress/integration/rendering/classDiagram-v2.spec.js b/cypress/integration/rendering/classDiagram-v2.spec.js
index 0c5dbc04b..f54768d9a 100644
--- a/cypress/integration/rendering/classDiagram-v2.spec.js
+++ b/cypress/integration/rendering/classDiagram-v2.spec.js
@@ -562,6 +562,20 @@ class C13["With Città foreign language"]
`
);
});
+ it('should add notes in namespaces', function () {
+ imgSnapshotTest(
+ `
+ classDiagram
+ note "This is a outer note"
+ note for C1 "This is a outer note for C1"
+ namespace Namespace1 {
+ note "This is a inner note"
+ note for C1 "This is a inner note for C1"
+ class C1
+ }
+ `
+ );
+ });
it('should render a simple class diagram with no members', () => {
imgSnapshotTest(
`
diff --git a/cypress/integration/rendering/classDiagram-v3.spec.js b/cypress/integration/rendering/classDiagram-v3.spec.js
index 0e66bf757..42a2ee955 100644
--- a/cypress/integration/rendering/classDiagram-v3.spec.js
+++ b/cypress/integration/rendering/classDiagram-v3.spec.js
@@ -709,6 +709,20 @@ class C13["With Città foreign language"]
`
);
});
+ it('should add notes in namespaces', function () {
+ imgSnapshotTest(
+ `
+ classDiagram
+ note "This is a outer note"
+ note for C1 "This is a outer note for C1"
+ namespace Namespace1 {
+ note "This is a inner note"
+ note for C1 "This is a inner note for C1"
+ class C1
+ }
+ `
+ );
+ });
it('should render a simple class diagram with no members', () => {
imgSnapshotTest(
`
diff --git a/cypress/integration/rendering/erDiagram.spec.js b/cypress/integration/rendering/erDiagram.spec.js
index 8f6193f96..6df44932d 100644
--- a/cypress/integration/rendering/erDiagram.spec.js
+++ b/cypress/integration/rendering/erDiagram.spec.js
@@ -369,4 +369,92 @@ ORDER ||--|{ LINE-ITEM : contains
);
});
});
+
+ describe('Special characters and numbers syntax', () => {
+ it('should render ER diagram with numeric entity names', () => {
+ imgSnapshotTest(
+ `
+ erDiagram
+ 1 ||--|| ORDER : places
+ ORDER ||--|{ 2 : contains
+ 2 ||--o{ 3.5 : references
+ `,
+ { logLevel: 1 }
+ );
+ });
+
+ it('should render ER diagram with "u" character in entity names and cardinality', () => {
+ imgSnapshotTest(
+ `
+ erDiagram
+ CUSTOMER ||--|| u : has
+ u ||--|| ORDER : places
+ PROJECT u--o{ TEAM_MEMBER : "parent"
+ `,
+ { logLevel: 1 }
+ );
+ });
+
+ it('should render ER diagram with decimal numbers in relationships', () => {
+ imgSnapshotTest(
+ `
+ erDiagram
+ 2.5 ||--|| 1.5 : has
+ CUSTOMER ||--o{ 3.14 : references
+ 1.0 ||--|{ ORDER : contains
+ `,
+ { logLevel: 1 }
+ );
+ });
+
+ it('should render ER diagram with numeric entity names and attributes', () => {
+ imgSnapshotTest(
+ `
+ erDiagram
+ 1 {
+ string name
+ int value
+ }
+ 1 ||--|| ORDER : places
+ ORDER {
+ float price
+ string description
+ }
+ `,
+ { logLevel: 1 }
+ );
+ });
+
+ it('should render complex ER diagram with mixed special entity names', () => {
+ imgSnapshotTest(
+ `
+ erDiagram
+ CUSTOMER ||--o{ 1 : places
+ 1 ||--|{ u : contains
+ 1.5
+ u ||--|| 2.5 : processes
+ 2.5 {
+ string id
+ float value
+ }
+ u {
+ varchar(50) name
+ int count
+ }
+ `,
+ { logLevel: 1 }
+ );
+ });
+ it('should render ER diagram with standalone numeric entities', () => {
+ imgSnapshotTest(
+ `erDiagram
+ PRODUCT ||--o{ ORDER-ITEM : has
+ 1.5
+ u
+ 1
+ `,
+ { logLevel: 1 }
+ );
+ });
+ });
});
diff --git a/cypress/integration/rendering/flowchart-elk.spec.js b/cypress/integration/rendering/flowchart-elk.spec.js
index 312e1d5b4..fac4f3b4b 100644
--- a/cypress/integration/rendering/flowchart-elk.spec.js
+++ b/cypress/integration/rendering/flowchart-elk.spec.js
@@ -109,7 +109,7 @@ describe('Flowchart ELK', () => {
const style = svg.attr('style');
expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
- verifyNumber(maxWidthValue, 380);
+ verifyNumber(maxWidthValue, 380, 15);
});
});
it('8-elk: should render a flowchart when useMaxWidth is false', () => {
@@ -128,7 +128,7 @@ describe('Flowchart ELK', () => {
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);
- verifyNumber(width, 380);
+ verifyNumber(width, 380, 15);
expect(svg).to.not.have.attr('style');
});
});
diff --git a/cypress/integration/rendering/flowchart-handDrawn.spec.js b/cypress/integration/rendering/flowchart-handDrawn.spec.js
index 49c55c628..d3ca1d1f1 100644
--- a/cypress/integration/rendering/flowchart-handDrawn.spec.js
+++ b/cypress/integration/rendering/flowchart-handDrawn.spec.js
@@ -1029,4 +1029,19 @@ graph TD
}
);
});
+
+ it('FDH49: should add edge animation', () => {
+ renderGraph(
+ `
+ flowchart TD
+ A(["Start"]) L_A_B_0@--> B{"Decision"}
+ B --> C["Option A"] & D["Option B"]
+ style C stroke-width:4px,stroke-dasharray: 5
+ L_A_B_0@{ animation: slow }
+ L_B_D_0@{ animation: fast }`,
+ { look: 'handDrawn', screenshot: false }
+ );
+ cy.get('path#L_A_B_0').should('have.class', 'edge-animation-slow');
+ cy.get('path#L_B_D_0').should('have.class', 'edge-animation-fast');
+ });
});
diff --git a/cypress/integration/rendering/flowchart-v2.spec.js b/cypress/integration/rendering/flowchart-v2.spec.js
index 8c6cde57a..5ef32c269 100644
--- a/cypress/integration/rendering/flowchart-v2.spec.js
+++ b/cypress/integration/rendering/flowchart-v2.spec.js
@@ -1186,4 +1186,17 @@ end
imgSnapshotTest(graph, { htmlLabels: false });
});
});
+
+ it('V2 - 17: should apply class def colour to edge label', () => {
+ imgSnapshotTest(
+ ` graph LR
+ id1(Start) link@-- "Label" -->id2(Stop)
+ style id1 fill:#f9f,stroke:#333,stroke-width:4px
+
+class id2 myClass
+classDef myClass fill:#bbf,stroke:#f66,stroke-width:2px,color:white,stroke-dasharray: 5 5
+class link myClass
+`
+ );
+ });
});
diff --git a/cypress/integration/rendering/flowchart.spec.js b/cypress/integration/rendering/flowchart.spec.js
index 40713ac4e..5e1984377 100644
--- a/cypress/integration/rendering/flowchart.spec.js
+++ b/cypress/integration/rendering/flowchart.spec.js
@@ -774,6 +774,21 @@ describe('Graph', () => {
expect(svg).to.not.have.attr('style');
});
});
+ it('40: should add edge animation', () => {
+ renderGraph(
+ `
+ flowchart TD
+ A(["Start"]) L_A_B_0@--> B{"Decision"}
+ B --> C["Option A"] & D["Option B"]
+ style C stroke-width:4px,stroke-dasharray: 5
+ L_A_B_0@{ animation: slow }
+ L_B_D_0@{ animation: fast }`,
+ { screenshot: false }
+ );
+ // Verify animation classes are applied to both edges
+ cy.get('path#L_A_B_0').should('have.class', 'edge-animation-slow');
+ cy.get('path#L_B_D_0').should('have.class', 'edge-animation-fast');
+ });
it('58: handle styling with style expressions', () => {
imgSnapshotTest(
`
@@ -973,4 +988,19 @@ graph TD
}
);
});
+
+ it('70: should render a subgraph with direction TD', () => {
+ imgSnapshotTest(
+ `
+ flowchart LR
+ subgraph A
+ direction TD
+ a --> b
+ end
+ `,
+ {
+ fontFamily: 'courier',
+ }
+ );
+ });
});
diff --git a/cypress/integration/rendering/gantt.spec.js b/cypress/integration/rendering/gantt.spec.js
index 32dbcb4d9..72cb6ea29 100644
--- a/cypress/integration/rendering/gantt.spec.js
+++ b/cypress/integration/rendering/gantt.spec.js
@@ -803,4 +803,34 @@ describe('Gantt diagram', () => {
{}
);
});
+ it('should handle numeric timestamps with dateFormat x', () => {
+ imgSnapshotTest(
+ `
+ gantt
+ title Process time profile (ms)
+ dateFormat x
+ axisFormat %L
+ tickInterval 250millisecond
+
+ section Pipeline
+ Parse JSON p1: 000, 120
+ `,
+ {}
+ );
+ });
+ it('should handle numeric timestamps with dateFormat X', () => {
+ imgSnapshotTest(
+ `
+ gantt
+ title Process time profile (ms)
+ dateFormat X
+ axisFormat %L
+ tickInterval 250millisecond
+
+ section Pipeline
+ Parse JSON p1: 000, 120
+ `,
+ {}
+ );
+ });
});
diff --git a/cypress/integration/rendering/sequencediagram-v2.spec.js b/cypress/integration/rendering/sequencediagram-v2.spec.js
index f1c2aafbd..42db4001d 100644
--- a/cypress/integration/rendering/sequencediagram-v2.spec.js
+++ b/cypress/integration/rendering/sequencediagram-v2.spec.js
@@ -655,5 +655,126 @@ describe('Sequence Diagram Special Cases', () => {
expect(svg).to.not.have.attr('style');
});
});
+
+ describe('Central Connection Rendering Tests', () => {
+ it('should render central connection circles on actor vertical lines', () => {
+ imgSnapshotTest(
+ `sequenceDiagram
+ participant Alice
+ participant Bob
+ participant Charlie
+ Alice ()->>() Bob: Central connection
+ Bob ()-->> Charlie: Reverse central connection
+ Charlie ()<<-->>() Alice: Dual central connection`,
+ { look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
+ );
+ });
+
+ it('should render central connections with different arrow types', () => {
+ imgSnapshotTest(
+ `sequenceDiagram
+ participant Alice
+ participant Bob
+ Alice ()->>() Bob: Solid open arrow
+ Alice ()-->>() Bob: Dotted open arrow
+ Alice ()-x() Bob: Solid cross
+ Alice ()--x() Bob: Dotted cross
+ Alice ()->() Bob: Solid arrow`,
+ { look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
+ );
+ });
+
+ it('should render central connections with bidirectional arrows', () => {
+ imgSnapshotTest(
+ `sequenceDiagram
+ participant Alice
+ participant Bob
+ Alice ()<<->>() Bob: Bidirectional solid
+ Alice ()<<-->>() Bob: Bidirectional dotted`,
+ { look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
+ );
+ });
+
+ it('should render central connections with activations', () => {
+ imgSnapshotTest(
+ `sequenceDiagram
+ participant Alice
+ participant Bob
+ participant Charlie
+ Alice ()->>() Bob: Activate Bob
+ activate Bob
+ Bob ()-->> Charlie: Message to Charlie
+ Bob ()->>() Alice: Response to Alice
+ deactivate Bob`,
+ { look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
+ );
+ });
+
+ it('should render central connections mixed with normal messages', () => {
+ imgSnapshotTest(
+ `sequenceDiagram
+ participant Alice
+ participant Bob
+ participant Charlie
+ Alice ->> Bob: Normal message
+ Bob ()->>() Charlie: Central connection
+ Charlie -->> Alice: Normal dotted message
+ Alice ()<<-->>() Bob: Dual central connection
+ Bob -x Charlie: Normal cross message`,
+ { look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
+ );
+ });
+
+ it('should render central connections with notes', () => {
+ imgSnapshotTest(
+ `sequenceDiagram
+ participant Alice
+ participant Bob
+ participant Charlie
+ Alice ()->>() Bob: Central connection
+ Note over Alice,Bob: Central connection note
+ Bob ()-->> Charlie: Reverse central connection
+ Note right of Charlie: Response note
+ Charlie ()<<-->>() Alice: Dual central connection`,
+ { look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
+ );
+ });
+
+ it('should render central connections with loops and alternatives', () => {
+ imgSnapshotTest(
+ `sequenceDiagram
+ participant Alice
+ participant Bob
+ participant Charlie
+ loop Every minute
+ Alice ()->>() Bob: Central heartbeat
+ Bob ()-->> Charlie: Forward heartbeat
+ end
+ alt Success
+ Charlie ()<<-->>() Alice: Success response
+ else Failure
+ Charlie ()-x() Alice: Failure response
+ end`,
+ { look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
+ );
+ });
+
+ it('should render central connections with different participant types', () => {
+ imgSnapshotTest(
+ `sequenceDiagram
+ participant Alice
+ actor Bob
+ participant Charlie@{"type":"boundary"}
+ participant David@{"type":"control"}
+ participant Eve@{"type":"entity"}
+ Alice ()->>() Bob: To actor
+ Bob ()-->> Charlie: To boundary
+ Charlie ()->>() David: To control
+ David ()<<-->>() Eve: To entity
+ Eve ()-x() Alice: Back to participant`,
+ { look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
+ );
+ });
+ });
});
});
diff --git a/cypress/integration/rendering/sequencediagram.spec.js b/cypress/integration/rendering/sequencediagram.spec.js
index 6709b557c..0ec913a8c 100644
--- a/cypress/integration/rendering/sequencediagram.spec.js
+++ b/cypress/integration/rendering/sequencediagram.spec.js
@@ -1053,4 +1053,167 @@ describe('Sequence diagram', () => {
]);
});
});
+ describe('render new arrow type', () => {
+ it('should render Solid half arrow top', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice -|\\ John: Hello John, how are you?
+ Alice-|\\ John: Hi Alice, I can hear you!
+ Alice -|\\ John: Test
+ `
+ );
+ });
+ it('should render Solid half arrow bottom', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice-|/John: Hello John, how are you?
+ Alice-|/John: Hi Alice, I can hear you!
+ Alice-|/John: Test
+ `
+ );
+ });
+
+ it('should render Stick half arrow top ', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice-\\\\John: Hello John, how are you?
+ Alice-\\\\John: Hi Alice, I can hear you!
+ Alice-\\\\John: Test
+ `
+ );
+ });
+ it('should render Stick half arrow bottom ', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice-//John: Hello John, how are you?
+ Alice-//John: Hi Alice, I can hear you!
+ Alice-//John: Test
+ `
+ );
+ });
+ it('should render Solid half arrow top reverse ', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice/|-John: Hello Alice, how are you?
+ Alice/|-John: Hi Alice, I can hear you!
+ Alice/|-John: Test
+
+ `
+ );
+ });
+
+ it('should render Solid half arrow bottom reverse ', () => {
+ imgSnapshotTest(
+ `sequenceDiagram
+ Alice \\|- John: Hello Alice, how are you?
+ Alice \\|- John: Hi Alice, I can hear you!
+ Alice \\|- John: Test`
+ );
+ });
+
+ it('should render Stick half arrow top reverse ', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice //-John: Hello Alice, how are you?
+ Alice //-John: Hi Alice, I can hear you!
+ Alice //-John: Test`
+ );
+ });
+
+ it('should render Stick half arrow bottom reverse ', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice \\\\-John: Hello Alice, how are you?
+ Alice \\\\-John: Hi Alice, I can hear you!
+ Alice \\\\-John: Test`
+ );
+ });
+
+ it('should render Solid half arrow top dotted', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice --|\\John: Hello John, how are you?
+ Alice --|\\John: Hi Alice, I can hear you!
+ Alice --|\\John: Test`
+ );
+ });
+
+ it('should render Solid half arrow bottom dotted', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice --|/John: Hello John, how are you?
+ Alice --|/John: Hi Alice, I can hear you!
+ Alice --|/John: Test`
+ );
+ });
+
+ it('should render Stick half arrow top dotted', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice--\\\\John: Hello John, how are you?
+ Alice--\\\\John: Hi Alice, I can hear you!
+ Alice--\\\\John: Test`
+ );
+ });
+
+ it('should render Stick half arrow bottom dotted', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice--//John: Hello John, how are you?
+ Alice--//John: Hi Alice, I can hear you!
+ Alice--//John: Test`
+ );
+ });
+
+ it('should render Solid half arrow top reverse dotted', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice/|--John: Hello Alice, how are you?
+ Alice/|--John: Hi Alice, I can hear you!
+ Alice/|--John: Test`
+ );
+ });
+
+ it('should render Solid half arrow bottom reverse dotted', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice\\|--John: Hello Alice, how are you?
+ Alice\\|--John: Hi Alice, I can hear you!
+ Alice\\|--John: Test`
+ );
+ });
+
+ it('should render Stick half arrow top reverse dotted ', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice//--John: Hello Alice, how are you?
+ Alice//--John: Hi Alice, I can hear you!
+ Alice//--John: Test`
+ );
+ });
+
+ it('should render Stick half arrow bottom reverse dotted ', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice\\\\--John: Hello Alice, how are you?
+ Alice\\\\--John: Hi Alice, I can hear you!
+ Alice\\\\--John: Test`
+ );
+ });
+ });
});
diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html
index fc33a58b4..90f40003a 100644
--- a/cypress/platform/knsv2.html
+++ b/cypress/platform/knsv2.html
@@ -32,26 +32,8 @@
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
rel="stylesheet"
/>
-
-
-