mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-27 20:26:47 +02:00
Compare commits
2 Commits
6638-seque
...
renovate/p
Author | SHA1 | Date | |
---|---|---|---|
![]() |
23fd1c59e6 | ||
![]() |
ee5969bc1e |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Add half-arrowheads (solid & stick) and central connection support
|
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
uses: github/codeql-action/init@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||
with:
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
languages: ${{ matrix.language }}
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
uses: github/codeql-action/autobuild@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
@@ -62,4 +62,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
uses: github/codeql-action/analyze@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||
|
2
.github/workflows/e2e-applitools.yml
vendored
2
.github/workflows/e2e-applitools.yml
vendored
@@ -56,7 +56,7 @@ jobs:
|
||||
args: -X POST "$APPLITOOLS_SERVER_URL/api/externals/github/push?apiKey=$APPLITOOLS_API_KEY&CommitSha=$GITHUB_SHA&BranchName=${APPLITOOLS_BRANCH}$&ParentBranchName=$APPLITOOLS_PARENT_BRANCH"
|
||||
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
id: cypress
|
||||
with:
|
||||
start: pnpm run dev
|
||||
|
4
.github/workflows/e2e-timings.yml
vendored
4
.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@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
with:
|
||||
runTests: false
|
||||
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
id: cypress
|
||||
with:
|
||||
install: false
|
||||
|
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@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
with:
|
||||
path: ./cypress/snapshots
|
||||
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
with:
|
||||
# just perform install
|
||||
runTests: false
|
||||
@@ -95,13 +95,13 @@ jobs:
|
||||
# These cached snapshots are downloaded, providing the reference snapshots.
|
||||
- name: Cache snapshots
|
||||
id: cache-snapshot
|
||||
uses: actions/cache/restore@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
|
||||
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
with:
|
||||
path: ./cypress/snapshots
|
||||
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
||||
|
||||
- name: Install dependencies
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
with:
|
||||
runTests: false
|
||||
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
# Install NPM dependencies, cache them correctly
|
||||
# and run all Cypress tests
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16
|
||||
id: cypress
|
||||
with:
|
||||
install: false
|
||||
|
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@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
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@c8bada60c408975afd1a20b3db81d6eee6789308 # v1.4.9
|
||||
uses: changesets/action@06245a4e0a36c064a573d4150030f5ec548e4fcc # v1.4.10
|
||||
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@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
|
||||
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
publish_results: true
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
- name: Upload to code-scanning
|
||||
uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
uses: github/codeql-action/upload-sarif@5378192d256ef1302a6980fffe5ca04426d43091 # v3.28.21
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
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@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
||||
with:
|
||||
branch: update-browserslist
|
||||
title: Update Browserslist
|
||||
|
@@ -1,659 +0,0 @@
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||
|
||||
const looks = ['classic'];
|
||||
const participantTypes = [
|
||||
{ type: 'participant', display: 'participant' },
|
||||
{ type: 'actor', display: 'actor' },
|
||||
{ type: 'boundary', display: 'boundary' },
|
||||
{ type: 'control', display: 'control' },
|
||||
{ type: 'entity', display: 'entity' },
|
||||
{ type: 'database', display: 'database' },
|
||||
{ type: 'collections', display: 'collections' },
|
||||
{ type: 'queue', display: 'queue' },
|
||||
];
|
||||
|
||||
const restrictedTypes = ['boundary', 'control', 'entity', 'database', 'collections', 'queue'];
|
||||
|
||||
const interactionTypes = ['->>', '-->>', '->', '-->', '-x', '--x', '->>+', '-->>+'];
|
||||
|
||||
const notePositions = ['left of', 'right of', 'over'];
|
||||
|
||||
function getParticipantLine(name, type, alias) {
|
||||
if (restrictedTypes.includes(type)) {
|
||||
return ` participant ${name}@{ "type" : "${type}" }\n`;
|
||||
} else if (alias) {
|
||||
return ` participant ${name}@{ "type" : "${type}" } \n`;
|
||||
} else {
|
||||
return ` participant ${name}@{ "type" : "${type}" }\n`;
|
||||
}
|
||||
}
|
||||
|
||||
looks.forEach((look) => {
|
||||
describe(`Sequence Diagram Tests - ${look} look`, () => {
|
||||
it('should render all participant types', () => {
|
||||
let diagramCode = `sequenceDiagram\n`;
|
||||
participantTypes.forEach((pt, index) => {
|
||||
const name = `${pt.display}${index}`;
|
||||
diagramCode += getParticipantLine(name, pt.type);
|
||||
});
|
||||
for (let i = 0; i < participantTypes.length - 1; i++) {
|
||||
diagramCode += ` ${participantTypes[i].display}${i} ->> ${participantTypes[i + 1].display}${i + 1}: Message ${i}\n`;
|
||||
}
|
||||
imgSnapshotTest(diagramCode, { look, sequence: { diagramMarginX: 50, diagramMarginY: 10 } });
|
||||
});
|
||||
|
||||
it('should render all interaction types', () => {
|
||||
let diagramCode = `sequenceDiagram\n`;
|
||||
diagramCode += getParticipantLine('A', 'actor');
|
||||
diagramCode += getParticipantLine('B', 'boundary');
|
||||
interactionTypes.forEach((interaction, index) => {
|
||||
diagramCode += ` A ${interaction} B: ${interaction} message ${index}\n`;
|
||||
});
|
||||
imgSnapshotTest(diagramCode, { look });
|
||||
});
|
||||
|
||||
it('should render participant creation and destruction', () => {
|
||||
let diagramCode = `sequenceDiagram\n`;
|
||||
participantTypes.forEach((pt, index) => {
|
||||
const name = `${pt.display}${index}`;
|
||||
diagramCode += getParticipantLine('A', pt.type);
|
||||
diagramCode += getParticipantLine('B', pt.type);
|
||||
diagramCode += ` create participant ${name}@{ "type" : "${pt.type}" }\n`;
|
||||
diagramCode += ` A ->> ${name}: Hello ${pt.display}\n`;
|
||||
if (index % 2 === 0) {
|
||||
diagramCode += ` destroy ${name}\n`;
|
||||
}
|
||||
});
|
||||
imgSnapshotTest(diagramCode, { look });
|
||||
});
|
||||
|
||||
it('should render notes in all positions', () => {
|
||||
let diagramCode = `sequenceDiagram\n`;
|
||||
diagramCode += getParticipantLine('A', 'actor');
|
||||
diagramCode += getParticipantLine('B', 'boundary');
|
||||
notePositions.forEach((position, index) => {
|
||||
diagramCode += ` Note ${position} A: Note ${position} ${index}\n`;
|
||||
});
|
||||
diagramCode += ` A ->> B: Message with notes\n`;
|
||||
imgSnapshotTest(diagramCode, { look });
|
||||
});
|
||||
|
||||
it('should render parallel interactions', () => {
|
||||
let diagramCode = `sequenceDiagram\n`;
|
||||
participantTypes.slice(0, 4).forEach((pt, index) => {
|
||||
diagramCode += getParticipantLine(`${pt.display}${index}`, pt.type);
|
||||
});
|
||||
diagramCode += ` par Parallel actions\n`;
|
||||
for (let i = 0; i < 3; i += 2) {
|
||||
diagramCode += ` ${participantTypes[i].display}${i} ->> ${participantTypes[i + 1].display}${i + 1}: Message ${i}\n`;
|
||||
if (i < participantTypes.length - 2) {
|
||||
diagramCode += ` and\n`;
|
||||
}
|
||||
}
|
||||
diagramCode += ` end\n`;
|
||||
imgSnapshotTest(diagramCode, { look });
|
||||
});
|
||||
|
||||
it('should render alternative flows', () => {
|
||||
let diagramCode = `sequenceDiagram\n`;
|
||||
diagramCode += getParticipantLine('A', 'actor');
|
||||
diagramCode += getParticipantLine('B', 'boundary');
|
||||
diagramCode += ` alt Successful case\n`;
|
||||
diagramCode += ` A ->> B: Request\n`;
|
||||
diagramCode += ` B -->> A: Success\n`;
|
||||
diagramCode += ` else Failure case\n`;
|
||||
diagramCode += ` A ->> B: Request\n`;
|
||||
diagramCode += ` B --x A: Failure\n`;
|
||||
diagramCode += ` end\n`;
|
||||
imgSnapshotTest(diagramCode, { look });
|
||||
});
|
||||
|
||||
it('should render loops', () => {
|
||||
let diagramCode = `sequenceDiagram\n`;
|
||||
participantTypes.slice(0, 3).forEach((pt, index) => {
|
||||
diagramCode += getParticipantLine(`${pt.display}${index}`, pt.type);
|
||||
});
|
||||
diagramCode += ` loop For each participant\n`;
|
||||
for (let i = 0; i < 3; i++) {
|
||||
diagramCode += ` ${participantTypes[0].display}0 ->> ${participantTypes[1].display}1: Message ${i}\n`;
|
||||
}
|
||||
diagramCode += ` end\n`;
|
||||
imgSnapshotTest(diagramCode, { look });
|
||||
});
|
||||
|
||||
it('should render boxes around groups', () => {
|
||||
let diagramCode = `sequenceDiagram\n`;
|
||||
diagramCode += ` box Group 1\n`;
|
||||
participantTypes.slice(0, 3).forEach((pt, index) => {
|
||||
diagramCode += ` ${getParticipantLine(`${pt.display}${index}`, pt.type)}`;
|
||||
});
|
||||
diagramCode += ` end\n`;
|
||||
diagramCode += ` box rgb(200,220,255) Group 2\n`;
|
||||
participantTypes.slice(3, 6).forEach((pt, index) => {
|
||||
diagramCode += ` ${getParticipantLine(`${pt.display}${index}`, pt.type)}`;
|
||||
});
|
||||
diagramCode += ` end\n`;
|
||||
diagramCode += ` ${participantTypes[0].display}0 ->> ${participantTypes[3].display}0: Cross-group message\n`;
|
||||
imgSnapshotTest(diagramCode, { look });
|
||||
});
|
||||
|
||||
it('should render with different font settings', () => {
|
||||
let diagramCode = `sequenceDiagram\n`;
|
||||
participantTypes.slice(0, 3).forEach((pt, index) => {
|
||||
diagramCode += getParticipantLine(`${pt.display}${index}`, pt.type);
|
||||
});
|
||||
diagramCode += ` ${participantTypes[0].display}0 ->> ${participantTypes[1].display}1: Regular message\n`;
|
||||
diagramCode += ` Note right of ${participantTypes[1].display}1: Regular note\n`;
|
||||
imgSnapshotTest(diagramCode, {
|
||||
look,
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
actorFontSize: 14,
|
||||
messageFontFamily: 'Arial',
|
||||
messageFontSize: 12,
|
||||
noteFontFamily: 'times',
|
||||
noteFontSize: 16,
|
||||
noteAlign: 'left',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Additional tests for specific combinations
|
||||
describe('Sequence Diagram Special Cases', () => {
|
||||
it('should render complex sequence with all features', () => {
|
||||
const diagramCode = `
|
||||
sequenceDiagram
|
||||
box rgb(200,220,255) Authentication
|
||||
actor User
|
||||
participant LoginUI@{ "type": "boundary" }
|
||||
participant AuthService@{ "type": "control" }
|
||||
participant UserDB@{ "type": "database" }
|
||||
end
|
||||
|
||||
box rgb(200,255,220) Order Processing
|
||||
participant Order@{ "type": "entity" }
|
||||
participant OrderQueue@{ "type": "queue" }
|
||||
participant AuditLogs@{ "type": "collections" }
|
||||
end
|
||||
|
||||
User ->> LoginUI: Enter credentials
|
||||
LoginUI ->> AuthService: Validate
|
||||
AuthService ->> UserDB: Query user
|
||||
UserDB -->> AuthService: User data
|
||||
alt Valid credentials
|
||||
AuthService -->> LoginUI: Success
|
||||
LoginUI -->> User: Welcome
|
||||
|
||||
par Place order
|
||||
User ->> Order: New order
|
||||
Order ->> OrderQueue: Process
|
||||
and
|
||||
Order ->> AuditLogs: Record
|
||||
end
|
||||
|
||||
loop Until confirmed
|
||||
OrderQueue ->> Order: Update status
|
||||
Order -->> User: Notification
|
||||
end
|
||||
else Invalid credentials
|
||||
AuthService --x LoginUI: Failure
|
||||
LoginUI --x User: Retry
|
||||
end
|
||||
`;
|
||||
imgSnapshotTest(diagramCode, {});
|
||||
});
|
||||
|
||||
it('should render with wrapped messages and notes', () => {
|
||||
const diagramCode = `
|
||||
sequenceDiagram
|
||||
participant A
|
||||
participant B
|
||||
|
||||
A ->> B: This is a very long message that should wrap properly in the diagram rendering
|
||||
Note over A,B: This is a very long note that should also wrap properly when rendered in the diagram
|
||||
|
||||
par Wrapped parallel
|
||||
A ->> B: Parallel message 1<br>with explicit line break
|
||||
and
|
||||
B ->> A: Parallel message 2<br>with explicit line break
|
||||
end
|
||||
|
||||
loop Wrapped loop
|
||||
Note right of B: This is a long note<br>in a loop
|
||||
A ->> B: Message in loop
|
||||
end
|
||||
`;
|
||||
imgSnapshotTest(diagramCode, { sequence: { wrap: true } });
|
||||
});
|
||||
describe('Sequence Diagram Rendering with Different Participant Types', () => {
|
||||
it('should render a sequence diagram with various participant types', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant User@{ "type": "actor" }
|
||||
participant AuthService@{ "type": "control" }
|
||||
participant UI@{ "type": "boundary" }
|
||||
participant OrderController@{ "type": "control" }
|
||||
participant Product@{ "type": "entity" }
|
||||
participant MongoDB@{ "type": "database" }
|
||||
participant Products@{ "type": "collections" }
|
||||
participant OrderQueue@{ "type": "queue" }
|
||||
User ->> UI: Login request
|
||||
UI ->> AuthService: Validate credentials
|
||||
AuthService -->> UI: Authentication token
|
||||
UI ->> OrderController: Place order
|
||||
OrderController ->> Product: Check availability
|
||||
Product -->> OrderController: Available
|
||||
OrderController ->> MongoDB: Save order
|
||||
MongoDB -->> OrderController: Order saved
|
||||
OrderController ->> OrderQueue: Process payment
|
||||
OrderQueue -->> User: Order confirmation
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render participant creation and destruction with different types', () => {
|
||||
imgSnapshotTest(`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "boundary" }
|
||||
Alice->>Bob: Hello Bob, how are you ?
|
||||
Bob->>Alice: Fine, thank you. And you?
|
||||
create participant Carl@{ "type" : "control" }
|
||||
Alice->>Carl: Hi Carl!
|
||||
create actor D as Donald
|
||||
Carl->>D: Hi!
|
||||
destroy Carl
|
||||
Alice-xCarl: We are too many
|
||||
destroy Bob
|
||||
Bob->>Alice: I agree
|
||||
`);
|
||||
});
|
||||
|
||||
it('should handle complex interactions between different participant types', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
box rgb(200,220,255) Authentication
|
||||
participant User@{ "type": "actor" }
|
||||
participant LoginUI@{ "type": "boundary" }
|
||||
participant AuthService@{ "type": "control" }
|
||||
participant UserDB@{ "type": "database" }
|
||||
end
|
||||
|
||||
box rgb(200,255,220) Order Processing
|
||||
participant Order@{ "type": "entity" }
|
||||
participant OrderQueue@{ "type": "queue" }
|
||||
participant AuditLogs@{ "type": "collections" }
|
||||
end
|
||||
|
||||
User ->> LoginUI: Enter credentials
|
||||
LoginUI ->> AuthService: Validate
|
||||
AuthService ->> UserDB: Query user
|
||||
UserDB -->> AuthService: User data
|
||||
|
||||
alt Valid credentials
|
||||
AuthService -->> LoginUI: Success
|
||||
LoginUI -->> User: Welcome
|
||||
|
||||
par Place order
|
||||
User ->> Order: New order
|
||||
Order ->> OrderQueue: Process
|
||||
and
|
||||
Order ->> AuditLogs: Record
|
||||
end
|
||||
|
||||
loop Until confirmed
|
||||
OrderQueue ->> Order: Update status
|
||||
Order -->> User: Notification
|
||||
end
|
||||
else Invalid credentials
|
||||
AuthService --x LoginUI: Failure
|
||||
LoginUI --x User: Retry
|
||||
end
|
||||
`,
|
||||
{ sequence: { useMaxWidth: false } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render parallel processes with different participant types', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Customer@{ "type": "actor" }
|
||||
participant Frontend@{ "type": "participant" }
|
||||
participant PaymentService@{ "type": "boundary" }
|
||||
participant InventoryManager@{ "type": "control" }
|
||||
participant Order@{ "type": "entity" }
|
||||
participant OrdersDB@{ "type": "database" }
|
||||
participant NotificationQueue@{ "type": "queue" }
|
||||
|
||||
Customer ->> Frontend: Place order
|
||||
Frontend ->> Order: Create order
|
||||
par Parallel Processing
|
||||
Order ->> PaymentService: Process payment
|
||||
and
|
||||
Order ->> InventoryManager: Reserve items
|
||||
end
|
||||
PaymentService -->> Order: Payment confirmed
|
||||
InventoryManager -->> Order: Items reserved
|
||||
Order ->> OrdersDB: Save finalized order
|
||||
OrdersDB -->> Order: Order saved
|
||||
Order ->> NotificationQueue: Send confirmation
|
||||
NotificationQueue -->> Customer: Order confirmation
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
||||
it('should render different participant types with notes and loops', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
actor Admin
|
||||
participant Dashboard
|
||||
participant AuthService@{ "type" : "boundary" }
|
||||
participant UserManager@{ "type" : "control" }
|
||||
participant UserProfile@{ "type" : "entity" }
|
||||
participant UserDB@{ "type" : "database" }
|
||||
participant Logs@{ "type" : "database" }
|
||||
|
||||
Admin ->> Dashboard: Open user management
|
||||
loop Authentication check
|
||||
Dashboard ->> AuthService: Verify admin rights
|
||||
AuthService ->> Dashboard: Access granted
|
||||
end
|
||||
Dashboard ->> UserManager: List users
|
||||
UserManager ->> UserDB: Query users
|
||||
UserDB ->> UserManager: Return user data
|
||||
Note right of UserDB: Encrypted data<br/>requires decryption
|
||||
UserManager ->> UserProfile: Format profiles
|
||||
UserProfile ->> UserManager: Formatted data
|
||||
UserManager ->> Dashboard: Display users
|
||||
Dashboard ->> Logs: Record access
|
||||
Logs ->> Admin: Audit trail
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render different participant types with alternative flows', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
actor Client
|
||||
participant MobileApp
|
||||
participant CloudService@{ "type" : "boundary" }
|
||||
participant DataProcessor@{ "type" : "control" }
|
||||
participant Transaction@{ "type" : "entity" }
|
||||
participant TransactionsDB@{ "type" : "database" }
|
||||
participant EventBus@{ "type" : "queue" }
|
||||
|
||||
Client ->> MobileApp: Initiate transaction
|
||||
MobileApp ->> CloudService: Authenticate
|
||||
alt Authentication successful
|
||||
CloudService -->> MobileApp: Auth token
|
||||
MobileApp ->> DataProcessor: Process data
|
||||
DataProcessor ->> Transaction: Create transaction
|
||||
Transaction ->> TransactionsDB: Save record
|
||||
TransactionsDB -->> Transaction: Confirmation
|
||||
Transaction ->> EventBus: Publish event
|
||||
EventBus -->> Client: Notification
|
||||
else Authentication failed
|
||||
CloudService -->> MobileApp: Error
|
||||
MobileApp -->> Client: Show error
|
||||
end
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render different participant types with wrapping text', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant B@{ "type" : "boundary" }
|
||||
participant C@{ "type" : "control" }
|
||||
participant E@{ "type" : "entity" }
|
||||
participant DB@{ "type" : "database" }
|
||||
participant COL@{ "type" : "collections" }
|
||||
participant Q@{ "type" : "queue" }
|
||||
|
||||
FE ->> B: Another long message<br/>with explicit<br/>line breaks
|
||||
B -->> FE: Response message that is also quite long and needs to wrap
|
||||
FE ->> C: Process data
|
||||
C ->> E: Validate
|
||||
E -->> C: Validation result
|
||||
C ->> DB: Save
|
||||
DB -->> C: Save result
|
||||
C ->> COL: Log
|
||||
COL -->> Q: Forward
|
||||
Q -->> LongNameUser: Final response with confirmation of all actions taken
|
||||
`,
|
||||
{ sequence: { wrap: true } }
|
||||
);
|
||||
});
|
||||
|
||||
describe('Sequence Diagram - New Participant Types with Long Notes and Messages', () => {
|
||||
it('should render long notes left of boundary', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "boundary" }
|
||||
actor Bob
|
||||
Alice->>Bob: Hola
|
||||
Note left of Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
Bob->>Alice: I'm short though
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render wrapped long notes left of control', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "control" }
|
||||
actor Bob
|
||||
Alice->>Bob: Hola
|
||||
Note left of Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
Bob->>Alice: I'm short though
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render long notes right of entity', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "entity" }
|
||||
actor Bob
|
||||
Alice->>Bob: Hola
|
||||
Note right of Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
Bob->>Alice: I'm short though
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render wrapped long notes right of database', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "database" }
|
||||
actor Bob
|
||||
Alice->>Bob: Hola
|
||||
Note right of Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
Bob->>Alice: I'm short though
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render long notes over collections', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "collections" }
|
||||
actor Bob
|
||||
Alice->>Bob: Hola
|
||||
Note over Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
Bob->>Alice: I'm short though
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render wrapped long notes over queue', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "queue" }
|
||||
actor Bob
|
||||
Alice->>Bob: Hola
|
||||
Note over Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
Bob->>Alice: I'm short though
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render notes over actor and boundary', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
actor Alice
|
||||
participant Charlie@{ "type" : "boundary" }
|
||||
note over Alice: Some note
|
||||
note over Charlie: Other note
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render long messages from database to collections', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "database" }
|
||||
participant Bob@{ "type" : "collections" }
|
||||
Alice->>Bob: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
Bob->>Alice: I'm short though
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render wrapped long messages from control to entity', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "control" }
|
||||
participant Bob@{ "type" : "entity" }
|
||||
Alice->>Bob:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
Bob->>Alice: I'm short though
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render long messages from queue to boundary', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "queue" }
|
||||
participant Bob@{ "type" : "boundary" }
|
||||
Alice->>Bob: I'm short
|
||||
Bob->>Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render wrapped long messages from actor to database', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
actor Alice
|
||||
participant Bob@{ "type" : "database" }
|
||||
Alice->>Bob: I'm short
|
||||
Bob->>Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('svg size', () => {
|
||||
it('should render a sequence diagram when useMaxWidth is true (default)', () => {
|
||||
renderGraph(
|
||||
`
|
||||
sequenceDiagram
|
||||
actor Alice
|
||||
participant Bob@{ "type" : "boundary" }
|
||||
participant John@{ "type" : "control" }
|
||||
Alice ->> Bob: Hello Bob, how are you?
|
||||
Bob-->>John: How about you John?
|
||||
Bob--x Alice: I am good thanks!
|
||||
Bob-x John: I am good thanks!
|
||||
Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
|
||||
Bob-->Alice: Checking with John...
|
||||
alt either this
|
||||
Alice->>John: Yes
|
||||
else or this
|
||||
Alice->>John: No
|
||||
else or this will happen
|
||||
Alice->John: Maybe
|
||||
end
|
||||
par this happens in parallel
|
||||
Alice -->> Bob: Parallel message 1
|
||||
and
|
||||
Alice -->> John: Parallel message 2
|
||||
end
|
||||
`,
|
||||
{ sequence: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.be.within(820 * 0.95, 820 * 1.05);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render a sequence diagram when useMaxWidth is false', () => {
|
||||
renderGraph(
|
||||
`
|
||||
sequenceDiagram
|
||||
actor Alice
|
||||
participant Bob@{ "type" : "boundary" }
|
||||
participant John@{ "type" : "control" }
|
||||
Alice ->> Bob: Hello Bob, how are you?
|
||||
Bob-->>John: How about you John?
|
||||
Bob--x Alice: I am good thanks!
|
||||
Bob-x John: I am good thanks!
|
||||
Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
|
||||
Bob-->Alice: Checking with John...
|
||||
alt either this
|
||||
Alice->>John: Yes
|
||||
else or this
|
||||
Alice->>John: No
|
||||
else or this will happen
|
||||
Alice->John: Maybe
|
||||
end
|
||||
par this happens in parallel
|
||||
Alice -->> Bob: Parallel message 1
|
||||
and
|
||||
Alice -->> John: Parallel message 2
|
||||
end
|
||||
`,
|
||||
{ sequence: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
expect(width).to.be.within(820 * 0.95, 820 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@@ -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`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -11,7 +11,7 @@
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
|
@@ -29,7 +29,8 @@ 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,7 +33,8 @@ 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:
|
||||
|
||||
@@ -47,7 +48,8 @@ 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,7 +22,6 @@ 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
|
||||
|
@@ -88,13 +88,103 @@ Defined in: node_modules/.pnpm/typescript\@5.7.3/node_modules/typescript/lib/lib
|
||||
|
||||
---
|
||||
|
||||
### prepareStackTrace()?
|
||||
### stackTraceLimit
|
||||
|
||||
> `static` `optional` **prepareStackTrace**: (`err`, `stackTraces`) => `any`
|
||||
> `static` **stackTraceLimit**: `number`
|
||||
|
||||
Defined in: node_modules/.pnpm/@types+node\@22.13.5/node_modules/@types/node/globals.d.ts:143
|
||||
Defined in: node_modules/.pnpm/@types+node\@22.17.2/node_modules/@types/node/globals.d.ts:161
|
||||
|
||||
Optional override for formatting stack traces
|
||||
The `Error.stackTraceLimit` property specifies the number of stack frames
|
||||
collected by a stack trace (whether generated by `new Error().stack` or
|
||||
`Error.captureStackTrace(obj)`).
|
||||
|
||||
The default value is `10` but may be set to any valid JavaScript number. Changes
|
||||
will affect any stack trace captured _after_ the value has been changed.
|
||||
|
||||
If set to a non-number value, or set to a negative number, stack traces will
|
||||
not capture any frames.
|
||||
|
||||
#### Inherited from
|
||||
|
||||
`Error.stackTraceLimit`
|
||||
|
||||
## Methods
|
||||
|
||||
### captureStackTrace()
|
||||
|
||||
> `static` **captureStackTrace**(`targetObject`, `constructorOpt`?): `void`
|
||||
|
||||
Defined in: node_modules/.pnpm/@types+node\@22.17.2/node_modules/@types/node/globals.d.ts:145
|
||||
|
||||
Creates a `.stack` property on `targetObject`, which when accessed returns
|
||||
a string representing the location in the code at which
|
||||
`Error.captureStackTrace()` was called.
|
||||
|
||||
```js
|
||||
const myObject = {};
|
||||
Error.captureStackTrace(myObject);
|
||||
myObject.stack; // Similar to `new Error().stack`
|
||||
```
|
||||
|
||||
The first line of the trace will be prefixed with
|
||||
`${myObject.name}: ${myObject.message}`.
|
||||
|
||||
The optional `constructorOpt` argument accepts a function. If given, all frames
|
||||
above `constructorOpt`, including `constructorOpt`, will be omitted from the
|
||||
generated stack trace.
|
||||
|
||||
The `constructorOpt` argument is useful for hiding implementation
|
||||
details of error generation from the user. For instance:
|
||||
|
||||
```js
|
||||
function a() {
|
||||
b();
|
||||
}
|
||||
|
||||
function b() {
|
||||
c();
|
||||
}
|
||||
|
||||
function c() {
|
||||
// Create an error without stack trace to avoid calculating the stack trace twice.
|
||||
const { stackTraceLimit } = Error;
|
||||
Error.stackTraceLimit = 0;
|
||||
const error = new Error();
|
||||
Error.stackTraceLimit = stackTraceLimit;
|
||||
|
||||
// Capture the stack trace above function b
|
||||
Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
|
||||
throw error;
|
||||
}
|
||||
|
||||
a();
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
##### targetObject
|
||||
|
||||
`object`
|
||||
|
||||
##### constructorOpt?
|
||||
|
||||
`Function`
|
||||
|
||||
#### Returns
|
||||
|
||||
`void`
|
||||
|
||||
#### Inherited from
|
||||
|
||||
`Error.captureStackTrace`
|
||||
|
||||
---
|
||||
|
||||
### prepareStackTrace()
|
||||
|
||||
> `static` **prepareStackTrace**(`err`, `stackTraces`): `any`
|
||||
|
||||
Defined in: node_modules/.pnpm/@types+node\@22.17.2/node_modules/@types/node/globals.d.ts:149
|
||||
|
||||
#### Parameters
|
||||
|
||||
@@ -117,43 +207,3 @@ Optional override for formatting stack traces
|
||||
#### Inherited from
|
||||
|
||||
`Error.prepareStackTrace`
|
||||
|
||||
---
|
||||
|
||||
### stackTraceLimit
|
||||
|
||||
> `static` **stackTraceLimit**: `number`
|
||||
|
||||
Defined in: node_modules/.pnpm/@types+node\@22.13.5/node_modules/@types/node/globals.d.ts:145
|
||||
|
||||
#### Inherited from
|
||||
|
||||
`Error.stackTraceLimit`
|
||||
|
||||
## Methods
|
||||
|
||||
### captureStackTrace()
|
||||
|
||||
> `static` **captureStackTrace**(`targetObject`, `constructorOpt`?): `void`
|
||||
|
||||
Defined in: node_modules/.pnpm/@types+node\@22.13.5/node_modules/@types/node/globals.d.ts:136
|
||||
|
||||
Create .stack property on a target object
|
||||
|
||||
#### Parameters
|
||||
|
||||
##### targetObject
|
||||
|
||||
`object`
|
||||
|
||||
##### constructorOpt?
|
||||
|
||||
`Function`
|
||||
|
||||
#### Returns
|
||||
|
||||
`void`
|
||||
|
||||
#### Inherited from
|
||||
|
||||
`Error.captureStackTrace`
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
# Interface: ParseOptions
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:84](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L84)
|
||||
Defined in: [packages/mermaid/src/types.ts:72](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L72)
|
||||
|
||||
## Properties
|
||||
|
||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:84](https://github.com/mermaid-js/mer
|
||||
|
||||
> `optional` **suppressErrors**: `boolean`
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:89](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L89)
|
||||
Defined in: [packages/mermaid/src/types.ts:77](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L77)
|
||||
|
||||
If `true`, parse will return `false` instead of throwing error when the diagram is invalid.
|
||||
The `parseError` function will not be called.
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
# Interface: ParseResult
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:92](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L92)
|
||||
Defined in: [packages/mermaid/src/types.ts:80](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L80)
|
||||
|
||||
## Properties
|
||||
|
||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:92](https://github.com/mermaid-js/mer
|
||||
|
||||
> **config**: [`MermaidConfig`](MermaidConfig.md)
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:100](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L100)
|
||||
Defined in: [packages/mermaid/src/types.ts:88](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L88)
|
||||
|
||||
The config passed as YAML frontmatter or directives
|
||||
|
||||
@@ -28,6 +28,6 @@ The config passed as YAML frontmatter or directives
|
||||
|
||||
> **diagramType**: `string`
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:96](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L96)
|
||||
Defined in: [packages/mermaid/src/types.ts:84](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L84)
|
||||
|
||||
The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
# Interface: RenderResult
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:110](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L110)
|
||||
Defined in: [packages/mermaid/src/types.ts:98](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L98)
|
||||
|
||||
## Properties
|
||||
|
||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:110](https://github.com/mermaid-js/me
|
||||
|
||||
> `optional` **bindFunctions**: (`element`) => `void`
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:128](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L128)
|
||||
Defined in: [packages/mermaid/src/types.ts:116](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L116)
|
||||
|
||||
Bind function to be called after the svg has been inserted into the DOM.
|
||||
This is necessary for adding event listeners to the elements in the svg.
|
||||
@@ -45,7 +45,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present.
|
||||
|
||||
> **diagramType**: `string`
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:118](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L118)
|
||||
Defined in: [packages/mermaid/src/types.ts:106](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L106)
|
||||
|
||||
The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
||||
@@ -55,6 +55,6 @@ The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
||||
> **svg**: `string`
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:114](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L114)
|
||||
Defined in: [packages/mermaid/src/types.ts:102](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L102)
|
||||
|
||||
The svg code for the rendered graph.
|
||||
|
@@ -29,7 +29,6 @@ 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,13 +35,11 @@ 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)
|
||||
|
@@ -139,7 +139,6 @@ 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)
|
||||
@@ -153,7 +152,6 @@ 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
|
||||
@@ -163,7 +161,6 @@ 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
|
||||
@@ -172,18 +169,15 @@ 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
|
||||
|
@@ -360,7 +360,8 @@ 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
|
||||
|
||||
|
@@ -74,126 +74,6 @@ sequenceDiagram
|
||||
Bob->>Alice: Hi Alice
|
||||
```
|
||||
|
||||
### Boundary
|
||||
|
||||
If you want to use the boundary symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "boundary" }
|
||||
participant Bob
|
||||
Alice->>Bob: Request from boundary
|
||||
Bob->>Alice: Response to boundary
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "boundary" }
|
||||
participant Bob
|
||||
Alice->>Bob: Request from boundary
|
||||
Bob->>Alice: Response to boundary
|
||||
```
|
||||
|
||||
### Control
|
||||
|
||||
If you want to use the control symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "control" }
|
||||
participant Bob
|
||||
Alice->>Bob: Control request
|
||||
Bob->>Alice: Control response
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "control" }
|
||||
participant Bob
|
||||
Alice->>Bob: Control request
|
||||
Bob->>Alice: Control response
|
||||
```
|
||||
|
||||
### Entity
|
||||
|
||||
If you want to use the entity symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "entity" }
|
||||
participant Bob
|
||||
Alice->>Bob: Entity request
|
||||
Bob->>Alice: Entity response
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "entity" }
|
||||
participant Bob
|
||||
Alice->>Bob: Entity request
|
||||
Bob->>Alice: Entity response
|
||||
```
|
||||
|
||||
### Database
|
||||
|
||||
If you want to use the database symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "database" }
|
||||
participant Bob
|
||||
Alice->>Bob: DB query
|
||||
Bob->>Alice: DB result
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "database" }
|
||||
participant Bob
|
||||
Alice->>Bob: DB query
|
||||
Bob->>Alice: DB result
|
||||
```
|
||||
|
||||
### Collections
|
||||
|
||||
If you want to use the collections symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "collections" }
|
||||
participant Bob
|
||||
Alice->>Bob: Collections request
|
||||
Bob->>Alice: Collections response
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "collections" }
|
||||
participant Bob
|
||||
Alice->>Bob: Collections request
|
||||
Bob->>Alice: Collections response
|
||||
```
|
||||
|
||||
### Queue
|
||||
|
||||
If you want to use the queue symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "queue" }
|
||||
participant Bob
|
||||
Alice->>Bob: Queue message
|
||||
Bob->>Alice: Queue response
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "queue" }
|
||||
participant Bob
|
||||
Alice->>Bob: Queue message
|
||||
Bob->>Alice: Queue response
|
||||
```
|
||||
|
||||
### Aliases
|
||||
|
||||
The actor can have a convenient identifier and a descriptive label.
|
||||
@@ -329,11 +209,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 +224,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**
|
||||
|
||||
The following half-arrow types are now 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
|
||||
|
||||
Mermaid sequence diagrams now 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:
|
||||
|
42
package.json
42
package.json
@@ -64,35 +64,35 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@applitools/eyes-cypress": "^3.44.9",
|
||||
"@argos-ci/cypress": "^5.0.2",
|
||||
"@argos-ci/cypress": "^5.0.7",
|
||||
"@changesets/changelog-github": "^0.5.1",
|
||||
"@changesets/cli": "^2.27.12",
|
||||
"@cspell/eslint-plugin": "^8.19.4",
|
||||
"@cypress/code-coverage": "^3.12.49",
|
||||
"@eslint/js": "^9.26.0",
|
||||
"@rollup/plugin-typescript": "^12.1.2",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^5.0.0",
|
||||
"@rollup/plugin-typescript": "^12.1.4",
|
||||
"@types/cors": "^2.8.19",
|
||||
"@types/express": "^5.0.3",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/lodash": "^4.17.15",
|
||||
"@types/lodash": "^4.17.20",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.17",
|
||||
"@types/rollup-plugin-visualizer": "^5.0.3",
|
||||
"@vitest/coverage-v8": "^3.0.6",
|
||||
"@vitest/spy": "^3.0.6",
|
||||
"@vitest/ui": "^3.0.6",
|
||||
"@vitest/coverage-v8": "^3.0.9",
|
||||
"@vitest/spy": "^3.0.9",
|
||||
"@vitest/ui": "^3.0.9",
|
||||
"ajv": "^8.17.1",
|
||||
"chokidar": "3.6.0",
|
||||
"concurrently": "^9.1.2",
|
||||
"cors": "^2.8.5",
|
||||
"cpy-cli": "^5.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"cspell": "^9.1.3",
|
||||
"cypress": "^14.5.1",
|
||||
"cspell": "^9.1.5",
|
||||
"cypress": "^14.5.4",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
"cypress-split": "^1.24.14",
|
||||
"esbuild": "^0.25.0",
|
||||
"cypress-split": "^1.24.21",
|
||||
"esbuild": "^0.25.9",
|
||||
"eslint": "^9.26.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-cypress": "^4.3.0",
|
||||
@@ -107,29 +107,29 @@
|
||||
"eslint-plugin-unicorn": "^59.0.1",
|
||||
"express": "^5.1.0",
|
||||
"globals": "^16.0.0",
|
||||
"globby": "^14.0.2",
|
||||
"globby": "^14.1.0",
|
||||
"husky": "^9.1.7",
|
||||
"jest": "^30.0.4",
|
||||
"jest": "^30.0.5",
|
||||
"jison": "^0.4.18",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"langium-cli": "3.3.0",
|
||||
"lint-staged": "^16.1.2",
|
||||
"lint-staged": "^16.1.5",
|
||||
"markdown-table": "^3.0.4",
|
||||
"nyc": "^17.1.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"prettier": "^3.5.2",
|
||||
"prettier-plugin-jsdoc": "^1.3.2",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-jsdoc": "^1.3.3",
|
||||
"rimraf": "^6.0.1",
|
||||
"rollup-plugin-visualizer": "^6.0.3",
|
||||
"start-server-and-test": "^2.0.10",
|
||||
"start-server-and-test": "^2.0.13",
|
||||
"tslib": "^2.8.1",
|
||||
"tsx": "^4.7.3",
|
||||
"typescript": "~5.7.3",
|
||||
"typescript-eslint": "^8.38.0",
|
||||
"vite": "^7.0.3",
|
||||
"vite": "^7.0.6",
|
||||
"vite-plugin-istanbul": "^7.0.0",
|
||||
"vitest": "^3.0.6"
|
||||
"vitest": "^3.0.9"
|
||||
},
|
||||
"nyc": {
|
||||
"report-dir": "coverage/cypress"
|
||||
|
@@ -37,7 +37,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^7.0.4",
|
||||
"@braintree/sanitize-url": "^7.1.1",
|
||||
"d3": "^7.9.0",
|
||||
"khroma": "^2.1.0"
|
||||
},
|
||||
|
@@ -154,7 +154,6 @@
|
||||
### 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 ...)
|
||||
@@ -173,14 +172,12 @@
|
||||
### 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
|
||||
|
||||
@@ -229,7 +226,6 @@
|
||||
- [#5999](https://github.com/mermaid-js/mermaid/pull/5999) [`742ad7c`](https://github.com/mermaid-js/mermaid/commit/742ad7c130964df1fb5544e909d9556081285f68) Thanks [@knsv](https://github.com/knsv)! - Adding Kanban board, a new diagram type
|
||||
|
||||
- [#5880](https://github.com/mermaid-js/mermaid/pull/5880) [`bdf145f`](https://github.com/mermaid-js/mermaid/commit/bdf145ffe362462176d9c1e68d5f3ff5c9d962b0) Thanks [@yari-dewalt](https://github.com/yari-dewalt)! - Class diagram changes:
|
||||
|
||||
- Updates the class diagram to the new unified way of rendering.
|
||||
- Includes a new "classBox" shape to be used in diagrams
|
||||
- Other updates such as:
|
||||
|
@@ -67,8 +67,8 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^7.0.4",
|
||||
"@iconify/utils": "^2.1.33",
|
||||
"@braintree/sanitize-url": "^7.1.1",
|
||||
"@iconify/utils": "^2.3.0",
|
||||
"@mermaid-js/parser": "workspace:^",
|
||||
"@types/d3": "^7.4.3",
|
||||
"cytoscape": "^3.29.3",
|
||||
@@ -89,7 +89,7 @@
|
||||
"uuid": "^11.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@adobe/jsonschema2md": "^8.0.2",
|
||||
"@adobe/jsonschema2md": "^8.0.5",
|
||||
"@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.1.0",
|
||||
"canvas": "^3.1.2",
|
||||
"chokidar": "3.6.0",
|
||||
"concurrently": "^9.1.2",
|
||||
"csstree-validator": "^4.0.1",
|
||||
"globby": "^14.0.2",
|
||||
"globby": "^14.1.0",
|
||||
"jison": "^0.4.18",
|
||||
"js-base64": "^3.7.7",
|
||||
"js-base64": "^3.7.8",
|
||||
"jsdom": "^26.1.0",
|
||||
"json-schema-to-typescript": "^15.0.4",
|
||||
"micromatch": "^4.0.8",
|
||||
"path-browserify": "^1.0.1",
|
||||
"prettier": "^3.5.2",
|
||||
"prettier": "^3.5.3",
|
||||
"remark": "^15.0.1",
|
||||
"remark-frontmatter": "^5.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"rimraf": "^6.0.1",
|
||||
"start-server-and-test": "^2.0.10",
|
||||
"start-server-and-test": "^2.0.13",
|
||||
"type-fest": "^4.35.0",
|
||||
"typedoc": "^0.27.8",
|
||||
"typedoc": "^0.27.9",
|
||||
"typedoc-plugin-markdown": "^4.4.2",
|
||||
"typescript": "~5.7.3",
|
||||
"unist-util-flatmap": "^1.0.0",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"vitepress": "^1.0.2",
|
||||
"vitepress": "^1.6.4",
|
||||
"vitepress-plugin-search": "1.0.4-alpha.22"
|
||||
},
|
||||
"files": [
|
||||
|
@@ -14,7 +14,7 @@
|
||||
|
||||
// Special states for recognizing aliases
|
||||
// A special state for grabbing text up to the first comment/newline
|
||||
%x ID ALIAS LINE CONFIG CONFIG_DATA
|
||||
%x ID ALIAS LINE
|
||||
|
||||
%x acc_title
|
||||
%x acc_descr
|
||||
@@ -28,11 +28,6 @@
|
||||
\%%(?!\{)[^\n]* /* skip comments */
|
||||
[^\}]\%\%[^\n]* /* skip comments */
|
||||
[0-9]+(?=[ \n]+) return 'NUM';
|
||||
<ID>\@\{ { this.begin('CONFIG'); return 'CONFIG_START'; }
|
||||
<CONFIG>[^\}]+ { return 'CONFIG_CONTENT'; }
|
||||
<CONFIG>\} { this.popState(); this.popState(); return 'CONFIG_END'; }
|
||||
<ID>[^\<->\->:\n,;@\s]+(?=\@\{) { yytext = yytext.trim(); return 'ACTOR'; }
|
||||
<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'; }
|
||||
@@ -78,7 +73,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';
|
||||
@@ -89,36 +84,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';
|
||||
|
||||
@@ -262,8 +231,6 @@ participant_statement
|
||||
| 'participant_actor' actor 'AS' restOfLine 'NEWLINE' {$2.draw='actor'; $2.type='addParticipant';$2.description=yy.parseMessage($4); $$=$2;}
|
||||
| 'participant_actor' actor 'NEWLINE' {$2.draw='actor'; $2.type='addParticipant'; $$=$2;}
|
||||
| 'destroy' actor 'NEWLINE' {$2.type='destroyParticipant'; $$=$2;}
|
||||
| 'participant' actor_with_config 'NEWLINE' {$2.draw='participant'; $2.type='addParticipant'; $$=$2;}
|
||||
|
||||
;
|
||||
|
||||
note_statement
|
||||
@@ -330,41 +297,10 @@ 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}]}
|
||||
;
|
||||
|
||||
actor_with_config
|
||||
: ACTOR config_object
|
||||
{
|
||||
$$ = {
|
||||
type: 'addParticipant',
|
||||
actor: $1,
|
||||
config: $2
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
config_object
|
||||
: CONFIG_START CONFIG_CONTENT CONFIG_END
|
||||
{
|
||||
$$ = $2.trim();
|
||||
}
|
||||
;
|
||||
// actor
|
||||
// : actor_participant
|
||||
// | actor_actor
|
||||
@@ -377,27 +313,6 @@ 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; }
|
||||
| DOTTED_ARROW { $$ = yy.LINETYPE.DOTTED; }
|
||||
| BIDIRECTIONAL_DOTTED_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_DOTTED; }
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import * as yaml from 'js-yaml';
|
||||
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { ImperativeState } from '../../utils/imperativeState.js';
|
||||
@@ -14,7 +13,6 @@ import {
|
||||
setDiagramTitle,
|
||||
} from '../common/commonDb.js';
|
||||
import type { Actor, AddMessageParams, Box, Message, Note } from './types.js';
|
||||
import type { ParticipantMetaData } from '../../types.js';
|
||||
|
||||
interface SequenceState {
|
||||
prevActor?: string;
|
||||
@@ -64,30 +62,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 = {
|
||||
@@ -101,17 +75,6 @@ const PLACEMENT = {
|
||||
OVER: 2,
|
||||
} as const;
|
||||
|
||||
export const PARTICIPANT_TYPE = {
|
||||
ACTOR: 'actor',
|
||||
BOUNDARY: 'boundary',
|
||||
COLLECTIONS: 'collections',
|
||||
CONTROL: 'control',
|
||||
DATABASE: 'database',
|
||||
ENTITY: 'entity',
|
||||
PARTICIPANT: 'participant',
|
||||
QUEUE: 'queue',
|
||||
} as const;
|
||||
|
||||
export class SequenceDB implements DiagramDB {
|
||||
private readonly state = new ImperativeState<SequenceState>(() => ({
|
||||
prevActor: undefined,
|
||||
@@ -156,22 +119,9 @@ export class SequenceDB implements DiagramDB {
|
||||
id: string,
|
||||
name: string,
|
||||
description: { text: string; wrap?: boolean | null; type: string },
|
||||
type: string,
|
||||
metadata?: any
|
||||
type: string
|
||||
) {
|
||||
let assignedBox = this.state.records.currentBox;
|
||||
let doc;
|
||||
if (metadata !== undefined) {
|
||||
let yamlData;
|
||||
// detect if shapeData contains a newline character
|
||||
if (!metadata.includes('\n')) {
|
||||
yamlData = '{\n' + metadata + '\n}';
|
||||
} else {
|
||||
yamlData = metadata + '\n';
|
||||
}
|
||||
doc = yaml.load(yamlData, { schema: yaml.JSON_SCHEMA }) as ParticipantMetaData;
|
||||
}
|
||||
type = doc?.type ?? type;
|
||||
const old = this.state.records.actors.get(id);
|
||||
if (old) {
|
||||
// If already set and trying to set to a new one throw error
|
||||
@@ -268,8 +218,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 +245,6 @@ export class SequenceDB implements DiagramDB {
|
||||
wrap: message?.wrap ?? this.autoWrap(),
|
||||
type: messageType,
|
||||
activate,
|
||||
centralConnection: centralConnection ?? 0,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
@@ -570,7 +518,7 @@ export class SequenceDB implements DiagramDB {
|
||||
});
|
||||
break;
|
||||
case 'addParticipant':
|
||||
this.addActor(param.actor, param.actor, param.description, param.draw, param.config);
|
||||
this.addActor(param.actor, param.actor, param.description, param.draw);
|
||||
break;
|
||||
case 'createParticipant':
|
||||
if (this.state.records.actors.has(param.actor)) {
|
||||
@@ -579,7 +527,7 @@ export class SequenceDB implements DiagramDB {
|
||||
);
|
||||
}
|
||||
this.state.records.lastCreated = param.actor;
|
||||
this.addActor(param.actor, param.actor, param.description, param.draw, param.config);
|
||||
this.addActor(param.actor, param.actor, param.description, param.draw);
|
||||
this.state.records.createdActors.set(param.actor, this.state.records.messages.length);
|
||||
break;
|
||||
case 'destroyParticipant':
|
||||
@@ -589,12 +537,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 +580,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!",
|
||||
@@ -2064,302 +2058,4 @@ 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(`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "database" }
|
||||
participant Bob@{ "type" : "database" }
|
||||
participant Carl@{ type: "database" }
|
||||
participant David@{ "type" : 'database' }
|
||||
participant Eve@{ type: 'database' }
|
||||
participant Favela@{ "type" : "database" }
|
||||
Bob->>+Alice: Hi Alice
|
||||
Alice->>+Bob: Hi Bob
|
||||
`);
|
||||
|
||||
const actors = diagram.db.getActors();
|
||||
|
||||
expect(actors.get('Alice').type).toBe('database');
|
||||
expect(actors.get('Alice').description).toBe('Alice');
|
||||
|
||||
expect(actors.get('Bob').type).toBe('database');
|
||||
expect(actors.get('Bob').description).toBe('Bob');
|
||||
|
||||
expect(actors.get('Carl').type).toBe('database');
|
||||
expect(actors.get('Carl').description).toBe('Carl');
|
||||
|
||||
expect(actors.get('David').type).toBe('database');
|
||||
expect(actors.get('David').description).toBe('David');
|
||||
|
||||
expect(actors.get('Eve').type).toBe('database');
|
||||
expect(actors.get('Eve').description).toBe('Eve');
|
||||
|
||||
expect(actors.get('Favela').type).toBe('database');
|
||||
expect(actors.get('Favela').description).toBe('Favela');
|
||||
|
||||
// Verify messages were parsed correctly
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages.length).toBe(4); // 2 messages + 2 activation messages
|
||||
expect(messages[0].from).toBe('Bob');
|
||||
expect(messages[0].to).toBe('Alice');
|
||||
expect(messages[0].message).toBe('Hi Alice');
|
||||
expect(messages[2].from).toBe('Alice'); // Second message (index 2 due to activation)
|
||||
expect(messages[2].to).toBe('Bob');
|
||||
expect(messages[2].message).toBe('Hi Bob');
|
||||
});
|
||||
|
||||
it('should parse mixed participant types with extended syntax', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant lead
|
||||
participant dsa@{ "type" : "queue" }
|
||||
API->>+Database: getUserb
|
||||
Database-->>-API: userb
|
||||
dsa --> Database: hello
|
||||
`);
|
||||
|
||||
// Verify actors were created
|
||||
const actors = diagram.db.getActors();
|
||||
|
||||
expect(actors.get('lead').type).toBe('participant');
|
||||
expect(actors.get('lead').description).toBe('lead');
|
||||
|
||||
// Participant with extended syntax
|
||||
expect(actors.get('dsa').type).toBe('queue');
|
||||
expect(actors.get('dsa').description).toBe('dsa');
|
||||
|
||||
// Implicitly created actors (from messages)
|
||||
expect(actors.get('API').type).toBe('participant');
|
||||
expect(actors.get('API').description).toBe('API');
|
||||
|
||||
expect(actors.get('Database').type).toBe('participant');
|
||||
expect(actors.get('Database').description).toBe('Database');
|
||||
|
||||
// Verify messages were parsed correctly
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages.length).toBe(5); // 3 messages + 2 activation messages
|
||||
|
||||
// First message with activation
|
||||
expect(messages[0].from).toBe('API');
|
||||
expect(messages[0].to).toBe('Database');
|
||||
expect(messages[0].message).toBe('getUserb');
|
||||
expect(messages[0].activate).toBe(true);
|
||||
|
||||
// Second message with deactivation
|
||||
expect(messages[2].from).toBe('Database');
|
||||
expect(messages[2].to).toBe('API');
|
||||
expect(messages[2].message).toBe('userb');
|
||||
|
||||
// Third message
|
||||
expect(messages[4].from).toBe('dsa');
|
||||
expect(messages[4].to).toBe('Database');
|
||||
expect(messages[4].message).toBe('hello');
|
||||
});
|
||||
|
||||
it('should fail for malformed JSON in participant definition', async () => {
|
||||
const invalidDiagram = `
|
||||
sequenceDiagram
|
||||
participant D@{ "type: "entity" }
|
||||
participant E@{ "type": "dat
|
||||
abase }
|
||||
`;
|
||||
|
||||
let error = false;
|
||||
try {
|
||||
await mermaidAPI.parse(invalidDiagram);
|
||||
} catch (e) {
|
||||
error = true;
|
||||
}
|
||||
expect(error).toBe(true);
|
||||
});
|
||||
|
||||
it('should fail for missing colon separator', async () => {
|
||||
const invalidDiagram = `
|
||||
sequenceDiagram
|
||||
participant C@{ "type" "control" }
|
||||
C ->> C: action
|
||||
`;
|
||||
|
||||
let error = false;
|
||||
try {
|
||||
await mermaidAPI.parse(invalidDiagram);
|
||||
} catch (e) {
|
||||
error = true;
|
||||
}
|
||||
expect(error).toBe(true);
|
||||
});
|
||||
|
||||
it('should fail for missing closing brace', async () => {
|
||||
const invalidDiagram = `
|
||||
sequenceDiagram
|
||||
participant E@{ "type": "entity"
|
||||
E ->> E: process
|
||||
`;
|
||||
|
||||
let error = false;
|
||||
try {
|
||||
await mermaidAPI.parse(invalidDiagram);
|
||||
} catch (e) {
|
||||
error = true;
|
||||
}
|
||||
expect(error).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('participant type parsing', () => {
|
||||
it('should parse boundary participant', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant boundary@{ "type" : "boundary" }
|
||||
boundary->boundary: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('boundary').type).toBe('boundary');
|
||||
expect(actors.get('boundary').description).toBe('boundary');
|
||||
});
|
||||
|
||||
it('should parse control participant', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant C@{ "type" : "control" }
|
||||
C->C: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('C').type).toBe('control');
|
||||
expect(actors.get('C').description).toBe('C');
|
||||
});
|
||||
|
||||
it('should parse entity participant', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant E@{ "type" : "entity" }
|
||||
E->E: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('E').type).toBe('entity');
|
||||
expect(actors.get('E').description).toBe('E');
|
||||
});
|
||||
|
||||
it('should parse database participant', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant D@{ "type" : "database" }
|
||||
D->D: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('D').type).toBe('database');
|
||||
expect(actors.get('D').description).toBe('D');
|
||||
});
|
||||
|
||||
it('should parse collections participant', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant L@{ "type" : "collections" }
|
||||
L->L: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('L').type).toBe('collections');
|
||||
expect(actors.get('L').description).toBe('L');
|
||||
});
|
||||
|
||||
it('should parse queue participant', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Q@{ "type" : "queue" }
|
||||
Q->Q: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('Q').type).toBe('queue');
|
||||
expect(actors.get('Q').description).toBe('Q');
|
||||
});
|
||||
});
|
||||
|
||||
describe('participant type parsing', () => {
|
||||
it('should parse actor participant', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant A@{ "type" : "queue" }
|
||||
A->A: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('A').type).toBe('queue');
|
||||
expect(actors.get('A').description).toBe('A');
|
||||
});
|
||||
|
||||
it('should parse participant participant', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant P@{ "type" : "database" }
|
||||
P->P: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('P').type).toBe('database');
|
||||
expect(actors.get('P').description).toBe('P');
|
||||
});
|
||||
|
||||
it('should parse boundary using actor keyword', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "collections" }
|
||||
participant Bob@{ "type" : "control" }
|
||||
Alice->>Bob: Hello Bob, how are you?
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('Alice').type).toBe('collections');
|
||||
expect(actors.get('Bob').type).toBe('control');
|
||||
expect(actors.get('Bob').description).toBe('Bob');
|
||||
});
|
||||
|
||||
it('should parse control using participant keyword', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant C@{ "type" : "control" }
|
||||
C->C: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('C').type).toBe('control');
|
||||
expect(actors.get('C').description).toBe('C');
|
||||
});
|
||||
|
||||
it('should parse entity using actor keyword', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant E@{ "type" : "entity" }
|
||||
E->E: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('E').type).toBe('entity');
|
||||
expect(actors.get('E').description).toBe('E');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -10,7 +10,6 @@ import assignWithDepth from '../../assignWithDepth.js';
|
||||
import utils from '../../utils.js';
|
||||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||
import type { Diagram } from '../../Diagram.js';
|
||||
import { PARTICIPANT_TYPE } from './sequenceDb.js';
|
||||
|
||||
let conf = {};
|
||||
|
||||
@@ -282,44 +281,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 [fromLeft] = activationBounds(msg.from, actors);
|
||||
const [toLeft] = activationBounds(msg.to, actors);
|
||||
const isArrowToRight = fromLeft <= toLeft;
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
if (msg.centralConnection === diagObj.db.LINETYPE.CENTRAL_CONNECTION) {
|
||||
const cx = isArrowToRight ? stopx + 5 : stopx - 8;
|
||||
drawCircle(cx);
|
||||
} else if (msg.centralConnection === diagObj.db.LINETYPE.CENTRAL_CONNECTION_REVERSE) {
|
||||
const cx = isArrowToRight ? startx - 5 : stopx + 8;
|
||||
drawCircle(cx);
|
||||
} else if (msg.centralConnection === diagObj.db.LINETYPE.CENTRAL_CONNECTION_DUAL) {
|
||||
const offset = isArrowToRight ? 5 : -5;
|
||||
drawCircle(stopx + offset);
|
||||
drawCircle(startx - offset);
|
||||
}
|
||||
};
|
||||
|
||||
const messageFont = (cnf) => {
|
||||
return {
|
||||
fontFamily: cnf.messageFontFamily,
|
||||
@@ -405,7 +366,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();
|
||||
@@ -471,9 +432,6 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
line.attr('y1', lineStartY);
|
||||
line.attr('x2', stopx);
|
||||
line.attr('y2', lineStartY);
|
||||
if (msg.centralConnection) {
|
||||
drawCentralConnection(diagram, msg, msgModel, diagObj, startx, stopx, lineStartY);
|
||||
}
|
||||
}
|
||||
// Make an SVG Container
|
||||
// Draw the line
|
||||
@@ -482,15 +440,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');
|
||||
@@ -506,51 +456,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)');
|
||||
}
|
||||
@@ -575,18 +480,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) {
|
||||
@@ -594,7 +488,6 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
} else {
|
||||
line.attr('x1', startx + SEQUENCE_NUMBER_RADIUS);
|
||||
}
|
||||
x = 3.5;
|
||||
}
|
||||
|
||||
diagram
|
||||
@@ -604,8 +497,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')
|
||||
@@ -615,8 +507,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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -855,19 +746,11 @@ function adjustCreatedDestroyedData(
|
||||
msgModel.startx = msgModel.startx - adjustment;
|
||||
}
|
||||
}
|
||||
const actorArray = [
|
||||
PARTICIPANT_TYPE.ACTOR,
|
||||
PARTICIPANT_TYPE.CONTROL,
|
||||
PARTICIPANT_TYPE.ENTITY,
|
||||
PARTICIPANT_TYPE.DATABASE,
|
||||
];
|
||||
|
||||
// if it is a create message
|
||||
if (createdActors.get(msg.to) == index) {
|
||||
const actor = actors.get(msg.to);
|
||||
const adjustment = actorArray.includes(actor.type)
|
||||
? ACTOR_TYPE_WIDTH / 2 + 3
|
||||
: actor.width / 2 + 3;
|
||||
const adjustment = actor.type == 'actor' ? ACTOR_TYPE_WIDTH / 2 + 3 : actor.width / 2 + 3;
|
||||
receiverAdjustment(actor, adjustment);
|
||||
actor.starty = lineStartY - actor.height / 2;
|
||||
bounds.bumpVerticalPos(actor.height / 2);
|
||||
@@ -876,7 +759,7 @@ function adjustCreatedDestroyedData(
|
||||
else if (destroyedActors.get(msg.from) == index) {
|
||||
const actor = actors.get(msg.from);
|
||||
if (conf.mirrorActors) {
|
||||
const adjustment = actorArray.includes(actor.type) ? ACTOR_TYPE_WIDTH / 2 : actor.width / 2;
|
||||
const adjustment = actor.type == 'actor' ? ACTOR_TYPE_WIDTH / 2 : actor.width / 2;
|
||||
senderAdjustment(actor, adjustment);
|
||||
}
|
||||
actor.stopy = lineStartY - actor.height / 2;
|
||||
@@ -886,9 +769,7 @@ function adjustCreatedDestroyedData(
|
||||
else if (destroyedActors.get(msg.to) == index) {
|
||||
const actor = actors.get(msg.to);
|
||||
if (conf.mirrorActors) {
|
||||
const adjustment = actorArray.includes(actor.type)
|
||||
? ACTOR_TYPE_WIDTH / 2 + 3
|
||||
: actor.width / 2 + 3;
|
||||
const adjustment = actor.type == 'actor' ? ACTOR_TYPE_WIDTH / 2 + 3 : actor.width / 2 + 3;
|
||||
receiverAdjustment(actor, adjustment);
|
||||
}
|
||||
actor.stopy = lineStartY - actor.height / 2;
|
||||
@@ -965,10 +846,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.
|
||||
@@ -1009,12 +886,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;
|
||||
@@ -1173,7 +1044,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);
|
||||
@@ -1186,27 +1057,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,
|
||||
@@ -1226,7 +1076,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);
|
||||
@@ -1237,11 +1087,10 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
for (const box of bounds.models.boxes) {
|
||||
box.height = bounds.getVerticalPos() - box.y;
|
||||
bounds.insert(box.x, box.y, box.x + box.width, box.height);
|
||||
const boxPadding = conf.boxMargin * 2;
|
||||
box.startx = box.x - boxPadding;
|
||||
box.starty = box.y - boxPadding * 0.25;
|
||||
box.stopx = box.startx + box.width + 2 * boxPadding;
|
||||
box.stopy = box.starty + box.height + boxPadding * 0.75;
|
||||
box.startx = box.x;
|
||||
box.starty = box.y;
|
||||
box.stopx = box.startx + box.width;
|
||||
box.stopy = box.starty + box.height;
|
||||
box.stroke = 'rgb(0,0,0, 0.5)';
|
||||
svgDraw.drawBox(diagram, box, conf);
|
||||
}
|
||||
@@ -1506,9 +1355,6 @@ async function calculateActorMargins(
|
||||
return (total += actors.get(aKey).width + (actors.get(aKey).margin || 0));
|
||||
}, 0);
|
||||
|
||||
const standardBoxPadding = conf.boxMargin * 8;
|
||||
totalWidth += standardBoxPadding;
|
||||
|
||||
totalWidth -= 2 * conf.boxTextMargin;
|
||||
if (box.wrap) {
|
||||
box.name = utils.wrapLabel(box.name, totalWidth - 2 * conf.wrapPadding, textFont);
|
||||
@@ -1606,27 +1452,6 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
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,
|
||||
@@ -1644,12 +1469,6 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
let startx = isArrowToRight ? fromRight : fromLeft;
|
||||
let stopx = isArrowToRight ? toLeft : toRight;
|
||||
|
||||
if (
|
||||
msg.centralConnection === diagObj.db.LINETYPE.CENTRAL_CONNECTION_REVERSE ||
|
||||
msg.centralConnection === diagObj.db.LINETYPE.CENTRAL_CONNECTION_DUAL
|
||||
) {
|
||||
startx += 4;
|
||||
}
|
||||
// As the line width is considered, the left and right values will be off by 2.
|
||||
const isArrowToActivation = Math.abs(toLeft - toRight) > 2;
|
||||
|
||||
@@ -1683,30 +1502,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);
|
||||
}
|
||||
|
||||
@@ -1714,14 +1510,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);
|
||||
}
|
||||
|
@@ -12,11 +12,6 @@ const getStyles = (options) =>
|
||||
.actor-line {
|
||||
stroke: ${options.actorLineColor};
|
||||
}
|
||||
|
||||
.innerArc {
|
||||
stroke-width: 1.5;
|
||||
stroke-dasharray: none;
|
||||
}
|
||||
|
||||
.messageLine0 {
|
||||
stroke-width: 1.5;
|
||||
@@ -120,7 +115,6 @@ const getStyles = (options) =>
|
||||
fill: ${options.actorBkg};
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
export default getStyles;
|
||||
|
@@ -415,600 +415,6 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
|
||||
return height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws an actor in the diagram with the attached line
|
||||
*
|
||||
* @param {any} elem - The diagram we'll draw to.
|
||||
* @param {any} actor - The actor to draw.
|
||||
* @param {any} conf - DrawText implementation discriminator object
|
||||
* @param {boolean} isFooter - If the actor is the footer one
|
||||
*/
|
||||
const drawActorTypeCollections = function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actorY + actor.height;
|
||||
|
||||
const boxplusLineGroup = elem.append('g').lower();
|
||||
var g = boxplusLineGroup;
|
||||
|
||||
if (!isFooter) {
|
||||
actorCnt++;
|
||||
if (Object.keys(actor.links || {}).length && !conf.forceMenus) {
|
||||
g.attr('onclick', popupMenuToggle(`actor${actorCnt}_popup`)).attr('cursor', 'pointer');
|
||||
}
|
||||
g.append('line')
|
||||
.attr('id', 'actor' + actorCnt)
|
||||
.attr('x1', center)
|
||||
.attr('y1', centerY)
|
||||
.attr('x2', center)
|
||||
.attr('y2', 2000)
|
||||
.attr('class', 'actor-line 200')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999')
|
||||
.attr('name', actor.name);
|
||||
|
||||
g = boxplusLineGroup.append('g');
|
||||
actor.actorCnt = actorCnt;
|
||||
|
||||
if (actor.links != null) {
|
||||
g.attr('id', 'root-' + actorCnt);
|
||||
}
|
||||
}
|
||||
|
||||
const rect = svgDrawCommon.getNoteRect();
|
||||
var cssclass = 'actor';
|
||||
if (actor.properties?.class) {
|
||||
cssclass = actor.properties.class;
|
||||
} else {
|
||||
rect.fill = '#eaeaea';
|
||||
}
|
||||
if (isFooter) {
|
||||
cssclass += ` ${BOTTOM_ACTOR_CLASS}`;
|
||||
} else {
|
||||
cssclass += ` ${TOP_ACTOR_CLASS}`;
|
||||
}
|
||||
rect.x = actor.x;
|
||||
rect.y = actorY;
|
||||
rect.width = actor.width;
|
||||
rect.height = actor.height;
|
||||
rect.class = cssclass;
|
||||
rect.name = actor.name;
|
||||
|
||||
// DRAW STACKED RECTANGLES
|
||||
const offset = 6;
|
||||
const shadowRect = {
|
||||
...rect,
|
||||
x: rect.x + (isFooter ? -offset : -offset),
|
||||
y: rect.y + (isFooter ? +offset : +offset),
|
||||
class: 'actor',
|
||||
};
|
||||
const rectElem = drawRect(g, rect); // draw main rectangle on top
|
||||
drawRect(g, shadowRect);
|
||||
actor.rectData = rect;
|
||||
|
||||
if (actor.properties?.icon) {
|
||||
const iconSrc = actor.properties.icon.trim();
|
||||
if (iconSrc.charAt(0) === '@') {
|
||||
svgDrawCommon.drawEmbeddedImage(g, rect.x + rect.width - 20, rect.y + 10, iconSrc.substr(1));
|
||||
} else {
|
||||
svgDrawCommon.drawImage(g, rect.x + rect.width - 20, rect.y + 10, iconSrc);
|
||||
}
|
||||
}
|
||||
|
||||
_drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
actor.description,
|
||||
g,
|
||||
rect.x - offset,
|
||||
rect.y + offset,
|
||||
rect.width,
|
||||
rect.height,
|
||||
{ class: `actor ${ACTOR_BOX_CLASS}` },
|
||||
conf
|
||||
);
|
||||
|
||||
let height = actor.height;
|
||||
if (rectElem.node) {
|
||||
const bounds = rectElem.node().getBBox();
|
||||
actor.height = bounds.height;
|
||||
height = bounds.height;
|
||||
}
|
||||
|
||||
return height;
|
||||
};
|
||||
|
||||
const drawActorTypeQueue = function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actorY + actor.height;
|
||||
|
||||
const boxplusLineGroup = elem.append('g').lower();
|
||||
let g = boxplusLineGroup;
|
||||
|
||||
if (!isFooter) {
|
||||
actorCnt++;
|
||||
if (Object.keys(actor.links || {}).length && !conf.forceMenus) {
|
||||
g.attr('onclick', popupMenuToggle(`actor${actorCnt}_popup`)).attr('cursor', 'pointer');
|
||||
}
|
||||
g.append('line')
|
||||
.attr('id', 'actor' + actorCnt)
|
||||
.attr('x1', center)
|
||||
.attr('y1', centerY)
|
||||
.attr('x2', center)
|
||||
.attr('y2', 2000)
|
||||
.attr('class', 'actor-line 200')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999')
|
||||
.attr('name', actor.name);
|
||||
|
||||
g = boxplusLineGroup.append('g');
|
||||
actor.actorCnt = actorCnt;
|
||||
|
||||
if (actor.links != null) {
|
||||
g.attr('id', 'root-' + actorCnt);
|
||||
}
|
||||
}
|
||||
|
||||
const rect = svgDrawCommon.getNoteRect();
|
||||
let cssclass = 'actor';
|
||||
if (actor.properties?.class) {
|
||||
cssclass = actor.properties.class;
|
||||
} else {
|
||||
rect.fill = '#eaeaea';
|
||||
}
|
||||
|
||||
if (isFooter) {
|
||||
cssclass += ` ${BOTTOM_ACTOR_CLASS}`;
|
||||
} else {
|
||||
cssclass += ` ${TOP_ACTOR_CLASS}`;
|
||||
}
|
||||
|
||||
rect.x = actor.x;
|
||||
rect.y = actorY;
|
||||
rect.width = actor.width;
|
||||
rect.height = actor.height;
|
||||
rect.class = cssclass;
|
||||
rect.name = actor.name;
|
||||
|
||||
// Cylinder dimensions
|
||||
const ry = rect.height / 2;
|
||||
const rx = ry / (2.5 + rect.height / 50);
|
||||
|
||||
// Cylinder base group
|
||||
const cylinderGroup = g.append('g');
|
||||
const cylinderArc = g.append('g');
|
||||
|
||||
// Main cylinder body
|
||||
cylinderGroup
|
||||
.append('path')
|
||||
.attr(
|
||||
'd',
|
||||
`M ${rect.x},${rect.y + ry}
|
||||
a ${rx},${ry} 0 0 0 0,${rect.height}
|
||||
h ${rect.width - 2 * rx}
|
||||
a ${rx},${ry} 0 0 0 0,-${rect.height}
|
||||
Z
|
||||
`
|
||||
)
|
||||
.attr('class', cssclass);
|
||||
cylinderArc
|
||||
.append('path')
|
||||
.attr(
|
||||
'd',
|
||||
`M ${rect.x},${rect.y + ry}
|
||||
a ${rx},${ry} 0 0 0 0,${rect.height}`
|
||||
)
|
||||
.attr('stroke', '#666')
|
||||
.attr('stroke-width', '1px')
|
||||
.attr('class', cssclass);
|
||||
|
||||
cylinderGroup.attr('transform', `translate(${rx}, ${-(rect.height / 2)})`);
|
||||
cylinderArc.attr('transform', `translate(${rect.width - rx}, ${-rect.height / 2})`);
|
||||
|
||||
actor.rectData = rect;
|
||||
|
||||
if (actor.properties?.icon) {
|
||||
const iconSrc = actor.properties.icon.trim();
|
||||
const iconX = rect.x + rect.width - 20;
|
||||
const iconY = rect.y + 10;
|
||||
if (iconSrc.charAt(0) === '@') {
|
||||
svgDrawCommon.drawEmbeddedImage(g, iconX, iconY, iconSrc.substr(1));
|
||||
} else {
|
||||
svgDrawCommon.drawImage(g, iconX, iconY, iconSrc);
|
||||
}
|
||||
}
|
||||
|
||||
_drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
actor.description,
|
||||
g,
|
||||
rect.x,
|
||||
rect.y,
|
||||
rect.width,
|
||||
rect.height,
|
||||
{ class: `actor ${ACTOR_BOX_CLASS}` },
|
||||
conf
|
||||
);
|
||||
|
||||
let height = actor.height;
|
||||
const lastPath = cylinderGroup.select('path:last-child');
|
||||
if (lastPath.node()) {
|
||||
const bounds = lastPath.node().getBBox();
|
||||
actor.height = bounds.height;
|
||||
height = bounds.height;
|
||||
}
|
||||
|
||||
return height;
|
||||
};
|
||||
|
||||
const drawActorTypeControl = function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actorY + 75;
|
||||
|
||||
const line = elem.append('g').lower();
|
||||
|
||||
if (!isFooter) {
|
||||
actorCnt++;
|
||||
line
|
||||
.append('line')
|
||||
.attr('id', 'actor' + actorCnt)
|
||||
.attr('x1', center)
|
||||
.attr('y1', centerY)
|
||||
.attr('x2', center)
|
||||
.attr('y2', 2000)
|
||||
.attr('class', 'actor-line 200')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999')
|
||||
.attr('name', actor.name);
|
||||
|
||||
actor.actorCnt = actorCnt;
|
||||
}
|
||||
const actElem = elem.append('g');
|
||||
let cssClass = ACTOR_MAN_FIGURE_CLASS;
|
||||
if (isFooter) {
|
||||
cssClass += ` ${BOTTOM_ACTOR_CLASS}`;
|
||||
} else {
|
||||
cssClass += ` ${TOP_ACTOR_CLASS}`;
|
||||
}
|
||||
actElem.attr('class', cssClass);
|
||||
actElem.attr('name', actor.name);
|
||||
|
||||
const rect = svgDrawCommon.getNoteRect();
|
||||
rect.x = actor.x;
|
||||
rect.y = actorY;
|
||||
rect.fill = '#eaeaea';
|
||||
rect.width = actor.width;
|
||||
rect.height = actor.height;
|
||||
rect.class = 'actor';
|
||||
|
||||
const cx = actor.x + actor.width / 2;
|
||||
const cy = actorY + 30;
|
||||
const r = 18;
|
||||
|
||||
actElem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', 'filled-head-control')
|
||||
.attr('refX', 11)
|
||||
.attr('refY', 5.8)
|
||||
.attr('markerWidth', 20)
|
||||
.attr('markerHeight', 28)
|
||||
.attr('orient', '172.5')
|
||||
.append('path')
|
||||
.attr('d', 'M 14.4 5.6 L 7.2 10.4 L 8.8 5.6 L 7.2 0.8 Z');
|
||||
|
||||
// Draw the base circle
|
||||
actElem
|
||||
.append('circle')
|
||||
.attr('cx', cx)
|
||||
.attr('cy', cy)
|
||||
.attr('r', r)
|
||||
.attr('fill', '#eaeaf7')
|
||||
.attr('stroke', '#666')
|
||||
.attr('stroke-width', 1.2);
|
||||
|
||||
// Draw looping arrow as arc path
|
||||
actElem
|
||||
.append('line')
|
||||
.attr('marker-end', 'url(#filled-head-control)')
|
||||
.attr('transform', `translate(${cx}, ${cy - r})`);
|
||||
|
||||
const bounds = actElem.node().getBBox();
|
||||
actor.height = bounds.height + 2 * (conf?.sequence?.labelBoxHeight ?? 0);
|
||||
|
||||
_drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
actor.description,
|
||||
actElem,
|
||||
rect.x,
|
||||
rect.y + r + (isFooter ? 5 : 10),
|
||||
rect.width,
|
||||
rect.height,
|
||||
{ class: `actor ${ACTOR_MAN_FIGURE_CLASS}` },
|
||||
conf
|
||||
);
|
||||
|
||||
return actor.height;
|
||||
};
|
||||
|
||||
const drawActorTypeEntity = function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actorY + 75;
|
||||
|
||||
const line = elem.append('g').lower();
|
||||
|
||||
const actElem = elem.append('g');
|
||||
let cssClass = ACTOR_MAN_FIGURE_CLASS;
|
||||
if (isFooter) {
|
||||
cssClass += ` ${BOTTOM_ACTOR_CLASS}`;
|
||||
} else {
|
||||
cssClass += ` ${TOP_ACTOR_CLASS}`;
|
||||
}
|
||||
actElem.attr('class', cssClass);
|
||||
actElem.attr('name', actor.name);
|
||||
|
||||
const rect = svgDrawCommon.getNoteRect();
|
||||
rect.x = actor.x;
|
||||
rect.y = actorY;
|
||||
rect.fill = '#eaeaea';
|
||||
rect.width = actor.width;
|
||||
rect.height = actor.height;
|
||||
rect.class = 'actor';
|
||||
|
||||
const cx = actor.x + actor.width / 2;
|
||||
const cy = actorY + (!isFooter ? 25 : 10);
|
||||
const r = 18;
|
||||
|
||||
actElem
|
||||
.append('circle')
|
||||
.attr('cx', cx)
|
||||
.attr('cy', cy)
|
||||
.attr('r', r)
|
||||
.attr('width', actor.width)
|
||||
.attr('height', actor.height);
|
||||
|
||||
actElem
|
||||
.append('line')
|
||||
.attr('x1', cx - r)
|
||||
.attr('x2', cx + r)
|
||||
.attr('y1', cy + r)
|
||||
.attr('y2', cy + r)
|
||||
.attr('stroke', '#333')
|
||||
.attr('stroke-width', 2);
|
||||
|
||||
const bounds = actElem.node().getBBox();
|
||||
actor.height = bounds.height + (conf?.sequence?.labelBoxHeight ?? 0);
|
||||
|
||||
if (!isFooter) {
|
||||
actorCnt++;
|
||||
line
|
||||
.append('line')
|
||||
.attr('id', 'actor' + actorCnt)
|
||||
.attr('x1', center)
|
||||
.attr('y1', centerY)
|
||||
.attr('x2', center)
|
||||
.attr('y2', 2000)
|
||||
.attr('class', 'actor-line 200')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999')
|
||||
.attr('name', actor.name);
|
||||
|
||||
actor.actorCnt = actorCnt;
|
||||
}
|
||||
|
||||
_drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
actor.description,
|
||||
actElem,
|
||||
rect.x,
|
||||
rect.y + (!isFooter ? (cy + r - actorY) / 2 : (cy - actorY + r - 5) / 2),
|
||||
rect.width,
|
||||
rect.height,
|
||||
{ class: `actor ${ACTOR_MAN_FIGURE_CLASS}` },
|
||||
conf
|
||||
);
|
||||
|
||||
if (!isFooter) {
|
||||
actElem.attr('transform', `translate(${0}, ${r / 2})`);
|
||||
} else {
|
||||
actElem.attr('transform', `translate(${0}, ${r / 2})`);
|
||||
}
|
||||
|
||||
return actor.height;
|
||||
};
|
||||
|
||||
const drawActorTypeDatabase = function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actorY + actor.height + 2 * conf.boxTextMargin;
|
||||
|
||||
const boxplusLineGroup = elem.append('g').lower();
|
||||
let g = boxplusLineGroup;
|
||||
|
||||
if (!isFooter) {
|
||||
actorCnt++;
|
||||
if (Object.keys(actor.links || {}).length && !conf.forceMenus) {
|
||||
g.attr('onclick', popupMenuToggle(`actor${actorCnt}_popup`)).attr('cursor', 'pointer');
|
||||
}
|
||||
g.append('line')
|
||||
.attr('id', 'actor' + actorCnt)
|
||||
.attr('x1', center)
|
||||
.attr('y1', centerY)
|
||||
.attr('x2', center)
|
||||
.attr('y2', 2000)
|
||||
.attr('class', 'actor-line 200')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999')
|
||||
.attr('name', actor.name);
|
||||
|
||||
g = boxplusLineGroup.append('g');
|
||||
actor.actorCnt = actorCnt;
|
||||
|
||||
if (actor.links != null) {
|
||||
g.attr('id', 'root-' + actorCnt);
|
||||
}
|
||||
}
|
||||
|
||||
const rect = svgDrawCommon.getNoteRect();
|
||||
|
||||
let cssclass = 'actor';
|
||||
if (actor.properties?.class) {
|
||||
cssclass = actor.properties.class;
|
||||
} else {
|
||||
rect.fill = '#eaeaea';
|
||||
}
|
||||
|
||||
if (isFooter) {
|
||||
cssclass += ` ${BOTTOM_ACTOR_CLASS}`;
|
||||
} else {
|
||||
cssclass += ` ${TOP_ACTOR_CLASS}`;
|
||||
}
|
||||
|
||||
rect.x = actor.x;
|
||||
rect.y = actorY;
|
||||
rect.width = actor.width;
|
||||
rect.height = actor.height;
|
||||
rect.class = cssclass;
|
||||
rect.name = actor.name;
|
||||
|
||||
// Cylinder dimensions
|
||||
rect.x = actor.x;
|
||||
rect.y = actorY;
|
||||
const w = rect.width / 4;
|
||||
const h = rect.width / 4;
|
||||
const rx = w / 2;
|
||||
const ry = rx / (2.5 + w / 50);
|
||||
|
||||
// Cylinder base group
|
||||
const cylinderGroup = g.append('g');
|
||||
|
||||
const d = `
|
||||
M ${rect.x},${rect.y + ry}
|
||||
a ${rx},${ry} 0 0 0 ${w},0
|
||||
a ${rx},${ry} 0 0 0 -${w},0
|
||||
l 0,${h - 2 * ry}
|
||||
a ${rx},${ry} 0 0 0 ${w},0
|
||||
l 0,-${h - 2 * ry}
|
||||
`;
|
||||
// Draw the main cylinder body
|
||||
cylinderGroup
|
||||
.append('path')
|
||||
.attr('d', d)
|
||||
.attr('fill', '#eaeaea')
|
||||
.attr('stroke', '#000')
|
||||
.attr('stroke-width', 1)
|
||||
.attr('class', cssclass);
|
||||
|
||||
if (!isFooter) {
|
||||
cylinderGroup.attr('transform', `translate(${w * 1.5}, ${(rect.height + ry) / 4})`);
|
||||
} else {
|
||||
cylinderGroup.attr('transform', `translate(${w * 1.5}, ${rect.height / 4 - 2 * ry})`);
|
||||
}
|
||||
actor.rectData = rect;
|
||||
_drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
actor.description,
|
||||
g,
|
||||
rect.x,
|
||||
rect.y + (!isFooter ? (rect.height + ry) / 2 : (rect.height + h) / 4),
|
||||
rect.width,
|
||||
rect.height,
|
||||
{ class: `actor ${ACTOR_BOX_CLASS}` },
|
||||
conf
|
||||
);
|
||||
|
||||
const lastPath = cylinderGroup.select('path:last-child');
|
||||
if (lastPath.node()) {
|
||||
const bounds = lastPath.node().getBBox();
|
||||
actor.height = bounds.height + (conf.sequence.labelBoxHeight ?? 0);
|
||||
}
|
||||
|
||||
return actor.height;
|
||||
};
|
||||
|
||||
const drawActorTypeBoundary = function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actorY + 80;
|
||||
const radius = 30;
|
||||
const line = elem.append('g').lower();
|
||||
|
||||
if (!isFooter) {
|
||||
actorCnt++;
|
||||
line
|
||||
.append('line')
|
||||
.attr('id', 'actor' + actorCnt)
|
||||
.attr('x1', center)
|
||||
.attr('y1', centerY)
|
||||
.attr('x2', center)
|
||||
.attr('y2', 2000)
|
||||
.attr('class', 'actor-line 200')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999')
|
||||
.attr('name', actor.name);
|
||||
|
||||
actor.actorCnt = actorCnt;
|
||||
}
|
||||
const actElem = elem.append('g');
|
||||
let cssClass = ACTOR_MAN_FIGURE_CLASS;
|
||||
if (isFooter) {
|
||||
cssClass += ` ${BOTTOM_ACTOR_CLASS}`;
|
||||
} else {
|
||||
cssClass += ` ${TOP_ACTOR_CLASS}`;
|
||||
}
|
||||
actElem.attr('class', cssClass);
|
||||
actElem.attr('name', actor.name);
|
||||
|
||||
const rect = svgDrawCommon.getNoteRect();
|
||||
rect.x = actor.x;
|
||||
rect.y = actorY;
|
||||
rect.fill = '#eaeaea';
|
||||
rect.width = actor.width;
|
||||
rect.height = actor.height;
|
||||
rect.class = 'actor';
|
||||
|
||||
actElem
|
||||
.append('line')
|
||||
.attr('id', 'actor-man-torso' + actorCnt)
|
||||
.attr('x1', actor.x + actor.width / 2 - radius * 2.5)
|
||||
.attr('y1', actorY + 10)
|
||||
.attr('x2', actor.x + actor.width / 2 - 15)
|
||||
.attr('y2', actorY + 10);
|
||||
|
||||
actElem
|
||||
.append('line')
|
||||
.attr('id', 'actor-man-arms' + actorCnt)
|
||||
.attr('x1', actor.x + actor.width / 2 - radius * 2.5)
|
||||
.attr('y1', actorY + 0) // starting Y
|
||||
.attr('x2', actor.x + actor.width / 2 - radius * 2.5)
|
||||
.attr('y2', actorY + 20); // ending Y (26px long, adjust as needed)
|
||||
|
||||
actElem
|
||||
.append('circle')
|
||||
.attr('cx', actor.x + actor.width / 2)
|
||||
.attr('cy', actorY + 10)
|
||||
.attr('r', radius);
|
||||
|
||||
const bounds = actElem.node().getBBox();
|
||||
actor.height = bounds.height + (conf.sequence.labelBoxHeight ?? 0);
|
||||
|
||||
_drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
actor.description,
|
||||
actElem,
|
||||
rect.x,
|
||||
rect.y + (!isFooter ? radius / 2 + 3 : radius / 2 - 4),
|
||||
rect.width,
|
||||
rect.height,
|
||||
{ class: `actor ${ACTOR_MAN_FIGURE_CLASS}` },
|
||||
conf
|
||||
);
|
||||
|
||||
if (!isFooter) {
|
||||
actElem.attr('transform', `translate(0,${radius / 2 + 7})`);
|
||||
} else {
|
||||
actElem.attr('transform', `translate(0,${radius / 2 + 7})`);
|
||||
}
|
||||
|
||||
return actor.height;
|
||||
};
|
||||
|
||||
const drawActorTypeActor = function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
@@ -1110,18 +516,6 @@ export const drawActor = async function (elem, actor, conf, isFooter) {
|
||||
return await drawActorTypeActor(elem, actor, conf, isFooter);
|
||||
case 'participant':
|
||||
return await drawActorTypeParticipant(elem, actor, conf, isFooter);
|
||||
case 'boundary':
|
||||
return await drawActorTypeBoundary(elem, actor, conf, isFooter);
|
||||
case 'control':
|
||||
return await drawActorTypeControl(elem, actor, conf, isFooter);
|
||||
case 'entity':
|
||||
return await drawActorTypeEntity(elem, actor, conf, isFooter);
|
||||
case 'database':
|
||||
return await drawActorTypeDatabase(elem, actor, conf, isFooter);
|
||||
case 'collections':
|
||||
return await drawActorTypeCollections(elem, actor, conf, isFooter);
|
||||
case 'queue':
|
||||
return await drawActorTypeQueue(elem, actor, conf, isFooter);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1709,77 +1103,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 +1125,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'
|
||||
|
@@ -17,7 +17,6 @@ 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,7 +23,6 @@ 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,13 +33,11 @@ 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)
|
||||
|
@@ -21,21 +21,21 @@
|
||||
"font-awesome": "^4.7.0",
|
||||
"jiti": "^2.4.2",
|
||||
"mermaid": "workspace:^",
|
||||
"vue": "^3.4.38"
|
||||
"vue": "^3.5.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/carbon": "^1.1.37",
|
||||
"@iconify-json/carbon": "^1.2.13",
|
||||
"@unocss/reset": "^66.0.0",
|
||||
"@vite-pwa/vitepress": "^1.0.0",
|
||||
"@vitejs/plugin-vue": "^6.0.0",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"fast-glob": "^3.3.3",
|
||||
"https-localhost": "^4.7.1",
|
||||
"pathe": "^2.0.3",
|
||||
"unocss": "^66.0.0",
|
||||
"unplugin-vue-components": "^28.4.0",
|
||||
"unplugin-vue-components": "^28.4.1",
|
||||
"vite": "^6.1.1",
|
||||
"vite-plugin-pwa": "^1.0.0",
|
||||
"vitepress": "1.6.3",
|
||||
"vite-plugin-pwa": "^1.0.3",
|
||||
"vitepress": "1.6.4",
|
||||
"workbox-window": "^7.3.0"
|
||||
}
|
||||
}
|
||||
|
@@ -83,7 +83,6 @@ 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)
|
||||
@@ -97,7 +96,6 @@ 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
|
||||
@@ -107,7 +105,6 @@ 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
|
||||
@@ -116,18 +113,15 @@ 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
|
||||
|
@@ -46,78 +46,6 @@ sequenceDiagram
|
||||
Bob->>Alice: Hi Alice
|
||||
```
|
||||
|
||||
### Boundary
|
||||
|
||||
If you want to use the boundary symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "boundary" }
|
||||
participant Bob
|
||||
Alice->>Bob: Request from boundary
|
||||
Bob->>Alice: Response to boundary
|
||||
```
|
||||
|
||||
### Control
|
||||
|
||||
If you want to use the control symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "control" }
|
||||
participant Bob
|
||||
Alice->>Bob: Control request
|
||||
Bob->>Alice: Control response
|
||||
```
|
||||
|
||||
### Entity
|
||||
|
||||
If you want to use the entity symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "entity" }
|
||||
participant Bob
|
||||
Alice->>Bob: Entity request
|
||||
Bob->>Alice: Entity response
|
||||
```
|
||||
|
||||
### Database
|
||||
|
||||
If you want to use the database symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "database" }
|
||||
participant Bob
|
||||
Alice->>Bob: DB query
|
||||
Bob->>Alice: DB result
|
||||
```
|
||||
|
||||
### Collections
|
||||
|
||||
If you want to use the collections symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "collections" }
|
||||
participant Bob
|
||||
Alice->>Bob: Collections request
|
||||
Bob->>Alice: Collections response
|
||||
```
|
||||
|
||||
### Queue
|
||||
|
||||
If you want to use the queue symbol for a participant, use the JSON configuration syntax as shown below.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "queue" }
|
||||
participant Bob
|
||||
Alice->>Bob: Queue message
|
||||
Bob->>Alice: Queue response
|
||||
```
|
||||
|
||||
### Aliases
|
||||
|
||||
The actor can have a convenient identifier and a descriptive label.
|
||||
@@ -216,11 +144,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 +159,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**
|
||||
|
||||
The following half-arrow types are now 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
|
||||
|
||||
Mermaid sequence diagrams now 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']
|
||||
`);
|
||||
});
|
||||
|
||||
|
@@ -13,18 +13,6 @@ export interface NodeMetaData {
|
||||
ticket?: string;
|
||||
}
|
||||
|
||||
export interface ParticipantMetaData {
|
||||
type?:
|
||||
| 'actor'
|
||||
| 'participant'
|
||||
| 'boundary'
|
||||
| 'control'
|
||||
| 'entity'
|
||||
| 'database'
|
||||
| 'collections'
|
||||
| 'queue';
|
||||
}
|
||||
|
||||
export interface EdgeMetaData {
|
||||
animation?: 'fast' | 'slow';
|
||||
animate?: boolean;
|
||||
|
@@ -44,20 +44,16 @@ 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`?
|
||||
|
||||
- To modify the returned value from the parser.
|
||||
|
@@ -154,7 +154,6 @@
|
||||
### 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 ...)
|
||||
@@ -173,14 +172,12 @@
|
||||
### 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
|
||||
|
||||
@@ -229,7 +226,6 @@
|
||||
- [#5999](https://github.com/mermaid-js/mermaid/pull/5999) [`742ad7c`](https://github.com/mermaid-js/mermaid/commit/742ad7c130964df1fb5544e909d9556081285f68) Thanks [@knsv](https://github.com/knsv)! - Adding Kanban board, a new diagram type
|
||||
|
||||
- [#5880](https://github.com/mermaid-js/mermaid/pull/5880) [`bdf145f`](https://github.com/mermaid-js/mermaid/commit/bdf145ffe362462176d9c1e68d5f3ff5c9d962b0) Thanks [@yari-dewalt](https://github.com/yari-dewalt)! - Class diagram changes:
|
||||
|
||||
- Updates the class diagram to the new unified way of rendering.
|
||||
- Includes a new "classBox" shape to be used in diagrams
|
||||
- Other updates such as:
|
||||
|
3412
pnpm-lock.yaml
generated
3412
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user