Merge branch 'next' into sidv/tinyMermaid

* next: (562 commits)
  Lint
  Remove echo
  RefTest
  Echo event
  Update cypress
  Fix applitools
  Fix applitools
  docs: fix lint
  docs: move community to Discord
  Swap condition blocks to avoid using negation
  Reposition const declaration to ideal place
  Change repetitive values into consts
  docs: fix swimm link
  Fix Update Browserslist
  Use pnpm/action-setup@v2
  Fix lint
  Cleanup e2e.yml
  Ignore push events on merge queue
  Remove ::
  Remove ::
  ...
This commit is contained in:
Sidharth Vinod
2024-01-24 09:25:52 +05:30
379 changed files with 14048 additions and 5964 deletions

View File

@@ -22,4 +22,9 @@ export const packageOptions = {
packageName: 'mermaid-zenuml', packageName: 'mermaid-zenuml',
file: 'detector.ts', file: 'detector.ts',
}, },
'mermaid-flowchart-elk': {
name: 'mermaid-flowchart-elk',
packageName: 'mermaid-flowchart-elk',
file: 'detector.ts',
},
} as const; } as const;

View File

@@ -17,12 +17,14 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
'er', 'er',
'pie', 'pie',
'quadrantChart', 'quadrantChart',
'xyChart',
'requirement', 'requirement',
'mindmap', 'mindmap',
'timeline', 'timeline',
'gitGraph', 'gitGraph',
'c4', 'c4',
'sankey', 'sankey',
'packet',
] as const; ] as const;
/** /**
@@ -34,7 +36,7 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
* @param mermaidConfigSchema - The Mermaid JSON Schema to use. * @param mermaidConfigSchema - The Mermaid JSON Schema to use.
* @returns The default mermaid config object. * @returns The default mermaid config object.
*/ */
export function generateDefaults(mermaidConfigSchema: JSONSchemaType<MermaidConfig>) { function generateDefaults(mermaidConfigSchema: JSONSchemaType<MermaidConfig>) {
const ajv = new Ajv2019({ const ajv = new Ajv2019({
useDefaults: true, useDefaults: true,
allowUnionTypes: true, allowUnionTypes: true,

18
.build/types.ts Normal file
View File

@@ -0,0 +1,18 @@
import { packageOptions } from './common.js';
import { execSync } from 'child_process';
const buildType = (packageName: string) => {
console.log(`Building types for ${packageName}`);
try {
const out = execSync(`tsc -p ./packages/${packageName}/tsconfig.json --emitDeclarationOnly`);
out.length > 0 && console.log(out.toString());
} catch (e) {
console.error(e);
e.stdout.length > 0 && console.error(e.stdout.toString());
e.stderr.length > 0 && console.error(e.stderr.toString());
}
};
for (const { packageName } of Object.values(packageOptions)) {
buildType(packageName);
}

View File

@@ -1,8 +1,8 @@
import { build } from 'esbuild'; import { build } from 'esbuild';
import { mkdir, writeFile } from 'node:fs/promises'; import { mkdir, writeFile } from 'node:fs/promises';
import { MermaidBuildOptions, defaultOptions, getBuildConfig } from './util.js';
import { packageOptions } from '../.build/common.js'; import { packageOptions } from '../.build/common.js';
import { generateLangium } from '../.build/generateLangium.js'; import { generateLangium } from '../.build/generateLangium.js';
import { MermaidBuildOptions, defaultOptions, getBuildConfig } from './util.js';
const shouldVisualize = process.argv.includes('--visualize'); const shouldVisualize = process.argv.includes('--visualize');
@@ -63,7 +63,7 @@ const main = async () => {
await generateLangium(); await generateLangium();
await mkdir('stats').catch(() => {}); await mkdir('stats').catch(() => {});
const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[]; const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[];
// it should build `parser` before `mermaid` because it's a dependecy // it should build `parser` before `mermaid` because it's a dependency
for (const pkg of packageNames) { for (const pkg of packageNames) {
await buildPackage(pkg).catch(handler); await buildPackage(pkg).catch(handler);
} }

View File

@@ -5,38 +5,25 @@ import { getBuildConfig, defaultOptions } from './util.js';
import { context } from 'esbuild'; import { context } from 'esbuild';
import chokidar from 'chokidar'; import chokidar from 'chokidar';
import { generateLangium } from '../.build/generateLangium.js'; import { generateLangium } from '../.build/generateLangium.js';
import { packageOptions } from '../.build/common.js';
const parserCtx = await context( const configs = Object.values(packageOptions).map(({ packageName }) =>
getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: 'parser' }) getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: packageName })
); );
const mermaidCtx = await context( const mermaidIIFEConfig = getBuildConfig({
getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: 'mermaid' })
);
const mermaidIIFECtx = await context(
getBuildConfig({
...defaultOptions, ...defaultOptions,
minify: false, minify: false,
core: false, core: false,
entryName: 'mermaid', entryName: 'mermaid',
format: 'iife', format: 'iife',
}) });
); configs.push(mermaidIIFEConfig);
const externalCtx = await context(
getBuildConfig({ const contexts = await Promise.all(configs.map((config) => context(config)));
...defaultOptions,
minify: false,
core: false,
entryName: 'mermaid-example-diagram',
})
);
const zenumlCtx = await context(
getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: 'mermaid-zenuml' })
);
const contexts = [parserCtx, mermaidCtx, mermaidIIFECtx, externalCtx, zenumlCtx];
const rebuildAll = async () => { const rebuildAll = async () => {
console.time('Rebuild time'); console.time('Rebuild time');
await Promise.all(contexts.map((ctx) => ctx.rebuild())); await Promise.all(contexts.map((ctx) => ctx.rebuild())).catch((e) => console.error(e));
console.timeEnd('Rebuild time'); console.timeEnd('Rebuild time');
}; };
@@ -101,10 +88,9 @@ async function createServer() {
app.use(cors()); app.use(cors());
app.get('/events', eventsHandler); app.get('/events', eventsHandler);
app.use(express.static('./packages/parser/dist')); for (const { packageName } of Object.values(packageOptions)) {
app.use(express.static('./packages/mermaid/dist')); app.use(express.static(`./packages/${packageName}/dist`));
app.use(express.static('./packages/mermaid-zenuml/dist')); }
app.use(express.static('./packages/mermaid-example-diagram/dist'));
app.use(express.static('demos')); app.use(express.static('demos'));
app.use(express.static('cypress/platform')); app.use(express.static('cypress/platform'));

View File

@@ -76,6 +76,7 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
define: { define: {
// This needs to be stringified for esbuild // This needs to be stringified for esbuild
includeLargeDiagrams: `${includeLargeDiagrams}`, includeLargeDiagrams: `${includeLargeDiagrams}`,
'import.meta.vitest': 'undefined',
}, },
}); });

View File

@@ -49,8 +49,10 @@ module.exports = {
'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/consistent-type-imports': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
'@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/no-unused-vars': 'warn',
'@typescript-eslint/ban-ts-comment': [ '@typescript-eslint/ban-ts-comment': [
'error', 'error',
{ {

View File

@@ -17,6 +17,9 @@ 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!
There is a chance that the bug is already fixed in the git `develop` branch, but is not released yet.
So please check in [Live Editor - Develop](https://develop.git.mermaid.live) before raising an issue.
- type: textarea - type: textarea
attributes: attributes:
label: Description label: Description
@@ -43,7 +46,7 @@ body:
attributes: attributes:
label: Code Sample label: Code Sample
description: |- description: |-
If applicable, add the code sample or a link to the [Live Editor](https://mermaid.live). If applicable, add the code sample or a link to the [Live Editor - Develop](https://develop.git.mermaid.live).
Any text pasted here will be rendered as a Code block. Any text pasted here will be rendered as a Code block.
render: text render: text
- type: textarea - type: textarea

View File

@@ -3,12 +3,18 @@ contact_links:
- name: GitHub Discussions - name: GitHub Discussions
url: https://github.com/mermaid-js/mermaid/discussions url: https://github.com/mermaid-js/mermaid/discussions
about: Ask the Community questions or share your own graphs in our discussions. about: Ask the Community questions or share your own graphs in our discussions.
- name: Slack - name: Discord
url: https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE url: https://discord.gg/wwtabKgp8y
about: Join our Community on Slack for Help and a casual chat. about: Join our Community on Discord for Help and a casual chat.
- name: Documentation - name: Documentation
url: https://mermaid-js.github.io url: https://mermaid.js.org
about: Read our documentation for all that Mermaid.js can offer. about: Read our documentation for all that Mermaid.js can offer.
- name: Live Editor - name: Live Editor
url: https://mermaid.live url: https://mermaid.live
about: Try the live editor to preview graphs in no time. about: Try the live editor to preview graphs in no time.
- name: Live Editor - Develop
url: https://develop.git.mermaid.live
about: Try unreleased changes in the develop branch.
- name: Live Editor - Next
url: https://next.git.mermaid.live
about: Try unreleased changes in the next branch.

View File

@@ -15,3 +15,4 @@ coverage:
# Turing off for now as code coverage isn't stable and causes unnecessary build failures. # Turing off for now as code coverage isn't stable and causes unnecessary build failures.
# default: # default:
# threshold: 2% # threshold: 2%
patch: off

4
.github/lychee.toml vendored
View File

@@ -34,8 +34,8 @@ exclude = [
# Don't check files that are generated during the build via `pnpm docs:code` # Don't check files that are generated during the build via `pnpm docs:code`
'packages/mermaid/src/docs/config/setup/*', 'packages/mermaid/src/docs/config/setup/*',
# Ignore slack invite # Ignore Discord invite
"https://join.slack.com/" "https://discord.gg"
] ]
# Exclude all private IPs from checking. # Exclude all private IPs from checking.

View File

@@ -1,4 +1,22 @@
'Type: Bug / Error': ['bug/*', fix/*] # yaml-language-server: $schema=https://raw.githubusercontent.com/release-drafter/release-drafter/master/schema.json
'Type: Enhancement': ['feature/*', 'feat/*'] autolabeler:
'Type: Other': ['other/*', 'chore/*', 'test/*', 'refactor/*'] - label: 'Type: Bug / Error'
'Area: Documentation': ['docs/*'] branch:
- '/bug\/.+/'
- '/fix\/.+/'
- label: 'Type: Enhancement'
branch:
- '/feature\/.+/'
- '/feat\/.+/'
- label: 'Type: Other'
branch:
- '/other\/.+/'
- '/chore\/.+/'
- '/test\/.+/'
- '/refactor\/.+/'
- label: 'Area: Documentation'
branch:
- '/docs\/.+/'
template: |
This field is unused, as we only use this config file for labeling PRs.

View File

@@ -14,5 +14,5 @@ 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 necessary unit/e2e tests. - [ ] :computer: have added necessary unit/e2e tests.
- [ ] :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. - [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/docs/community/contributing.md#update-documentation) is used for all new features.
- [ ] :bookmark: targeted `develop` branch - [ ] :bookmark: targeted `develop` branch

View File

@@ -25,8 +25,6 @@ categories:
change-template: '- $TITLE (#$NUMBER) @$AUTHOR' change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
sort-by: title sort-by: title
sort-direction: ascending sort-direction: ascending
branches:
- develop
exclude-labels: exclude-labels:
- 'Skip changelog' - 'Skip changelog'
no-changes-template: 'This release contains minor changes and bugfixes.' no-changes-template: 'This release contains minor changes and bugfixes.'

View File

@@ -16,12 +16,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18 node-version: 18
@@ -29,7 +29,7 @@ jobs:
- name: Install Packages - name: Install Packages
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Verify release verion - name: Verify release version
if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release')) }} if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release')) }}
run: pnpm --filter mermaid run docs:verify-version run: pnpm --filter mermaid run docs:verify-version

View File

@@ -19,13 +19,13 @@ jobs:
matrix: matrix:
node-version: [18.x] node-version: [18.x]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- 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
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Check for difference in README.md and docs/README.md - name: Check for difference in README.md and docs/README.md
run: | run: |

View File

@@ -15,7 +15,7 @@ jobs:
name: check tests name: check tests
if: github.repository_owner == 'mermaid-js' if: github.repository_owner == 'mermaid-js'
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: testomatio/check-tests@stable - uses: testomatio/check-tests@stable

View File

@@ -29,7 +29,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL

View File

@@ -1,6 +1,6 @@
# Dependency Review Action # Dependency Review Action
# #
# This Action will scan dependency manifest files that change as part of a Pull Reqest, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. # This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging.
# #
# Source repository: https://github.com/actions/dependency-review-action # Source repository: https://github.com/actions/dependency-review-action
# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
@@ -15,6 +15,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 'Checkout Repository' - name: 'Checkout Repository'
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: 'Dependency Review' - name: 'Dependency Review'
uses: actions/dependency-review-action@v3 uses: actions/dependency-review-action@v3

View File

@@ -28,15 +28,15 @@ jobs:
- if: ${{ ! env.USE_APPLI }} - if: ${{ ! env.USE_APPLI }}
name: Warn if not using Applitools name: Warn if not using Applitools
run: | run: |
echo "::error,title=Not using Applitols::APPLITOOLS_API_KEY is empty, disabling Applitools for this run." echo "::error,title=Not using Applitools::APPLITOOLS_API_KEY is empty, disabling Applitools for this run."
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- 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
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}

View File

@@ -1,32 +1,86 @@
# We use github cache to save snapshots between runs.
# For PRs and MergeQueues, the target commit is used, and for push events, github.event.previous is used.
# If a snapshot for a given Hash is not found, we checkout that commit, run the tests and cache the snapshots.
# These are then downloaded before running the E2E, providing the reference snapshots.
# If there are any errors, the diff image is uploaded to artifacts, and the user is notified.
name: E2E name: E2E
on: on:
push: push:
branches-ignore:
- 'gh-readonly-queue/**'
pull_request: pull_request:
merge_group: merge_group:
permissions: permissions:
contents: read contents: read
env:
# For PRs and MergeQueues, the target commit is used, and for push events, github.event.previous is used.
targetHash: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || (github.event.before == '0000000000000000000000000000000000000000' && 'develop' || github.event.before) }}
jobs: jobs:
cache:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18.x
- name: Cache snapshots
id: cache-snapshot
uses: actions/cache@v4
with:
save-always: true
path: ./cypress/snapshots
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
# If a snapshot for a given Hash is not found, we checkout that commit, run the tests and cache the snapshots.
- name: Switch to base branch
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
uses: actions/checkout@v4
with:
ref: ${{ env.targetHash }}
- name: Cypress run
uses: cypress-io/github-action@v4
id: cypress-snapshot-gen
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
with:
start: pnpm run dev
wait-on: 'http://localhost:9000'
browser: chrome
e2e: e2e:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: cache
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
node-version: [18.x] node-version: [18.x]
containers: [1, 2, 3, 4] containers: [1, 2, 3, 4]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- 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
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
# These cached snapshots are downloaded, providing the reference snapshots.
- name: Cache snapshots
id: cache-snapshot
uses: actions/cache/restore@v3
with:
path: ./cypress/snapshots
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
# Install NPM dependencies, cache them correctly # Install NPM dependencies, cache them correctly
# and run all Cypress tests # and run all Cypress tests
- name: Cypress run - name: Cypress run
@@ -38,6 +92,7 @@ jobs:
with: with:
start: pnpm run dev:coverage start: pnpm run dev:coverage
wait-on: 'http://localhost:9000' wait-on: 'http://localhost:9000'
browser: chrome
# 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
record: ${{ secrets.CYPRESS_RECORD_KEY != '' }} record: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
@@ -46,6 +101,7 @@ jobs:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
VITEST_COVERAGE: true VITEST_COVERAGE: true
CYPRESS_COMMIT: ${{ github.sha }} CYPRESS_COMMIT: ${{ github.sha }}
- name: Upload Coverage to Codecov - name: Upload Coverage to Codecov
uses: codecov/codecov-action@v3 uses: codecov/codecov-action@v3
# Run step only pushes to develop and pull_requests # Run step only pushes to develop and pull_requests
@@ -57,9 +113,55 @@ jobs:
fail_ci_if_error: false fail_ci_if_error: false
verbose: true verbose: true
token: 6845cc80-77ee-4e17-85a1-026cd95e0766 token: 6845cc80-77ee-4e17-85a1-026cd95e0766
# We upload the artifacts into numbered archives to prevent overwriting
- name: Upload Artifacts - name: Upload Artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: ${{ failure() && steps.cypress.conclusion == 'failure' }} if: ${{ always() }}
with:
name: snapshots-${{ matrix.containers }}
retention-days: 1
path: ./cypress/snapshots
combineArtifacts:
needs: e2e
runs-on: ubuntu-latest
if: ${{ always() }}
steps:
# Download all snapshot artifacts and merge them into a single folder
- name: Download All Artifacts
uses: actions/download-artifact@v4
with:
path: snapshots
pattern: snapshots-*
merge-multiple: true
# For successful push events, we save the snapshots cache
- name: Save snapshots cache
id: cache-upload
if: ${{ github.event_name == 'push' && needs.e2e.result != 'failure' }}
uses: actions/cache/save@v3
with:
path: ./snapshots
key: ${{ runner.os }}-snapshots-${{ github.event.after }}
- name: Flatten images to a folder
if: ${{ needs.e2e.result == 'failure' }}
run: |
mkdir errors
cd snapshots
find . -mindepth 2 -type d -name "*__diff_output__*" -exec sh -c 'mv "$0"/*.png ../errors/' {} \;
- name: Upload Error snapshots
if: ${{ needs.e2e.result == 'failure' }}
uses: actions/upload-artifact@v4
id: upload-artifacts
with: with:
name: error-snapshots name: error-snapshots
path: cypress/snapshots/**/__diff_output__/* retention-days: 10
path: errors/
- name: Notify Users
if: ${{ needs.e2e.result == 'failure' }}
run: |
echo "::error title=Visual tests failed::You can view images that failed by downloading the error-snapshots artifact: ${{ steps.upload-artifacts.outputs.artifact-url }}"

View File

@@ -26,7 +26,7 @@ jobs:
# lychee only uses the GITHUB_TOKEN to avoid rate-limiting # lychee only uses the GITHUB_TOKEN to avoid rate-limiting
contents: read contents: read
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Restore lychee cache - name: Restore lychee cache
uses: actions/cache@v3 uses: actions/cache@v3
@@ -36,7 +36,7 @@ jobs:
restore-keys: cache-lychee- restore-keys: cache-lychee-
- name: Link Checker - name: Link Checker
uses: lycheeverse/lychee-action@v1.8.0 uses: lycheeverse/lychee-action@v1.9.1
with: with:
args: >- args: >-
--config .github/lychee.toml --config .github/lychee.toml

View File

@@ -20,13 +20,13 @@ jobs:
matrix: matrix:
node-version: [18.x] node-version: [18.x]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- 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
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}

View File

@@ -1,23 +0,0 @@
name: Validate PR Labeler Configuration
on:
push:
paths:
- .github/workflows/pr-labeler-config-validator.yml
- .github/workflows/pr-labeler.yml
- .github/pr-labeler.yml
pull_request:
paths:
- .github/workflows/pr-labeler-config-validator.yml
- .github/workflows/pr-labeler.yml
- .github/pr-labeler.yml
jobs:
pr-labeler:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Validate Configuration
uses: Yash-Singh1/pr-labeler-config-validator@releases/v0.0.3
with:
configuration-path: .github/pr-labeler.yml

View File

@@ -1,13 +1,31 @@
name: Apply labels to PR name: Apply labels to PR
on: on:
pull_request_target: pull_request_target:
types: [opened] # required for pr-labeler to support PRs from forks
# ===================== ⛔ ☢️ 🚫 ⚠️ Warning ⚠️ 🚫 ☢️ ⛔ =======================
# Be very careful what you put in this GitHub Action workflow file to avoid
# malicious PRs from getting access to the Mermaid-js repo.
#
# Please read the following first before reviewing/merging:
# - https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
# - https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
types: [opened, reopened, synchronize]
permissions:
contents: read
jobs: jobs:
pr-labeler: pr-labeler:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read # read permission is required to read config file
pull-requests: write # write permission is required to label PRs
steps: steps:
- name: Label PR - name: Label PR
uses: TimonVS/pr-labeler-action@v4 uses: release-drafter/release-drafter@v5
with:
config-name: pr-labeler.yml
disable-autolabeler: false
disable-releaser: true
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -23,12 +23,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18 node-version: 18

View File

@@ -3,13 +3,21 @@ name: Draft Release
on: on:
push: push:
branches: branches:
- develop - master
permissions:
contents: read
jobs: jobs:
draft-release: draft-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: write # write permission is required to create a github release
pull-requests: read # required to read PR titles/labels
steps: steps:
- name: Draft Release - name: Draft Release
uses: toolmantim/release-drafter@v5 uses: release-drafter/release-drafter@v5
with:
disable-autolabeler: true
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -9,14 +9,14 @@ jobs:
publish-preview: publish-preview:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18.x node-version: 18.x

View File

@@ -8,14 +8,14 @@ jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: fregante/setup-git-user@v2 - 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
- name: Setup Node.js v18 - name: Setup Node.js v18
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: 18.x node-version: 18.x

View File

@@ -12,13 +12,13 @@ jobs:
matrix: matrix:
node-version: [18.x] node-version: [18.x]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- 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
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
cache: pnpm cache: pnpm
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}

View File

@@ -8,11 +8,18 @@ jobs:
update-browser-list: update-browser-list:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- run: npx browserslist@latest --update-db - uses: pnpm/action-setup@v2
- run: npx update-browserslist-db@latest
- name: Commit changes - name: Commit changes
uses: EndBug/add-and-commit@v9 uses: EndBug/add-and-commit@v9
with: with:
author_name: ${{ github.actor }} author_name: ${{ github.actor }}
author_email: ${{ github.actor }}@users.noreply.github.com author_email: ${{ github.actor }}@users.noreply.github.com
message: 'chore: update browsers list' message: 'chore: update browsers list'
push: false
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:
branch: update-browserslist
title: Update Browserslist

1
.gitignore vendored
View File

@@ -47,6 +47,7 @@ stats/
demos/dev/** demos/dev/**
!/demos/dev/example.html !/demos/dev/example.html
!/demos/dev/reload.js !/demos/dev/reload.js
tsx-0/**
# autogenereated by langium-cli # autogenereated by langium-cli
generated/ generated/

View File

@@ -6,6 +6,6 @@ export default {
// https://prettier.io/docs/en/cli.html#--cache // https://prettier.io/docs/en/cli.html#--cache
'prettier --write', 'prettier --write',
], ],
'cSpell.json': ['ts-node-esm scripts/fixCSpell.ts'], 'cSpell.json': ['tsx scripts/fixCSpell.ts'],
'**/*.jison': ['pnpm -w run lint:jison'], '**/*.jison': ['pnpm -w run lint:jison'],
}; };

1
.npmrc
View File

@@ -1,2 +1,3 @@
registry=https://registry.npmjs.org
auto-install-peers=true auto-install-peers=true
strict-peer-dependencies=false strict-peer-dependencies=false

View File

@@ -10,6 +10,8 @@ stats
.nyc_output .nyc_output
# Autogenerated by `pnpm run --filter mermaid types:build-config` # Autogenerated by `pnpm run --filter mermaid types:build-config`
packages/mermaid/src/config.type.ts packages/mermaid/src/config.type.ts
# autogenereated by langium-cli # autogenereated by langium-cli
generated/ generated/
# Ignore the files creates in /demos/dev except for example.html
demos/dev/**
!/demos/dev/example.html

View File

@@ -74,6 +74,9 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
output, output,
}, },
}, },
define: {
'import.meta.vitest': 'undefined',
},
resolve: { resolve: {
extensions: [], extensions: [],
}, },

View File

@@ -1,6 +1,7 @@
import express from 'express'; import express from 'express';
import cors from 'cors'; import cors from 'cors';
import { createServer as createViteServer } from 'vite'; import { createServer as createViteServer } from 'vite';
import { packageOptions } from '../.build/common.js';
async function createServer() { async function createServer() {
const app = express(); const app = express();
@@ -14,10 +15,9 @@ async function createServer() {
}); });
app.use(cors()); app.use(cors());
app.use(express.static('./packages/parser/dist')); for (const { packageName } of Object.values(packageOptions)) {
app.use(express.static('./packages/mermaid/dist')); app.use(express.static(`./packages/${packageName}/dist`));
app.use(express.static('./packages/mermaid-zenuml/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'));
app.use(express.static('cypress/platform')); app.use(express.static('cypress/platform'));

3
.vscode/launch.json vendored
View File

@@ -18,7 +18,8 @@
"type": "node", "type": "node",
"request": "launch", "request": "launch",
"args": ["scripts/docs.cli.mts"], "args": ["scripts/docs.cli.mts"],
"runtimeArgs": ["--loader", "ts-node/esm"], // we'll need to change this to --import in Node.JS v20.6.0 and up
"runtimeArgs": ["--loader", "tsx/esm"],
"cwd": "${workspaceRoot}/packages/mermaid", "cwd": "${workspaceRoot}/packages/mermaid",
"skipFiles": ["<node_internals>/**", "**/node_modules/**"], "skipFiles": ["<node_internals>/**", "**/node_modules/**"],
"smartStep": true, "smartStep": true,

View File

@@ -68,7 +68,7 @@ try {
### Init deprecated and InitThrowsErrors removed ### Init deprecated and InitThrowsErrors removed
The config passed to `init` was not being used eariler. The config passed to `init` was not being used earlier.
It will now be used. It will now be used.
The `init` function is deprecated and will be removed in the next major release. The `init` function is deprecated and will be removed in the next major release.
init currently works as a wrapper to `initialize` and `run`. init currently works as a wrapper to `initialize` and `run`.
@@ -195,7 +195,7 @@ mermaid.run({
- "Cannot activate" in sequenceDiagram [\#647](https://github.com/knsv/mermaid/issues/647) - "Cannot activate" in sequenceDiagram [\#647](https://github.com/knsv/mermaid/issues/647)
- Link \("click" statement\) in flowchart does not work in exported SVG [\#646](https://github.com/knsv/mermaid/issues/646) - Link \("click" statement\) in flowchart does not work in exported SVG [\#646](https://github.com/knsv/mermaid/issues/646)
- How to pass styling [\#639](https://github.com/knsv/mermaid/issues/639) - How to pass styling [\#639](https://github.com/knsv/mermaid/issues/639)
- The live editor cant show seq diagram with notes for 8.0.0-alpha.3 [\#638](https://github.com/knsv/mermaid/issues/638) - The live editor can't show seq diagram with notes for 8.0.0-alpha.3 [\#638](https://github.com/knsv/mermaid/issues/638)
- import mermaid.css with ES6 + NPM [\#634](https://github.com/knsv/mermaid/issues/634) - import mermaid.css with ES6 + NPM [\#634](https://github.com/knsv/mermaid/issues/634)
- Actor line cuts through other elements [\#633](https://github.com/knsv/mermaid/issues/633) - Actor line cuts through other elements [\#633](https://github.com/knsv/mermaid/issues/633)
- Graph TD line out of the picture \(left side\) [\#630](https://github.com/knsv/mermaid/issues/630) - Graph TD line out of the picture \(left side\) [\#630](https://github.com/knsv/mermaid/issues/630)
@@ -504,7 +504,7 @@ mermaid.run({
- Docs css: code hard to read [\#324](https://github.com/knsv/mermaid/issues/324) - Docs css: code hard to read [\#324](https://github.com/knsv/mermaid/issues/324)
- About Markpad integration [\#323](https://github.com/knsv/mermaid/issues/323) - About Markpad integration [\#323](https://github.com/knsv/mermaid/issues/323)
- How to link backwords in flowchat? [\#321](https://github.com/knsv/mermaid/issues/321) - How to link backwards in flowchat? [\#321](https://github.com/knsv/mermaid/issues/321)
- Help with editor [\#310](https://github.com/knsv/mermaid/issues/310) - Help with editor [\#310](https://github.com/knsv/mermaid/issues/310)
- +1 [\#293](https://github.com/knsv/mermaid/issues/293) - +1 [\#293](https://github.com/knsv/mermaid/issues/293)
- Basic chart does not render on Chome, but does in Firefox [\#290](https://github.com/knsv/mermaid/issues/290) - Basic chart does not render on Chome, but does in Firefox [\#290](https://github.com/knsv/mermaid/issues/290)
@@ -619,7 +619,7 @@ mermaid.run({
- render to png from the cli does not display the marker-end arrow heads [\#181](https://github.com/knsv/mermaid/issues/181) - render to png from the cli does not display the marker-end arrow heads [\#181](https://github.com/knsv/mermaid/issues/181)
- Links in sequence diagrams [\#159](https://github.com/knsv/mermaid/issues/159) - Links in sequence diagrams [\#159](https://github.com/knsv/mermaid/issues/159)
- comment characters `%%` cause parse error [\#141](https://github.com/knsv/mermaid/issues/141) - comment characters `%%` cause parse error [\#141](https://github.com/knsv/mermaid/issues/141)
- Add a reversed assymetric shape [\#124](https://github.com/knsv/mermaid/issues/124) - Add a reversed asymmetric shape [\#124](https://github.com/knsv/mermaid/issues/124)
- Add syntax for double headed arrows [\#123](https://github.com/knsv/mermaid/issues/123) - Add syntax for double headed arrows [\#123](https://github.com/knsv/mermaid/issues/123)
- Support for font-awesome [\#49](https://github.com/knsv/mermaid/issues/49) - Support for font-awesome [\#49](https://github.com/knsv/mermaid/issues/49)
@@ -659,7 +659,7 @@ mermaid.run({
- Auto linewrap for notes in sequence diagrams [\#178](https://github.com/knsv/mermaid/issues/178) - Auto linewrap for notes in sequence diagrams [\#178](https://github.com/knsv/mermaid/issues/178)
- Execute code after initialize [\#176](https://github.com/knsv/mermaid/issues/176) - Execute code after initialize [\#176](https://github.com/knsv/mermaid/issues/176)
- Autoscaling for all diagram types [\#175](https://github.com/knsv/mermaid/issues/175) - Autoscaling for all diagram types [\#175](https://github.com/knsv/mermaid/issues/175)
- Problem wit click event callback [\#174](https://github.com/knsv/mermaid/issues/174) - Problem with click event callback [\#174](https://github.com/knsv/mermaid/issues/174)
- How to escape characters? [\#170](https://github.com/knsv/mermaid/issues/170) - How to escape characters? [\#170](https://github.com/knsv/mermaid/issues/170)
- it can not work [\#167](https://github.com/knsv/mermaid/issues/167) - it can not work [\#167](https://github.com/knsv/mermaid/issues/167)
- UML Class diagram [\#154](https://github.com/knsv/mermaid/issues/154) - UML Class diagram [\#154](https://github.com/knsv/mermaid/issues/154)
@@ -762,7 +762,7 @@ mermaid.run({
- subgraph background is black in rendered flowchart PNG via CLI [\#121](https://github.com/knsv/mermaid/issues/121) - subgraph background is black in rendered flowchart PNG via CLI [\#121](https://github.com/knsv/mermaid/issues/121)
- Integrate editor at https://github.com/naseer/mermaid-webapp [\#110](https://github.com/knsv/mermaid/issues/110) - Integrate editor at https://github.com/naseer/mermaid-webapp [\#110](https://github.com/knsv/mermaid/issues/110)
- Internet Explorer Support [\#99](https://github.com/knsv/mermaid/issues/99) - Internet Explorer Support [\#99](https://github.com/knsv/mermaid/issues/99)
- Assymetric shapes not documented [\#82](https://github.com/knsv/mermaid/issues/82) - Asymmetric shapes not documented [\#82](https://github.com/knsv/mermaid/issues/82)
- NoModificationAllowedError [\#23](https://github.com/knsv/mermaid/issues/23) - NoModificationAllowedError [\#23](https://github.com/knsv/mermaid/issues/23)
- Improve arrows [\#3](https://github.com/knsv/mermaid/issues/3) - Improve arrows [\#3](https://github.com/knsv/mermaid/issues/3)
@@ -908,7 +908,7 @@ mermaid.run({
- Question marks don't render properly with /dist/mermaid.full.min.js [\#30](https://github.com/knsv/mermaid/issues/30) - Question marks don't render properly with /dist/mermaid.full.min.js [\#30](https://github.com/knsv/mermaid/issues/30)
- Error with some characters [\#25](https://github.com/knsv/mermaid/issues/25) - Error with some characters [\#25](https://github.com/knsv/mermaid/issues/25)
- Provide parse function in browser widthout `require`? [\#21](https://github.com/knsv/mermaid/issues/21) - Provide parse function in browser without `require`? [\#21](https://github.com/knsv/mermaid/issues/21)
- Better label text support [\#18](https://github.com/knsv/mermaid/issues/18) - Better label text support [\#18](https://github.com/knsv/mermaid/issues/18)
- Cap-cased words break parser [\#8](https://github.com/knsv/mermaid/issues/8) - Cap-cased words break parser [\#8](https://github.com/knsv/mermaid/issues/8)

View File

@@ -59,8 +59,8 @@ representative at an online or offline event.
## Enforcement ## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at security@mermaid.live reported to the community leaders responsible for enforcement at <security@mermaid.live>.
.
All complaints will be reviewed and investigated promptly and fairly. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the All community leaders are obligated to respect the privacy and security of the

View File

@@ -1,78 +0,0 @@
# Contributing
Please read in detail about how to contribute documentation and code on the [Mermaid documentation site.](https://mermaid-js.github.io/mermaid/#/development)
---
# Mermaid contribution cheat-sheet
## Requirements
- [volta](https://volta.sh/) to manage node versions.
- [Node.js](https://nodejs.org/en/). `volta install node`
- [pnpm](https://pnpm.io/) package manager. `volta install pnpm`
## 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
git clone git@github.com:mermaid-js/mermaid.git
cd mermaid
```
Install required packages:
```bash
# npx is required for first install as volta support for pnpm is not added yet.
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
# 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
```
## Branch name format:
```text
[feature | bug | chore | docs]/[issue number]_[short description using dashes ('-') or underscores ('_') instead of spaces]
```
eg: `feature/2945_state-diagram-new-arrow-florbs`, `bug/1123_fix_random_ugly_red_text`
## Documentation
Documentation is necessary for all non bugfix/refactoring changes.
Only make changes to files that are in [`/packages/mermaid/src/docs`](packages/mermaid/src/docs)
**_DO NOT CHANGE FILES IN `/docs` MANUALLY_**
The `/docs` folder will be rebuilt and committed as part of a pre-commit hook.
[Join our slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)

1
CONTRIBUTING.md Symbolic link
View File

@@ -0,0 +1 @@
./packages/mermaid/src/docs/community/contributing.md

2
Dockerfile Normal file
View File

@@ -0,0 +1,2 @@
FROM node:18.19.0-alpine3.18 AS base
RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -

View File

@@ -15,11 +15,14 @@ Generate diagrams from markdown-like text.
<a href="https://mermaid.live/"><b>Live Editor!</b></a> <a href="https://mermaid.live/"><b>Live Editor!</b></a>
</p> </p>
<p align="center"> <p align="center">
<a href="https://mermaid.js.org">📖 Documentation</a> | <a href="https://mermaid.js.org/intro/">🚀 Getting Started</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE" title="Slack invite">🙌 Join Us</a> <a href="https://mermaid.js.org">📖 Documentation</a> | <a href="https://mermaid.js.org/intro/">🚀 Getting Started</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/wwtabKgp8y" title="Discord invite">🙌 Join Us</a>
</p> </p>
<p align="center"> <p align="center">
<a href="./README.zh-CN.md">简体中文</a> <a href="./README.zh-CN.md">简体中文</a>
</p> </p>
<p align="center">
Try Live Editor previews of future releases: <a href="https://develop.git.mermaid.live/" title="Try the mermaid version from the develop branch.">Develop</a> | <a href="https://next.git.mermaid.live/" title="Try the mermaid version from the next branch.">Next</a>
</p>
<br> <br>
<br> <br>
@@ -30,8 +33,8 @@ Generate diagrams from markdown-like text.
[![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop) [![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 Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/wwtabKgp8y)
[![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=twitter)](https://twitter.com/mermaidjs_) [![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_)
<img src="./img/header.png" alt="" /> <img src="./img/header.png" alt="" />
@@ -41,6 +44,22 @@ Generate diagrams from markdown-like text.
<a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a> <a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
## Table of content
<details>
<summary>Expand contents</summary>
- [About](#about)
- [Examples](#examples)
- [Release](#release)
- [Related projects](#related-projects)
- [Contributors](#contributors)
- [Security and safe diagrams](#security-and-safe-diagrams)
- [Reporting vulnerabilities](#reporting-vulnerabilities)
- [Appreciation](#appreciation)
</details>
## About ## About
<!-- <Main description> --> <!-- <Main description> -->
@@ -55,12 +74,12 @@ Mermaid addresses this problem by enabling users to create easily modifiable dia
<br/> <br/>
Mermaid allows even non-programmers to easily create detailed diagrams through the [Mermaid Live Editor](https://mermaid.live/).<br/> Mermaid allows even non-programmers to easily create detailed diagrams through the [Mermaid Live Editor](https://mermaid.live/).<br/>
[Tutorials](./docs/config/Tutorials.md) has video tutorials. For video tutorials, visit our [Tutorials](./docs/ecosystem/tutorials.md) page.
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations.md). Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations-community.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). 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-community.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). 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/ecosystem/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.

View File

@@ -12,15 +12,19 @@ Mermaid
<p> <p>
<p align="center"> <p align="center">
<a href="https://mermaid.live/"><b>Live Editor!</b></a> <a href="https://mermaid.live/"><b>实时编辑器!</b></a>
</p> </p>
<p align="center"> <p align="center">
<a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE" title="Slack invite">🙌 加入我们</a> <a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/wwtabKgp8y" title="Discord invite">🙌 加入我们</a>
</p> </p>
<p align="center"> <p align="center">
<a href="./README.md">English</a> <a href="./README.md">English</a>
</p> </p>
<p align="center">
尝试未来版本的实时编辑器预览: <a href="https://develop.git.mermaid.live/" title="尝试来自develop分支的mermaid版本。">Develop</a> | <a href="https://next.git.mermaid.live/" title="尝试来自next分支的mermaid版本。">Next</a>
</p>
<br> <br>
<br> <br>
@@ -30,8 +34,8 @@ Mermaid
[![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop) [![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 Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/wwtabKgp8y)
[![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=twitter)](https://twitter.com/mermaidjs_) [![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_)
<img src="./img/header.png" alt="" /> <img src="./img/header.png" alt="" />
@@ -53,9 +57,9 @@ Mermaid 是一个基于 Javascript 的图表绘制工具,通过解析类 Markd
Mermaid 通过允许用户创建便于修改的图表来解决这一难题,它也可以作为生产脚本(或其他代码)的一部分。<br/> Mermaid 通过允许用户创建便于修改的图表来解决这一难题,它也可以作为生产脚本(或其他代码)的一部分。<br/>
<br/> <br/>
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/ecosystem/tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/ecosystem/integrations-community.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/intro/getting-started.md), [用法](./docs/config/usage.md) 和 [教程](./docs/config/Tutorials.md). 如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/intro/getting-started.md), [用法](./docs/config/usage.md) 和 [教程](./docs/ecosystem/tutorials.md).
<!-- </Main description> --> <!-- </Main description> -->

View File

@@ -1,21 +0,0 @@
/**
* Mocked C4Context diagram renderer
*/
import { vi } from 'vitest';
export const drawPersonOrSystemArray = vi.fn();
export const drawBoundary = vi.fn();
export const setConf = vi.fn();
export const draw = vi.fn().mockImplementation(() => {
return '';
});
export default {
drawPersonOrSystemArray,
drawBoundary,
setConf,
draw,
};

View File

@@ -1,16 +0,0 @@
/**
* Mocked class diagram v2 renderer
*/
import { vi } from 'vitest';
export const setConf = vi.fn();
export const draw = vi.fn().mockImplementation(() => {
return '';
});
export default {
setConf,
draw,
};

View File

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

View File

@@ -1 +0,0 @@
// DO NOT delete this file. It is used by vitest to mock the dagre-d3 module.

View File

@@ -1,3 +0,0 @@
module.exports = function (txt: string) {
return txt;
};

View File

@@ -1,16 +0,0 @@
/**
* Mocked er diagram renderer
*/
import { vi } from 'vitest';
export const setConf = vi.fn();
export const draw = vi.fn().mockImplementation(() => {
return '';
});
export default {
setConf,
draw,
};

View File

@@ -1,24 +0,0 @@
/**
* Mocked flow (flowchart) diagram v2 renderer
*/
import { vi } from 'vitest';
export const setConf = vi.fn();
export const addVertices = vi.fn();
export const addEdges = vi.fn();
export const getClasses = vi.fn().mockImplementation(() => {
return {};
});
export const draw = vi.fn().mockImplementation(() => {
return '';
});
export default {
setConf,
addVertices,
addEdges,
getClasses,
draw,
};

View File

@@ -1,16 +0,0 @@
/**
* Mocked gantt diagram renderer
*/
import { vi } from 'vitest';
export const setConf = vi.fn();
export const draw = vi.fn().mockImplementation(() => {
return '';
});
export default {
setConf,
draw,
};

View File

@@ -1,13 +0,0 @@
/**
* Mocked git (graph) diagram renderer
*/
import { vi } from 'vitest';
export const draw = vi.fn().mockImplementation(() => {
return '';
});
export default {
draw,
};

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,23 +0,0 @@
/**
* Mocked sequence diagram renderer
*/
import { vi } from 'vitest';
export const bounds = vi.fn();
export const drawActors = vi.fn();
export const drawActorsPopup = vi.fn();
export const setConf = vi.fn();
export const draw = vi.fn().mockImplementation(() => {
return '';
});
export default {
bounds,
drawActors,
drawActorsPopup,
setConf,
draw,
};

View File

@@ -1,22 +0,0 @@
/**
* Mocked state diagram v2 renderer
*/
import { vi } from 'vitest';
export const setConf = vi.fn();
export const getClasses = vi.fn().mockImplementation(() => {
return {};
});
export const stateDomId = vi.fn().mockImplementation(() => {
return 'mocked-stateDiagram-stateDomId';
});
export const draw = vi.fn().mockImplementation(() => {
return '';
});
export default {
setConf,
getClasses,
draw,
};

View File

@@ -1,19 +0,0 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { defineConfig } = require('cypress');
module.exports = defineConfig({
testConcurrency: 1,
browser: [
// Add browsers with different viewports
// { width: 800, height: 600, name: 'chrome' },
// { width: 700, height: 500, name: 'firefox' },
// { width: 1600, height: 1200, name: 'ie11' },
// { width: 1024, height: 768, name: 'edgechromium' },
// { width: 800, height: 600, name: 'safari' },
// // Add mobile emulation devices in Portrait mode
// { deviceName: 'iPhone X', screenOrientation: 'portrait' },
// { deviceName: 'Pixel 2', screenOrientation: 'portrait' },
],
// set batch name to the configuration
// batchName: `Mermaid ${process.env.APPLI_BRANCH ?? "'no APPLI_BRANCH set'"}`,
});

View File

@@ -22,9 +22,11 @@
"brkt", "brkt",
"brolin", "brolin",
"brotli", "brotli",
"catmull",
"città", "città",
"classdef", "classdef",
"codedoc", "codedoc",
"codemia",
"colour", "colour",
"commitlint", "commitlint",
"cpettitt", "cpettitt",
@@ -104,6 +106,7 @@
"pathe", "pathe",
"pbrolin", "pbrolin",
"phpbb", "phpbb",
"pixelmatch",
"plantuml", "plantuml",
"playfair", "playfair",
"pnpm", "pnpm",
@@ -126,6 +129,7 @@
"sidharth", "sidharth",
"sidharthv", "sidharthv",
"sphinxcontrib", "sphinxcontrib",
"ssim",
"startx", "startx",
"starty", "starty",
"statediagram", "statediagram",
@@ -159,6 +163,7 @@
"vitepress", "vitepress",
"vueuse", "vueuse",
"xlink", "xlink",
"xychart",
"yash", "yash",
"yokozuna", "yokozuna",
"zenuml", "zenuml",

View File

@@ -1,24 +0,0 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const { defineConfig } = require('cypress');
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
const coverage = require('@cypress/code-coverage/task');
module.exports = defineConfig({
projectId: 'n2sma2',
e2e: {
specPattern: 'cypress/integration/**/*.{js,jsx,ts,tsx}',
setupNodeEvents(on, config) {
coverage(on, config);
addMatchImageSnapshotPlugin(on, config);
// copy any needed variables from process.env to config.env
config.env.useAppli = process.env.USE_APPLI ? true : false;
// do not forget to return the changed config object!
return config;
},
},
video: false,
});
require('@applitools/eyes-cypress')(module);

30
cypress.config.ts Normal file
View File

@@ -0,0 +1,30 @@
import { defineConfig } from 'cypress';
import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';
import coverage from '@cypress/code-coverage/task';
import eyesPlugin from '@applitools/eyes-cypress';
export default eyesPlugin(
defineConfig({
projectId: 'n2sma2',
viewportWidth: 1440,
viewportHeight: 1024,
e2e: {
specPattern: 'cypress/integration/**/*.{js,ts}',
setupNodeEvents(on, config) {
coverage(on, config);
on('before:browser:launch', (browser, launchOptions) => {
if (browser.name === 'chrome' && browser.isHeadless) {
launchOptions.args.push('--window-size=1440,1024', '--force-device-scale-factor=1');
}
return launchOptions;
});
addMatchImageSnapshotPlugin(on, config);
// copy any needed variables from process.env to config.env
config.env.useAppli = process.env.USE_APPLI ? true : false;
// do not forget to return the changed config object!
return config;
},
},
video: false,
})
);

View File

@@ -10,7 +10,7 @@ interface CypressConfig {
type CypressMermaidConfig = MermaidConfig & CypressConfig; type CypressMermaidConfig = MermaidConfig & CypressConfig;
interface CodeObject { interface CodeObject {
code: string; code: string | string[];
mermaid: CypressMermaidConfig; mermaid: CypressMermaidConfig;
} }
@@ -25,7 +25,7 @@ const batchId: string =
: Cypress.env('CYPRESS_COMMIT') || Date.now().toString()); : Cypress.env('CYPRESS_COMMIT') || Date.now().toString());
export const mermaidUrl = ( export const mermaidUrl = (
graphStr: string, graphStr: string | string[],
options: CypressMermaidConfig, options: CypressMermaidConfig,
api: boolean api: boolean
): string => { ): string => {
@@ -82,7 +82,7 @@ export const urlSnapshotTest = (
}; };
export const renderGraph = ( export const renderGraph = (
graphStr: string, graphStr: string | string[],
options: CypressMermaidConfig = {}, options: CypressMermaidConfig = {},
api = false api = false
): void => { ): void => {

View File

@@ -117,7 +117,6 @@ describe('Configuration', () => {
}); });
it('should not taint the initial configuration when using multiple directives', () => { it('should not taint the initial configuration when using multiple directives', () => {
const url = 'http://localhost:9000/regression/issue-1874.html'; const url = 'http://localhost:9000/regression/issue-1874.html';
cy.viewport(1440, 1024);
cy.visit(url); cy.visit(url);
cy.get('svg'); cy.get('svg');

View File

@@ -0,0 +1,14 @@
import { urlSnapshotTest, openURLAndVerifyRendering } from '../../helpers/util.ts';
describe('Flowchart elk', () => {
it('should use dagre as fallback', () => {
urlSnapshotTest('http://localhost:9000/flow-elk.html', {
name: 'flow-elk fallback to dagre',
});
});
it('should allow overriding with external package', () => {
urlSnapshotTest('http://localhost:9000/flow-elk.html?elk=true', {
name: 'flow-elk overriding dagre with elk',
});
});
});

View File

@@ -1,14 +1,12 @@
describe('Rerendering', () => { describe('Rerendering', () => {
it('should be able to render after an error has occurred', () => { it('should be able to render after an error has occurred', () => {
const url = 'http://localhost:9000/render-after-error.html'; const url = 'http://localhost:9000/render-after-error.html';
cy.viewport(1440, 1024);
cy.visit(url); cy.visit(url);
cy.get('#graphDiv').should('exist'); cy.get('#graphDiv').should('exist');
}); });
it('should be able to render and rerender a graph via API', () => { it('should be able to render and rerender a graph via API', () => {
const url = 'http://localhost:9000/rerender.html'; const url = 'http://localhost:9000/rerender.html';
cy.viewport(1440, 1024);
cy.visit(url); cy.visit(url);
cy.get('#graph [id^=flowchart-A]').should('have.text', 'XMas'); cy.get('#graph [id^=flowchart-A]').should('have.text', 'XMas');

View File

@@ -132,4 +132,9 @@ describe('XSS', () => {
cy.wait(1000); cy.wait(1000);
cy.get('#the-malware').should('not.exist'); cy.get('#the-malware').should('not.exist');
}); });
it('should sanitize backticks in class names properly', () => {
cy.visit('http://localhost:9000/xss24.html');
cy.wait(1000);
cy.get('#the-malware').should('not.exist');
});
}); });

View File

@@ -571,4 +571,14 @@ class C13["With Città foreign language"]
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
}); });
it('should render a simple class diagram with style definition', () => {
imgSnapshotTest(
`
classDiagram-v2
class Class10
style Class10 fill:#f9f,stroke:#333,stroke-width:4px
`,
{ logLevel: 1, flowchart: { htmlLabels: false } }
);
});
}); });

View File

@@ -501,4 +501,16 @@ describe('Class diagram', () => {
B : -methods() B : -methods()
`); `);
}); });
it('should handle notes with anchor tag having target attribute', () => {
renderGraph(
`classDiagram
class test { }
note for test "<a href='https://mermaid.js.org/' target="_blank"><code>note about mermaid</code></a>"`
);
cy.get('svg').then((svg) => {
cy.get('a').should('have.attr', 'target', '_blank').should('have.attr', 'rel', 'noopener');
});
});
}); });

View File

@@ -1,4 +1,4 @@
import { imgSnapshotTest } from '../../helpers/util.ts'; import { imgSnapshotTest, urlSnapshotTest } 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', () => {
@@ -206,8 +206,7 @@ graph TD
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); urlSnapshotTest(url, {});
cy.matchImageSnapshot('conf-and-directives.spec-when-rendering-several-diagrams-diagram-1');
}); });
}); });
}); });

View File

@@ -1,12 +0,0 @@
import { imgSnapshotTest } from '../../helpers/util.ts';
describe('Flowchart', () => {
it('34: testing the label width in percy', () => {
imgSnapshotTest(
`graph TD
A[Christmas]
`,
{ theme: 'forest', fontFamily: '"Noto Sans SC", sans-serif' }
);
});
});

View File

@@ -729,6 +729,37 @@ A ~~~ B
{} {}
); );
}); });
it('5064: Should render when subgraph child has links to outside node and subgraph', () => {
imgSnapshotTest(
`flowchart TB
Out --> In
subgraph Sub
In
end
Sub --> In`
);
});
it('5059: Should render when subgraph contains only subgraphs, has link to outside and itself is part of a link', () => {
imgSnapshotTest(
`flowchart
subgraph Main
subgraph Child1
Node1
Node2
end
subgraph Child2
Node3
Node4
end
end
Main --> Out1
Child2 --> Out2`
);
});
describe('Markdown strings flowchart (#4220)', () => { describe('Markdown strings flowchart (#4220)', () => {
describe('html labels', () => { describe('html labels', () => {
it('With styling and classes', () => { it('With styling and classes', () => {
@@ -874,4 +905,93 @@ end
}); });
}); });
}); });
describe('Subgraph title margins', () => {
it('Should render subgraphs with title margins set (LR)', () => {
imgSnapshotTest(
`flowchart LR
subgraph TOP
direction TB
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
`,
{ flowchart: { subGraphTitleMargin: { top: 10, bottom: 5 } } }
);
});
it('Should render subgraphs with title margins set (TD)', () => {
imgSnapshotTest(
`flowchart TD
subgraph TOP
direction LR
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
`,
{ flowchart: { subGraphTitleMargin: { top: 8, bottom: 16 } } }
);
});
it('Should render subgraphs with title margins set (LR) and htmlLabels set to false', () => {
imgSnapshotTest(
`flowchart LR
subgraph TOP
direction TB
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
`,
{
htmlLabels: false,
flowchart: { htmlLabels: false, subGraphTitleMargin: { top: 10, bottom: 5 } },
}
);
});
it('Should render subgraphs with title margins and edge labels', () => {
imgSnapshotTest(
`flowchart LR
subgraph TOP
direction TB
subgraph B1
direction RL
i1 --lb1-->f1
end
subgraph B2
direction BT
i2 --lb2-->f2
end
end
A --lb3--> TOP --lb4--> B
B1 --lb5--> B2
`,
{ flowchart: { subGraphTitleMargin: { top: 10, bottom: 5 } } }
);
});
});
}); });

View File

@@ -245,7 +245,10 @@ describe('Gantt diagram', () => {
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.be.within(984 * 0.95, 984 * 1.05); expect(maxWidthValue).to.be.within(
Cypress.config().viewportWidth * 0.95,
Cypress.config().viewportWidth * 1.05
);
}); });
}); });
@@ -285,11 +288,11 @@ describe('Gantt diagram', () => {
{ gantt: { useMaxWidth: false } } { gantt: { 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'));
// use within because the absolute value can be slightly different depending on the environment ±5% expect(width).to.be.within(
// expect(height).to.be.within(484 * 0.95, 484 * 1.05); Cypress.config().viewportWidth * 0.95,
expect(width).to.be.within(984 * 0.95, 984 * 1.05); Cypress.config().viewportWidth * 1.05
);
expect(svg).to.not.have.attr('style'); expect(svg).to.not.have.attr('style');
}); });
}); });
@@ -520,6 +523,32 @@ describe('Gantt diagram', () => {
); );
}); });
// TODO: fix it
//
// This test is skipped deliberately
// because it fails and blocks our development pipeline
// It was added as an attempt to fix gantt performance issues
//
// https://github.com/mermaid-js/mermaid/issues/3274
//
it.skip('should render a gantt diagram with very large intervals, skipping excludes if interval > 5 years', () => {
imgSnapshotTest(
`gantt
title A long Gantt Diagram
dateFormat YYYY-MM-DD
axisFormat %m-%d
tickInterval 1day
excludes weekends
section Section
A task : a1, 9999-10-01, 30d
Another task : after a1, 20d
section Another
Task in sec : 2022-10-20, 12d
another task : 24d
`
);
});
it('should render when compact is true', () => { it('should render when compact is true', () => {
imgSnapshotTest( imgSnapshotTest(
` `

View File

@@ -26,7 +26,7 @@ describe('Git Graph diagram', () => {
`gitGraph `gitGraph
commit id: "Normal Commit" commit id: "Normal Commit"
commit id: "Reverse Commit" type: REVERSE commit id: "Reverse Commit" type: REVERSE
commit id: "Hightlight Commit" type: HIGHLIGHT commit id: "Highlight Commit" type: HIGHLIGHT
`, `,
{} {}
); );
@@ -36,7 +36,7 @@ describe('Git Graph diagram', () => {
`gitGraph `gitGraph
commit id: "Normal Commit with tag" tag: "v1.0.0" commit id: "Normal Commit with tag" tag: "v1.0.0"
commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1" commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1"
commit id: "Hightlight Commit" type: HIGHLIGHT tag: "8.8.4" commit id: "Highlight Commit" type: HIGHLIGHT tag: "8.8.4"
`, `,
{} {}
); );
@@ -102,7 +102,7 @@ describe('Git Graph diagram', () => {
{} {}
); );
}); });
it('8: should render a simple gitgraph with more than 8 branchs & overriding variables', () => { it('8: should render a simple gitgraph with more than 8 branches & overriding variables', () => {
imgSnapshotTest( imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { `%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'gitBranchLabel0': '#ffffff', 'gitBranchLabel0': '#ffffff',
@@ -358,7 +358,7 @@ gitGraph
`gitGraph TB: `gitGraph TB:
commit id: "Normal Commit" commit id: "Normal Commit"
commit id: "Reverse Commit" type: REVERSE commit id: "Reverse Commit" type: REVERSE
commit id: "Hightlight Commit" type: HIGHLIGHT commit id: "Highlight Commit" type: HIGHLIGHT
`, `,
{} {}
); );
@@ -368,7 +368,7 @@ gitGraph
`gitGraph TB: `gitGraph TB:
commit id: "Normal Commit with tag" tag: "v1.0.0" commit id: "Normal Commit with tag" tag: "v1.0.0"
commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1" commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1"
commit id: "Hightlight Commit" type: HIGHLIGHT tag: "8.8.4" commit id: "Highlight Commit" type: HIGHLIGHT tag: "8.8.4"
`, `,
{} {}
); );
@@ -434,7 +434,7 @@ gitGraph
{} {}
); );
}); });
it('22: should render a simple gitgraph with more than 8 branchs & overriding variables | Vertical Branch', () => { it('22: should render a simple gitgraph with more than 8 branches & overriding variables | Vertical Branch', () => {
imgSnapshotTest( imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { `%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'gitBranchLabel0': '#ffffff', 'gitBranchLabel0': '#ffffff',
@@ -701,4 +701,246 @@ gitGraph TB:
{} {}
); );
}); });
it('34: should render a simple gitgraph with two branches from same commit', () => {
imgSnapshotTest(
`gitGraph
commit id:"1-abcdefg"
commit id:"2-abcdefg"
branch feature-001
commit id:"3-abcdefg"
commit id:"4-abcdefg"
checkout main
branch feature-002
commit id:"5-abcdefg"
checkout feature-001
merge feature-002
`,
{}
);
});
it('35: should render a simple gitgraph with two branches from same commit | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id:"1-abcdefg"
commit id:"2-abcdefg"
branch feature-001
commit id:"3-abcdefg"
commit id:"4-abcdefg"
checkout main
branch feature-002
commit id:"5-abcdefg"
checkout feature-001
merge feature-002
`,
{}
);
});
it('36: should render GitGraph with branch that is not used immediately', () => {
imgSnapshotTest(
`gitGraph LR:
commit id:"1-abcdefg"
branch x
checkout main
commit id:"2-abcdefg"
checkout x
commit id:"3-abcdefg"
checkout main
merge x
`,
{}
);
});
it('37: should render GitGraph with branch that is not used immediately | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id:"1-abcdefg"
branch x
checkout main
commit id:"2-abcdefg"
checkout x
commit id:"3-abcdefg"
checkout main
merge x
`,
{}
);
});
it('38: should render GitGraph with branch and sub-branch neither of which used immediately', () => {
imgSnapshotTest(
`gitGraph LR:
commit id:"1-abcdefg"
branch x
checkout main
commit id:"2-abcdefg"
checkout x
commit id:"3-abcdefg"
checkout main
merge x
checkout x
branch y
checkout x
commit id:"4-abcdefg"
checkout y
commit id:"5-abcdefg"
checkout x
merge y
`,
{}
);
});
it('39: should render GitGraph with branch and sub-branch neither of which used immediately | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id:"1-abcdefg"
branch x
checkout main
commit id:"2-abcdefg"
checkout x
commit id:"3-abcdefg"
checkout main
merge x
checkout x
branch y
checkout x
commit id:"4-abcdefg"
checkout y
commit id:"5-abcdefg"
checkout x
merge y
`,
{}
);
});
it('40: should render a simple gitgraph with cherry pick merge commit', () => {
imgSnapshotTest(
`gitGraph
commit id: "ZERO"
branch feature
branch release
checkout feature
commit id: "A"
commit id: "B"
checkout main
merge feature id: "M"
checkout release
cherry-pick id: "M" parent:"B"`
);
});
it('41: should render default GitGraph with parallelCommits set to false', () => {
imgSnapshotTest(
`gitGraph
commit id:"1-abcdefg"
commit id:"2-abcdefg"
branch develop
commit id:"3-abcdefg"
commit id:"4-abcdefg"
checkout main
branch feature
commit id:"5-abcdefg"
commit id:"6-abcdefg"
checkout main
commit id:"7-abcdefg"
commit id:"8-abcdefg"
`,
{ gitGraph: { parallelCommits: false } }
);
});
it('42: should render GitGraph with parallel commits', () => {
imgSnapshotTest(
`gitGraph
commit id:"1-abcdefg"
commit id:"2-abcdefg"
branch develop
commit id:"3-abcdefg"
commit id:"4-abcdefg"
checkout main
branch feature
commit id:"5-abcdefg"
commit id:"6-abcdefg"
checkout main
commit id:"7-abcdefg"
commit id:"8-abcdefg"
`,
{ gitGraph: { parallelCommits: true } }
);
});
it('43: should render GitGraph with parallel commits | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id:"1-abcdefg"
commit id:"2-abcdefg"
branch develop
commit id:"3-abcdefg"
commit id:"4-abcdefg"
checkout main
branch feature
commit id:"5-abcdefg"
commit id:"6-abcdefg"
checkout main
commit id:"7-abcdefg"
commit id:"8-abcdefg"
`,
{ gitGraph: { parallelCommits: true } }
);
});
it('44: should render GitGraph with unconnected branches and no parallel commits', () => {
imgSnapshotTest(
`gitGraph
branch dev
branch v2
branch feat
commit id:"1-abcdefg"
commit id:"2-abcdefg"
checkout main
commit id:"3-abcdefg"
checkout dev
commit id:"4-abcdefg"
checkout v2
commit id:"5-abcdefg"
checkout main
commit id:"6-abcdefg"
`,
{ gitGraph: { parallelCommits: false } }
);
});
it('45: should render GitGraph with unconnected branches and parallel commits', () => {
imgSnapshotTest(
`gitGraph
branch dev
branch v2
branch feat
commit id:"1-abcdefg"
commit id:"2-abcdefg"
checkout main
commit id:"3-abcdefg"
checkout dev
commit id:"4-abcdefg"
checkout v2
commit id:"5-abcdefg"
checkout main
commit id:"6-abcdefg"
`,
{ gitGraph: { parallelCommits: true } }
);
});
it('46: should render GitGraph with unconnected branches and parallel commits | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
branch dev
branch v2
branch feat
commit id:"1-abcdefg"
commit id:"2-abcdefg"
checkout main
commit id:"3-abcdefg"
checkout dev
commit id:"4-abcdefg"
checkout v2
commit id:"5-abcdefg"
checkout main
commit id:"6-abcdefg"
`,
{ gitGraph: { parallelCommits: true } }
);
});
}); });

View File

@@ -0,0 +1,10 @@
import { urlSnapshotTest } from '../../helpers/util.ts';
describe('Marker Unique IDs Per Diagram', () => {
it('should render a blue arrow tip in second digram', () => {
urlSnapshotTest('http://localhost:9000/marker_unique_id.html', {
logLevel: 1,
flowchart: { htmlLabels: false },
});
});
});

View File

@@ -0,0 +1,67 @@
import { imgSnapshotTest } from '../../helpers/util';
describe('packet structure', () => {
it('should render a simple packet diagram', () => {
imgSnapshotTest(
`packet-beta
title Hello world
0-10: "hello"
`
);
});
it('should render a complex packet diagram', () => {
imgSnapshotTest(
`packet-beta
0-15: "Source Port"
16-31: "Destination Port"
32-63: "Sequence Number"
64-95: "Acknowledgment Number"
96-99: "Data Offset"
100-105: "Reserved"
106: "URG"
107: "ACK"
108: "PSH"
109: "RST"
110: "SYN"
111: "FIN"
112-127: "Window"
128-143: "Checksum"
144-159: "Urgent Pointer"
160-191: "(Options and Padding)"
192-223: "data"
`
);
});
it('should render a complex packet diagram with showBits false', () => {
imgSnapshotTest(
`
---
title: "Packet Diagram"
config:
packet:
showBits: false
---
packet-beta
0-15: "Source Port"
16-31: "Destination Port"
32-63: "Sequence Number"
64-95: "Acknowledgment Number"
96-99: "Data Offset"
100-105: "Reserved"
106: "URG"
107: "ACK"
108: "PSH"
109: "RST"
110: "SYN"
111: "FIN"
112-127: "Window"
128-143: "Checksum"
144-159: "Urgent Pointer"
160-191: "(Options and Padding)"
192-223: "data"
`
);
});
});

View File

@@ -44,7 +44,7 @@ describe('pie chart', () => {
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.be.within(590, 600); // depends on installed fonts: 596.2 on my PC, 597.5 on CI
}); });
}); });
@@ -59,7 +59,7 @@ describe('pie chart', () => {
); );
cy.get('svg').should((svg) => { cy.get('svg').should((svg) => {
const width = parseFloat(svg.attr('width')); const width = parseFloat(svg.attr('width'));
expect(width).to.eq(984); expect(width).to.be.within(590, 600); // depends on installed fonts: 596.2 on my PC, 597.5 on CI
expect(svg).to.not.have.attr('style'); expect(svg).to.not.have.attr('style');
}); });
}); });

View File

@@ -160,4 +160,70 @@ describe('Quadrant Chart', () => {
); );
cy.get('svg'); cy.get('svg');
}); });
it('should render x-axis labels in the center, if x-axis has two labels', () => {
imgSnapshotTest(
`
quadrantChart
title Reach and engagement of campaigns
x-axis Low Reach --> High Reach
y-axis Low 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 y-axis labels in the center, if y-axis has two labels', () => {
imgSnapshotTest(
`
quadrantChart
title Reach and engagement of campaigns
x-axis Low 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 both axes labels on the left and bottom, if both axes have only one label', () => {
imgSnapshotTest(
`
quadrantChart
title Reach and engagement of campaigns
x-axis Reach -->
y-axis Engagement -->
quadrant-1 We should expand
quadrant-2 Need to promote
quadrant-3 Re-evaluate
quadrant-4 May be improved
Campaign A: [0.3, 0.6]
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

@@ -930,4 +930,36 @@ context('Sequence diagram', () => {
}); });
}); });
}); });
context('render after error', () => {
it('should render diagram after fixing destroy participant error', () => {
cy.on('uncaught:exception', (err) => {
return false;
});
renderGraph([
`sequenceDiagram
Alice->>Bob: Hello Bob, how are you ?
Bob->>Alice: Fine, thank you. And you?
create participant Carl
Alice->>Carl: Hi Carl!
create actor D as Donald
Carl->>D: Hi!
destroy Carl
Alice-xCarl: We are too many
destroy Bo
Bob->>Alice: I agree`,
`sequenceDiagram
Alice->>Bob: Hello Bob, how are you ?
Bob->>Alice: Fine, thank you. And you?
create participant Carl
Alice->>Carl: Hi Carl!
create actor D as Donald
Carl->>D: Hi!
destroy Carl
Alice-xCarl: We are too many
destroy Bob
Bob->>Alice: I agree`,
]);
});
});
}); });

View File

@@ -57,7 +57,7 @@ describe('Timeline diagram', () => {
{} {}
); );
}); });
it('5: should render a simple timeline with directive overriden colors', () => { it('5: should render a simple timeline with directive overridden colors', () => {
imgSnapshotTest( imgSnapshotTest(
` %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { ` %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'cScale0': '#ff0000', 'cScale0': '#ff0000',

View File

@@ -0,0 +1,322 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('XY Chart', () => {
it('should render the simplest possible chart', () => {
imgSnapshotTest(
`
xychart-beta
line [10, 30, 20]
`,
{}
);
cy.get('svg');
});
it('Should render a complete chart', () => {
imgSnapshotTest(
`
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
});
it('Should render a chart without title', () => {
imgSnapshotTest(
`
xychart-beta
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('y-axis title not required', () => {
imgSnapshotTest(
`
xychart-beta
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Should render a chart without y-axis with different range', () => {
imgSnapshotTest(
`
xychart-beta
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
bar [5000, 6000, 7500, 8200, 9500, 10500, 14000, 3200, 9200, 9900, 3400, 6000]
line [2000, 7000, 6500, 9200, 9500, 7500, 11000, 10200, 3200, 8500, 7000, 8800]
`,
{}
);
cy.get('svg');
});
it('x axis title not required', () => {
imgSnapshotTest(
`
xychart-beta
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
bar [5000, 6000, 7500, 8200, 9500, 10500, 14000, 3200, 9200, 9900, 3400, 6000]
line [2000, 7000, 6500, 9200, 9500, 7500, 11000, 10200, 3200, 8500, 7000, 8800]
`,
{}
);
cy.get('svg');
});
it('Multiple plots can be rendered', () => {
imgSnapshotTest(
`
xychart-beta
line [23, 46, 77, 34]
line [45, 32, 33, 12]
bar [87, 54, 99, 85]
line [78, 88, 22, 4]
line [22, 29, 75, 33]
bar [52, 96, 35, 10]
`,
{}
);
cy.get('svg');
});
it('Decimals and negative numbers are supported', () => {
imgSnapshotTest(
`
xychart-beta
y-axis -2.4 --> 3.5
line [+1.3, .6, 2.4, -.34]
`,
{}
);
cy.get('svg');
});
it('Render spark line with "plotReservedSpacePercent"', () => {
imgSnapshotTest(
`
---
config:
theme: dark
xyChart:
width: 200
height: 20
plotReservedSpacePercent: 100
---
xychart-beta
line [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
`,
{}
);
cy.get('svg');
});
it('Render spark bar without displaying other property', () => {
imgSnapshotTest(
`
---
config:
theme: dark
xyChart:
width: 200
height: 20
xAxis:
showLabel: false
showTitle: false
showTick: false
showAxisLine: false
yAxis:
showLabel: false
showTitle: false
showTick: false
showAxisLine: false
---
xychart-beta
bar [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
`,
{}
);
cy.get('svg');
});
it('Should use all the config from directive', () => {
imgSnapshotTest(
`
%%{init: {"xyChart": {"width": 1000, "height": 600, "titlePadding": 5, "titleFontSize": 10, "xAxis": {"labelFontSize": "20", "labelPadding": 10, "titleFontSize": 30, "titlePadding": 20, "tickLength": 10, "tickWidth": 5}, "yAxis": {"labelFontSize": "20", "labelPadding": 10, "titleFontSize": 30, "titlePadding": 20, "tickLength": 10, "tickWidth": 5}, "plotBorderWidth": 5, "chartOrientation": "horizontal", "plotReservedSpacePercent": 60 }}}%%
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Should use all the config from yaml', () => {
imgSnapshotTest(
`
---
config:
theme: forest
xyChart:
width: 1000
height: 600
titlePadding: 5
titleFontSize: 10
xAxis:
labelFontSize: 20
labelPadding: 10
titleFontSize: 30
titlePadding: 20
tickLength: 10
tickWidth: 5
axisLineWidth: 5
yAxis:
labelFontSize: 20
labelPadding: 10
titleFontSize: 30
titlePadding: 20
tickLength: 10
tickWidth: 5
axisLineWidth: 5
chartOrientation: horizontal
plotReservedSpacePercent: 60
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Render with show axis title false', () => {
imgSnapshotTest(
`
---
config:
xyChart:
xAxis:
showTitle: false
yAxis:
showTitle: false
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Render with show axis label false', () => {
imgSnapshotTest(
`
---
config:
xyChart:
xAxis:
showLabel: false
yAxis:
showLabel: false
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Render with show axis tick false', () => {
imgSnapshotTest(
`
---
config:
xyChart:
xAxis:
showTick: false
yAxis:
showTick: false
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Render with show axis line false', () => {
imgSnapshotTest(
`
---
config:
xyChart:
xAxis:
showAxisLine: false
yAxis:
showAxisLine: false
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Render all the theme color', () => {
imgSnapshotTest(
`
---
config:
themeVariables:
xyChart:
titleColor: "#ff0000"
backgroundColor: "#f0f8ff"
yAxisLabelColor: "#ee82ee"
yAxisTitleColor: "#7fffd4"
yAxisTickColor: "#87ceeb"
yAxisLineColor: "#ff6347"
xAxisLabelColor: "#7fffd4"
xAxisTitleColor: "#ee82ee"
xAxisTickColor: "#ff6347"
xAxisLineColor: "#87ceeb"
plotColorPalette: "#008000, #faba63"
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
});

View File

@@ -0,0 +1,28 @@
<html>
<body>
<pre class="mermaid">
flowchart-elk
a[hello] --> b[world]
b --> c{test}
c --> one
c --> two
c --> three
</pre>
<script type="module">
import mermaid from './mermaid.esm.mjs';
import elk from './mermaid-flowchart-elk.esm.min.mjs';
if (window.location.search.includes('elk')) {
await mermaid.registerExternalDiagrams([elk]);
}
mermaid.initialize({
logLevel: 3,
startOnLoad: false,
});
await mermaid.run();
if (window.Cypress) {
window.rendered = true;
}
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -58,12 +58,21 @@
</head> </head>
<body> <body>
<pre id="diagram" class="mermaid"> <pre id="diagram" class="mermaid">
flowchart flowchart TB
classDef mainCategories fill:#f9d5e5, stroke:#233d4d,stroke-width:2px, font-weight:bold; C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z & A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8
CS(Customer Awareness Journey):::mainCategories ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
</pre C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z & A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8
>
<pre id="diagram" class="mermaid"> </pre>
<pre id="diagram" class="mermaid2">
flowchart TB
A & A & A & A & A & A & A & A ---> C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z
</pre>
<pre id="diagram" class="mermaid2">
flowchart TB
A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8 --> C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z
</pre>
<pre id="diagram" class="mermaid2">
flowchart flowchart
Node1:::class1 --> Node2:::class2 Node1:::class1 --> Node2:::class2
Node1:::class1 --> Node3:::class2 Node1:::class1 --> Node3:::class2
@@ -441,6 +450,7 @@ mindmap
messageFontFamily: 'courier', messageFontFamily: 'courier',
}, },
fontSize: 16, fontSize: 16,
logLevel: 0,
}); });
function callback() { function callback() {
alert('It worked'); alert('It worked');

View File

@@ -0,0 +1,53 @@
<html>
<head> </head>
<body>
<h1>Example</h1>
<pre class="mermaid">
%%{init:{"theme":"base", "themeVariables": {"lineColor":"red"}}}%%
flowchart LR
subgraph red
A --> B
end
</pre>
<pre class="mermaid">
%%{init:{"theme":"base", "themeVariables": {"lineColor":"blue"}}}%%
flowchart LR
subgraph black
A --> B
end
</pre>
<pre class="mermaid">
---
config:
theme: base
themeVariables:
lineColor: yellow
---
flowchart LR
subgraph red
A --> B
end
</pre>
<pre class="mermaid">
---
config:
theme: base
themeVariables:
lineColor: green
---
flowchart LR
subgraph black
A --> B
end
</pre>
<script type="module">
import mermaid from './mermaid.esm.mjs';
mermaid.initialize({ startOnLoad: false, logLevel: 0 });
await mermaid.run();
if (window.Cypress) {
window.rendered = true;
}
</script>
</body>
</html>

View File

@@ -1,15 +1,6 @@
<html> <html>
<head> <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 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> <style>
body { body {
/* background: rgb(221, 208, 208); */ /* background: rgb(221, 208, 208); */
@@ -122,26 +113,21 @@
<script type="module"> <script type="module">
import mermaid from './mermaid.esm.mjs'; import mermaid from './mermaid.esm.mjs';
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({ mermaid.initialize({
// theme: 'dark',
// theme: 'dark',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0, logLevel: 0,
// flowchart: { useMaxWidth: true },
graph: { curve: 'cardinal', htmlLabels: false }, graph: { curve: 'cardinal', htmlLabels: false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true }, sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
fontFamily: '"arial", sans-serif', fontFamily: '"arial", sans-serif',
curve: 'cardinal', curve: 'cardinal',
securityLevel: 'strict', securityLevel: 'strict',
startOnLoad: false,
}); });
function callback() {
alert('It worked'); await mermaid.run();
if (window.Cypress) {
window.rendered = true;
} }
</script> </script>
</body> </body>

View File

@@ -42,6 +42,16 @@
font-size: 72px; font-size: 72px;
} }
</style> </style>
<script>
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');
}
</script>
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>

View File

@@ -42,6 +42,16 @@
font-size: 72px; font-size: 72px;
} }
</style> </style>
<script>
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');
}
</script>
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>

View File

@@ -42,6 +42,16 @@
font-size: 72px; font-size: 72px;
} }
</style> </style>
<script>
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');
}
</script>
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>

View File

@@ -42,6 +42,16 @@
font-size: 72px; font-size: 72px;
} }
</style> </style>
<script>
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');
}
</script>
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>

View File

@@ -42,6 +42,16 @@
font-size: 72px; font-size: 72px;
} }
</style> </style>
<script>
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');
}
</script>
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>

View File

@@ -42,6 +42,16 @@
font-size: 72px; font-size: 72px;
} }
</style> </style>
<script>
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');
}
</script>
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>

View File

@@ -42,6 +42,16 @@
font-size: 72px; font-size: 72px;
} }
</style> </style>
<script>
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');
}
</script>
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>

View File

@@ -42,6 +42,16 @@
font-size: 72px; font-size: 72px;
} }
</style> </style>
<script>
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');
}
</script>
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>

View File

@@ -42,6 +42,16 @@
font-size: 72px; font-size: 72px;
} }
</style> </style>
<script>
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');
}
</script>
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>

View File

@@ -42,6 +42,16 @@
font-size: 72px; font-size: 72px;
} }
</style> </style>
<script>
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');
}
</script>
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>

View File

@@ -42,6 +42,16 @@
font-size: 72px; font-size: 72px;
} }
</style> </style>
<script>
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');
}
</script>
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>

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