mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-29 12:19:41 +02:00
Compare commits
48 Commits
mermaid@11
...
renovate/p
Author | SHA1 | Date | |
---|---|---|---|
![]() |
99be04115c | ||
![]() |
717d3b3bb2 | ||
![]() |
2f8d9ba958 | ||
![]() |
7effdc147b | ||
![]() |
6e67515f41 | ||
![]() |
09b74f1c29 | ||
![]() |
880da21908 | ||
![]() |
38191243be | ||
![]() |
b75dcb8a82 | ||
![]() |
4c1e170f4a | ||
![]() |
d5c4eff251 | ||
![]() |
5324fd8dfd | ||
![]() |
bd25b88a01 | ||
![]() |
d3de3ecbbb | ||
![]() |
3964ce0a0f | ||
![]() |
4dbabba8e8 | ||
![]() |
e3ef5e4208 | ||
![]() |
daeb85bac2 | ||
![]() |
2cdaf03ada | ||
![]() |
f6fa0260e7 | ||
![]() |
29aad6d23c | ||
![]() |
82ef7b5fdb | ||
![]() |
11cd3f1262 | ||
![]() |
ac4aa94e78 | ||
![]() |
c40faac80d | ||
![]() |
c530baed3f | ||
![]() |
045699de10 | ||
![]() |
1988d24227 | ||
![]() |
39f90debe7 | ||
![]() |
73e9849f99 | ||
![]() |
5a05540a5f | ||
![]() |
2b58df9665 | ||
![]() |
0b42bdba07 | ||
![]() |
74c96db3e2 | ||
![]() |
bd47c57eaf | ||
![]() |
3e5d2db514 | ||
![]() |
40990bb096 | ||
![]() |
7ca0665764 | ||
![]() |
81a6a361ab | ||
![]() |
62faacdeeb | ||
![]() |
0e40d8e8a8 | ||
![]() |
e8d6daf4f6 | ||
![]() |
cb4ed605b2 | ||
![]() |
ba9db26bfa | ||
![]() |
252b1837f7 | ||
![]() |
6b9c15d7f0 | ||
![]() |
fda640c90c | ||
![]() |
584a789183 |
5
.changeset/deep-pumas-run.md
Normal file
5
.changeset/deep-pumas-run.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
chore: Fix mindmap rendering in docs and apply tidytree layout
|
5
.changeset/four-eyes-wish.md
Normal file
5
.changeset/four-eyes-wish.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Ensure edge label color is applied when using classDef with edge IDs
|
5
.changeset/loud-results-melt.md
Normal file
5
.changeset/loud-results-melt.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Add half-arrowheads (solid & stick) and central connection support
|
5
.changeset/moody-fans-try.md
Normal file
5
.changeset/moody-fans-try.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Resolve gantt chart crash due to invalid array length
|
5
.changeset/proud-colts-smell.md
Normal file
5
.changeset/proud-colts-smell.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Add IDs in architecture diagrams
|
9
.changeset/revert-marked-dependency.md
Normal file
9
.changeset/revert-marked-dependency.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
chore: revert marked dependency from ^15.0.7 to ^16.0.0
|
||||
|
||||
- Reverted marked package version to ^16.0.0 for better compatibility
|
||||
- This is a dependency update that maintains API compatibility
|
||||
- All tests pass with the updated version
|
5
.changeset/sweet-games-build.md
Normal file
5
.changeset/sweet-games-build.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix(er-diagram): prevent syntax error when using 'u', numbers, and decimals in node names
|
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@@ -26,8 +26,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ['javascript']
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
language: ['javascript', 'actions']
|
||||
# CodeQL supports [ 'actions', 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
|
2
.github/workflows/e2e-timings.yml
vendored
2
.github/workflows/e2e-timings.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Commit and create pull request
|
||||
uses: peter-evans/create-pull-request@915d841dae6a4f191bb78faf61a257411d7be4d2
|
||||
uses: peter-evans/create-pull-request@9ec683ee07f9121fdf529b923931dd78d977a5c9
|
||||
with:
|
||||
add-paths: |
|
||||
cypress/timings.json
|
||||
|
@@ -369,4 +369,92 @@ ORDER ||--|{ LINE-ITEM : contains
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Special characters and numbers syntax', () => {
|
||||
it('should render ER diagram with numeric entity names', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
erDiagram
|
||||
1 ||--|| ORDER : places
|
||||
ORDER ||--|{ 2 : contains
|
||||
2 ||--o{ 3.5 : references
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render ER diagram with "u" character in entity names and cardinality', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
erDiagram
|
||||
CUSTOMER ||--|| u : has
|
||||
u ||--|| ORDER : places
|
||||
PROJECT u--o{ TEAM_MEMBER : "parent"
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render ER diagram with decimal numbers in relationships', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
erDiagram
|
||||
2.5 ||--|| 1.5 : has
|
||||
CUSTOMER ||--o{ 3.14 : references
|
||||
1.0 ||--|{ ORDER : contains
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render ER diagram with numeric entity names and attributes', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
erDiagram
|
||||
1 {
|
||||
string name
|
||||
int value
|
||||
}
|
||||
1 ||--|| ORDER : places
|
||||
ORDER {
|
||||
float price
|
||||
string description
|
||||
}
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render complex ER diagram with mixed special entity names', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
erDiagram
|
||||
CUSTOMER ||--o{ 1 : places
|
||||
1 ||--|{ u : contains
|
||||
1.5
|
||||
u ||--|| 2.5 : processes
|
||||
2.5 {
|
||||
string id
|
||||
float value
|
||||
}
|
||||
u {
|
||||
varchar(50) name
|
||||
int count
|
||||
}
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
});
|
||||
it('should render ER diagram with numeric entity names and attributes', () => {
|
||||
imgSnapshotTest(
|
||||
`erDiagram
|
||||
PRODUCT ||--o{ ORDER-ITEM : has
|
||||
1.5
|
||||
u
|
||||
1
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -655,5 +655,126 @@ describe('Sequence Diagram Special Cases', () => {
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Central Connection Rendering Tests', () => {
|
||||
it('should render central connection circles on actor vertical lines', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
Alice ()->>() Bob: Central connection
|
||||
Bob ()-->> Charlie: Reverse central connection
|
||||
Charlie ()<<-->>() Alice: Dual central connection`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with different arrow types', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()->>() Bob: Solid open arrow
|
||||
Alice ()-->>() Bob: Dotted open arrow
|
||||
Alice ()-x() Bob: Solid cross
|
||||
Alice ()--x() Bob: Dotted cross
|
||||
Alice ()->() Bob: Solid arrow`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with bidirectional arrows', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()<<->>() Bob: Bidirectional solid
|
||||
Alice ()<<-->>() Bob: Bidirectional dotted`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with activations', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
Alice ()->>() Bob: Activate Bob
|
||||
activate Bob
|
||||
Bob ()-->> Charlie: Message to Charlie
|
||||
Bob ()->>() Alice: Response to Alice
|
||||
deactivate Bob`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections mixed with normal messages', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
Alice ->> Bob: Normal message
|
||||
Bob ()->>() Charlie: Central connection
|
||||
Charlie -->> Alice: Normal dotted message
|
||||
Alice ()<<-->>() Bob: Dual central connection
|
||||
Bob -x Charlie: Normal cross message`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with notes', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
Alice ()->>() Bob: Central connection
|
||||
Note over Alice,Bob: Central connection note
|
||||
Bob ()-->> Charlie: Reverse central connection
|
||||
Note right of Charlie: Response note
|
||||
Charlie ()<<-->>() Alice: Dual central connection`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with loops and alternatives', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
loop Every minute
|
||||
Alice ()->>() Bob: Central heartbeat
|
||||
Bob ()-->> Charlie: Forward heartbeat
|
||||
end
|
||||
alt Success
|
||||
Charlie ()<<-->>() Alice: Success response
|
||||
else Failure
|
||||
Charlie ()-x() Alice: Failure response
|
||||
end`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with different participant types', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
actor Bob
|
||||
participant Charlie@{"type":"boundary"}
|
||||
participant David@{"type":"control"}
|
||||
participant Eve@{"type":"entity"}
|
||||
Alice ()->>() Bob: To actor
|
||||
Bob ()-->> Charlie: To boundary
|
||||
Charlie ()->>() David: To control
|
||||
David ()<<-->>() Eve: To entity
|
||||
Eve ()-x() Alice: Back to participant`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1053,4 +1053,167 @@ describe('Sequence diagram', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
describe('render new arrow type', () => {
|
||||
it('should render Solid half arrow top', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice -|\\ John: Hello John, how are you?
|
||||
Alice-|\\ John: Hi Alice, I can hear you!
|
||||
Alice -|\\ John: Test
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should render Solid half arrow bottom', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice-|/John: Hello John, how are you?
|
||||
Alice-|/John: Hi Alice, I can hear you!
|
||||
Alice-|/John: Test
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow top ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice-\\\\John: Hello John, how are you?
|
||||
Alice-\\\\John: Hi Alice, I can hear you!
|
||||
Alice-\\\\John: Test
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should render Stick half arrow bottom ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice-//John: Hello John, how are you?
|
||||
Alice-//John: Hi Alice, I can hear you!
|
||||
Alice-//John: Test
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should render Solid half arrow top reverse ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice/|-John: Hello Alice, how are you?
|
||||
Alice/|-John: Hi Alice, I can hear you!
|
||||
Alice/|-John: Test
|
||||
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Solid half arrow bottom reverse ', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
Alice \\|- John: Hello Alice, how are you?
|
||||
Alice \\|- John: Hi Alice, I can hear you!
|
||||
Alice \\|- John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow top reverse ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice //-John: Hello Alice, how are you?
|
||||
Alice //-John: Hi Alice, I can hear you!
|
||||
Alice //-John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow bottom reverse ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice \\\\-John: Hello Alice, how are you?
|
||||
Alice \\\\-John: Hi Alice, I can hear you!
|
||||
Alice \\\\-John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Solid half arrow top dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice --|\\John: Hello John, how are you?
|
||||
Alice --|\\John: Hi Alice, I can hear you!
|
||||
Alice --|\\John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Solid half arrow bottom dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice --|/John: Hello John, how are you?
|
||||
Alice --|/John: Hi Alice, I can hear you!
|
||||
Alice --|/John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow top dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice--\\\\John: Hello John, how are you?
|
||||
Alice--\\\\John: Hi Alice, I can hear you!
|
||||
Alice--\\\\John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow bottom dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice--//John: Hello John, how are you?
|
||||
Alice--//John: Hi Alice, I can hear you!
|
||||
Alice--//John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Solid half arrow top reverse dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice/|--John: Hello Alice, how are you?
|
||||
Alice/|--John: Hi Alice, I can hear you!
|
||||
Alice/|--John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Solid half arrow bottom reverse dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice\\|--John: Hello Alice, how are you?
|
||||
Alice\\|--John: Hi Alice, I can hear you!
|
||||
Alice\\|--John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow top reverse dotted ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice//--John: Hello Alice, how are you?
|
||||
Alice//--John: Hi Alice, I can hear you!
|
||||
Alice//--John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow bottom reverse dotted ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice\\\\--John: Hello Alice, how are you?
|
||||
Alice\\\\--John: Hi Alice, I can hear you!
|
||||
Alice\\\\--John: Test`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -329,7 +329,11 @@ Messages can be of two displayed either solid or with a dotted line.
|
||||
[Actor][Arrow][Actor]:Message text
|
||||
```
|
||||
|
||||
There are ten types of arrows currently supported:
|
||||
Lines can be solid or dotted, and can end with various types of arrowheads, crosses, or open arrows.
|
||||
|
||||
#### Supported Arrow Types
|
||||
|
||||
**Standard Arrow Types**
|
||||
|
||||
| Type | Description |
|
||||
| -------- | ---------------------------------------------------- |
|
||||
@@ -344,6 +348,58 @@ There are ten types of arrows currently supported:
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
|
||||
**Half-Arrows (v\<MERMAID_RELEASE_VERSION>+)**
|
||||
|
||||
The following half-arrow types are supported for more expressive sequence diagrams. Both solid and dotted variants are available by increasing the number of dashes (`-` → `--`).
|
||||
|
||||
---
|
||||
|
||||
| Type | Description |
|
||||
| ------- | ---------------------------------------------------- |
|
||||
| `-\|\` | Solid line with top half arrowhead |
|
||||
| `--\|\` | Dotted line with top half arrowhead |
|
||||
| `-\|/` | Solid line with bottom half arrowhead |
|
||||
| `--\|/` | Dotted line with bottom half arrowhead |
|
||||
| `/\|-` | Solid line with reverse top half arrowhead |
|
||||
| `/\|--` | Dotted line with reverse top half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom half arrowhead |
|
||||
| `-\\` | Solid line with top stick half arrowhead |
|
||||
| `--\\` | Dotted line with top stick half arrowhead |
|
||||
| `-//` | Solid line with bottom stick half arrowhead |
|
||||
| `--//` | Dotted line with bottom stick half arrowhead |
|
||||
| `//-` | Solid line with reverse top stick half arrowhead |
|
||||
| `//--` | Dotted line with reverse top stick half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom stick half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom stick half arrowhead |
|
||||
|
||||
## Central Connections (v\<MERMAID_RELEASE_VERSION>+)
|
||||
|
||||
Mermaid sequence diagrams support **central lifeline connections** using a `()`.
|
||||
This is useful to represent messages or signals that connect to a central point, rather than from one actor directly to another.
|
||||
|
||||
To indicate a central connection, append `()` to the arrow syntax.
|
||||
|
||||
#### Basic Syntax
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
Alice->>()John: Hello John
|
||||
Alice()->>John: How are you?
|
||||
John()->>()Alice: Great!
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
Alice->>()John: Hello John
|
||||
Alice()->>John: How are you?
|
||||
John()->>()Alice: Great!
|
||||
```
|
||||
|
||||
## Activations
|
||||
|
||||
It is possible to activate and deactivate an actor. (de)activation can be dedicated declarations:
|
||||
|
36
package.json
36
package.json
@@ -63,12 +63,12 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@applitools/eyes-cypress": "^3.44.9",
|
||||
"@applitools/eyes-cypress": "^3.55.2",
|
||||
"@argos-ci/cypress": "^6.1.1",
|
||||
"@changesets/changelog-github": "^0.5.1",
|
||||
"@changesets/cli": "^2.27.12",
|
||||
"@changesets/cli": "^2.29.7",
|
||||
"@cspell/eslint-plugin": "^8.19.4",
|
||||
"@cypress/code-coverage": "^3.12.49",
|
||||
"@cypress/code-coverage": "^3.14.6",
|
||||
"@eslint/js": "^9.26.0",
|
||||
"@rollup/plugin-typescript": "^12.1.4",
|
||||
"@types/cors": "^2.8.19",
|
||||
@@ -77,22 +77,22 @@
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/lodash": "^4.17.20",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"@types/node": "^22.13.17",
|
||||
"@types/node": "^22.18.6",
|
||||
"@types/rollup-plugin-visualizer": "^5.0.3",
|
||||
"@vitest/coverage-v8": "^3.0.9",
|
||||
"@vitest/spy": "^3.0.9",
|
||||
"@vitest/ui": "^3.0.9",
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"@vitest/spy": "^3.2.4",
|
||||
"@vitest/ui": "^3.2.4",
|
||||
"ajv": "^8.17.1",
|
||||
"chokidar": "3.6.0",
|
||||
"concurrently": "^9.1.2",
|
||||
"concurrently": "^9.2.1",
|
||||
"cors": "^2.8.5",
|
||||
"cpy-cli": "^5.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"cspell": "^9.1.5",
|
||||
"cspell": "^9.2.1",
|
||||
"cypress": "^14.5.4",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
"cypress-split": "^1.24.21",
|
||||
"esbuild": "^0.25.9",
|
||||
"cypress-split": "^1.24.23",
|
||||
"esbuild": "^0.25.10",
|
||||
"eslint": "^9.26.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-cypress": "^4.3.0",
|
||||
@@ -106,10 +106,10 @@
|
||||
"eslint-plugin-tsdoc": "^0.4.0",
|
||||
"eslint-plugin-unicorn": "^59.0.1",
|
||||
"express": "^5.1.0",
|
||||
"globals": "^16.0.0",
|
||||
"globals": "^16.4.0",
|
||||
"globby": "^14.1.0",
|
||||
"husky": "^9.1.7",
|
||||
"jest": "^30.0.5",
|
||||
"jest": "^30.1.3",
|
||||
"jison": "^0.4.18",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsdom": "^26.1.0",
|
||||
@@ -118,18 +118,18 @@
|
||||
"markdown-table": "^3.0.4",
|
||||
"nyc": "^17.1.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-jsdoc": "^1.3.3",
|
||||
"rimraf": "^6.0.1",
|
||||
"rollup-plugin-visualizer": "^6.0.3",
|
||||
"start-server-and-test": "^2.0.13",
|
||||
"start-server-and-test": "^2.1.2",
|
||||
"tslib": "^2.8.1",
|
||||
"tsx": "^4.7.3",
|
||||
"tsx": "^4.20.5",
|
||||
"typescript": "~5.7.3",
|
||||
"typescript-eslint": "^8.38.0",
|
||||
"vite": "^7.0.6",
|
||||
"vite": "^7.0.7",
|
||||
"vite-plugin-istanbul": "^7.0.0",
|
||||
"vitest": "^3.0.9"
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"nyc": {
|
||||
"report-dir": "coverage/cypress"
|
||||
|
@@ -42,7 +42,7 @@
|
||||
"khroma": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^9.1.2",
|
||||
"concurrently": "^9.2.1",
|
||||
"mermaid": "workspace:*",
|
||||
"rimraf": "^6.0.1"
|
||||
},
|
||||
|
@@ -33,7 +33,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@zenuml/core": "^3.35.2"
|
||||
"@zenuml/core": "^3.41.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mermaid": "workspace:^"
|
||||
|
@@ -1,24 +1,5 @@
|
||||
# mermaid
|
||||
|
||||
## 11.12.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#6921](https://github.com/mermaid-js/mermaid/pull/6921) [`764b315`](https://github.com/mermaid-js/mermaid/commit/764b315dc16d0359add7c6b8e3ef7592e9bdc09c) Thanks [@quilicicf](https://github.com/quilicicf)! - feat: Add IDs in architecture diagrams
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6950](https://github.com/mermaid-js/mermaid/pull/6950) [`a957908`](https://github.com/mermaid-js/mermaid/commit/a9579083bfba367a4f4678547ec37ed7b61b9f5b) Thanks [@shubhamparikh2704](https://github.com/shubhamparikh2704)! - chore: Fix mindmap rendering in docs and apply tidytree layout
|
||||
|
||||
- [#6826](https://github.com/mermaid-js/mermaid/pull/6826) [`1d36810`](https://github.com/mermaid-js/mermaid/commit/1d3681053b9168354e48e5763023b6305cd1ca72) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Ensure edge label color is applied when using classDef with edge IDs
|
||||
|
||||
- [#6945](https://github.com/mermaid-js/mermaid/pull/6945) [`d318f1a`](https://github.com/mermaid-js/mermaid/commit/d318f1a13cd7429334a29c70e449074ec1cb9f68) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Resolve gantt chart crash due to invalid array length
|
||||
|
||||
- [#6918](https://github.com/mermaid-js/mermaid/pull/6918) [`cfe9238`](https://github.com/mermaid-js/mermaid/commit/cfe9238882cbe95416db1feea3112456a71b6aaf) Thanks [@shubhamparikh2704](https://github.com/shubhamparikh2704)! - chore: revert marked dependency from ^15.0.7 to ^16.0.0
|
||||
- Reverted marked package version to ^16.0.0 for better compatibility
|
||||
- This is a dependency update that maintains API compatibility
|
||||
- All tests pass with the updated version
|
||||
|
||||
## 11.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "11.12.0",
|
||||
"version": "11.11.0",
|
||||
"description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
|
||||
"type": "module",
|
||||
"module": "./dist/mermaid.core.mjs",
|
||||
@@ -68,10 +68,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^7.1.1",
|
||||
"@iconify/utils": "^3.0.1",
|
||||
"@iconify/utils": "^3.0.2",
|
||||
"@mermaid-js/parser": "workspace:^",
|
||||
"@types/d3": "^7.4.3",
|
||||
"cytoscape": "^3.29.3",
|
||||
"cytoscape": "^3.33.1",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
"cytoscape-fcose": "^2.2.0",
|
||||
"d3": "^7.9.0",
|
||||
@@ -82,7 +82,7 @@
|
||||
"katex": "^0.16.22",
|
||||
"khroma": "^2.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"marked": "^16.2.1",
|
||||
"marked": "^16.3.0",
|
||||
"roughjs": "^4.6.6",
|
||||
"stylis": "^4.3.6",
|
||||
"ts-dedent": "^2.2.0",
|
||||
@@ -105,9 +105,9 @@
|
||||
"@types/stylis": "^4.2.7",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"ajv": "^8.17.1",
|
||||
"canvas": "^3.1.2",
|
||||
"canvas": "^3.2.0",
|
||||
"chokidar": "3.6.0",
|
||||
"concurrently": "^9.1.2",
|
||||
"concurrently": "^9.2.1",
|
||||
"csstree-validator": "^4.0.1",
|
||||
"globby": "^14.1.0",
|
||||
"jison": "^0.4.18",
|
||||
@@ -116,14 +116,14 @@
|
||||
"json-schema-to-typescript": "^15.0.4",
|
||||
"micromatch": "^4.0.8",
|
||||
"path-browserify": "^1.0.1",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier": "^3.6.2",
|
||||
"remark": "^15.0.1",
|
||||
"remark-frontmatter": "^5.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"rimraf": "^6.0.1",
|
||||
"start-server-and-test": "^2.0.13",
|
||||
"type-fest": "^4.35.0",
|
||||
"typedoc": "^0.28.12",
|
||||
"start-server-and-test": "^2.1.2",
|
||||
"type-fest": "^4.41.0",
|
||||
"typedoc": "^0.28.13",
|
||||
"typedoc-plugin-markdown": "^4.8.1",
|
||||
"typescript": "~5.7.3",
|
||||
"unist-util-flatmap": "^1.0.0",
|
||||
|
@@ -66,12 +66,15 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
\}\| return 'ONE_OR_MORE';
|
||||
"one" return 'ONLY_ONE';
|
||||
"only one" return 'ONLY_ONE';
|
||||
"1" return 'ONLY_ONE';
|
||||
[0-9]+\.[0-9]+ return 'DECIMAL_NUM';
|
||||
"1"(?=\s+[A-Za-z_"']) return 'ONLY_ONE';
|
||||
"1" return 'ENTITY_ONE';
|
||||
[0-9]+ return 'NUM';
|
||||
\|\| return 'ONLY_ONE';
|
||||
o\| return 'ZERO_OR_ONE';
|
||||
o\{ return 'ZERO_OR_MORE';
|
||||
\|\{ return 'ONE_OR_MORE';
|
||||
\s*u return 'MD_PARENT';
|
||||
u(?=[\.\-\|]) return 'MD_PARENT';
|
||||
\.\. return 'NON_IDENTIFYING';
|
||||
\-\- return 'IDENTIFYING';
|
||||
"to" return 'IDENTIFYING';
|
||||
@@ -80,13 +83,15 @@ o\{ return 'ZERO_OR_MORE';
|
||||
\-\. return 'NON_IDENTIFYING';
|
||||
<style>([^\x00-\x7F]|\w|\-|\*)+ return 'STYLE_TEXT';
|
||||
<style>';' return 'SEMI';
|
||||
([^\x00-\x7F]|\w|\-|\*)+ return 'UNICODE_TEXT';
|
||||
[0-9] return 'NUM';
|
||||
([^\x00-\x7F]|\w|\-|\*|\.)+ return 'UNICODE_TEXT';
|
||||
. return yytext[0];
|
||||
<<EOF>> return 'EOF';
|
||||
|
||||
/lex
|
||||
|
||||
%left 'ONLY_ONE'
|
||||
%left 'ZERO_OR_ONE' 'ZERO_OR_MORE' 'ONE_OR_MORE' 'MD_PARENT'
|
||||
|
||||
%start start
|
||||
%% /* language grammar */
|
||||
|
||||
@@ -228,6 +233,9 @@ styleComponent: STYLE_TEXT | NUM | COLON | BRKT;
|
||||
entityName
|
||||
: 'ENTITY_NAME' { $$ = $1.replace(/"/g, ''); }
|
||||
| 'UNICODE_TEXT' { $$ = $1; }
|
||||
| 'NUM' { $$ = $1; }
|
||||
| 'DECIMAL_NUM' { $$ = $1; }
|
||||
| 'ENTITY_ONE' { $$ = $1; }
|
||||
;
|
||||
|
||||
attributes
|
||||
|
@@ -1001,4 +1001,90 @@ describe('when parsing ER diagram it...', function () {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('syntax fixes for special characters and numbers', function () {
|
||||
describe('standalone entity names', function () {
|
||||
it('should allow number "1" as standalone entity', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\n1`);
|
||||
});
|
||||
|
||||
it('should allow character "u" as standalone entity', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\nu`);
|
||||
});
|
||||
|
||||
it('should allow decimal numbers as standalone entities', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\n2.5`);
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\n1.5`);
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\n0.1`);
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER }|..|{ DELIVERY-ADDRESS : has\n99.99`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('entity names with attributes', function () {
|
||||
it('should allow "u" as entity name with attributes', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nu {\nstring name\nint id\n}`);
|
||||
});
|
||||
|
||||
it('should allow number "1" as entity name with attributes', function () {
|
||||
erDiagram.parser.parse(`erDiagram\n1 {\nstring name\nint id\n}`);
|
||||
});
|
||||
|
||||
it('should allow decimal numbers as entity names with attributes', function () {
|
||||
erDiagram.parser.parse(`erDiagram\n2.5 {\nstring name\nint id\n}`);
|
||||
erDiagram.parser.parse(`erDiagram\n1.5 {\nstring value\n}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('entity names in relationships', function () {
|
||||
it('should allow "u" in relationships', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER ||--|| u : has`);
|
||||
erDiagram.parser.parse(`erDiagram\nu ||--|| ORDER : places`);
|
||||
erDiagram.parser.parse(`erDiagram\nu ||--|| v : connects`);
|
||||
});
|
||||
|
||||
it('should allow numbers in relationships', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER ||--|| 1 : has`);
|
||||
erDiagram.parser.parse(`erDiagram\n1 ||--|| ORDER : places`);
|
||||
erDiagram.parser.parse(`erDiagram\n1 ||--|| 2 : connects`);
|
||||
});
|
||||
|
||||
it('should allow decimal numbers in relationships', function () {
|
||||
erDiagram.parser.parse(`erDiagram\nCUSTOMER ||--|| 2.5 : has`);
|
||||
erDiagram.parser.parse(`erDiagram\n1.5 ||--|| ORDER : places`);
|
||||
erDiagram.parser.parse(`erDiagram\n2.5 ||--|| 5.5 : connects`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mixed scenarios', function () {
|
||||
it('should handle complex diagram with special entity names', function () {
|
||||
erDiagram.parser.parse(
|
||||
`erDiagram
|
||||
CUSTOMER ||--o{ 1 : places
|
||||
1 ||--|{ u : contains
|
||||
u {
|
||||
string name
|
||||
int quantity
|
||||
}
|
||||
"2.5" ||--|| ORDER : processes
|
||||
ORDER {
|
||||
int id
|
||||
date created
|
||||
}
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle attributes with numbers in names (but not starting)', function () {
|
||||
erDiagram.parser.parse(
|
||||
`erDiagram
|
||||
ENTITY {
|
||||
string name1
|
||||
int value2
|
||||
float point3_5
|
||||
}
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -78,7 +78,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
"off" return 'off';
|
||||
"," return ',';
|
||||
";" return 'NEWLINE';
|
||||
[^+<\->\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)))[\-]*[^\+<\->\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; }
|
||||
[^\/\\\+\()\+<\->\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)|\-\|\\|\-\\|\-\/|\-\/\/|\-\|\/|\/\|\-|\\\|\-|\/\/\-|\\\\\-|\/\|\-|\-\-\|\\|\-\-|\(\)))[\-]*[^\+<\->\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; } //final_4.11
|
||||
"->>" return 'SOLID_ARROW';
|
||||
"<<->>" return 'BIDIRECTIONAL_SOLID_ARROW';
|
||||
"-->>" return 'DOTTED_ARROW';
|
||||
@@ -89,10 +89,36 @@ 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';
|
||||
|
||||
@@ -304,6 +330,20 @@ 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}]}
|
||||
;
|
||||
@@ -337,7 +377,28 @@ signaltype
|
||||
: SOLID_OPEN_ARROW { $$ = yy.LINETYPE.SOLID_OPEN; }
|
||||
| DOTTED_OPEN_ARROW { $$ = yy.LINETYPE.DOTTED_OPEN; }
|
||||
| SOLID_ARROW { $$ = yy.LINETYPE.SOLID; }
|
||||
| BIDIRECTIONAL_SOLID_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_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; }
|
||||
| SOLID_CROSS { $$ = yy.LINETYPE.SOLID_CROSS; }
|
||||
|
@@ -64,6 +64,30 @@ 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 = {
|
||||
@@ -244,7 +268,8 @@ export class SequenceDB implements DiagramDB {
|
||||
idTo?: Message['to'],
|
||||
message?: { text: string; wrap: boolean },
|
||||
messageType?: number,
|
||||
activate = false
|
||||
activate = false,
|
||||
centralConnection?: number
|
||||
) {
|
||||
if (messageType === this.LINETYPE.ACTIVE_END) {
|
||||
const cnt = this.activationCount(idFrom ?? '');
|
||||
@@ -271,6 +296,7 @@ export class SequenceDB implements DiagramDB {
|
||||
wrap: message?.wrap ?? this.autoWrap(),
|
||||
type: messageType,
|
||||
activate,
|
||||
centralConnection: centralConnection ?? 0,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
@@ -563,6 +589,12 @@ 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;
|
||||
@@ -606,7 +638,14 @@ export class SequenceDB implements DiagramDB {
|
||||
this.state.records.lastDestroyed = undefined;
|
||||
}
|
||||
}
|
||||
this.addSignal(param.from, param.to, param.msg, param.signalType, param.activate);
|
||||
this.addSignal(
|
||||
param.from,
|
||||
param.to,
|
||||
param.msg,
|
||||
param.signalType,
|
||||
param.activate,
|
||||
param.centralConnection
|
||||
);
|
||||
break;
|
||||
case 'boxStart':
|
||||
this.addBox(param.boxData);
|
||||
|
@@ -104,6 +104,7 @@ describe('more than one sequence diagram', () => {
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Alice",
|
||||
"id": "0",
|
||||
"message": "Hello Bob, how are you?",
|
||||
@@ -113,6 +114,7 @@ describe('more than one sequence diagram', () => {
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Bob",
|
||||
"id": "1",
|
||||
"message": "I am good thanks!",
|
||||
@@ -131,6 +133,7 @@ describe('more than one sequence diagram', () => {
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Alice",
|
||||
"id": "0",
|
||||
"message": "Hello Bob, how are you?",
|
||||
@@ -140,6 +143,7 @@ describe('more than one sequence diagram', () => {
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Bob",
|
||||
"id": "1",
|
||||
"message": "I am good thanks!",
|
||||
@@ -160,6 +164,7 @@ describe('more than one sequence diagram', () => {
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Alice",
|
||||
"id": "0",
|
||||
"message": "Hello John, how are you?",
|
||||
@@ -169,6 +174,7 @@ describe('more than one sequence diagram', () => {
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "John",
|
||||
"id": "1",
|
||||
"message": "I am good thanks!",
|
||||
@@ -181,6 +187,254 @@ describe('more than one sequence diagram', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Central Connection Parsing', () => {
|
||||
describe('when parsing central connection syntax', () => {
|
||||
it('should parse actor ()->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
// Find the actual message (type: 'addMessage')
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 0, // SOLID (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()-->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()-->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 1, // DOTTED (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ->>() actor syntax as CENTRAL_CONNECTION', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(2); // addMessage + centralConnection (no activation for this pattern)
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 59, // CENTRAL_CONNECTION
|
||||
activate: true,
|
||||
type: 0, // SOLID (based on actual parsing)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()-->> actor syntax as CENTRAL_CONNECTION_REVERSE', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()-->> Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(2); // addMessage + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 60, // CENTRAL_CONNECTION_REVERSE
|
||||
activate: false,
|
||||
type: 1, // DOTTED (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()->> actor syntax as CENTRAL_CONNECTION_REVERSE', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()->> Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(2); // addMessage + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 60, // CENTRAL_CONNECTION_REVERSE
|
||||
activate: false,
|
||||
type: 0, // SOLID (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()<<-->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()<<-->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 34, // BIDIRECTIONAL_DOTTED
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()<<->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()<<->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 33, // BIDIRECTIONAL_SOLID
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple central connection types in one diagram', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
Alice ()->>() Bob: Message 1
|
||||
Bob ()-->> Charlie: Message 2
|
||||
Charlie ()<<-->>() Alice: Message 3
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(8); // 3 addMessages + 5 central connection markers
|
||||
|
||||
// Filter to get only the actual messages
|
||||
const actualMessages = messages.filter((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessages).toHaveLength(3);
|
||||
|
||||
expect(actualMessages[0]).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()->>())
|
||||
});
|
||||
|
||||
expect(actualMessages[1]).toMatchObject({
|
||||
from: 'Bob',
|
||||
to: 'Charlie',
|
||||
centralConnection: 60, // CENTRAL_CONNECTION_REVERSE (()-->>)
|
||||
});
|
||||
|
||||
expect(actualMessages[2]).toMatchObject({
|
||||
from: 'Charlie',
|
||||
to: 'Alice',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()<<-->>())
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle central connections with different arrow types', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()-x() Bob: Cross message
|
||||
Alice ()--x() Bob: Dotted cross message
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(6); // 2 addMessages + 4 central connection markers
|
||||
|
||||
const actualMessages = messages.filter((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessages).toHaveLength(2);
|
||||
|
||||
expect(actualMessages[0]).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()-x())
|
||||
type: 3, // SOLID_CROSS
|
||||
});
|
||||
|
||||
expect(actualMessages[1]).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()--x())
|
||||
type: 4, // DOTTED_CROSS
|
||||
});
|
||||
});
|
||||
|
||||
it('should not break existing parsing without central connections', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ->> Bob: Normal message
|
||||
Bob -->> Alice: Normal dotted message
|
||||
Alice -x Bob: Normal cross message
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3);
|
||||
|
||||
messages.forEach((msg) => {
|
||||
expect(msg.centralConnection).toBe(0); // No central connection
|
||||
});
|
||||
|
||||
expect(messages[0].type).toBe(0); // SOLID (based on actual parsing)
|
||||
expect(messages[1].type).toBe(1); // DOTTED (based on actual parsing)
|
||||
expect(messages[2].type).toBe(3); // SOLID_CROSS
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when parsing a sequenceDiagram', function () {
|
||||
let diagram;
|
||||
beforeEach(async function () {
|
||||
@@ -2058,6 +2312,36 @@ 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(`
|
||||
|
@@ -282,6 +282,49 @@ const drawNote = async function (elem: any, noteModel: NoteModel) {
|
||||
bounds.models.addNote(noteModel);
|
||||
};
|
||||
|
||||
const drawCentralConnection = function (
|
||||
elem: any,
|
||||
msg: any,
|
||||
msgModel: any,
|
||||
diagObj: Diagram,
|
||||
startx: number,
|
||||
stopx: number,
|
||||
lineStartY: number
|
||||
) {
|
||||
const actors = diagObj.db.getActors();
|
||||
const fromActor = actors.get(msg.from);
|
||||
const toActor = actors.get(msg.to);
|
||||
const fromCenter = fromActor.x + fromActor.width / 2;
|
||||
const toCenter = toActor.x + toActor.width / 2;
|
||||
|
||||
const g = elem.append('g');
|
||||
|
||||
const drawCircle = (cx: number) => {
|
||||
g.append('circle')
|
||||
.attr('cx', cx)
|
||||
.attr('cy', lineStartY)
|
||||
.attr('r', 5)
|
||||
.attr('width', 10)
|
||||
.attr('height', 10);
|
||||
};
|
||||
|
||||
const { CENTRAL_CONNECTION, CENTRAL_CONNECTION_REVERSE, CENTRAL_CONNECTION_DUAL } =
|
||||
diagObj.db.LINETYPE;
|
||||
|
||||
switch (msg.centralConnection) {
|
||||
case CENTRAL_CONNECTION:
|
||||
drawCircle(toCenter);
|
||||
break;
|
||||
case CENTRAL_CONNECTION_REVERSE:
|
||||
drawCircle(fromCenter);
|
||||
break;
|
||||
case CENTRAL_CONNECTION_DUAL:
|
||||
drawCircle(fromCenter);
|
||||
drawCircle(toCenter);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const messageFont = (cnf) => {
|
||||
return {
|
||||
fontFamily: cnf.messageFontFamily,
|
||||
@@ -367,7 +410,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) {
|
||||
const drawMessage = async function (diagram, msgModel, lineStartY: number, diagObj: Diagram, msg) {
|
||||
const { startx, stopx, starty, message, type, sequenceIndex, sequenceVisible } = msgModel;
|
||||
const textDims = utils.calculateTextDimensions(message, messageFont(conf));
|
||||
const textObj = svgDrawCommon.getTextObj();
|
||||
@@ -433,6 +476,9 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
line.attr('y1', lineStartY);
|
||||
line.attr('x2', stopx);
|
||||
line.attr('y2', lineStartY);
|
||||
if (hasCentralConnection(msg, diagObj)) {
|
||||
drawCentralConnection(diagram, msg, msgModel, diagObj, startx, stopx, lineStartY);
|
||||
}
|
||||
}
|
||||
// Make an SVG Container
|
||||
// Draw the line
|
||||
@@ -441,7 +487,15 @@ 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.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
|
||||
) {
|
||||
line.style('stroke-dasharray', '3, 3');
|
||||
line.attr('class', 'messageLine1');
|
||||
@@ -457,6 +511,51 @@ 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)');
|
||||
}
|
||||
@@ -481,7 +580,18 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID ||
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED;
|
||||
|
||||
if (isBidirectional) {
|
||||
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) {
|
||||
const SEQUENCE_NUMBER_RADIUS = 6;
|
||||
|
||||
if (startx < stopx) {
|
||||
@@ -489,6 +599,7 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
} else {
|
||||
line.attr('x1', startx + SEQUENCE_NUMBER_RADIUS);
|
||||
}
|
||||
x = 3.5;
|
||||
}
|
||||
|
||||
diagram
|
||||
@@ -498,7 +609,8 @@ 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('marker-start', 'url(' + url + '#sequencenumber)')
|
||||
.attr('transform', `translate(-${x}, 0)`);
|
||||
|
||||
diagram
|
||||
.append('text')
|
||||
@@ -508,7 +620,8 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
.attr('font-size', '12px')
|
||||
.attr('text-anchor', 'middle')
|
||||
.attr('class', 'sequenceNumber')
|
||||
.text(sequenceIndex);
|
||||
.text(sequenceIndex)
|
||||
.attr('transform', `translate(-${x}, 0)`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -857,6 +970,10 @@ 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.
|
||||
@@ -897,6 +1014,12 @@ 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;
|
||||
@@ -1055,7 +1178,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
createdActors,
|
||||
destroyedActors
|
||||
);
|
||||
messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY });
|
||||
messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY, msg });
|
||||
bounds.models.addMessage(msgModel);
|
||||
} catch (e) {
|
||||
log.error('error while drawing message', e);
|
||||
@@ -1068,6 +1191,27 @@ 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,
|
||||
@@ -1087,7 +1231,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);
|
||||
await drawMessage(diagram, e.messageModel, e.lineStartY, diagObj, e.msg);
|
||||
}
|
||||
if (conf.mirrorActors) {
|
||||
await drawActors(diagram, actors, actorKeys, true);
|
||||
@@ -1461,12 +1605,85 @@ const buildNoteModel = async function (msg, actors, diagObj) {
|
||||
return noteModel;
|
||||
};
|
||||
|
||||
// Central connection positioning constants
|
||||
const CENTRAL_CONNECTION_BASE_OFFSET = 4;
|
||||
const CENTRAL_CONNECTION_BIDIRECTIONAL_OFFSET = 6;
|
||||
|
||||
/**
|
||||
* Check if a message has central connection
|
||||
* @param msg - The message object
|
||||
* @param diagObj - The diagram object containing LINETYPE constants
|
||||
* @returns True if the message has any type of central connection
|
||||
*/
|
||||
const hasCentralConnection = function (msg, diagObj) {
|
||||
const { CENTRAL_CONNECTION, CENTRAL_CONNECTION_REVERSE, CENTRAL_CONNECTION_DUAL } =
|
||||
diagObj.db.LINETYPE;
|
||||
return [CENTRAL_CONNECTION, CENTRAL_CONNECTION_REVERSE, CENTRAL_CONNECTION_DUAL].includes(
|
||||
msg.centralConnection
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the positioning offset for central connection arrows
|
||||
* @param msg - The message object
|
||||
* @param diagObj - The diagram object containing LINETYPE constants
|
||||
* @param isArrowToRight - Whether the arrow is pointing to the right
|
||||
* @returns The offset to apply to startx position
|
||||
*/
|
||||
const calculateCentralConnectionOffset = function (msg, diagObj, isArrowToRight) {
|
||||
const {
|
||||
CENTRAL_CONNECTION_REVERSE,
|
||||
CENTRAL_CONNECTION_DUAL,
|
||||
BIDIRECTIONAL_SOLID,
|
||||
BIDIRECTIONAL_DOTTED,
|
||||
} = diagObj.db.LINETYPE;
|
||||
|
||||
let offset = 0;
|
||||
|
||||
if (
|
||||
msg.centralConnection === CENTRAL_CONNECTION_REVERSE ||
|
||||
msg.centralConnection === CENTRAL_CONNECTION_DUAL
|
||||
) {
|
||||
offset += CENTRAL_CONNECTION_BASE_OFFSET;
|
||||
}
|
||||
|
||||
if (
|
||||
msg.centralConnection === CENTRAL_CONNECTION_DUAL &&
|
||||
(msg.type === BIDIRECTIONAL_SOLID || msg.type === BIDIRECTIONAL_DOTTED)
|
||||
) {
|
||||
offset += isArrowToRight ? 0 : -CENTRAL_CONNECTION_BIDIRECTIONAL_OFFSET;
|
||||
}
|
||||
|
||||
return offset;
|
||||
};
|
||||
|
||||
const buildMessageModel = function (msg, actors, diagObj) {
|
||||
if (
|
||||
![
|
||||
diagObj.db.LINETYPE.SOLID_OPEN,
|
||||
diagObj.db.LINETYPE.DOTTED_OPEN,
|
||||
diagObj.db.LINETYPE.SOLID,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_TOP,
|
||||
diagObj.db.LINETYPE.SOLID_BOTTOM,
|
||||
diagObj.db.LINETYPE.STICK_TOP,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_BOTTOM_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_CROSS,
|
||||
diagObj.db.LINETYPE.DOTTED_CROSS,
|
||||
@@ -1484,6 +1701,8 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
let startx = isArrowToRight ? fromRight : fromLeft;
|
||||
let stopx = isArrowToRight ? toLeft : toRight;
|
||||
|
||||
// Apply central connection positioning adjustments
|
||||
startx += calculateCentralConnectionOffset(msg, diagObj, isArrowToRight);
|
||||
// As the line width is considered, the left and right values will be off by 2.
|
||||
const isArrowToActivation = Math.abs(toLeft - toRight) > 2;
|
||||
|
||||
@@ -1517,7 +1736,30 @@ 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].includes(msg.type)) {
|
||||
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)
|
||||
) {
|
||||
stopx += adjustValue(3);
|
||||
}
|
||||
|
||||
@@ -1525,9 +1767,14 @@ 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].includes(
|
||||
msg.type
|
||||
)
|
||||
[
|
||||
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)
|
||||
) {
|
||||
startx -= adjustValue(3);
|
||||
}
|
||||
|
@@ -1709,6 +1709,77 @@ 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,
|
||||
@@ -1731,4 +1802,8 @@ export default {
|
||||
getNoteRect,
|
||||
fixLifeLineHeights,
|
||||
sanitizeUrl,
|
||||
insertSolidTopArrowHead,
|
||||
insertSolidBottomArrowHead,
|
||||
insertStickTopArrowHead,
|
||||
insertStickBottomArrowHead,
|
||||
};
|
||||
|
@@ -35,6 +35,7 @@ export interface Message {
|
||||
type?: number;
|
||||
activate?: boolean;
|
||||
placement?: string;
|
||||
centralConnection?: number;
|
||||
}
|
||||
|
||||
export interface AddMessageParams {
|
||||
@@ -50,6 +51,8 @@ export interface AddMessageParams {
|
||||
| 'destroyParticipant'
|
||||
| 'activeStart'
|
||||
| 'activeEnd'
|
||||
| 'centralConnection'
|
||||
| 'centralConnectionReverse'
|
||||
| 'addNote'
|
||||
| 'addLinks'
|
||||
| 'addALink'
|
||||
|
@@ -17,7 +17,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@vueuse/core": "^13.1.0",
|
||||
"@vueuse/core": "^13.9.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"jiti": "^2.4.2",
|
||||
"mermaid": "workspace:^",
|
||||
@@ -25,17 +25,17 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/carbon": "^1.2.13",
|
||||
"@unocss/reset": "^66.0.0",
|
||||
"@unocss/reset": "^66.5.1",
|
||||
"@vite-pwa/vitepress": "^1.0.0",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"fast-glob": "^3.3.3",
|
||||
"https-localhost": "^4.7.1",
|
||||
"pathe": "^2.0.3",
|
||||
"unocss": "^66.4.2",
|
||||
"unplugin-vue-components": "^28.4.0",
|
||||
"vite": "^7.0.0",
|
||||
"vite-plugin-pwa": "^1.0.0",
|
||||
"vitepress": "1.6.3",
|
||||
"unocss": "^66.5.1",
|
||||
"unplugin-vue-components": "^28.4.1",
|
||||
"vite": "^7.0.7",
|
||||
"vite-plugin-pwa": "^1.0.3",
|
||||
"vitepress": "1.6.4",
|
||||
"workbox-window": "^7.3.0"
|
||||
}
|
||||
}
|
||||
|
@@ -216,7 +216,11 @@ Messages can be of two displayed either solid or with a dotted line.
|
||||
[Actor][Arrow][Actor]:Message text
|
||||
```
|
||||
|
||||
There are ten types of arrows currently supported:
|
||||
Lines can be solid or dotted, and can end with various types of arrowheads, crosses, or open arrows.
|
||||
|
||||
#### Supported Arrow Types
|
||||
|
||||
**Standard Arrow Types**
|
||||
|
||||
| Type | Description |
|
||||
| -------- | ---------------------------------------------------- |
|
||||
@@ -231,6 +235,49 @@ There are ten types of arrows currently supported:
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
|
||||
**Half-Arrows (v<MERMAID_RELEASE_VERSION>+)**
|
||||
|
||||
The following half-arrow types are supported for more expressive sequence diagrams. Both solid and dotted variants are available by increasing the number of dashes (`-` → `--`).
|
||||
|
||||
---
|
||||
|
||||
| Type | Description |
|
||||
| ------- | ---------------------------------------------------- |
|
||||
| `-\|\` | Solid line with top half arrowhead |
|
||||
| `--\|\` | Dotted line with top half arrowhead |
|
||||
| `-\|/` | Solid line with bottom half arrowhead |
|
||||
| `--\|/` | Dotted line with bottom half arrowhead |
|
||||
| `/\|-` | Solid line with reverse top half arrowhead |
|
||||
| `/\|--` | Dotted line with reverse top half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom half arrowhead |
|
||||
| `-\\` | Solid line with top stick half arrowhead |
|
||||
| `--\\` | Dotted line with top stick half arrowhead |
|
||||
| `-//` | Solid line with bottom stick half arrowhead |
|
||||
| `--//` | Dotted line with bottom stick half arrowhead |
|
||||
| `//-` | Solid line with reverse top stick half arrowhead |
|
||||
| `//--` | Dotted line with reverse top stick half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom stick half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom stick half arrowhead |
|
||||
|
||||
## Central Connections (v<MERMAID_RELEASE_VERSION>+)
|
||||
|
||||
Mermaid sequence diagrams support **central lifeline connections** using a `()`.
|
||||
This is useful to represent messages or signals that connect to a central point, rather than from one actor directly to another.
|
||||
|
||||
To indicate a central connection, append `()` to the arrow syntax.
|
||||
|
||||
#### Basic Syntax
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
Alice->>()John: Hello John
|
||||
Alice()->>John: How are you?
|
||||
John()->>()Alice: Great!
|
||||
```
|
||||
|
||||
## Activations
|
||||
|
||||
It is possible to activate and deactivate an actor. (de)activation can be dedicated declarations:
|
||||
|
@@ -207,7 +207,7 @@ describe('when using mermaid and ', () => {
|
||||
[Error: Parse error on line 2:
|
||||
...equenceDiagramAlice:->Bob: Hello Bob, h...
|
||||
----------------------^
|
||||
Expecting 'SOLID_OPEN_ARROW', 'DOTTED_OPEN_ARROW', 'SOLID_ARROW', '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', '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']
|
||||
`);
|
||||
});
|
||||
|
||||
|
@@ -1,24 +1,5 @@
|
||||
# mermaid
|
||||
|
||||
## 11.12.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#6921](https://github.com/mermaid-js/mermaid/pull/6921) [`764b315`](https://github.com/mermaid-js/mermaid/commit/764b315dc16d0359add7c6b8e3ef7592e9bdc09c) Thanks [@quilicicf](https://github.com/quilicicf)! - feat: Add IDs in architecture diagrams
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6950](https://github.com/mermaid-js/mermaid/pull/6950) [`a957908`](https://github.com/mermaid-js/mermaid/commit/a9579083bfba367a4f4678547ec37ed7b61b9f5b) Thanks [@shubhamparikh2704](https://github.com/shubhamparikh2704)! - chore: Fix mindmap rendering in docs and apply tidytree layout
|
||||
|
||||
- [#6826](https://github.com/mermaid-js/mermaid/pull/6826) [`1d36810`](https://github.com/mermaid-js/mermaid/commit/1d3681053b9168354e48e5763023b6305cd1ca72) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Ensure edge label color is applied when using classDef with edge IDs
|
||||
|
||||
- [#6945](https://github.com/mermaid-js/mermaid/pull/6945) [`d318f1a`](https://github.com/mermaid-js/mermaid/commit/d318f1a13cd7429334a29c70e449074ec1cb9f68) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Resolve gantt chart crash due to invalid array length
|
||||
|
||||
- [#6918](https://github.com/mermaid-js/mermaid/pull/6918) [`cfe9238`](https://github.com/mermaid-js/mermaid/commit/cfe9238882cbe95416db1feea3112456a71b6aaf) Thanks [@shubhamparikh2704](https://github.com/shubhamparikh2704)! - chore: revert marked dependency from ^15.0.7 to ^16.0.0
|
||||
- Reverted marked package version to ^16.0.0 for better compatibility
|
||||
- This is a dependency update that maintains API compatibility
|
||||
- All tests pass with the updated version
|
||||
|
||||
## 11.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mermaid-js/tiny",
|
||||
"version": "11.12.0",
|
||||
"version": "11.11.0",
|
||||
"description": "Tiny version of mermaid",
|
||||
"type": "commonjs",
|
||||
"main": "./dist/mermaid.tiny.js",
|
||||
|
1013
pnpm-lock.yaml
generated
1013
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user