Merge branch 'develop' into sidv/tinyMermaid
* develop: (52 commits) docs: Add quadrant point styling feat: Change precedence of styling chore(deps): update all minor dependencies chore(deps): update all patch dependencies fix: eslint ignore, type definition chore(deps): update all patch dependencies fix: Remove `ImperativeState` type restriction. 📝🐛 fix schema link update latest news section Changes to rendering/gitGraph.spec.js - Added additional rendering test functionality for recognizing 'switch' as an alias to 'checkout'. 1. Changes to gitGraph.jison - Updated the regex to allow either 'checkout' or 'switch' 2. Changes to gitGraphParser.spec.js - Additional test coverage added for the changes made to the parser. 3. Changes to gitGraphParserV2.spec.js - Additional test coverafe added for the changes made to the parser. 4. Changes to gitgraph.md - Updated documentation to let users know that checkout/switch can be used interchangeably. revert from and to type to object add eslint rule consistent-type-definations Update createText.ts chore(deps): update all patch dependencies revert lock file simplify message type from and to move types to separate file use interfaces instead of types feat: create utils func + test cases ...
This commit is contained in:
commit
70038e90ce
|
@ -1,11 +0,0 @@
|
|||
dist/**
|
||||
.github/**
|
||||
docs/Setup.md
|
||||
cypress.config.js
|
||||
cypress/plugins/index.js
|
||||
coverage
|
||||
*.json
|
||||
node_modules
|
||||
|
||||
# autogenereated by langium-cli
|
||||
generated/
|
|
@ -0,0 +1 @@
|
|||
.gitignore
|
|
@ -53,6 +53,7 @@ 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',
|
||||
{
|
||||
|
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
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@v2
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ 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@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
|
|
@ -17,4 +17,4 @@ jobs:
|
|||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@v4
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@v3
|
||||
uses: actions/dependency-review-action@v4
|
||||
|
|
|
@ -106,7 +106,7 @@ jobs:
|
|||
# These cached snapshots are downloaded, providing the reference snapshots.
|
||||
- name: Cache snapshots
|
||||
id: cache-snapshot
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
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@v3
|
||||
uses: codecov/codecov-action@v4
|
||||
# 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@v3
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ./snapshots
|
||||
key: ${{ runner.os }}-snapshots-${{ github.event.after }}
|
||||
|
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Restore lychee cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .lycheecache
|
||||
key: cache-lychee-${{ github.sha }}
|
||||
|
|
|
@ -22,7 +22,7 @@ jobs:
|
|||
pull-requests: write # write permission is required to label PRs
|
||||
steps:
|
||||
- name: Label PR
|
||||
uses: release-drafter/release-drafter@v5
|
||||
uses: release-drafter/release-drafter@v6
|
||||
with:
|
||||
config-name: pr-labeler.yml
|
||||
disable-autolabeler: false
|
||||
|
|
|
@ -37,13 +37,13 @@ jobs:
|
|||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v3
|
||||
uses: actions/configure-pages@v4
|
||||
|
||||
- name: Run Build
|
||||
run: pnpm --filter mermaid run docs:build:vitepress
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
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@v2
|
||||
uses: actions/deploy-pages@v4
|
||||
|
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
pull-requests: read # required to read PR titles/labels
|
||||
steps:
|
||||
- name: Draft Release
|
||||
uses: release-drafter/release-drafter@v5
|
||||
uses: release-drafter/release-drafter@v6
|
||||
with:
|
||||
disable-autolabeler: true
|
||||
env:
|
||||
|
|
|
@ -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@v3
|
||||
uses: codecov/codecov-action@v4
|
||||
# Run step only pushes to develop and pull_requests
|
||||
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/develop' }}
|
||||
with:
|
||||
|
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
message: 'chore: update browsers list'
|
||||
push: false
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
branch: update-browserslist
|
||||
title: Update Browserslist
|
||||
|
|
|
@ -1 +1 @@
|
|||
v20.11.1
|
||||
20.12.2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
FROM node:20.11.1-alpine3.19 AS base
|
||||
FROM node:20.12.2-alpine3.19 AS base
|
||||
RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -
|
||||
|
|
|
@ -1458,5 +1458,79 @@ 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, renderGraph } from '../../helpers/util.ts';
|
||||
import { imgSnapshotTest } from '../../helpers/util.ts';
|
||||
|
||||
describe('Quadrant Chart', () => {
|
||||
it('should render if only chart type is provided', () => {
|
||||
|
@ -226,4 +226,52 @@ 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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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/4.7.0/css/font-awesome.min.css"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/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:12.17.4
|
||||
image: cypress/included:13.7.3
|
||||
stdin_open: true
|
||||
tty: true
|
||||
working_dir: /mermaid
|
||||
|
|
|
@ -28,13 +28,23 @@ Thank you for being part of our story. Here's to creating, innovating, and colla
|
|||
|
||||
Knut Sveidqvist 🧜♂️✨
|
||||
|
||||
## Mermaid Chart's Visual Editor for Flowcharts
|
||||
## Mermaid Chart's Visual Editor for Flowcharts and Sequence diagrams
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
Learn more:
|
||||
|
||||
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.
|
||||
- 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)
|
||||
|
||||
## 📖 Blog posts
|
||||
|
||||
|
|
|
@ -6,6 +6,18 @@
|
|||
|
||||
# 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.
|
||||
> 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).
|
||||
|
||||
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,6 +1178,36 @@ 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,6 +56,8 @@ 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,3 +168,86 @@ 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
|
||||
```
|
||||
|
|
|
@ -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.4",
|
||||
"packageManager": "pnpm@8.15.7",
|
||||
"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 --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": "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:jison": "tsx ./scripts/jison/lint.mts",
|
||||
"contributors": "tsx scripts/updateContributors.ts",
|
||||
"cypress": "cypress run",
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^6.0.4",
|
||||
"@braintree/sanitize-url": "^7.0.0",
|
||||
"d3": "^7.9.0",
|
||||
"khroma": "^2.1.0"
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "mermaid",
|
||||
"version": "11.0.0-alpha.6",
|
||||
"version": "11.0.0-alpha.7",
|
||||
"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": "^7.1.5",
|
||||
"@adobe/jsonschema2md": "^8.0.0",
|
||||
"@types/cytoscape": "^3.19.16",
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/d3-sankey": "^0.12.4",
|
||||
|
|
|
@ -3,6 +3,7 @@ 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
|
||||
|
@ -59,10 +60,7 @@ const createLabel = (_vertexText, style, isTitle, isNode) => {
|
|||
log.debug('vertexText' + vertexText);
|
||||
const node = {
|
||||
isNode,
|
||||
label: decodeEntities(vertexText).replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell: disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
label: replaceIconSubstring(decodeEntities(vertexText)),
|
||||
labelStyle: style.replace('fill:', 'color:'),
|
||||
};
|
||||
let vertexNode = addHtmlLabel(node);
|
||||
|
|
|
@ -138,7 +138,7 @@ export interface ClassNote {
|
|||
text: string;
|
||||
}
|
||||
|
||||
export type ClassRelation = {
|
||||
export interface ClassRelation {
|
||||
id1: string;
|
||||
id2: string;
|
||||
relationTitle1: string;
|
||||
|
@ -152,7 +152,7 @@ export type ClassRelation = {
|
|||
type2: number;
|
||||
lineType: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface NamespaceNode {
|
||||
id: string;
|
||||
|
|
|
@ -9,6 +9,7 @@ import common, { evaluate, renderKatex } from '../common/common.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) {
|
||||
|
@ -56,14 +57,9 @@ 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(
|
||||
vertexText.replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell:disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
getConfig()
|
||||
),
|
||||
label: await renderKatex(replacedVertexText, getConfig()),
|
||||
};
|
||||
vertexNode = addHtmlLabel(svg, node).node();
|
||||
vertexNode.parentNode.removeChild(vertexNode);
|
||||
|
@ -242,13 +238,7 @@ 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(
|
||||
edge.text.replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell:disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
getConfig()
|
||||
)}</span>`;
|
||||
}">${await renderKatex(replaceIconSubstring(edge.text), getConfig())}</span>`;
|
||||
} else {
|
||||
edgeData.labelType = 'text';
|
||||
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
|
||||
|
|
|
@ -88,6 +88,16 @@ 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,6 +520,78 @@ 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';
|
||||
checkout(?=\s|$) return 'CHECKOUT';
|
||||
\b(checkout|switch)(?=\s|$) return 'CHECKOUT';
|
||||
"LR" return 'DIR';
|
||||
"TB" return 'DIR';
|
||||
"BT" return 'DIR';
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
%x point_start
|
||||
%x point_x
|
||||
%x point_y
|
||||
%x class_name
|
||||
%%
|
||||
\%\%(?!\{)[^\n]* /* skip comments */
|
||||
[^\}]\%\%[^\n]* /* skip comments */
|
||||
|
@ -35,6 +36,7 @@ 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";}
|
||||
|
@ -43,6 +45,9 @@ 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();}
|
||||
|
@ -75,6 +80,31 @@ 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
|
||||
|
@ -92,6 +122,7 @@ line
|
|||
|
||||
statement
|
||||
:
|
||||
| classDefStatement {$$=[];}
|
||||
| SPACE statement
|
||||
| axisDetails
|
||||
| quadrantDetails
|
||||
|
@ -103,7 +134,10 @@ statement
|
|||
;
|
||||
|
||||
points
|
||||
: text point_start point_x point_y {yy.addPoint($1, $3, $4);}
|
||||
: 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);}
|
||||
;
|
||||
|
||||
axisDetails
|
||||
|
|
|
@ -212,20 +212,34 @@ 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();
|
||||
|
@ -264,15 +278,149 @@ 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'
|
||||
'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']
|
||||
);
|
||||
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,7 +10,15 @@ const defaultThemeVariables = getThemeVariables();
|
|||
export type TextVerticalPos = 'left' | 'center' | 'right';
|
||||
export type TextHorizontalPos = 'top' | 'middle' | 'bottom';
|
||||
|
||||
export interface QuadrantPointInputType extends Point {
|
||||
export interface StylesObject {
|
||||
className?: string;
|
||||
radius?: number;
|
||||
color?: string;
|
||||
strokeColor?: string;
|
||||
strokeWidth?: string;
|
||||
}
|
||||
|
||||
export interface QuadrantPointInputType extends Point, StylesObject {
|
||||
text: string;
|
||||
}
|
||||
|
||||
|
@ -23,7 +31,9 @@ export interface QuadrantTextType extends Point {
|
|||
rotation: number;
|
||||
}
|
||||
|
||||
export interface QuadrantPointType extends Point {
|
||||
export interface QuadrantPointType
|
||||
extends Point,
|
||||
Pick<StylesObject, 'strokeColor' | 'strokeWidth'> {
|
||||
fill: string;
|
||||
radius: number;
|
||||
text: QuadrantTextType;
|
||||
|
@ -117,6 +127,7 @@ export class QuadrantBuilder {
|
|||
private config: QuadrantBuilderConfig;
|
||||
private themeConfig: QuadrantBuilderThemeConfig;
|
||||
private data: QuadrantBuilderData;
|
||||
private classes: Record<string, StylesObject> = {};
|
||||
|
||||
constructor() {
|
||||
this.config = this.getDefaultConfig();
|
||||
|
@ -191,6 +202,7 @@ export class QuadrantBuilder {
|
|||
this.config = this.getDefaultConfig();
|
||||
this.themeConfig = this.getDefaultThemeConfig();
|
||||
this.data = this.getDefaultData();
|
||||
this.classes = {};
|
||||
log.info('clear called');
|
||||
}
|
||||
|
||||
|
@ -202,6 +214,10 @@ 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 };
|
||||
|
@ -470,11 +486,15 @@ 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: this.themeConfig.quadrantPointFill,
|
||||
radius: this.config.pointRadius,
|
||||
fill: point.color || this.themeConfig.quadrantPointFill,
|
||||
radius: point.radius || this.config.pointRadius,
|
||||
text: {
|
||||
text: point.text,
|
||||
fill: this.themeConfig.quadrantPointTextFill,
|
||||
|
@ -485,6 +505,8 @@ export class QuadrantBuilder {
|
|||
fontSize: this.config.pointLabelFontSize,
|
||||
rotation: 0,
|
||||
},
|
||||
strokeColor: point.strokeColor || this.themeConfig.quadrantPointFill,
|
||||
strokeWidth: point.strokeWidth || '0px',
|
||||
};
|
||||
return props;
|
||||
});
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
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,7 +9,14 @@ 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();
|
||||
|
||||
|
@ -17,7 +24,10 @@ function textSanitizer(text: string) {
|
|||
return sanitizeText(text.trim(), config);
|
||||
}
|
||||
|
||||
type LexTextObj = { text: string; type: 'text' | 'markdown' };
|
||||
interface LexTextObj {
|
||||
text: string;
|
||||
type: 'text' | 'markdown';
|
||||
}
|
||||
|
||||
const quadrantBuilder = new QuadrantBuilder();
|
||||
|
||||
|
@ -53,8 +63,52 @@ function setYAxisBottomText(textObj: LexTextObj) {
|
|||
quadrantBuilder.setData({ yAxisBottomText: textSanitizer(textObj.text) });
|
||||
}
|
||||
|
||||
function addPoint(textObj: LexTextObj, x: number, y: number) {
|
||||
quadrantBuilder.addPoints([{ x, y, text: 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 setWidth(width: number) {
|
||||
|
@ -108,7 +162,9 @@ export default {
|
|||
setXAxisRightText,
|
||||
setYAxisTopText,
|
||||
setYAxisBottomText,
|
||||
parseStyles,
|
||||
addPoint,
|
||||
addClass,
|
||||
getQuadrantData,
|
||||
clear,
|
||||
setAccTitle,
|
||||
|
|
|
@ -152,7 +152,9 @@ 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('fill', (data: QuadrantPointType) => data.fill)
|
||||
.attr('stroke', (data: QuadrantPointType) => data.strokeColor)
|
||||
.attr('stroke-width', (data: QuadrantPointType) => data.strokeWidth);
|
||||
|
||||
dataPoints
|
||||
.append('text')
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
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 };
|
|
@ -1,5 +1,6 @@
|
|||
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,
|
||||
|
@ -10,9 +11,24 @@ import {
|
|||
setAccTitle,
|
||||
setDiagramTitle,
|
||||
} from '../common/commonDb.js';
|
||||
import { ImperativeState } from '../../utils/imperativeState.js';
|
||||
import type { Actor, AddMessageParams, Box, Message, Note } from './types.js';
|
||||
|
||||
const state = new ImperativeState(() => ({
|
||||
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>(() => ({
|
||||
prevActor: undefined,
|
||||
actors: {},
|
||||
createdActors: {},
|
||||
|
@ -27,7 +43,7 @@ const state = new ImperativeState(() => ({
|
|||
lastDestroyed: undefined,
|
||||
}));
|
||||
|
||||
export const addBox = function (data) {
|
||||
export const addBox = function (data: { text: string; color: string; wrap: boolean }) {
|
||||
state.records.boxes.push({
|
||||
name: data.text,
|
||||
wrap: (data.wrap === undefined && autoWrap()) || !!data.wrap,
|
||||
|
@ -37,20 +53,19 @@ export const addBox = function (data) {
|
|||
state.records.currentBox = state.records.boxes.slice(-1)[0];
|
||||
};
|
||||
|
||||
export const addActor = function (id, name, description, type) {
|
||||
export const addActor = function (
|
||||
id: string,
|
||||
name: string,
|
||||
description: { text: string; wrap?: boolean | null; type: string },
|
||||
type: string
|
||||
) {
|
||||
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.`
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -82,7 +97,7 @@ export const addActor = function (id, name, description, type) {
|
|||
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;
|
||||
|
@ -94,19 +109,23 @@ export const addActor = function (id, name, description, type) {
|
|||
state.records.prevActor = id;
|
||||
};
|
||||
|
||||
const activationCount = (part) => {
|
||||
const activationCount = (part: string) => {
|
||||
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.actor === part
|
||||
state.records.messages[i].from?.actor === part
|
||||
) {
|
||||
count++;
|
||||
}
|
||||
if (
|
||||
state.records.messages[i].type === LINETYPE.ACTIVE_END &&
|
||||
state.records.messages[i].from.actor === part
|
||||
state.records.messages[i].from?.actor === part
|
||||
) {
|
||||
count--;
|
||||
}
|
||||
|
@ -114,7 +133,12 @@ const activationCount = (part) => {
|
|||
return count;
|
||||
};
|
||||
|
||||
export const addMessage = function (idFrom, idTo, message, answer) {
|
||||
export const addMessage = function (
|
||||
idFrom: Message['from'],
|
||||
idTo: Message['to'],
|
||||
message: { text: string; wrap?: boolean },
|
||||
answer: Message['answer']
|
||||
) {
|
||||
state.records.messages.push({
|
||||
from: idFrom,
|
||||
to: idTo,
|
||||
|
@ -125,17 +149,21 @@ export const addMessage = function (idFrom, idTo, message, answer) {
|
|||
};
|
||||
|
||||
export const addSignal = function (
|
||||
idFrom,
|
||||
idTo,
|
||||
message = { text: undefined, wrap: undefined },
|
||||
messageType,
|
||||
activate = false
|
||||
idFrom?: Message['from'],
|
||||
idTo?: Message['to'],
|
||||
message?: { text: string; wrap: boolean },
|
||||
messageType?: number,
|
||||
activate: boolean = false
|
||||
) {
|
||||
if (messageType === LINETYPE.ACTIVE_END) {
|
||||
const cnt = activationCount(idFrom.actor);
|
||||
const cnt = activationCount(idFrom?.actor || '');
|
||||
if (cnt < 1) {
|
||||
// Bail out as there is an activation signal from an inactive participant
|
||||
let error = new Error('Trying to inactivate an inactive participant (' + idFrom.actor + ')');
|
||||
const error = new Error(
|
||||
'Trying to inactivate an inactive participant (' + idFrom?.actor + ')'
|
||||
);
|
||||
|
||||
// @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
|
||||
error.hash = {
|
||||
text: '->>-',
|
||||
token: '->>-',
|
||||
|
@ -149,8 +177,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,
|
||||
});
|
||||
|
@ -181,7 +209,7 @@ export const getCreatedActors = function () {
|
|||
export const getDestroyedActors = function () {
|
||||
return state.records.destroyedActors;
|
||||
};
|
||||
export const getActor = function (id) {
|
||||
export const getActor = function (id: string) {
|
||||
return state.records.actors[id];
|
||||
};
|
||||
export const getActorKeys = function () {
|
||||
|
@ -195,7 +223,7 @@ export const disableSequenceNumbers = function () {
|
|||
};
|
||||
export const showSequenceNumbers = () => state.records.sequenceNumbersEnabled;
|
||||
|
||||
export const setWrap = function (wrapSetting) {
|
||||
export const setWrap = function (wrapSetting?: boolean) {
|
||||
state.records.wrapEnabled = wrapSetting;
|
||||
};
|
||||
|
||||
|
@ -205,7 +233,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 () {
|
||||
|
@ -213,25 +241,25 @@ export const clear = function () {
|
|||
commonClear();
|
||||
};
|
||||
|
||||
export const parseMessage = function (str) {
|
||||
const _str = str.trim();
|
||||
export const parseMessage = function (str: string) {
|
||||
const trimmedStr = str.trim();
|
||||
const message = {
|
||||
text: _str.replace(/^:?(?:no)?wrap:/, '').trim(),
|
||||
text: trimmedStr.replace(/^:?(?:no)?wrap:/, '').trim(),
|
||||
wrap:
|
||||
_str.match(/^:?wrap:/) !== null
|
||||
trimmedStr.match(/^:?wrap:/) !== null
|
||||
? true
|
||||
: _str.match(/^:?nowrap:/) !== null
|
||||
: trimmedStr.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) {
|
||||
export const parseBoxData = function (str: string) {
|
||||
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;
|
||||
|
@ -312,18 +340,21 @@ export const PLACEMENT = {
|
|||
OVER: 2,
|
||||
};
|
||||
|
||||
export const addNote = function (actor, placement, message) {
|
||||
const note = {
|
||||
export const addNote = function (
|
||||
actor: { actor: string },
|
||||
placement: Message['placement'],
|
||||
message: { text: string; wrap?: boolean }
|
||||
) {
|
||||
const note: Note = {
|
||||
actor: actor,
|
||||
placement: placement,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
|
||||
};
|
||||
|
||||
// Coerce actor into a [to, from, ...] array
|
||||
//@ts-ignore: 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],
|
||||
|
@ -335,7 +366,7 @@ export const addNote = function (actor, placement, message) {
|
|||
});
|
||||
};
|
||||
|
||||
export const addLinks = function (actorId, text) {
|
||||
export const addLinks = function (actorId: string, text: { text: string }) {
|
||||
// find the actor
|
||||
const actor = getActor(actorId);
|
||||
// JSON.parse the text
|
||||
|
@ -351,17 +382,17 @@ export const addLinks = function (actorId, text) {
|
|||
}
|
||||
};
|
||||
|
||||
export const addALink = function (actorId, text) {
|
||||
export const addALink = function (actorId: string, text: { text: string }) {
|
||||
// find the actor
|
||||
const actor = getActor(actorId);
|
||||
try {
|
||||
const links = {};
|
||||
const links: Record<string, string> = {};
|
||||
let sanitizedText = sanitizeText(text.text, getConfig());
|
||||
var sep = sanitizedText.indexOf('@');
|
||||
const sep = sanitizedText.indexOf('@');
|
||||
sanitizedText = sanitizedText.replace(/&/g, '&');
|
||||
sanitizedText = sanitizedText.replace(/=/g, '=');
|
||||
var label = sanitizedText.slice(0, sep - 1).trim();
|
||||
var link = sanitizedText.slice(sep + 1).trim();
|
||||
const label = sanitizedText.slice(0, sep - 1).trim();
|
||||
const link = sanitizedText.slice(sep + 1).trim();
|
||||
|
||||
links[label] = link;
|
||||
// add the deserialized text to the actor's links field.
|
||||
|
@ -372,26 +403,26 @@ export const addALink = function (actorId, text) {
|
|||
};
|
||||
|
||||
/**
|
||||
* @param {any} actor
|
||||
* @param {any} links
|
||||
* @param actor - the actor to add the links to
|
||||
* @param links - the links to add to the actor
|
||||
*/
|
||||
function insertLinks(actor, links) {
|
||||
function insertLinks(actor: Actor, links: Record<string, string>) {
|
||||
if (actor.links == null) {
|
||||
actor.links = links;
|
||||
} else {
|
||||
for (let key in links) {
|
||||
for (const key in links) {
|
||||
actor.links[key] = links[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const addProperties = function (actorId, text) {
|
||||
export const addProperties = function (actorId: string, text: { text: string }) {
|
||||
// find the actor
|
||||
const actor = getActor(actorId);
|
||||
// JSON.parse the text
|
||||
try {
|
||||
let sanitizedText = sanitizeText(text.text, getConfig());
|
||||
const properties = JSON.parse(sanitizedText);
|
||||
const sanitizedText = sanitizeText(text.text, getConfig());
|
||||
const properties: Record<string, unknown> = JSON.parse(sanitizedText);
|
||||
// add the deserialized text to the actor's property field.
|
||||
insertProperties(actor, properties);
|
||||
} catch (e) {
|
||||
|
@ -400,30 +431,27 @@ export const addProperties = function (actorId, text) {
|
|||
};
|
||||
|
||||
/**
|
||||
* @param {any} actor
|
||||
* @param {any} properties
|
||||
* @param actor - the actor to add the properties to
|
||||
* @param properties - the properties to add to the actor's properties
|
||||
*/
|
||||
function insertProperties(actor, properties) {
|
||||
function insertProperties(actor: Actor, properties: Record<string, unknown>) {
|
||||
if (actor.properties == null) {
|
||||
actor.properties = properties;
|
||||
} else {
|
||||
for (let key in properties) {
|
||||
for (const key in properties) {
|
||||
actor.properties[key] = properties[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function boxEnd() {
|
||||
state.records.currentBox = undefined;
|
||||
}
|
||||
|
||||
export const addDetails = function (actorId, text) {
|
||||
export const addDetails = function (actorId: string, text: { text: string }) {
|
||||
// find the actor
|
||||
const actor = getActor(actorId);
|
||||
const elem = document.getElementById(text.text);
|
||||
const elem = document.getElementById(text.text)!;
|
||||
|
||||
// JSON.parse the text
|
||||
try {
|
||||
|
@ -442,7 +470,7 @@ export const addDetails = function (actorId, text) {
|
|||
}
|
||||
};
|
||||
|
||||
export const getActorProperty = function (actor, key) {
|
||||
export const getActorProperty = function (actor: Actor, key: string) {
|
||||
if (actor !== undefined && actor.properties !== undefined) {
|
||||
return actor.properties[key];
|
||||
}
|
||||
|
@ -450,20 +478,7 @@ export const getActorProperty = function (actor, key) {
|
|||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
export const apply = function (param: any | AddMessageParams | AddMessageParams[]) {
|
||||
if (Array.isArray(param)) {
|
||||
param.forEach(function (item) {
|
||||
apply(item);
|
|
@ -1,6 +1,5 @@
|
|||
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';
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
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?: { actor: string };
|
||||
to?: { actor: 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;
|
||||
}
|
|
@ -26,13 +26,23 @@ Thank you for being part of our story. Here's to creating, innovating, and colla
|
|||
|
||||
Knut Sveidqvist 🧜♂️✨
|
||||
|
||||
## Mermaid Chart's Visual Editor for Flowcharts
|
||||
## Mermaid Chart's Visual Editor for Flowcharts and Sequence diagrams
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
Learn more:
|
||||
|
||||
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.
|
||||
- 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)
|
||||
|
||||
## 📖 Blog posts
|
||||
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
# 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
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"fetch-contributors": "tsx .vitepress/scripts/fetch-contributors.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdi/font": "^6.9.96",
|
||||
"@mdi/font": "^7.0.0",
|
||||
"@vueuse/core": "^10.9.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"jiti": "^1.21.0",
|
||||
|
@ -24,17 +24,17 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/carbon": "^1.1.31",
|
||||
"@unocss/reset": "^0.58.6",
|
||||
"@unocss/reset": "^0.59.0",
|
||||
"@vite-pwa/vitepress": "^0.4.0",
|
||||
"@vitejs/plugin-vue": "^4.6.2",
|
||||
"@vitejs/plugin-vue": "^5.0.0",
|
||||
"fast-glob": "^3.3.2",
|
||||
"https-localhost": "^4.7.1",
|
||||
"pathe": "^1.1.2",
|
||||
"unocss": "^0.58.6",
|
||||
"unocss": "^0.59.0",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"vite": "^4.5.2",
|
||||
"vite": "^5.0.0",
|
||||
"vite-plugin-pwa": "^0.19.7",
|
||||
"vitepress": "1.0.0-rc.45",
|
||||
"vitepress": "1.1.0",
|
||||
"workbox-window": "^7.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 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.
|
||||
> 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).
|
||||
|
||||
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.
|
||||
|
||||
|
@ -75,7 +75,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
|
||||
|
||||
|
@ -162,7 +162,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
|
||||
|
|
|
@ -799,6 +799,30 @@ 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"]
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
|
|
@ -33,6 +33,8 @@ 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.
|
||||
|
|
|
@ -136,3 +136,66 @@ 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
|
||||
```
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { replaceIconSubstring } from './createText.js';
|
||||
|
||||
describe('replaceIconSubstring', () => {
|
||||
it('converts FontAwesome icon notations to HTML tags', () => {
|
||||
const input = 'This is an icon: fa:fa-user and fab:fa-github';
|
||||
const output = replaceIconSubstring(input);
|
||||
const expected =
|
||||
"This is an icon: <i class='fa fa-user'></i> and <i class='fab fa-github'></i>";
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
|
||||
it('handles strings without FontAwesome icon notations', () => {
|
||||
const input = 'This string has no icons';
|
||||
const output = replaceIconSubstring(input);
|
||||
expect(output).toEqual(input); // No change expected
|
||||
});
|
||||
|
||||
it('correctly processes multiple FontAwesome icon notations in one string', () => {
|
||||
const input = 'Icons galore: fa:fa-arrow-right, fak:fa-truck, fas:fa-home';
|
||||
const output = replaceIconSubstring(input);
|
||||
const expected =
|
||||
"Icons galore: <i class='fa fa-arrow-right'></i>, <i class='fak fa-truck'></i>, <i class='fas fa-home'></i>";
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
|
||||
it('correctly replaces a very long icon name with the fak prefix', () => {
|
||||
const input = 'Here is a long icon: fak:fa-truck-driving-long-winding-road in use';
|
||||
const output = replaceIconSubstring(input);
|
||||
const expected =
|
||||
"Here is a long icon: <i class='fak fa-truck-driving-long-winding-road'></i> in use";
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
});
|
|
@ -168,6 +168,19 @@ function updateTextContentAndStyles(tspan: any, wrappedLine: MarkdownWord[]) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert fontawesome labels into fontawesome icons by using a regex pattern
|
||||
* @param text - The raw string to convert
|
||||
* @returns string with fontawesome icons as i tags
|
||||
*/
|
||||
export function replaceIconSubstring(text: string) {
|
||||
// The letters 'bklrs' stand for possible endings of the fontawesome prefix (e.g. 'fab' for brands, 'fak' for fa-kit) // cspell: disable-line
|
||||
return text.replace(
|
||||
/fa[bklrs]?:fa-[\w-]+/g, // cspell: disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
);
|
||||
}
|
||||
|
||||
// Note when using from flowcharts converting the API isNode means classes should be set accordingly. When using htmlLabels => to sett classes to'nodeLabel' when isNode=true otherwise 'edgeLabel'
|
||||
// When not using htmlLabels => to set classes to 'title-row' when isTitle=true otherwise 'title-row'
|
||||
export const createText = (
|
||||
|
@ -189,12 +202,10 @@ export const createText = (
|
|||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
|
||||
const htmlText = markdownToHTML(text, config);
|
||||
const decodedReplacedText = replaceIconSubstring(decodeEntities(htmlText));
|
||||
const node = {
|
||||
isNode,
|
||||
label: decodeEntities(htmlText).replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell: disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
label: decodedReplacedText,
|
||||
labelStyle: style.replace('fill:', 'color:'),
|
||||
};
|
||||
const vertexNode = addHtmlSpan(el, node, width, classes, addSvgBackground);
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
# you may need to add it to `.build/jsonSchema.ts`, `src/docs.mts`
|
||||
# and `scripts/create-types-from-json-schema.mjs`
|
||||
# to get the default values/docs/types to generate properly.
|
||||
$id: https://mermaid-js.github.io/schemas/config.schema.json
|
||||
$id: https://mermaid.js.org/schemas/config.schema.json
|
||||
$schema: https://json-schema.org/draft/2019-09/schema
|
||||
title: Mermaid Config
|
||||
type: object
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
* Resettable state storage.
|
||||
* @example
|
||||
* ```
|
||||
* const state = new ImperativeState(() => {
|
||||
* const state = new ImperativeState(() => ({
|
||||
* foo: undefined as string | undefined,
|
||||
* bar: [] as number[],
|
||||
* baz: 1 as number | undefined,
|
||||
* });
|
||||
* }));
|
||||
*
|
||||
* state.records.foo = "hi";
|
||||
* console.log(state.records.foo); // prints "hi";
|
||||
|
@ -21,7 +21,7 @@
|
|||
* // }
|
||||
* ```
|
||||
*/
|
||||
export class ImperativeState<S extends Record<string, unknown>> {
|
||||
export class ImperativeState<S> {
|
||||
public records: S;
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,12 +19,12 @@ import { InfoTokenBuilder } from './tokenBuilder.js';
|
|||
/**
|
||||
* Declaration of `Info` services.
|
||||
*/
|
||||
type InfoAddedServices = {
|
||||
interface InfoAddedServices {
|
||||
parser: {
|
||||
TokenBuilder: InfoTokenBuilder;
|
||||
ValueConverter: CommonValueConverter;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Union of Langium default services and `Info` services.
|
||||
|
|
|
@ -19,12 +19,12 @@ import { PacketTokenBuilder } from './tokenBuilder.js';
|
|||
/**
|
||||
* Declaration of `Packet` services.
|
||||
*/
|
||||
type PacketAddedServices = {
|
||||
interface PacketAddedServices {
|
||||
parser: {
|
||||
TokenBuilder: PacketTokenBuilder;
|
||||
ValueConverter: CommonValueConverter;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Union of Langium default services and `Packet` services.
|
||||
|
|
|
@ -19,12 +19,12 @@ import { PieValueConverter } from './valueConverter.js';
|
|||
/**
|
||||
* Declaration of `Pie` services.
|
||||
*/
|
||||
type PieAddedServices = {
|
||||
interface PieAddedServices {
|
||||
parser: {
|
||||
TokenBuilder: PieTokenBuilder;
|
||||
ValueConverter: PieValueConverter;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Union of Langium default services and `Pie` services.
|
||||
|
|
4000
pnpm-lock.yaml
4000
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue