mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-23 16:04:12 +02:00
Compare commits
4 Commits
feature/66
...
fix/flowch
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c16d20c855 | ||
![]() |
270f05d409 | ||
![]() |
c6134a05d2 | ||
![]() |
bf4a57fd04 |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Support edge animation in hand drawn look
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Resolved parsing error where direction TD was not recognized within subgraphs
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Correct viewBox casing and make SVGs responsive
|
5
.changeset/clean-wolves-turn.md
Normal file
5
.changeset/clean-wolves-turn.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Render newlines as spaces in class diagrams
|
5
.changeset/crazy-loops-matter.md
Normal file
5
.changeset/crazy-loops-matter.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Handle arrows correctly when auto number is enabled
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Improve participant parsing and prevent recursive loops on invalid syntax
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
chore: Fix mindmap rendering in docs and apply tidytree layout
|
5
.changeset/deep-times-make.md
Normal file
5
.changeset/deep-times-make.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
Add IDs in architecture diagrams
|
5
.changeset/hungry-baths-glow.md
Normal file
5
.changeset/hungry-baths-glow.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
|
7
.changeset/hungry-guests-drive.md
Normal file
7
.changeset/hungry-guests-drive.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'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
|
5
.changeset/lazy-wolves-film.md
Normal file
5
.changeset/lazy-wolves-film.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Ensure flowchart htmlLabels resolution respects both global and flowchart config
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Add half-arrowheads (solid & stick) and central connection support
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Resolve gantt chart crash due to invalid array length
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@mermaid': patch
|
||||
---
|
||||
|
||||
fix: Mindmap breaking in ELK layout
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix(er-diagram): prevent syntax error when using 'u', numbers, and decimals in node names
|
10
.github/workflows/codeql.yml
vendored
10
.github/workflows/codeql.yml
vendored
@@ -26,8 +26,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ['javascript', 'actions']
|
||||
# CodeQL supports [ 'actions', 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
language: ['javascript']
|
||||
# CodeQL supports [ '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@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||
uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
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@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||
uses: github/codeql-action/autobuild@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
|
||||
# ℹ️ 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@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||
uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
|
2
.github/workflows/e2e-applitools.yml
vendored
2
.github/workflows/e2e-applitools.yml
vendored
@@ -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@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
id: cypress
|
||||
with:
|
||||
start: pnpm run dev
|
||||
|
6
.github/workflows/e2e-timings.yml
vendored
6
.github/workflows/e2e-timings.yml
vendored
@@ -27,12 +27,12 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
- name: Install dependencies
|
||||
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
with:
|
||||
runTests: false
|
||||
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
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@915d841dae6a4f191bb78faf61a257411d7be4d2
|
||||
uses: peter-evans/create-pull-request@18e469570b1cf0dfc11d60ec121099f8ff3e617a
|
||||
with:
|
||||
add-paths: |
|
||||
cypress/timings.json
|
||||
|
10
.github/workflows/e2e.yml
vendored
10
.github/workflows/e2e.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
node-version-file: '.node-version'
|
||||
- name: Cache snapshots
|
||||
id: cache-snapshot
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
|
||||
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@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
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@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache/restore@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
|
||||
with:
|
||||
path: ./cypress/snapshots
|
||||
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
||||
|
||||
- name: Install dependencies
|
||||
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
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@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
id: cypress
|
||||
with:
|
||||
install: false
|
||||
|
2
.github/workflows/link-checker.yml
vendored
2
.github/workflows/link-checker.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Restore lychee cache
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
|
||||
with:
|
||||
path: .lycheecache
|
||||
key: cache-lychee-${{ github.sha }}
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
- name: Create Release Pull Request or Publish to npm
|
||||
id: changesets
|
||||
uses: changesets/action@06245a4e0a36c064a573d4150030f5ec548e4fcc # v1.4.10
|
||||
uses: changesets/action@c8bada60c408975afd1a20b3db81d6eee6789308 # v1.4.9
|
||||
with:
|
||||
version: pnpm changeset:version
|
||||
publish: pnpm changeset:publish
|
||||
|
6
.github/workflows/scorecard.yml
vendored
6
.github/workflows/scorecard.yml
vendored
@@ -20,18 +20,18 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run analysis
|
||||
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
|
||||
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
publish_results: true
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
- name: Upload to code-scanning
|
||||
uses: github/codeql-action/upload-sarif@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||
uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
2
.github/workflows/update-browserlist.yml
vendored
2
.github/workflows/update-browserlist.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
message: 'chore: update browsers list'
|
||||
push: false
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
||||
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||
with:
|
||||
branch: update-browserslist
|
||||
title: Update Browserslist
|
||||
|
@@ -1 +1 @@
|
||||
./packages/mermaid/CHANGELOG.md
|
||||
./packages/mermaid/CHANGELOG.md
|
@@ -1 +1 @@
|
||||
./packages/mermaid/src/docs/community/contributing.md
|
||||
./packages/mermaid/src/docs/community/contributing.md
|
@@ -6,7 +6,6 @@ interface CypressConfig {
|
||||
listUrl?: boolean;
|
||||
listId?: string;
|
||||
name?: string;
|
||||
screenshot?: boolean;
|
||||
}
|
||||
type CypressMermaidConfig = MermaidConfig & CypressConfig;
|
||||
|
||||
@@ -91,7 +90,7 @@ export const renderGraph = (
|
||||
|
||||
export const openURLAndVerifyRendering = (
|
||||
url: string,
|
||||
{ screenshot = true, ...options }: CypressMermaidConfig,
|
||||
options: CypressMermaidConfig,
|
||||
validation?: any
|
||||
): void => {
|
||||
const name: string = (options.name ?? cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||
@@ -99,15 +98,12 @@ export const openURLAndVerifyRendering = (
|
||||
cy.visit(url);
|
||||
cy.window().should('have.property', 'rendered', true);
|
||||
cy.get('svg').should('be.visible');
|
||||
cy.get('svg').should('not.have.attr', 'viewbox');
|
||||
|
||||
if (validation) {
|
||||
cy.get('svg').should(validation);
|
||||
}
|
||||
|
||||
if (screenshot) {
|
||||
verifyScreenshot(name);
|
||||
}
|
||||
verifyScreenshot(name);
|
||||
};
|
||||
|
||||
export const verifyScreenshot = (name: string): void => {
|
||||
|
@@ -661,19 +661,6 @@ class Class10
|
||||
{ logLevel: 1, htmlLabels: true, layout: 'elk' }
|
||||
);
|
||||
});
|
||||
|
||||
it('ELK: should render a class with a text label, members and multiple annotations', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
<<interface>> <<injected>>
|
||||
+member1
|
||||
}
|
||||
C1 --> C2`,
|
||||
{ logLevel: 1, htmlLabels: true, layout: 'elk' }
|
||||
);
|
||||
});
|
||||
|
||||
it('ELK: should render multiple classes with same text labels', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
|
@@ -661,19 +661,6 @@ class Class10
|
||||
{ logLevel: 1, htmlLabels: true, look: 'handDrawn' }
|
||||
);
|
||||
});
|
||||
|
||||
it('HD: should render a class with a text label, membersand multiple annotations', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
<<interface>> <<injected>>
|
||||
+member1
|
||||
}
|
||||
C1 --> C2`,
|
||||
{ logLevel: 1, htmlLabels: true, look: 'handDrawn' }
|
||||
);
|
||||
});
|
||||
|
||||
it('HD: should render multiple classes with same text labels', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
|
@@ -510,16 +510,6 @@ class Class10
|
||||
C1 --> C2`
|
||||
);
|
||||
});
|
||||
it('should render a class with a text label, members and multiple annotations', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
<<interface>> <<injected>>
|
||||
+member1
|
||||
}
|
||||
C1 --> C2`
|
||||
);
|
||||
});
|
||||
it('should render multiple classes with same text labels', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
|
@@ -657,17 +657,6 @@ class Class10
|
||||
C1 --> C2`
|
||||
);
|
||||
});
|
||||
it('should render a class with a text label, members and multiple annotations', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
<<interface>> <<injected>>
|
||||
+member1
|
||||
}
|
||||
C1 --> C2`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render multiple classes with same text labels', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
|
@@ -452,20 +452,6 @@ describe('Class diagram', () => {
|
||||
<<Interface>> \`This\nTitle\nHas\nMany\nNewlines\`
|
||||
`);
|
||||
});
|
||||
it('should render with newlines in title and multiple annotations', () => {
|
||||
imgSnapshotTest(`
|
||||
classDiagram
|
||||
class \`This\nTitle\nHas\nMany\nNewlines\` {
|
||||
+String Also
|
||||
-String Many
|
||||
#int Members
|
||||
+And()
|
||||
-Many()
|
||||
#Methods()
|
||||
}
|
||||
<<Interface>> <<Service>> \`This\nTitle\nHas\nMany\nNewlines\`
|
||||
`);
|
||||
});
|
||||
|
||||
it('should handle newline title in namespace', () => {
|
||||
imgSnapshotTest(`
|
||||
|
@@ -369,92 +369,4 @@ 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 numeric entity names and attributes', () => {
|
||||
imgSnapshotTest(
|
||||
`erDiagram
|
||||
PRODUCT ||--o{ ORDER-ITEM : has
|
||||
1.5
|
||||
u
|
||||
1
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1029,19 +1029,4 @@ 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');
|
||||
});
|
||||
});
|
||||
|
@@ -1199,4 +1199,61 @@ class link myClass
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
describe('htmlLabels rendering', () => {
|
||||
it('should not render with htmlLabels when disabled via flowchart config', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart LR
|
||||
A["HTML label <br> with breaks"] --> B["Another label"]
|
||||
C --> D
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should not render with htmlLabels when disabled via global config', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart LR
|
||||
A["HTML label <br> with breaks"] --> B["Another label"]
|
||||
C --> D
|
||||
`,
|
||||
{ htmlLabels: false }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render with htmlLabels when enabled', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart LR
|
||||
A["HTML label <br> with breaks"] --> B["Another label"]
|
||||
C --> D
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('should not render with htmlLabels when disabled via flowchart config, even when enabled in global config', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart LR
|
||||
A["HTML label <br> with breaks"] --> B["Another label"]
|
||||
C --> D
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: false } },
|
||||
undefined,
|
||||
($svg) => {
|
||||
expect($svg.find('foreignObject').length).to.equal(0);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should create foreignObject elements when htmlLabels enabled', () => {
|
||||
renderGraph(
|
||||
`flowchart TD
|
||||
A["Node with <br> HTML"] -- "edge <br> label" --> B["Another node"]
|
||||
C --> D
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
cy.get('svg foreignObject').should('exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -774,21 +774,6 @@ 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(
|
||||
`
|
||||
@@ -988,19 +973,4 @@ graph TD
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('70: should render a subgraph with direction TD', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart LR
|
||||
subgraph A
|
||||
direction TD
|
||||
a --> b
|
||||
end
|
||||
`,
|
||||
{
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@@ -803,34 +803,4 @@ 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
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@@ -655,126 +655,5 @@ 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 } }
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1053,167 +1053,4 @@ 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`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -110,48 +110,6 @@
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
mindmap
|
||||
root((mindmap))
|
||||
Origins
|
||||
Long history
|
||||
::icon(fa fa-book)
|
||||
Popularisation
|
||||
British popular psychology author Tony Buzan
|
||||
Research
|
||||
On effectiveness<br/>and features
|
||||
On Automatic creation
|
||||
Uses
|
||||
Creative techniques
|
||||
Strategic planning
|
||||
Argument mapping
|
||||
Tools
|
||||
id)I am a cloud(
|
||||
id))I am a bang((
|
||||
Tools
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart
|
||||
aid0
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
mindmap
|
||||
aid0
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: ogdc
|
||||
---
|
||||
flowchart-elk TB
|
||||
c1-->a2
|
||||
subgraph one
|
||||
|
@@ -603,10 +603,6 @@
|
||||
</div>
|
||||
<div class="test">
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: dark
|
||||
---
|
||||
classDiagram
|
||||
test ()--() test2
|
||||
</pre>
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"lib": ["es2020", "dom"],
|
||||
"types": ["cypress", "node", "@argos-ci/cypress/support"],
|
||||
"types": ["cypress", "node", "@argos-ci/cypress/dist/support.d.ts"],
|
||||
"allowImportingTsExtensions": true,
|
||||
"noEmit": true
|
||||
},
|
||||
|
@@ -1,93 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Class Diagram - Multiple Stereotypes Test</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Multiple Stereotypes Test</h1>
|
||||
|
||||
<h2>Test 1: Inline with class definition (single)</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape <<interface>>
|
||||
</pre>
|
||||
|
||||
<h2>Test 2: Inline with class definition (multiple)</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape <<interface>> <<injected>>
|
||||
</pre>
|
||||
|
||||
<h2>Test 3: Separate line (single)</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape
|
||||
<<interface>> Shape
|
||||
</pre>
|
||||
|
||||
<h2>Test 4: Separate line (multiple)</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape
|
||||
<<interface>> <<injected>> Shape
|
||||
</pre>
|
||||
|
||||
<h2>Test 5: Inside class body (single)</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape{
|
||||
<<interface>>
|
||||
noOfVertices
|
||||
draw()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2>Test 6: Inside class body (multiple on same line)</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape{
|
||||
<<interface>> <<injected>>
|
||||
noOfVertices
|
||||
draw()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2>Test 7: Combined example</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape{
|
||||
<<interface>> <<injected>>
|
||||
noOfVertices
|
||||
draw()
|
||||
}
|
||||
class Color{
|
||||
<<enumeration>>
|
||||
RED
|
||||
BLUE
|
||||
GREEN
|
||||
WHITE
|
||||
BLACK
|
||||
}
|
||||
Shape <|-- Color
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'default',
|
||||
logLevel: 3,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -38,7 +38,7 @@
|
||||
+quack()
|
||||
}
|
||||
class Fish{
|
||||
-int sizeInFeet
|
||||
-Listint sizeInFeet
|
||||
-canEat()
|
||||
}
|
||||
class Zebra{
|
||||
@@ -143,7 +143,21 @@
|
||||
Pineapple : -int leafCount()
|
||||
Pineapple : -int spikeCount()
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Person {
|
||||
+ID : Guid
|
||||
+FirstName : string
|
||||
+LastName : string
|
||||
-privateProperty : string
|
||||
#ProtectedProperty : string
|
||||
~InternalProperty : string
|
||||
~AnotherInternalProperty : List~List~string~~
|
||||
}
|
||||
class People List~List~Person~~
|
||||
</pre>
|
||||
<hr />
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
|
@@ -11,7 +11,7 @@
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
|
@@ -29,8 +29,7 @@ In GitHub, you first [**fork a mermaid repository**](https://github.com/mermaid-
|
||||
|
||||
Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with.
|
||||
|
||||
> **💡 Tip**
|
||||
> [Here is a GitHub document that gives an overview of the process](https://docs.github.com/en/get-started/quickstart/fork-a-repo).
|
||||
> **💡 Tip** > [Here is a GitHub document that gives an overview of the process](https://docs.github.com/en/get-started/quickstart/fork-a-repo).
|
||||
|
||||
```bash
|
||||
git clone git@github.com/your-fork/mermaid
|
||||
|
@@ -33,8 +33,7 @@ mindmap
|
||||
|
||||
## Join the Development
|
||||
|
||||
> **💡 Tip**
|
||||
> **Check out our** [**detailed contribution guide**](./contributing.md).
|
||||
> **💡 Tip** > **Check out our** [**detailed contribution guide**](./contributing.md).
|
||||
|
||||
Where to start:
|
||||
|
||||
@@ -48,8 +47,7 @@ Where to start:
|
||||
|
||||
## A Question Or a Suggestion?
|
||||
|
||||
> **💡 Tip**
|
||||
> **Have a look at** [**how to open an issue**](./questions-and-suggestions.md).
|
||||
> **💡 Tip** > **Have a look at** [**how to open an issue**](./questions-and-suggestions.md).
|
||||
|
||||
If you have faced a vulnerability [report it to us](./security.md).
|
||||
|
||||
|
@@ -22,6 +22,7 @@ While directives allow you to change most of the default configuration settings,
|
||||
Mermaid basically supports two types of configuration options to be overridden by directives.
|
||||
|
||||
1. _General/Top Level configurations_ : These are the configurations that are available and applied to all the diagram. **Some of the most important top-level** configurations are:
|
||||
|
||||
- theme
|
||||
- fontFamily
|
||||
- logLevel
|
||||
|
@@ -29,6 +29,7 @@ Try the Ultimate AI, Mermaid, and Visual Diagramming Suite by creating an accoun
|
||||
- **Plugins** - A plugin system for extending the functionality of Mermaid.
|
||||
|
||||
Official Mermaid Chart plugins:
|
||||
|
||||
- [Mermaid Chart GPT](https://chatgpt.com/g/g-684cc36f30208191b21383b88650a45d-mermaid-chart-diagrams-and-charts)
|
||||
- [Confluence](https://marketplace.atlassian.com/apps/1234056/mermaid-chart-for-confluence?hosting=cloud&tab=overview)
|
||||
- [Jira](https://marketplace.atlassian.com/apps/1234810/mermaid-chart-for-jira?tab=overview&hosting=cloud)
|
||||
|
@@ -35,11 +35,13 @@ The Mermaid Chart team is excited to introduce a new Visual Editor for Flowchart
|
||||
Learn more:
|
||||
|
||||
- Visual Editor For Flowcharts
|
||||
|
||||
- [Blog post](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts)
|
||||
|
||||
- [Demo video](https://www.youtube.com/watch?v=5aja0gijoO0)
|
||||
|
||||
- Visual Editor For Sequence diagrams
|
||||
|
||||
- [Blog post](https://www.mermaidchart.com/blog/posts/mermaid-chart-unveils-visual-editor-for-sequence-diagrams)
|
||||
|
||||
- [Demo video](https://youtu.be/imc2u5_N6Dc)
|
||||
|
@@ -6,18 +6,6 @@
|
||||
|
||||
# Blog
|
||||
|
||||
## [The Essential Guide to Mermaid Chart Plugin for VS Code \[08/2025\]](https://docs.mermaidchart.com/blog/posts/the-essential-guide-to-mermaid-chart-plugin-for-vs-code-08-2025)
|
||||
|
||||
9/9/2025 • 5 mins
|
||||
|
||||
Creating diagrams in VS Code has never been easier—the Mermaid VS Code plugin transforms text-based syntax into clear, professional visuals right inside your editor. With live previews, smart editing, and AI-powered diagram generation, it removes the friction from visualization so you can focus on coding.
|
||||
|
||||
## [How to Create Perfect Flowcharts Using AI in 2025 Step-by-Step Guide](https://docs.mermaidchart.com/blog/posts/how-to-create-perfect-flowcharts-using-ai-in-2025-step-by-step-guide)
|
||||
|
||||
7/22/2025 • 8 mins
|
||||
|
||||
In 2025, AI tools make creating flowcharts faster and easier than ever. With Mermaid’s AI flowchart generator, you can turn plain text into clear, accurate diagrams in seconds. This guide walks through how it works and how to get the most out of it for technical and business workflows alike.
|
||||
|
||||
## [Mermaid introduces the Visual Editor for Entity Relationship diagrams](https://docs.mermaidchart.com/blog/posts/mermaid-introduces-the-visual-editor-for-entity-relationship-diagrams)
|
||||
|
||||
7/15/2025 • 7 mins
|
||||
|
@@ -194,7 +194,7 @@ architecture-beta
|
||||
## Icons
|
||||
|
||||
By default, architecture diagram supports the following icons: `cloud`, `database`, `disk`, `internet`, `server`.
|
||||
Users can use any of the 200,000+ icons available in iconify.design, or add other custom icons, by [registering an icon pack](../config/icons.md).
|
||||
Users can use any of the 200,000+ icons available in iconify.design, or [add custom icons](../config/icons.md).
|
||||
|
||||
After the icons are installed, they can be used in the architecture diagram by using the format "name:icon-name", where name is the value used when registering the icon pack.
|
||||
|
||||
|
@@ -139,6 +139,7 @@ The following unfinished features are not supported in the short term.
|
||||
- [ ] Legend
|
||||
|
||||
- [x] System Context
|
||||
|
||||
- [x] Person(alias, label, ?descr, ?sprite, ?tags, $link)
|
||||
- [x] Person_Ext
|
||||
- [x] System(alias, label, ?descr, ?sprite, ?tags, $link)
|
||||
@@ -152,6 +153,7 @@ The following unfinished features are not supported in the short term.
|
||||
- [x] System_Boundary
|
||||
|
||||
- [x] Container diagram
|
||||
|
||||
- [x] Container(alias, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
- [x] ContainerDb
|
||||
- [x] ContainerQueue
|
||||
@@ -161,6 +163,7 @@ The following unfinished features are not supported in the short term.
|
||||
- [x] Container_Boundary(alias, label, ?tags, $link)
|
||||
|
||||
- [x] Component diagram
|
||||
|
||||
- [x] Component(alias, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
- [x] ComponentDb
|
||||
- [x] ComponentQueue
|
||||
@@ -169,15 +172,18 @@ The following unfinished features are not supported in the short term.
|
||||
- [x] ComponentQueue_Ext
|
||||
|
||||
- [x] Dynamic diagram
|
||||
|
||||
- [x] RelIndex(index, from, to, label, ?tags, $link)
|
||||
|
||||
- [x] Deployment diagram
|
||||
|
||||
- [x] Deployment_Node(alias, label, ?type, ?descr, ?sprite, ?tags, $link)
|
||||
- [x] Node(alias, label, ?type, ?descr, ?sprite, ?tags, $link): short name of Deployment_Node()
|
||||
- [x] Node_L(alias, label, ?type, ?descr, ?sprite, ?tags, $link): left aligned Node()
|
||||
- [x] Node_R(alias, label, ?type, ?descr, ?sprite, ?tags, $link): right aligned Node()
|
||||
|
||||
- [x] Relationship Types
|
||||
|
||||
- [x] Rel(from, to, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
- [x] BiRel (bidirectional relationship)
|
||||
- [x] Rel_U, Rel_Up
|
||||
|
@@ -21,7 +21,7 @@ title: Animal example
|
||||
classDiagram
|
||||
note "From Duck till Zebra"
|
||||
Animal <|-- Duck
|
||||
note for Duck "can fly<br>can swim<br>can dive<br>can help in debugging"
|
||||
note for Duck "can fly\ncan swim\ncan dive\ncan help in debugging"
|
||||
Animal <|-- Fish
|
||||
Animal <|-- Zebra
|
||||
Animal : +int age
|
||||
@@ -50,7 +50,7 @@ title: Animal example
|
||||
classDiagram
|
||||
note "From Duck till Zebra"
|
||||
Animal <|-- Duck
|
||||
note for Duck "can fly<br>can swim<br>can dive<br>can help in debugging"
|
||||
note for Duck "can fly\ncan swim\ncan dive\ncan help in debugging"
|
||||
Animal <|-- Fish
|
||||
Animal <|-- Zebra
|
||||
Animal : +int age
|
||||
|
@@ -360,8 +360,7 @@ gantt
|
||||
weekday monday
|
||||
```
|
||||
|
||||
> **Warning**
|
||||
> `millisecond` and `second` support was added in v10.3.0
|
||||
> **Warning** > `millisecond` and `second` support was added in v10.3.0
|
||||
|
||||
## Output in compact mode
|
||||
|
||||
|
@@ -329,11 +329,7 @@ Messages can be of two displayed either solid or with a dotted line.
|
||||
[Actor][Arrow][Actor]:Message text
|
||||
```
|
||||
|
||||
Lines can be solid or dotted, and can end with various types of arrowheads, crosses, or open arrows.
|
||||
|
||||
#### Supported Arrow Types
|
||||
|
||||
**Standard Arrow Types**
|
||||
There are ten types of arrows currently supported:
|
||||
|
||||
| Type | Description |
|
||||
| -------- | ---------------------------------------------------- |
|
||||
@@ -348,58 +344,6 @@ Lines can be solid or dotted, and can end with various types of arrowheads, cros
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
|
||||
**Half-Arrows (v\<MERMAID_RELEASE_VERSION>+)**
|
||||
|
||||
The following half-arrow types are supported for more expressive sequence diagrams. Both solid and dotted variants are available by increasing the number of dashes (`-` → `--`).
|
||||
|
||||
---
|
||||
|
||||
| Type | Description |
|
||||
| ------- | ---------------------------------------------------- |
|
||||
| `-\|\` | Solid line with top half arrowhead |
|
||||
| `--\|\` | Dotted line with top half arrowhead |
|
||||
| `-\|/` | Solid line with bottom half arrowhead |
|
||||
| `--\|/` | Dotted line with bottom half arrowhead |
|
||||
| `/\|-` | Solid line with reverse top half arrowhead |
|
||||
| `/\|--` | Dotted line with reverse top half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom half arrowhead |
|
||||
| `-\\` | Solid line with top stick half arrowhead |
|
||||
| `--\\` | Dotted line with top stick half arrowhead |
|
||||
| `-//` | Solid line with bottom stick half arrowhead |
|
||||
| `--//` | Dotted line with bottom stick half arrowhead |
|
||||
| `//-` | Solid line with reverse top stick half arrowhead |
|
||||
| `//--` | Dotted line with reverse top stick half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom stick half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom stick half arrowhead |
|
||||
|
||||
## Central Connections (v\<MERMAID_RELEASE_VERSION>+)
|
||||
|
||||
Mermaid sequence diagrams support **central lifeline connections** using a `()`.
|
||||
This is useful to represent messages or signals that connect to a central point, rather than from one actor directly to another.
|
||||
|
||||
To indicate a central connection, append `()` to the arrow syntax.
|
||||
|
||||
#### Basic Syntax
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
Alice->>()John: Hello John
|
||||
Alice()->>John: How are you?
|
||||
John()->>()Alice: Great!
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
Alice->>()John: Hello John
|
||||
Alice()->>John: How are you?
|
||||
John()->>()Alice: Great!
|
||||
```
|
||||
|
||||
## Activations
|
||||
|
||||
It is possible to activate and deactivate an actor. (de)activation can be dedicated declarations:
|
||||
|
54
package.json
54
package.json
@@ -63,36 +63,36 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@applitools/eyes-cypress": "^3.55.2",
|
||||
"@argos-ci/cypress": "^6.1.3",
|
||||
"@applitools/eyes-cypress": "^3.44.9",
|
||||
"@argos-ci/cypress": "^5.0.2",
|
||||
"@changesets/changelog-github": "^0.5.1",
|
||||
"@changesets/cli": "^2.29.7",
|
||||
"@changesets/cli": "^2.27.12",
|
||||
"@cspell/eslint-plugin": "^8.19.4",
|
||||
"@cypress/code-coverage": "^3.14.6",
|
||||
"@cypress/code-coverage": "^3.12.49",
|
||||
"@eslint/js": "^9.26.0",
|
||||
"@rollup/plugin-typescript": "^12.1.4",
|
||||
"@types/cors": "^2.8.19",
|
||||
"@types/express": "^5.0.3",
|
||||
"@rollup/plugin-typescript": "^12.1.2",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/lodash": "^4.17.20",
|
||||
"@types/lodash": "^4.17.15",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"@types/node": "^22.18.6",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/rollup-plugin-visualizer": "^5.0.3",
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"@vitest/spy": "^3.2.4",
|
||||
"@vitest/ui": "^3.2.4",
|
||||
"@vitest/coverage-v8": "^3.0.6",
|
||||
"@vitest/spy": "^3.0.6",
|
||||
"@vitest/ui": "^3.0.6",
|
||||
"ajv": "^8.17.1",
|
||||
"chokidar": "3.6.0",
|
||||
"concurrently": "^9.2.1",
|
||||
"concurrently": "^9.1.2",
|
||||
"cors": "^2.8.5",
|
||||
"cpy-cli": "^5.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"cspell": "^9.2.1",
|
||||
"cypress": "^14.5.4",
|
||||
"cspell": "^9.1.3",
|
||||
"cypress": "^14.5.1",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
"cypress-split": "^1.24.23",
|
||||
"esbuild": "^0.25.10",
|
||||
"cypress-split": "^1.24.14",
|
||||
"esbuild": "^0.25.0",
|
||||
"eslint": "^9.26.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-cypress": "^4.3.0",
|
||||
@@ -106,30 +106,30 @@
|
||||
"eslint-plugin-tsdoc": "^0.4.0",
|
||||
"eslint-plugin-unicorn": "^59.0.1",
|
||||
"express": "^5.1.0",
|
||||
"globals": "^16.4.0",
|
||||
"globby": "^14.1.0",
|
||||
"globals": "^16.0.0",
|
||||
"globby": "^14.0.2",
|
||||
"husky": "^9.1.7",
|
||||
"jest": "^30.1.3",
|
||||
"jest": "^30.0.4",
|
||||
"jison": "^0.4.18",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"langium-cli": "3.3.0",
|
||||
"lint-staged": "^16.1.6",
|
||||
"lint-staged": "^16.1.2",
|
||||
"markdown-table": "^3.0.4",
|
||||
"nyc": "^17.1.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-jsdoc": "^1.3.3",
|
||||
"prettier": "^3.5.2",
|
||||
"prettier-plugin-jsdoc": "^1.3.2",
|
||||
"rimraf": "^6.0.1",
|
||||
"rollup-plugin-visualizer": "^6.0.3",
|
||||
"start-server-and-test": "^2.1.2",
|
||||
"start-server-and-test": "^2.0.10",
|
||||
"tslib": "^2.8.1",
|
||||
"tsx": "^4.20.5",
|
||||
"tsx": "^4.7.3",
|
||||
"typescript": "~5.7.3",
|
||||
"typescript-eslint": "^8.38.0",
|
||||
"vite": "^7.0.7",
|
||||
"vite": "^7.0.3",
|
||||
"vite-plugin-istanbul": "^7.0.0",
|
||||
"vitest": "^3.2.4"
|
||||
"vitest": "^3.0.6"
|
||||
},
|
||||
"nyc": {
|
||||
"report-dir": "coverage/cypress"
|
||||
|
@@ -37,12 +37,12 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^7.1.1",
|
||||
"@braintree/sanitize-url": "^7.0.4",
|
||||
"d3": "^7.9.0",
|
||||
"khroma": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^9.2.1",
|
||||
"concurrently": "^9.1.2",
|
||||
"mermaid": "workspace:*",
|
||||
"rimraf": "^6.0.1"
|
||||
},
|
||||
|
@@ -1,16 +1,5 @@
|
||||
# @mermaid-js/layout-elk
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800), [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20), [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05), [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8)]:
|
||||
- mermaid@11.11.0
|
||||
|
||||
## 0.1.9
|
||||
|
||||
### Patch Changes
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mermaid-js/layout-elk",
|
||||
"version": "0.2.0",
|
||||
"version": "0.1.9",
|
||||
"description": "ELK layout engine for mermaid",
|
||||
"module": "dist/mermaid-layout-elk.core.mjs",
|
||||
"types": "dist/layouts.d.ts",
|
||||
|
@@ -67,22 +67,7 @@ export const render = async (
|
||||
|
||||
// Add the element to the DOM
|
||||
if (!node.isGroup) {
|
||||
// const child = node as NodeWithVertex;
|
||||
const child: NodeWithVertex = {
|
||||
id: node.id,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
// Store the original node data for later use
|
||||
label: node.label,
|
||||
isGroup: node.isGroup,
|
||||
shape: node.shape,
|
||||
padding: node.padding,
|
||||
cssClasses: node.cssClasses,
|
||||
cssStyles: node.cssStyles,
|
||||
look: node.look,
|
||||
// Include parentId for subgraph processing
|
||||
parentId: node.parentId,
|
||||
};
|
||||
const child = node as NodeWithVertex;
|
||||
graph.children.push(child);
|
||||
nodeDb[node.id] = node;
|
||||
|
||||
@@ -165,7 +150,7 @@ export const render = async (
|
||||
domId: { node: () => any; attr: (arg0: string, arg1: string) => void };
|
||||
}) {
|
||||
if (node) {
|
||||
nodeDb[node.id] ??= {};
|
||||
nodeDb[node.id] = node;
|
||||
nodeDb[node.id].offset = {
|
||||
posX: node.x + relX,
|
||||
posY: node.y + relY,
|
||||
@@ -875,13 +860,11 @@ export const render = async (
|
||||
log.info('APA01 layout result:', JSON.stringify(g, null, 2));
|
||||
} catch (error) {
|
||||
log.error('APA01 ELK layout error:', error);
|
||||
log.error('APA01 elkGraph that caused error:', JSON.stringify(elkGraph, null, 2));
|
||||
throw error;
|
||||
}
|
||||
|
||||
// debugger;
|
||||
await drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
|
||||
|
||||
g.edges?.map(
|
||||
(edge: {
|
||||
sources: (string | number)[];
|
||||
|
@@ -1,12 +0,0 @@
|
||||
# @mermaid-js/layout-tidy-tree
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800), [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20), [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05), [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8)]:
|
||||
- mermaid@11.11.0
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mermaid-js/layout-tidy-tree",
|
||||
"version": "0.2.0",
|
||||
"version": "0.1.0",
|
||||
"description": "Tidy-tree layout engine for mermaid",
|
||||
"module": "dist/mermaid-layout-tidy-tree.core.mjs",
|
||||
"types": "dist/layouts.d.ts",
|
||||
|
@@ -33,7 +33,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@zenuml/core": "^3.41.4"
|
||||
"@zenuml/core": "^3.35.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mermaid": "workspace:^"
|
||||
|
@@ -1,19 +1,5 @@
|
||||
# mermaid
|
||||
|
||||
## 11.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#6704](https://github.com/mermaid-js/mermaid/pull/6704) [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05) Thanks [@omkarht](https://github.com/omkarht)! - feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
|
||||
|
||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6905](https://github.com/mermaid-js/mermaid/pull/6905) [`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Render newlines as spaces in class diagrams
|
||||
|
||||
- [#6886](https://github.com/mermaid-js/mermaid/pull/6886) [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Handle arrows correctly when auto number is enabled
|
||||
|
||||
## 11.10.0
|
||||
|
||||
### Minor Changes
|
||||
@@ -168,6 +154,7 @@
|
||||
### Minor Changes
|
||||
|
||||
- [#6408](https://github.com/mermaid-js/mermaid/pull/6408) [`ad65313`](https://github.com/mermaid-js/mermaid/commit/ad653138e16765d095613a6e5de86dc5e52ac8f0) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: restore curve type configuration functionality for flowcharts. This fixes the issue where curve type settings were not being applied when configured through any of the following methods:
|
||||
|
||||
- Config
|
||||
- Init directive (%%{ init: { 'flowchart': { 'curve': '...' } } }%%)
|
||||
- LinkStyle command (linkStyle default interpolate ...)
|
||||
@@ -186,12 +173,14 @@
|
||||
### Minor Changes
|
||||
|
||||
- [#6187](https://github.com/mermaid-js/mermaid/pull/6187) [`7809b5a`](https://github.com/mermaid-js/mermaid/commit/7809b5a93fae127f45727071f5ff14325222c518) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - Flowchart new syntax for node metadata bugs
|
||||
|
||||
- Incorrect label mapping for nodes when using `&`
|
||||
- Syntax error when `}` with trailing spaces before new line
|
||||
|
||||
- [#6136](https://github.com/mermaid-js/mermaid/pull/6136) [`ec0d9c3`](https://github.com/mermaid-js/mermaid/commit/ec0d9c389aa6018043187654044c1e0b5aa4f600) Thanks [@knsv](https://github.com/knsv)! - Adding support for animation of flowchart edges
|
||||
|
||||
- [#6373](https://github.com/mermaid-js/mermaid/pull/6373) [`05bdf0e`](https://github.com/mermaid-js/mermaid/commit/05bdf0e20e2629fe77513218fbd4e28e65f75882) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - Upgrade Requirement and ER diagram to use the common renderer flow
|
||||
|
||||
- Added support for directions
|
||||
- Added support for hand drawn look
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "11.11.0",
|
||||
"version": "11.10.0",
|
||||
"description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
|
||||
"type": "module",
|
||||
"module": "./dist/mermaid.core.mjs",
|
||||
@@ -67,29 +67,29 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^7.1.1",
|
||||
"@iconify/utils": "^3.0.2",
|
||||
"@braintree/sanitize-url": "^7.0.4",
|
||||
"@iconify/utils": "^3.0.1",
|
||||
"@mermaid-js/parser": "workspace:^",
|
||||
"@types/d3": "^7.4.3",
|
||||
"cytoscape": "^3.33.1",
|
||||
"cytoscape": "^3.29.3",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
"cytoscape-fcose": "^2.2.0",
|
||||
"d3": "^7.9.0",
|
||||
"d3-sankey": "^0.12.3",
|
||||
"dagre-d3-es": "7.0.11",
|
||||
"dayjs": "^1.11.18",
|
||||
"dayjs": "^1.11.13",
|
||||
"dompurify": "^3.2.5",
|
||||
"katex": "^0.16.22",
|
||||
"khroma": "^2.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"marked": "^16.3.0",
|
||||
"marked": "^16.0.0",
|
||||
"roughjs": "^4.6.6",
|
||||
"stylis": "^4.3.6",
|
||||
"ts-dedent": "^2.2.0",
|
||||
"uuid": "^11.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@adobe/jsonschema2md": "^8.0.5",
|
||||
"@adobe/jsonschema2md": "^8.0.2",
|
||||
"@iconify/types": "^2.0.0",
|
||||
"@types/cytoscape": "^3.21.9",
|
||||
"@types/cytoscape-fcose": "^2.2.4",
|
||||
@@ -105,30 +105,30 @@
|
||||
"@types/stylis": "^4.2.7",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"ajv": "^8.17.1",
|
||||
"canvas": "^3.2.0",
|
||||
"canvas": "^3.1.0",
|
||||
"chokidar": "3.6.0",
|
||||
"concurrently": "^9.2.1",
|
||||
"concurrently": "^9.1.2",
|
||||
"csstree-validator": "^4.0.1",
|
||||
"globby": "^14.1.0",
|
||||
"globby": "^14.0.2",
|
||||
"jison": "^0.4.18",
|
||||
"js-base64": "^3.7.8",
|
||||
"js-base64": "^3.7.7",
|
||||
"jsdom": "^26.1.0",
|
||||
"json-schema-to-typescript": "^15.0.4",
|
||||
"micromatch": "^4.0.8",
|
||||
"path-browserify": "^1.0.1",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier": "^3.5.2",
|
||||
"remark": "^15.0.1",
|
||||
"remark-frontmatter": "^5.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"rimraf": "^6.0.1",
|
||||
"start-server-and-test": "^2.1.2",
|
||||
"type-fest": "^4.41.0",
|
||||
"typedoc": "^0.28.13",
|
||||
"typedoc-plugin-markdown": "^4.8.1",
|
||||
"start-server-and-test": "^2.0.10",
|
||||
"type-fest": "^4.35.0",
|
||||
"typedoc": "^0.28.9",
|
||||
"typedoc-plugin-markdown": "^4.8.0",
|
||||
"typescript": "~5.7.3",
|
||||
"unist-util-flatmap": "^1.0.0",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"vitepress": "^1.6.4",
|
||||
"vitepress": "^1.0.2",
|
||||
"vitepress-plugin-search": "1.0.4-alpha.22"
|
||||
},
|
||||
"files": [
|
||||
|
@@ -627,7 +627,7 @@ export class ClassDB implements DiagramDB {
|
||||
padding: config.class!.padding ?? 16,
|
||||
// parent node must be one of [rect, roundedWithTitle, noteGroup, divider]
|
||||
shape: 'rect',
|
||||
cssStyles: [],
|
||||
cssStyles: ['fill: none', 'stroke: black'],
|
||||
look: config.look,
|
||||
};
|
||||
nodes.push(node);
|
||||
|
@@ -18,7 +18,6 @@
|
||||
%x acc_descr_multiline
|
||||
%x class
|
||||
%x class-body
|
||||
%x class-body-annotation
|
||||
%x namespace
|
||||
%x namespace-body
|
||||
%%
|
||||
@@ -83,16 +82,9 @@ Function arguments are optional: 'call <callback_name>()' simply executes 'callb
|
||||
<class-body><<EOF>> return "EOF_IN_STRUCT";
|
||||
<class-body>"[*]" { return 'EDGE_STATE';}
|
||||
<class-body>[{] return "OPEN_IN_STRUCT";
|
||||
<class-body>"<<" { this.begin("class-body-annotation"); return 'ANNOTATION_START';}
|
||||
<class-body>[\n] /* nothing */
|
||||
<class-body>[ \t]+ /* skip whitespace in class body */
|
||||
<class-body>[^{}\n]* { return "MEMBER";}
|
||||
|
||||
<class-body-annotation>">>" { this.popState(); return 'ANNOTATION_END';}
|
||||
<class-body-annotation>[0-9]+ return 'NUM';
|
||||
<class-body-annotation>\w+ return 'ALPHA';
|
||||
<class-body-annotation>[\s]+ /* ignore whitespace */
|
||||
|
||||
<*>"cssClass" return 'CSSCLASS';
|
||||
<*>"callback" return 'CALLBACK';
|
||||
<*>"link" return 'LINK';
|
||||
@@ -302,26 +294,12 @@ classStatement
|
||||
| classIdentifier STYLE_SEPARATOR alphaNumToken {yy.setCssClass($1, $3);}
|
||||
| classIdentifier STRUCT_START members STRUCT_STOP {yy.addMembers($1,$3);}
|
||||
| classIdentifier STRUCT_START STRUCT_STOP {}
|
||||
| classIdentifier STRUCT_START NEWLINE members STRUCT_STOP {yy.addMembers($1,$4);}
|
||||
| classIdentifier STRUCT_START annotationList members STRUCT_STOP {for(const annotation of $3) { yy.addAnnotation($1, annotation); } yy.addMembers($1,$4);}
|
||||
| classIdentifier STRUCT_START annotationList STRUCT_STOP {for(const annotation of $3) { yy.addAnnotation($1, annotation); }}
|
||||
| classIdentifier STRUCT_START NEWLINE annotationList members STRUCT_STOP {for(const annotation of $4) { yy.addAnnotation($1, annotation); } yy.addMembers($1,$5);}
|
||||
| classIdentifier STRUCT_START NEWLINE annotationList STRUCT_STOP {for(const annotation of $4) { yy.addAnnotation($1, annotation); }}
|
||||
| classIdentifier STYLE_SEPARATOR alphaNumToken STRUCT_START members STRUCT_STOP {yy.setCssClass($1, $3);yy.addMembers($1,$5);}
|
||||
| classIdentifier STYLE_SEPARATOR alphaNumToken STRUCT_START NEWLINE members STRUCT_STOP {yy.setCssClass($1, $3);yy.addMembers($1,$6);}
|
||||
| classIdentifier STYLE_SEPARATOR alphaNumToken STRUCT_START annotationList members STRUCT_STOP {yy.setCssClass($1, $3); for(const annotation of $5) { yy.addAnnotation($1, annotation); } yy.addMembers($1,$6);}
|
||||
| classIdentifier STYLE_SEPARATOR alphaNumToken STRUCT_START annotationList STRUCT_STOP {yy.setCssClass($1, $3); for(const annotation of $5) { yy.addAnnotation($1, annotation); }}
|
||||
| classIdentifier STYLE_SEPARATOR alphaNumToken STRUCT_START NEWLINE annotationList members STRUCT_STOP {yy.setCssClass($1, $3); for(const annotation of $6) { yy.addAnnotation($1, annotation); } yy.addMembers($1,$7);}
|
||||
| classIdentifier STYLE_SEPARATOR alphaNumToken STRUCT_START NEWLINE annotationList STRUCT_STOP {yy.setCssClass($1, $3); for(const annotation of $6) { yy.addAnnotation($1, annotation); }}
|
||||
;
|
||||
|
||||
classIdentifier
|
||||
: CLASS className {$$=$2; yy.addClass($2);}
|
||||
| CLASS className ANNOTATION_START alphaNumToken ANNOTATION_END {$$=$2; yy.addClass($2); yy.addAnnotation($2,$4);}
|
||||
| CLASS className annotationList {$$=$2; yy.addClass($2); for(const annotation of $3) { yy.addAnnotation($2, annotation); }}
|
||||
| CLASS className classLabel {$$=$2; yy.addClass($2);yy.setClassLabel($2, $3);}
|
||||
| CLASS className classLabel ANNOTATION_START alphaNumToken ANNOTATION_END {$$=$2; yy.addClass($2);yy.setClassLabel($2, $3); yy.addAnnotation($2,$5);}
|
||||
| CLASS className classLabel annotationList {$$=$2; yy.addClass($2);yy.setClassLabel($2, $3); for(const annotation of $4) { yy.addAnnotation($2, annotation); }}
|
||||
;
|
||||
|
||||
|
||||
@@ -333,12 +311,6 @@ emptyBody
|
||||
|
||||
annotationStatement
|
||||
: ANNOTATION_START alphaNumToken ANNOTATION_END className { yy.addAnnotation($4,$2); }
|
||||
| annotationList className { for(const annotation of $1) { yy.addAnnotation($2, annotation); } }
|
||||
;
|
||||
|
||||
annotationList
|
||||
: ANNOTATION_START alphaNumToken ANNOTATION_END { $$ = [$2]; }
|
||||
| annotationList ANNOTATION_START alphaNumToken ANNOTATION_END { $1.push($3); $$ = $1; }
|
||||
;
|
||||
|
||||
members
|
||||
|
@@ -36,8 +36,8 @@ export async function textHelper<T extends SVGGraphicsElement>(
|
||||
|
||||
annotationGroup = shapeSvg.insert('g').attr('class', 'annotation-group text');
|
||||
if (node.annotations.length > 0) {
|
||||
const annotationText = node.annotations.map((a: string) => `«${a}»`).join('\n');
|
||||
await addText(annotationGroup, { text: annotationText } as unknown as ClassMember, 0);
|
||||
const annotation = node.annotations[0];
|
||||
await addText(annotationGroup, { text: `«${annotation}»` } as unknown as ClassMember, 0);
|
||||
|
||||
const annotationGroupBBox = annotationGroup.node()!.getBBox();
|
||||
annotationGroupHeight = annotationGroupBBox.height;
|
||||
|
@@ -13,30 +13,6 @@ const getStyles = (options) =>
|
||||
|
||||
}
|
||||
|
||||
.cluster-label text {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
.cluster-label span {
|
||||
color: ${options.titleColor};
|
||||
}
|
||||
.cluster-label span p {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.cluster rect {
|
||||
fill: ${options.clusterBkg};
|
||||
stroke: ${options.clusterBorder};
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.cluster text {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
|
||||
.cluster span {
|
||||
color: ${options.titleColor};
|
||||
}
|
||||
|
||||
.nodeLabel, .edgeLabel {
|
||||
color: ${options.classText};
|
||||
}
|
||||
|
@@ -66,15 +66,12 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
\}\| return 'ONE_OR_MORE';
|
||||
"one" return 'ONLY_ONE';
|
||||
"only one" return 'ONLY_ONE';
|
||||
[0-9]+\.[0-9]+ return 'DECIMAL_NUM';
|
||||
"1"(?=\s+[A-Za-z_"']) return 'ONLY_ONE';
|
||||
"1" return 'ENTITY_ONE';
|
||||
[0-9]+ return 'NUM';
|
||||
"1" return 'ONLY_ONE';
|
||||
\|\| return 'ONLY_ONE';
|
||||
o\| return 'ZERO_OR_ONE';
|
||||
o\{ return 'ZERO_OR_MORE';
|
||||
\|\{ return 'ONE_OR_MORE';
|
||||
u(?=[\.\-\|]) return 'MD_PARENT';
|
||||
\s*u return 'MD_PARENT';
|
||||
\.\. return 'NON_IDENTIFYING';
|
||||
\-\- return 'IDENTIFYING';
|
||||
"to" return 'IDENTIFYING';
|
||||
@@ -83,15 +80,13 @@ u(?=[\.\-\|]) return 'MD_PARENT';
|
||||
\-\. return 'NON_IDENTIFYING';
|
||||
<style>([^\x00-\x7F]|\w|\-|\*)+ return 'STYLE_TEXT';
|
||||
<style>';' return 'SEMI';
|
||||
([^\x00-\x7F]|\w|\-|\*|\.)+ return 'UNICODE_TEXT';
|
||||
([^\x00-\x7F]|\w|\-|\*)+ return 'UNICODE_TEXT';
|
||||
[0-9] return 'NUM';
|
||||
. return yytext[0];
|
||||
<<EOF>> return 'EOF';
|
||||
|
||||
/lex
|
||||
|
||||
%left 'ONLY_ONE'
|
||||
%left 'ZERO_OR_ONE' 'ZERO_OR_MORE' 'ONE_OR_MORE' 'MD_PARENT'
|
||||
|
||||
%start start
|
||||
%% /* language grammar */
|
||||
|
||||
@@ -233,9 +228,6 @@ styleComponent: STYLE_TEXT | NUM | COLON | BRKT;
|
||||
entityName
|
||||
: 'ENTITY_NAME' { $$ = $1.replace(/"/g, ''); }
|
||||
| 'UNICODE_TEXT' { $$ = $1; }
|
||||
| 'NUM' { $$ = $1; }
|
||||
| 'DECIMAL_NUM' { $$ = $1; }
|
||||
| 'ENTITY_ONE' { $$ = $1; }
|
||||
;
|
||||
|
||||
attributes
|
||||
|
@@ -1001,90 +1001,4 @@ describe('when parsing ER diagram it...', function () {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('syntax fixes for special characters and numbers', function () {
|
||||
describe('standalone entity names', function () {
|
||||
it('should allow number "1" as standalone entity', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\n1`);
|
||||
});
|
||||
|
||||
it('should allow character "u" as standalone entity', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\nu`);
|
||||
});
|
||||
|
||||
it('should allow decimal numbers as standalone entities', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\n2.5`);
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\n1.5`);
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\n0.1`);
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\n99.99`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('entity names with attributes', function () {
|
||||
it('should allow "u" as entity name with attributes', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nu {\nstring name\nint id\n}`);
|
||||
});
|
||||
|
||||
it('should allow number "1" as entity name with attributes', function () {
|
||||
erDiagram.parser.parse(`erDiagram\n1 {\nstring name\nint id\n}`);
|
||||
});
|
||||
|
||||
it('should allow decimal numbers as entity names with attributes', function () {
|
||||
erDiagram.parser.parse(`erDiagram\n2.5 {\nstring name\nint id\n}`);
|
||||
erDiagram.parser.parse(`erDiagram\n1.5 {\nstring value\n}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('entity names in relationships', function () {
|
||||
it('should allow "u" in relationships', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER ||--|| u : has`);
|
||||
erDiagram.parser.parse(`erDiagram\nu ||--|| ORDER : places`);
|
||||
erDiagram.parser.parse(`erDiagram\nu ||--|| v : connects`);
|
||||
});
|
||||
|
||||
it('should allow numbers in relationships', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER ||--|| 1 : has`);
|
||||
erDiagram.parser.parse(`erDiagram\n1 ||--|| ORDER : places`);
|
||||
erDiagram.parser.parse(`erDiagram\n1 ||--|| 2 : connects`);
|
||||
});
|
||||
|
||||
it('should allow decimal numbers in relationships', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER ||--|| 2.5 : has`);
|
||||
erDiagram.parser.parse(`erDiagram\n1.5 ||--|| ORDER : places`);
|
||||
erDiagram.parser.parse(`erDiagram\n2.5 ||--|| 5.5 : connects`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mixed scenarios', function () {
|
||||
it('should handle complex diagram with special entity names', function () {
|
||||
erDiagram.parser.parse(
|
||||
`erDiagram
|
||||
CUSTOMER ||--o{ 1 : places
|
||||
1 ||--|{ u : contains
|
||||
u {
|
||||
string name
|
||||
int quantity
|
||||
}
|
||||
"2.5" ||--|| ORDER : processes
|
||||
ORDER {
|
||||
int id
|
||||
date created
|
||||
}
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle attributes with numbers in names (but not starting)', function () {
|
||||
erDiagram.parser.parse(
|
||||
`erDiagram
|
||||
ENTITY {
|
||||
string name1
|
||||
int value2
|
||||
float point3_5
|
||||
}
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -21,7 +21,13 @@ export const diagram = {
|
||||
if (cnf.layout) {
|
||||
setConfig({ layout: cnf.layout });
|
||||
}
|
||||
cnf.flowchart.htmlLabels = cnf.flowchart?.htmlLabels ?? cnf?.htmlLabels;
|
||||
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } });
|
||||
setConfig({
|
||||
flowchart: {
|
||||
arrowMarkerAbsolute: cnf.arrowMarkerAbsolute,
|
||||
htmlLabels: cnf.flowchart.htmlLabels,
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
@@ -140,7 +140,6 @@ that id.
|
||||
.*direction\s+BT[^\n]* return 'direction_bt';
|
||||
.*direction\s+RL[^\n]* return 'direction_rl';
|
||||
.*direction\s+LR[^\n]* return 'direction_lr';
|
||||
.*direction\s+TD[^\n]* return 'direction_td';
|
||||
|
||||
[^\s\"]+\@(?=[^\{\"]) { return 'LINK_ID'; }
|
||||
[0-9]+ return 'NUM';
|
||||
@@ -627,8 +626,6 @@ direction
|
||||
{ $$={stmt:'dir', value:'RL'};}
|
||||
| direction_lr
|
||||
{ $$={stmt:'dir', value:'LR'};}
|
||||
| direction_td
|
||||
{ $$={stmt:'dir', value:'TD'};}
|
||||
;
|
||||
|
||||
%%
|
||||
|
@@ -309,21 +309,4 @@ describe('when parsing subgraphs', function () {
|
||||
expect(subgraphA.nodes).toContain('a');
|
||||
expect(subgraphA.nodes).not.toContain('c');
|
||||
});
|
||||
it('should correctly parse direction TD inside a subgraph', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph LR
|
||||
subgraph WithTD
|
||||
direction TD
|
||||
A1 --> A2
|
||||
end
|
||||
`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
|
||||
expect(subgraph.dir).toBe('TD');
|
||||
expect(subgraph.nodes).toContain('A1');
|
||||
expect(subgraph.nodes).toContain('A2');
|
||||
});
|
||||
});
|
||||
|
@@ -268,9 +268,7 @@ const fixTaskDates = function (startTime, endTime, dateFormat, excludes, include
|
||||
|
||||
const getStartDate = function (prevTime, dateFormat, str) {
|
||||
str = str.trim();
|
||||
if ((dateFormat.trim() === 'x' || dateFormat.trim() === 'X') && /^\d+$/.test(str)) {
|
||||
return new Date(Number(str));
|
||||
}
|
||||
|
||||
// Test for after
|
||||
const afterRePattern = /^after\s+(?<ids>[\d\w- ]+)/;
|
||||
const afterStatement = afterRePattern.exec(str);
|
||||
|
@@ -16,7 +16,7 @@ const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
|
||||
const svgWidth = bitWidth * bitsPerRow + 2;
|
||||
const svg: SVG = selectSvgElement(id);
|
||||
|
||||
svg.attr('viewBox', `0 0 ${svgWidth} ${svgHeight}`);
|
||||
svg.attr('viewbox', `0 0 ${svgWidth} ${svgHeight}`);
|
||||
configureSvgSize(svg, svgHeight, svgWidth, config.useMaxWidth);
|
||||
|
||||
for (const [word, packet] of words.entries()) {
|
||||
|
@@ -2,7 +2,6 @@ import type { Diagram } from '../../Diagram.js';
|
||||
import type { RadarDiagramConfig } from '../../config.type.js';
|
||||
import type { DiagramRenderer, DrawDefinition, SVG, SVGGroup } from '../../diagram-api/types.js';
|
||||
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
|
||||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||
import type { RadarDB, RadarAxis, RadarCurve } from './types.js';
|
||||
|
||||
const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
|
||||
@@ -54,9 +53,11 @@ const drawFrame = (svg: SVG, config: Required<RadarDiagramConfig>): SVGGroup =>
|
||||
x: config.marginLeft + config.width / 2,
|
||||
y: config.marginTop + config.height / 2,
|
||||
};
|
||||
configureSvgSize(svg, totalHeight, totalWidth, config.useMaxWidth ?? true);
|
||||
|
||||
svg.attr('viewBox', `0 0 ${totalWidth} ${totalHeight}`);
|
||||
// Initialize the SVG
|
||||
svg
|
||||
.attr('viewbox', `0 0 ${totalWidth} ${totalHeight}`)
|
||||
.attr('width', totalWidth)
|
||||
.attr('height', totalHeight);
|
||||
// g element to center the radar chart
|
||||
return svg.append('g').attr('transform', `translate(${center.x}, ${center.y})`);
|
||||
};
|
||||
|
@@ -32,14 +32,13 @@
|
||||
<CONFIG>[^\}]+ { return 'CONFIG_CONTENT'; }
|
||||
<CONFIG>\} { this.popState(); this.popState(); return 'CONFIG_END'; }
|
||||
<ID>[^\<->\->:\n,;@\s]+(?=\@\{) { yytext = yytext.trim(); return 'ACTOR'; }
|
||||
<ID>[^<>:\n,;@\s]+(?=\s+as\s) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
|
||||
<ID>[^<>:\n,;@]+(?=\s*[\n;#]|$) { yytext = yytext.trim(); this.popState(); return 'ACTOR'; }
|
||||
<ID>[^<>:\n,;@]*\<[^\n]* { this.popState(); return 'INVALID'; }
|
||||
<ID>[^\<->\->:\n,;@]+?([\-]*[^\<->\->:\n,;@]+?)*?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
|
||||
"box" { this.begin('LINE'); return 'box'; }
|
||||
"participant" { this.begin('ID'); return 'participant'; }
|
||||
"actor" { this.begin('ID'); return 'participant_actor'; }
|
||||
"create" return 'create';
|
||||
"destroy" { this.begin('ID'); return 'destroy'; }
|
||||
<ID>[^<\->\->:\n,;]+?([\-]*[^<\->\->:\n,;]+?)*?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
|
||||
<ALIAS>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
|
||||
<ALIAS>(?:) { this.popState(); this.popState(); return 'NEWLINE'; }
|
||||
"loop" { this.begin('LINE'); return 'loop'; }
|
||||
@@ -79,7 +78,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
"off" return 'off';
|
||||
"," return ',';
|
||||
";" return 'NEWLINE';
|
||||
[^\/\\\+\()\+<\->\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)|\-\|\\|\-\\|\-\/|\-\/\/|\-\|\/|\/\|\-|\\\|\-|\/\/\-|\\\\\-|\/\|\-|\-\-\|\\|\-\-|\(\)))[\-]*[^\+<\->\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; } //final_4.11
|
||||
[^+<\->\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)))[\-]*[^\+<\->\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; }
|
||||
"->>" return 'SOLID_ARROW';
|
||||
"<<->>" return 'BIDIRECTIONAL_SOLID_ARROW';
|
||||
"-->>" return 'DOTTED_ARROW';
|
||||
@@ -90,36 +89,10 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
\-\-[x] return 'DOTTED_CROSS';
|
||||
\-[\)] return 'SOLID_POINT';
|
||||
\-\-[\)] return 'DOTTED_POINT';
|
||||
|
||||
//normal-dotted
|
||||
\-\-\|\\ return 'SOLID_ARROW_TOP_DOTTED';
|
||||
\-\-\|\/ return 'SOLID_ARROW_BOTTOM_DOTTED';
|
||||
\-\-\\\\ return 'STICK_ARROW_TOP_DOTTED';
|
||||
\-\-\/\/ return 'STICK_ARROW_BOTTOM_DOTTED';
|
||||
|
||||
//reverse-dotted
|
||||
\/\|\-\- return 'SOLID_ARROW_TOP_REVERSE_DOTTED';
|
||||
\\\|\-\- return 'SOLID_ARROW_BOTTOM_REVERSE_DOTTED';
|
||||
\/\/\-\- return 'STICK_ARROW_TOP_REVERSE_DOTTED';
|
||||
\\\\\-\- return 'STICK_ARROW_BOTTOM_REVERSE_DOTTED';
|
||||
|
||||
//normal
|
||||
\-\|\\ return 'SOLID_ARROW_TOP';
|
||||
\-\|\/ return 'SOLID_ARROW_BOTTOM';
|
||||
\-\\\\ return 'STICK_ARROW_TOP';
|
||||
\-\/\/ return 'STICK_ARROW_BOTTOM';
|
||||
|
||||
//reverse
|
||||
\/\|\- return 'SOLID_ARROW_TOP_REVERSE';
|
||||
\\\|\- return 'SOLID_ARROW_BOTTOM_REVERSE';
|
||||
\/\/\- return 'STICK_ARROW_TOP_REVERSE';
|
||||
\\\\\- return 'STICK_ARROW_BOTTOM_REVERSE';
|
||||
|
||||
":"(?:(?:no)?wrap:)?[^#\n;]* return 'TXT';
|
||||
":" return 'TXT';
|
||||
"+" return '+';
|
||||
"-" return '-';
|
||||
"()" return '()';
|
||||
<<EOF>> return 'NEWLINE';
|
||||
. return 'INVALID';
|
||||
|
||||
@@ -146,7 +119,6 @@ line
|
||||
: SPACE statement { $$ = $2 }
|
||||
| statement { $$ = $1 }
|
||||
| NEWLINE { $$=[]; }
|
||||
| INVALID { $$=[]; }
|
||||
;
|
||||
|
||||
box_section
|
||||
@@ -332,20 +304,6 @@ signal
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5},
|
||||
{type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $1.actor}
|
||||
]}
|
||||
| actor signaltype '()' actor text2
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5, activate: true, centralConnection: yy.LINETYPE.CENTRAL_CONNECTION},
|
||||
{type: 'centralConnection', signalType: yy.LINETYPE.CENTRAL_CONNECTION, actor: $4.actor, }
|
||||
]}
|
||||
|
||||
| actor '()' signaltype actor text2
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$3, msg:$5, activate: false, centralConnection: yy.LINETYPE.CENTRAL_CONNECTION_REVERSE},
|
||||
{type: 'centralConnectionReverse', signalType: yy.LINETYPE.CENTRAL_CONNECTION_REVERSE, actor: $1.actor}
|
||||
]}
|
||||
| actor '()' signaltype '()' actor text2
|
||||
{ $$ = [$1,$5,{type: 'addMessage', from:$1.actor, to:$5.actor, signalType:$3, msg:$6, activate: true, centralConnection: yy.LINETYPE.CENTRAL_CONNECTION_DUAL},
|
||||
{type: 'centralConnection', signalType: yy.LINETYPE.CENTRAL_CONNECTION, actor: $5.actor, },
|
||||
{type: 'centralConnectionReverse', signalType: yy.LINETYPE.CENTRAL_CONNECTION_REVERSE, actor: $1.actor}
|
||||
]}
|
||||
| actor signaltype actor text2
|
||||
{ $$ = [$1,$3,{type: 'addMessage', from:$1.actor, to:$3.actor, signalType:$2, msg:$4}]}
|
||||
;
|
||||
@@ -379,28 +337,7 @@ signaltype
|
||||
: SOLID_OPEN_ARROW { $$ = yy.LINETYPE.SOLID_OPEN; }
|
||||
| DOTTED_OPEN_ARROW { $$ = yy.LINETYPE.DOTTED_OPEN; }
|
||||
| SOLID_ARROW { $$ = yy.LINETYPE.SOLID; }
|
||||
|
||||
| SOLID_ARROW_TOP { $$ = yy.LINETYPE.SOLID_TOP; }
|
||||
| SOLID_ARROW_BOTTOM { $$ = yy.LINETYPE.SOLID_BOTTOM; }
|
||||
| STICK_ARROW_TOP { $$ = yy.LINETYPE.STICK_TOP; }
|
||||
| STICK_ARROW_BOTTOM { $$ = yy.LINETYPE.STICK_BOTTOM; }
|
||||
|
||||
| SOLID_ARROW_TOP_DOTTED { $$ = yy.LINETYPE.SOLID_TOP_DOTTED; }
|
||||
| SOLID_ARROW_BOTTOM_DOTTED { $$ = yy.LINETYPE.SOLID_BOTTOM_DOTTED; }
|
||||
| STICK_ARROW_TOP_DOTTED { $$ = yy.LINETYPE.STICK_TOP_DOTTED; }
|
||||
| STICK_ARROW_BOTTOM_DOTTED { $$ = yy.LINETYPE.STICK_BOTTOM_DOTTED; }
|
||||
|
||||
| SOLID_ARROW_TOP_REVERSE { $$ = yy.LINETYPE.SOLID_ARROW_TOP_REVERSE; }
|
||||
| SOLID_ARROW_BOTTOM_REVERSE { $$ = yy.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE; }
|
||||
| STICK_ARROW_TOP_REVERSE { $$ = yy.LINETYPE.STICK_ARROW_TOP_REVERSE; }
|
||||
| STICK_ARROW_BOTTOM_REVERSE { $$ = yy.LINETYPE.STICK_ARROW_BOTTOM_REVERSE; }
|
||||
|
||||
| SOLID_ARROW_TOP_REVERSE_DOTTED { $$ = yy.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED; }
|
||||
| SOLID_ARROW_BOTTOM_REVERSE_DOTTED { $$ = yy.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED; }
|
||||
| STICK_ARROW_TOP_REVERSE_DOTTED { $$ = yy.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED; }
|
||||
| STICK_ARROW_BOTTOM_REVERSE_DOTTED { $$ = yy.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED; }
|
||||
|
||||
| BIDIRECTIONAL_SOLID_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_SOLID; }
|
||||
| BIDIRECTIONAL_SOLID_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_SOLID; }
|
||||
| DOTTED_ARROW { $$ = yy.LINETYPE.DOTTED; }
|
||||
| BIDIRECTIONAL_DOTTED_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_DOTTED; }
|
||||
| SOLID_CROSS { $$ = yy.LINETYPE.SOLID_CROSS; }
|
||||
@@ -413,4 +350,4 @@ text2
|
||||
: TXT {$$ = yy.parseMessage($1.trim().substring(1)) }
|
||||
;
|
||||
|
||||
%%
|
||||
%%
|
||||
|
@@ -64,30 +64,6 @@ const LINETYPE = {
|
||||
PAR_OVER_START: 32,
|
||||
BIDIRECTIONAL_SOLID: 33,
|
||||
BIDIRECTIONAL_DOTTED: 34,
|
||||
|
||||
SOLID_TOP: 41,
|
||||
SOLID_BOTTOM: 42,
|
||||
STICK_TOP: 43,
|
||||
STICK_BOTTOM: 44,
|
||||
|
||||
SOLID_ARROW_TOP_REVERSE: 45,
|
||||
SOLID_ARROW_BOTTOM_REVERSE: 46,
|
||||
STICK_ARROW_TOP_REVERSE: 47,
|
||||
STICK_ARROW_BOTTOM_REVERSE: 48,
|
||||
|
||||
SOLID_TOP_DOTTED: 51,
|
||||
SOLID_BOTTOM_DOTTED: 52,
|
||||
STICK_TOP_DOTTED: 53,
|
||||
STICK_BOTTOM_DOTTED: 54,
|
||||
|
||||
SOLID_ARROW_TOP_REVERSE_DOTTED: 55,
|
||||
SOLID_ARROW_BOTTOM_REVERSE_DOTTED: 56,
|
||||
STICK_ARROW_TOP_REVERSE_DOTTED: 57,
|
||||
STICK_ARROW_BOTTOM_REVERSE_DOTTED: 58,
|
||||
|
||||
CENTRAL_CONNECTION: 59,
|
||||
CENTRAL_CONNECTION_REVERSE: 60,
|
||||
CENTRAL_CONNECTION_DUAL: 61,
|
||||
} as const;
|
||||
|
||||
const ARROWTYPE = {
|
||||
@@ -268,8 +244,7 @@ export class SequenceDB implements DiagramDB {
|
||||
idTo?: Message['to'],
|
||||
message?: { text: string; wrap: boolean },
|
||||
messageType?: number,
|
||||
activate = false,
|
||||
centralConnection?: number
|
||||
activate = false
|
||||
) {
|
||||
if (messageType === this.LINETYPE.ACTIVE_END) {
|
||||
const cnt = this.activationCount(idFrom ?? '');
|
||||
@@ -296,7 +271,6 @@ export class SequenceDB implements DiagramDB {
|
||||
wrap: message?.wrap ?? this.autoWrap(),
|
||||
type: messageType,
|
||||
activate,
|
||||
centralConnection: centralConnection ?? 0,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
@@ -589,12 +563,6 @@ export class SequenceDB implements DiagramDB {
|
||||
case 'activeStart':
|
||||
this.addSignal(param.actor, undefined, undefined, param.signalType);
|
||||
break;
|
||||
case 'centralConnection':
|
||||
this.addSignal(param.actor, undefined, undefined, param.signalType);
|
||||
break;
|
||||
case 'centralConnectionReverse':
|
||||
this.addSignal(param.actor, undefined, undefined, param.signalType);
|
||||
break;
|
||||
case 'activeEnd':
|
||||
this.addSignal(param.actor, undefined, undefined, param.signalType);
|
||||
break;
|
||||
@@ -638,14 +606,7 @@ export class SequenceDB implements DiagramDB {
|
||||
this.state.records.lastDestroyed = undefined;
|
||||
}
|
||||
}
|
||||
this.addSignal(
|
||||
param.from,
|
||||
param.to,
|
||||
param.msg,
|
||||
param.signalType,
|
||||
param.activate,
|
||||
param.centralConnection
|
||||
);
|
||||
this.addSignal(param.from, param.to, param.msg, param.signalType, param.activate);
|
||||
break;
|
||||
case 'boxStart':
|
||||
this.addBox(param.boxData);
|
||||
|
@@ -104,7 +104,6 @@ describe('more than one sequence diagram', () => {
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Alice",
|
||||
"id": "0",
|
||||
"message": "Hello Bob, how are you?",
|
||||
@@ -114,7 +113,6 @@ describe('more than one sequence diagram', () => {
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Bob",
|
||||
"id": "1",
|
||||
"message": "I am good thanks!",
|
||||
@@ -133,7 +131,6 @@ describe('more than one sequence diagram', () => {
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Alice",
|
||||
"id": "0",
|
||||
"message": "Hello Bob, how are you?",
|
||||
@@ -143,7 +140,6 @@ describe('more than one sequence diagram', () => {
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Bob",
|
||||
"id": "1",
|
||||
"message": "I am good thanks!",
|
||||
@@ -164,7 +160,6 @@ describe('more than one sequence diagram', () => {
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Alice",
|
||||
"id": "0",
|
||||
"message": "Hello John, how are you?",
|
||||
@@ -174,7 +169,6 @@ describe('more than one sequence diagram', () => {
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "John",
|
||||
"id": "1",
|
||||
"message": "I am good thanks!",
|
||||
@@ -187,254 +181,6 @@ describe('more than one sequence diagram', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Central Connection Parsing', () => {
|
||||
describe('when parsing central connection syntax', () => {
|
||||
it('should parse actor ()->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
// Find the actual message (type: 'addMessage')
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 0, // SOLID (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()-->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()-->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 1, // DOTTED (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ->>() actor syntax as CENTRAL_CONNECTION', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(2); // addMessage + centralConnection (no activation for this pattern)
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 59, // CENTRAL_CONNECTION
|
||||
activate: true,
|
||||
type: 0, // SOLID (based on actual parsing)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()-->> actor syntax as CENTRAL_CONNECTION_REVERSE', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()-->> Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(2); // addMessage + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 60, // CENTRAL_CONNECTION_REVERSE
|
||||
activate: false,
|
||||
type: 1, // DOTTED (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()->> actor syntax as CENTRAL_CONNECTION_REVERSE', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()->> Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(2); // addMessage + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 60, // CENTRAL_CONNECTION_REVERSE
|
||||
activate: false,
|
||||
type: 0, // SOLID (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()<<-->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()<<-->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 34, // BIDIRECTIONAL_DOTTED
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()<<->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()<<->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 33, // BIDIRECTIONAL_SOLID
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple central connection types in one diagram', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
Alice ()->>() Bob: Message 1
|
||||
Bob ()-->> Charlie: Message 2
|
||||
Charlie ()<<-->>() Alice: Message 3
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(8); // 3 addMessages + 5 central connection markers
|
||||
|
||||
// Filter to get only the actual messages
|
||||
const actualMessages = messages.filter((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessages).toHaveLength(3);
|
||||
|
||||
expect(actualMessages[0]).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()->>())
|
||||
});
|
||||
|
||||
expect(actualMessages[1]).toMatchObject({
|
||||
from: 'Bob',
|
||||
to: 'Charlie',
|
||||
centralConnection: 60, // CENTRAL_CONNECTION_REVERSE (()-->>)
|
||||
});
|
||||
|
||||
expect(actualMessages[2]).toMatchObject({
|
||||
from: 'Charlie',
|
||||
to: 'Alice',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()<<-->>())
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle central connections with different arrow types', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()-x() Bob: Cross message
|
||||
Alice ()--x() Bob: Dotted cross message
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(6); // 2 addMessages + 4 central connection markers
|
||||
|
||||
const actualMessages = messages.filter((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessages).toHaveLength(2);
|
||||
|
||||
expect(actualMessages[0]).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()-x())
|
||||
type: 3, // SOLID_CROSS
|
||||
});
|
||||
|
||||
expect(actualMessages[1]).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()--x())
|
||||
type: 4, // DOTTED_CROSS
|
||||
});
|
||||
});
|
||||
|
||||
it('should not break existing parsing without central connections', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ->> Bob: Normal message
|
||||
Bob -->> Alice: Normal dotted message
|
||||
Alice -x Bob: Normal cross message
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3);
|
||||
|
||||
messages.forEach((msg) => {
|
||||
expect(msg.centralConnection).toBe(0); // No central connection
|
||||
});
|
||||
|
||||
expect(messages[0].type).toBe(0); // SOLID (based on actual parsing)
|
||||
expect(messages[1].type).toBe(1); // DOTTED (based on actual parsing)
|
||||
expect(messages[2].type).toBe(3); // SOLID_CROSS
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when parsing a sequenceDiagram', function () {
|
||||
let diagram;
|
||||
beforeEach(async function () {
|
||||
@@ -2312,36 +2058,6 @@ Bob->>Alice:Got it!
|
||||
expect(messages[0].from).toBe('Alice');
|
||||
expect(messages[0].to).toBe('Bob');
|
||||
});
|
||||
|
||||
it('1 should parse ', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
actor Bob
|
||||
actor Alice
|
||||
Bob -|\\ Alice: Hello Alice, how are you?
|
||||
Bob -|/ Alice: Hello Alice, how are you?
|
||||
Bob -// Alice: Hello Alice, how are you?
|
||||
Bob -\\\\ Alice: Hello Alice, how are you?
|
||||
|
||||
Bob \\|- Alice: Hello Alice, how are you?
|
||||
Bob /|- Alice: Hello Alice, how are you?
|
||||
Bob //- Alice: Hello Alice, how are you?
|
||||
Bob \\\\- Alice: Hello Alice, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
});
|
||||
|
||||
it('2 should parse ', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
actor Bob
|
||||
actor Alice
|
||||
Alice ()<<->>() Bob: hey?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
});
|
||||
describe('when parsing extended participant syntax', () => {
|
||||
it('should parse participants with different quote styles and whitespace', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
@@ -2609,17 +2325,5 @@ Bob->>Alice:Got it!
|
||||
expect(actors.get('E').type).toBe('entity');
|
||||
expect(actors.get('E').description).toBe('E');
|
||||
});
|
||||
it('should handle fail parsing when alias token causes conflicts in participant definition', async () => {
|
||||
let error = false;
|
||||
try {
|
||||
await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant SAS MyServiceWithMoreThan20Chars <br> service decription
|
||||
`);
|
||||
} catch (e) {
|
||||
error = true;
|
||||
}
|
||||
expect(error).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -282,49 +282,6 @@ const drawNote = async function (elem: any, noteModel: NoteModel) {
|
||||
bounds.models.addNote(noteModel);
|
||||
};
|
||||
|
||||
const drawCentralConnection = function (
|
||||
elem: any,
|
||||
msg: any,
|
||||
msgModel: any,
|
||||
diagObj: Diagram,
|
||||
startx: number,
|
||||
stopx: number,
|
||||
lineStartY: number
|
||||
) {
|
||||
const actors = diagObj.db.getActors();
|
||||
const fromActor = actors.get(msg.from);
|
||||
const toActor = actors.get(msg.to);
|
||||
const fromCenter = fromActor.x + fromActor.width / 2;
|
||||
const toCenter = toActor.x + toActor.width / 2;
|
||||
|
||||
const g = elem.append('g');
|
||||
|
||||
const drawCircle = (cx: number) => {
|
||||
g.append('circle')
|
||||
.attr('cx', cx)
|
||||
.attr('cy', lineStartY)
|
||||
.attr('r', 5)
|
||||
.attr('width', 10)
|
||||
.attr('height', 10);
|
||||
};
|
||||
|
||||
const { CENTRAL_CONNECTION, CENTRAL_CONNECTION_REVERSE, CENTRAL_CONNECTION_DUAL } =
|
||||
diagObj.db.LINETYPE;
|
||||
|
||||
switch (msg.centralConnection) {
|
||||
case CENTRAL_CONNECTION:
|
||||
drawCircle(toCenter);
|
||||
break;
|
||||
case CENTRAL_CONNECTION_REVERSE:
|
||||
drawCircle(fromCenter);
|
||||
break;
|
||||
case CENTRAL_CONNECTION_DUAL:
|
||||
drawCircle(fromCenter);
|
||||
drawCircle(toCenter);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const messageFont = (cnf) => {
|
||||
return {
|
||||
fontFamily: cnf.messageFontFamily,
|
||||
@@ -410,7 +367,7 @@ async function boundMessage(_diagram, msgModel): Promise<number> {
|
||||
* @param lineStartY - The Y coordinate at which the message line starts
|
||||
* @param diagObj - The diagram object.
|
||||
*/
|
||||
const drawMessage = async function (diagram, msgModel, lineStartY: number, diagObj: Diagram, msg) {
|
||||
const drawMessage = async function (diagram, msgModel, lineStartY: number, diagObj: Diagram) {
|
||||
const { startx, stopx, starty, message, type, sequenceIndex, sequenceVisible } = msgModel;
|
||||
const textDims = utils.calculateTextDimensions(message, messageFont(conf));
|
||||
const textObj = svgDrawCommon.getTextObj();
|
||||
@@ -476,9 +433,6 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
line.attr('y1', lineStartY);
|
||||
line.attr('x2', stopx);
|
||||
line.attr('y2', lineStartY);
|
||||
if (hasCentralConnection(msg, diagObj)) {
|
||||
drawCentralConnection(diagram, msg, msgModel, diagObj, startx, stopx, lineStartY);
|
||||
}
|
||||
}
|
||||
// Make an SVG Container
|
||||
// Draw the line
|
||||
@@ -487,15 +441,7 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
type === diagObj.db.LINETYPE.DOTTED_CROSS ||
|
||||
type === diagObj.db.LINETYPE.DOTTED_POINT ||
|
||||
type === diagObj.db.LINETYPE.DOTTED_OPEN ||
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.SOLID_TOP_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.SOLID_BOTTOM_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_TOP_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_BOTTOM_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED
|
||||
) {
|
||||
line.style('stroke-dasharray', '3, 3');
|
||||
line.attr('class', 'messageLine1');
|
||||
@@ -511,51 +457,6 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
line.attr('stroke-width', 2);
|
||||
line.attr('stroke', 'none'); // handled by theme/css anyway
|
||||
line.style('fill', 'none'); // remove any fill colour
|
||||
|
||||
if (type === diagObj.db.LINETYPE.SOLID_TOP || type === diagObj.db.LINETYPE.SOLID_TOP_DOTTED) {
|
||||
line.attr('marker-end', 'url(' + url + '#solidTopArrowHead)');
|
||||
}
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.SOLID_BOTTOM ||
|
||||
type === diagObj.db.LINETYPE.SOLID_BOTTOM_DOTTED
|
||||
) {
|
||||
line.attr('marker-end', 'url(' + url + '#solidBottomArrowHead)');
|
||||
}
|
||||
if (type === diagObj.db.LINETYPE.STICK_TOP || type === diagObj.db.LINETYPE.STICK_TOP_DOTTED) {
|
||||
line.attr('marker-end', 'url(' + url + '#stickTopArrowHead)');
|
||||
}
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.STICK_BOTTOM ||
|
||||
type === diagObj.db.LINETYPE.STICK_BOTTOM_DOTTED
|
||||
) {
|
||||
line.attr('marker-end', 'url(' + url + '#stickBottomArrowHead)');
|
||||
}
|
||||
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED
|
||||
) {
|
||||
line.attr('marker-start', 'url(' + url + '#solidBottomArrowHead)');
|
||||
}
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED
|
||||
) {
|
||||
line.attr('marker-start', 'url(' + url + '#solidTopArrowHead)');
|
||||
}
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED
|
||||
) {
|
||||
line.attr('marker-start', 'url(' + url + '#stickBottomArrowHead)');
|
||||
}
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED
|
||||
) {
|
||||
line.attr('marker-start', 'url(' + url + '#stickTopArrowHead)');
|
||||
}
|
||||
|
||||
if (type === diagObj.db.LINETYPE.SOLID || type === diagObj.db.LINETYPE.DOTTED) {
|
||||
line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
||||
}
|
||||
@@ -580,18 +481,7 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID ||
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED;
|
||||
|
||||
const isReverseArrowType =
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED;
|
||||
|
||||
let x = 0;
|
||||
if (isBidirectional || isReverseArrowType) {
|
||||
if (isBidirectional) {
|
||||
const SEQUENCE_NUMBER_RADIUS = 6;
|
||||
|
||||
if (startx < stopx) {
|
||||
@@ -599,7 +489,6 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
} else {
|
||||
line.attr('x1', startx + SEQUENCE_NUMBER_RADIUS);
|
||||
}
|
||||
x = 3.5;
|
||||
}
|
||||
|
||||
diagram
|
||||
@@ -609,8 +498,7 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
.attr('x2', startx)
|
||||
.attr('y2', lineStartY)
|
||||
.attr('stroke-width', 0)
|
||||
.attr('marker-start', 'url(' + url + '#sequencenumber)')
|
||||
.attr('transform', `translate(-${x}, 0)`);
|
||||
.attr('marker-start', 'url(' + url + '#sequencenumber)');
|
||||
|
||||
diagram
|
||||
.append('text')
|
||||
@@ -620,8 +508,7 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
.attr('font-size', '12px')
|
||||
.attr('text-anchor', 'middle')
|
||||
.attr('class', 'sequenceNumber')
|
||||
.text(sequenceIndex)
|
||||
.attr('transform', `translate(-${x}, 0)`);
|
||||
.text(sequenceIndex);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -970,10 +857,6 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
svgDraw.insertArrowCrossHead(diagram);
|
||||
svgDraw.insertArrowFilledHead(diagram);
|
||||
svgDraw.insertSequenceNumber(diagram);
|
||||
svgDraw.insertSolidTopArrowHead(diagram);
|
||||
svgDraw.insertSolidBottomArrowHead(diagram);
|
||||
svgDraw.insertStickTopArrowHead(diagram);
|
||||
svgDraw.insertStickBottomArrowHead(diagram);
|
||||
|
||||
/**
|
||||
* @param msg - The message to draw.
|
||||
@@ -1014,12 +897,6 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
case diagObj.db.LINETYPE.ACTIVE_START:
|
||||
bounds.newActivation(msg, diagram, actors);
|
||||
break;
|
||||
case diagObj.db.LINETYPE.CENTRAL_CONNECTION:
|
||||
bounds.newActivation(msg, diagram, actors);
|
||||
break;
|
||||
case diagObj.db.LINETYPE.CENTRAL_CONNECTION_REVERSE:
|
||||
bounds.newActivation(msg, diagram, actors);
|
||||
break;
|
||||
case diagObj.db.LINETYPE.ACTIVE_END:
|
||||
activeEnd(msg, bounds.getVerticalPos());
|
||||
break;
|
||||
@@ -1178,7 +1055,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
createdActors,
|
||||
destroyedActors
|
||||
);
|
||||
messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY, msg });
|
||||
messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY });
|
||||
bounds.models.addMessage(msgModel);
|
||||
} catch (e) {
|
||||
log.error('error while drawing message', e);
|
||||
@@ -1191,27 +1068,6 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
diagObj.db.LINETYPE.SOLID_OPEN,
|
||||
diagObj.db.LINETYPE.DOTTED_OPEN,
|
||||
diagObj.db.LINETYPE.SOLID,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_TOP,
|
||||
diagObj.db.LINETYPE.SOLID_BOTTOM,
|
||||
diagObj.db.LINETYPE.STICK_TOP,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_BOTTOM_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_CROSS,
|
||||
diagObj.db.LINETYPE.DOTTED_CROSS,
|
||||
@@ -1231,7 +1087,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
await drawActors(diagram, actors, actorKeys, false);
|
||||
|
||||
for (const e of messagesToDraw) {
|
||||
await drawMessage(diagram, e.messageModel, e.lineStartY, diagObj, e.msg);
|
||||
await drawMessage(diagram, e.messageModel, e.lineStartY, diagObj);
|
||||
}
|
||||
if (conf.mirrorActors) {
|
||||
await drawActors(diagram, actors, actorKeys, true);
|
||||
@@ -1605,85 +1461,12 @@ const buildNoteModel = async function (msg, actors, diagObj) {
|
||||
return noteModel;
|
||||
};
|
||||
|
||||
// Central connection positioning constants
|
||||
const CENTRAL_CONNECTION_BASE_OFFSET = 4;
|
||||
const CENTRAL_CONNECTION_BIDIRECTIONAL_OFFSET = 6;
|
||||
|
||||
/**
|
||||
* Check if a message has central connection
|
||||
* @param msg - The message object
|
||||
* @param diagObj - The diagram object containing LINETYPE constants
|
||||
* @returns True if the message has any type of central connection
|
||||
*/
|
||||
const hasCentralConnection = function (msg, diagObj) {
|
||||
const { CENTRAL_CONNECTION, CENTRAL_CONNECTION_REVERSE, CENTRAL_CONNECTION_DUAL } =
|
||||
diagObj.db.LINETYPE;
|
||||
return [CENTRAL_CONNECTION, CENTRAL_CONNECTION_REVERSE, CENTRAL_CONNECTION_DUAL].includes(
|
||||
msg.centralConnection
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the positioning offset for central connection arrows
|
||||
* @param msg - The message object
|
||||
* @param diagObj - The diagram object containing LINETYPE constants
|
||||
* @param isArrowToRight - Whether the arrow is pointing to the right
|
||||
* @returns The offset to apply to startx position
|
||||
*/
|
||||
const calculateCentralConnectionOffset = function (msg, diagObj, isArrowToRight) {
|
||||
const {
|
||||
CENTRAL_CONNECTION_REVERSE,
|
||||
CENTRAL_CONNECTION_DUAL,
|
||||
BIDIRECTIONAL_SOLID,
|
||||
BIDIRECTIONAL_DOTTED,
|
||||
} = diagObj.db.LINETYPE;
|
||||
|
||||
let offset = 0;
|
||||
|
||||
if (
|
||||
msg.centralConnection === CENTRAL_CONNECTION_REVERSE ||
|
||||
msg.centralConnection === CENTRAL_CONNECTION_DUAL
|
||||
) {
|
||||
offset += CENTRAL_CONNECTION_BASE_OFFSET;
|
||||
}
|
||||
|
||||
if (
|
||||
msg.centralConnection === CENTRAL_CONNECTION_DUAL &&
|
||||
(msg.type === BIDIRECTIONAL_SOLID || msg.type === BIDIRECTIONAL_DOTTED)
|
||||
) {
|
||||
offset += isArrowToRight ? 0 : -CENTRAL_CONNECTION_BIDIRECTIONAL_OFFSET;
|
||||
}
|
||||
|
||||
return offset;
|
||||
};
|
||||
|
||||
const buildMessageModel = function (msg, actors, diagObj) {
|
||||
if (
|
||||
![
|
||||
diagObj.db.LINETYPE.SOLID_OPEN,
|
||||
diagObj.db.LINETYPE.DOTTED_OPEN,
|
||||
diagObj.db.LINETYPE.SOLID,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_TOP,
|
||||
diagObj.db.LINETYPE.SOLID_BOTTOM,
|
||||
diagObj.db.LINETYPE.STICK_TOP,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_BOTTOM_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_CROSS,
|
||||
diagObj.db.LINETYPE.DOTTED_CROSS,
|
||||
@@ -1701,8 +1484,6 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
let startx = isArrowToRight ? fromRight : fromLeft;
|
||||
let stopx = isArrowToRight ? toLeft : toRight;
|
||||
|
||||
// Apply central connection positioning adjustments
|
||||
startx += calculateCentralConnectionOffset(msg, diagObj, isArrowToRight);
|
||||
// As the line width is considered, the left and right values will be off by 2.
|
||||
const isArrowToActivation = Math.abs(toLeft - toRight) > 2;
|
||||
|
||||
@@ -1736,30 +1517,7 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
* Shorten the length of arrow at the end and move the marker forward (using refX) to have a clean arrowhead
|
||||
* This is not required for open arrows that don't have arrowheads
|
||||
*/
|
||||
if (
|
||||
![
|
||||
diagObj.db.LINETYPE.SOLID_OPEN,
|
||||
diagObj.db.LINETYPE.DOTTED_OPEN,
|
||||
|
||||
diagObj.db.LINETYPE.STICK_TOP,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM,
|
||||
|
||||
diagObj.db.LINETYPE.STICK_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE,
|
||||
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE,
|
||||
].includes(msg.type)
|
||||
) {
|
||||
if (![diagObj.db.LINETYPE.SOLID_OPEN, diagObj.db.LINETYPE.DOTTED_OPEN].includes(msg.type)) {
|
||||
stopx += adjustValue(3);
|
||||
}
|
||||
|
||||
@@ -1767,14 +1525,9 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
* Shorten start position of bidirectional arrow to accommodate for second arrowhead
|
||||
*/
|
||||
if (
|
||||
[
|
||||
diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID,
|
||||
diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE,
|
||||
].includes(msg.type)
|
||||
[diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID, diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED].includes(
|
||||
msg.type
|
||||
)
|
||||
) {
|
||||
startx -= adjustValue(3);
|
||||
}
|
||||
|
@@ -1709,77 +1709,6 @@ const _drawMenuItemTextCandidateFunc = (function () {
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
* Setup arrow head and define the marker. The result is appended to the svg.
|
||||
*
|
||||
* @param elem
|
||||
*/
|
||||
export const insertSolidTopArrowHead = function (elem) {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', 'solidTopArrowHead')
|
||||
.attr('refX', 7.9)
|
||||
.attr('refY', 7.25)
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
.attr('markerWidth', 12)
|
||||
.attr('markerHeight', 12)
|
||||
.attr('orient', 'auto-start-reverse')
|
||||
.append('path')
|
||||
.attr('d', 'M 0 0 L 10 8 L 0 8 z'); // this is actual shape for arrowhead
|
||||
};
|
||||
|
||||
export const insertSolidBottomArrowHead = function (elem) {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', 'solidBottomArrowHead')
|
||||
.attr('refX', 7.9)
|
||||
.attr('refY', 0.75)
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
.attr('markerWidth', 12)
|
||||
.attr('markerHeight', 12)
|
||||
.attr('orient', 'auto-start-reverse')
|
||||
.append('path')
|
||||
.attr('d', 'M 0 0 L 10 0 L 0 8 z');
|
||||
};
|
||||
|
||||
export const insertStickTopArrowHead = function (elem) {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', 'stickTopArrowHead')
|
||||
.attr('refX', 7.5)
|
||||
.attr('refY', 7)
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
.attr('markerWidth', 12)
|
||||
.attr('markerHeight', 12)
|
||||
.attr('orient', 'auto-start-reverse')
|
||||
.append('path')
|
||||
.attr('d', 'M 0 0 L 7 7')
|
||||
.attr('stroke', 'black')
|
||||
.attr('stroke-width', 1.5)
|
||||
.attr('fill', 'none');
|
||||
};
|
||||
|
||||
export const insertStickBottomArrowHead = function (elem) {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', 'stickBottomArrowHead')
|
||||
.attr('refX', 7.5)
|
||||
.attr('refY', 0)
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
.attr('markerWidth', 12)
|
||||
.attr('markerHeight', 12)
|
||||
.attr('orient', 'auto-start-reverse')
|
||||
.append('path')
|
||||
.attr('d', 'M 0 7 L 7 0')
|
||||
.attr('stroke', 'black')
|
||||
.attr('stroke-width', 1.5)
|
||||
.attr('fill', 'none');
|
||||
};
|
||||
|
||||
export default {
|
||||
drawRect,
|
||||
drawText,
|
||||
@@ -1802,8 +1731,4 @@ export default {
|
||||
getNoteRect,
|
||||
fixLifeLineHeights,
|
||||
sanitizeUrl,
|
||||
insertSolidTopArrowHead,
|
||||
insertSolidBottomArrowHead,
|
||||
insertStickTopArrowHead,
|
||||
insertStickBottomArrowHead,
|
||||
};
|
||||
|
@@ -35,7 +35,6 @@ export interface Message {
|
||||
type?: number;
|
||||
activate?: boolean;
|
||||
placement?: string;
|
||||
centralConnection?: number;
|
||||
}
|
||||
|
||||
export interface AddMessageParams {
|
||||
@@ -51,8 +50,6 @@ export interface AddMessageParams {
|
||||
| 'destroyParticipant'
|
||||
| 'activeStart'
|
||||
| 'activeEnd'
|
||||
| 'centralConnection'
|
||||
| 'centralConnectionReverse'
|
||||
| 'addNote'
|
||||
| 'addLinks'
|
||||
| 'addALink'
|
||||
|
@@ -40,26 +40,105 @@ const openSourceFeatures: Feature[] = [
|
||||
{ iconUrl: '/icons/version-history.svg', featureName: 'Version history' },
|
||||
];
|
||||
|
||||
const editorColumns: EditorColumn[] = [
|
||||
{
|
||||
title: 'Mermaid Pro',
|
||||
description: 'Unlock AI and real-time collaboration',
|
||||
highlighted: true,
|
||||
redBarText: 'Recommended',
|
||||
proTrialButtonText: 'Start free trial',
|
||||
proTrialUrl:
|
||||
'https://www.mermaidchart.com/app/sign-up?utm_source=mermaid_js&utm_medium=2_editor_selection&utm_campaign=start_pro&redirect=%2Fapp%2Fuser%2Fbilling%2Fcheckout%3FisFromMermaid%3Dtrue',
|
||||
features: mermaidChartFeatures,
|
||||
},
|
||||
{
|
||||
title: 'Open Source',
|
||||
description: 'Code only, no login',
|
||||
buttonText: 'Start free',
|
||||
redirectUrl: 'https://mermaid.live/edit',
|
||||
features: openSourceFeatures,
|
||||
},
|
||||
const playgroundFeatures: Feature[] = [
|
||||
{ iconUrl: '/icons/public.svg', featureName: 'Diagram stored in URL' },
|
||||
{ iconUrl: '/icons/terminal.svg', featureName: 'Code editor' },
|
||||
{ iconUrl: '/icons/whiteboard.svg', featureName: 'Whiteboard' },
|
||||
];
|
||||
|
||||
const editorColumnVariants: EditorColumn[][] = [
|
||||
[
|
||||
{
|
||||
title: 'Playground',
|
||||
description: 'Basic features, no login',
|
||||
redirectUrl:
|
||||
'https://www.mermaidchart.com/app/sign-up?utm_source=mermaid_js&utm_medium=3_editor_selection_A&utm_campaign=start_playground',
|
||||
buttonText: 'Start free',
|
||||
features: playgroundFeatures,
|
||||
},
|
||||
{
|
||||
title: 'Free or Pro',
|
||||
description: 'Advanced features, Free or Pro account',
|
||||
proTrialUrl:
|
||||
'https://www.mermaidchart.com/app/sign-up?utm_source=mermaid_js&utm_medium=3_editor_selection_A&utm_campaign=start_free',
|
||||
proTrialButtonText: 'Start free',
|
||||
highlighted: true,
|
||||
redBarText: 'Best for collaboration',
|
||||
features: mermaidChartFeatures,
|
||||
},
|
||||
{
|
||||
title: 'Open Source',
|
||||
description: 'Code only, no login',
|
||||
redirectUrl: 'https://mermaid.live/edit',
|
||||
buttonText: 'Start free',
|
||||
features: openSourceFeatures,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
title: 'Mermaid Pro',
|
||||
description: 'Unlock AI and real-time collaboration',
|
||||
redirectUrl:
|
||||
'https://www.mermaidchart.com/app/sign-up?utm_source=mermaid_js&utm_medium=editor_selection_B&utm_campaign=start_free',
|
||||
buttonText: 'Start Free',
|
||||
highlighted: true,
|
||||
redBarText: 'Recommended',
|
||||
proTrialButtonText: 'Start Pro trial',
|
||||
proTrialUrl:
|
||||
'https://www.mermaidchart.com/app/sign-up?utm_source=mermaid_js&utm_medium=editor_selection_B&utm_campaign=start_trial&redirect=%2Fapp%2Fuser%2Fbilling%2Fcheckout%3FisFromMermaid%3Dtrue',
|
||||
features: mermaidChartFeatures,
|
||||
},
|
||||
{
|
||||
title: 'Open Source',
|
||||
description: 'Code only, no login',
|
||||
buttonText: 'Start free',
|
||||
redirectUrl: 'https://mermaid.live/edit',
|
||||
isButtonMargined: true,
|
||||
features: openSourceFeatures,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
title: 'Mermaid Pro',
|
||||
description: 'Unlock AI and real-time collaboration',
|
||||
highlighted: true,
|
||||
redBarText: 'Recommended',
|
||||
proTrialButtonText: 'Start free trial',
|
||||
proTrialUrl:
|
||||
'https://www.mermaidchart.com/app/sign-up?utm_source=mermaid_js&utm_medium=editor_selection_C&utm_campaign=start_trial&redirect=%2Fapp%2Fuser%2Fbilling%2Fcheckout%3FisFromMermaid%3Dtrue',
|
||||
features: mermaidChartFeatures,
|
||||
},
|
||||
{
|
||||
title: 'Open Source',
|
||||
description: 'Code only, no login',
|
||||
buttonText: 'Start free',
|
||||
redirectUrl: 'https://mermaid.live/edit',
|
||||
features: openSourceFeatures,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
title: 'Mermaid Pro',
|
||||
description: 'Unlock AI and real-time collaboration',
|
||||
highlighted: true,
|
||||
redBarText: 'Recommended',
|
||||
proTrialButtonText: 'Start free',
|
||||
proTrialUrl:
|
||||
'https://www.mermaidchart.com/app/sign-up?utm_source=mermaid_js&utm_medium=editor_selection_D&utm_campaign=start_free',
|
||||
features: mermaidChartFeatures,
|
||||
},
|
||||
{
|
||||
title: 'Open Source',
|
||||
description: 'Code only, no login',
|
||||
redirectUrl: 'https://mermaid.live/edit',
|
||||
buttonText: 'Start free',
|
||||
features: openSourceFeatures,
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
const editorColumns = editorColumnVariants[Math.floor(Math.random() * editorColumnVariants.length)];
|
||||
|
||||
const isVisible = ref(false);
|
||||
|
||||
const handleMouseDown = (e: MouseEvent) => {
|
||||
|
@@ -17,6 +17,7 @@ While directives allow you to change most of the default configuration settings,
|
||||
Mermaid basically supports two types of configuration options to be overridden by directives.
|
||||
|
||||
1. _General/Top Level configurations_ : These are the configurations that are available and applied to all the diagram. **Some of the most important top-level** configurations are:
|
||||
|
||||
- theme
|
||||
- fontFamily
|
||||
- logLevel
|
||||
|
@@ -23,6 +23,7 @@ Try the Ultimate AI, Mermaid, and Visual Diagramming Suite by creating an accoun
|
||||
- **Plugins** - A plugin system for extending the functionality of Mermaid.
|
||||
|
||||
Official Mermaid Chart plugins:
|
||||
|
||||
- [Mermaid Chart GPT](https://chatgpt.com/g/g-684cc36f30208191b21383b88650a45d-mermaid-chart-diagrams-and-charts)
|
||||
- [Confluence](https://marketplace.atlassian.com/apps/1234056/mermaid-chart-for-confluence?hosting=cloud&tab=overview)
|
||||
- [Jira](https://marketplace.atlassian.com/apps/1234810/mermaid-chart-for-jira?tab=overview&hosting=cloud)
|
||||
|
@@ -33,11 +33,13 @@ The Mermaid Chart team is excited to introduce a new Visual Editor for Flowchart
|
||||
Learn more:
|
||||
|
||||
- Visual Editor For Flowcharts
|
||||
|
||||
- [Blog post](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts)
|
||||
|
||||
- [Demo video](https://www.youtube.com/watch?v=5aja0gijoO0)
|
||||
|
||||
- Visual Editor For Sequence diagrams
|
||||
|
||||
- [Blog post](https://www.mermaidchart.com/blog/posts/mermaid-chart-unveils-visual-editor-for-sequence-diagrams)
|
||||
|
||||
- [Demo video](https://youtu.be/imc2u5_N6Dc)
|
||||
|
@@ -1,17 +1,5 @@
|
||||
# Blog
|
||||
|
||||
## [The Essential Guide to Mermaid Chart Plugin for VS Code [08/2025]](https://docs.mermaidchart.com/blog/posts/the-essential-guide-to-mermaid-chart-plugin-for-vs-code-08-2025)
|
||||
|
||||
9/9/2025 • 5 mins
|
||||
|
||||
Creating diagrams in VS Code has never been easier—the Mermaid VS Code plugin transforms text-based syntax into clear, professional visuals right inside your editor. With live previews, smart editing, and AI-powered diagram generation, it removes the friction from visualization so you can focus on coding.
|
||||
|
||||
## [How to Create Perfect Flowcharts Using AI in 2025 Step-by-Step Guide](https://docs.mermaidchart.com/blog/posts/how-to-create-perfect-flowcharts-using-ai-in-2025-step-by-step-guide)
|
||||
|
||||
7/22/2025 • 8 mins
|
||||
|
||||
In 2025, AI tools make creating flowcharts faster and easier than ever. With Mermaid’s AI flowchart generator, you can turn plain text into clear, accurate diagrams in seconds. This guide walks through how it works and how to get the most out of it for technical and business workflows alike.
|
||||
|
||||
## [Mermaid introduces the Visual Editor for Entity Relationship diagrams](https://docs.mermaidchart.com/blog/posts/mermaid-introduces-the-visual-editor-for-entity-relationship-diagrams)
|
||||
|
||||
7/15/2025 • 7 mins
|
||||
|
@@ -17,25 +17,25 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@vueuse/core": "^13.9.0",
|
||||
"@vueuse/core": "^13.1.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"jiti": "^2.4.2",
|
||||
"mermaid": "workspace:^",
|
||||
"vue": "^3.5.21"
|
||||
"vue": "^3.4.38"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/carbon": "^1.2.13",
|
||||
"@unocss/reset": "^66.5.1",
|
||||
"@iconify-json/carbon": "^1.1.37",
|
||||
"@unocss/reset": "^66.0.0",
|
||||
"@vite-pwa/vitepress": "^1.0.0",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@vitejs/plugin-vue": "^6.0.0",
|
||||
"fast-glob": "^3.3.3",
|
||||
"https-localhost": "^4.7.1",
|
||||
"pathe": "^2.0.3",
|
||||
"unocss": "^66.5.1",
|
||||
"unplugin-vue-components": "^28.4.1",
|
||||
"vite": "^7.0.7",
|
||||
"vite-plugin-pwa": "^1.0.3",
|
||||
"vitepress": "1.6.4",
|
||||
"unocss": "^66.4.2",
|
||||
"unplugin-vue-components": "^28.4.0",
|
||||
"vite": "^7.0.0",
|
||||
"vite-plugin-pwa": "^1.0.0",
|
||||
"vitepress": "1.6.3",
|
||||
"workbox-window": "^7.3.0"
|
||||
}
|
||||
}
|
||||
|
@@ -156,7 +156,7 @@ architecture-beta
|
||||
## Icons
|
||||
|
||||
By default, architecture diagram supports the following icons: `cloud`, `database`, `disk`, `internet`, `server`.
|
||||
Users can use any of the 200,000+ icons available in iconify.design, or add other custom icons, by [registering an icon pack](../config/icons.md).
|
||||
Users can use any of the 200,000+ icons available in iconify.design, or [add custom icons](../config/icons.md).
|
||||
|
||||
After the icons are installed, they can be used in the architecture diagram by using the format "name:icon-name", where name is the value used when registering the icon pack.
|
||||
|
||||
|
@@ -83,6 +83,7 @@ The following unfinished features are not supported in the short term.
|
||||
- [ ] Legend
|
||||
|
||||
- [x] System Context
|
||||
|
||||
- [x] Person(alias, label, ?descr, ?sprite, ?tags, $link)
|
||||
- [x] Person_Ext
|
||||
- [x] System(alias, label, ?descr, ?sprite, ?tags, $link)
|
||||
@@ -96,6 +97,7 @@ The following unfinished features are not supported in the short term.
|
||||
- [x] System_Boundary
|
||||
|
||||
- [x] Container diagram
|
||||
|
||||
- [x] Container(alias, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
- [x] ContainerDb
|
||||
- [x] ContainerQueue
|
||||
@@ -105,6 +107,7 @@ The following unfinished features are not supported in the short term.
|
||||
- [x] Container_Boundary(alias, label, ?tags, $link)
|
||||
|
||||
- [x] Component diagram
|
||||
|
||||
- [x] Component(alias, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
- [x] ComponentDb
|
||||
- [x] ComponentQueue
|
||||
@@ -113,15 +116,18 @@ The following unfinished features are not supported in the short term.
|
||||
- [x] ComponentQueue_Ext
|
||||
|
||||
- [x] Dynamic diagram
|
||||
|
||||
- [x] RelIndex(index, from, to, label, ?tags, $link)
|
||||
|
||||
- [x] Deployment diagram
|
||||
|
||||
- [x] Deployment_Node(alias, label, ?type, ?descr, ?sprite, ?tags, $link)
|
||||
- [x] Node(alias, label, ?type, ?descr, ?sprite, ?tags, $link): short name of Deployment_Node()
|
||||
- [x] Node_L(alias, label, ?type, ?descr, ?sprite, ?tags, $link): left aligned Node()
|
||||
- [x] Node_R(alias, label, ?type, ?descr, ?sprite, ?tags, $link): right aligned Node()
|
||||
|
||||
- [x] Relationship Types
|
||||
|
||||
- [x] Rel(from, to, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
- [x] BiRel (bidirectional relationship)
|
||||
- [x] Rel_U, Rel_Up
|
||||
|
@@ -15,7 +15,7 @@ title: Animal example
|
||||
classDiagram
|
||||
note "From Duck till Zebra"
|
||||
Animal <|-- Duck
|
||||
note for Duck "can fly<br>can swim<br>can dive<br>can help in debugging"
|
||||
note for Duck "can fly\ncan swim\ncan dive\ncan help in debugging"
|
||||
Animal <|-- Fish
|
||||
Animal <|-- Zebra
|
||||
Animal : +int age
|
||||
@@ -358,19 +358,17 @@ It is possible to annotate classes with markers to provide additional metadata a
|
||||
- `<<Service>>` To represent a service class
|
||||
- `<<Enumeration>>` To represent an enum
|
||||
|
||||
Annotations are defined within the opening `<<` and closing `>>`. There are multiple ways to add an annotation to a class, which all result in the same output, and you can add multiple annotations by adding others on the same line:
|
||||
Annotations are defined within the opening `<<` and closing `>>`. There are two ways to add an annotation to a class, and either way the output will be same:
|
||||
|
||||
> **Tip:**
|
||||
> In Mermaid class diagrams, annotations like `<<interface>>` can be attached in two ways:
|
||||
>
|
||||
> - **Inline with the class definition** (Recommended for consistency):
|
||||
>
|
||||
> ```mermaid-example
|
||||
> classDiagram
|
||||
> class Shape <<interface>>
|
||||
> ```
|
||||
|
||||
> ```mermaid-example
|
||||
> classDiagram
|
||||
> class Shape <<interface>> <<injected>>
|
||||
> ```
|
||||
>
|
||||
> - **Separate line after the class definition**:
|
||||
>
|
||||
@@ -380,18 +378,25 @@ Annotations are defined within the opening `<<` and closing `>>`. There are mult
|
||||
> <<interface>> Shape
|
||||
> ```
|
||||
>
|
||||
> ```mermaid-example
|
||||
> classDiagram
|
||||
> class Shape
|
||||
> <<interface>> <<injected>> Shape
|
||||
> ```
|
||||
> Both methods are fully supported and produce identical diagrams.
|
||||
> However, it is recommended to use the **inline style** for better readability and consistent formatting across diagrams.
|
||||
|
||||
> In a **_nested structure_** along with the class definition:
|
||||
- In a **_separate line_** after a class is defined:
|
||||
|
||||
```mermaid-example
|
||||
classDiagram
|
||||
class Shape
|
||||
<<interface>> Shape
|
||||
Shape : noOfVertices
|
||||
Shape : draw()
|
||||
```
|
||||
|
||||
- In a **_nested structure_** along with the class definition:
|
||||
|
||||
```mermaid-example
|
||||
classDiagram
|
||||
class Shape{
|
||||
<<interface>> <<injected>>
|
||||
<<interface>>
|
||||
noOfVertices
|
||||
draw()
|
||||
}
|
||||
|
@@ -216,11 +216,7 @@ Messages can be of two displayed either solid or with a dotted line.
|
||||
[Actor][Arrow][Actor]:Message text
|
||||
```
|
||||
|
||||
Lines can be solid or dotted, and can end with various types of arrowheads, crosses, or open arrows.
|
||||
|
||||
#### Supported Arrow Types
|
||||
|
||||
**Standard Arrow Types**
|
||||
There are ten types of arrows currently supported:
|
||||
|
||||
| Type | Description |
|
||||
| -------- | ---------------------------------------------------- |
|
||||
@@ -235,49 +231,6 @@ Lines can be solid or dotted, and can end with various types of arrowheads, cros
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
|
||||
**Half-Arrows (v<MERMAID_RELEASE_VERSION>+)**
|
||||
|
||||
The following half-arrow types are supported for more expressive sequence diagrams. Both solid and dotted variants are available by increasing the number of dashes (`-` → `--`).
|
||||
|
||||
---
|
||||
|
||||
| Type | Description |
|
||||
| ------- | ---------------------------------------------------- |
|
||||
| `-\|\` | Solid line with top half arrowhead |
|
||||
| `--\|\` | Dotted line with top half arrowhead |
|
||||
| `-\|/` | Solid line with bottom half arrowhead |
|
||||
| `--\|/` | Dotted line with bottom half arrowhead |
|
||||
| `/\|-` | Solid line with reverse top half arrowhead |
|
||||
| `/\|--` | Dotted line with reverse top half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom half arrowhead |
|
||||
| `-\\` | Solid line with top stick half arrowhead |
|
||||
| `--\\` | Dotted line with top stick half arrowhead |
|
||||
| `-//` | Solid line with bottom stick half arrowhead |
|
||||
| `--//` | Dotted line with bottom stick half arrowhead |
|
||||
| `//-` | Solid line with reverse top stick half arrowhead |
|
||||
| `//--` | Dotted line with reverse top stick half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom stick half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom stick half arrowhead |
|
||||
|
||||
## Central Connections (v<MERMAID_RELEASE_VERSION>+)
|
||||
|
||||
Mermaid sequence diagrams support **central lifeline connections** using a `()`.
|
||||
This is useful to represent messages or signals that connect to a central point, rather than from one actor directly to another.
|
||||
|
||||
To indicate a central connection, append `()` to the arrow syntax.
|
||||
|
||||
#### Basic Syntax
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
Alice->>()John: Hello John
|
||||
Alice()->>John: How are you?
|
||||
John()->>()Alice: Great!
|
||||
```
|
||||
|
||||
## Activations
|
||||
|
||||
It is possible to activate and deactivate an actor. (de)activation can be dedicated declarations:
|
||||
|
@@ -207,7 +207,7 @@ describe('when using mermaid and ', () => {
|
||||
[Error: Parse error on line 2:
|
||||
...equenceDiagramAlice:->Bob: Hello Bob, h...
|
||||
----------------------^
|
||||
Expecting '()', 'SOLID_OPEN_ARROW', 'DOTTED_OPEN_ARROW', 'SOLID_ARROW', 'SOLID_ARROW_TOP', 'SOLID_ARROW_BOTTOM', 'STICK_ARROW_TOP', 'STICK_ARROW_BOTTOM', 'SOLID_ARROW_TOP_DOTTED', 'SOLID_ARROW_BOTTOM_DOTTED', 'STICK_ARROW_TOP_DOTTED', 'STICK_ARROW_BOTTOM_DOTTED', 'SOLID_ARROW_TOP_REVERSE', 'SOLID_ARROW_BOTTOM_REVERSE', 'STICK_ARROW_TOP_REVERSE', 'STICK_ARROW_BOTTOM_REVERSE', 'SOLID_ARROW_TOP_REVERSE_DOTTED', 'SOLID_ARROW_BOTTOM_REVERSE_DOTTED', 'STICK_ARROW_TOP_REVERSE_DOTTED', 'STICK_ARROW_BOTTOM_REVERSE_DOTTED', 'BIDIRECTIONAL_SOLID_ARROW', 'DOTTED_ARROW', 'BIDIRECTIONAL_DOTTED_ARROW', 'SOLID_CROSS', 'DOTTED_CROSS', 'SOLID_POINT', 'DOTTED_POINT', got 'TXT']
|
||||
Expecting 'SOLID_OPEN_ARROW', 'DOTTED_OPEN_ARROW', 'SOLID_ARROW', 'BIDIRECTIONAL_SOLID_ARROW', 'DOTTED_ARROW', 'BIDIRECTIONAL_DOTTED_ARROW', 'SOLID_CROSS', 'DOTTED_CROSS', 'SOLID_POINT', 'DOTTED_POINT', got 'TXT']
|
||||
`);
|
||||
});
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { evaluate } from '../../diagrams/common/common.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { createText } from '../createText.js';
|
||||
import utils from '../../utils.js';
|
||||
@@ -45,8 +44,8 @@ export const getLabelStyles = (styleArray) => {
|
||||
};
|
||||
|
||||
export const insertEdgeLabel = async (elem, edge) => {
|
||||
let useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
|
||||
|
||||
const config = getConfig();
|
||||
let useHtmlLabels = config.flowchart.htmlLabels;
|
||||
const { labelStyles } = styles2String(edge);
|
||||
edge.labelStyle = labelStyles;
|
||||
const labelElement = await createText(elem, edge.label, {
|
||||
@@ -605,14 +604,6 @@ export const insertEdge = function (
|
||||
const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style];
|
||||
let strokeColor = edgeStyles.find((style) => style?.startsWith('stroke:'));
|
||||
|
||||
let animationClass = '';
|
||||
if (edge.animate) {
|
||||
animationClass = 'edge-animation-fast';
|
||||
}
|
||||
if (edge.animation) {
|
||||
animationClass = 'edge-animation-' + edge.animation;
|
||||
}
|
||||
|
||||
let animatedEdge = false;
|
||||
if (edge.look === 'handDrawn') {
|
||||
const rc = rough.svg(elem);
|
||||
@@ -628,13 +619,7 @@ export const insertEdge = function (
|
||||
svgPath = select(svgPathNode)
|
||||
.select('path')
|
||||
.attr('id', edge.id)
|
||||
.attr(
|
||||
'class',
|
||||
' ' +
|
||||
strokeClasses +
|
||||
(edge.classes ? ' ' + edge.classes : '') +
|
||||
(animationClass ? ' ' + animationClass : '')
|
||||
)
|
||||
.attr('class', ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : ''))
|
||||
.attr('style', edgeStyles ? edgeStyles.reduce((acc, style) => acc + ';' + style, '') : '');
|
||||
let d = svgPath.attr('d');
|
||||
svgPath.attr('d', d);
|
||||
@@ -642,6 +627,13 @@ export const insertEdge = function (
|
||||
} else {
|
||||
const stylesFromClasses = edgeClassStyles.join(';');
|
||||
const styles = edgeStyles ? edgeStyles.reduce((acc, style) => acc + style + ';', '') : '';
|
||||
let animationClass = '';
|
||||
if (edge.animate) {
|
||||
animationClass = ' edge-animation-fast';
|
||||
}
|
||||
if (edge.animation) {
|
||||
animationClass = ' edge-animation-' + edge.animation;
|
||||
}
|
||||
|
||||
const pathStyle =
|
||||
(stylesFromClasses ? stylesFromClasses + ';' + styles + ';' : styles) +
|
||||
@@ -653,10 +645,7 @@ export const insertEdge = function (
|
||||
.attr('id', edge.id)
|
||||
.attr(
|
||||
'class',
|
||||
' ' +
|
||||
strokeClasses +
|
||||
(edge.classes ? ' ' + edge.classes : '') +
|
||||
(animationClass ? ' ' + animationClass : '')
|
||||
' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : '') + (animationClass ?? '')
|
||||
)
|
||||
.attr('style', pathStyle);
|
||||
|
||||
|
@@ -130,6 +130,7 @@ const lollipop = (elem, type, id) => {
|
||||
.attr('markerHeight', 240)
|
||||
.attr('orient', 'auto')
|
||||
.append('circle')
|
||||
.attr('stroke', 'black')
|
||||
.attr('fill', 'transparent')
|
||||
.attr('cx', 7)
|
||||
.attr('cy', 7)
|
||||
@@ -146,6 +147,7 @@ const lollipop = (elem, type, id) => {
|
||||
.attr('markerHeight', 240)
|
||||
.attr('orient', 'auto')
|
||||
.append('circle')
|
||||
.attr('stroke', 'black')
|
||||
.attr('fill', 'transparent')
|
||||
.attr('cx', 7)
|
||||
.attr('cy', 7)
|
||||
|
@@ -13,7 +13,7 @@ export const labelHelper = async <T extends SVGGraphicsElement>(
|
||||
_classes?: string
|
||||
) => {
|
||||
let cssClasses;
|
||||
const useHtmlLabels = node.useHtmlLabels || evaluate(getConfig()?.htmlLabels);
|
||||
const useHtmlLabels = node.useHtmlLabels || evaluate(getConfig()?.flowchart?.htmlLabels);
|
||||
if (!_classes) {
|
||||
cssClasses = 'node default';
|
||||
} else {
|
||||
|
@@ -44,15 +44,18 @@ ValueConverter -->> Package: Return AST
|
||||
```
|
||||
|
||||
- When to override `TokenBuilder`?
|
||||
|
||||
- To override keyword rules.
|
||||
- To override terminal rules that need a custom function.
|
||||
- To manually reorder the list of rules.
|
||||
|
||||
- When to override `Lexer`?
|
||||
|
||||
- To modify input before tokenizing.
|
||||
- To insert/modify tokens that cannot or have not been parsed.
|
||||
|
||||
- When to override `LangiumParser`?
|
||||
|
||||
- To insert or modify attributes that can't be parsed.
|
||||
|
||||
- When to override `ValueConverter`?
|
||||
|
@@ -1,19 +1,5 @@
|
||||
# mermaid
|
||||
|
||||
## 11.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#6704](https://github.com/mermaid-js/mermaid/pull/6704) [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05) Thanks [@omkarht](https://github.com/omkarht)! - feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
|
||||
|
||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6905](https://github.com/mermaid-js/mermaid/pull/6905) [`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Render newlines as spaces in class diagrams
|
||||
|
||||
- [#6886](https://github.com/mermaid-js/mermaid/pull/6886) [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Handle arrows correctly when auto number is enabled
|
||||
|
||||
## 11.10.0
|
||||
|
||||
### Minor Changes
|
||||
@@ -168,6 +154,7 @@
|
||||
### Minor Changes
|
||||
|
||||
- [#6408](https://github.com/mermaid-js/mermaid/pull/6408) [`ad65313`](https://github.com/mermaid-js/mermaid/commit/ad653138e16765d095613a6e5de86dc5e52ac8f0) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: restore curve type configuration functionality for flowcharts. This fixes the issue where curve type settings were not being applied when configured through any of the following methods:
|
||||
|
||||
- Config
|
||||
- Init directive (%%{ init: { 'flowchart': { 'curve': '...' } } }%%)
|
||||
- LinkStyle command (linkStyle default interpolate ...)
|
||||
@@ -186,12 +173,14 @@
|
||||
### Minor Changes
|
||||
|
||||
- [#6187](https://github.com/mermaid-js/mermaid/pull/6187) [`7809b5a`](https://github.com/mermaid-js/mermaid/commit/7809b5a93fae127f45727071f5ff14325222c518) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - Flowchart new syntax for node metadata bugs
|
||||
|
||||
- Incorrect label mapping for nodes when using `&`
|
||||
- Syntax error when `}` with trailing spaces before new line
|
||||
|
||||
- [#6136](https://github.com/mermaid-js/mermaid/pull/6136) [`ec0d9c3`](https://github.com/mermaid-js/mermaid/commit/ec0d9c389aa6018043187654044c1e0b5aa4f600) Thanks [@knsv](https://github.com/knsv)! - Adding support for animation of flowchart edges
|
||||
|
||||
- [#6373](https://github.com/mermaid-js/mermaid/pull/6373) [`05bdf0e`](https://github.com/mermaid-js/mermaid/commit/05bdf0e20e2629fe77513218fbd4e28e65f75882) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - Upgrade Requirement and ER diagram to use the common renderer flow
|
||||
|
||||
- Added support for directions
|
||||
- Added support for hand drawn look
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mermaid-js/tiny",
|
||||
"version": "11.11.0",
|
||||
"version": "11.10.0",
|
||||
"description": "Tiny version of mermaid",
|
||||
"type": "commonjs",
|
||||
"main": "./dist/mermaid.tiny.js",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user