mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-03 06:09:45 +02:00
Compare commits
3 Commits
gh-readonl
...
fix/5378
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9fd6a1396b | ||
![]() |
3df86ea1e6 | ||
![]() |
7bc201673d |
@@ -1 +0,0 @@
|
||||
.gitignore
|
11
.eslintignore
Normal file
11
.eslintignore
Normal file
@@ -0,0 +1,11 @@
|
||||
dist/**
|
||||
.github/**
|
||||
docs/Setup.md
|
||||
cypress.config.js
|
||||
cypress/plugins/index.js
|
||||
coverage
|
||||
*.json
|
||||
node_modules
|
||||
|
||||
# autogenereated by langium-cli
|
||||
generated/
|
@@ -53,7 +53,6 @@ module.exports = {
|
||||
'@typescript-eslint/no-floating-promises': 'error',
|
||||
'@typescript-eslint/no-misused-promises': 'error',
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
'@typescript-eslint/consistent-type-definitions': 'error',
|
||||
'@typescript-eslint/ban-ts-comment': [
|
||||
'error',
|
||||
{
|
||||
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -37,13 +37,13 @@ jobs:
|
||||
run: pnpm run build
|
||||
|
||||
- name: Upload Mermaid Build as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mermaid-build
|
||||
path: packages/mermaid/dist
|
||||
|
||||
- name: Upload Mermaid Mindmap Build as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mermaid-mindmap-build
|
||||
path: packages/mermaid-mindmap/dist
|
||||
|
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
languages: ${{ matrix.language }}
|
||||
@@ -45,7 +45,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@v3
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ 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
|
||||
@@ -59,4 +59,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
2
.github/workflows/dependency-review.yml
vendored
2
.github/workflows/dependency-review.yml
vendored
@@ -17,4 +17,4 @@ jobs:
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@v4
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@v4
|
||||
uses: actions/dependency-review-action@v3
|
||||
|
6
.github/workflows/e2e.yml
vendored
6
.github/workflows/e2e.yml
vendored
@@ -106,7 +106,7 @@ jobs:
|
||||
# These cached snapshots are downloaded, providing the reference snapshots.
|
||||
- name: Cache snapshots
|
||||
id: cache-snapshot
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
path: ./cypress/snapshots
|
||||
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
||||
@@ -148,7 +148,7 @@ jobs:
|
||||
CYPRESS_COMMIT: ${{ github.sha }}
|
||||
|
||||
- name: Upload Coverage to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v3
|
||||
# Run step only pushes to develop and pull_requests
|
||||
if: ${{ steps.cypress.conclusion == 'success' && (github.event_name == 'pull_request' || github.ref == 'refs/heads/develop')}}
|
||||
with:
|
||||
@@ -185,7 +185,7 @@ jobs:
|
||||
- name: Save snapshots cache
|
||||
id: cache-upload
|
||||
if: ${{ github.event_name == 'push' && needs.e2e.result != 'failure' }}
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v3
|
||||
with:
|
||||
path: ./snapshots
|
||||
key: ${{ runner.os }}-snapshots-${{ github.event.after }}
|
||||
|
2
.github/workflows/link-checker.yml
vendored
2
.github/workflows/link-checker.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Restore lychee cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .lycheecache
|
||||
key: cache-lychee-${{ github.sha }}
|
||||
|
2
.github/workflows/pr-labeler.yml
vendored
2
.github/workflows/pr-labeler.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
pull-requests: write # write permission is required to label PRs
|
||||
steps:
|
||||
- name: Label PR
|
||||
uses: release-drafter/release-drafter@v6
|
||||
uses: release-drafter/release-drafter@v5
|
||||
with:
|
||||
config-name: pr-labeler.yml
|
||||
disable-autolabeler: false
|
||||
|
6
.github/workflows/publish-docs.yml
vendored
6
.github/workflows/publish-docs.yml
vendored
@@ -37,13 +37,13 @@ jobs:
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v4
|
||||
uses: actions/configure-pages@v3
|
||||
|
||||
- name: Run Build
|
||||
run: pnpm --filter mermaid run docs:build:vitepress
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
with:
|
||||
path: packages/mermaid/src/vitepress/.vitepress/dist
|
||||
|
||||
@@ -56,4 +56,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
uses: actions/deploy-pages@v2
|
||||
|
2
.github/workflows/release-draft.yml
vendored
2
.github/workflows/release-draft.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
pull-requests: read # required to read PR titles/labels
|
||||
steps:
|
||||
- name: Draft Release
|
||||
uses: release-drafter/release-drafter@v6
|
||||
uses: release-drafter/release-drafter@v5
|
||||
with:
|
||||
disable-autolabeler: true
|
||||
env:
|
||||
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
pnpm exec vitest run ./packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts --coverage
|
||||
|
||||
- name: Upload Coverage to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v3
|
||||
# Run step only pushes to develop and pull_requests
|
||||
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/develop' }}
|
||||
with:
|
||||
|
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@v6
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
branch: update-browserslist
|
||||
title: Update Browserslist
|
||||
|
@@ -1 +1 @@
|
||||
20.12.2
|
||||
v20.11.1
|
||||
|
@@ -1,2 +1,2 @@
|
||||
FROM node:20.12.2-alpine3.19 AS base
|
||||
FROM node:20.11.1-alpine3.19 AS base
|
||||
RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -
|
||||
|
@@ -1458,79 +1458,5 @@ gitGraph TB:
|
||||
{ gitGraph: { parallelCommits: true } }
|
||||
);
|
||||
});
|
||||
it('73: should render a simple gitgraph with three branches and tagged merge commit using switch instead of checkout', () => {
|
||||
imgSnapshotTest(
|
||||
`gitGraph
|
||||
commit id: "1"
|
||||
commit id: "2"
|
||||
branch nice_feature
|
||||
switch nice_feature
|
||||
commit id: "3"
|
||||
switch main
|
||||
commit id: "4"
|
||||
switch nice_feature
|
||||
branch very_nice_feature
|
||||
switch very_nice_feature
|
||||
commit id: "5"
|
||||
switch main
|
||||
commit id: "6"
|
||||
switch nice_feature
|
||||
commit id: "7"
|
||||
switch main
|
||||
merge nice_feature id: "12345" tag: "my merge commit"
|
||||
switch very_nice_feature
|
||||
commit id: "8"
|
||||
switch main
|
||||
commit id: "9"
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('74: should render commits for more than 8 branches using switch instead of checkout', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gitGraph
|
||||
switch main
|
||||
%% Make sure to manually set the ID of all commits, for consistent visual tests
|
||||
commit id: "1-abcdefg"
|
||||
switch main
|
||||
branch branch1
|
||||
commit id: "2-abcdefg"
|
||||
switch main
|
||||
merge branch1
|
||||
branch branch2
|
||||
commit id: "3-abcdefg"
|
||||
switch main
|
||||
merge branch2
|
||||
branch branch3
|
||||
commit id: "4-abcdefg"
|
||||
switch main
|
||||
merge branch3
|
||||
branch branch4
|
||||
commit id: "5-abcdefg"
|
||||
switch main
|
||||
merge branch4
|
||||
branch branch5
|
||||
commit id: "6-abcdefg"
|
||||
switch main
|
||||
merge branch5
|
||||
branch branch6
|
||||
commit id: "7-abcdefg"
|
||||
switch main
|
||||
merge branch6
|
||||
branch branch7
|
||||
commit id: "8-abcdefg"
|
||||
switch main
|
||||
merge branch7
|
||||
branch branch8
|
||||
commit id: "9-abcdefg"
|
||||
switch main
|
||||
merge branch8
|
||||
branch branch9
|
||||
commit id: "10-abcdefg"
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util.ts';
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||
|
||||
describe('Quadrant Chart', () => {
|
||||
it('should render if only chart type is provided', () => {
|
||||
@@ -226,52 +226,4 @@ describe('Quadrant Chart', () => {
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('it should render data points with styles', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Reach -->
|
||||
y-axis Engagement -->
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
Campaign A: [0.3, 0.6] radius: 20
|
||||
Campaign B: [0.45, 0.23] color: #ff0000
|
||||
Campaign C: [0.57, 0.69] stroke-color: #ff00ff
|
||||
Campaign D: [0.78, 0.34] stroke-width: 3px
|
||||
Campaign E: [0.40, 0.34] radius: 20, color: #ff0000 , stroke-color : #ff00ff, stroke-width : 3px
|
||||
Campaign F: [0.35, 0.78] stroke-width: 3px , color: #ff0000, radius: 20, stroke-color: #ff00ff
|
||||
Campaign G: [0.22, 0.22] stroke-width: 3px , color: #309708 , radius : 20 , stroke-color: #5060ff
|
||||
Campaign H: [0.22, 0.44]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('it should render data points with styles + classes', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Reach -->
|
||||
y-axis Engagement -->
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
Campaign A:::class1: [0.3, 0.6] radius: 20
|
||||
Campaign B: [0.45, 0.23] color: #ff0000
|
||||
Campaign C: [0.57, 0.69] stroke-color: #ff00ff
|
||||
Campaign D:::class2: [0.78, 0.34] stroke-width: 3px
|
||||
Campaign E:::class2: [0.40, 0.34] radius: 20, color: #ff0000, stroke-color: #ff00ff, stroke-width: 3px
|
||||
Campaign F:::class1: [0.35, 0.78]
|
||||
classDef class1 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px
|
||||
classDef class2 color: #f00fff, radius : 10
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
|
@@ -20,7 +20,7 @@ services:
|
||||
- 9000:9000
|
||||
- 3333:3333
|
||||
cypress:
|
||||
image: cypress/included:13.7.3
|
||||
image: cypress/included:12.17.4
|
||||
stdin_open: true
|
||||
tty: true
|
||||
working_dir: /mermaid
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
@@ -84,13 +84,3 @@ Example with legacy mode enabled (the latest version of KaTeX's stylesheet can b
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Handling Rendering Differences
|
||||
|
||||
Due to differences between default fonts across operating systems and browser's MathML implementations, inconsistent results can be seen across platforms. If having consistent results are important, or the most optimal rendered results are desired, `forceLegacyMathML` can be enabled in the config.
|
||||
|
||||
This option will always use KaTeX's stylesheet instead of only when MathML is not supported (as with `legacyMathML`). Note that only `forceLegacyMathML` needs to be set.
|
||||
|
||||
If including KaTeX's stylesheet is not a concern, enabling this option is recommended to avoid scenarios where no MathML implementation within a browser provides the desired output (as seen below).
|
||||
|
||||

|
||||
|
@@ -240,8 +240,6 @@ Communication tools and platforms
|
||||
|
||||
### Other
|
||||
|
||||
- [Astro](https://astro.build/)
|
||||
- [Adding diagrams to your Astro site with MermaidJS and Playwright](https://agramont.net/blog/diagraming-with-mermaidjs-astro/)
|
||||
- [Bisheng](https://www.npmjs.com/package/bisheng)
|
||||
- [bisheng-plugin-mermaid](https://github.com/yct21/bisheng-plugin-mermaid)
|
||||
- [Blazorade Mermaid: Render Mermaid diagrams in Blazor applications](https://github.com/Blazorade/Blazorade-Mermaid/wiki)
|
||||
@@ -251,7 +249,6 @@ Communication tools and platforms
|
||||
- [Jekyll](https://jekyllrb.com/)
|
||||
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
|
||||
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)
|
||||
- [MarkChart: Preview Mermaid diagrams on macOS](https://markchart.app/)
|
||||
- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic)
|
||||
- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)
|
||||
- [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io) ✅
|
||||
|
@@ -28,23 +28,13 @@ Thank you for being part of our story. Here's to creating, innovating, and colla
|
||||
|
||||
Knut Sveidqvist 🧜♂️✨
|
||||
|
||||
## Mermaid Chart's Visual Editor for Flowcharts and Sequence diagrams
|
||||
## Mermaid Chart's Visual Editor for Flowcharts
|
||||
|
||||
The Mermaid Chart team is excited to introduce a new Visual Editor for Flowcharts and Sequence diagrams, enabling users of all skill levels to create diagrams easily and efficiently, with both GUI and code-based editing options.
|
||||
The Mermaid Chart team is excited to introduce a new Visual Editor for flowcharts, enabling users of all skill levels to create diagrams easily and efficiently, with both GUI and code-based editing options.
|
||||
|
||||
Learn more:
|
||||
Create flowchart nodes, connect them with edges, update shapes, change colors, and edit labels with just a few clicks that automatically reflect in your diagram’s code for easy customizability.
|
||||
|
||||
- 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)
|
||||
Read more about it in our latest [BLOG POST](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts) and watch a [DEMO VIDEO](https://www.youtube.com/watch?v=5aja0gijoO0) on our YouTube page.
|
||||
|
||||
## 📖 Blog posts
|
||||
|
||||
|
@@ -6,18 +6,6 @@
|
||||
|
||||
# Blog
|
||||
|
||||
## [Mermaid Chart Unveils Visual Editor for Sequence Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-chart-unveils-visual-editor-for-sequence-diagrams/)
|
||||
|
||||
8 April 2024 · 5 mins
|
||||
|
||||
Sequence diagrams are excellent tools for communication and documentation.
|
||||
|
||||
## [Modeling system states: It starts with a Turing machine](https://www.mermaidchart.com/blog/posts/modeling-system-states/)
|
||||
|
||||
27 March 2024 · 12 mins
|
||||
|
||||
In computer science, there are a few fundamental papers that, without exaggeration, changed everything.
|
||||
|
||||
## [Mermaid Chart Raises $7.5M to Reinvent Visual Collaboration for Enterprises](https://www.mermaidchart.com/blog/posts/mermaid-chart-raises-7.5m-to-reinvent-visual-collaoration-for-enterprises/)
|
||||
|
||||
20 March 2024 · 4 mins
|
||||
|
@@ -6,7 +6,7 @@
|
||||
|
||||
# Entity Relationship Diagrams
|
||||
|
||||
> An entity–relationship model (or ER model) describes interrelated things of interest in a specific domain of knowledge. A basic ER model is composed of entity types (which classify the things of interest) and specifies relationships that can exist between entities (instances of those entity types) [Wikipedia](https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model).
|
||||
> An entity–relationship model (or ER model) describes interrelated things of interest in a specific domain of knowledge. A basic ER model is composed of entity types (which classify the things of interest) and specifies relationships that can exist between entities (instances of those entity types). Wikipedia.
|
||||
|
||||
Note that practitioners of ER modelling almost always refer to _entity types_ simply as _entities_. For example the `CUSTOMER` entity _type_ would be referred to simply as the `CUSTOMER` entity. This is so common it would be inadvisable to do anything else, but technically an entity is an abstract _instance_ of an entity type, and this is what an ER diagram shows - abstract instances, and the relationships between them. This is why entities are always named using singular nouns.
|
||||
|
||||
@@ -111,7 +111,7 @@ Only the `first-entity` part of a statement is mandatory. This makes it possible
|
||||
|
||||
The `relationship` part of each statement can be broken down into three sub-components:
|
||||
|
||||
- the cardinality of the first entity with respect to the second
|
||||
- the cardinality of the first entity with respect to the second,
|
||||
- whether the relationship confers identity on a 'child' entity
|
||||
- the cardinality of the second entity with respect to the first
|
||||
|
||||
@@ -232,7 +232,7 @@ erDiagram
|
||||
|
||||
#### Attribute Keys and Comments
|
||||
|
||||
Attributes may also have a `key` or comment defined. Keys can be `PK`, `FK` or `UK`, for Primary Key, Foreign Key or Unique Key. To specify multiple key constraints on a single attribute, separate them with a comma (e.g., `PK, FK`). A `comment` is defined by double quotes at the end of an attribute. Comments themselves cannot have double-quote characters in them.
|
||||
Attributes may also have a `key` or comment defined. Keys can be `PK`, `FK` or `UK`, for Primary Key, Foreign Key or Unique Key. To specify multiple key constraints on a single attribute, separate them with a comma (e.g., `PK, FK`).. A `comment` is defined by double quotes at the end of an attribute. Comments themselves cannot have double-quote characters in them.
|
||||
|
||||
```mermaid-example
|
||||
erDiagram
|
||||
|
@@ -1178,36 +1178,6 @@ Adding this snippet in the `<head>` would add support for Font Awesome v6.5.1
|
||||
/>
|
||||
```
|
||||
|
||||
### Custom icons
|
||||
|
||||
It is possible to use custom icons served from Font Awesome as long as the website imports the corresponding kit.
|
||||
|
||||
Note that this is currently a paid feature from Font Awesome.
|
||||
|
||||
For custom icons, you need to use the `fak` prefix.
|
||||
|
||||
**Example**
|
||||
|
||||
```
|
||||
flowchart TD
|
||||
B[fa:fa-twitter] %% standard icon
|
||||
B-->E(fak:fa-custom-icon-name) %% custom icon
|
||||
```
|
||||
|
||||
And trying to render it
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
B["fa:fa-twitter for peace"]
|
||||
B-->C["fab:fa-truck-bold a custom icon"]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
B["fa:fa-twitter for peace"]
|
||||
B-->C["fab:fa-truck-bold a custom icon"]
|
||||
```
|
||||
|
||||
## Graph declarations with spaces between vertices and link and without semicolon
|
||||
|
||||
- In graph declarations, the statements also can now end without a semicolon. After release 0.2.16, ending a graph statement with semicolon is just optional. So the below graph declaration is also valid along with the old declarations of the graph.
|
||||
|
@@ -56,8 +56,6 @@ In Mermaid, we support the basic git operations like:
|
||||
With the help of these key git commands, you will be able to draw a gitgraph in Mermaid very easily and quickly.
|
||||
Entity names are often capitalized, although there is no accepted standard on this, and it is not required in Mermaid.
|
||||
|
||||
**NOTE**: `checkout` and `switch` can be used interchangeably.
|
||||
|
||||
## Syntax
|
||||
|
||||
Mermaid syntax for a gitgraph is very straight-forward and simple. It follows a declarative-approach, where each commit is drawn on the timeline in the diagram, in order of its occurrences/presence in code. Basically, it follows the insertion order for each command.
|
||||
|
@@ -168,86 +168,3 @@ quadrantChart
|
||||
quadrant-3 Delegate
|
||||
quadrant-4 Delete
|
||||
```
|
||||
|
||||
### Point styling
|
||||
|
||||
Points can either be styled directly or with defined shared classes
|
||||
|
||||
1. Direct styling
|
||||
|
||||
```md
|
||||
Point A: [0.9, 0.0] radius: 12
|
||||
Point B: [0.8, 0.1] color: #ff3300, radius: 10
|
||||
Point C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0
|
||||
Point D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0
|
||||
```
|
||||
|
||||
2. Classes styling
|
||||
|
||||
```md
|
||||
Point A:::class1: [0.9, 0.0]
|
||||
Point B:::class2: [0.8, 0.1]
|
||||
Point C:::class3: [0.7, 0.2]
|
||||
Point D:::class3: [0.7, 0.2]
|
||||
classDef class1 color: #109060
|
||||
classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px
|
||||
classDef class3 color: #f00fff, radius : 10
|
||||
```
|
||||
|
||||
#### Available styles:
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------ | ---------------------------------------------------------------------- |
|
||||
| color | Fill color of the point |
|
||||
| radius | Radius of the point |
|
||||
| stroke-width | Border width of the point |
|
||||
| stroke-color | Border color of the point (useless when stroke-width is not specified) |
|
||||
|
||||
> **Note**
|
||||
> Order of preference:
|
||||
>
|
||||
> 1. Direct styles
|
||||
> 2. Class styles
|
||||
> 3. Theme styles
|
||||
|
||||
## Example on styling
|
||||
|
||||
```mermaid-example
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
Campaign A: [0.9, 0.0] radius: 12
|
||||
Campaign B:::class1: [0.8, 0.1] color: #ff3300, radius: 10
|
||||
Campaign C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0
|
||||
Campaign D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0
|
||||
Campaign E:::class2: [0.5, 0.4]
|
||||
Campaign F:::class3: [0.4, 0.5] color: #0000ff
|
||||
classDef class1 color: #109060
|
||||
classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px
|
||||
classDef class3 color: #f00fff, radius : 10
|
||||
```
|
||||
|
||||
```mermaid
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
Campaign A: [0.9, 0.0] radius: 12
|
||||
Campaign B:::class1: [0.8, 0.1] color: #ff3300, radius: 10
|
||||
Campaign C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0
|
||||
Campaign D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0
|
||||
Campaign E:::class2: [0.5, 0.4]
|
||||
Campaign F:::class3: [0.4, 0.5] color: #0000ff
|
||||
classDef class1 color: #109060
|
||||
classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px
|
||||
classDef class3 color: #f00fff, radius : 10
|
||||
```
|
||||
|
@@ -160,7 +160,7 @@ In a real world use of state diagrams you often end up with diagrams that are mu
|
||||
have several internal states. These are called composite states in this terminology.
|
||||
|
||||
In order to define a composite state you need to use the state keyword followed by an id and the body of the composite
|
||||
state between {}. You can name a composite state on a separate line just like a simple state. See the example below:
|
||||
state between {}. See the example below:
|
||||
|
||||
```mermaid-example
|
||||
stateDiagram-v2
|
||||
@@ -169,14 +169,6 @@ stateDiagram-v2
|
||||
[*] --> second
|
||||
second --> [*]
|
||||
}
|
||||
|
||||
[*] --> NamedComposite
|
||||
NamedComposite: Another Composite
|
||||
state NamedComposite {
|
||||
[*] --> namedSimple
|
||||
namedSimple --> [*]
|
||||
namedSimple: Another simple
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
@@ -186,14 +178,6 @@ stateDiagram-v2
|
||||
[*] --> second
|
||||
second --> [*]
|
||||
}
|
||||
|
||||
[*] --> NamedComposite
|
||||
NamedComposite: Another Composite
|
||||
state NamedComposite {
|
||||
[*] --> namedSimple
|
||||
namedSimple --> [*]
|
||||
namedSimple: Another simple
|
||||
}
|
||||
```
|
||||
|
||||
You can do this in several layers:
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"version": "10.2.4",
|
||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@8.15.7",
|
||||
"packageManager": "pnpm@8.15.4",
|
||||
"keywords": [
|
||||
"diagram",
|
||||
"markdown",
|
||||
@@ -25,8 +25,8 @@
|
||||
"dev:vite": "tsx .vite/server.ts",
|
||||
"dev:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm dev:vite",
|
||||
"release": "pnpm build",
|
||||
"lint": "cross-env NODE_OPTIONS=--max_old_space_size=8192 eslint --cache --cache-strategy content . && pnpm lint:jison && prettier --cache --check .",
|
||||
"lint:fix": "cross-env NODE_OPTIONS=--max_old_space_size=8192 eslint --cache --cache-strategy content --fix . && prettier --write . && tsx scripts/fixCSpell.ts",
|
||||
"lint": "cross-env NODE_OPTIONS=--max_old_space_size=8192 eslint --cache --cache-strategy content --ignore-path .gitignore . && pnpm lint:jison && prettier --cache --check .",
|
||||
"lint:fix": "cross-env NODE_OPTIONS=--max_old_space_size=8192 eslint --cache --cache-strategy content --fix --ignore-path .gitignore . && prettier --write . && tsx scripts/fixCSpell.ts",
|
||||
"lint:jison": "tsx ./scripts/jison/lint.mts",
|
||||
"contributors": "tsx scripts/updateContributors.ts",
|
||||
"cypress": "cypress run",
|
||||
@@ -129,7 +129,8 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"cytoscape@3.28.1": "patches/cytoscape@3.28.1.patch"
|
||||
"cytoscape@3.28.1": "patches/cytoscape@3.28.1.patch",
|
||||
"lodash-es@4.17.21": "patches/lodash-es@4.17.21.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^7.0.0",
|
||||
"@braintree/sanitize-url": "^6.0.4",
|
||||
"d3": "^7.9.0",
|
||||
"khroma": "^2.1.0"
|
||||
},
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "11.0.0-alpha.7",
|
||||
"version": "11.0.0-alpha.6",
|
||||
"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",
|
||||
@@ -87,7 +87,7 @@
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@adobe/jsonschema2md": "^8.0.0",
|
||||
"@adobe/jsonschema2md": "^7.1.5",
|
||||
"@types/cytoscape": "^3.19.16",
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/d3-sankey": "^0.12.4",
|
||||
|
@@ -21,7 +21,7 @@ export const updateCurrentConfig = (siteCfg: MermaidConfig, _directives: Mermaid
|
||||
let sumOfDirectives: MermaidConfig = {};
|
||||
for (const d of _directives) {
|
||||
sanitize(d);
|
||||
// Apply the data from the directive where the overrides the themeVariables
|
||||
// Apply the data from the directive where the the overrides the themeVariables
|
||||
sumOfDirectives = assignWithDepth(sumOfDirectives, d);
|
||||
}
|
||||
|
||||
|
@@ -120,13 +120,6 @@ export interface MermaidConfig {
|
||||
*
|
||||
*/
|
||||
legacyMathML?: boolean;
|
||||
/**
|
||||
* This option forces Mermaid to rely on KaTeX's own stylesheet for rendering MathML. Due to differences between OS
|
||||
* fonts and browser's MathML implementation, this option is recommended if consistent rendering is important.
|
||||
* If set to true, ignores legacyMathML.
|
||||
*
|
||||
*/
|
||||
forceLegacyMathML?: boolean;
|
||||
/**
|
||||
* This option controls if the generated ids of nodes in the SVG are
|
||||
* generated randomly or based on a seed.
|
||||
|
@@ -45,7 +45,7 @@ flowchart
|
||||
a --> C2
|
||||
```
|
||||
|
||||
To handle this case a special type of edge is inserted. The edge to/from the cluster is replaced with an edge to/from a node in the cluster which is tagged with toCluster/fromCluster. When rendering this edge the intersection between the edge and the border of the cluster is calculated making the edge start/stop there. In practice this renders like an edge to/from the cluster.
|
||||
To handle this case a special type of edge is inserted. The edge to/from the cluster is replaced with an edge to/from a node in the cluster which is tagged with toCluster/fromCluster. When rendering this edge the intersection between the edge and the border of the cluster is calculated making the edge start/stop there. In practice this renders like an an edge to/from the cluster.
|
||||
|
||||
In the diagram above the root diagram would be rendered with C1 whereas C2 would be rendered recursively.
|
||||
|
||||
|
@@ -3,7 +3,6 @@ import { log } from '../logger.js';
|
||||
import { getConfig } from '../diagram-api/diagramAPI.js';
|
||||
import { evaluate } from '../diagrams/common/common.js';
|
||||
import { decodeEntities } from '../utils.js';
|
||||
import { replaceIconSubstring } from '../rendering-util/createText.js';
|
||||
|
||||
/**
|
||||
* @param dom
|
||||
@@ -60,7 +59,10 @@ const createLabel = (_vertexText, style, isTitle, isNode) => {
|
||||
log.debug('vertexText' + vertexText);
|
||||
const node = {
|
||||
isNode,
|
||||
label: replaceIconSubstring(decodeEntities(vertexText)),
|
||||
label: decodeEntities(vertexText).replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell: disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
labelStyle: style.replace('fill:', 'color:'),
|
||||
};
|
||||
let vertexNode = addHtmlLabel(node);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Borrowed with love from dagre-d3. Many thanks to cpettitt!
|
||||
* Borrowed with love from from dagre-d3. Many thanks to cpettitt!
|
||||
*/
|
||||
|
||||
import node from './intersect-node.js';
|
||||
|
@@ -262,7 +262,7 @@ const getBlocksFlat = () => {
|
||||
return [...Object.values(blockDatabase)];
|
||||
};
|
||||
/**
|
||||
* Returns the hierarchy of blocks
|
||||
* Returns the the hierarchy of blocks
|
||||
* @returns
|
||||
*/
|
||||
const getBlocks = () => {
|
||||
|
@@ -4,7 +4,7 @@ import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { render } from '../../dagre-wrapper/index.js';
|
||||
import utils, { getEdgeId } from '../../utils.js';
|
||||
import utils from '../../utils.js';
|
||||
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
|
||||
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
|
||||
import common from '../common/common.js';
|
||||
@@ -231,10 +231,7 @@ export const addRelations = function (relations: ClassRelation[], g: graphlib.Gr
|
||||
//Set relationship style and line type
|
||||
classes: 'relation',
|
||||
pattern: edge.relation.lineType == 1 ? 'dashed' : 'solid',
|
||||
id: getEdgeId(edge.id1, edge.id2, {
|
||||
prefix: 'id',
|
||||
counter: cnt,
|
||||
}),
|
||||
id: `id_${edge.id1}_${edge.id2}_${cnt}`,
|
||||
// Set link type for rendering
|
||||
arrowhead: edge.type === 'arrow_open' ? 'none' : 'normal',
|
||||
//Set edge extra labels
|
||||
|
@@ -138,7 +138,7 @@ export interface ClassNote {
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface ClassRelation {
|
||||
export type ClassRelation = {
|
||||
id1: string;
|
||||
id2: string;
|
||||
relationTitle1: string;
|
||||
@@ -152,7 +152,7 @@ export interface ClassRelation {
|
||||
type2: number;
|
||||
lineType: number;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export interface NamespaceNode {
|
||||
id: string;
|
||||
|
@@ -337,20 +337,18 @@ export const renderKatex = async (text: string, config: MermaidConfig): Promise<
|
||||
return text;
|
||||
}
|
||||
|
||||
if (!(isMathMLSupported() || config.legacyMathML || config.forceLegacyMathML)) {
|
||||
if (!isMathMLSupported() && !config.legacyMathML) {
|
||||
return text.replace(katexRegex, 'MathML is unsupported in this environment.');
|
||||
}
|
||||
|
||||
const { default: katex } = await import('katex');
|
||||
const outputMode =
|
||||
config.forceLegacyMathML || (!isMathMLSupported() && config.legacyMathML)
|
||||
? 'htmlAndMathml'
|
||||
: 'mathml';
|
||||
return text
|
||||
.split(lineBreakRegex)
|
||||
.map((line) =>
|
||||
hasKatex(line)
|
||||
? `<div style="display: flex; align-items: center; justify-content: center; white-space: nowrap;">${line}</div>`
|
||||
? `<div style="display: flex; align-items: center; justify-content: center; white-space: nowrap;">
|
||||
${line}
|
||||
</div>`
|
||||
: `<div>${line}</div>`
|
||||
)
|
||||
.join('')
|
||||
@@ -359,7 +357,7 @@ export const renderKatex = async (text: string, config: MermaidConfig): Promise<
|
||||
.renderToString(c, {
|
||||
throwOnError: true,
|
||||
displayMode: true,
|
||||
output: outputMode,
|
||||
output: isMathMLSupported() ? 'mathml' : 'htmlAndMathml',
|
||||
})
|
||||
.replace(/\n/g, ' ')
|
||||
.replace(/<annotation.*<\/annotation>/g, '')
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
||||
import { select, curveLinear, selectAll } from 'd3';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import utils, { getEdgeId } from '../../utils.js';
|
||||
import utils from '../../utils.js';
|
||||
import { render } from '../../dagre-wrapper/index.js';
|
||||
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
|
||||
import { log } from '../../logger.js';
|
||||
@@ -210,11 +210,7 @@ export const addEdges = async function (edges, g, diagObj) {
|
||||
cnt++;
|
||||
|
||||
// Identify Link
|
||||
const linkIdBase = getEdgeId(edge.start, edge.end, {
|
||||
counter: cnt,
|
||||
prefix: 'L',
|
||||
});
|
||||
|
||||
const linkIdBase = 'L-' + edge.start + '-' + edge.end;
|
||||
// count the links from+to the same node to give unique id
|
||||
if (linkIdCnt[linkIdBase] === undefined) {
|
||||
linkIdCnt[linkIdBase] = 0;
|
||||
@@ -223,8 +219,7 @@ export const addEdges = async function (edges, g, diagObj) {
|
||||
linkIdCnt[linkIdBase]++;
|
||||
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
|
||||
}
|
||||
let linkId = `${linkIdBase}_${linkIdCnt[linkIdBase]}`;
|
||||
|
||||
let linkId = linkIdBase + '-' + linkIdCnt[linkIdBase];
|
||||
log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);
|
||||
const linkNameStart = 'LS-' + edge.start;
|
||||
const linkNameEnd = 'LE-' + edge.end;
|
||||
|
@@ -6,10 +6,9 @@ import { applyStyle } from 'dagre-d3-es/src/dagre-js/util.js';
|
||||
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
|
||||
import { log } from '../../logger.js';
|
||||
import common, { evaluate, renderKatex } from '../common/common.js';
|
||||
import { interpolateToCurve, getStylesFromArray, getEdgeId } from '../../utils.js';
|
||||
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
|
||||
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
|
||||
import flowChartShapes from './flowChartShapes.js';
|
||||
import { replaceIconSubstring } from '../../rendering-util/createText.js';
|
||||
|
||||
const conf = {};
|
||||
export const setConf = function (cnf) {
|
||||
@@ -57,9 +56,14 @@ export const addVertices = async function (vert, g, svgId, root, _doc, diagObj)
|
||||
let vertexNode;
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
const replacedVertexText = replaceIconSubstring(vertexText);
|
||||
const node = {
|
||||
label: await renderKatex(replacedVertexText, getConfig()),
|
||||
label: await renderKatex(
|
||||
vertexText.replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell:disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
getConfig()
|
||||
),
|
||||
};
|
||||
vertexNode = addHtmlLabel(svg, node).node();
|
||||
vertexNode.parentNode.removeChild(vertexNode);
|
||||
@@ -175,10 +179,7 @@ export const addEdges = async function (edges, g, diagObj) {
|
||||
cnt++;
|
||||
|
||||
// Identify Link
|
||||
const linkId = getEdgeId(edge.start, edge.end, {
|
||||
counter: cnt,
|
||||
prefix: 'L',
|
||||
});
|
||||
const linkId = 'L-' + edge.start + '-' + edge.end;
|
||||
const linkNameStart = 'LS-' + edge.start;
|
||||
const linkNameEnd = 'LE-' + edge.end;
|
||||
|
||||
@@ -241,7 +242,13 @@ export const addEdges = async function (edges, g, diagObj) {
|
||||
edgeData.labelType = 'html';
|
||||
edgeData.label = `<span id="L-${linkId}" class="edgeLabel L-${linkNameStart}' L-${linkNameEnd}" style="${
|
||||
edgeData.labelStyle
|
||||
}">${await renderKatex(replaceIconSubstring(edge.text), getConfig())}</span>`;
|
||||
}">${await renderKatex(
|
||||
edge.text.replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell:disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
getConfig()
|
||||
)}</span>`;
|
||||
} else {
|
||||
edgeData.labelType = 'text';
|
||||
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
|
||||
|
@@ -141,7 +141,7 @@ describe('when parsing flowcharts', function () {
|
||||
expect(edges[3].type).toBe('arrow_point');
|
||||
expect(edges[3].text).toBe('');
|
||||
});
|
||||
it('should handle chaining and multiple nodes in link statement FVC ', function () {
|
||||
it('should handle chaining and multiple nodes in in link statement FVC ', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph TD
|
||||
A --> B & B2 & C --> D2;
|
||||
@@ -181,7 +181,7 @@ describe('when parsing flowcharts', function () {
|
||||
expect(edges[5].type).toBe('arrow_point');
|
||||
expect(edges[5].text).toBe('');
|
||||
});
|
||||
it('should handle chaining and multiple nodes in link statement with extra info in statements', function () {
|
||||
it('should handle chaining and multiple nodes in in link statement with extra info in statements', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph TD
|
||||
A[ h ] -- hello --> B[" test "]:::exClass & C --> D;
|
||||
|
@@ -64,7 +64,7 @@ describe('parsing a flow chart', function () {
|
||||
expect(edges[0].end).toBe('monograph');
|
||||
});
|
||||
|
||||
describe('special characters should be handled.', function () {
|
||||
describe('special characters should be be handled.', function () {
|
||||
const charTest = function (char, result) {
|
||||
const res = flow.parser.parse('graph TD;A(' + char + ')-->B;');
|
||||
|
||||
|
@@ -88,16 +88,6 @@ describe('when parsing a gitGraph', function () {
|
||||
expect(parser.yy.getCurrentBranch()).toBe('new');
|
||||
});
|
||||
|
||||
it('should switch a branch', function () {
|
||||
const str = 'gitGraph:\n' + 'branch new\n' + 'switch new\n';
|
||||
|
||||
parser.parse(str);
|
||||
const commits = parser.yy.getCommits();
|
||||
|
||||
expect(Object.keys(commits).length).toBe(0);
|
||||
expect(parser.yy.getCurrentBranch()).toBe('new');
|
||||
});
|
||||
|
||||
it('should add commits to checked out branch', function () {
|
||||
const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n' + 'commit\n' + 'commit\n';
|
||||
|
||||
|
@@ -520,78 +520,6 @@ describe('when parsing a gitGraph', function () {
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle new branch switch', function () {
|
||||
const str = `gitGraph:
|
||||
commit
|
||||
branch testBranch
|
||||
switch testBranch
|
||||
`;
|
||||
|
||||
parser.parse(str);
|
||||
const commits = parser.yy.getCommits();
|
||||
expect(Object.keys(commits).length).toBe(1);
|
||||
expect(parser.yy.getCurrentBranch()).toBe('testBranch');
|
||||
expect(parser.yy.getDirection()).toBe('LR');
|
||||
expect(Object.keys(parser.yy.getBranches()).length).toBe(2);
|
||||
});
|
||||
|
||||
it('should handle new branch switch & commit', function () {
|
||||
const str = `gitGraph:
|
||||
commit
|
||||
branch testBranch
|
||||
switch testBranch
|
||||
commit
|
||||
`;
|
||||
|
||||
parser.parse(str);
|
||||
const commits = parser.yy.getCommits();
|
||||
expect(Object.keys(commits).length).toBe(2);
|
||||
expect(parser.yy.getCurrentBranch()).toBe('testBranch');
|
||||
expect(parser.yy.getDirection()).toBe('LR');
|
||||
expect(Object.keys(parser.yy.getBranches()).length).toBe(2);
|
||||
const commit1 = Object.keys(commits)[0];
|
||||
const commit2 = Object.keys(commits)[1];
|
||||
expect(commits[commit1].branch).toBe('main');
|
||||
expect(commits[commit1].parents).toStrictEqual([]);
|
||||
expect(commits[commit2].branch).toBe('testBranch');
|
||||
expect(commits[commit2].parents).toStrictEqual([commit1]);
|
||||
});
|
||||
|
||||
it('should handle new branch switch & commit and merge', function () {
|
||||
const str = `gitGraph:
|
||||
commit
|
||||
branch testBranch
|
||||
switch testBranch
|
||||
commit
|
||||
commit
|
||||
switch main
|
||||
merge testBranch
|
||||
`;
|
||||
|
||||
parser.parse(str);
|
||||
const commits = parser.yy.getCommits();
|
||||
expect(Object.keys(commits).length).toBe(4);
|
||||
expect(parser.yy.getCurrentBranch()).toBe('main');
|
||||
expect(parser.yy.getDirection()).toBe('LR');
|
||||
expect(Object.keys(parser.yy.getBranches()).length).toBe(2);
|
||||
const commit1 = Object.keys(commits)[0];
|
||||
const commit2 = Object.keys(commits)[1];
|
||||
const commit3 = Object.keys(commits)[2];
|
||||
const commit4 = Object.keys(commits)[3];
|
||||
expect(commits[commit1].branch).toBe('main');
|
||||
expect(commits[commit1].parents).toStrictEqual([]);
|
||||
expect(commits[commit2].branch).toBe('testBranch');
|
||||
expect(commits[commit2].parents).toStrictEqual([commits[commit1].id]);
|
||||
expect(commits[commit3].branch).toBe('testBranch');
|
||||
expect(commits[commit3].parents).toStrictEqual([commits[commit2].id]);
|
||||
expect(commits[commit4].branch).toBe('main');
|
||||
expect(commits[commit4].parents).toStrictEqual([commits[commit1].id, commits[commit3].id]);
|
||||
expect(parser.yy.getBranchesAsObjArray()).toStrictEqual([
|
||||
{ name: 'main' },
|
||||
{ name: 'testBranch' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle merge tags', function () {
|
||||
const str = `gitGraph:
|
||||
commit
|
||||
|
@@ -41,7 +41,7 @@ merge(?=\s|$) return 'MERGE';
|
||||
cherry\-pick(?=\s|$) return 'CHERRY_PICK';
|
||||
"parent:" return 'PARENT_COMMIT'
|
||||
// "reset" return 'RESET';
|
||||
\b(checkout|switch)(?=\s|$) return 'CHECKOUT';
|
||||
checkout(?=\s|$) return 'CHECKOUT';
|
||||
"LR" return 'DIR';
|
||||
"TB" return 'DIR';
|
||||
"BT" return 'DIR';
|
||||
|
@@ -11,7 +11,6 @@
|
||||
%x point_start
|
||||
%x point_x
|
||||
%x point_y
|
||||
%x class_name
|
||||
%%
|
||||
\%\%(?!\{)[^\n]* /* skip comments */
|
||||
[^\}]\%\%[^\n]* /* skip comments */
|
||||
@@ -36,7 +35,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
|
||||
" "*"quadrant-2"" "* return 'QUADRANT_2';
|
||||
" "*"quadrant-3"" "* return 'QUADRANT_3';
|
||||
" "*"quadrant-4"" "* return 'QUADRANT_4';
|
||||
"classDef" return 'CLASSDEF';
|
||||
|
||||
["][`] { this.begin("md_string");}
|
||||
<md_string>[^`"]+ { return "MD_STR";}
|
||||
@@ -45,9 +43,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
|
||||
<string>["] this.popState();
|
||||
<string>[^"]* return "STR";
|
||||
|
||||
\:\:\: {this.begin('class_name')}
|
||||
<class_name>^\w+ {this.popState(); return 'class_name';}
|
||||
|
||||
\s*\:\s*\[\s* {this.begin("point_start"); return 'point_start';}
|
||||
<point_start>(1)|(0(.\d+)?) {this.begin('point_x'); return 'point_x';}
|
||||
<point_start>\s*\]" "* {this.popState();}
|
||||
@@ -80,31 +75,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
|
||||
|
||||
%% /* language grammar */
|
||||
|
||||
idStringToken : ALPHA | NUM | NODE_STRING | DOWN | MINUS | DEFAULT | COMMA | COLON | AMP | BRKT | MULT | UNICODE_TEXT;
|
||||
styleComponent: ALPHA | NUM | NODE_STRING | COLON | UNIT | SPACE | BRKT | STYLE | PCT | MINUS ;
|
||||
|
||||
idString
|
||||
:idStringToken
|
||||
{$$=$idStringToken}
|
||||
| idString idStringToken
|
||||
{$$=$idString+''+$idStringToken}
|
||||
;
|
||||
|
||||
style: styleComponent
|
||||
|style styleComponent
|
||||
{$$ = $style + $styleComponent;}
|
||||
;
|
||||
|
||||
stylesOpt: style
|
||||
{$$ = [$style.trim()]}
|
||||
| stylesOpt COMMA style
|
||||
{$stylesOpt.push($style.trim());$$ = $stylesOpt;}
|
||||
;
|
||||
|
||||
classDefStatement
|
||||
: CLASSDEF SPACE idString SPACE stylesOpt {$$ = $CLASSDEF;yy.addClass($idString,$stylesOpt);}
|
||||
;
|
||||
|
||||
start
|
||||
: eol start
|
||||
| SPACE start
|
||||
@@ -122,7 +92,6 @@ line
|
||||
|
||||
statement
|
||||
:
|
||||
| classDefStatement {$$=[];}
|
||||
| SPACE statement
|
||||
| axisDetails
|
||||
| quadrantDetails
|
||||
@@ -134,10 +103,7 @@ statement
|
||||
;
|
||||
|
||||
points
|
||||
: text point_start point_x point_y {yy.addPoint($1, "", $3, $4, []);}
|
||||
| text class_name point_start point_x point_y {yy.addPoint($1, $2, $4, $5, []);}
|
||||
| text point_start point_x point_y stylesOpt {yy.addPoint($1, "", $3, $4, $stylesOpt);}
|
||||
| text class_name point_start point_x point_y stylesOpt {yy.addPoint($1, $2, $4, $5, $stylesOpt);}
|
||||
: text point_start point_x point_y {yy.addPoint($1, $3, $4);}
|
||||
;
|
||||
|
||||
axisDetails
|
||||
|
@@ -212,34 +212,20 @@ describe('Testing quadrantChart jison file', () => {
|
||||
it('should be able to parse points', () => {
|
||||
let str = 'quadrantChart\npoint1: [0.1, 0.4]';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'point1', type: 'text' },
|
||||
'',
|
||||
'0.1',
|
||||
'0.4',
|
||||
[]
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith({ text: 'point1', type: 'text' }, '0.1', '0.4');
|
||||
|
||||
clearMocks();
|
||||
str = 'QuadRantChart \n Point1 : [0.1, 0.4] ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'Point1', type: 'text' },
|
||||
'',
|
||||
'0.1',
|
||||
'0.4',
|
||||
[]
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith({ text: 'Point1', type: 'text' }, '0.1', '0.4');
|
||||
|
||||
clearMocks();
|
||||
str = 'QuadRantChart \n "Point1 : (* +=[❤": [1, 0] ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'Point1 : (* +=[❤', type: 'text' },
|
||||
'',
|
||||
'1',
|
||||
'0',
|
||||
[]
|
||||
'0'
|
||||
);
|
||||
|
||||
clearMocks();
|
||||
@@ -278,149 +264,15 @@ describe('Testing quadrantChart jison file', () => {
|
||||
expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' });
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'Microsoft', type: 'text' },
|
||||
'',
|
||||
'0.75',
|
||||
'0.75',
|
||||
[]
|
||||
'0.75'
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'Salesforce', type: 'text' },
|
||||
'',
|
||||
'0.55',
|
||||
'0.60',
|
||||
[]
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'IBM', type: 'text' },
|
||||
'',
|
||||
'0.51',
|
||||
'0.40',
|
||||
[]
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'Incorta', type: 'text' },
|
||||
'',
|
||||
'0.20',
|
||||
'0.30',
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to parse the whole chart with point styling with all params or some params', () => {
|
||||
const str = `quadrantChart
|
||||
title Analytics and Business Intelligence Platforms
|
||||
x-axis "Completeness of Vision ❤" --> "x-axis-2"
|
||||
y-axis Ability to Execute --> "y-axis-2"
|
||||
quadrant-1 Leaders
|
||||
quadrant-2 Challengers
|
||||
quadrant-3 Niche
|
||||
quadrant-4 Visionaries
|
||||
Microsoft: [0.75, 0.75] radius: 10
|
||||
Salesforce: [0.55, 0.60] radius: 10, color: #ff0000
|
||||
IBM: [0.51, 0.40] radius: 10, color: #ff0000, stroke-color: #ff00ff
|
||||
Incorta: [0.20, 0.30] radius: 10 ,color: #ff0000 ,stroke-color: #ff00ff ,stroke-width: 10px`;
|
||||
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({
|
||||
text: 'Completeness of Vision ❤',
|
||||
type: 'text',
|
||||
});
|
||||
expect(mockDB.setXAxisRightText).toHaveBeenCalledWith({ text: 'x-axis-2', type: 'text' });
|
||||
expect(mockDB.setYAxisTopText).toHaveBeenCalledWith({ text: 'y-axis-2', type: 'text' });
|
||||
expect(mockDB.setYAxisBottomText).toHaveBeenCalledWith({
|
||||
text: 'Ability to Execute',
|
||||
type: 'text',
|
||||
});
|
||||
expect(mockDB.setQuadrant1Text).toHaveBeenCalledWith({ text: 'Leaders', type: 'text' });
|
||||
expect(mockDB.setQuadrant2Text).toHaveBeenCalledWith({ text: 'Challengers', type: 'text' });
|
||||
expect(mockDB.setQuadrant3Text).toHaveBeenCalledWith({ text: 'Niche', type: 'text' });
|
||||
expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' });
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'Microsoft', type: 'text' },
|
||||
'',
|
||||
'0.75',
|
||||
'0.75',
|
||||
['radius: 10']
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'Salesforce', type: 'text' },
|
||||
'',
|
||||
'0.55',
|
||||
'0.60',
|
||||
['radius: 10', 'color: #ff0000']
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'IBM', type: 'text' },
|
||||
'',
|
||||
'0.51',
|
||||
'0.40',
|
||||
['radius: 10', 'color: #ff0000', 'stroke-color: #ff00ff']
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'Incorta', type: 'text' },
|
||||
'',
|
||||
'0.20',
|
||||
'0.30',
|
||||
['radius: 10', 'color: #ff0000', 'stroke-color: #ff00ff', 'stroke-width: 10px']
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to parse the whole chart with point styling with params in a random order + class names', () => {
|
||||
const str = `quadrantChart
|
||||
title Analytics and Business Intelligence Platforms
|
||||
x-axis "Completeness of Vision ❤" --> "x-axis-2"
|
||||
y-axis Ability to Execute --> "y-axis-2"
|
||||
quadrant-1 Leaders
|
||||
quadrant-2 Challengers
|
||||
quadrant-3 Niche
|
||||
quadrant-4 Visionaries
|
||||
Microsoft: [0.75, 0.75] stroke-color: #ff00ff ,stroke-width: 10px, color: #ff0000, radius: 10
|
||||
Salesforce:::class1: [0.55, 0.60] radius: 10, color: #ff0000
|
||||
IBM: [0.51, 0.40] stroke-color: #ff00ff ,stroke-width: 10px
|
||||
Incorta: [0.20, 0.30] stroke-width: 10px`;
|
||||
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({
|
||||
text: 'Completeness of Vision ❤',
|
||||
type: 'text',
|
||||
});
|
||||
expect(mockDB.setXAxisRightText).toHaveBeenCalledWith({ text: 'x-axis-2', type: 'text' });
|
||||
expect(mockDB.setYAxisTopText).toHaveBeenCalledWith({ text: 'y-axis-2', type: 'text' });
|
||||
expect(mockDB.setYAxisBottomText).toHaveBeenCalledWith({
|
||||
text: 'Ability to Execute',
|
||||
type: 'text',
|
||||
});
|
||||
expect(mockDB.setQuadrant1Text).toHaveBeenCalledWith({ text: 'Leaders', type: 'text' });
|
||||
expect(mockDB.setQuadrant2Text).toHaveBeenCalledWith({ text: 'Challengers', type: 'text' });
|
||||
expect(mockDB.setQuadrant3Text).toHaveBeenCalledWith({ text: 'Niche', type: 'text' });
|
||||
expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' });
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'Microsoft', type: 'text' },
|
||||
'',
|
||||
'0.75',
|
||||
'0.75',
|
||||
['stroke-color: #ff00ff', 'stroke-width: 10px', 'color: #ff0000', 'radius: 10']
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'Salesforce', type: 'text' },
|
||||
'class1',
|
||||
'0.55',
|
||||
'0.60',
|
||||
['radius: 10', 'color: #ff0000']
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'IBM', type: 'text' },
|
||||
'',
|
||||
'0.51',
|
||||
'0.40',
|
||||
['stroke-color: #ff00ff', 'stroke-width: 10px']
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith(
|
||||
{ text: 'Incorta', type: 'text' },
|
||||
'',
|
||||
'0.20',
|
||||
'0.30',
|
||||
['stroke-width: 10px']
|
||||
'0.60'
|
||||
);
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith({ text: 'IBM', type: 'text' }, '0.51', '0.40');
|
||||
expect(mockDB.addPoint).toHaveBeenCalledWith({ text: 'Incorta', type: 'text' }, '0.20', '0.30');
|
||||
});
|
||||
});
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { scaleLinear } from 'd3';
|
||||
import { log } from '../../logger.js';
|
||||
import type { BaseDiagramConfig, QuadrantChartConfig } from '../../config.type.js';
|
||||
import defaultConfig from '../../defaultConfig.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { getThemeVariables } from '../../themes/theme-default.js';
|
||||
import type { Point } from '../../types.js';
|
||||
|
||||
@@ -10,15 +10,7 @@ const defaultThemeVariables = getThemeVariables();
|
||||
export type TextVerticalPos = 'left' | 'center' | 'right';
|
||||
export type TextHorizontalPos = 'top' | 'middle' | 'bottom';
|
||||
|
||||
export interface StylesObject {
|
||||
className?: string;
|
||||
radius?: number;
|
||||
color?: string;
|
||||
strokeColor?: string;
|
||||
strokeWidth?: string;
|
||||
}
|
||||
|
||||
export interface QuadrantPointInputType extends Point, StylesObject {
|
||||
export interface QuadrantPointInputType extends Point {
|
||||
text: string;
|
||||
}
|
||||
|
||||
@@ -31,9 +23,7 @@ export interface QuadrantTextType extends Point {
|
||||
rotation: number;
|
||||
}
|
||||
|
||||
export interface QuadrantPointType
|
||||
extends Point,
|
||||
Pick<StylesObject, 'strokeColor' | 'strokeWidth'> {
|
||||
export interface QuadrantPointType extends Point {
|
||||
fill: string;
|
||||
radius: number;
|
||||
text: QuadrantTextType;
|
||||
@@ -127,7 +117,6 @@ export class QuadrantBuilder {
|
||||
private config: QuadrantBuilderConfig;
|
||||
private themeConfig: QuadrantBuilderThemeConfig;
|
||||
private data: QuadrantBuilderData;
|
||||
private classes: Record<string, StylesObject> = {};
|
||||
|
||||
constructor() {
|
||||
this.config = this.getDefaultConfig();
|
||||
@@ -202,7 +191,6 @@ export class QuadrantBuilder {
|
||||
this.config = this.getDefaultConfig();
|
||||
this.themeConfig = this.getDefaultThemeConfig();
|
||||
this.data = this.getDefaultData();
|
||||
this.classes = {};
|
||||
log.info('clear called');
|
||||
}
|
||||
|
||||
@@ -214,10 +202,6 @@ export class QuadrantBuilder {
|
||||
this.data.points = [...points, ...this.data.points];
|
||||
}
|
||||
|
||||
addClass(className: string, styles: StylesObject) {
|
||||
this.classes[className] = styles;
|
||||
}
|
||||
|
||||
setConfig(config: Partial<QuadrantBuilderConfig>) {
|
||||
log.trace('setConfig called with: ', config);
|
||||
this.config = { ...this.config, ...config };
|
||||
@@ -486,15 +470,11 @@ export class QuadrantBuilder {
|
||||
.range([quadrantHeight + quadrantTop, quadrantTop]);
|
||||
|
||||
const points: QuadrantPointType[] = this.data.points.map((point) => {
|
||||
const classStyles = this.classes[point.className as keyof typeof this.classes];
|
||||
if (classStyles) {
|
||||
point = { ...classStyles, ...point };
|
||||
}
|
||||
const props: QuadrantPointType = {
|
||||
x: xAxis(point.x),
|
||||
y: yAxis(point.y),
|
||||
fill: point.color || this.themeConfig.quadrantPointFill,
|
||||
radius: point.radius || this.config.pointRadius,
|
||||
fill: this.themeConfig.quadrantPointFill,
|
||||
radius: this.config.pointRadius,
|
||||
text: {
|
||||
text: point.text,
|
||||
fill: this.themeConfig.quadrantPointTextFill,
|
||||
@@ -505,8 +485,6 @@ export class QuadrantBuilder {
|
||||
fontSize: this.config.pointLabelFontSize,
|
||||
rotation: 0,
|
||||
},
|
||||
strokeColor: point.strokeColor || this.themeConfig.quadrantPointFill,
|
||||
strokeWidth: point.strokeWidth || '0px',
|
||||
};
|
||||
return props;
|
||||
});
|
||||
|
@@ -1,50 +0,0 @@
|
||||
import quadrantDb from './quadrantDb.js';
|
||||
|
||||
describe('quadrant unit tests', () => {
|
||||
it('should parse the styles array and return a StylesObject', () => {
|
||||
const styles = ['radius: 10', 'color: #ff0000', 'stroke-color: #ff00ff', 'stroke-width: 10px'];
|
||||
const result = quadrantDb.parseStyles(styles);
|
||||
|
||||
expect(result).toEqual({
|
||||
radius: 10,
|
||||
color: '#ff0000',
|
||||
strokeColor: '#ff00ff',
|
||||
strokeWidth: '10px',
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error for non supported style name', () => {
|
||||
const styles: string[] = ['test_name: value'];
|
||||
expect(() => quadrantDb.parseStyles(styles)).toThrowError(
|
||||
'style named test_name is not supported.'
|
||||
);
|
||||
});
|
||||
|
||||
it('should return an empty StylesObject for an empty input array', () => {
|
||||
const styles: string[] = [];
|
||||
const result = quadrantDb.parseStyles(styles);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('should throw an error for non supported style value', () => {
|
||||
let styles: string[] = ['radius: f'];
|
||||
expect(() => quadrantDb.parseStyles(styles)).toThrowError(
|
||||
'value for radius f is invalid, please use a valid number'
|
||||
);
|
||||
|
||||
styles = ['color: ffaa'];
|
||||
expect(() => quadrantDb.parseStyles(styles)).toThrowError(
|
||||
'value for color ffaa is invalid, please use a valid hex code'
|
||||
);
|
||||
|
||||
styles = ['stroke-color: #f677779'];
|
||||
expect(() => quadrantDb.parseStyles(styles)).toThrowError(
|
||||
'value for stroke-color #f677779 is invalid, please use a valid hex code'
|
||||
);
|
||||
|
||||
styles = ['stroke-width: 30'];
|
||||
expect(() => quadrantDb.parseStyles(styles)).toThrowError(
|
||||
'value for stroke-width 30 is invalid, please use a valid number of pixels (eg. 10px)'
|
||||
);
|
||||
});
|
||||
});
|
@@ -9,14 +9,7 @@ import {
|
||||
setAccDescription,
|
||||
clear as commonClear,
|
||||
} from '../common/commonDb.js';
|
||||
import type { StylesObject } from './quadrantBuilder.js';
|
||||
import { QuadrantBuilder } from './quadrantBuilder.js';
|
||||
import {
|
||||
validateHexCode,
|
||||
validateSizeInPixels,
|
||||
validateNumber,
|
||||
InvalidStyleError,
|
||||
} from './utils.js';
|
||||
|
||||
const config = getConfig();
|
||||
|
||||
@@ -24,10 +17,7 @@ function textSanitizer(text: string) {
|
||||
return sanitizeText(text.trim(), config);
|
||||
}
|
||||
|
||||
interface LexTextObj {
|
||||
text: string;
|
||||
type: 'text' | 'markdown';
|
||||
}
|
||||
type LexTextObj = { text: string; type: 'text' | 'markdown' };
|
||||
|
||||
const quadrantBuilder = new QuadrantBuilder();
|
||||
|
||||
@@ -63,52 +53,8 @@ function setYAxisBottomText(textObj: LexTextObj) {
|
||||
quadrantBuilder.setData({ yAxisBottomText: textSanitizer(textObj.text) });
|
||||
}
|
||||
|
||||
function parseStyles(styles: string[]): StylesObject {
|
||||
const stylesObject: StylesObject = {};
|
||||
for (const style of styles) {
|
||||
const [key, value] = style.trim().split(/\s*:\s*/);
|
||||
if (key === 'radius') {
|
||||
if (validateNumber(value)) {
|
||||
throw new InvalidStyleError(key, value, 'number');
|
||||
}
|
||||
stylesObject.radius = parseInt(value);
|
||||
} else if (key === 'color') {
|
||||
if (validateHexCode(value)) {
|
||||
throw new InvalidStyleError(key, value, 'hex code');
|
||||
}
|
||||
stylesObject.color = value;
|
||||
} else if (key === 'stroke-color') {
|
||||
if (validateHexCode(value)) {
|
||||
throw new InvalidStyleError(key, value, 'hex code');
|
||||
}
|
||||
stylesObject.strokeColor = value;
|
||||
} else if (key === 'stroke-width') {
|
||||
if (validateSizeInPixels(value)) {
|
||||
throw new InvalidStyleError(key, value, 'number of pixels (eg. 10px)');
|
||||
}
|
||||
stylesObject.strokeWidth = value;
|
||||
} else {
|
||||
throw new Error(`style named ${key} is not supported.`);
|
||||
}
|
||||
}
|
||||
return stylesObject;
|
||||
}
|
||||
|
||||
function addPoint(textObj: LexTextObj, className: string, x: number, y: number, styles: string[]) {
|
||||
const stylesObject = parseStyles(styles);
|
||||
quadrantBuilder.addPoints([
|
||||
{
|
||||
x,
|
||||
y,
|
||||
text: textSanitizer(textObj.text),
|
||||
className,
|
||||
...stylesObject,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
function addClass(className: string, styles: string[]) {
|
||||
quadrantBuilder.addClass(className, parseStyles(styles));
|
||||
function addPoint(textObj: LexTextObj, x: number, y: number) {
|
||||
quadrantBuilder.addPoints([{ x, y, text: textSanitizer(textObj.text) }]);
|
||||
}
|
||||
|
||||
function setWidth(width: number) {
|
||||
@@ -162,9 +108,7 @@ export default {
|
||||
setXAxisRightText,
|
||||
setYAxisTopText,
|
||||
setYAxisBottomText,
|
||||
parseStyles,
|
||||
addPoint,
|
||||
addClass,
|
||||
getQuadrantData,
|
||||
clear,
|
||||
setAccTitle,
|
||||
|
@@ -152,9 +152,7 @@ export const draw = (txt: string, id: string, _version: string, diagObj: Diagram
|
||||
.attr('cx', (data: QuadrantPointType) => data.x)
|
||||
.attr('cy', (data: QuadrantPointType) => data.y)
|
||||
.attr('r', (data: QuadrantPointType) => data.radius)
|
||||
.attr('fill', (data: QuadrantPointType) => data.fill)
|
||||
.attr('stroke', (data: QuadrantPointType) => data.strokeColor)
|
||||
.attr('stroke-width', (data: QuadrantPointType) => data.strokeWidth);
|
||||
.attr('fill', (data: QuadrantPointType) => data.fill);
|
||||
|
||||
dataPoints
|
||||
.append('text')
|
||||
|
@@ -1,20 +0,0 @@
|
||||
class InvalidStyleError extends Error {
|
||||
constructor(style: string, value: string, type: string) {
|
||||
super(`value for ${style} ${value} is invalid, please use a valid ${type}`);
|
||||
this.name = 'InvalidStyleError';
|
||||
}
|
||||
}
|
||||
|
||||
function validateHexCode(value: string): boolean {
|
||||
return !/^#?([\dA-Fa-f]{6}|[\dA-Fa-f]{3})$/.test(value);
|
||||
}
|
||||
|
||||
function validateNumber(value: string): boolean {
|
||||
return !/^\d+$/.test(value);
|
||||
}
|
||||
|
||||
function validateSizeInPixels(value: string): boolean {
|
||||
return !/^\d+px$/.test(value);
|
||||
}
|
||||
|
||||
export { validateHexCode, validateNumber, validateSizeInPixels, InvalidStyleError };
|
@@ -3,7 +3,7 @@
|
||||
* (c) 2014-2015 Knut Sveidqvist
|
||||
* MIT license.
|
||||
*
|
||||
* Based on js sequence diagrams jison grammar
|
||||
* Based on js sequence diagrams jison grammr
|
||||
* https://bramp.github.io/js-sequence-diagrams/
|
||||
* (c) 2012-2013 Andrew Brampton (bramp.net)
|
||||
* Simplified BSD license.
|
||||
@@ -138,8 +138,8 @@ statement
|
||||
| autonumber NUM 'NEWLINE' { $$ = {type:'sequenceIndex',sequenceIndex: Number($2), sequenceIndexStep:1, sequenceVisible:true, signalType:yy.LINETYPE.AUTONUMBER};}
|
||||
| autonumber off 'NEWLINE' { $$ = {type:'sequenceIndex', sequenceVisible:false, signalType:yy.LINETYPE.AUTONUMBER};}
|
||||
| autonumber 'NEWLINE' {$$ = {type:'sequenceIndex', sequenceVisible:true, signalType:yy.LINETYPE.AUTONUMBER}; }
|
||||
| 'activate' actor 'NEWLINE' {$$={type: 'activeStart', signalType: yy.LINETYPE.ACTIVE_START, actor: $2.actor};}
|
||||
| 'deactivate' actor 'NEWLINE' {$$={type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $2.actor};}
|
||||
| 'activate' actor 'NEWLINE' {$$={type: 'activeStart', signalType: yy.LINETYPE.ACTIVE_START, actor: $2};}
|
||||
| 'deactivate' actor 'NEWLINE' {$$={type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $2};}
|
||||
| note_statement 'NEWLINE'
|
||||
| links_statement 'NEWLINE'
|
||||
| link_statement 'NEWLINE'
|
||||
@@ -288,11 +288,11 @@ placement
|
||||
signal
|
||||
: actor signaltype '+' actor text2
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5, activate: true},
|
||||
{type: 'activeStart', signalType: yy.LINETYPE.ACTIVE_START, actor: $4.actor}
|
||||
{type: 'activeStart', signalType: yy.LINETYPE.ACTIVE_START, actor: $4}
|
||||
]}
|
||||
| actor signaltype '-' actor text2
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5},
|
||||
{type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $1.actor}
|
||||
{type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $1}
|
||||
]}
|
||||
| actor signaltype actor text2
|
||||
{ $$ = [$1,$3,{type: 'addMessage', from:$1.actor, to:$3.actor, signalType:$2, msg:$4}]}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { ImperativeState } from '../../utils/imperativeState.js';
|
||||
import { sanitizeText } from '../common/common.js';
|
||||
import {
|
||||
clear as commonClear,
|
||||
@@ -11,24 +10,9 @@ import {
|
||||
setAccTitle,
|
||||
setDiagramTitle,
|
||||
} from '../common/commonDb.js';
|
||||
import type { Actor, AddMessageParams, Box, Message, Note } from './types.js';
|
||||
import { ImperativeState } from '../../utils/imperativeState.js';
|
||||
|
||||
interface SequenceState {
|
||||
prevActor?: string;
|
||||
actors: Record<string, Actor>;
|
||||
createdActors: Record<string, number>;
|
||||
destroyedActors: Record<string, number>;
|
||||
boxes: Box[];
|
||||
messages: Message[];
|
||||
notes: Note[];
|
||||
sequenceNumbersEnabled: boolean;
|
||||
wrapEnabled?: boolean;
|
||||
currentBox?: Box;
|
||||
lastCreated?: Actor;
|
||||
lastDestroyed?: Actor;
|
||||
}
|
||||
|
||||
const state = new ImperativeState<SequenceState>(() => ({
|
||||
const state = new ImperativeState(() => ({
|
||||
prevActor: undefined,
|
||||
actors: {},
|
||||
createdActors: {},
|
||||
@@ -43,7 +27,7 @@ const state = new ImperativeState<SequenceState>(() => ({
|
||||
lastDestroyed: undefined,
|
||||
}));
|
||||
|
||||
export const addBox = function (data: { text: string; color: string; wrap: boolean }) {
|
||||
export const addBox = function (data) {
|
||||
state.records.boxes.push({
|
||||
name: data.text,
|
||||
wrap: (data.wrap === undefined && autoWrap()) || !!data.wrap,
|
||||
@@ -53,19 +37,20 @@ export const addBox = function (data: { text: string; color: string; wrap: boole
|
||||
state.records.currentBox = state.records.boxes.slice(-1)[0];
|
||||
};
|
||||
|
||||
export const addActor = function (
|
||||
id: string,
|
||||
name: string,
|
||||
description: { text: string; wrap?: boolean | null; type: string },
|
||||
type: string
|
||||
) {
|
||||
export const addActor = function (id, name, description, type) {
|
||||
let assignedBox = state.records.currentBox;
|
||||
const old = state.records.actors[id];
|
||||
if (old) {
|
||||
// If already set and trying to set to a new one throw error
|
||||
if (state.records.currentBox && old.box && state.records.currentBox !== old.box) {
|
||||
throw new Error(
|
||||
`A same participant should only be defined in one Box: ${old.name} can't be in '${old.box.name}' and in '${state.records.currentBox.name}' at the same time.`
|
||||
'A same participant should only be defined in one Box: ' +
|
||||
old.name +
|
||||
" can't be in '" +
|
||||
old.box.name +
|
||||
"' and in '" +
|
||||
state.records.currentBox.name +
|
||||
"' at the same time."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -97,7 +82,7 @@ export const addActor = function (
|
||||
properties: {},
|
||||
actorCnt: null,
|
||||
rectData: null,
|
||||
type: type ?? 'participant',
|
||||
type: type || 'participant',
|
||||
};
|
||||
if (state.records.prevActor && state.records.actors[state.records.prevActor]) {
|
||||
state.records.actors[state.records.prevActor].nextActor = id;
|
||||
@@ -109,22 +94,19 @@ export const addActor = function (
|
||||
state.records.prevActor = id;
|
||||
};
|
||||
|
||||
const activationCount = (part: string) => {
|
||||
const activationCount = (part) => {
|
||||
let i;
|
||||
let count = 0;
|
||||
if (!part) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < state.records.messages.length; i++) {
|
||||
if (
|
||||
state.records.messages[i].type === LINETYPE.ACTIVE_START &&
|
||||
state.records.messages[i].from === part
|
||||
state.records.messages[i].from.actor === part
|
||||
) {
|
||||
count++;
|
||||
}
|
||||
if (
|
||||
state.records.messages[i].type === LINETYPE.ACTIVE_END &&
|
||||
state.records.messages[i].from === part
|
||||
state.records.messages[i].from.actor === part
|
||||
) {
|
||||
count--;
|
||||
}
|
||||
@@ -132,12 +114,7 @@ const activationCount = (part: string) => {
|
||||
return count;
|
||||
};
|
||||
|
||||
export const addMessage = function (
|
||||
idFrom: Message['from'],
|
||||
idTo: Message['to'],
|
||||
message: { text: string; wrap?: boolean },
|
||||
answer: Message['answer']
|
||||
) {
|
||||
export const addMessage = function (idFrom, idTo, message, answer) {
|
||||
state.records.messages.push({
|
||||
from: idFrom,
|
||||
to: idTo,
|
||||
@@ -148,19 +125,17 @@ export const addMessage = function (
|
||||
};
|
||||
|
||||
export const addSignal = function (
|
||||
idFrom?: Message['from'],
|
||||
idTo?: Message['to'],
|
||||
message?: { text: string; wrap: boolean },
|
||||
messageType?: number,
|
||||
activate: boolean = false
|
||||
idFrom,
|
||||
idTo,
|
||||
message = { text: undefined, wrap: undefined },
|
||||
messageType,
|
||||
activate = false
|
||||
) {
|
||||
if (messageType === LINETYPE.ACTIVE_END) {
|
||||
const cnt = activationCount(idFrom || '');
|
||||
const cnt = activationCount(idFrom.actor);
|
||||
if (cnt < 1) {
|
||||
// Bail out as there is an activation signal from an inactive participant
|
||||
const error = new Error('Trying to inactivate an inactive participant (' + idFrom + ')');
|
||||
|
||||
// @ts-ignore: we are passing hash param to the error object, however we should define our own custom error class to make it type safe
|
||||
let error = new Error('Trying to inactivate an inactive participant (' + idFrom.actor + ')');
|
||||
error.hash = {
|
||||
text: '->>-',
|
||||
token: '->>-',
|
||||
@@ -174,8 +149,8 @@ export const addSignal = function (
|
||||
state.records.messages.push({
|
||||
from: idFrom,
|
||||
to: idTo,
|
||||
message: message?.text ?? '',
|
||||
wrap: (message?.wrap === undefined && autoWrap()) || !!message?.wrap,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
|
||||
type: messageType,
|
||||
activate,
|
||||
});
|
||||
@@ -206,7 +181,7 @@ export const getCreatedActors = function () {
|
||||
export const getDestroyedActors = function () {
|
||||
return state.records.destroyedActors;
|
||||
};
|
||||
export const getActor = function (id: string) {
|
||||
export const getActor = function (id) {
|
||||
return state.records.actors[id];
|
||||
};
|
||||
export const getActorKeys = function () {
|
||||
@@ -220,7 +195,7 @@ export const disableSequenceNumbers = function () {
|
||||
};
|
||||
export const showSequenceNumbers = () => state.records.sequenceNumbersEnabled;
|
||||
|
||||
export const setWrap = function (wrapSetting?: boolean) {
|
||||
export const setWrap = function (wrapSetting) {
|
||||
state.records.wrapEnabled = wrapSetting;
|
||||
};
|
||||
|
||||
@@ -230,7 +205,7 @@ export const autoWrap = () => {
|
||||
if (state.records.wrapEnabled !== undefined) {
|
||||
return state.records.wrapEnabled;
|
||||
}
|
||||
return getConfig()?.sequence?.wrap;
|
||||
return getConfig().sequence.wrap;
|
||||
};
|
||||
|
||||
export const clear = function () {
|
||||
@@ -238,25 +213,25 @@ export const clear = function () {
|
||||
commonClear();
|
||||
};
|
||||
|
||||
export const parseMessage = function (str: string) {
|
||||
const trimmedStr = str.trim();
|
||||
export const parseMessage = function (str) {
|
||||
const _str = str.trim();
|
||||
const message = {
|
||||
text: trimmedStr.replace(/^:?(?:no)?wrap:/, '').trim(),
|
||||
text: _str.replace(/^:?(?:no)?wrap:/, '').trim(),
|
||||
wrap:
|
||||
trimmedStr.match(/^:?wrap:/) !== null
|
||||
_str.match(/^:?wrap:/) !== null
|
||||
? true
|
||||
: trimmedStr.match(/^:?nowrap:/) !== null
|
||||
: _str.match(/^:?nowrap:/) !== null
|
||||
? false
|
||||
: undefined,
|
||||
};
|
||||
log.debug(`parseMessage: ${message}`);
|
||||
log.debug('parseMessage:', message);
|
||||
return message;
|
||||
};
|
||||
|
||||
// We expect the box statement to be color first then description
|
||||
// The color can be rgb,rgba,hsl,hsla, or css code names #hex codes are not supported for now because of the way the char # is handled
|
||||
// We extract first segment as color, the rest of the line is considered as text
|
||||
export const parseBoxData = function (str: string) {
|
||||
export const parseBoxData = function (str) {
|
||||
const match = str.match(/^((?:rgba?|hsla?)\s*\(.*\)|\w*)(.*)$/);
|
||||
let color = match != null && match[1] ? match[1].trim() : 'transparent';
|
||||
let title = match != null && match[2] ? match[2].trim() : undefined;
|
||||
@@ -337,21 +312,18 @@ export const PLACEMENT = {
|
||||
OVER: 2,
|
||||
};
|
||||
|
||||
export const addNote = function (
|
||||
actor: { actor: string },
|
||||
placement: Message['placement'],
|
||||
message: { text: string; wrap?: boolean }
|
||||
) {
|
||||
const note: Note = {
|
||||
export const addNote = function (actor, placement, message) {
|
||||
const note = {
|
||||
actor: actor,
|
||||
placement: placement,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
|
||||
};
|
||||
|
||||
//@ts-ignore: Coerce actor into a [to, from, ...] array
|
||||
// Coerce actor into a [to, from, ...] array
|
||||
// eslint-disable-next-line unicorn/prefer-spread
|
||||
const actors = [].concat(actor, actor);
|
||||
|
||||
state.records.notes.push(note);
|
||||
state.records.messages.push({
|
||||
from: actors[0],
|
||||
@@ -363,7 +335,7 @@ export const addNote = function (
|
||||
});
|
||||
};
|
||||
|
||||
export const addLinks = function (actorId: string, text: { text: string }) {
|
||||
export const addLinks = function (actorId, text) {
|
||||
// find the actor
|
||||
const actor = getActor(actorId);
|
||||
// JSON.parse the text
|
||||
@@ -379,17 +351,17 @@ export const addLinks = function (actorId: string, text: { text: string }) {
|
||||
}
|
||||
};
|
||||
|
||||
export const addALink = function (actorId: string, text: { text: string }) {
|
||||
export const addALink = function (actorId, text) {
|
||||
// find the actor
|
||||
const actor = getActor(actorId);
|
||||
try {
|
||||
const links: Record<string, string> = {};
|
||||
const links = {};
|
||||
let sanitizedText = sanitizeText(text.text, getConfig());
|
||||
const sep = sanitizedText.indexOf('@');
|
||||
var sep = sanitizedText.indexOf('@');
|
||||
sanitizedText = sanitizedText.replace(/&/g, '&');
|
||||
sanitizedText = sanitizedText.replace(/=/g, '=');
|
||||
const label = sanitizedText.slice(0, sep - 1).trim();
|
||||
const link = sanitizedText.slice(sep + 1).trim();
|
||||
var label = sanitizedText.slice(0, sep - 1).trim();
|
||||
var link = sanitizedText.slice(sep + 1).trim();
|
||||
|
||||
links[label] = link;
|
||||
// add the deserialized text to the actor's links field.
|
||||
@@ -400,26 +372,26 @@ export const addALink = function (actorId: string, text: { text: string }) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param actor - the actor to add the links to
|
||||
* @param links - the links to add to the actor
|
||||
* @param {any} actor
|
||||
* @param {any} links
|
||||
*/
|
||||
function insertLinks(actor: Actor, links: Record<string, string>) {
|
||||
function insertLinks(actor, links) {
|
||||
if (actor.links == null) {
|
||||
actor.links = links;
|
||||
} else {
|
||||
for (const key in links) {
|
||||
for (let key in links) {
|
||||
actor.links[key] = links[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const addProperties = function (actorId: string, text: { text: string }) {
|
||||
export const addProperties = function (actorId, text) {
|
||||
// find the actor
|
||||
const actor = getActor(actorId);
|
||||
// JSON.parse the text
|
||||
try {
|
||||
const sanitizedText = sanitizeText(text.text, getConfig());
|
||||
const properties: Record<string, unknown> = JSON.parse(sanitizedText);
|
||||
let sanitizedText = sanitizeText(text.text, getConfig());
|
||||
const properties = JSON.parse(sanitizedText);
|
||||
// add the deserialized text to the actor's property field.
|
||||
insertProperties(actor, properties);
|
||||
} catch (e) {
|
||||
@@ -428,27 +400,30 @@ export const addProperties = function (actorId: string, text: { text: string })
|
||||
};
|
||||
|
||||
/**
|
||||
* @param actor - the actor to add the properties to
|
||||
* @param properties - the properties to add to the actor's properties
|
||||
* @param {any} actor
|
||||
* @param {any} properties
|
||||
*/
|
||||
function insertProperties(actor: Actor, properties: Record<string, unknown>) {
|
||||
function insertProperties(actor, properties) {
|
||||
if (actor.properties == null) {
|
||||
actor.properties = properties;
|
||||
} else {
|
||||
for (const key in properties) {
|
||||
for (let key in properties) {
|
||||
actor.properties[key] = properties[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function boxEnd() {
|
||||
state.records.currentBox = undefined;
|
||||
}
|
||||
|
||||
export const addDetails = function (actorId: string, text: { text: string }) {
|
||||
export const addDetails = function (actorId, text) {
|
||||
// find the actor
|
||||
const actor = getActor(actorId);
|
||||
const elem = document.getElementById(text.text)!;
|
||||
const elem = document.getElementById(text.text);
|
||||
|
||||
// JSON.parse the text
|
||||
try {
|
||||
@@ -467,7 +442,7 @@ export const addDetails = function (actorId: string, text: { text: string }) {
|
||||
}
|
||||
};
|
||||
|
||||
export const getActorProperty = function (actor: Actor, key: string) {
|
||||
export const getActorProperty = function (actor, key) {
|
||||
if (actor !== undefined && actor.properties !== undefined) {
|
||||
return actor.properties[key];
|
||||
}
|
||||
@@ -475,7 +450,20 @@ export const getActorProperty = function (actor: Actor, key: string) {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const apply = function (param: any | AddMessageParams | AddMessageParams[]) {
|
||||
/**
|
||||
* @typedef {object} AddMessageParams A message from one actor to another.
|
||||
* @property {string} from - The id of the actor sending the message.
|
||||
* @property {string} to - The id of the actor receiving the message.
|
||||
* @property {string} msg - The message text.
|
||||
* @property {number} signalType - The type of signal.
|
||||
* @property {"addMessage"} type - Set to `"addMessage"` if this is an `AddMessageParams`.
|
||||
* @property {boolean} [activate] - If `true`, this signal starts an activation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {object | object[] | AddMessageParams} param - Object of parameters.
|
||||
*/
|
||||
export const apply = function (param) {
|
||||
if (Array.isArray(param)) {
|
||||
param.forEach(function (item) {
|
||||
apply(item);
|
@@ -534,10 +534,10 @@ deactivate Bob`;
|
||||
expect(messages.length).toBe(4);
|
||||
expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED);
|
||||
expect(messages[1].type).toBe(diagram.db.LINETYPE.ACTIVE_START);
|
||||
expect(messages[1].from).toBe('Bob');
|
||||
expect(messages[1].from.actor).toBe('Bob');
|
||||
expect(messages[2].type).toBe(diagram.db.LINETYPE.DOTTED);
|
||||
expect(messages[3].type).toBe(diagram.db.LINETYPE.ACTIVE_END);
|
||||
expect(messages[3].from).toBe('Bob');
|
||||
expect(messages[3].from.actor).toBe('Bob');
|
||||
});
|
||||
it('should handle actor one line notation activation', async () => {
|
||||
const str = `
|
||||
@@ -556,10 +556,10 @@ deactivate Bob`;
|
||||
expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED);
|
||||
expect(messages[0].activate).toBeTruthy();
|
||||
expect(messages[1].type).toBe(diagram.db.LINETYPE.ACTIVE_START);
|
||||
expect(messages[1].from).toBe('Bob');
|
||||
expect(messages[1].from.actor).toBe('Bob');
|
||||
expect(messages[2].type).toBe(diagram.db.LINETYPE.DOTTED);
|
||||
expect(messages[3].type).toBe(diagram.db.LINETYPE.ACTIVE_END);
|
||||
expect(messages[3].from).toBe('Bob');
|
||||
expect(messages[3].from.actor).toBe('Bob');
|
||||
});
|
||||
it('should handle stacked activations', async () => {
|
||||
const str = `
|
||||
@@ -579,14 +579,14 @@ deactivate Bob`;
|
||||
expect(messages.length).toBe(8);
|
||||
expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED);
|
||||
expect(messages[1].type).toBe(diagram.db.LINETYPE.ACTIVE_START);
|
||||
expect(messages[1].from).toBe('Bob');
|
||||
expect(messages[1].from.actor).toBe('Bob');
|
||||
expect(messages[2].type).toBe(diagram.db.LINETYPE.DOTTED);
|
||||
expect(messages[3].type).toBe(diagram.db.LINETYPE.ACTIVE_START);
|
||||
expect(messages[3].from).toBe('Carol');
|
||||
expect(messages[3].from.actor).toBe('Carol');
|
||||
expect(messages[5].type).toBe(diagram.db.LINETYPE.ACTIVE_END);
|
||||
expect(messages[5].from).toBe('Bob');
|
||||
expect(messages[5].from.actor).toBe('Bob');
|
||||
expect(messages[7].type).toBe(diagram.db.LINETYPE.ACTIVE_END);
|
||||
expect(messages[7].from).toBe('Carol');
|
||||
expect(messages[7].from.actor).toBe('Carol');
|
||||
});
|
||||
it('should handle fail parsing when activating an inactive participant', async () => {
|
||||
const str = `
|
||||
|
@@ -144,15 +144,15 @@ export const bounds = {
|
||||
this.updateBounds(_startx, _starty, _stopx, _stopy);
|
||||
},
|
||||
newActivation: function (message, diagram, actors) {
|
||||
const actorRect = actors[message.from];
|
||||
const stackedSize = actorActivations(message.from).length || 0;
|
||||
const actorRect = actors[message.from.actor];
|
||||
const stackedSize = actorActivations(message.from.actor).length || 0;
|
||||
const x = actorRect.x + actorRect.width / 2 + ((stackedSize - 1) * conf.activationWidth) / 2;
|
||||
this.activations.push({
|
||||
startx: x,
|
||||
starty: this.verticalPos + 2,
|
||||
stopx: x + conf.activationWidth,
|
||||
stopy: undefined,
|
||||
actor: message.from,
|
||||
actor: message.from.actor,
|
||||
anchored: svgDraw.anchorElement(diagram),
|
||||
});
|
||||
},
|
||||
@@ -162,7 +162,7 @@ export const bounds = {
|
||||
.map(function (activation) {
|
||||
return activation.actor;
|
||||
})
|
||||
.lastIndexOf(message.from);
|
||||
.lastIndexOf(message.from.actor);
|
||||
return this.activations.splice(lastActorActivationIdx, 1)[0];
|
||||
},
|
||||
createLoop: function (title = { message: undefined, wrap: false, width: undefined }, fill) {
|
||||
@@ -836,7 +836,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
activationData,
|
||||
verticalPos,
|
||||
conf,
|
||||
actorActivations(msg.from).length
|
||||
actorActivations(msg.from.actor).length
|
||||
);
|
||||
|
||||
bounds.insert(activationData.startx, verticalPos - 10, activationData.stopx, verticalPos);
|
||||
@@ -1545,14 +1545,14 @@ const calculateLoopBounds = async function (messages, actors, _maxWidthPerActor,
|
||||
break;
|
||||
case diagObj.db.LINETYPE.ACTIVE_START:
|
||||
{
|
||||
const actorRect = actors[msg.from ? msg.from : msg.to.actor];
|
||||
const stackedSize = actorActivations(msg.from ? msg.from : msg.to.actor).length;
|
||||
const actorRect = actors[msg.from ? msg.from.actor : msg.to.actor];
|
||||
const stackedSize = actorActivations(msg.from ? msg.from.actor : msg.to.actor).length;
|
||||
const x =
|
||||
actorRect.x + actorRect.width / 2 + ((stackedSize - 1) * conf.activationWidth) / 2;
|
||||
const toAdd = {
|
||||
startx: x,
|
||||
stopx: x + conf.activationWidth,
|
||||
actor: msg.from,
|
||||
actor: msg.from.actor,
|
||||
enabled: true,
|
||||
};
|
||||
bounds.activations.push(toAdd);
|
||||
@@ -1562,7 +1562,7 @@ const calculateLoopBounds = async function (messages, actors, _maxWidthPerActor,
|
||||
{
|
||||
const lastActorActivationIdx = bounds.activations
|
||||
.map((a) => a.actor)
|
||||
.lastIndexOf(msg.from);
|
||||
.lastIndexOf(msg.from.actor);
|
||||
delete bounds.activations.splice(lastActorActivationIdx, 1)[0];
|
||||
}
|
||||
break;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import common, { calculateMathMLDimensions, hasKatex, renderKatex } from '../common/common.js';
|
||||
import * as svgDrawCommon from '../common/svgDrawCommon.js';
|
||||
import { addFunction } from '../../interactionDb.js';
|
||||
import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js';
|
||||
import { sanitizeUrl } from '@braintree/sanitize-url';
|
||||
import * as configApi from '../../config.js';
|
||||
|
@@ -1,92 +0,0 @@
|
||||
export interface Box {
|
||||
name: string;
|
||||
wrap: boolean;
|
||||
fill: string;
|
||||
actorKeys: string[];
|
||||
}
|
||||
|
||||
export interface Actor {
|
||||
box?: Box;
|
||||
name: string;
|
||||
description: string;
|
||||
wrap: boolean;
|
||||
prevActor?: string;
|
||||
nextActor?: string;
|
||||
links: Record<string, unknown>;
|
||||
properties: Record<string, unknown>;
|
||||
actorCnt: number | null;
|
||||
rectData: unknown;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface Message {
|
||||
from?: string;
|
||||
to?: string;
|
||||
message:
|
||||
| string
|
||||
| {
|
||||
start: number;
|
||||
step: number;
|
||||
visible: boolean;
|
||||
};
|
||||
wrap: boolean;
|
||||
answer?: unknown;
|
||||
type?: number;
|
||||
activate?: boolean;
|
||||
placement?: string;
|
||||
}
|
||||
|
||||
export interface AddMessageParams {
|
||||
from: string;
|
||||
to: string;
|
||||
msg: string;
|
||||
signalType: number;
|
||||
type:
|
||||
| 'addMessage'
|
||||
| 'sequenceIndex'
|
||||
| 'addParticipant'
|
||||
| 'createParticipant'
|
||||
| 'destroyParticipant'
|
||||
| 'activeStart'
|
||||
| 'activeEnd'
|
||||
| 'addNote'
|
||||
| 'addLinks'
|
||||
| 'addALink'
|
||||
| 'addProperties'
|
||||
| 'addDetails'
|
||||
| 'boxStart'
|
||||
| 'boxEnd'
|
||||
| 'loopStart'
|
||||
| 'loopEnd'
|
||||
| 'rectStart'
|
||||
| 'rectEnd'
|
||||
| 'optStart'
|
||||
| 'optEnd'
|
||||
| 'altStart'
|
||||
| 'else'
|
||||
| 'altEnd'
|
||||
| 'setAccTitle'
|
||||
| 'parStart'
|
||||
| 'parAnd'
|
||||
| 'parEnd'
|
||||
| 'and'
|
||||
| 'criticalStart'
|
||||
| 'criticalOption'
|
||||
| 'option'
|
||||
| 'criticalEnd'
|
||||
| 'breakStart'
|
||||
| 'breakEnd'
|
||||
| 'parOverStart'
|
||||
| 'parOverEnd'
|
||||
| 'parOverAnd'
|
||||
| 'parOverEnd';
|
||||
|
||||
activate: boolean;
|
||||
}
|
||||
|
||||
export interface Note {
|
||||
actor: { actor: string };
|
||||
placement: Message['placement'];
|
||||
message: string;
|
||||
wrap: boolean;
|
||||
}
|
@@ -145,7 +145,7 @@ const getRootDocV2 = () => {
|
||||
* Ex: the section within a fork has its own statements, and incoming and outgoing statements
|
||||
* refer to the fork as a whole (document).
|
||||
* See the parser grammar: the definition of a document is a document then a 'line', where a line can be a statement.
|
||||
* This will push the statement into the list of statements for the current document.
|
||||
* This will push the statement into the the list of statements for the current document.
|
||||
*
|
||||
* @param _doc
|
||||
*/
|
||||
|
@@ -5,7 +5,7 @@ import { render } from '../../dagre-wrapper/index.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||
import common from '../common/common.js';
|
||||
import utils, { getEdgeId } from '../../utils.js';
|
||||
import utils from '../../utils.js';
|
||||
|
||||
import {
|
||||
DEFAULT_DIAGRAM_DIRECTION,
|
||||
@@ -252,6 +252,7 @@ const setupNode = (g, parent, parsedItem, diagramStates, diagramDb, altFlag) =>
|
||||
type: 'group',
|
||||
padding: 0, //getConfig().flowchart.padding
|
||||
};
|
||||
graphItemCount++;
|
||||
|
||||
const parentNodeId = itemId + PARENT_ID;
|
||||
g.setNode(parentNodeId, groupData);
|
||||
@@ -269,23 +270,17 @@ const setupNode = (g, parent, parsedItem, diagramStates, diagramDb, altFlag) =>
|
||||
from = noteData.id;
|
||||
to = itemId;
|
||||
}
|
||||
|
||||
g.setEdge(from, to, {
|
||||
arrowhead: 'none',
|
||||
arrowType: '',
|
||||
style: G_EDGE_STYLE,
|
||||
labelStyle: '',
|
||||
id: getEdgeId(from, to, {
|
||||
counter: graphItemCount,
|
||||
}),
|
||||
classes: CSS_EDGE_NOTE_EDGE,
|
||||
arrowheadStyle: G_EDGE_ARROWHEADSTYLE,
|
||||
labelpos: G_EDGE_LABELPOS,
|
||||
labelType: G_EDGE_LABELTYPE,
|
||||
thickness: G_EDGE_THICKNESS,
|
||||
});
|
||||
|
||||
graphItemCount++;
|
||||
} else {
|
||||
g.setNode(itemId, nodeData);
|
||||
}
|
||||
@@ -329,9 +324,7 @@ const setupDoc = (g, parentParsedItem, doc, diagramStates, diagramDb, altFlag) =
|
||||
setupNode(g, parentParsedItem, item.state1, diagramStates, diagramDb, altFlag);
|
||||
setupNode(g, parentParsedItem, item.state2, diagramStates, diagramDb, altFlag);
|
||||
const edgeData = {
|
||||
id: getEdgeId(item.state1.id, item.state2.id, {
|
||||
counter: graphItemCount,
|
||||
}),
|
||||
id: 'edge' + graphItemCount,
|
||||
arrowhead: 'normal',
|
||||
arrowTypeEnd: 'arrow_barb',
|
||||
style: G_EDGE_STYLE,
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user