Merge branch 'develop' into fixElkTests

This commit is contained in:
Sidharth Vinod 2023-09-06 17:28:28 +00:00 committed by GitHub
commit 212b368ffd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
491 changed files with 33655 additions and 17028 deletions

View File

@ -5,3 +5,4 @@ cypress.config.js
cypress/plugins/index.js cypress/plugins/index.js
coverage coverage
*.json *.json
node_modules

View File

@ -38,12 +38,17 @@ module.exports = {
'lodash', 'lodash',
'unicorn', 'unicorn',
], ],
ignorePatterns: [
// this file is automatically generated by `pnpm run --filter mermaid types:build-config`
'packages/mermaid/src/config.type.ts',
],
rules: { rules: {
curly: 'error', curly: 'error',
'no-console': 'error', 'no-console': 'error',
'no-prototype-builtins': 'off', 'no-prototype-builtins': 'off',
'no-unused-vars': 'off', 'no-unused-vars': 'off',
'cypress/no-async-tests': 'off', 'cypress/no-async-tests': 'off',
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': 'error', '@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/ban-ts-comment': [ '@typescript-eslint/ban-ts-comment': [
@ -123,6 +128,14 @@ module.exports = {
files: ['*.{ts,tsx}'], files: ['*.{ts,tsx}'],
plugins: ['tsdoc'], plugins: ['tsdoc'],
rules: { rules: {
'no-restricted-syntax': [
'error',
{
selector: 'TSEnumDeclaration',
message:
'Prefer using TypeScript union types over TypeScript enum, since TypeScript enums have a bunch of issues, see https://dev.to/dvddpl/whats-the-problem-with-typescript-enums-2okj',
},
],
'tsdoc/syntax': 'error', 'tsdoc/syntax': 'error',
}, },
}, },

View File

@ -50,19 +50,20 @@ body:
attributes: attributes:
label: Setup label: Setup
description: |- description: |-
Please fill out the below info. Please fill out the info below.
Note that you only need to fill out one and not both sections. Note that you only need to fill out the relevant section
value: |- value: |-
**Desktop** - Mermaid version:
- OS and Version: [Windows, Linux, Mac, ...]
- Browser and Version: [Chrome, Edge, Firefox] - Browser and Version: [Chrome, Edge, Firefox]
- type: textarea
**Smartphone** attributes:
label: Suggested Solutions
- Device: [Samsung, iPhone, ...] description: >
- OS and Version: [Android, iOS, ...] If applicable, suggest solutions that could resolve the bug.
- Browser and Version: [Chrome, Safari, ...] It would help maintainers/contributors to not waste time looking for the solution. Even pointing the line causing the bug would be great!
placeholder: |-
- Variable `parser` in file <filepath> is not initialised ...
- Add a new type for ...
- type: textarea - type: textarea
attributes: attributes:
label: Additional Context label: Additional Context

View File

@ -1,4 +1,4 @@
blank_issues_enabled: false blank_issues_enabled: true
contact_links: contact_links:
- name: GitHub Discussions - name: GitHub Discussions
url: https://github.com/mermaid-js/mermaid/discussions url: https://github.com/mermaid-js/mermaid/discussions

View File

@ -3,6 +3,7 @@ description: Suggest a new Diagram Type to add to Mermaid.
labels: labels:
- 'Status: Triage' - 'Status: Triage'
- 'Type: Enhancement' - 'Type: Enhancement'
- 'Type: New Diagram'
body: body:
- type: markdown - type: markdown
@ -17,6 +18,14 @@ body:
- Use a clear and concise title - Use a clear and concise title
- Fill out the text fields with as much detail as possible. - Fill out the text fields with as much detail as possible.
- Never be shy to give us screenshots and/or code samples. It will help! - Never be shy to give us screenshots and/or code samples. It will help!
## Example issues
Refer to the discussions here to get an idea of how the diagram syntax is created.
- https://github.com/mermaid-js/mermaid/issues/4269
- https://github.com/mermaid-js/mermaid/issues/4282
- type: textarea - type: textarea
attributes: attributes:
label: Proposal label: Proposal
@ -35,8 +44,17 @@ body:
description: If applicable, add screenshots to show possible examples of how the diagram may look like. description: If applicable, add screenshots to show possible examples of how the diagram may look like.
- type: textarea - type: textarea
attributes: attributes:
label: Code Sample label: Syntax
description: |- description: |-
If applicable, add a code sample for how to implement this new diagram. If possible, include a syntax which could be used to write the diagram.
The text will automatically be rendered as JavaScript code. Try to add one or two examples of valid use-cases here.
render: javascript - type: dropdown
id: implementation
attributes:
label: Implementation
description: |-
Would you like to implement this yourself, or is it a proposal for the community?
If there is no corresponding PR from your side after 30 days, the diagram will be open for everyone to implement.
options:
- I will try and implement it myself.
- This is a proposal which I'd love to see built into mermaid by the wonderful community.

17
.github/codecov.yaml vendored Normal file
View File

@ -0,0 +1,17 @@
codecov:
branch: develop
comment:
layout: 'reach, diff, flags, files'
behavior: default
require_changes: false # if true: only post the comment if coverage changes
require_base: no # [yes :: must have a base report to post]
require_head: yes # [yes :: must have a head report to post]
coverage:
status:
project:
off
# Turing off for now as code coverage isn't stable and causes unnecessary build failures.
# default:
# threshold: 2%

44
.github/lychee.toml vendored Normal file
View File

@ -0,0 +1,44 @@
############################# Display #############################
# Verbose program output
# Accepts log level: "error", "warn", "info", "debug", "trace"
verbose = "debug"
# Don't show interactive progress bar while checking links.
no_progress = true
############################# Cache ###############################
# Enable link caching. This can be helpful to avoid checking the same links on
# multiple runs.
cache = true
# Discard all cached requests older than this duration.
max_cache_age = "1d"
############################# Requests ############################
# Comma-separated list of accepted status codes for valid links.
accept = [200, 429]
############################# Exclusions ##########################
# Exclude URLs and mail addresses from checking (supports regex).
exclude = [
# Network error: Forbidden
"https://codepen.io",
# Timeout error, maybe Twitter has anti-bot defenses against GitHub's CI servers?
"https://twitter.com/mermaidjs_",
# Don't check files that are generated during the build via `pnpm docs:code`
'packages/mermaid/src/docs/config/setup/*',
# Ignore slack invite
"https://join.slack.com/"
]
# Exclude all private IPs from checking.
# Equivalent to setting `exclude_private`, `exclude_link_local`, and
# `exclude_loopback` to true.
exclude_all_private = true

View File

@ -1,3 +1,4 @@
'Type: Bug / Error': 'bug/*' 'Type: Bug / Error': ['bug/*', fix/*]
'Type: Enhancement': 'feature/*' 'Type: Enhancement': ['feature/*', 'feat/*']
'Type: Other': 'other/*' 'Type: Other': ['other/*', 'chore/*', 'test/*', 'refactor/*']
'Area: Documentation': ['docs/*']

View File

@ -13,6 +13,6 @@ Describe the way your implementation works or what design decisions you made if
Make sure you Make sure you
- [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md) - [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md)
- [ ] :computer: have added unit/e2e tests (if appropriate) - [ ] :computer: have added necessary unit/e2e tests.
- [ ] :notebook: have added documentation (if appropriate) - [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/docs/community/development.md#3-update-documentation) is used for all new features.
- [ ] :bookmark: targeted `develop` branch - [ ] :bookmark: targeted `develop` branch

View File

@ -1,14 +1,27 @@
name-template: '$NEXT_PATCH_VERSION' name-template: '$NEXT_PATCH_VERSION'
tag-template: '$NEXT_PATCH_VERSION' tag-template: '$NEXT_PATCH_VERSION'
categories: categories:
- title: '🚨 **Breaking Changes**'
labels:
- 'Breaking Change'
- title: '🚀 Features' - title: '🚀 Features'
labels: labels:
- 'Type: Enhancement' - 'Type: Enhancement'
- 'feature' # deprecated, new PRs shouldn't have this
- title: '🐛 Bug Fixes' - title: '🐛 Bug Fixes'
labels: labels:
- 'Type: Bug / Error' - 'Type: Bug / Error'
- 'fix' # deprecated, new PRs shouldn't have this
- title: '🧰 Maintenance' - title: '🧰 Maintenance'
label: 'Type: Other' labels:
- 'Type: Other'
- 'chore' # deprecated, new PRs shouldn't have this
- title: '⚡️ Performance'
labels:
- 'Type: Performance'
- title: '📚 Documentation'
labels:
- 'Area: Documentation'
change-template: '- $TITLE (#$NUMBER) @$AUTHOR' change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
sort-by: title sort-by: title
sort-direction: ascending sort-direction: ascending

37
.github/workflows/build-docs.yml vendored Normal file
View File

@ -0,0 +1,37 @@
name: Build Vitepress docs
on:
push:
branches:
- master
- release/*
pull_request:
merge_group:
permissions:
contents: read
jobs:
build-docs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
- name: Setup Node.js
uses: actions/setup-node@v3
with:
cache: pnpm
node-version: 18
- name: Install Packages
run: pnpm install --frozen-lockfile
- name: Verify release verion
if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release')) }}
run: pnpm --filter mermaid run docs:verify-version
- name: Run Build
run: pnpm --filter mermaid run docs:build:vitepress

View File

@ -2,6 +2,7 @@ name: Build
on: on:
push: {} push: {}
merge_group:
pull_request: pull_request:
types: types:
- opened - opened
@ -12,7 +13,7 @@ permissions:
contents: read contents: read
jobs: jobs:
build: build-mermaid:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:

View File

@ -14,7 +14,7 @@ permissions:
contents: read contents: read
jobs: jobs:
check: check-readme:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository

View File

@ -1,15 +1,16 @@
on: on:
push: {} push:
merge_group:
pull_request: pull_request:
types: types:
- opened - opened
- synchronize - synchronize
- ready_for_review - ready_for_review
name: Static analysis name: Static analysis on Test files
jobs: jobs:
test: check-tests:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: check tests name: check tests
if: github.repository_owner == 'mermaid-js' if: github.repository_owner == 'mermaid-js'

View File

@ -19,7 +19,7 @@ env:
USE_APPLI: ${{ secrets.APPLITOOLS_API_KEY && 'true' || '' }} USE_APPLI: ${{ secrets.APPLITOOLS_API_KEY && 'true' || '' }}
jobs: jobs:
test: e2e-applitools:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
@ -38,15 +38,8 @@ jobs:
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
cache: pnpm
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Install Packages
run: |
pnpm install --frozen-lockfile
env:
CYPRESS_CACHE_FOLDER: .cache/Cypress
- if: ${{ env.USE_APPLI }} - if: ${{ env.USE_APPLI }}
name: Notify applitools of new batch name: Notify applitools of new batch
# Copied from docs https://applitools.com/docs/topics/integrations/github-integration-ci-setup.html # Copied from docs https://applitools.com/docs/topics/integrations/github-integration-ci-setup.html
@ -54,19 +47,22 @@ jobs:
env: env:
# e.g. mermaid-js/mermaid/my-branch # e.g. mermaid-js/mermaid/my-branch
APPLITOOLS_BRANCH: ${{ github.repository }}/${{ github.ref_name }} APPLITOOLS_BRANCH: ${{ github.repository }}/${{ github.ref_name }}
APPLITOOLS_PARENT_BRANCH: ${{ github.inputs.parent_branch }} APPLITOOLS_PARENT_BRANCH: ${{ github.event.inputs.parent_branch }}
APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }} APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
APPLITOOLS_SERVER_URL: 'https://eyesapi.applitools.com' APPLITOOLS_SERVER_URL: 'https://eyesapi.applitools.com'
- name: Run E2E Tests - name: Cypress run
run: pnpm run e2e uses: cypress-io/github-action@v4
id: cypress
with:
start: pnpm run dev
wait-on: 'http://localhost:9000'
env: env:
CYPRESS_CACHE_FOLDER: .cache/Cypress
# Mermaid applitools.config.js uses this to pick batch name. # Mermaid applitools.config.js uses this to pick batch name.
APPLI_BRANCH: ${{ github.ref_name }} APPLI_BRANCH: ${{ github.ref_name }}
APPLITOOLS_BATCH_ID: ${{ github.sha }} APPLITOOLS_BATCH_ID: ${{ github.sha }}
# e.g. mermaid-js/mermaid/my-branch # e.g. mermaid-js/mermaid/my-branch
APPLITOOLS_BRANCH: ${{ github.repository }}/${{ github.ref_name }} APPLITOOLS_BRANCH: ${{ github.repository }}/${{ github.ref_name }}
APPLITOOLS_PARENT_BRANCH: ${{ github.inputs.parent_branch }} APPLITOOLS_PARENT_BRANCH: ${{ github.event.inputs.parent_branch }}
APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }} APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
APPLITOOLS_SERVER_URL: 'https://eyesapi.applitools.com' APPLITOOLS_SERVER_URL: 'https://eyesapi.applitools.com'

View File

@ -1,12 +1,15 @@
name: E2E name: E2E
on: [push, pull_request] on:
push:
pull_request:
merge_group:
permissions: permissions:
contents: read contents: read
jobs: jobs:
build: e2e:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
@ -21,11 +24,7 @@ jobs:
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v3
# Need to skip setup if Cypress run is skipped, otherwise an error
# is thrown since the pnpm cache step fails
if: ${{ ( env.CYPRESS_RECORD_KEY != '' ) || ( matrix.containers == 1 ) }}
with: with:
cache: pnpm
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
# Install NPM dependencies, cache them correctly # Install NPM dependencies, cache them correctly
@ -37,7 +36,7 @@ jobs:
# Otherwise (e.g. if running from fork), we run on a single container only # Otherwise (e.g. if running from fork), we run on a single container only
if: ${{ ( env.CYPRESS_RECORD_KEY != '' ) || ( matrix.containers == 1 ) }} if: ${{ ( env.CYPRESS_RECORD_KEY != '' ) || ( matrix.containers == 1 ) }}
with: with:
start: pnpm run dev start: pnpm run dev:coverage
wait-on: 'http://localhost:9000' wait-on: 'http://localhost:9000'
# Disable recording if we don't have an API key # Disable recording if we don't have an API key
# e.g. if this action was run from a fork # e.g. if this action was run from a fork
@ -45,7 +44,19 @@ jobs:
parallel: ${{ secrets.CYPRESS_RECORD_KEY != '' }} parallel: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
env: env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
VITEST_COVERAGE: true
CYPRESS_COMMIT: ${{ github.sha }}
- name: Upload Coverage to Codecov
uses: codecov/codecov-action@v3
# Run step only pushes to develop and pull_requests
if: ${{ steps.cypress.conclusion == 'success' && (github.event_name == 'pull_request' || github.ref == 'refs/heads/develop')}}
with:
files: coverage/cypress/lcov.info
flags: e2e
name: mermaid-codecov
fail_ci_if_error: false
verbose: true
token: 6845cc80-77ee-4e17-85a1-026cd95e0766
- name: Upload Artifacts - name: Upload Artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
if: ${{ failure() && steps.cypress.conclusion == 'failure' }} if: ${{ failure() && steps.cypress.conclusion == 'failure' }}

View File

@ -14,12 +14,13 @@ on:
pull_request: pull_request:
branches: branches:
- master - master
workflow_dispatch:
schedule: schedule:
# * is a special character in YAML so you have to quote this string # * is a special character in YAML so you have to quote this string
- cron: '30 8 * * *' - cron: '30 8 * * *'
jobs: jobs:
linkChecker: link-checker:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
# lychee only uses the GITHUB_TOKEN to avoid rate-limiting # lychee only uses the GITHUB_TOKEN to avoid rate-limiting
@ -35,9 +36,13 @@ jobs:
restore-keys: cache-lychee- restore-keys: cache-lychee-
- name: Link Checker - name: Link Checker
uses: lycheeverse/lychee-action@v1.5.4 uses: lycheeverse/lychee-action@v1.8.0
with: with:
args: --verbose --no-progress --cache --max-cache-age 1d packages/mermaid/src/docs/**/*.md README.md README.zh-CN.md args: >-
--config .github/lychee.toml
packages/mermaid/src/docs/**/*.md
README.md
README.zh-CN.md
fail: true fail: true
jobSummary: true jobSummary: true
env: env:

View File

@ -1,7 +1,8 @@
name: Lint name: Lint
on: on:
push: {} push:
merge_group:
pull_request: pull_request:
types: types:
- opened - opened
@ -42,7 +43,7 @@ jobs:
if ! pnpm run lint; then if ! pnpm run lint; then
# print a nice error message on lint failure # print a nice error message on lint failure
ERROR_MESSAGE='Running `pnpm run lint` failed.' ERROR_MESSAGE='Running `pnpm run lint` failed.'
ERROR_MESSAGE+=' Running `pnpm run lint:fix` may fix this issue. ' ERROR_MESSAGE+=' Running `pnpm -w run lint:fix` may fix this issue. '
ERROR_MESSAGE+=" If this error doesn't occur on your local machine," ERROR_MESSAGE+=" If this error doesn't occur on your local machine,"
ERROR_MESSAGE+=' make sure your packages are up-to-date by running `pnpm install`.' ERROR_MESSAGE+=' make sure your packages are up-to-date by running `pnpm install`.'
ERROR_MESSAGE+=' You may also need to delete your prettier cache by running' ERROR_MESSAGE+=' You may also need to delete your prettier cache by running'
@ -52,6 +53,33 @@ jobs:
exit 1 exit 1
fi fi
- name: Verify `./src/config.type.ts` is in sync with `./src/schemas/config.schema.yaml`
shell: bash
run: |
if ! pnpm run --filter mermaid types:verify-config; then
ERROR_MESSAGE='Running `pnpm run --filter mermaid types:verify-config` failed.'
ERROR_MESSAGE+=' This should be fixed by running'
ERROR_MESSAGE+=' `pnpm run --filter mermaid types:build-config`'
ERROR_MESSAGE+=' on your local machine.'
echo "::error title=Lint failure::${ERROR_MESSAGE}"
# make sure to return an error exitcode so that GitHub actions shows a red-cross
exit 1
fi
- name: Verify no circular dependencies
working-directory: ./packages/mermaid
shell: bash
run: |
if ! pnpm run --filter mermaid checkCircle; then
ERROR_MESSAGE='Circular dependency detected.'
ERROR_MESSAGE+=' This should be fixed by removing the circular dependency.'
ERROR_MESSAGE+=' Run `pnpm run --filter mermaid checkCircle` on your local machine'
ERROR_MESSAGE+=' to see the circular dependency.'
echo "::error title=Lint failure::${ERROR_MESSAGE}"
# make sure to return an error exitcode so that GitHub actions shows a red-cross
exit 1
fi
- name: Verify Docs - name: Verify Docs
id: verifyDocs id: verifyDocs
working-directory: ./packages/mermaid working-directory: ./packages/mermaid

View File

@ -1,11 +1,15 @@
name: Validate PR Labeler Configuration name: Validate PR Labeler Configuration
on: on:
push: {} push:
paths:
- .github/workflows/pr-labeler-config-validator.yml
- .github/workflows/pr-labeler.yml
- .github/pr-labeler.yml
pull_request: pull_request:
types: paths:
- opened - .github/workflows/pr-labeler-config-validator.yml
- synchronize - .github/workflows/pr-labeler.yml
- ready_for_review - .github/pr-labeler.yml
jobs: jobs:
pr-labeler: pr-labeler:

View File

@ -5,10 +5,6 @@ on:
push: push:
branches: branches:
- master - master
pull_request:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions: permissions:
@ -23,7 +19,7 @@ concurrency:
jobs: jobs:
# Build job # Build job
build: build-docs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
@ -52,13 +48,12 @@ jobs:
path: packages/mermaid/src/vitepress/.vitepress/dist path: packages/mermaid/src/vitepress/.vitepress/dist
# Deployment job # Deployment job
deploy: deploy-docs:
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
environment: environment:
name: github-pages name: github-pages
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build needs: build-docs
steps: steps:
- name: Deploy to GitHub Pages - name: Deploy to GitHub Pages
id: deployment id: deployment
uses: actions/deploy-pages@v1 uses: actions/deploy-pages@v2

View File

@ -6,7 +6,7 @@ on:
- 'release/**' - 'release/**'
jobs: jobs:
publish: publish-preview:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: fregante/setup-git-user@v1 - uses: fregante/setup-git-user@v2
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json # uses version from "packageManager" field in package.json

View File

@ -1,12 +1,12 @@
name: Unit Tests name: Unit Tests
on: [push, pull_request] on: [push, pull_request, merge_group]
permissions: permissions:
contents: read contents: read
jobs: jobs:
build: unit-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
@ -31,13 +31,24 @@ jobs:
- name: Run Unit Tests - name: Run Unit Tests
run: | run: |
pnpm run ci --coverage pnpm test:coverage
- name: Upload Coverage to Coveralls - name: Run ganttDb tests using California timezone
# it feels a bit weird to use @master, but that's what the docs use env:
# (coveralls also doesn't publish a @v1 we can use) # Makes sure that gantt db works even in a timezone that has daylight savings
# https://github.com/marketplace/actions/coveralls-github-action # since some days have 25 hours instead of 24.
uses: coverallsapp/github-action@master TZ: America/Los_Angeles
run: |
pnpm exec vitest run ./packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts --coverage
- name: Upload Coverage to Codecov
uses: codecov/codecov-action@v3
# Run step only pushes to develop and pull_requests
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/develop' }}
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} files: ./coverage/vitest/lcov.info
flag-name: unit flags: unit
name: mermaid-codecov
fail_ci_if_error: false
verbose: true
token: 6845cc80-77ee-4e17-85a1-026cd95e0766

View File

@ -5,7 +5,7 @@ on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
build: update-browser-list:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

10
.gitignore vendored
View File

@ -3,8 +3,10 @@
node_modules/ node_modules/
coverage/ coverage/
.idea/ .idea/
.pnpm-store/
dist dist
v8-compile-cache-0
yarn-error.log yarn-error.log
.npmrc .npmrc
@ -36,3 +38,11 @@ tsconfig.tsbuildinfo
knsv*.html knsv*.html
local*.html local*.html
stats/ stats/
**/user-avatars/*
**/contributor-names.json
.pnpm-store
.nyc_output
demos/dev/**
!/demos/dev/example.html

View File

@ -1,5 +1,5 @@
export default { export default {
'!(docs/**/*)*.{ts,js,json,html,md,mts}': [ '!(docs/**/*)*.{ts,js,html,md,mts}': [
'eslint --cache --cache-strategy content --fix', 'eslint --cache --cache-strategy content --fix',
// don't cache prettier yet, since we use `prettier-plugin-jsdoc`, // don't cache prettier yet, since we use `prettier-plugin-jsdoc`,
// and prettier doesn't invalidate cache on plugin updates" // and prettier doesn't invalidate cache on plugin updates"

View File

@ -1,16 +0,0 @@
# These links are ignored by our link checker https://github.com/lycheeverse/lychee
# The file allows you to list multiple regular expressions for exclusion (one pattern per line).
# Network error: Forbidden
https://codepen.io
# Network error: The certificate was not trusted
https://mkdocs.org/
https://osawards.com/javascript/#nominees
https://osawards.com/javascript/2019
# Timeout error, maybe Twitter has anti-bot defences against GitHub's CI servers?
https://twitter.com/mermaidjs_
# Don't check files that are generated during the build via `pnpm docs:code`
packages/mermaid/src/docs/config/setup/*

1
.npmrc
View File

@ -1,3 +1,2 @@
auto-install-peers=true auto-install-peers=true
strict-peer-dependencies=false strict-peer-dependencies=false
use-inline-specifiers-lockfile-format=true

View File

@ -5,3 +5,8 @@ coverage
# Autogenerated by PNPM # Autogenerated by PNPM
pnpm-lock.yaml pnpm-lock.yaml
stats stats
**/.vitepress/components.d.ts
**/.vitepress/cache
.nyc_output
# Autogenerated by `pnpm run --filter mermaid types:build-config`
packages/mermaid/src/config.type.ts

View File

@ -2,14 +2,19 @@ import { build, InlineConfig, type PluginOption } from 'vite';
import { resolve } from 'path'; import { resolve } from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import jisonPlugin from './jisonPlugin.js'; import jisonPlugin from './jisonPlugin.js';
import jsonSchemaPlugin from './jsonSchemaPlugin.js';
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import typescript from '@rollup/plugin-typescript';
import { visualizer } from 'rollup-plugin-visualizer'; import { visualizer } from 'rollup-plugin-visualizer';
import type { TemplateType } from 'rollup-plugin-visualizer/dist/plugin/template-types.js'; import type { TemplateType } from 'rollup-plugin-visualizer/dist/plugin/template-types.js';
import istanbul from 'vite-plugin-istanbul';
const visualize = process.argv.includes('--visualize'); const visualize = process.argv.includes('--visualize');
const watch = process.argv.includes('--watch'); const watch = process.argv.includes('--watch');
const mermaidOnly = process.argv.includes('--mermaid'); const mermaidOnly = process.argv.includes('--mermaid');
const coverage = process.env.VITE_COVERAGE === 'true';
const __dirname = fileURLToPath(new URL('.', import.meta.url)); const __dirname = fileURLToPath(new URL('.', import.meta.url));
const sourcemap = false;
type OutputOptions = Exclude< type OutputOptions = Exclude<
Exclude<InlineConfig['build'], undefined>['rollupOptions'], Exclude<InlineConfig['build'], undefined>['rollupOptions'],
@ -42,6 +47,11 @@ const packageOptions = {
packageName: 'mermaid-example-diagram', packageName: 'mermaid-example-diagram',
file: 'detector.ts', file: 'detector.ts',
}, },
'mermaid-zenuml': {
name: 'mermaid-zenuml',
packageName: 'mermaid-zenuml',
file: 'detector.ts',
},
}; };
interface BuildOptions { interface BuildOptions {
@ -59,9 +69,15 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
{ {
name, name,
format: 'esm', format: 'esm',
sourcemap: true, sourcemap,
entryFileNames: `${name}.esm${minify ? '.min' : ''}.mjs`, entryFileNames: `${name}.esm${minify ? '.min' : ''}.mjs`,
}, },
{
name,
format: 'umd',
sourcemap,
entryFileNames: `${name}${minify ? '.min' : ''}.js`,
},
]; ];
if (core) { if (core) {
@ -78,7 +94,7 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
{ {
name, name,
format: 'esm', format: 'esm',
sourcemap: true, sourcemap,
entryFileNames: `${name}.core.mjs`, entryFileNames: `${name}.core.mjs`,
}, },
]; ];
@ -102,9 +118,21 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
}, },
}, },
resolve: { resolve: {
extensions: ['.jison', '.js', '.ts', '.json'], extensions: [],
}, },
plugins: [jisonPlugin(), ...visualizerOptions(packageName, core)], plugins: [
jisonPlugin(),
jsonSchemaPlugin(), // handles `.schema.yaml` files
// @ts-expect-error According to the type definitions, rollup plugins are incompatible with vite
typescript({ compilerOptions: { declaration: false } }),
istanbul({
exclude: ['node_modules', 'test/', '__mocks__'],
extension: ['.js', '.ts'],
requireEnv: true,
forceBuildInstrument: coverage,
}),
...visualizerOptions(packageName, core),
],
}; };
if (watch && config.build) { if (watch && config.build) {
@ -133,6 +161,7 @@ if (watch) {
build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' })); build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' }));
if (!mermaidOnly) { if (!mermaidOnly) {
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' })); build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-zenuml' }));
} }
} else if (visualize) { } else if (visualize) {
await build(getBuildConfig({ minify: false, core: true, entryName: 'mermaid' })); await build(getBuildConfig({ minify: false, core: true, entryName: 'mermaid' }));

View File

@ -1,8 +1,6 @@
// @ts-ignore No typings for jison
import jison from 'jison'; import jison from 'jison';
export const transformJison = (src: string): string => { export const transformJison = (src: string): string => {
// @ts-ignore No typings for jison
const parser = new jison.Generator(src, { const parser = new jison.Generator(src, {
moduleType: 'js', moduleType: 'js',
'token-stack': true, 'token-stack': true,

150
.vite/jsonSchemaPlugin.ts Normal file
View File

@ -0,0 +1,150 @@
import { load, JSON_SCHEMA } from 'js-yaml';
import assert from 'node:assert';
import Ajv2019, { type JSONSchemaType } from 'ajv/dist/2019.js';
import { PluginOption } from 'vite';
import type { MermaidConfig, BaseDiagramConfig } from '../packages/mermaid/src/config.type.js';
/**
* All of the keys in the mermaid config that have a mermaid diagram config.
*/
const MERMAID_CONFIG_DIAGRAM_KEYS = [
'flowchart',
'sequence',
'gantt',
'journey',
'class',
'state',
'er',
'pie',
'quadrantChart',
'requirement',
'mindmap',
'timeline',
'gitGraph',
'c4',
'sankey',
] as const;
/**
* Generate default values from the JSON Schema.
*
* AJV does not support nested default values yet (or default values with $ref),
* so we need to manually find them (this may be fixed in ajv v9).
*
* @param mermaidConfigSchema - The Mermaid JSON Schema to use.
* @returns The default mermaid config object.
*/
function generateDefaults(mermaidConfigSchema: JSONSchemaType<MermaidConfig>) {
const ajv = new Ajv2019({
useDefaults: true,
allowUnionTypes: true,
strict: true,
});
ajv.addKeyword({
keyword: 'meta:enum', // used by jsonschema2md
errors: false,
});
ajv.addKeyword({
keyword: 'tsType', // used by json-schema-to-typescript
errors: false,
});
// ajv currently doesn't support nested default values, see https://github.com/ajv-validator/ajv/issues/1718
// (may be fixed in v9) so we need to manually use sub-schemas
const mermaidDefaultConfig = {};
assert.ok(mermaidConfigSchema.$defs);
const baseDiagramConfig = mermaidConfigSchema.$defs.BaseDiagramConfig;
for (const key of MERMAID_CONFIG_DIAGRAM_KEYS) {
const subSchemaRef = mermaidConfigSchema.properties[key].$ref;
const [root, defs, defName] = subSchemaRef.split('/');
assert.strictEqual(root, '#');
assert.strictEqual(defs, '$defs');
const subSchema = {
$schema: mermaidConfigSchema.$schema,
$defs: mermaidConfigSchema.$defs,
...mermaidConfigSchema.$defs[defName],
} as JSONSchemaType<BaseDiagramConfig>;
const validate = ajv.compile(subSchema);
mermaidDefaultConfig[key] = {};
for (const required of subSchema.required ?? []) {
if (subSchema.properties[required] === undefined && baseDiagramConfig.properties[required]) {
mermaidDefaultConfig[key][required] = baseDiagramConfig.properties[required].default;
}
}
if (!validate(mermaidDefaultConfig[key])) {
throw new Error(
`schema for subconfig ${key} does not have valid defaults! Errors were ${JSON.stringify(
validate.errors,
undefined,
2
)}`
);
}
}
const validate = ajv.compile(mermaidConfigSchema);
if (!validate(mermaidDefaultConfig)) {
throw new Error(
`Mermaid config JSON Schema does not have valid defaults! Errors were ${JSON.stringify(
validate.errors,
undefined,
2
)}`
);
}
return mermaidDefaultConfig;
}
/**
* Vite plugin that handles JSON Schemas saved as a `.schema.yaml` file.
*
* Use `my-example.schema.yaml?only-defaults=true` to only load the default values.
*/
export default function jsonSchemaPlugin(): PluginOption {
return {
name: 'json-schema-plugin',
transform(src: string, id: string) {
const idAsUrl = new URL(id, 'file:///');
if (!idAsUrl.pathname.endsWith('schema.yaml')) {
return;
}
if (idAsUrl.searchParams.get('only-defaults')) {
const jsonSchema = load(src, {
filename: idAsUrl.pathname,
// only allow JSON types in our YAML doc (will probably be default in YAML 1.3)
// e.g. `true` will be parsed a boolean `true`, `True` will be parsed as string `"True"`.
schema: JSON_SCHEMA,
}) as JSONSchemaType<MermaidConfig>;
return {
code: `export default ${JSON.stringify(generateDefaults(jsonSchema), undefined, 2)};`,
map: null, // no source map
};
} else {
return {
code: `export default ${JSON.stringify(
load(src, {
filename: idAsUrl.pathname,
// only allow JSON types in our YAML doc (will probably be default in YAML 1.3)
// e.g. `true` will be parsed a boolean `true`, `True` will be parsed as string `"True"`.
schema: JSON_SCHEMA,
}),
undefined,
2
)};`,
map: null, // provide source map if available
};
}
},
};
}

View File

@ -8,12 +8,14 @@ async function createServer() {
// Create Vite server in middleware mode // Create Vite server in middleware mode
const vite = await createViteServer({ const vite = await createViteServer({
configFile: './vite.config.ts', configFile: './vite.config.ts',
mode: 'production',
server: { middlewareMode: true }, server: { middlewareMode: true },
appType: 'custom', // don't include Vite's default HTML handling middlewares appType: 'custom', // don't include Vite's default HTML handling middleware
}); });
app.use(cors()); app.use(cors());
app.use(express.static('./packages/mermaid/dist')); app.use(express.static('./packages/mermaid/dist'));
app.use(express.static('./packages/mermaid-zenuml/dist'));
app.use(express.static('./packages/mermaid-example-diagram/dist')); app.use(express.static('./packages/mermaid-example-diagram/dist'));
app.use(vite.middlewares); app.use(vite.middlewares);
app.use(express.static('demos')); app.use(express.static('demos'));

2
.vscode/launch.json vendored
View File

@ -17,7 +17,7 @@
"name": "Docs generation", "name": "Docs generation",
"type": "node", "type": "node",
"request": "launch", "request": "launch",
"args": ["src/docs.mts"], "args": ["scripts/docs.cli.mts"],
"runtimeArgs": ["--loader", "ts-node/esm"], "runtimeArgs": ["--loader", "ts-node/esm"],
"cwd": "${workspaceRoot}/packages/mermaid", "cwd": "${workspaceRoot}/packages/mermaid",
"skipFiles": ["<node_internals>/**", "**/node_modules/**"], "skipFiles": ["<node_internals>/**", "**/node_modules/**"],

View File

@ -1,6 +1,105 @@
# Change Log # Changelog
// TODO: Populate changelog ## [10.0.0](https://github.com/mermaid-js/mermaid/releases/tag/v10.0.0)
### Mermaid is ESM only!
We've dropped CJS support. So, you will have to update your import scripts as follows.
```html
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
</script>
```
You can keep using v9 by adding the `@9` in the CDN URL.
```diff
- <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/mermaid@9/dist/mermaid.js"></script>
```
### mermaid.render is async and doesn't accept callbacks
```js
// < v10
mermaid.render('id', 'graph TD;\nA-->B', (svg, bindFunctions) => {
element.innerHTML = svg;
if (bindFunctions) {
bindFunctions(element);
}
});
// Shorter syntax
if (bindFunctions) {
bindFunctions(element);
}
// can be replaced with the `?.` shorthand
bindFunctions?.(element);
// >= v10 with async/await
const { svg, bindFunctions } = await mermaid.render('id', 'graph TD;\nA-->B');
element.innerHTML = svg;
bindFunctions?.(element);
// >= v10 with promise.then
mermaid.render('id', 'graph TD;A-->B').then(({ svg, bindFunctions }) => {
element.innerHTML = svg;
bindFunctions?.(element);
});
```
### mermaid.parse is async and ParseError is removed
```js
// < v10
mermaid.parse(text, parseError);
//>= v10
await mermaid.parse(text).catch(parseError);
// or
try {
await mermaid.parse(text);
} catch (err) {
parseError(err);
}
```
### Init deprecated and InitThrowsErrors removed
The config passed to `init` was not being used eariler.
It will now be used.
The `init` function is deprecated and will be removed in the next major release.
init currently works as a wrapper to `initialize` and `run`.
```js
// < v10
mermaid.init(config, selector, cb);
//>= v10
mermaid.initialize(config);
mermaid.run({
querySelector: selector,
postRenderCallback: cb,
suppressErrors: true,
});
```
```js
// < v10
mermaid.initThrowsErrors(config, selector, cb);
//>= v10
mermaid.initialize(config);
mermaid.run({
querySelector: selector,
postRenderCallback: cb,
suppressErrors: false,
});
```
// TODO: Populate changelog pre v10
- Config has a lot of changes - Config has a lot of changes
- globalReset resets to `defaultConfig` instead of current config. Use `reset` instead. - globalReset resets to `defaultConfig` instead of current config. Use `reset` instead.

16
CITATION.cff Normal file
View File

@ -0,0 +1,16 @@
cff-version: 1.2.0
title: 'Mermaid: Generate diagrams from markdown-like text'
message: >-
If you use this software, please cite it using the metadata from this file.
type: software
authors:
- family-names: Sveidqvist
given-names: Knut
- name: 'Contributors to Mermaid'
repository-code: 'https://github.com/mermaid-js/mermaid'
date-released: 2014-12-02
url: 'https://mermaid.js.org/'
abstract: >-
JavaScript based diagramming and charting tool that renders Markdown-inspired
text definitions to create and modify diagrams dynamically.
license: MIT

View File

@ -1,14 +1,10 @@
# Contributing # Contributing
So you want to help? That's great! Please read in detail about how to contribute documentation and code on the [Mermaid documentation site.](https://mermaid-js.github.io/mermaid/#/development)
![Happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif) ---
Here are a few things to know to get you started on the right path. # Mermaid contribution cheat-sheet
Below link will help you making a copy of the repository in your local system.
https://docs.github.com/en/get-started/quickstart/fork-a-repo
## Requirements ## Requirements
@ -18,161 +14,65 @@ https://docs.github.com/en/get-started/quickstart/fork-a-repo
## Development Installation ## Development Installation
If you don't have direct access to push to mermaid repositories, make a fork first. Then clone. Or clone directly from mermaid-js:
```bash ```bash
git clone git@github.com:mermaid-js/mermaid.git git clone git@github.com:mermaid-js/mermaid.git
cd mermaid cd mermaid
```
Install required packages:
```bash
# npx is required for first install as volta support for pnpm is not added yet. # npx is required for first install as volta support for pnpm is not added yet.
npx pnpm install npx pnpm install
pnpm test # run unit tests
pnpm dev # starts a dev server
```
Open <http://localhost:9000> in your browser after starting the dev server.
You can also duplicate the `example.html` file in `demos/dev`, rename it and add your own mermaid code to it.
That will be served at <http://localhost:9000/dev/your-file-name.html>.
### Docker
If you are using docker and docker-compose, you have self-documented `run` bash script, which is a convenient alias for docker-compose commands:
```bash
./run install # npx pnpm install
./run test # pnpm test
```
## Testing
```bash
# Run unit test
pnpm test pnpm test
# Run unit test in watch mode
pnpm test:watch
# Run E2E test
pnpm e2e
# Debug E2E tests
pnpm dev
pnpm cypress:open # in another terminal
``` ```
## Committing code ## Branch name format:
We make all changes via pull requests. As we have many pull requests from developers new to mermaid, the current approach is to have _knsv, Knut Sveidqvist_ as a main reviewer of changes and merging pull requests. More precisely like this:
- Large changes reviewed by knsv or other developer asked to review by knsv
- Smaller low-risk changes like dependencies, documentation, etc. can be merged by active collaborators
- Documentation (updates to the `package/mermaid/src/docs` folder is also allowed via direct commits)
To commit code, create a branch, let it start with the type like feature or bug followed by the issue number for reference and some describing text.
One example:
`feature/945_state_diagrams`
Another:
`bug/123_nasty_bug_branch`
## Committing documentation
Less strict here, it is OK to commit directly in the `develop` branch if you are a collaborator.
The documentation is written in **Markdown**. For more information about Markdown [see the GitHub Markdown help page](https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax).
### Documentation source files are in [`/packages/mermaid/src/docs`](packages/mermaid/src/docs)
The source files for the project documentation are located in the [`/packages/mermaid/src/docs`](packages/mermaid/src/docs) directory. This is where you should make changes.
The files under `/packages/mermaid/src/docs` are processed to generate the published documentation, and the resulting files are put into the `/docs` directory.
```mermaid
flowchart LR
classDef default fill:#fff,color:black,stroke:black
source["files in /packages/mermaid/src/docs\n(changes should be done here)"] -- automatic processing\nto generate the final documentation--> published["files in /docs\ndisplayed on the official documentation site"]
```text
[feature | bug | chore | docs]/[issue number]_[short description using dashes ('-') or underscores ('_') instead of spaces]
``` ```
You can use `note`, `tip`, `warning` and `danger` in triple backticks to add a note, tip, warning or danger box. eg: `feature/2945_state-diagram-new-arrow-florbs`, `bug/1123_fix_random_ugly_red_text`
Do not use vitepress specific markdown syntax `::: warning` as it will not be processed correctly.
```` ## Documentation
```note
Note content
```
```tip Documentation is necessary for all non bugfix/refactoring changes.
Tip content
```
```warning Only make changes to files that are in [`/packages/mermaid/src/docs`](packages/mermaid/src/docs)
Warning content
```
```danger **_DO NOT CHANGE FILES IN `/docs` MANUALLY_**
Danger content
```
```` The `/docs` folder will be rebuilt and committed as part of a pre-commit hook.
**_DO NOT CHANGE FILES IN `/docs`_**
### The official documentation site
**[The mermaid documentation site](https://mermaid-js.github.io/mermaid/) is powered by [Vitepress](https://vitepress.vuejs.org/), a simple documentation site generator.**
If you want to preview the whole documentation site on your machine:
```sh
cd packages/mermaid
pnpm i
pnpm docs:dev
```
You can now build and serve the documentation site:
```sh
pnpm docs:serve
```
## Branching
Going forward we will use a git flow inspired approach to branching. So development is done in develop, to do the development in the develop.
Once development is done we branch a release branch from develop for testing.
Once the release happens we merge the release branch to master and kill the release branch.
This means... **branch off your pull request from develop**
## Content of a pull request
A new feature has been born. Great! But without the steps below it might just ... fade away ...
### **Add unit tests for the parsing part**
This is important so that, if someone else does a change to the grammar that does not know about this great feature, gets notified early on when that change breaks the parser. Another important aspect is that without proper parsing tests refactoring is pretty much impossible.
### **Add e2e tests**
This tests the rendering and visual appearance of the diagram. This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks!
To start working with the e2e tests, run `pnpm run dev` to start the dev server, after that start cypress by running `pnpm exec cypress open` in the mermaid folder.
The rendering tests are very straightforward to create. There is a function imgSnapshotTest. This function takes a diagram in text form, the mermaid options and renders that diagram in cypress.
When running in ci it will take a snapshot of the rendered diagram and compare it with the snapshot from last build and flag for review it if it differs.
This is what a rendering test looks like:
```javascript
it('should render forks and joins', () => {
imgSnapshotTest(
`
stateDiagram
state fork_state &lt;&lt;fork&gt;&gt;
[*] --> fork_state
fork_state --> State2
fork_state --> State3
state join_state &lt;&lt;join&gt;&gt;
State2 --> join_state
State3 --> join_state
join_state --> State4
State4 --> [*]
`,
{ logLevel: 0 }
);
cy.get('svg');
});
```
### **Add documentation for it**
Finally, if it is not in the documentation, no one will know about it and then **no one will use it**. Wouldn't that be sad? With all the effort that was put into the feature?
The source files for documentation are in `/packages/mermaid/src/docs` and are written in markdown. Just pick the right section and start typing. See the [Committing Documentation](#committing-documentation) section for more about how the documentation is generated.
#### Adding to or changing the documentation organization
If you want to add a new section or change the organization (structure), then you need to make sure to **change the side navigation** in `mermaid/src/docs/.vitepress/config.js`.
When changes are committed and then released, they become part of the `master` branch and become part of the published documentation on https://mermaid-js.github.io/mermaid/
## Last words
Don't get daunted if it is hard in the beginning. We have a great community with only encouraging words. So if you get stuck, ask for help and hints in the slack forum. If you want to show off something good, show it off there.
[Join our slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [Join our slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
![A superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)

View File

@ -8,7 +8,7 @@ Mermaid
Generate diagrams from markdown-like text. Generate diagrams from markdown-like text.
<p> <p>
<p align="center"> <p align="center">
<a href="https://www.npmjs.com/package/vitest"><img src="https://img.shields.io/npm/v/mermaid?color=ff3670&label="></a> <a href="https://www.npmjs.com/package/mermaid"><img src="https://img.shields.io/npm/v/mermaid?color=ff3670&label="></a>
<p> <p>
<p align="center"> <p align="center">
@ -27,7 +27,7 @@ Generate diagrams from markdown-like text.
[![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid)
[![Build CI Status](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml/badge.svg)](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml) [![Build CI Status](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml/badge.svg)](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml)
[![npm minified gzipped bundle size](https://img.shields.io/bundlephobia/minzip/mermaid)](https://bundlephobia.com/package/mermaid) [![npm minified gzipped bundle size](https://img.shields.io/bundlephobia/minzip/mermaid)](https://bundlephobia.com/package/mermaid)
[![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
[![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid)
[![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
@ -60,7 +60,7 @@ Use Mermaid with your favorite applications, check out the list of [Integrations
You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) as well many of your other favorite applications—check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations.md). You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) as well many of your other favorite applications—check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations.md).
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/community/n00b-overview.md), [Usage](./docs/config/usage.md) and [Tutorials](./docs/config/Tutorials.md). For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/intro/getting-started.md), [Usage](./docs/config/usage.md) and [Tutorials](./docs/config/Tutorials.md).
In our release process we rely heavily on visual regression tests using [applitools](https://applitools.com/). Applitools is a great service which has been easy to use and integrate with our tests. In our release process we rely heavily on visual regression tests using [applitools](https://applitools.com/). Applitools is a great service which has been easy to use and integrate with our tests.
@ -165,6 +165,13 @@ class Class10 {
int id int id
size() size()
} }
namespace Namespace01 {
class Class11
class Class12 {
int id
size()
}
}
``` ```
```mermaid ```mermaid
@ -184,6 +191,13 @@ class Class10 {
int id int id
size() size()
} }
namespace Namespace01 {
class Class11
class Class12 {
int id
size()
}
}
``` ```
### State diagram [<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid.live/edit#pako:eNpdkEFvgzAMhf8K8nEqpYSNthx22Xbcqcexg0sCiZQQlDhIFeK_L8A6TfXp6fOz9ewJGssFVOAJSbwr7ByadGR1n8T6evpO0vQ1uZDSekOrXGFsPqJPO6q-2-imH8f_0TeHXm50lfelsAMjnEHFY6xpMdRAUhhRQxUlFy0GTTXU_RytYeAx-AdXZB1ULWovdoCB7OXWN1CRC-Ju-r3uz6UtchGHJqDbsPygU57iysb2reoWHpyOWBINvsqypb3vFMlw3TfWZF5xiY7keC6zkpUnZIUojwW-FAVvrvn51LLnvOXHQ84Q5nn-AVtLcwk">live editor</a>] ### State diagram [<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid.live/edit#pako:eNpdkEFvgzAMhf8K8nEqpYSNthx22Xbcqcexg0sCiZQQlDhIFeK_L8A6TfXp6fOz9ewJGssFVOAJSbwr7ByadGR1n8T6evpO0vQ1uZDSekOrXGFsPqJPO6q-2-imH8f_0TeHXm50lfelsAMjnEHFY6xpMdRAUhhRQxUlFy0GTTXU_RytYeAx-AdXZB1ULWovdoCB7OXWN1CRC-Ju-r3uz6UtchGHJqDbsPygU57iysb2reoWHpyOWBINvsqypb3vFMlw3TfWZF5xiY7keC6zkpUnZIUojwW-FAVvrvn51LLnvOXHQ84Q5nn-AVtLcwk">live editor</a>]
@ -226,6 +240,44 @@ pie
### Git graph [experimental - <a href="https://mermaid.live/edit#pako:eNqNkMFugzAMhl8F-VyVAR1tOW_aA-zKxSSGRCMJCk6lCvHuNZPKZdM0n-zf3_8r8QIqaIIGMqnB8kfEybQ--y4VnLP8-9RF9Mpkmm40hmlnDKmvkPiH_kfS7nFo_VN0FAf6XwocQGgxa_nGsm1bYEOOWmik1dRjGrmF1q-Cpkkj07u2HCI0PY4zHQATh8-7V9BwTPSE3iwOEd1OjQE1iWkBvk_bzQY7s0Sq4Hs7bHqKo8iGeZqbPN_WR7mpSd1RHpvPVhuMbG7XOq_L-oJlRfW5wteq0qorrpe-PBW9Pr8UJcK6rg-BLYPQ">live editor</a>] ### Git graph [experimental - <a href="https://mermaid.live/edit#pako:eNqNkMFugzAMhl8F-VyVAR1tOW_aA-zKxSSGRCMJCk6lCvHuNZPKZdM0n-zf3_8r8QIqaIIGMqnB8kfEybQ--y4VnLP8-9RF9Mpkmm40hmlnDKmvkPiH_kfS7nFo_VN0FAf6XwocQGgxa_nGsm1bYEOOWmik1dRjGrmF1q-Cpkkj07u2HCI0PY4zHQATh8-7V9BwTPSE3iwOEd1OjQE1iWkBvk_bzQY7s0Sq4Hs7bHqKo8iGeZqbPN_WR7mpSd1RHpvPVhuMbG7XOq_L-oJlRfW5wteq0qorrpe-PBW9Pr8UJcK6rg-BLYPQ">live editor</a>]
### Bar chart (using gantt chart) [<a href="https://mermaid-js.github.io/mermaid/#/gantt">docs</a> - <a href="https://mermaid.live/edit#pako:eNptkU1vhCAQhv8KIenNugiI4rkf6bmXpvEyFVxJFDYyNt1u9r8X63Z7WQ9m5pknLzieaBeMpQ3dg0dsPUkPOhwteXZIXmJcbCT3xMAxkuh8Z8kIEclyMIB209fqKcwTICFvG4IvFy_oLrZ-g9F26ILfQgvNFN94VaRXQ1iWqpumZBcu1J8p1E1TXDx59eQNr5LyEqjJn6hv5QnGNlxevZJmdLLpy5xJSzut45biYCfb0iaVxvawjNjS1p-TCguG16PvaIPzYjO67e3BwX6GiTY9jPFKH43DMF_hGMDY1J4oHg-_f8hFTJFd8L3br3yZx4QHxENsdrt1nO8dDstH3oVpF50ZYMbhU6ud4qoGLqyqBJRCmO6j0HXPZdGbihUc6Pmc0QP49xD-b5X69ZQv2gjO81IwzWqhC1lKrjJ6pA3nVS7SMiVjrKirWlYp5fs3osgrWeo00lorLWvOzz8JVbXm">live editor</a>]
```
gantt
title Git Issues - days since last update
dateFormat X
axisFormat %s
section Issue19062
71 : 0, 71
section Issue19401
36 : 0, 36
section Issue193
34 : 0, 34
section Issue7441
9 : 0, 9
section Issue1300
5 : 0, 5
```
```mermaid
gantt
title Git Issues - days since last update
dateFormat X
axisFormat %s
section Issue19062
71 : 0, 71
section Issue19401
36 : 0, 36
section Issue193
34 : 0, 34
section Issue7441
9 : 0, 9
section Issue1300
5 : 0, 5
```
### User Journey diagram [<a href="https://mermaid-js.github.io/mermaid/#/user-journey">docs</a> - <a href="https://mermaid.live/edit#pako:eNplkMFuwjAQRH9l5TMiTVIC-FqqnjhxzWWJN4khsSN7XRSh_HsdKBVt97R6Mzsj-yoqq0hIAXCywRkaSwNxWHNHsB_hYt1ZmwYUfiueKtbWwIcFtjf5zgH2eCZgQgkrCXt64GgMg2fUzkvIn5Xd_V5COtMFvCH_62ht_5yk7MU8sn61HDTfxD8VYiF6cj1qFd94nWkpuKWYKWRcFdUYOi5FaaZoDYNCpnel2Toha-w8LQQGtofRVEKyC_Qw7TQ2DvsfV2dRUTy6Ch6H-UMb7TlGVtbUupl5cF3ELfPgZZLM8rLR3IbjsrJ94rVq0XH7uS2SIis2mOVUrHNc5bmqjul2U2evaa3WL2mGYpqmL2BGiho">live editor</a>] ### User Journey diagram [<a href="https://mermaid-js.github.io/mermaid/#/user-journey">docs</a> - <a href="https://mermaid.live/edit#pako:eNplkMFuwjAQRH9l5TMiTVIC-FqqnjhxzWWJN4khsSN7XRSh_HsdKBVt97R6Mzsj-yoqq0hIAXCywRkaSwNxWHNHsB_hYt1ZmwYUfiueKtbWwIcFtjf5zgH2eCZgQgkrCXt64GgMg2fUzkvIn5Xd_V5COtMFvCH_62ht_5yk7MU8sn61HDTfxD8VYiF6cj1qFd94nWkpuKWYKWRcFdUYOi5FaaZoDYNCpnel2Toha-w8LQQGtofRVEKyC_Qw7TQ2DvsfV2dRUTy6Ch6H-UMb7TlGVtbUupl5cF3ELfPgZZLM8rLR3IbjsrJ94rVq0XH7uS2SIis2mOVUrHNc5bmqjul2U2evaa3WL2mGYpqmL2BGiho">live editor</a>]
``` ```
@ -334,7 +386,7 @@ Update version number in `package.json`.
npm publish npm publish
``` ```
The above command generates files into the `dist` folder and publishes them to npmjs.org. The above command generates files into the `dist` folder and publishes them to <https://www.npmjs.com>.
## Related projects ## Related projects
@ -350,7 +402,7 @@ Detailed information about how to contribute can be found in the [contribution g
## Security and safe diagrams ## Security and safe diagrams
For public sites, it can be precarious to retrieve text from users on the internet, storing that content for presentation in a browser at a later stage. The reason is that the user content can contain embedded malicious scripts that will run when the data is presented. For Mermaid this is a risk, specially as mermaid diagrams contain many characters that are used in html which makes the standard sanitation unusable as it also breaks the diagrams. We still make an effort to sanitise the incoming code and keep refining the process but it is hard to guarantee that there are no loop holes. For public sites, it can be precarious to retrieve text from users on the internet, storing that content for presentation in a browser at a later stage. The reason is that the user content can contain embedded malicious scripts that will run when the data is presented. For Mermaid this is a risk, specially as mermaid diagrams contain many characters that are used in html which makes the standard sanitation unusable as it also breaks the diagrams. We still make an effort to sanitize the incoming code and keep refining the process but it is hard to guarantee that there are no loop holes.
As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing javascript in the code from being executed. This is a great step forward for better security. As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing javascript in the code from being executed. This is a great step forward for better security.
@ -358,7 +410,7 @@ _Unfortunately you can not have a cake and eat it at the same time which in this
## Reporting vulnerabilities ## Reporting vulnerabilities
To report a vulnerability, please e-mail security@mermaid.live with a description of the issue, the steps you took to create the issue, affected versions, and if known, mitigations for the issue. To report a vulnerability, please e-mail <security@mermaid.live> with a description of the issue, the steps you took to create the issue, affected versions, and if known, mitigations for the issue.
## Appreciation ## Appreciation

View File

@ -8,7 +8,7 @@ Mermaid
通过解析类 Markdown 的文本语法来实现图表的创建和动态修改。 通过解析类 Markdown 的文本语法来实现图表的创建和动态修改。
<p> <p>
<p align="center"> <p align="center">
<a href="https://www.npmjs.com/package/vitest"><img src="https://img.shields.io/npm/v/mermaid?color=ff3670&label="></a> <a href="https://www.npmjs.com/package/mermaid"><img src="https://img.shields.io/npm/v/mermaid?color=ff3670&label="></a>
<p> <p>
<p align="center"> <p align="center">
@ -27,7 +27,7 @@ Mermaid
[![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid)
[![Build CI Status](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml/badge.svg)](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml) [![Build CI Status](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml/badge.svg)](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml)
[![npm minified gzipped bundle size](https://img.shields.io/bundlephobia/minzip/mermaid)](https://bundlephobia.com/package/mermaid) [![npm minified gzipped bundle size](https://img.shields.io/bundlephobia/minzip/mermaid)](https://bundlephobia.com/package/mermaid)
[![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
[![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid)
[![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
@ -55,7 +55,7 @@ Mermaid 通过允许用户创建便于修改的图表来解决这一难题,它
Mermaid 甚至能让非程序员也能通过 [Mermaid Live Editor](https://mermaid.live/) 轻松创建详细的图表。<br/> Mermaid 甚至能让非程序员也能通过 [Mermaid Live Editor](https://mermaid.live/) 轻松创建详细的图表。<br/>
你可以访问 [教程](./docs/config/Tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/ecosystem/integrations.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。 你可以访问 [教程](./docs/config/Tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/ecosystem/integrations.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/community/n00b-overview.md), [用法](./docs/config/usage.md) 和 [教程](./docs/config/Tutorials.md). 如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/intro/getting-started.md), [用法](./docs/config/usage.md) 和 [教程](./docs/config/Tutorials.md).
<!-- </Main description> --> <!-- </Main description> -->
@ -322,7 +322,7 @@ Rel(SystemC, customerA, "Sends e-mails to")
npm publish npm publish
``` ```
以上的命令会将文件打包到 `dist` 目录并发布至 npmjs.org. 以上的命令会将文件打包到 `dist` 目录并发布至 <https://www.npmjs.com>.
## 相关项目 ## 相关项目

View File

@ -1,58 +0,0 @@
# A collection of updates that change the behavior
## Async
`parse`, `render` are now async.
## Lazy loading and asynchronisity
- Invalid dates are rendered as syntax error instead of returning best guess or the current date
## ParseError is removed
```js
//< v10.0.0
mermaid.parse(text, parseError);
//>= v10.0.0
await mermaid.parse(text).catch(parseError);
// or
try {
await mermaid.parse(text);
} catch (err) {
parseError(err);
}
```
## Init deprecated and InitThrowsErrors removed
The config passed to `init` was not being used eariler.
It will now be used.
The `init` function is deprecated and will be removed in the next major release.
init currently works as a wrapper to `initialize` and `run`.
```js
//< v10.0.0
mermaid.init(config, selector, cb);
//>= v10.0.0
mermaid.initialize(config);
mermaid.run({
querySelector: selector,
postRenderCallback: cb,
suppressErrors: true,
});
```
```js
//< v10.0.0
mermaid.initThrowsErrors(config, selector, cb);
//>= v10.0.0
mermaid.initialize(config);
mermaid.run({
querySelector: selector,
postRenderCallback: cb,
suppressErrors: false,
});
```

View File

@ -1,5 +1,4 @@
// @ts-nocheck TODO: Fix TS import { MockedD3 } from '../packages/mermaid/src/tests/MockedD3.js';
import { MockedD3 } from '../packages/mermaid/src/tests/MockedD3';
export const select = function () { export const select = function () {
return new MockedD3(); return new MockedD3();

8
__mocks__/pieRenderer.ts Normal file
View File

@ -0,0 +1,8 @@
/**
* Mocked pie (picChart) diagram renderer
*/
import { vi } from 'vitest';
const draw = vi.fn().mockImplementation(() => '');
export const renderer = { draw };

View File

@ -1,5 +1,5 @@
/** /**
* Mocked pie (picChart) diagram renderer * Mocked Sankey diagram renderer
*/ */
import { vi } from 'vitest'; import { vi } from 'vitest';

View File

@ -5,11 +5,14 @@
"acyclicer", "acyclicer",
"adamiecki", "adamiecki",
"alois", "alois",
"aloisklink",
"antiscript", "antiscript",
"antlr",
"appli", "appli",
"applitools", "applitools",
"asciidoctor", "asciidoctor",
"ashish", "ashish",
"ashishjain",
"astah", "astah",
"bbox", "bbox",
"bilkent", "bilkent",
@ -19,23 +22,32 @@
"brkt", "brkt",
"brolin", "brolin",
"brotli", "brotli",
"città",
"classdef", "classdef",
"codedoc", "codedoc",
"colour", "colour",
"commitlint",
"cpettitt", "cpettitt",
"customizability", "customizability",
"cuzon", "cuzon",
"cytoscape", "cytoscape",
"dagre", "dagre",
"deepdwn",
"descr", "descr",
"docsify", "docsify",
"docsy", "docsy",
"doku", "doku",
"dompurify", "dompurify",
"dont",
"doublecircle",
"edgechromium", "edgechromium",
"elems",
"elkjs", "elkjs",
"elle",
"faber", "faber",
"flatmap", "flatmap",
"foswiki",
"frontmatter",
"ftplugin", "ftplugin",
"gantt", "gantt",
"gitea", "gitea",
@ -45,30 +57,48 @@
"graphviz", "graphviz",
"grav", "grav",
"greywolf", "greywolf",
"gzipped",
"huynh",
"huynhicode",
"inkdrop", "inkdrop",
"jaoude", "jaoude",
"jgreywolf",
"jison", "jison",
"jiti",
"kaufmann", "kaufmann",
"khroma", "khroma",
"klemm", "klemm",
"klink", "klink",
"knsv", "knsv",
"knut", "knut",
"knutsveidqvist",
"laganeckas", "laganeckas",
"linetype",
"lintstagedrc", "lintstagedrc",
"logmsg", "logmsg",
"lucida", "lucida",
"markdownish",
"matthieu", "matthieu",
"matthieumorel",
"mdast", "mdast",
"mdbook", "mdbook",
"mermaidjs",
"mermerd", "mermerd",
"mindaugas", "mindaugas",
"mindmap", "mindmap",
"mindmaps", "mindmaps",
"mitigations", "mitigations",
"mkdocs", "mkdocs",
"mmorel",
"mult", "mult",
"neurodiverse",
"nextra",
"nikolay",
"nirname",
"npmjs",
"orlandoni", "orlandoni",
"pathe",
"pbrolin",
"phpbb", "phpbb",
"plantuml", "plantuml",
"playfair", "playfair",
@ -79,17 +109,29 @@
"ranksep", "ranksep",
"rect", "rect",
"rects", "rects",
"reda",
"redmine", "redmine",
"regexes",
"rehype",
"roledescription", "roledescription",
"rozhkov",
"sandboxed", "sandboxed",
"sankey",
"setupgraphviewbox", "setupgraphviewbox",
"shiki", "shiki",
"sidharth", "sidharth",
"sidharthv", "sidharthv",
"sphinxcontrib", "sphinxcontrib",
"startx",
"starty",
"statediagram", "statediagram",
"steph",
"stopx",
"stopy",
"stylis", "stylis",
"subhash-halder",
"substate", "substate",
"sulais",
"sveidqvist", "sveidqvist",
"swimm", "swimm",
"techn", "techn",
@ -97,16 +139,26 @@
"textlength", "textlength",
"treemap", "treemap",
"ts-nocheck", "ts-nocheck",
"tsdoc",
"tuleap", "tuleap",
"tylerlong",
"typora",
"ugge", "ugge",
"unist", "unist",
"unocss",
"upvoting",
"valign",
"verdana", "verdana",
"viewports", "viewports",
"vinod", "vinod",
"visio", "visio",
"vitepress", "vitepress",
"vueuse",
"xlink", "xlink",
"yash" "yash",
"yokozuna",
"zenuml",
"zune"
], ],
"patterns": [ "patterns": [
{ "name": "Markdown links", "pattern": "\\((.*)\\)", "description": "" }, { "name": "Markdown links", "pattern": "\\((.*)\\)", "description": "" },
@ -146,6 +198,7 @@
], ],
"ignorePaths": [ "ignorePaths": [
"packages/mermaid/src/docs/CHANGELOG.md", "packages/mermaid/src/docs/CHANGELOG.md",
"packages/mermaid/src/docs/.vitepress/redirect.ts" "packages/mermaid/src/docs/.vitepress/redirect.ts",
"packages/mermaid/src/docs/.vitepress/contributor-names.json"
] ]
} }

View File

@ -2,12 +2,14 @@
const { defineConfig } = require('cypress'); const { defineConfig } = require('cypress');
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin'); const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
const coverage = require('@cypress/code-coverage/task');
module.exports = defineConfig({ module.exports = defineConfig({
projectId: 'n2sma2', projectId: 'n2sma2',
e2e: { e2e: {
specPattern: 'cypress/integration/**/*.{js,jsx,ts,tsx}', specPattern: 'cypress/integration/**/*.{js,jsx,ts,tsx}',
setupNodeEvents(on, config) { setupNodeEvents(on, config) {
coverage(on, config);
addMatchImageSnapshotPlugin(on, config); addMatchImageSnapshotPlugin(on, config);
// copy any needed variables from process.env to config.env // copy any needed variables from process.env to config.env
config.env.useAppli = process.env.USE_APPLI ? true : false; config.env.useAppli = process.env.USE_APPLI ? true : false;

View File

@ -1,93 +0,0 @@
const utf8ToB64 = (str) => {
return window.btoa(unescape(encodeURIComponent(str)));
};
const batchId = 'mermaid-batch' + new Date().getTime();
export const mermaidUrl = (graphStr, options, api) => {
const obj = {
code: graphStr,
mermaid: options,
};
const objStr = JSON.stringify(obj);
let url = 'http://localhost:9000/e2e.html?graph=' + utf8ToB64(objStr);
if (api) {
url = 'http://localhost:9000/xss.html?graph=' + graphStr;
}
if (options.listUrl) {
cy.log(options.listId, ' ', url);
}
return url;
};
export const imgSnapshotTest = (graphStr, _options, api = false, validation) => {
cy.log(_options);
const options = Object.assign(_options);
if (!options.fontFamily) {
options.fontFamily = 'courier';
}
if (!options.sequence) {
options.sequence = {};
}
if (!options.sequence || (options.sequence && !options.sequence.actorFontFamily)) {
options.sequence.actorFontFamily = 'courier';
}
if (options.sequence && !options.sequence.noteFontFamily) {
options.sequence.noteFontFamily = 'courier';
}
options.sequence.actorFontFamily = 'courier';
options.sequence.noteFontFamily = 'courier';
options.sequence.messageFontFamily = 'courier';
if (options.sequence && !options.sequence.actorFontFamily) {
options.sequence.actorFontFamily = 'courier';
}
if (!options.fontSize) {
options.fontSize = '16px';
}
const url = mermaidUrl(graphStr, options, api);
openURLAndVerifyRendering(url, options, validation);
};
export const urlSnapshotTest = (url, _options, api = false, validation) => {
const options = Object.assign(_options);
openURLAndVerifyRendering(url, options, validation);
};
export const renderGraph = (graphStr, options, api) => {
const url = mermaidUrl(graphStr, options, api);
openURLAndVerifyRendering(url, options);
};
const openURLAndVerifyRendering = (url, options, validation = undefined) => {
const useAppli = Cypress.env('useAppli');
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
if (useAppli) {
cy.log('Opening eyes ' + Cypress.spec.name + ' --- ' + name);
cy.eyesOpen({
appName: 'Mermaid',
testName: name,
batchName: Cypress.spec.name,
batchId: batchId + Cypress.spec.name,
});
}
cy.visit(url);
cy.window().should('have.property', 'rendered', true);
cy.get('svg').should('be.visible');
if (validation) {
cy.get('svg').should(validation);
}
if (useAppli) {
cy.log('Check eyes' + Cypress.spec.name);
cy.eyesCheckWindow('Click!');
cy.log('Closing eyes' + Cypress.spec.name);
cy.eyesClose();
} else {
cy.matchImageSnapshot(name);
}
};

136
cypress/helpers/util.ts Normal file
View File

@ -0,0 +1,136 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Buffer } from 'buffer';
import type { MermaidConfig } from '../../packages/mermaid/src/config.type.js';
interface CypressConfig {
listUrl?: boolean;
listId?: string;
name?: string;
}
type CypressMermaidConfig = MermaidConfig & CypressConfig;
interface CodeObject {
code: string;
mermaid: CypressMermaidConfig;
}
const utf8ToB64 = (str: string): string => {
return Buffer.from(decodeURIComponent(encodeURIComponent(str))).toString('base64');
};
const batchId: string =
'mermaid-batch-' +
(Cypress.env('useAppli')
? Date.now().toString()
: Cypress.env('CYPRESS_COMMIT') || Date.now().toString());
export const mermaidUrl = (
graphStr: string,
options: CypressMermaidConfig,
api: boolean
): string => {
const codeObject: CodeObject = {
code: graphStr,
mermaid: options,
};
const objStr: string = JSON.stringify(codeObject);
let url = `http://localhost:9000/e2e.html?graph=${utf8ToB64(objStr)}`;
if (api) {
url = `http://localhost:9000/xss.html?graph=${graphStr}`;
}
if (options.listUrl) {
cy.log(options.listId, ' ', url);
}
return url;
};
export const imgSnapshotTest = (
graphStr: string,
_options: CypressMermaidConfig = {},
api = false,
validation?: any
): void => {
cy.log(JSON.stringify(_options));
const options: CypressMermaidConfig = Object.assign(_options);
if (!options.fontFamily) {
options.fontFamily = 'courier';
}
if (!options.sequence) {
options.sequence = {};
}
if (!options.sequence || (options.sequence && !options.sequence.actorFontFamily)) {
options.sequence.actorFontFamily = 'courier';
}
if (options.sequence && !options.sequence.noteFontFamily) {
options.sequence.noteFontFamily = 'courier';
}
options.sequence.actorFontFamily = 'courier';
options.sequence.noteFontFamily = 'courier';
options.sequence.messageFontFamily = 'courier';
if (options.sequence && !options.sequence.actorFontFamily) {
options.sequence.actorFontFamily = 'courier';
}
if (!options.fontSize) {
options.fontSize = 16;
}
const url: string = mermaidUrl(graphStr, options, api);
openURLAndVerifyRendering(url, options, validation);
};
export const urlSnapshotTest = (
url: string,
_options: CypressMermaidConfig,
_api = false,
validation?: any
): void => {
const options: CypressMermaidConfig = Object.assign(_options);
openURLAndVerifyRendering(url, options, validation);
};
export const renderGraph = (
graphStr: string,
options: CypressMermaidConfig = {},
api = false
): void => {
const url: string = mermaidUrl(graphStr, options, api);
openURLAndVerifyRendering(url, options);
};
export const openURLAndVerifyRendering = (
url: string,
options: CypressMermaidConfig,
validation?: any
): void => {
const useAppli: boolean = Cypress.env('useAppli');
const name: string = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
if (useAppli) {
cy.log(`Opening eyes ${Cypress.spec.name} --- ${name}`);
cy.eyesOpen({
appName: 'Mermaid',
testName: name,
batchName: Cypress.spec.name,
batchId: batchId + Cypress.spec.name,
});
}
cy.visit(url);
cy.window().should('have.property', 'rendered', true);
cy.get('svg').should('be.visible');
if (validation) {
cy.get('svg').should(validation);
}
if (useAppli) {
cy.log(`Check eyes ${Cypress.spec.name}`);
cy.eyesCheckWindow('Click!');
cy.log(`Closing eyes ${Cypress.spec.name}`);
cy.eyesClose();
} else {
cy.matchImageSnapshot(name);
}
};

View File

@ -1,4 +1,4 @@
import { renderGraph } from '../../helpers/util'; import { renderGraph } from '../../helpers/util.ts';
describe('Configuration', () => { describe('Configuration', () => {
describe('arrowMarkerAbsolute', () => { describe('arrowMarkerAbsolute', () => {
it('should handle default value false of arrowMarkerAbsolute', () => { it('should handle default value false of arrowMarkerAbsolute', () => {

View File

@ -1,4 +1,4 @@
import { urlSnapshotTest } from '../../helpers/util'; import { urlSnapshotTest } from '../../helpers/util.ts';
describe('mermaid', () => { describe('mermaid', () => {
describe('registerDiagram', () => { describe('registerDiagram', () => {

View File

@ -1,4 +1,4 @@
import { urlSnapshotTest } from '../../helpers/util'; import { urlSnapshotTest, openURLAndVerifyRendering } from '../../helpers/util.ts';
describe('CSS injections', () => { describe('CSS injections', () => {
it('should not allow CSS injections outside of the diagram', () => { it('should not allow CSS injections outside of the diagram', () => {
@ -13,4 +13,11 @@ describe('CSS injections', () => {
flowchart: { htmlLabels: false }, flowchart: { htmlLabels: false },
}); });
}); });
it('should not allow manipulating styletags using arrowheads', () => {
openURLAndVerifyRendering('http://localhost:9000/xss23-css.html', {
logLevel: 1,
arrowMarkerAbsolute: false,
flowchart: { htmlLabels: true },
});
});
}); });

View File

@ -1,4 +1,4 @@
import { mermaidUrl } from '../../helpers/util.js'; import { mermaidUrl } from '../../helpers/util.ts';
describe('XSS', () => { describe('XSS', () => {
it('should handle xss in tags', () => { it('should handle xss in tags', () => {
const str = const str =

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest } from '../../helpers/util.js'; import { imgSnapshotTest } from '../../helpers/util.ts';
describe('Git Graph diagram', () => { describe('Git Graph diagram', () => {
it('1: should render a simple gitgraph with commit on main branch', () => { it('1: should render a simple gitgraph with commit on main branch', () => {

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('C4 diagram', () => { describe('C4 diagram', () => {
it('should render a simple C4Context diagram', () => { it('should render a simple C4Context diagram', () => {

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest } from '../../helpers/util'; import { imgSnapshotTest } from '../../helpers/util.ts';
describe('Class diagram V2', () => { describe('Class diagram V2', () => {
it('0: should render a simple class diagram', () => { it('0: should render a simple class diagram', () => {
imgSnapshotTest( imgSnapshotTest(
@ -13,7 +13,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('1: should render a simple class diagram', () => { it('1: should render a simple class diagram', () => {
@ -47,7 +46,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('2: should render a simple class diagrams with cardinality', () => { it('2: should render a simple class diagrams with cardinality', () => {
@ -76,7 +74,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('should render a simple class diagram with different visibilities', () => { it('should render a simple class diagram with different visibilities', () => {
@ -94,7 +91,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('should render multiple class diagrams', () => { it('should render multiple class diagrams', () => {
@ -147,7 +143,6 @@ describe('Class diagram V2', () => {
], ],
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('4: should render a simple class diagram with comments', () => { it('4: should render a simple class diagram with comments', () => {
@ -177,7 +172,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('5: should render a simple class diagram with abstract method', () => { it('5: should render a simple class diagram with abstract method', () => {
@ -189,7 +183,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('6: should render a simple class diagram with static method', () => { it('6: should render a simple class diagram with static method', () => {
@ -201,7 +194,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('7: should render a simple class diagram with Generic class', () => { it('7: should render a simple class diagram with Generic class', () => {
@ -221,7 +213,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('8: should render a simple class diagram with Generic class and relations', () => { it('8: should render a simple class diagram with Generic class and relations', () => {
@ -242,7 +233,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('9: should render a simple class diagram with clickable link', () => { it('9: should render a simple class diagram with clickable link', () => {
@ -264,7 +254,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('10: should render a simple class diagram with clickable callback', () => { it('10: should render a simple class diagram with clickable callback', () => {
@ -286,7 +275,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('11: should render a simple class diagram with return type on method', () => { it('11: should render a simple class diagram with return type on method', () => {
@ -301,7 +289,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('12: should render a simple class diagram with generic types', () => { it('12: should render a simple class diagram with generic types', () => {
@ -317,7 +304,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('13: should render a simple class diagram with css classes applied', () => { it('13: should render a simple class diagram with css classes applied', () => {
@ -335,7 +321,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('14: should render a simple class diagram with css classes applied directly', () => { it('14: should render a simple class diagram with css classes applied directly', () => {
@ -351,7 +336,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('15: should render a simple class diagram with css classes applied two multiple classes', () => { it('15: should render a simple class diagram with css classes applied two multiple classes', () => {
@ -365,7 +349,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('16a: should render a simple class diagram with static field', () => { it('16a: should render a simple class diagram with static field', () => {
@ -378,7 +361,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('16b: should handle the direction statement with TB', () => { it('16b: should handle the direction statement with TB', () => {
@ -403,32 +385,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
});
it('18: should handle the direction statement with LR', () => {
imgSnapshotTest(
`
classDiagram
direction LR
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
`,
{ logLevel: 1, flowchart: { htmlLabels: false } }
);
cy.get('svg');
}); });
it('17a: should handle the direction statement with BT', () => { it('17a: should handle the direction statement with BT', () => {
imgSnapshotTest( imgSnapshotTest(
@ -452,7 +408,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('17b: should handle the direction statement with RL', () => { it('17b: should handle the direction statement with RL', () => {
imgSnapshotTest( imgSnapshotTest(
@ -476,10 +431,33 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('18: should render a simple class diagram with notes', () => { it('18a: should handle the direction statement with LR', () => {
imgSnapshotTest(
`
classDiagram
direction LR
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
`,
{ logLevel: 1, flowchart: { htmlLabels: false } }
);
});
it('18b: should render a simple class diagram with notes', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram-v2 classDiagram-v2
@ -493,7 +471,6 @@ describe('Class diagram V2', () => {
`, `,
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
cy.get('svg');
}); });
it('1433: should render a simple class with a title', () => { it('1433: should render a simple class with a title', () => {
@ -503,8 +480,95 @@ title: simple class diagram
--- ---
classDiagram-v2 classDiagram-v2
class Class10 class Class10
`, `
{} );
});
it('should render a class with text label', () => {
imgSnapshotTest(
`classDiagram
class C1["Class 1 with text label"]
C1 --> C2`
);
});
it('should render two classes with text labels', () => {
imgSnapshotTest(
`classDiagram
class C1["Class 1 with text label"]
class C2["Class 2 with chars @?"]
C1 --> C2`
);
});
it('should render a class with a text label, members and annotation', () => {
imgSnapshotTest(
`classDiagram
class C1["Class 1 with text label"] {
&lt;&lt;interface&gt;&gt;
+member1
}
C1 --> C2`
);
});
it('should render multiple classes with same text labels', () => {
imgSnapshotTest(
`classDiagram
class C1["Class with text label"]
class C2["Class with text label"]
class C3["Class with text label"]
C1 --> C2
C3 ..> C2
`
);
});
it('should render classes with different text labels', () => {
imgSnapshotTest(
`classDiagram
class C1["OneWord"]
class C2["With, Comma"]
class C3["With (Brackets)"]
class C4["With [Brackets]"]
class C5["With {Brackets}"]
class C7["With 1 number"]
class C8["With . period..."]
class C9["With - dash"]
class C10["With _ underscore"]
class C11["With ' single quote"]
class C12["With ~!@#$%^&*()_+=-/?"]
class C13["With Città foreign language"]
`
);
});
it('should render classLabel if class has already been defined earlier', () => {
imgSnapshotTest(
`classDiagram
Animal <|-- Duck
class Duck["Duck with text label"]
`
);
});
it('should add classes namespaces', function () {
imgSnapshotTest(
`
classDiagram
namespace Namespace1 {
class C1
class C2
}
C1 --> C2
class C3
class C4
`
);
});
it('should render a simple class diagram with no members', () => {
imgSnapshotTest(
`
classDiagram-v2
class Class10
`,
{ logLevel: 1, flowchart: { htmlLabels: false } }
); );
}); });
}); });

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('Class diagram', () => { describe('Class diagram', () => {
it('1: should render a simple class diagram', () => { it('1: should render a simple class diagram', () => {
@ -286,7 +286,7 @@ describe('Class diagram', () => {
cy.get('svg'); cy.get('svg');
}); });
it('15: should render a simple class diagram with css classes applied two multiple classes', () => { it('15: should render a simple class diagram with css classes applied to multiple classes', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
@ -423,4 +423,82 @@ describe('Class diagram', () => {
); );
cy.get('svg'); cy.get('svg');
}); });
it('should render class diagram with newlines in title', () => {
imgSnapshotTest(`
classDiagram
Animal <|-- \`Du\nck\`
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class \`Du\nck\` {
+String beakColor
+String featherColor
+swim()
+quack()
}
`);
cy.get('svg');
});
it('should render class diagram with many newlines in title', () => {
imgSnapshotTest(`
classDiagram
class \`This\nTitle\nHas\nMany\nNewlines\` {
+String Also
-Stirng Many
#int Members
+And()
-Many()
#Methods()
}
`);
});
it('should render with newlines in title and an annotation', () => {
imgSnapshotTest(`
classDiagram
class \`This\nTitle\nHas\nMany\nNewlines\` {
+String Also
-Stirng Many
#int Members
+And()
-Many()
#Methods()
}
&lt;&lt;Interface&gt;&gt; \`This\nTitle\nHas\nMany\nNewlines\`
`);
});
it('should handle newline title in namespace', () => {
imgSnapshotTest(`
classDiagram
namespace testingNamespace {
class \`This\nTitle\nHas\nMany\nNewlines\` {
+String Also
-Stirng Many
#int Members
+And()
-Many()
#Methods()
}
}
`);
});
it('should handle newline in string label', () => {
imgSnapshotTest(`
classDiagram
class A["This has\na newline!"] {
+String boop
-Int beep
#double bop
}
class B["This title also has\na newline"]
B : +with(more)
B : -methods()
`);
});
}); });

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest } from '../../helpers/util.js'; import { imgSnapshotTest } from '../../helpers/util.ts';
describe('Configuration and directives - nodes should be light blue', () => { describe('Configuration and directives - nodes should be light blue', () => {
it('No config - use default', () => { it('No config - use default', () => {
@ -14,7 +14,6 @@ describe('Configuration and directives - nodes should be light blue', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('Settings from initialize - nodes should be green', () => { it('Settings from initialize - nodes should be green', () => {
imgSnapshotTest( imgSnapshotTest(
@ -28,7 +27,6 @@ graph TD
end `, end `,
{ theme: 'forest' } { theme: 'forest' }
); );
cy.get('svg');
}); });
it('Settings from initialize overriding themeVariable - nodes should be red', () => { it('Settings from initialize overriding themeVariable - nodes should be red', () => {
imgSnapshotTest( imgSnapshotTest(
@ -46,7 +44,6 @@ graph TD
`, `,
{ theme: 'base', themeVariables: { primaryColor: '#ff0000' }, logLevel: 0 } { theme: 'base', themeVariables: { primaryColor: '#ff0000' }, logLevel: 0 }
); );
cy.get('svg');
}); });
it('Settings from directive - nodes should be grey', () => { it('Settings from directive - nodes should be grey', () => {
imgSnapshotTest( imgSnapshotTest(
@ -62,7 +59,24 @@ graph TD
`, `,
{} {}
); );
cy.get('svg'); });
it('Settings from frontmatter - nodes should be grey', () => {
imgSnapshotTest(
`
---
config:
theme: neutral
---
graph TD
A(Start) --> B[/Another/]
A[/Another/] --> C[End]
subgraph section
B
C
end
`,
{}
);
}); });
it('Settings from directive overriding theme variable - nodes should be red', () => { it('Settings from directive overriding theme variable - nodes should be red', () => {
@ -79,7 +93,6 @@ graph TD
`, `,
{} {}
); );
cy.get('svg');
}); });
it('Settings from initialize and directive - nodes should be grey', () => { it('Settings from initialize and directive - nodes should be grey', () => {
imgSnapshotTest( imgSnapshotTest(
@ -95,7 +108,6 @@ graph TD
`, `,
{ theme: 'forest' } { theme: 'forest' }
); );
cy.get('svg');
}); });
it('Theme from initialize, directive overriding theme variable - nodes should be red', () => { it('Theme from initialize, directive overriding theme variable - nodes should be red', () => {
imgSnapshotTest( imgSnapshotTest(
@ -111,8 +123,71 @@ graph TD
`, `,
{ theme: 'base' } { theme: 'base' }
); );
cy.get('svg');
}); });
it('Theme from initialize, frontmatter overriding theme variable - nodes should be red', () => {
imgSnapshotTest(
`
---
config:
theme: base
themeVariables:
primaryColor: '#ff0000'
---
graph TD
A(Start) --> B[/Another/]
A[/Another/] --> C[End]
subgraph section
B
C
end
`,
{ theme: 'forest' }
);
});
it('Theme from initialize, frontmatter overriding theme variable, directive overriding primaryColor - nodes should be red', () => {
imgSnapshotTest(
`
---
config:
theme: base
themeVariables:
primaryColor: '#00ff00'
---
%%{init: {'theme': 'base', 'themeVariables':{ 'primaryColor': '#ff0000'}}}%%
graph TD
A(Start) --> B[/Another/]
A[/Another/] --> C[End]
subgraph section
B
C
end
`,
{ theme: 'forest' }
);
});
it('should render if values are not quoted properly', () => {
// #ff0000 is not quoted properly, and will evaluate to null.
// This test ensures that the rendering still works.
imgSnapshotTest(
`---
config:
theme: base
themeVariables:
primaryColor: #ff0000
---
graph TD
A(Start) --> B[/Another/]
A[/Another/] --> C[End]
subgraph section
B
C
end
`,
{ theme: 'forest' }
);
});
it('Theme variable from initialize, theme from directive - nodes should be red', () => { it('Theme variable from initialize, theme from directive - nodes should be red', () => {
imgSnapshotTest( imgSnapshotTest(
` `
@ -127,13 +202,11 @@ graph TD
`, `,
{ themeVariables: { primaryColor: '#ff0000' } } { themeVariables: { primaryColor: '#ff0000' } }
); );
cy.get('svg');
}); });
describe('when rendering several diagrams', () => { describe('when rendering several diagrams', () => {
it('diagrams should not taint later diagrams', () => { it('diagrams should not taint later diagrams', () => {
const url = 'http://localhost:9000/theme-directives.html'; const url = 'http://localhost:9000/theme-directives.html';
cy.visit(url); cy.visit(url);
cy.get('svg');
cy.matchImageSnapshot('conf-and-directives.spec-when-rendering-several-diagrams-diagram-1'); cy.matchImageSnapshot('conf-and-directives.spec-when-rendering-several-diagrams-diagram-1');
}); });
}); });

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest } from '../../helpers/util'; import { imgSnapshotTest } from '../../helpers/util.ts';
describe('Current diagram', () => { describe('Current diagram', () => {
it('should render a state with states in it', () => { it('should render a state with states in it', () => {

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest } from '../../helpers/util'; import { imgSnapshotTest } from '../../helpers/util.ts';
describe('Flowchart', () => { describe('Flowchart', () => {
it('34: testing the label width in percy', () => { it('34: testing the label width in percy', () => {

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('Entity Relationship Diagram', () => { describe('Entity Relationship Diagram', () => {
it('should render a simple ER diagram', () => { it('should render a simple ER diagram', () => {
@ -10,7 +10,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render an ER diagram with a recursive relationship', () => { it('should render an ER diagram with a recursive relationship', () => {
@ -23,7 +22,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render an ER diagram with multiple relationships between the same two entities', () => { it('should render an ER diagram with multiple relationships between the same two entities', () => {
@ -35,7 +33,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render a cyclical ER diagram', () => { it('should render a cyclical ER diagram', () => {
@ -48,7 +45,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render a not-so-simple ER diagram', () => { it('should render a not-so-simple ER diagram', () => {
@ -66,7 +62,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render multiple ER diagrams', () => { it('should render multiple ER diagrams', () => {
@ -85,7 +80,6 @@ describe('Entity Relationship Diagram', () => {
], ],
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render an ER diagram with blank or empty labels', () => { it('should render an ER diagram with blank or empty labels', () => {
@ -98,7 +92,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render an ER diagrams when useMaxWidth is true (default)', () => { it('should render an ER diagrams when useMaxWidth is true (default)', () => {
@ -151,7 +144,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ er: { useMaxWidth: false } } { er: { useMaxWidth: false } }
); );
cy.get('svg');
}); });
it('should render entities with and without attributes', () => { it('should render entities with and without attributes', () => {
@ -164,7 +156,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render entities with generic and array attributes', () => { it('should render entities with generic and array attributes', () => {
@ -179,7 +170,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render entities with length in attributes type', () => { it('should render entities with length in attributes type', () => {
@ -193,7 +183,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render entities and attributes with big and small entity names', () => { it('should render entities and attributes with big and small entity names', () => {
@ -209,6 +198,26 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
});
it('should render entities with attributes that begin with asterisk', () => {
imgSnapshotTest(
`
erDiagram
BOOK {
int *id
string name
varchar(99) summary
}
BOOK }o..o{ STORE : soldBy
STORE {
int *id
string name
varchar(50) address
}
`,
{ loglevel: 1 }
);
cy.get('svg'); cy.get('svg');
}); });
@ -228,7 +237,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render entities with comments', () => { it('should render entities with comments', () => {
@ -247,7 +255,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render entities with keys and comments', () => { it('should render entities with keys and comments', () => {
@ -267,7 +274,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render entities with aliases', () => { it('should render entities with aliases', () => {
@ -285,7 +291,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('1433: should render a simple ER diagram with a title', () => { it('1433: should render a simple ER diagram with a title', () => {
@ -300,4 +305,21 @@ ORDER ||--|{ LINE-ITEM : contains
{} {}
); );
}); });
it('should render entities with entity name aliases', () => {
imgSnapshotTest(
`
erDiagram
p[Person] {
varchar(64) firstName
varchar(64) lastName
}
c["Customer Account"] {
varchar(128) email
}
p ||--o| c : has
`,
{ logLevel: 1 }
);
});
}); });

View File

@ -0,0 +1,45 @@
import { imgSnapshotTest } from '../../helpers/util';
describe('Error Diagrams', () => {
beforeEach(() => {
cy.on('uncaught:exception', (err) => {
expect(err.message).to.include('Parse error');
// return false to prevent the error from
// failing this test
return false;
});
});
it('should render a simple ER diagram', () => {
imgSnapshotTest(
`
error
`,
{ logLevel: 1 }
);
});
it('should render error diagram for actual errors', () => {
imgSnapshotTest(
`
flowchart TD
A[Christmas] --|Get money| B(Go shopping)
`,
{ logLevel: 1 }
);
});
it('should render error for wrong ER diagram', () => {
imgSnapshotTest(
`
erDiagram
ATLAS-ORGANIZATION ||--|{ ATLAS-PROJECTS : "has many"
ATLAS-PROJECTS ||--|{ MONGODB-CLUSTERS : "has many"
ATLAS-PROJECTS ||--|{ ATLAS-TEAMS : "has many"
MONGODB-CLUSTERS ||..|{
ATLAS-TEAMS ||..|{
`,
{ logLevel: 1 }
);
});
});

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('Flowchart ELK', () => { describe('Flowchart ELK', () => {
it('1-elk: should render a simple flowchart', () => { it('1-elk: should render a simple flowchart', () => {
@ -681,7 +681,166 @@ title: Simple flowchart
flowchart-elk TD flowchart-elk TD
A --> B A --> B
`, `,
{ titleTopMargin: 0 } { flowchart: { titleTopMargin: 0 } }
); );
}); });
it('elk: should include classes on the edges', () => {
renderGraph(
`flowchart-elk TD
A --> B --> C --> D
`,
{}
);
cy.get('svg').should((svg) => {
const edges = svg.querySelectorAll('.edges > path');
edges.forEach((edge) => {
expect(edge).to.have.class('flowchart-link');
});
});
});
describe('Markdown strings flowchart-elk (#4220)', () => {
describe('html labels', () => {
it('With styling and classes', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
flowchart-elk LR
A:::someclass --> B["\`The **cat** in the hat\`"]:::someclass
id1(Start)-->id2(Stop)
style id1 fill:#f9f,stroke:#333,stroke-width:4px
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
classDef someclass fill:#f96
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('With formatting in a node', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
flowchart-elk LR
a{"\`The **cat** in the hat\`"} -- 1o --> b
a -- 2o --> c
a -- 3o --> d
g --2i--> a
d --1i--> a
h --3i -->a
b --> d(The dog in the hog)
c --> d
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('New line in node and formatted edge label', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
flowchart-elk LR
b("\`The dog in **the** hog.(1)
NL\`") --"\`1o **bold**\`"--> c
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('Wrapping long text with a new line', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
flowchart-elk LR
b(\`The dog in **the** hog.(1).. a a a a *very long text* about it
Word!
Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. \`) --> c
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('Sub graphs and markdown strings', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
flowchart-elk LR
subgraph "One"
a("\`The **cat**
in the hat\`") -- "1o" --> b{{"\`The **dog** in the hog\`"}}
end
subgraph "\`**Two**\`"
c("\`The **cat**
in the hat\`") -- "\`1o **ipa**\`" --> d("The dog in the hog")
end
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
});
describe('svg text labels', () => {
it('With styling and classes', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": false}} }%%
flowchart-elk LR
A:::someclass --> B["\`The **cat** in the hat\`"]:::someclass
id1(Start)-->id2(Stop)
style id1 fill:#f9f,stroke:#333,stroke-width:4px
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
classDef someclass fill:#f96
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('With formatting in a node', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": false}} }%%
flowchart-elk LR
a{"\`The **cat** in the hat\`"} -- 1o --> b
a -- 2o --> c
a -- 3o --> d
g --2i--> a
d --1i--> a
h --3i -->a
b --> d(The dog in the hog)
c --> d
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('New line in node and formatted edge label', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": false}} }%%
flowchart-elk LR
b("\`The dog in **the** hog.(1)
NL\`") --"\`1o **bold**\`"--> c
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('Wrapping long text with a new line', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": false}} }%%
flowchart-elk LR
b("\`The dog in **the** hog.(1).. a a a a *very long text* about it
Word!
Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. \`") --> c
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('Sub graphs and markdown strings', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": false}} }%%
flowchart-elk LR
subgraph "One"
a("\`The **cat**
in the hat\`") -- "1o" --> b{{"\`The **dog** in the hog\`"}}
end
subgraph "\`**Two**\`"
c("\`The **cat**
in the hat\`") -- "\`1o **ipa**\`" --> d("The dog in the hog")
end
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
});
});
}); });

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('Flowchart v2', () => { describe('Flowchart v2', () => {
it('1: should render a simple flowchart', () => { it('1: should render a simple flowchart', () => {
@ -172,7 +172,7 @@ describe('Flowchart v2', () => {
); );
}); });
it('52: handle nested subgraphs in several levels', () => { it('52: handle nested subgraphs in several levels.', () => {
imgSnapshotTest( imgSnapshotTest(
`flowchart TB `flowchart TB
b-->B b-->B
@ -449,7 +449,7 @@ flowchart TD
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' } { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
); );
}); });
it('65: text-color from classes', () => { it('65-1: text-color from classes', () => {
imgSnapshotTest( imgSnapshotTest(
` `
flowchart LR flowchart LR
@ -460,6 +460,31 @@ flowchart TD
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' } { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
); );
}); });
it('65-2: bold text from classes', () => {
imgSnapshotTest(
`
flowchart
classDef cat fill:#f9d5e5, stroke:#233d4d,stroke-width:2px, font-weight:bold;
CS(A long bold text to be viewed):::cat
`,
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
);
});
it('65-3: bigger font from classes', () => {
imgSnapshotTest(
`
flowchart
Node1:::class1 --> Node2:::class2
Node1:::class1 --> Node3:::class2
Node3 --> Node4((I am a circle)):::larger
classDef class1 fill:lightblue
classDef class2 fill:pink
classDef larger font-size:30px,fill:yellow
`,
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
);
});
it('66: More nested subgraph cases (TB)', () => { it('66: More nested subgraph cases (TB)', () => {
imgSnapshotTest( imgSnapshotTest(
` `
@ -671,7 +696,182 @@ title: Simple flowchart
flowchart TD flowchart TD
A --> B A --> B
`, `,
{ titleTopMargin: 0 } { flowchart: { titleTopMargin: 10 } }
); );
}); });
it('3192: It should be possieble to render flowcharts with invisible edges', () => {
imgSnapshotTest(
`---
title: Simple flowchart with invisible edges
---
flowchart TD
A ~~~ B
`,
{ flowchart: { titleTopMargin: 10 } }
);
});
it('4023: Should render html labels with images and-or text correctly', () => {
imgSnapshotTest(
`flowchart TD
B[<img src='https://mermaid.js.org/mermaid-logo.svg'>]
B-->C[<img src="https://mermaid.js.org/mermaid-logo.svg"> more text <img src='https://mermaid.js.org/mermaid-logo.svg'>]
B-->D(<img src='https://mermaid.js.org/mermaid-logo.svg'> some text)
B-->E(plain)`,
{}
);
});
it('4439: Should render the graph even if some images are missing', () => {
imgSnapshotTest(
`flowchart TD
B[<img>]
B-->C[<img>]`,
{}
);
});
describe('Markdown strings flowchart (#4220)', () => {
describe('html labels', () => {
it('With styling and classes', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
flowchart LR
A:::someclass --> B["\`The **cat** in the hat\`"]:::someclass
id1(Start)-->id2(Stop)
style id1 fill:#f9f,stroke:#333,stroke-width:4px
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
classDef someclass fill:#f96
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('With formatting in a node', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
flowchart LR
a{"\`The **cat** in the hat\`"} -- 1o --> b
a -- 2o --> c
a -- 3o --> d
g --2i--> a
d --1i--> a
h --3i -->a
b --> d(The dog in the hog)
c --> d
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('New line in node and formatted edge label', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
flowchart LR
b("\`The dog in **the** hog.(1)
NL\`") --"\`1o **bold**\`"--> c
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('Wrapping long text with a new line', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
flowchart LR
b("\`The dog in **the** hog.(1).. a a a a *very long text* about it
Word!
Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. \`") --> c
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('Sub graphs and markdown strings', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": true}} }%%
flowchart LR
subgraph "One"
a("\`The **cat**
in the hat\`") -- "1o" --> b{{"\`The **dog** in the hog\`"}}
end
subgraph "\`**Two**\`"
c("\`The **cat**
in the hat\`") -- "\`1o **ipa**\`" --> d("The dog in the hog")
end
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
});
describe('svg text labels', () => {
it('With styling and classes', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": false}} }%%
flowchart LR
A:::someclass --> B["\`The **cat** in the hat\`"]:::someclass
id1(Start)-->id2(Stop)
style id1 fill:#f9f,stroke:#333,stroke-width:4px
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
classDef someclass fill:#f96
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('With formatting in a node', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": false}} }%%
flowchart LR
a{"\`The **cat** in the hat\`"} -- 1o --> b
a -- 2o --> c
a -- 3o --> d
g --2i--> a
d --1i--> a
h --3i -->a
b --> d(The dog in the hog)
c --> d
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('New line in node and formatted edge label', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": false}} }%%
flowchart LR
b("\`The dog in **the** hog.(1)
NL\`") --"\`1o **bold**\`"--> c
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('Wrapping long text with a new line', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": false}} }%%
flowchart LR
b("\`The dog in **the** hog.(1).. a a a a *very long text* about it
Word!
Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. \`") --> c
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('Sub graphs and markdown strings', () => {
imgSnapshotTest(
`%%{init: {"flowchart": {"htmlLabels": false}} }%%
flowchart LR
subgraph "One"
a("\`The **cat**
in the hat\`") -- "1o" --> b{{"\`The **dog** in the hog\`"}}
end
subgraph "\`**Two**\`"
c("\`The **cat**
in the hat\`") -- "\`1o **ipa**\`" --> d("The dog in the hog")
end
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
});
});
}); });

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('Graph', () => { describe('Graph', () => {
it('1: should render a simple flowchart no htmlLabels', () => { it('1: should render a simple flowchart no htmlLabels', () => {
@ -891,4 +891,27 @@ graph TD
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' } { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
); );
}); });
it('66: apply class called default on node called default', () => {
imgSnapshotTest(
`
graph TD
classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff
hello --> default
`,
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
);
});
it('67: should be able to style default node independently', () => {
imgSnapshotTest(
`
flowchart TD
classDef default fill:#a34
hello --> default
style default stroke:#000,stroke-width:4px
`,
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
);
});
}); });

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('Gantt diagram', () => { describe('Gantt diagram', () => {
beforeEach(() => { beforeEach(() => {
@ -133,6 +133,24 @@ describe('Gantt diagram', () => {
); );
}); });
it('should default to showing today marker', () => {
// This test only works if the environment thinks today is 1010-10-10
imgSnapshotTest(
`
gantt
title Show today marker (vertical line should be visible)
dateFormat YYYY-MM-DD
axisFormat %d
%% Should default to being on
%% todayMarker on
section Section1
Yesterday: 1010-10-09, 1d
Today: 1010-10-10, 1d
`,
{}
);
});
it('should hide today marker', () => { it('should hide today marker', () => {
imgSnapshotTest( imgSnapshotTest(
` `
@ -142,7 +160,8 @@ describe('Gantt diagram', () => {
axisFormat %d axisFormat %d
todayMarker off todayMarker off
section Section1 section Section1
Today: 1, -1h Yesterday: 1010-10-09, 1d
Today: 1010-10-10, 1d
`, `,
{} {}
); );
@ -157,7 +176,8 @@ describe('Gantt diagram', () => {
axisFormat %d axisFormat %d
todayMarker stroke-width:5px,stroke:#00f,opacity:0.5 todayMarker stroke-width:5px,stroke:#00f,opacity:0.5
section Section1 section Section1
Today: 1, -1h Yesterday: 1010-10-09, 1d
Today: 1010-10-10, 1d
`, `,
{} {}
); );
@ -310,6 +330,48 @@ describe('Gantt diagram', () => {
); );
}); });
it('should render a gantt diagram with tick is 2 milliseconds', () => {
imgSnapshotTest(
`
gantt
title A Gantt Diagram
dateFormat SSS
axisFormat %Lms
tickInterval 2millisecond
excludes weekends
section Section
A task : a1, 000, 6ms
Another task : after a1, 6ms
section Another
Task in sec : a2, 006, 3ms
another task : 3ms
`,
{}
);
});
it('should render a gantt diagram with tick is 2 seconds', () => {
imgSnapshotTest(
`
gantt
title A Gantt Diagram
dateFormat ss
axisFormat %Ss
tickInterval 2second
excludes weekends
section Section
A task : a1, 00, 6s
Another task : after a1, 6s
section Another
Task in sec : 06, 3s
another task : 3s
`,
{}
);
});
it('should render a gantt diagram with tick is 15 minutes', () => { it('should render a gantt diagram with tick is 15 minutes', () => {
imgSnapshotTest( imgSnapshotTest(
` `
@ -394,6 +456,28 @@ describe('Gantt diagram', () => {
); );
}); });
it('should render a gantt diagram with tick is 1 week, with the day starting on monday', () => {
imgSnapshotTest(
`
gantt
title A Gantt Diagram
dateFormat YYYY-MM-DD
axisFormat %m-%d
tickInterval 1week
weekday monday
excludes weekends
section Section
A task : a1, 2022-10-01, 30d
Another task : after a1, 20d
section Another
Task in sec : 2022-10-20, 12d
another task : 24d
`,
{}
);
});
it('should render a gantt diagram with tick is 1 month', () => { it('should render a gantt diagram with tick is 1 month', () => {
imgSnapshotTest( imgSnapshotTest(
` `
@ -435,4 +519,39 @@ describe('Gantt diagram', () => {
{ gantt: { topAxis: true } } { gantt: { topAxis: true } }
); );
}); });
it('should render when compact is true', () => {
imgSnapshotTest(
`
---
displayMode: compact
---
gantt
title GANTT compact
dateFormat HH:mm:ss
axisFormat %Hh%M
section DB Clean
Clean: 12:00:00, 10m
Clean: 12:30:00, 12m
Clean: 13:00:00, 8m
Clean: 13:30:00, 9m
Clean: 14:00:00, 13m
Clean: 14:30:00, 10m
Clean: 15:00:00, 11m
section Sessions
A: 12:00:00, 63m
B: 12:30:00, 12m
C: 13:05:00, 12m
D: 13:06:00, 33m
E: 13:15:00, 55m
F: 13:20:00, 12m
G: 13:32:00, 18m
H: 13:50:00, 20m
I: 14:10:00, 10m
`,
{}
);
});
}); });

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest } from '../../helpers/util.js'; import { imgSnapshotTest } from '../../helpers/util.ts';
describe('Git Graph diagram', () => { describe('Git Graph diagram', () => {
it('1: should render a simple gitgraph with commit on main branch', () => { it('1: should render a simple gitgraph with commit on main branch', () => {
@ -333,4 +333,372 @@ gitGraph
{} {}
); );
}); });
it('15: should render a simple gitgraph with commit on main branch | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id: "1"
commit id: "2"
commit id: "3"
`,
{}
);
});
it('16: should render a simple gitgraph with commit on main branch with Id | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id: "One"
commit id: "Two"
commit id: "Three"
`,
{}
);
});
it('17: should render a simple gitgraph with different commitTypes on main branch | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id: "Normal Commit"
commit id: "Reverse Commit" type: REVERSE
commit id: "Hightlight Commit" type: HIGHLIGHT
`,
{}
);
});
it('18: should render a simple gitgraph with tags commitTypes on main branch | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id: "Normal Commit with tag" tag: "v1.0.0"
commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1"
commit id: "Hightlight Commit" type: HIGHLIGHT tag: "8.8.4"
`,
{}
);
});
it('19: should render a simple gitgraph with two branches | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id: "1"
commit id: "2"
branch develop
checkout develop
commit id: "3"
commit id: "4"
checkout main
commit id: "5"
commit id: "6"
`,
{}
);
});
it('20: should render a simple gitgraph with two branches and merge commit | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id: "1"
commit id: "2"
branch develop
checkout develop
commit id: "3"
commit id: "4"
checkout main
merge develop
commit id: "5"
commit id: "6"
`,
{}
);
});
it('21: should render a simple gitgraph with three branches and tagged merge commit | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id: "1"
commit id: "2"
branch nice_feature
checkout nice_feature
commit id: "3"
checkout main
commit id: "4"
checkout nice_feature
branch very_nice_feature
checkout very_nice_feature
commit id: "5"
checkout main
commit id: "6"
checkout nice_feature
commit id: "7"
checkout main
merge nice_feature id: "12345" tag: "my merge commit"
checkout very_nice_feature
commit id: "8"
checkout main
commit id: "9"
`,
{}
);
});
it('22: should render a simple gitgraph with more than 8 branchs & overriding variables | Vertical Branch', () => {
imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'gitBranchLabel0': '#ffffff',
'gitBranchLabel1': '#ffffff',
'gitBranchLabel2': '#ffffff',
'gitBranchLabel3': '#ffffff',
'gitBranchLabel4': '#ffffff',
'gitBranchLabel5': '#ffffff',
'gitBranchLabel6': '#ffffff',
'gitBranchLabel7': '#ffffff',
} } }%%
gitGraph TB:
checkout main
branch branch1
branch branch2
branch branch3
branch branch4
branch branch5
branch branch6
branch branch7
branch branch8
branch branch9
checkout branch1
commit id: "1"
`,
{}
);
});
it('23: should render a simple gitgraph with rotated labels | Vertical Branch', () => {
imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'gitGraph': {
'rotateCommitLabel': true
} } }%%
gitGraph TB:
commit id: "75f7219e83b321cd3fdde7dcf83bc7c1000a6828"
commit id: "0db4784daf82736dec4569e0dc92980d328c1f2e"
commit id: "7067e9973f9eaa6cd4a4b723c506d1eab598e83e"
commit id: "66972321ad6c199013b5b31f03b3a86fa3f9817d"
`,
{}
);
});
it('24: should render a simple gitgraph with horizontal labels | Vertical Branch', () => {
imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'gitGraph': {
'rotateCommitLabel': false
} } }%%
gitGraph TB:
commit id: "Alpha"
commit id: "Beta"
commit id: "Gamma"
commit id: "Delta"
`,
{}
);
});
it('25: should render a simple gitgraph with cherry pick commit | Vertical Branch', () => {
imgSnapshotTest(
`
gitGraph TB:
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
checkout develop
commit id:"C"
`,
{}
);
});
it('26: should render a gitgraph with cherry pick commit with custom tag | Vertical Branch', () => {
imgSnapshotTest(
`
gitGraph TB:
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
commit id:"TWO"
cherry-pick id:"A" tag: "snapshot"
commit id:"THREE"
checkout develop
commit id:"C"
`,
{}
);
});
it('27: should render a gitgraph with cherry pick commit with no tag | Vertical Branch', () => {
imgSnapshotTest(
`
gitGraph TB:
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
commit id:"TWO"
cherry-pick id:"A" tag: ""
commit id:"THREE"
checkout develop
commit id:"C"
`,
{}
);
});
it('28: should render a simple gitgraph with two cherry pick commit | Vertical Branch', () => {
imgSnapshotTest(
`
gitGraph TB:
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
branch featureA
commit id:"FIX"
commit id: "FIX-2"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
cherry-pick id:"FIX"
checkout develop
commit id:"C"
merge featureA
`,
{}
);
});
it('29: should render commits for more than 8 branches | Vertical Branch', () => {
imgSnapshotTest(
`
gitGraph TB:
checkout main
%% Make sure to manually set the ID of all commits, for consistent visual tests
commit id: "1-abcdefg"
checkout main
branch branch1
commit id: "2-abcdefg"
checkout main
merge branch1
branch branch2
commit id: "3-abcdefg"
checkout main
merge branch2
branch branch3
commit id: "4-abcdefg"
checkout main
merge branch3
branch branch4
commit id: "5-abcdefg"
checkout main
merge branch4
branch branch5
commit id: "6-abcdefg"
checkout main
merge branch5
branch branch6
commit id: "7-abcdefg"
checkout main
merge branch6
branch branch7
commit id: "8-abcdefg"
checkout main
merge branch7
branch branch8
commit id: "9-abcdefg"
checkout main
merge branch8
branch branch9
commit id: "10-abcdefg"
`,
{}
);
});
it('30: should render a simple gitgraph with three branches,custom merge commit id,tag,type | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id: "1"
commit id: "2"
branch nice_feature
checkout nice_feature
commit id: "3"
checkout main
commit id: "4"
checkout nice_feature
branch very_nice_feature
checkout very_nice_feature
commit id: "5"
checkout main
commit id: "6"
checkout nice_feature
commit id: "7"
checkout main
merge nice_feature id: "customID" tag: "customTag" type: REVERSE
checkout very_nice_feature
commit id: "8"
checkout main
commit id: "9"
`,
{}
);
});
it('31: should render a simple gitgraph with a title | Vertical Branch', () => {
imgSnapshotTest(
`---
title: simple gitGraph
---
gitGraph TB:
commit id: "1-abcdefg"
`,
{}
);
});
it('32: should render a simple gitgraph overlapping commits | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id:"s1"
commit id:"s2"
branch branch1
commit id:"s3"
commit id:"s4"
checkout main
commit id:"s5"
checkout branch1
commit id:"s6"
commit id:"s7"
merge main
`,
{}
);
});
it('33: should render a simple gitgraph overlapping commits', () => {
imgSnapshotTest(
`gitGraph
commit id:"s1"
commit id:"s2"
branch branch1
commit id:"s3"
commit id:"s4"
checkout main
commit id:"s5"
checkout branch1
commit id:"s6"
commit id:"s7"
merge main
`,
{}
);
});
}); });

View File

@ -1,13 +0,0 @@
import { imgSnapshotTest } from '../../helpers/util.js';
describe('Sequencediagram', () => {
it('should render a simple info diagrams', () => {
imgSnapshotTest(
`
info
showInfo
`,
{}
);
});
});

View File

@ -0,0 +1,11 @@
import { imgSnapshotTest } from '../../helpers/util.ts';
describe('info diagram', () => {
it('should handle an info definition', () => {
imgSnapshotTest(`info`);
});
it('should handle an info definition with showInfo', () => {
imgSnapshotTest(`info showInfo`);
});
});

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('User journey diagram', () => { describe('User journey diagram', () => {
it('Simple test', () => { it('Simple test', () => {

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest } from '../../helpers/util.js'; import { imgSnapshotTest } from '../../helpers/util.ts';
/** /**
* Check whether the SVG Element has a Mindmap root * Check whether the SVG Element has a Mindmap root
@ -52,6 +52,17 @@ root[A root with a long text that wraps to keep the node size in check]
); );
}); });
it('a root with wrapping text and long words that exceed width', () => {
imgSnapshotTest(
`mindmap
root[A few smaller words but then averylongsetofcharacterswithoutwhitespacetoseparate that we expect to wrapontonextlinesandnotexceedwidthparameters]
`,
{},
undefined,
shouldHaveRoot
);
});
it('a root with an icon', () => { it('a root with an icon', () => {
imgSnapshotTest( imgSnapshotTest(
`mindmap `mindmap
@ -223,5 +234,17 @@ mindmap
shouldHaveRoot shouldHaveRoot
); );
}); });
describe('Markdown strings mindmaps (#4220)', () => {
it('Formatted label with linebreak and a wrapping label and emojis', () => {
imgSnapshotTest(
`mindmap
id1[\`**Start** with
a second line 😎\`]
id2[\`The dog in **the** hog... a *very long text* about it
Word!\`]
`
);
});
});
/* The end */ /* The end */
}); });

View File

@ -1,78 +1,85 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('Pie Chart', () => { describe('pie chart', () => {
it('should render a simple pie diagram', () => { it('should render a simple pie diagram', () => {
imgSnapshotTest( imgSnapshotTest(
`pie title Sports in Sweden
"Bandy": 40
"Ice-Hockey": 80
"Football": 90
` `
pie title Sports in Sweden
"Bandy" : 40
"Ice-Hockey" : 80
"Football" : 90
`,
{}
); );
cy.get('svg');
}); });
it('should render a simple pie diagram with long labels', () => { it('should render a simple pie diagram with long labels', () => {
imgSnapshotTest( imgSnapshotTest(
`pie title NETFLIX
"Time spent looking for movie": 90
"Time spent watching it": 10
` `
pie title NETFLIX
"Time spent looking for movie" : 90
"Time spent watching it" : 10
`,
{}
); );
cy.get('svg');
}); });
it('should render a simple pie diagram with capital letters for labels', () => { it('should render a simple pie diagram with capital letters for labels', () => {
imgSnapshotTest( imgSnapshotTest(
`pie title What Voldemort doesn't have?
"FRIENDS": 2
"FAMILY": 3
"NOSE": 45
` `
pie title What Voldemort doesn't have?
"FRIENDS" : 2
"FAMILY" : 3
"NOSE" : 45
`,
{}
); );
cy.get('svg');
}); });
it('should render a pie diagram when useMaxWidth is true (default)', () => { it('should render a pie diagram when useMaxWidth is true (default)', () => {
renderGraph( renderGraph(
` `pie title Sports in Sweden
pie title Sports in Sweden "Bandy": 40
"Bandy" : 40 "Ice-Hockey": 80
"Ice-Hockey" : 80 "Football": 90
"Football" : 90
`, `,
{ pie: { useMaxWidth: true } } { pie: { useMaxWidth: true } }
); );
cy.get('svg').should((svg) => { cy.get('svg').should((svg) => {
expect(svg).to.have.attr('width', '100%'); expect(svg).to.have.attr('width', '100%');
// expect(svg).to.have.attr('height');
// const height = parseFloat(svg.attr('height'));
// expect(height).to.eq(450);
const style = svg.attr('style'); const style = svg.attr('style');
expect(style).to.match(/^max-width: [\d.]+px;$/); expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
expect(maxWidthValue).to.eq(984); expect(maxWidthValue).to.eq(984);
}); });
}); });
it('should render a pie diagram when useMaxWidth is false', () => { it('should render a pie diagram when useMaxWidth is false', () => {
renderGraph( renderGraph(
` `pie title Sports in Sweden
pie title Sports in Sweden "Bandy": 40
"Bandy" : 40 "Ice-Hockey": 80
"Ice-Hockey" : 80 "Football": 90
"Football" : 90
`, `,
{ pie: { useMaxWidth: false } } { pie: { useMaxWidth: false } }
); );
cy.get('svg').should((svg) => { cy.get('svg').should((svg) => {
// const height = parseFloat(svg.attr('height'));
const width = parseFloat(svg.attr('width')); const width = parseFloat(svg.attr('width'));
// expect(height).to.eq(450);
expect(width).to.eq(984); expect(width).to.eq(984);
expect(svg).to.not.have.attr('style'); expect(svg).to.not.have.attr('style');
}); });
}); });
it('should render a pie diagram when textPosition is setted', () => {
imgSnapshotTest(
`pie
"Dogs": 50
"Cats": 25
`,
{ logLevel: 1, pie: { textPosition: 0.9 } }
);
});
it('should render a pie diagram with showData', () => {
imgSnapshotTest(
`pie showData
"Dogs": 50
"Cats": 25
`
);
});
}); });

View File

@ -0,0 +1,163 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('Quadrant Chart', () => {
it('should render if only chart type is provided', () => {
imgSnapshotTest(
`
quadrantChart
`,
{}
);
cy.get('svg');
});
it('should render a complete quadrant chart', () => {
imgSnapshotTest(
`
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.3, 0.6]
Campaign B: [0.45, 0.23]
Campaign C: [0.57, 0.69]
Campaign D: [0.78, 0.34]
Campaign E: [0.40, 0.34]
Campaign F: [0.35, 0.78]
`,
{}
);
cy.get('svg');
});
it('should render without points', () => {
imgSnapshotTest(
`
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
`,
{}
);
cy.get('svg');
});
it('should able to render y-axix on right side', () => {
imgSnapshotTest(
`
%%{init: {"quadrantChart": {"yAxisPosition": "right"}}}%%
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
`,
{}
);
cy.get('svg');
});
it('should able to render x-axix on bottom', () => {
imgSnapshotTest(
`
%%{init: {"quadrantChart": {"xAxisPosition": "bottom"}}}%%
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
`,
{}
);
cy.get('svg');
});
it('should able to render x-axix on bottom and y-axis on right', () => {
imgSnapshotTest(
`
%%{init: {"quadrantChart": {"xAxisPosition": "bottom", "yAxisPosition": "right"}}}%%
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
`,
{}
);
cy.get('svg');
});
it('should render without title', () => {
imgSnapshotTest(
`
quadrantChart
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
`,
{}
);
cy.get('svg');
});
it('should use all the config', () => {
imgSnapshotTest(
`
%%{init: {"quadrantChart": {"chartWidth": 600, "chartHeight": 600, "titlePadding": 20, "titleFontSize": 10, "quadrantPadding": 20, "quadrantTextTopPadding": 40, "quadrantLabelFontSize": 20, "quadrantInternalBorderStrokeWidth": 3, "quadrantExternalBorderStrokeWidth": 5, "xAxisLabelPadding": 20, "xAxisLabelFontSize": 20, "yAxisLabelPadding": 20, "yAxisLabelFontSize": 20, "pointTextPadding": 20, "pointLabelFontSize": 20, "pointRadius": 10 }}}%%
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.3, 0.6]
Campaign B: [0.45, 0.23]
Campaign C: [0.57, 0.69]
Campaign D: [0.78, 0.34]
Campaign E: [0.40, 0.34]
Campaign F: [0.35, 0.78]
`,
{}
);
cy.get('svg');
});
it('should use all the theme variable', () => {
imgSnapshotTest(
`
%%{init: {"themeVariables": {"quadrant1Fill": "#b4dcff","quadrant2Fill": "#fef0ff", "quadrant3Fill": "#fffaf0", "quadrant4Fill": "#f0fff2", "quadrant1TextFill": "#ff0000", "quadrant2TextFill": "#2d00df", "quadrant3TextFill": "#00ffda", "quadrant4TextFill": "#e68300", "quadrantPointFill": "#0149ff", "quadrantPointTextFill": "#dc00ff", "quadrantXAxisTextFill": "#ffb500", "quadrantYAxisTextFill": "#fae604", "quadrantInternalBorderStrokeFill": "#3636f2", "quadrantExternalBorderStrokeFill": "#ff1010", "quadrantTitleFill": "#00ea19"} }}%%
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.3, 0.6]
Campaign B: [0.45, 0.23]
Campaign C: [0.57, 0.69]
Campaign D: [0.78, 0.34]
Campaign E: [0.40, 0.34]
Campaign F: [0.35, 0.78]
`,
{}
);
cy.get('svg');
});
});

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('Requirement diagram', () => { describe('Requirement diagram', () => {
it('sample', () => { it('sample', () => {

View File

@ -0,0 +1,144 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('Sankey Diagram', () => {
it('should render a simple example', () => {
imgSnapshotTest(
`
sankey-beta
sourceNode,targetNode,10
`,
{}
);
});
describe('when given a linkColor', function () {
this.beforeAll(() => {
cy.wrap(
`sankey-beta
a,b,10
`
).as('graph');
});
it('links should use hex color', function () {
renderGraph(this.graph, { sankey: { linkColor: '#636465' } });
cy.get('.link path').should((link) => {
expect(link.attr('stroke')).to.equal('#636465');
});
});
it('links should be the same color as source node', function () {
renderGraph(this.graph, { sankey: { linkColor: 'source' } });
cy.get('.link path').then((link) => {
cy.get('.node[id="node-1"] rect').should((node) =>
expect(link.attr('stroke')).to.equal(node.attr('fill'))
);
});
});
it('links should be the same color as target node', function () {
renderGraph(this.graph, { sankey: { linkColor: 'target' } });
cy.get('.link path').then((link) => {
cy.get('.node[id="node-2"] rect').should((node) =>
expect(link.attr('stroke')).to.equal(node.attr('fill'))
);
});
});
it('links must be gradient', function () {
renderGraph(this.graph, { sankey: { linkColor: 'gradient' } });
cy.get('.link path').should((link) => {
expect(link.attr('stroke')).to.equal('url(#linearGradient-3)');
});
});
});
describe('when given a nodeAlignment', function () {
this.beforeAll(() => {
cy.wrap(
`
sankey-beta
a,b,8
b,c,8
c,d,8
d,e,8
x,c,4
c,y,4
`
).as('graph');
});
this.afterEach(() => {
cy.get('.node[id="node-1"]').should((node) => {
expect(node.attr('x')).to.equal('0');
});
cy.get('.node[id="node-2"]').should((node) => {
expect(node.attr('x')).to.equal('100');
});
cy.get('.node[id="node-3"]').should((node) => {
expect(node.attr('x')).to.equal('200');
});
cy.get('.node[id="node-4"]').should((node) => {
expect(node.attr('x')).to.equal('300');
});
cy.get('.node[id="node-5"]').should((node) => {
expect(node.attr('x')).to.equal('400');
});
});
it('should justify nodes', function () {
renderGraph(this.graph, {
sankey: { nodeAlignment: 'justify', width: 410, useMaxWidth: false },
});
cy.get('.node[id="node-6"]').should((node) => {
expect(node.attr('x')).to.equal('0');
});
cy.get('.node[id="node-7"]').should((node) => {
expect(node.attr('x')).to.equal('400');
});
});
it('should align nodes left', function () {
renderGraph(this.graph, {
sankey: { nodeAlignment: 'left', width: 410, useMaxWidth: false },
});
cy.get('.node[id="node-6"]').should((node) => {
expect(node.attr('x')).to.equal('0');
});
cy.get('.node[id="node-7"]').should((node) => {
expect(node.attr('x')).to.equal('300');
});
});
it('should align nodes right', function () {
renderGraph(this.graph, {
sankey: { nodeAlignment: 'right', width: 410, useMaxWidth: false },
});
cy.get('.node[id="node-6"]').should((node) => {
expect(node.attr('x')).to.equal('100');
});
cy.get('.node[id="node-7"]').should((node) => {
expect(node.attr('x')).to.equal('400');
});
});
it('should center nodes', function () {
renderGraph(this.graph, {
sankey: { nodeAlignment: 'center', width: 410, useMaxWidth: false },
});
cy.get('.node[id="node-6"]').should((node) => {
expect(node.attr('x')).to.equal('100');
});
cy.get('.node[id="node-7"]').should((node) => {
expect(node.attr('x')).to.equal('300');
});
});
});
});

View File

@ -1,6 +1,6 @@
/// <reference types="Cypress" /> /// <reference types="Cypress" />
import { imgSnapshotTest, renderGraph } from '../../helpers/util'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
context('Sequence diagram', () => { context('Sequence diagram', () => {
it('should render a sequence diagram with boxes', () => { it('should render a sequence diagram with boxes', () => {
@ -88,6 +88,16 @@ context('Sequence diagram', () => {
{} {}
); );
}); });
it('should handle empty lines', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice->>John: Hello John<br/>
John-->>Alice: Great<br/><br/>day!
`,
{}
);
});
it('should handle line breaks and wrap annotations', () => { it('should handle line breaks and wrap annotations', () => {
imgSnapshotTest( imgSnapshotTest(
` `
@ -116,7 +126,109 @@ context('Sequence diagram', () => {
loop Loopy loop Loopy
Bob->>Alice: Pasten Bob->>Alice: Pasten
end `, end `,
{ wrap: true } {
sequence: {
wrap: true,
},
}
);
});
it('should render a sequence diagram with par_over', () => {
imgSnapshotTest(
`
sequenceDiagram
participant Alice
participant Bob
participant John
par_over Section title
Alice ->> Bob: Message 1<br>Second line
Bob ->> John: Message 2
end
par_over Two line<br>section title
Note over Alice: Alice note
Note over Bob: Bob note<br>Second line
Note over John: John note
end
par_over Mixed section
Alice ->> Bob: Message 1
Note left of Bob: Alice/Bob Note
end
`
);
});
it('should render a sequence diagram with basic actor creation and destruction', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice ->> Bob: Hello Bob, how are you ?
Bob ->> Alice: Fine, thank you. And you?
create participant Polo
Alice ->> Polo: Hi Polo!
create actor Ola1 as Ola
Polo ->> Ola1: Hiii
Ola1 ->> Alice: Hi too
destroy Ola1
Alice --x Ola1: Bye!
Alice ->> Bob: And now?
create participant Ola2 as Ola
Alice ->> Ola2: Hello again
destroy Alice
Alice --x Ola2: Bye for me!
destroy Bob
Ola2 --> Bob: The end
`
);
});
it('should render a sequence diagram with actor creation and destruction coupled with backgrounds, loops and notes', () => {
imgSnapshotTest(
`
sequenceDiagram
accTitle: test the accTitle
accDescr: Test a description
participant Alice
participant Bob
autonumber 10 10
rect rgb(200, 220, 100)
rect rgb(200, 255, 200)
Alice ->> Bob: Hello Bob, how are you?
create participant John as John<br />Second Line
Bob-->>John: How about you John?
end
Bob--x Alice: I am good thanks!
Bob-x John: I am good thanks!
Note right of John: John thinks a long<br />long time, so long<br />that the text does<br />not fit on a row.
Bob-->Alice: Checking with John...
Note over John:wrap: John looks like he's still thinking, so Bob prods him a bit.
Bob-x John: Hey John - we're still waiting to know<br />how you're doing
Note over John:nowrap: John's trying hard not to break his train of thought.
destroy John
Bob-x John: John! Cmon!
Note over John: After a few more moments, John<br />finally snaps out of it.
end
autonumber off
alt either this
create actor Lola
Alice->>+Lola: Yes
Lola-->>-Alice: OK
else or this
autonumber
Alice->>Lola: No
else or this will happen
Alice->Lola: Maybe
end
autonumber 200
par this happens in parallel
destroy Bob
Alice -->> Bob: Parallel message 1
and
Alice -->> Lola: Parallel message 2
end
`
); );
}); });
context('font settings', () => { context('font settings', () => {

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('State diagram', () => { describe('State diagram', () => {
it('v2 should render a simple info', () => { it('v2 should render a simple info', () => {

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('State diagram', () => { describe('State diagram', () => {
it('should render a simple state diagrams', () => { it('should render a simple state diagrams', () => {

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest } from '../../helpers/util.js'; import { imgSnapshotTest } from '../../helpers/util.ts';
describe('themeCSS balancing, it', () => { describe('themeCSS balancing, it', () => {
it('should not allow unbalanced CSS definitions', () => { it('should not allow unbalanced CSS definitions', () => {

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest } from '../../helpers/util.js'; import { imgSnapshotTest } from '../../helpers/util.ts';
describe('Timeline diagram', () => { describe('Timeline diagram', () => {
it('1: should render a simple timeline with no specific sections', () => { it('1: should render a simple timeline with no specific sections', () => {

View File

@ -0,0 +1,19 @@
import { imgSnapshotTest } from '../../helpers/util.ts';
describe('Zen UML', () => {
it('Basic Zen UML diagram', () => {
imgSnapshotTest(
`
zenuml
A.method() {
if(x) {
B.method() {
selfCall() { return X }
}
}
}
`,
{}
);
});
});

View File

@ -188,7 +188,7 @@ mindmap
//import mindmap from '../../packages/mermaid-mindmap/src/detector'; //import mindmap from '../../packages/mermaid-mindmap/src/detector';
// import example from '../../packages/mermaid-example-diagram/src/detector'; // import example from '../../packages/mermaid-example-diagram/src/detector';
// import timeline from '../../packages/mermaid-timeline/src/detector'; // import timeline from '../../packages/mermaid-timeline/src/detector';
import mermaid from '../../packages/mermaid/src/mermaid'; import mermaid from './mermaid.esm.mjs';
// await mermaid.registerExternalDiagrams([]); // await mermaid.registerExternalDiagrams([]);
mermaid.parseError = function (err, hash) { mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err); // console.error('Mermaid error: ', err);

View File

@ -1,4 +1,5 @@
import mermaid from '../../packages/mermaid/src/mermaid'; // TODO: this file should be testing the ./mermaid.core.mjs file, as that's the file listed in the package.json file that users will use
import mermaid from './mermaid.esm.mjs';
let code = `flowchart LR let code = `flowchart LR
Power_Supply --> Transmitter_A Power_Supply --> Transmitter_A

View File

@ -12,7 +12,6 @@
<style> <style>
body { body {
background: rgb(221, 208, 208); background: rgb(221, 208, 208);
/*background:#333;*/
font-family: 'Arial'; font-family: 'Arial';
} }
h1 { h1 {
@ -120,17 +119,9 @@ classE o-- classF : aggregation
}; };
mermaid.initialize({ mermaid.initialize({
theme: 'default', theme: 'default',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0, logLevel: 0,
flowchart: { curve: 'linear', htmlLabels: true }, flowchart: { curve: 'linear', htmlLabels: true },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true }, sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"arial", sans-serif',
// themeVariables: {
// fontFamily: '"arial", sans-serif',
// },
curve: 'linear', curve: 'linear',
securityLevel: 'loose', securityLevel: 'loose',
}); });

View File

@ -11,9 +11,9 @@ example-diagram
<!-- <script src="//cdn.jsdelivr.net/npm/mermaid@9.1.7/dist/mermaid.min.js"></script> --> <!-- <script src="//cdn.jsdelivr.net/npm/mermaid@9.1.7/dist/mermaid.min.js"></script> -->
<!-- <script type="module" src="./external-diagrams-mindmap.mjs" /> --> <!-- <script type="module" src="./external-diagrams-mindmap.mjs" /> -->
<script type="module"> <script type="module">
import exampleDiagram from '../../packages/mermaid-example-diagram/src/detector'; import exampleDiagram from '../../packages/mermaid-example-diagram/dist/mermaid-example-diagram.core.mjs';
// import example from '../../packages/mermaid-example-diagram/src/detector'; // import example from '../../packages/mermaid-example-diagram/src/detector';
import mermaid from '../../packages/mermaid/src/mermaid'; import mermaid from './mermaid.esm.mjs';
await mermaid.registerExternalDiagrams([exampleDiagram]); await mermaid.registerExternalDiagrams([exampleDiagram]);
await mermaid.initialize({ logLevel: 0 }); await mermaid.initialize({ logLevel: 0 });

View File

@ -0,0 +1,46 @@
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
<style>
body {
font-family: 'trebuchet ms', verdana, arial;
}
</style>
</head>
<body>
<pre class="mermaid">
graph TB
subgraph One
a1-->a2-->a3
end
</pre>
<pre class="mermaid">
graph TB
a_a --> b_b:::apa --> c_c:::apa
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
class a_a apa;
</pre>
<pre class="mermaid">
graph TB
a_a(Aftonbladet) --> b_b[gorilla]:::apa --> c_c{chimp}:::apa -->a_a
a_a --> c --> d_d --> c_c
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
class a_a apa;
click a_a "http://www.aftonbladet.se" "apa"
</pre>
<script type="module">
import mermaid from './mermaid.esm.mjs';
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
logLevel: 3,
flowchart: { curve: 'linear' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>
</body>
</html>

View File

@ -1,23 +0,0 @@
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
</head>
<body>
<h1>info below</h1>
<pre class="mermaid">
info
</pre>
<script type="module">
import mermaid from './mermaid.esm.mjs';
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
logLevel: 3,
flowchart: { curve: 'linear' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>
</body>
</html>

View File

@ -42,368 +42,86 @@
</style> </style>
</head> </head>
<body> <body>
<pre class="mermaid2" style="width: 50%"> <pre class="mermaid" style="width: 50%">
flowchart LR %%{init: {"flowchart": {"htmlLabels": true}} }%%
subgraph one flowchart LR
direction LR b("`The dog in **the** hog.(1).. a a a a *very long text* about it
A[myClass1] --> B[default] Word!
subgraph two
direction BT
C[myClass2] --> D[default]
end
end
Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words.`") --apa--> c
</pre
>
<pre class="mermaid" style="width: 50%">
classDiagram-v2
classA -- classB : Inheritance
classA -- classC : link
classC -- classD : link
classB -- classD
</pre> </pre>
<pre class="mermaid2" style="width: 50%"> <pre class="mermaid" style="width: 50%">
flowchart LR sequenceDiagram
classDef aPID stroke:#4e4403,fill:#fdde29,color:#4e4403,rx:5px,ry:5px; Alice->>Bob: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
classDef crm stroke:#333333,fill:#DCDCDC,color:#333333,rx:5px,ry:5px; loop Loopy
classDef type stroke:#502604,fill:#FAB565,color:#502604,rx:20px,ry:20px;; Bob->>Alice: Pasten
end
O0("Joe")
class O0 aPID;
O1("Person")
class O1 crm;
O0 -- has type -->O1["Person"]
O2("aat:300411314")
class O2 type;
click O2 function "Sorry the newline html tags are not being processed correctly<br/> So all of this appears on the <br/> same line."
O0 -- has type -->O2["Bug"]
click O0 function "Lots of great info about Joe<br>Lots of great info about Joe<br>burt<br>fred";
</pre> </pre>
<pre class="mermaid2" style="width: 50%"> <pre class="mermaid" style="width: 50%">
flowchart TD %%{init: {"flowchart": {"htmlLabels": false}} }%%
subgraph test flowchart LR
direction TB b("`The dog in **the** hog.(1)
subgraph test2 NL`") --"`1o **bold**`"--> c[new strings svg labels]
direction LR
F --> D
end
subgraph test3
direction TB
G --> H
end
end
</pre> </pre>
<pre class="mermaid2" style="width: 50%"> <pre class="mermaid" style="width: 50%">
flowchart TD %%{init: {"flowchart": {"htmlLabels": true}} }%%
flowchart LR
release-branch[Create Release Branch]:::relClass b("`The dog in **the** hog.(1)
develop-branch[Update Develop Branch]:::relClass NL`") --"`1o **bold**`"--> c[new strings html labels]
github-release-draft[GitHub Release Draft]:::relClass
trigger-pipeline[Trigger Jenkins pipeline]:::fixClass
github-release[GitHub Release]:::postClass
build-ready --> release-branch
build-ready --> develop-branch
release-branch --> jenkins-release-build
jenkins-release-build --> github-release-draft
jenkins-release-build --> install-release
install-release --> verify-release
jenkins-release-build --> announce
github-release-draft --> github-release
verify-release --> verify-check
verify-check -- Yes --> github-release
verify-check -- No --> release-fix
release-fix --> release-branch-pr
verify-check -- No --> delete-artifacts
release-branch-pr --> trigger-pipeline
delete-artifacts --> trigger-pipeline
trigger-pipeline --> jenkins-release-build
</pre> </pre>
<pre class="mermaid2" style="width: 50%"> <pre class="mermaid" style="width: 50%">
flowchart LR %%{init: {"flowchart": {"htmlLabels": true}} }%%
a["<strong>Haiya</strong>"]===>b flowchart LR
b("The dog in the hog.(1)\nNL") --"1o bold"--> c[old strings svg labels]
</pre> </pre>
<pre class="mermaid2" style="width: 50%"> <script type="module">
flowchart TD // import mindmap from '../../packages/mermaid-mindmap/src/detector';
A --> B // import example from '../../packages/mermaid-example-diagram/src/mermaid-example-diagram.core.mjs';
A --> C import mermaid from './mermaid.esm.mjs';
B --> C // await mermaid.registerExternalDiagrams([example]);
</pre>
<pre class="mermaid2" style="width: 50%">
flowchart TD
A([stadium shape test])
A -->|Get money| B([Go shopping])
B --> C([Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?])
C -->|One| D([Laptop])
C -->|Two| E([iPhone])
C -->|Three| F([Car<br/>wroom wroom])
click A "index.html#link-clicked" "link test"
click B testClick "click test"
classDef someclass fill:#f96;
class A someclass;
class C someclass;
</pre>
<pre class="mermaid2" style="width: 50%">
sequenceDiagram
title: My Sequence Diagram Title
accTitle: My Acc Sequence Diagram
accDescr: My Sequence Diagram Description
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
</pre>
<pre class="mermaid2" style="width: 50%">
graph TD
A -->|000| B
B -->|111| C
linkStyle 1 stroke:#ff3,stroke-width:4px,color:red;
</pre>
<pre class="mermaid2" style="width: 100%">
journey
accTitle: My User Journey Diagram
accDescr: My User Journey Diagram Description
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
</pre>
<pre class="mermaid2" style="width: 100%">
info
</pre>
<pre class="mermaid2" style="width: 100%">
requirementDiagram
accTitle: My req Diagram
accDescr: My req Diagram Description
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
functionalRequirement test_req2 {
id: 1.1
text: the second test text.
risk: low
verifymethod: inspection
}
performanceRequirement test_req3 {
id: 1.2
text: the third test text.
risk: medium
verifymethod: demonstration
}
element test_entity {
type: simulation
}
element test_entity2 {
type: word doc
docRef: reqs/test_entity
}
test_entity - satisfies -> test_req2
test_req - traces -> test_req2
test_req - contains -> test_req3
test_req <- copies - test_entity2
</pre>
<pre class="mermaid2" style="width: 100%">
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
excludes weekends
%% (`excludes` accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays".)
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
Functionality added :milestone, 2014-01-25, 0d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
</pre>
<pre class="mermaid2" style="width: 100%">
stateDiagram
state Active {
Idle
}
Inactive --> Idle: ACT
Active --> Active: LOG
</pre>
<pre class="mermaid2" style="width: 100%">
flowchart TB
accTitle: My flowchart
accDescr: My flowchart Description
subgraph One
a1-->a2-->a3
end
</pre>
<pre class="mermaid2" style="width: 100%">
sequenceDiagram
A ->> B: 1
rect rgb(204, 0, 102)
break yes
rect rgb(0, 204, 204)
C ->> C: 0
end
end
end
B ->> A: Return
</pre>
<pre class="mermaid2" style="width: 100%">
classDiagram
accTitle: My class diagram
accDescr: My class diagram Description
Class01 <|-- AveryLongClass : Cool
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
class Class10 {
int id
size()
}
</pre>
<pre class="mermaid2" style="width: 100%">
%%{init: {'config': {'wrap': true }}}%%
sequenceDiagram
participant A as Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
A->>Bob: Hola
Bob-->A: Pasten !
</pre>
<pre class="mermaid2" style="width: 100%">
gitGraph
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
branch featureA
commit id:"FIX"
commit id: "FIX-2"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
cherry-pick id:"FIX"
checkout develop
commit id:"C"
merge featureA
</pre>
<pre class="mermaid2" style="width: 100%">
flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
</pre>
<pre class="mermaid2" style="width: 100%">
classDiagram
Animal "1" <|-- Duck
Animal <|-- Fish
Animal <--o Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
</pre>
<pre class="mermaid2" style="width: 100%">
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
CAR {
string registrationNumber
string make
string model
}
PERSON ||--o{ NAMED-DRIVER : is
PERSON {
string firstName
string lastName
int age
}
</pre>
<!-- <script src="./mermaid.js"></script> -->
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) { mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err); // console.error('Mermaid error: ', err);
}; };
mermaid.initialize({ mermaid.initialize({
maxTextSize: 900000, // theme: 'forest',
startOnLoad: true, startOnLoad: true,
securityLevel: 'loose',
logLevel: 0, logLevel: 0,
fontFamily: 'courier',
flowchart: { flowchart: {
// curve: 'curveLinear', // defaultRenderer: 'elk',
useMaxWidth: true, useMaxWidth: false,
htmlLabels: false, // htmlLabels: false,
fontFamily: 'courier', htmlLabels: true,
}, },
lazyLoadedDiagrams: ['./mermaid-mindmap-detector.js'], // htmlLabels: false,
gantt: {
useMaxWidth: false,
},
sequence: {
wrap: true,
},
useMaxWidth: false,
}); });
function callback() { function callback() {
alert('It worked'); alert('It worked');
} }
function clickByFlow(elemName) {
const div = document.createElement('div');
div.className = 'created-by-click';
div.style = 'padding: 20px; background: green; color: white;';
div.innerText = 'Clicked By Flow';
document.getElementsByTagName('body')[0].appendChild(div);
}
mermaid.parseError = function (err, hash) { mermaid.parseError = function (err, hash) {
console.error('In parse error:'); console.error('In parse error:');
console.error(err); console.error(err);
}; };
// mermaid.test1('first_slow', 1200).then((r) => console.info(r));
// mermaid.test1('second_fast', 200).then((r) => console.info(r));
// mermaid.test1('third_fast', 200).then((r) => console.info(r));
// mermaid.test1('forth_slow', 1200).then((r) => console.info(r));
</script> </script>
</body> </body>
</html> </html>

View File

@ -29,9 +29,9 @@
} }
.mermaid svg { .mermaid svg {
/* font-size: 18px !important; */ /* font-size: 18px !important; */
background-color: #eee; background-color: #efefef;
background-image: radial-gradient(#fff 1%, transparent 11%), background-image: radial-gradient(#fff 51%, transparent 91%),
radial-gradient(#fff 1%, transparent 11%); radial-gradient(#fff 51%, transparent 91%);
background-size: 20px 20px; background-size: 20px 20px;
background-position: 0 0, 10px 10px; background-position: 0 0, 10px 10px;
background-repeat: repeat; background-repeat: repeat;
@ -51,27 +51,118 @@
font-family: monospace; font-family: monospace;
font-size: 72px; font-size: 72px;
} }
/* tspan {
font-size: 6px !important;
} */
</style> </style>
</head> </head>
<body> <body>
<pre id="diagram" class="mermaid"> <pre id="diagram" class="mermaid">
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%% flowchart
graph BT classDef mainCategories fill:#f9d5e5, stroke:#233d4d,stroke-width:2px, font-weight:bold;
a{The cat in the hat} -- 1o --> b CS(Customer Awareness Journey):::mainCategories
a -- 2o --> c </pre
a -- 3o --> d >
g --2i--> a <pre id="diagram" class="mermaid">
d --1i--> a flowchart
h --3i -->a Node1:::class1 --> Node2:::class2
b --> d(The dog in the hog) Node1:::class1 --> Node3:::class2
c --> d Node3 --> Node4((I am a circle)):::larger
classDef class1 fill:lightblue
classDef class2 fill:pink
classDef larger font-size:30px,fill:yellow
</pre
>
<pre id="diagram" class="mermaid2">
stateDiagram-v2
[*] --> Still
Still --> [*]
Still --> Moving
Moving --> Still
Moving --> Crash
Crash --> [*] </pre
>
<pre id="diagram" class="mermaid2">
flowchart RL
subgraph "`one`"
a1 -- l1 --> a2
a1 -- l2 --> a2
end
</pre> </pre>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
flowchart-elk TB flowchart RL
a --> b subgraph "`one`"
a --> c a1 -- l1 --> a2
b --> d a1 -- l2 --> a2
c --> d end
</pre>
<pre id="diagram" class="mermaid2">
flowchart
id["`A root with a long text that wraps to keep the node size in check. A root with a long text that wraps to keep the node size in check`"]</pre
>
<pre id="diagram" class="mermaid2">
flowchart LR
A[A text that needs to be wrapped wraps to another line]
B[A text that needs to be<br/>wrapped wraps to another line]
C["`A text that needs to be wrapped to another line`"]</pre>
<pre id="diagram" class="mermaid2">
flowchart LR
C["`A text
that needs
to be wrapped
in another
way`"]
</pre
>
<pre id="diagram" class="mermaid2">
classDiagram-v2
note "I love this diagram!\nDo you love it?"
</pre>
<pre id="diagram" class="mermaid2">
stateDiagram-v2
State1: The state with a note with minus - and plus + in it
note left of State1
Important information! You can write
notes with . and in them.
end note </pre
>
<pre id="diagram" class="mermaid2">
mindmap
root
Child3(A node with an icon and with a long text that wraps to keep the node size in check)
</pre
>
<pre id="diagram" class="mermaid2">
%%{init: {"theme": "forest"} }%%
mindmap
id1[**Start2**<br/>end]
id2[**Start2**<br />end]
%% Another comment
id3[**Start2**<br>end] %% Comment
id4[**Start2**<br >end<br >the very end]
</pre>
<pre id="diagram" class="mermaid2">
mindmap
id1["`**Start2**
second line 😎 with long text that is wrapping to the next line`"]
id2["`Child **with bold** text`"]
id3["`Children of which some
is using *italic type of* text`"]
id4[Child]
id5["`Child
Row
and another
`"]
</pre>
<pre id="diagram" class="mermaid2">
mindmap
id1("`**Root**`"]
id2["`A formatted text... with **bold** and *italics*`"]
id3[Regular labels works as usual]
id4["`Emojis and unicode works too: 🤓
शान्तिः سلام 和平 `"]
</pre> </pre>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%% %%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
@ -89,7 +180,7 @@ flowchart TB
rom --> core2 rom --> core2
end end
subgraph amd[AMD Latte GPU] subgraph amd["`**AMD** Latte GPU`"]
mem[Memory & I/O Bridge] mem[Memory & I/O Bridge]
dram[DRAM Controller] dram[DRAM Controller]
edram[32 MB EDRAM MEM1] edram[32 MB EDRAM MEM1]
@ -128,6 +219,62 @@ flowchart TB
rtc{{rtc}} rtc{{rtc}}
</pre </pre
> >
<pre id="diagram" class="mermaid2">
%%{init: {"flowchart": {"defaultRenderer": "elk", "htmlLabels": false}} }%%
flowchart TB
%% I could not figure out how to use double quotes in labels in Mermaid
subgraph ibm[IBM Espresso CPU]
core0[IBM PowerPC Broadway Core 0]
core1[IBM PowerPC Broadway Core 1]
core2[IBM PowerPC Broadway Core 2]
rom[16 KB ROM]
core0 --- core2
rom --> core2
end
subgraph amd["`**AMD** Latte GPU`"]
mem[Memory & I/O Bridge]
dram[DRAM Controller]
edram[32 MB EDRAM MEM1]
rom[512 B SEEPROM]
sata[SATA IF]
exi[EXI]
subgraph gx[GX]
sram[3 MB 1T-SRAM]
end
radeon[AMD Radeon R7xx GX2]
mem --- gx
mem --- radeon
rom --- mem
mem --- sata
mem --- exi
dram --- sata
dram --- exi
end
ddr3[2 GB DDR3 RAM MEM2]
mem --- ddr3
dram --- ddr3
edram --- ddr3
core1 --- mem
exi --- rtc
rtc{{rtc}}
</pre
>
<br /> <br />
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
flowchart TB flowchart TB
@ -263,25 +410,37 @@ mindmap
<script type="module"> <script type="module">
// import mindmap from '../../packages/mermaid-mindmap/src/detector'; // import mindmap from '../../packages/mermaid-mindmap/src/detector';
import example from '../../packages/mermaid-example-diagram/src/detector'; // import example from '../../packages/mermaid-example-diagram/src/mermaid-example-diagram.core.mjs';
import mermaid from '../../packages/mermaid/src/mermaid'; import mermaid from './mermaid.esm.mjs';
await mermaid.registerExternalDiagrams([example]); // await mermaid.registerExternalDiagrams([example]);
mermaid.parseError = function (err, hash) { mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err); // console.error('Mermaid error: ', err);
}; };
// mermaid.initialize({
// // theme: 'forest',
// startOnLoad: true,
// logLevel: 0,
// flowchart: {
// // defaultRenderer: 'elk',
// useMaxWidth: false,
// // htmlLabels: false,
// htmlLabels: true,
// },
// // htmlLabels: false,
// gantt: {
// useMaxWidth: false,
// },
// useMaxWidth: false,
// });
mermaid.initialize({ mermaid.initialize({
theme: 'forest', flowchart: { titleTopMargin: 10 },
startOnLoad: true, fontFamily: 'courier',
logLevel: 5, sequence: {
flowchart: { actorFontFamily: 'courier',
// defaultRenderer: 'elk', noteFontFamily: 'courier',
useMaxWidth: false, messageFontFamily: 'courier',
htmlLabels: true,
}, },
gantt: { fontSize: 16,
useMaxWidth: false,
},
useMaxWidth: false,
}); });
function callback() { function callback() {
alert('It worked'); alert('It worked');

View File

@ -40,7 +40,7 @@
<script type="module"> <script type="module">
// import mermaid from './mermaid.esm.mjs'; // import mermaid from './mermaid.esm.mjs';
import mermaid from '../../packages/mermaid/src/mermaid'; import mermaid from '../../packages/mermaid/dist/mermaid.esm.mjs';
// import mermaidMindmap from './mermaid-mindmap.esm.mjs'; // import mermaidMindmap from './mermaid-mindmap.esm.mjs';
// import mermaidMindmap from 'https://cdn.jsdelivr.net/npm/@mermaid-js/mermaid-mindmap@9.3.0/+esm'; // import mermaidMindmap from 'https://cdn.jsdelivr.net/npm/@mermaid-js/mermaid-mindmap@9.3.0/+esm';

View File

@ -1,246 +1,17 @@
<html> <html>
<head>
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
<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"
/>
<link
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
rel="stylesheet"
/>
<style>
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
font-family: 'Arial';
/* font-size: 18px !important; */
}
h1 {
color: grey;
}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
background-color: #eee;
background-image: radial-gradient(#fff 1%, transparent 11%),
radial-gradient(#fff 1%, transparent 11%);
background-size: 20px 20px;
background-position: 0 0, 10px 10px;
background-repeat: repeat;
}
.malware {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 150px;
background: red;
color: black;
display: flex;
display: flex;
justify-content: center;
align-items: center;
font-family: monospace;
font-size: 72px;
}
</style>
</head>
<body> <body>
<pre id="diagram" class="mermaid"> <pre id="diagram" class="mermaid">
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
graph TB graph TB
a --> b a --> b
a --> c a --> c
b --> d b --> d
c --> d c --> d
</pre> </pre>
<pre id="diagram" class="mermaid">
flowchart-elk LR
subgraph A
a --> b
end
subgraph B
b
end
</pre>
<pre id="diagram" class="mermaid">
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
flowchart TB
%% I could not figure out how to use double quotes in labels in Mermaid
subgraph ibm[IBM Espresso CPU]
core0[IBM PowerPC Broadway Core 0]
core1[IBM PowerPC Broadway Core 1]
core2[IBM PowerPC Broadway Core 2]
rom[16 KB ROM] <div id="d2"></div>
core0 --- core2
rom --> core2
end
subgraph amd[AMD Latte GPU]
mem[Memory & I/O Bridge]
dram[DRAM Controller]
edram[32 MB EDRAM MEM1]
rom[512 B SEEPROM]
sata[SATA IF]
exi[EXI]
subgraph gx[GX]
sram[3 MB 1T-SRAM]
end
radeon[AMD Radeon R7xx GX2]
mem --- gx
mem --- radeon
rom --- mem
mem --- sata
mem --- exi
dram --- sata
dram --- exi
end
ddr3[2 GB DDR3 RAM MEM2]
mem --- ddr3
dram --- ddr3
edram --- ddr3
core1 --- mem
exi --- rtc
rtc{{rtc}}
</pre
>
<br />
<pre id="diagram" class="mermaid">
flowchart TB
%% I could not figure out how to use double quotes in labels in Mermaid
subgraph ibm[IBM Espresso CPU]
core0[IBM PowerPC Broadway Core 0]
core1[IBM PowerPC Broadway Core 1]
core2[IBM PowerPC Broadway Core 2]
rom[16 KB ROM]
core0 --- core2
rom --> core2
end
subgraph amd[AMD Latte GPU]
mem[Memory & I/O Bridge]
dram[DRAM Controller]
edram[32 MB EDRAM MEM1]
rom[512 B SEEPROM]
sata[SATA IF]
exi[EXI]
subgraph gx[GX]
sram[3 MB 1T-SRAM]
end
radeon[AMD Radeon R7xx GX2]
mem --- gx
mem --- radeon
rom --- mem
mem --- sata
mem --- exi
dram --- sata
dram --- exi
end
ddr3[2 GB DDR3 RAM MEM2]
mem --- ddr3
dram --- ddr3
edram --- ddr3
core1 --- mem
exi --- rtc
rtc{{rtc}}
</pre
>
<br />
&nbsp;
<pre id="diagram" class="mermaid2">
flowchart LR
B1 --be be--x B2
B1 --bo bo--o B3
subgraph Ugge
B2
B3
subgraph inner
B4
B5
end
subgraph inner2
subgraph deeper
C4
C5
end
C6
end
B4 --> C4
B3 -- X --> B4
B2 --> inner
C4 --> C5
end
subgraph outer
B6
end
B6 --> B5
</pre
>
<pre id="diagram" class="mermaid2">
sequenceDiagram
Customer->>+Stripe: Makes a payment request
Stripe->>+Bank: Forwards the payment request to the bank
Bank->>+Customer: Asks for authorization
Customer->>+Bank: Provides authorization
Bank->>+Stripe: Sends a response with payment details
Stripe->>+Merchant: Sends a notification of payment receipt
Merchant->>+Stripe: Confirms the payment
Stripe->>+Customer: Sends a confirmation of payment
Customer->>+Merchant: Receives goods or services
</pre
>
<pre id="diagram" class="mermaid2">
gantt
title Style today marker (vertical line should be 5px wide and half-transparent blue)
dateFormat YYYY-MM-DD
axisFormat %d
todayMarker stroke-width:5px,stroke:#00f,opacity:0.5
section Section1
Today: 1, -1h
</pre>
<script type="module"> <script type="module">
import mermaid from '../../packages/mermaid/src/mermaid'; import mermaid from '/mermaid.esm.mjs';
mermaid.parseError = function (err, hash) { mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err); // console.error('Mermaid error: ', err);
}; };
@ -265,6 +36,11 @@ sequenceDiagram
console.error('In parse error:'); console.error('In parse error:');
console.error(err); console.error(err);
}; };
const value = `graph TD\nHello --> World`;
const el = document.getElementById('d2');
const { svg } = await mermaid.render('d22', value);
console.log(svg);
el.innerHTML = svg;
// mermaid.test1('first_slow', 1200).then((r) => console.info(r)); // mermaid.test1('first_slow', 1200).then((r) => console.info(r));
// mermaid.test1('second_fast', 200).then((r) => console.info(r)); // mermaid.test1('second_fast', 200).then((r) => console.info(r));
// mermaid.test1('third_fast', 200).then((r) => console.info(r)); // mermaid.test1('third_fast', 200).then((r) => console.info(r));

View File

@ -1,5 +1,6 @@
import mermaid2 from '../../packages/mermaid/src/mermaid'; import mermaid2 from './mermaid.esm.mjs';
import externalExample from '../../packages/mermaid-example-diagram/src/detector'; import externalExample from '../../packages/mermaid-example-diagram/dist/mermaid-example-diagram.core.mjs';
import zenUml from '../../packages/mermaid-zenuml/dist/mermaid-zenuml.core.mjs';
function b64ToUtf8(str) { function b64ToUtf8(str) {
return decodeURIComponent(escape(window.atob(str))); return decodeURIComponent(escape(window.atob(str)));
@ -44,10 +45,9 @@ const contentLoaded = async function () {
document.getElementsByTagName('body')[0].appendChild(div); document.getElementsByTagName('body')[0].appendChild(div);
} }
await mermaid2.registerExternalDiagrams([externalExample]); await mermaid2.registerExternalDiagrams([externalExample, zenUml]);
mermaid2.initialize(graphObj.mermaid); mermaid2.initialize(graphObj.mermaid);
await mermaid2.init(); await mermaid2.run();
markRendered();
} }
}; };
@ -123,7 +123,6 @@ const contentLoadedApi = async function () {
bindFunctions(div); bindFunctions(div);
} }
} }
markRendered();
}; };
if (typeof document !== 'undefined') { if (typeof document !== 'undefined') {
@ -135,10 +134,10 @@ if (typeof document !== 'undefined') {
function () { function () {
if (this.location.href.match('xss.html')) { if (this.location.href.match('xss.html')) {
this.console.log('Using api'); this.console.log('Using api');
void contentLoadedApi(); void contentLoadedApi().finally(markRendered);
} else { } else {
this.console.log('Not using api'); this.console.log('Not using api');
void contentLoaded(); void contentLoaded().finally(markRendered);
} }
}, },
false false

View File

@ -0,0 +1,85 @@
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
<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"
/>
<link
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
rel="stylesheet"
/>
<style>
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
font-family: 'Arial';
/* font-size: 18px !important; */
}
h1 {
color: grey;
}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
}
.malware {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 150px;
background: red;
color: black;
display: flex;
display: flex;
justify-content: center;
align-items: center;
font-family: monospace;
font-size: 72px;
}
</style>
</head>
<body>
<div>Security check</div>
<div class="flex">
<div id="diagram" class="mermaid"></div>
<div id="graph-div"></div>
<div id="res" class=""></div>
</div>
<script type="module">
import mermaid from './mermaid.esm.mjs';
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'base',
startOnLoad: false,
flowcharts: { htmlLabels: true },
});
function callback() {
alert('It worked');
}
function xssAttack() {
const div = document.createElement('div');
div.id = 'the-malware';
div.className = 'malware';
div.innerHTML = 'XSS Succeeded';
document.getElementsByTagName('body')[0].appendChild(div);
throw new Error('XSS Succeeded');
}
let diagram = `graph TD
A[["a marker-end=#quot;url(<s title='#<style>*{background:red}</style>'>b"]]
`;
const el = document.querySelector('#graph-div');
console.log(diagram);
const { svg } = await mermaid.render('graph-div', diagram);
document.querySelector('#res').innerHTML = svg;
window.rendered = true;
</script>
</body>
</html>

View File

@ -13,8 +13,8 @@
// https://on.cypress.io/configuration // https://on.cypress.io/configuration
// *********************************************************** // ***********************************************************
import '@cypress/code-coverage/support';
import '@applitools/eyes-cypress/commands'; import '@applitools/eyes-cypress/commands';
// Import commands.js using ES2015 syntax: // Import commands.js using ES2015 syntax:
import './commands'; import './commands';

View File

@ -2,7 +2,9 @@
"compilerOptions": { "compilerOptions": {
"target": "es2020", "target": "es2020",
"lib": ["es2020", "dom"], "lib": ["es2020", "dom"],
"types": ["cypress", "node"] "types": ["cypress", "node"],
"allowImportingTsExtensions": true,
"noEmit": true
}, },
"include": ["**/*.ts"] "include": ["**/*.ts"]
} }

View File

@ -38,12 +38,14 @@
+quack() +quack()
} }
class Fish{ class Fish{
-int sizeInFeet -Listint sizeInFeet
-canEat() -canEat()
} }
class Zebra{ class Zebra{
+bool is_wild +bool is_wild
+run() +run(List~T~, List~OT~)
%% +run-composite(List~T, K~)
+run-nested(List~List~OT~~)
} }
</pre> </pre>
@ -80,6 +82,7 @@
Class01 : #size() Class01 : #size()
Class01 : -int chimp Class01 : -int chimp
Class01 : +int gorilla Class01 : +int gorilla
Class01 : +abstractAttribute string*
class Class10~T~ { class Class10~T~ {
&lt;&lt;service&gt;&gt; &lt;&lt;service&gt;&gt;
int id int id
@ -122,6 +125,8 @@
classDiagram classDiagram
direction LR direction LR
Animal ()-- Dog Animal ()-- Dog
Animal ()-- Cat
note for Cat "should have no members area"
Dog : bark() Dog : bark()
Dog : species() Dog : species()
</pre> </pre>
@ -151,6 +156,30 @@
~InternalProperty : string ~InternalProperty : string
~AnotherInternalProperty : List~List~string~~ ~AnotherInternalProperty : List~List~string~~
} }
class People List~List~Person~~
</pre>
<hr />
<pre class="mermaid">
classDiagram
A1 --> B1
namespace A {
class A1 {
+foo : string
}
class A2 {
+bar : int
}
}
namespace B {
class B1 {
+foo : bool
}
class B2 {
+bar : float
}
}
A2 --> B2
</pre> </pre>
<hr /> <hr />

34
demos/dev/example.html Normal file
View File

@ -0,0 +1,34 @@
<!--Do not edit this file-->
<!--Duplicate this file to any name you like, run `pnpm dev`, open http://localhost:9000/dev/name.html to view-->
<html>
<head>
<title>Mermaid development page</title>
</head>
<body>
<pre id="diagram" class="mermaid">
graph TB
a --> b
a --> c
b --> d
c --> d
</pre>
<div id="dynamicDiagram"></div>
<script type="module">
import mermaid from '/mermaid.esm.mjs';
mermaid.parseError = function (err, hash) {
console.error('Mermaid error: ', err);
};
mermaid.initialize({
startOnLoad: true,
logLevel: 0,
});
const value = `graph TD\nHello --> World`;
const el = document.getElementById('dynamicDiagram');
const { svg } = await mermaid.render('dd', value);
console.log(svg);
el.innerHTML = svg;
</script>
</body>
</html>

View File

@ -21,6 +21,8 @@
<pre class="mermaid"> <pre class="mermaid">
--- ---
title: This is a title title: This is a title
config:
theme: forest
--- ---
erDiagram erDiagram
%% title This is a title %% title This is a title
@ -108,6 +110,35 @@
} }
MANUFACTURER only one to zero or more CAR : makes MANUFACTURER only one to zero or more CAR : makes
</pre> </pre>
<hr />
<pre class="mermaid">
erDiagram
p[Person] {
string firstName
string lastName
}
a["Customer Account"] {
string email
}
p ||--o| a : has
</pre>
<hr />
<pre class="mermaid">
erDiagram
_customer_order {
bigint id PK
bigint customer_id FK
text shipping_address
text delivery_method
timestamp_with_time_zone ordered_at
numeric total_tax_amount
numeric total_price
text payment_method
}
</pre>
<hr />
<script type="module"> <script type="module">
import mermaid from './mermaid.esm.mjs'; import mermaid from './mermaid.esm.mjs';

38
demos/error.html Normal file
View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Error | Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
</head>
<body>
<pre class="mermaid">
erDiagram
ATLAS-ORGANIZATION ||--|{ ATLAS-PROJECTS : "has many"
ATLAS-PROJECTS ||--|{ MONGODB-CLUSTERS : "has many"
ATLAS-PROJECTS ||--|{ ATLAS-TEAMS : "has many"
</pre>
<pre class="mermaid">
erDiagram
ATLAS-ORGANIZATION ||--|{ ATLAS-PROJECTS : "has many"
ATLAS-PROJECTS ||--|{ MONGODB-CLUSTERS : "has many"
ATLAS-PROJECTS ||--|{ ATLAS-TEAMS : "has many"
MONGODB-CLUSTERS ||..|{
ATLAS-TEAMS ||..|{
</pre>
<hr />
<pre class="mermaid">
flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
</pre>
<pre class="mermaid">
flowchart TD
A[Christmas] --|Get money| B(Go shopping)
</pre>
<script type="module">
import mermaid from './mermaid.esm.mjs';
</script>
</body>
</html>

View File

@ -123,6 +123,13 @@
<h3>flowchart</h3> <h3>flowchart</h3>
<pre class="mermaid"> <pre class="mermaid">
---
title: This is another complicated flow
config:
theme: base
flowchart:
curve: cardinal
---
flowchart LR flowchart LR
sid-B3655226-6C29-4D00-B685-3D5C734DC7E1[" sid-B3655226-6C29-4D00-B685-3D5C734DC7E1["
@ -1505,6 +1512,34 @@
</pre> </pre>
<hr /> <hr />
<pre class="mermaid">
graph TD
A([Start]) ==> B[Step 1]
B ==> C{Flow 1}
C -- Choice 1.1 --> D[Step 2.1]
C -- Choice 1.3 --> I[Step 2.3]
C == Choice 1.2 ==> E[Step 2.2]
D --> F{Flow 2}
E ==> F{Flow 2}
F{Flow 2} == Choice 2.1 ==> H[Feedback node]
H[Feedback node] ==> B[Step 1]
F{Flow 2} == Choice 2.2 ==> G((Finish))
linkStyle 0,1,4,6,7,8,9 stroke:gold, stroke-width:4px
classDef active_node fill:#0CF,stroke:#09F,stroke-width:6px
classDef unactive_node fill:#e0e0e0,stroke:#bdbdbd,stroke-width:3px
classDef bugged_node fill:#F88,stroke:#F22,stroke-width:3px
classDef start_node,finish_node fill:#3B1,stroke:#391,stroke-width:8px
class A start_node;
class B,C,E,F,H active_node;
class D unactive_node;
class G finish_node;
class I bugged_node
</pre>
<hr />
<h1 id="link-clicked">Anchor for "link-clicked" test</h1> <h1 id="link-clicked">Anchor for "link-clicked" test</h1>
<script type="module"> <script type="module">

View File

@ -78,7 +78,7 @@
axisFormat %d/%m axisFormat %d/%m
todayMarker off todayMarker off
section Section1 section Section1
Today: 1, -01:00, 5min Today: 1, 08-08-09-01:00, 5min
</pre> </pre>
<hr /> <hr />
@ -89,7 +89,7 @@
axisFormat %d/%m axisFormat %d/%m
todayMarker stroke-width:5px,stroke:#00f,opacity:0.5 todayMarker stroke-width:5px,stroke:#00f,opacity:0.5
section Section1 section Section1
Today: 1, -01:00, 5min Today: 1, 08-08-09-01:00, 5min
</pre> </pre>
<hr /> <hr />
@ -166,6 +166,37 @@
</pre> </pre>
<hr /> <hr />
<pre class="mermaid">
---
displayMode: compact
---
gantt
title GANTT compact
dateFormat HH:mm:ss
axisFormat %Hh%M
section DB Clean
Clean: 12:00:00, 10m
Clean: 12:30:00, 12m
Clean: 13:00:00, 8m
Clean: 13:30:00, 9m
Clean: 14:00:00, 13m
Clean: 14:30:00, 10m
Clean: 15:00:00, 11m
section Sessions
A: 12:00:00, 63m
B: 12:30:00, 12m
C: 13:05:00, 12m
D: 13:06:00, 33m
E: 13:15:00, 55m
F: 13:20:00, 12m
G: 13:32:00, 18m
H: 13:50:00, 20m
I: 14:10:00, 10m
</pre>
<hr />
<script> <script>
function ganttTestClick(a, b, c) { function ganttTestClick(a, b, c) {
console.log('a:', a); console.log('a:', a);

View File

@ -45,6 +45,9 @@
<li> <li>
<h2><a href="./git.html">Git</a></h2> <h2><a href="./git.html">Git</a></h2>
</li> </li>
<li>
<h2><a href="./info.html">Info</a></h2>
</li>
<li> <li>
<h2><a href="./journey.html">Journey</a></h2> <h2><a href="./journey.html">Journey</a></h2>
</li> </li>
@ -54,6 +57,9 @@
<li> <li>
<h2><a href="./pie.html">Pie</a></h2> <h2><a href="./pie.html">Pie</a></h2>
</li> </li>
<li>
<h2><a href="./quadrantchart.html">Quadrant charts</a></h2>
</li>
<li> <li>
<h2><a href="./requirements.html">Requirements</a></h2> <h2><a href="./requirements.html">Requirements</a></h2>
</li> </li>
@ -63,6 +69,15 @@
<li> <li>
<h2><a href="./state.html">State</a></h2> <h2><a href="./state.html">State</a></h2>
</li> </li>
<li>
<h2><a href="./timeline.html">Timeline</a></h2>
</li>
<li>
<h2><a href="./zenuml.html">ZenUML</a></h2>
</li>
<li>
<h2><a href="./sankey.html">Sankey</a></h2>
</li>
</ul> </ul>
</body> </body>
</html> </html>

Some files were not shown because too many files have changed in this diff Show More